lmfit-0.9.7/0000755000076500000240000000000013114357470013557 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/0000755000076500000240000000000013114357470014324 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/.DS_Store0000644000076500000240000002000413064117710015776 0ustar Newvillestaff00000000000000Bud1 cache_  @ @ @ @ __pycache__Ilocblob;(_buildIlocblob(_buildbwspblobbplist00  ]ShowStatusBar[ShowSidebar[ShowToolbar[ShowTabView_ContainerShowSidebar\WindowBounds[ShowPathbar  _{{235, 63}, {861, 628}}%1=I`myz{|}~_buildvSrnlong_imagesIlocblob(_staticIlocblob( _templatesIlocblob( bounds.rstIlocblob;builtin_models.rstIlocblobconf.pyIlocblobconfidence.rstIlocblobconstraints.rstIlocblob contents.rstIlocblob; extensions.pyIlocblobextensions.pycIlocblobfaq.rstIlocblob fitting.rstIlocblob index.rstIlocblob;xinstallation.rstIlocblobx intro.rstIlocblobxMakefileIlocblobx model.rstIlocblobxparameters.rstIlocblob;sphinxIlocblob support.rstIlocblobtest_ci2_result.pngIlocblob whatsnew.rstIlocblob E DSDB ` @ @ @ model.rstIlocblobxparameters.rstIlocblob;sphinxIlocblob support.rstIlocblobtest_ci2_result.pngIlocblob whatsnew.rstIlocbloblmfit-0.9.7/doc/__pycache__/0000755000076500000240000000000013114357470016534 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/__pycache__/extensions.cpython-35.pyc0000644000076500000240000000054613055705632023366 0ustar Newvillestaff00000000000000 X&@s2dddddgZdZdZejedS)zsphinx.ext.autodoczsphinx.ext.todozsphinx.ext.coveragezsphinx.ext.intersphinxnumpydoczsphinx.ext.mathjaxzsphinx.ext.pngmathN) extensionsZmathjaxZpngmathappendrr0/Users/Newville/Codes/lmfit-py/doc/extensions.pys lmfit-0.9.7/doc/__pycache__/extensions.cpython-36.pyc0000644000076500000240000000047213062751170023361 0ustar Newvillestaff000000000000003 wX!@sdddddddgZdS)zsphinx.ext.autodoczsphinx.ext.todozsphinx.ext.coveragezsphinx.ext.intersphinxzsphinx.ext.extlinkszsphinx.ext.napoleonzsphinx.ext.mathjaxN) extensionsrr0/Users/Newville/Codes/lmfit-py/doc/extensions.pys lmfit-0.9.7/doc/_images/0000755000076500000240000000000013114357470015730 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/_images/conf_interval1.png0000644000076500000240000005103513066042256021353 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATx{tUՁ TA (r)@GE*|"<T Eڱ .hPhZ|`E ?hB:syg-jO~>' 0 c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c СC3gF]*''GeeeM6MݻwWN4bmݺ#(ضo>͝;W󎊋%IXsuWg5o<ݻWÇm§H555*((Ж-[4dϭƍUQQ/˒믿^ל9sO{5l3 }*(($544znEEN?N;M_~_ѣB[ /;>d>|X)VaaacUUUu˓$֚ bzTWWa F߄{O;ws9С9r.$@uEQ{ aÆg1!yw]„ˬ [TTB R]]$)L%=\Ĺ8sq$Ia9JKI5xqëJX!6mR~~:SR?|Edsq$ 8'q. g8p@S۶'>z7NZbƎ+I裏_JGVv2͝;W󎊋%)nZG}T~Fp @ {2p @ {~֬Y:sկ~&tm޼YڰaC444;nF} _{8@ 0⑧zJoVXP`~fϞ3fgϞ~ f@<ѣsNIݻ%Ivܩ={]v DR~czI/:vȇqaFx?u} ŋuUUUIVZJI'cРA4hP4.:/}x @X`v%IbZrVXX,'K.>&ā;v~N>}T__h2!@C0` 1c !@C0` 1c !@C0` 1c !@C0`L[ 7I c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` i̙***RǎURRkZzڵkue@;w裏Qo4i.\ &hѢEjӦF 6| /+B]wݥgnMwq/mgZl~h0a 3fK*77W/N9IԩS5|p=SzGVQQmjڴiMrssu-hƍڳgOvA>駟;z6f۶nݪSN-2Dm۶wz}۵k.=cZrfϞ?`joݚ3CmEEEQAAl٢!C$|O~c]w~Z{C#@־}{Hl=wޒvڹ>.":`1 [ ǏRwz衛oap# ⱞ={$Ig}^z%Qp׈QGx췿9~[ ,W\?:3A  6LtWkՀt}iɒ%> @"Y_{C'! >lk)DR~c$ h\@Ll%"2=F8ZX^juŒ1V998MR?3N#+]1k!GǏO?թ͛[o[oid@ Ep%;!b@ ,^XPUU$iժU$M>]:3u7S~~?T~fϞ lt0a"@X`v%IbZrVXX,'PSN{UTTVgy&O[=z 6gYAC8cǎYp-0ب ؽPsKC#? B'ZTag쁌Ύ"D sd%9Thv"y-<|"ÙT8 !L#@/a8:>ǁ@Ap߁o1a6 bx)8*:{M~!H HC~DG 5*IC^!@&*a:8h^ #1B_g;l SQb4Fx)_ep (#B#3Οam"D7 <<\cTd#'Scab  St^FX*;XrO l ׅ%<܈#jDƭ(i l)kFGuh<[5wjlQEx5;~"@H 2ix۱Ը"OB$Kv  rx8Fl902g'^܈B$j!D;5<޼S\yi#ng!JCœ!:$g$:\ F:ƚA$ƈ[˳\ qI "@Xz|Dt80EWai#NC$J!D+)>LTp<\nFxxvLbE|t6D4D q!̂+2~Ň䄇?̈D2B "Aca4nH֖d!̂0FxHÓJY`6dV*YU9~+5&a|<[5.u|<{U5o)~,raޜx&p_@(1DpcV~t4Gx鬈'r][n& ",h{xFp9!RXKQLJYGԵn^v7[ X-] ,>j*D2 *B>  @ĘzpvD5BC\ (G+\%hZR?^vRex,+Wƒ]1W""*ixΆT!ifBBG " (yxH؀.zL#Dr$ˋf!\ GX\GDZ ^3=d@ @9>+^˥@T @H=>hN|t?g͂@ @6r!>*:MyKN2q{ GIB~xv+~I,F!` {A !. d +K!>t.˛/ A "o]J">lgA\ ˆ,Kv̂%pg? G;'{0G{ < 2,QD`,@ P *@J@^~DW">~ †&Rl`$_ݗ $ i *2A H6,>֕4WWW3gH;vTII֮]kk׮Ո#t)K.SCCcF0 @eUbU4mݺUWNZ2d$i۶mIvZ{Zz8 uEv,Wn,jCuu 7J{Om۶ɓ5sL 8P>~رcz<7GafÓW@t*77yyyM_OqC=;S4f}q3+`YGʥWX~]:tP]]]#G4}=scnoF֦\cWg?#ֈV. XF胎f<6>ac?9*飄/,,L̪ZTTT{>P=Z/(($߿2#ݾ_eKn:Stfc;د{.Z uAuܹM$IIk:묳7MKa5[>)*ƍǏkɒ%MTZZSTSS۷رcM$IO>dӱz[n袋  B<]zE|x"WnCj={ݫ}L*-=o֬Y*//Ν;իW/Iҵ^.L>>#]pza-YDڵm }4{tR߿_իu饗6=&)=w߭e˖驧ҹ瞫~:nc:|?2h!վ8y*G\͛7OK3"pB-\!"EW^ . X|՝ϝ}A'y<1F+~%xmqqWR!@0p+[T\C|HB.+Gp@f\Z~  "i/ %R- *f?XAA'. * X@f H"@ܼV&?X~WW~2_p(] "@,svW~  ЁquGTi_%hU,|lU/ v @a!‚",KȜ ?,2 0%x=UGWpU-ri2A!d~ֽ?2L :tHsȑ#յkW䨬cSOK_zN:~r5GW)ā}iܹzwT\\,Ib-s!MY``U"NネŠ1l޼y>>8f X$[~%xl~8a+>.aA e3 IDAT<^|Etpna2^ f@ YlM2E7"%x˷ُ  ?'kcI 4܃!zZ_K5⭗Rc|f6mڤ1chСZ|rrO:M!\,,J4=?\Gb %M7> X塿/ugkҧR~@T0ŋuUUUIVZJItW1c>!q_q,$˯ܜ0^"@Z`v%IbZrVXX,'^wV,ӬY?i$qB=\*~F8cǎ70dۀ;6{>+! BZ_+-~XceU+v.G`]_}` 7!d\d 68X~՚`@ @JK+f?QEH̅&>I6W?D2@>7ѦM^ O>#{• פIt9hѺտ q}7u0J@ <Ydu7׿~)77WF<Fl샰񑈧K!;/YDcƌѓO>t_o֞={G4A|H̀9rdc۷ג%KC_G4B 3& d%^9ao@D*@:uO?4N=Zb*q_o.rcWQC0`u>}K؍7jG[H pGnm~ܹ&7%= *W|f?U/W~~$iƌ馛4hРb5x`?  ^qd K.D\r$>رcQ-n{@XzlWMA| \ag|\zebӹl:DKJR}b \^zωa@åx$"~+@X a>$ 7s L ]D2^zE|"B6s>g @Ph@l0pdK@F+a!̬~Xxnw߇e,D>Ck݁/">d)2 8cu+f>9t@~հU쇓Tig?YB ٳ*-,GA2,T`vW I >LX]ŕtvF~^5aiQ.>,\v5!pI^H^b@ @$ ̂ |G>⇘t㵄" 2\z(>U z\%>DIߦZ覄@exe6+>2߇@ ϼ 0*h#@j>bd  a VxClAY$h7\m` @H(,˰.H @@xqODAYY~p߇o >d#8[/(++7و$߆Z XsGtMfƇ HHGl#@2,BXxF|xu]@#@IZaar8{_p(̙3UTT;Dk׮:SNUNNF(4@?$췷gA6= {WL4I .Ԅ h"iFF҆ ,믿2)y8Z憃9 >6oެe˖G?z!M2E֭S޽5c KРӧ_zP̂J SQQmjڴiMrssu-hƍڳgOXt~m?TCCE @)վ4awطuV_:ujq|Ȑ!m۶|5sL?`# @8tD]uu 7JOw\6gARa)|.>Rl:OƏM~ jkkwW[_*I_H;olQwL-w" ڐn߿JU2{I-oyO>02jIRQQQ[Nob ܹctaڵK]vUΝ3 @x$R,d.ϐM~ Azٖ һᆱ8i&IRqqqUVVJ/nSUUu鬳RiGӓKlR|hֆt"NV\&6;D| 7NǏג%KթT%%%ٳ$F۷oױc$I]v{V\ݻkȐ!zt5`KˆqUEDZMVjm뛒kuc.+Ǿ^i :TǏٳw^Weeel11k,kΝիrss5oXz#@(35 "%Bqs!!C!D)fCZ7l+/:/gA}X$B`D߾pZͥGp)"Y4ξrn̂]3!Hą 6bDD@ b%,ZsqG` @Dd!>^7&V~ștXҾ;%_ @ }n1R0>2%E~D ^~ER,Ʌ+c%0Jv7 …"ʋXYOտ;Kfa~d)V%9DH$;3#ˮ p/"Bj|$`l߇C~w $B2Bpx݌x+$>P9bF dƇw;r-I6bR, "C%w @k)! l@#@,R,iDn|8W#@,I .⃫^ :tHsȑ#յkW䨬,q7o֭ު.HڵSN@0K D}4w\;*..$bǭYFO>ڴi}&| SW$B`"> F;v>[oէ~͛7__`pK\=B%ޘlp]@ o^2* kjXmr$ܔΒ`Wv0م8x@$1kFHsc*߬P"BL0E,d-B} %B|fe~@joVdžIn~(2Ͽ*]Ubၿ5?8V҉+5U٪q'Lhu!y,7)J~YWlZ;80c$Ip?~ɥ)l3!ֹvKl=!Dpa47F+S߬P"Bb7>pk߇՟`9xb8p@UUUUVR4}tuEvҥK%I$WCC飯}K˱rK7_ը,K˱Ye+@=#guv%IbNܔ0iǎի֯_#F=Fuֵx7xC]tIg}X)垐D").B$ i!Ha}I%mٲE^xA/l>?oȋ}yo.`9c׫^ǏǛw^$D \G֕{0ƇC )FHJ6#$ه«;Dҽ+>LD钍JHkޯ%w JH6%_ !n#HůK`I#lqz]ھ:ey4ΆD%F?Ι> lu}B{4~MyF"o=Luף Ҧ$DU{_Y5"YBٲώq G>2@|@8  Zx"#vǐnɕ`@b  KJ$m%Y9,)Ҭ詖f%brq8!`ƒqs&D|sr.kwF˵2]s~@V`@ܜ 2ߜ.e0"9I']HT?Ү .`…s&DJ=h]GpjW$Cp,DE˲$!b\re'r;B${"%fCp,x:*D }X\5 Fqy_Წ+cd%g}H0B\ o~xd*w9D)ۗ2LF.+lҽRHzY_'1.|U~ @xΫR/DRI!K!۳$ClU#^,FxKJF,Bu!>-jD_5{FN67 D،Fn, h` l/JKnIV#Kd+qcɕA| OEd)D2٠.%ޤ(m$c%(x6ŭA@ |tlHijYH*#lG0-_y!RِTK")X Zr%9C"9 H"Ɖh{|  FΆHf7N2 Fnc,$@6K֯%Y;!њ[,)$"Hdޚ}h#@%Y+!Ί$ /Nlf$>@4dz!RWjHsb!]d9s(B$Wʒň")>#@%YҬFNfELqz+f>^"@׳!16!~@v @NF"y"RSA==)Pr!fּn %v BˏH#;˵Sy@9ޜ.9Z%"+n胬a\d'f@DFgCZ,~@vb@d<Cvn?Ad/f@DRF!)_#Ɛd/@et,)iG"@D^Ƴ!+!Ҩy#-beljH3ă`&tYW]pzh,̙3UTT;Dk׮M_|Q'OV}jԩ10j\0I&i…0a-Z6mhԨQڰaC͜9S/ƎG}T7x/_Ao/,\Ҩvgax0D͛l2=ú;$I&LЀ4cƌ#K/mqlȑ6l/^sz:vYϵeY~Oyu|H??k׮ھ}'Ep0HsA C[ԩSC $m۶M={z}͝;W󎊋%IX,qwEՃ>o~/\G5=l =)**RMM e 2$xj֭:3$IC_zJSN59l }*(($544$}ܳ>k)>$.S|r ={h߾}d%ܸx MtATWW#Gx M ^5.jZݺuSv>VdžI%!⁞={{z⾶y$3MR?_/i,;VWݻz4~xG/^Jj*UVVJO.]?~___tm?.|~DG$̓~߃D#@X`v%IbZrVXX,'K.:3K/;ЬYkF ,H2ā;vXzy睧^x !X}IDAT@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` G4sLcǎ*))ڵk-=6mwN:iĈںu#F pdҤIZp&LEM65j6lؐy3h7oݫÇ74z=Yd~ =Yd@J7oֲeH=Lu֩wޚ1cFVTThƍ*++=ܣ[oUׯW6m4gC~!@੗@p.N\Ĺ8p$EUTTm۶6mZӱ\r-ڸqٓ򹧟~/7;t׿=/mݺUWNZ2d$i۶m){2d>w}"PV]]¸Ǫ{.:$kY8sqIr.Ç:S]TWWwȑ#M_?$@ 5l0)Z=\Ĺ8sq$Ia9Æ Kk۷oZܹsܱ„K%IEEEI_/"),,3<B_뮓${ر'ߣs:s4Hׯ[ʦM$II_XРX,߿Akhhh{͛7D=I'>`u]$FP~Զ}/_\7x~_iر>Hs*Mp Zro߾*++믿_|Q^zwK///Ν;իW/I'~饗ꭷҝwީnݺ?vޭ^{- %Xp\s.]kZzuS|HR,kJrrrfyZhjkk5tPYp ^ӷmԩznAך:urrr4zhF=7ڵk5br)ҥ˗{8jodz.֮].LܹG}T}5~xW֭.=ӖM6MݻwWN4bmݺQ{#s/j߿շo_M:U555FL& 78Q&[z!mܸQǏ\j-^X^x^}U^_WYYօE碴TSLW\|Pmڴ۵{nC=^xAFҀt]wcǎZfn6}zG UVV>ӤITTTÇB&LΝ;u]w%}n}}jf̘Ѵ)sڲegd.s1sL8p@Ǐ9眣>@/իm6;L&硹({3soYW^i8zhc^C^^^׾5KQ__p7L2O> Gb\رC ~C4&s|!//a-6sczq˖-kb >lӱ}5z _WVc/rC,k1VC{3"jK`_t Fy{Seqs@S!*5J7:h4Rr5ʭf?'U4ufE `lmL}D].6# ":pxs{}vwKzu@@'NЎ;dSd{n^uIR__ߴb֬Y9s|>ߨ񼼼TmGJKKZiڵ1߯׫^.5'Xl^k&ps,x"M`:AL~5_K/4.WY455i…:x !߯۷'jYlٲEڼyN<`0ݻw/жm\6_̙3zب^x9~nj/^X:}tʍHO__z{{Zk&HsHu3,ú L :$q{,X`.\03s&եfaYYYn߿{1sǶmNq6ȑ#g8j~͛7'--vux^3_87ģԸ$8:t($q݌$n fv=U:uf̘a%鈉dxq{7GZfϞm,5&E[[ŋ-g}fk֬4s;y577[ +WZJJݻIII~zxss9c*7"rj6lSIɺnFEtBuvvZQQ͝;:;;9ʕVVV6j,~H&5cΝ58ހ;UL4 ϷwxYYtM644R]U^^n9]w]R\8Y\Ͳ\{!KE2t= HOOVZG ˻566gQ{{{344~AT}lM4 Iϗ1sJc_ "ӽ;Jutt( ƫ\W[N===:u̙3Gc;;;%bĹsT^^nA_}^ Z9$ypd]7600J:x.\x={VvZ>jiiUSSc.,$yv>srrb^kEА.^8f|OCCC13QΟ?/O;SǎsC? ׫[o55%,$KTccc܀=Z9$9pd\7i+g`0 իmƌ__q^gg qY\[dۙ3gڍ4 3:s^~ŋ~fө",JJJ,;;ۺFm﮻27.?ƌ]pcL# 矖i;wNGYFZ|oi߾}:}jjji&Ig1<<OzCoB_ur-ܵ &zH?Q۽;&Lu3,iDw@ZJKKCO"xB󪪪X0}͢϶njs̱3gwaۻf`˖-3bϞ=nFL|駶b ˳4ζߚFͻRV]]m~߼^ѣG܅&y]?ۻhMu3,i3΀p 7p Ѐp Ѐp Ѐp Ѐp ЀvܩիWokp W^ѣGU\\,Ir'DM{{ եD81 SOnٳ~z1s %Ifv$g@ ~G>|X> /h׮]*--Չ'4k֬D@1PQQu֍ҥKkƍ ɅK CTWW,XL?~<0Ѐ@ ?^۷o7߬t(77Wzzz]`@ lٲE{ճ>KI6lؠWA1P[[*[uww'*&.HMMs <@ ϧo]VssǼ#( _ڪ;vH6mzOɈbwQJJۧIw5>Pkk$q}:ti@I1^ %54 \C54 \C54 \C54 \C54 \C54 \C54 \C5m!PqIENDB`lmfit-0.9.7/doc/_images/conf_interval1a.png0000644000076500000240000004471413066042256021522 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATx{tT߄T\E `T*T^PTE](덛E=D8P=6C)) mE@"d?pd{f\➽'{<.ed1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1cZhƌnݺ)++KQ_بٳggϞܹJر)ZxyJ\.WT׶k /СC5jcv@ o֭[UUU뒤)ShРAZhy `1С$I'kԻwo_|HR=4eWɓ':V8 vء/8xQQ>S޽ۆQF+???X]]! F8qBn;xǎ%IMMM؄0{ !D߄w}Wǎt颁&;srrtĉϑz9R/yw5h ݻw'5BC.!lAAA~/8 zKε{0q*4A!5Zjd%=a5X;a;/ 'Y ?AջCmۦ\#Q tv"NJݱ;Wkp_}FW'CCC5`egOI&Jׯĉ%IG/K?^۷sȰZJT/jkk%I%%%ڵ͛J۷O}t&@5c ޽~l2߿_ra_^.KӦMS׮]rZ-,mڴI\I!@{F<\A:,=z駭Zhƌnݺ)++Km^sI}K_RVV-[fhiWkp_}0Çxb;*,,i@?яGune(F=45Qv M{@"@bTPPݻWOvp f@,tR}Hk׮VQ1tPՇ~;vi]V]vU 0l&B q,Q'Ix<1]{yIڷoq?>CX>СC}v͘1CzҌ3 (ıb}g}&I:믫O>6 N`)$7/e˖ĉu! F)Ikt 7hzGTVVf ų *,,TMMMI 86R(HjI;n8TFԤW͖4p %+}ZG :^SSzK_Wmd8ZJ$K$E{nf}K_Rnn\{>dòe˴~I҆ ~z\.M6M5k^{5UUUI{fΜ}{ի?7{s qػwos/_n`$@Ac$PH! 6>sGR^t` HimG3`HY#ԯ W` #@)'K U&VLjHG_"BMNjPˮ&}>]3wy px#x?2"@*> ϵ1 # 3"-bG%T|$^)Xǰ3>38B`|Xrf>V̀lge|]p`p-汊v˯`+a8E4AE+ڥW~YlB)>mPU_,HsZ;$-I"10*XW7ձhh#>1G`H=xCϸ[Mm_8rǺIA!燊F,K|x#I~C,ebox!%?>&hC i+^vg!@IS|!D$|'|I 5H7y!i@̢;\},63 GD%[ D&'m;@  VBQr/k8}e:8)x,^R KA"> m VhkiHb`06p|Hgf?d0Hdh'j߾2(XW7ϗ^Id2-8Wd2g>K$2¶# v`=G]˗/ԩSrJkNƍӖ-["^[^^kFn[?tR]q:pN<DȲ+HO555Zf.]{W4uT y< g @ ɚ >c 4H;wnuHsΰn޼Y\p6nܨs9G]vU=C"%X’~^땟t{.5sL͝;WC Ѻu裏ԩSz-7G@ṙtqv/رpK,Yx@4a} ͬ } RPR#ُ8@Qsss'N>oZ˥[noYMMMm.BcRg>!1XesΕz }_x_[_xձO?:)HC.$ {W^I=БbH!IXg? m]v˹s[Q-ʫ!:tu1uw|۶m°װaôg8p@_}ǽAӳgϸ8K E0I&MӧOwY*..V>}$I ڵkN:;鍊n$?kiiQyywﮯ|+~ ؁HG,Çɓ5|:tHWEEjkkU^^;o޼yԾ}Էo_I 7ܠѣG?9.H/l٢2oޮ  pNl.@… zj=zTC ƍ5b9.K.+_|Qf=쳺 mLG!@,hg?mp*--Uiiis[͈xjZ|CҙoXDsH"f@⎏XFH=x 8LBȾ i%^U~,p#P~0s|!>B-b W|$qR@#@+@QJf?Wh `XMmG'^+lJ+W `Xs|L0#˯E`/<6#w}f? ` HJ|` f@bIdxχĻ>f12fC^H4iWRr}!_b H?Ei̘1֭TQQǣg}V_Ν; /c=0 ]r| `%$ŋ;侮PrZsq͜9S|o?Eiرv !IH%w AX^1KPPP7PQQQ9n[U\ԯ_?-ZHFmr 02!!$iWA| H:t蠼v!@ khh$HKß7B]zE|,,JKK/|} @%>|!Y@Q, B|,DW^k׮v@82>^G`1`f-\P~ R!>G{?dbĀw6m:=T(plQ @|O}abZz6HeŶmۦ &hZv"O:͖4㣍} >`{$ Xekukƍrc|I 3 qZjUWW'Iz饗T[[+I*))5\F͙3G|O+>B@|Ĵ*e˖i$˥ 6hr\6mZZZt\.͛7/ӧ @ 1/~y8#j~jH񜖖#`5cˮf?mHJ|DZr̂m<$f? FF,w<~l <>b⊏@^: ̀#3cUw~_xHaR/l8 (K|*-Ӯ]ԣG)++xo6lؠzȆpX#o7Ɔ7Dښ ]_{>ӤM>]u饗jРAt_=6Zre:>ZDi eeeԌ3_J?Ov5n8=A{<F )Bϸ[SJ<>Bcˮ `i„ O;o|Cw}OԓO>i8rGAx dϞ=7XTVVj޼y:|yF tN|RIZHΝPϞ=ukر8qbHIWVG>tN|RAZVw_ϧO>[7|n*exm|ln2>DtN|5}M;ŤQjҿ-6p ڼyyo~oߞM@IaH%i52sL9RyyyU=ԩS /QuuA0.58rjkk;z֬Y|C`HMxD dŊz}~WwÞxb`%R+qćrӥU\uU͕$͙3Gr˥\ 6LÆ c,'<ښx U\ve$I|&N /Q0ŲeWE|xg?x ]UodY|dD3#xM !1Hoi 2b @ʲ}U]HmG$!1 8:>|TŁшqC">2ڊے%WH*>H& /)aExH~dьGl.u|^r%$8 G"Ӱb\(qLJ3^ #@8|AS8c#$ 3 lafsd&1D|-mI"!@"R|}UଇD| q!D`bzLJH0<$HƤS|D| dzHm @X.0dzH , @Lh1r+UxHm!@$cvԌxf=$HIoxH @$MGY#@$E*e)96>ab 577kܹ*((PNT\\͛7=fRVVƏo(4̀HḪ">$#ͣ z@XӧO׺ut=h*//׸qk/;o߮ uQ. qsD||j9K q555Zf.]{W4uT  577?qpn]~0aes ":>_0(zH' MK^\#? {z~~~eV׽o~k߾}Nҧ~[nҥK?RMɚƛo;1<}СֱcZ¶m$I!$}_N_b S  [o7D|@,&MKLw3oF///Wqq X jllԀѣG_l]GgV~jC)#5yd͟?_RUQQZϛ7Oڷos=W{n}իz?l@V!<$UYY j:z 7jĈs\.\.WOJՓ$Gp*--Uiiis[͈wd FFAxhx õ!_0(9+>R dtg"@ D|! 9*>2 dPR`H`,zp f@4*<$CC">zHLYəHBaz 6Ax^ ťk|'HQ!C"> @ J(>7KG)&%W3 #&t  1h^0y|d&f@@|t ` ?J8Pbۛ̂ܩ3 c#ςx"+ q8~JKKm6ԨQ7꼚=ڶm׿jiiip6Ċ7B p6KÇk:TXXj\6mڤ2dw}׆"X|΂0lj$jhhP^^x <[ϟ/ۭ|;ڽ{b )\JG :(//Oxž=HxHIpMlxEADRY)t^;0 Y)I!y̮D|b<_RD6C C'>,(uxH @LRnF ]r'TtHC">djI;n8TF8lI6>„e|Dt*Z D|8{$  ɒ!{< R=^! vHVZFI^z%JJJJԵkW߿_W$m߾]c_~oHb{x;!xDCiٲeڿ$riÆ Z~\.M]j޽z衇|\.-\P4j(${ƇTO #@wވ5J---FYKQm}ZD| @LLJWPH#` }!?<$Ά6wbU!߉Gm1xzK…D|{ @GYd>r7/F!GR#һ<  @ć£">MO4aGTO \0>)> uun$o7>|y`(aËv @Y&un# .2^<ˬGxl$iAƉIox!R#Fx"7g?m3>f=ddƇBDŇҫX{ d=X#S:o6XP*8AK̇(/pV$܆s{LC %/ 6FC  H[V<+T54R⣭Yp H=S`!mXOJ 1ę@ @LG{A-<>43IYE| G %EjC ,D|LG $IҪP!@2Ώ9D p!EU&|`kcyU(@.o7 C$zH ;9͆D\ePq.01sߋ3 p_dxx!@ 0Q">bGVI !"$1">C6ćW'd<@gix I <$ Q1H-<Dt$ˤZxE?bܬs窠@:uRqq6oW^yE3gԠAk֬Yjhh00j؍$ Ou{U^^q^_s窱Q'O{iժUڸqvܩ^z)`rR|XFk֬ҥKuJNkΜ9ڲeKkWX#F:6f9RVŋ-;,$M ?ǒ*WUUl͞=wvn֭[uƇ$}_Unݴk.K `I#:$vءAsέIvܩ>}D}|;=z$up{;̪W~~~qﱺoŊ:yn馤,$@|`^SSnw;>{=ú馛4jԨd E iL{=ONN8qy4vڥ &袋.3<1™XDxg ~G g(!YK "j}ڴirssc3RzO?97#_ yСCU]]cǎK.۶m$}uIk# Ige 8äIti577\ž'`544h׮]:uǏkܸqצMԿ}%=Bx,Çɓ5|:tHWEEjkkU^^;o޼yԾ}Էo_Iҭު?Ϛ9s.]n0IV8See.\իWѣ2d6nE.K.u_rL?Z}֯_?$ @r*--Uiiis[͈H޽{= !@C0` A[6sd&!d#@Clj|^Sy 7#01c !@C0` 1c !@C0` 1c !@btq-ZHcƌQnݔИ1cԥKu]ӦMӑ#G p$Fŋ;侮Pr;p ~]uU:yamRMAA7xCEEE!{Ԥ;vsΑ$ >\W]u}Y͚5G`$F:tP^^$=oݺu|!IG֠AvZ 8b6lXgEEEڱc GX^Y~~>C # hjj$:v  ɑ$577}vĉV`Yʻ_}}wۇLRnF%m Ւ^8v܆q@>}ԳgOpfK`@F)H*1> u"'Nƍu߱W^yE&Ol0UVQuuu^zIuU ,/K}k_w߭cǎ'E]3f9|nl| òe˴~I҆ ~z\.M6M]v9眣_]{͛'ۭ뮻N˖-ks8ݻ7/׿ţR{@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1c !@C0` 1ܬs窠@:uRqq6oյ={zΝ;+Ԏ;,1@\O˗kԩZrڵkqi˖-m^ҢkV/JJJTZZCiԨQڳg.j@{ijjjjf,Yo];<͙3kuVUTTh…ַjkN-2.uZj 5񫪪RvvfϞ;vumi֭:x`[_}z)SWN]t :rT}}$ %r-R z|RC~~-r7J.uɒߣK.8p`CZǎk(۶m$Bjumnn ğNx<RSSb=$y3ճgO$544Q Pv?^vnfĉ%IG5vX?燂rM7iÆ {ԿUTThzW4bIgޖ^YY}o߾μ }Ĉz뭷{s` .ZpV^GjȐ!ڸq/>$rZf%IYYYڴix\RMMM>|*++ cxc$ŬYG}ڵkue[n:u%瞳p'*Ik֬ѥ^Ν;_^{͢QxUW],u]IYޮ_^7t?| .߯>⑦x7{AM2Eg}/o޽{-_}*''Gzѣ/G H{@۷B;v ZNYYN]~zG%ӦMӑ#G~!x$}ŋ5yd͜9S}|z&z_^ӟ$)Y<;P>}4m4W_j*mڴIoș,'k_;|PZ|F;w[nڙ}]eggz?P=Z^Zzk. I<@ZZZ<^zo3~;ug!CX5ܔ}ݺu'++˳b G⽯^MMM~y}Qu]4{o_cyg=̔}]dryo;k.OvvgV 7%}駞޽{{⊈. 9X^Zo}QybxANN:,ow]v޽e/RJ%+V(??_w}<> Gz⽯^{=%{{WX_ox\ת* >\_W|MGڵkjQ=Zsw8q;vΝ W^1]{kz衇g{Zx|M͙3ǢD+aÆiŊٳv=6u$r_%VK,ђ%KX {AԣG+{_[ZZ׿UÆ H?̡?XGѮ]`޽;?X]@rq{G{'knj_|Q7tomNnݺ7xѣGh˖-zW_}~3u]j߾fϞmѨ/Jgf=.bM2%#K}@K,Qvv&MKU?P}>w-L2Ec VIDATo%IZvƎ:$y<577GuO~wޭ+WETց?h1bfΜSNLz~K.;}.fMl˦)ꢧi]\6rۢF6pR#X &[acrCڄi 4bXllu%HpcYś{ w~}pGXoU]]>͜9lڵk֜Az'|… ꫯT\\-Z3]yСCqv1,Y'$͛g͜9s̳>^t8c ضe8xb":88h\.YjUx|=C9rDGGW_}ܸq#(k .غum555qŅЃN2gϾ9] \222sUSWWuUuww+>>^?xѡM6GDDhɒ%1?({UgRRim۶iƍrGO?TXXh1c$}UQQ:+++K]&#3ޞ>}Zq<#c=ÇL[nS~~m6aÇ$ڳgo.ǣjÆ Z`A\] kkF=k !k !k `ٳgUQQkɚ6m 믿4p1&EDQ^^:-_\x<ե^/rK`T@'N(==][3g=}܂AݭwyGO=bcc5uT`!Iՙ3gl @HD~D))):vء*((P=x3 ֭Ν;UVVIPQQ~wjܹK $ MMMZj>3?3l[oCi޽zl @H@ """]/xcݺuڻwjkk*@ (((PCC┑6JHHЗ n߾];vPNNbbbp"kj=#ڽ{^rss?hr?]رcjkk 88zf|w@XkxXC` 5@XC` 5@XC` 5@XC` 5A4ZpIENDB`lmfit-0.9.7/doc/_images/conf_interval2.png0000644000076500000240000004056413066042256021361 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATx{u5Ùt@buC@ sC3B[hjTbf)q<=^{mvy:wSwI'e„ =8͋ݼ8Ks̞=[|@d5-[ye7_iߟ/9VZ>}o>lMcǎs3XV\sMrGӧz|xN?lV쓪U~xk4_~9cǎvm޽{gʔ)T*+mSWWÇ9S[[Sf̘1뮻rwsm69sWZֽ{v,1iҽ{̙3'6mZcUiݺuNO~+}_M=VD:v옡C`c,ojժUjkk,juZlR|KL>}!˖-?ha̙3'I[O>dڷo:[n93t 9"4YKǎ;Cv-uuusg' 7P`ZhZ:8sr]w?q:t_q+}/})w\.|'> 5*4InZK7xc8㌌1"w~SN9%Ir]w` Z;2lذ|s%\k뭷Nkk椓NJNVZ6dȐ 2C=7k_Ҳs64>|Ϟ{n)UU3<$r-׸̈́ ҧO<|8C=}6D`'x"tP~vmiݺ>}z{_|bzCCC>T* 4h MUrEeܹy$&M̙3$FZ sѣs뭷;+ ɓ$ӦMː!C2t3 ,ĉ3uwqݻw#矟g}6IRT2qr-T*6lX3k֬T*|^ec9f*T*+ܣG|ӟĉ3gΜTUUW^K3r {pD51cnS__֏m{oqM׀#@bP @1(F#@bP @1(F#@bPLm֬Y$']6DlHFpΙe~㏧e˖:QlyW??%iHh~:nmfϞݸAx |yWs@AI%$%3gNn DPYg$Vn,&;N١(BPܛoVIZf],@]]]١(BP\~ Y\I_v( $UI~d;M2)Iu.1Fc ׾}$\I.LZjy^٢E_*O?tr~|1N99$msfvcwߝ<2/jjZț˖e׿~|__?{lMJS$@XkO>dg͒%d˥K3?ɔE2jԨt5GqDcI5 &ղeZ_-ZV$;V*7vlqB:Z7.K廖W|!>X^}`4lk-Zdɻ7$y*ҥKcFBN<,UUyeuI~|3Rš N;[o-v Ik"U*ֲeƏ#'NSO=qnbY6m2dȐ[bP @1(ƻ`lyx?]v%GqDڵkc z?~|TUCUU^Z$'tR~~-w}{DxO`#P__e˖墋.\ÓlYZ/[\;o^>wA㏧G<-׀4aǏ]:ZʷN=5;&9 I뷶2,^Ǎ7,W@%KdwM$s,ϓI~wl&?-[S'@C9$sT_hd^&/ɯ|"Iw4IuuuQa ˝ߞO&\GtHto⦾cyI*|pYa] &{҆|b5Zd$/%iHd Yǎ9c N -XML_^x gyxL瞴m۶DŽFzrwz.^4d$&9oٲҵkN;,]4]tI6_װ_Î;"N;yrM%›oiժU۪Ի#c˖pBq 3gN32w,?>ɖ Wd9묳{ɨ^Y~_?˖+_J/6@ ;,]4/sgܸqy'2iҤ4lp/~:?1OOC׮޹馛rWR>hr\x??<ڲeOO>}ҪRIMC*NRSU$Iv2jԨ5q Iϟ/^y%7$yɒ,Nrkq=eIJ]=%KҧO-XI~LX,;U/&EWWg;y)ns6J$ӻR֫$44dQN9;˿z(INrǯ-|[k$UUUY/{K2/b~ߦ>?o|_NNs`M@n3I׺_&٬] 805559caB4x @#<2={Ȩ-$IHreV*9SRSSӸC&@$i۶m<9[K_2RVWgԉ'f̘1="l܂=zΟ<i׮]9t֭GMxJ;{wc$`#@bP @1(F#@bP @1(F#@bP @1(F#@b]e̘1$h4y3voK޽$Jem2|9sf=̘1cr<#8p`.\gĈrGcE`u7ӧO[l=#UUvc='3\޽{̙L6-{*۴n:SN'?˾կG3fL 8=NK.]2eʔ$Iz葑#G;g>uVCCC̞=;G|4&u>sL>N;w*>ѪU&YiٲJ;,I2}|y;G">dذaM7ݴsڸ{kӿ| _=G}GH.O|+_ɯ~\ziݺu>sYe5Ć2gΜ$[l=cYti-[wy7،4?gΧ>j"~:OKә1cFc ||9rd~1"~z_Q;ұc}ٳ$ݺu[e]׮] /lh~|#:ujmYԴM.-9A)e՛ {\ O?tҲVZ.\r%9#dɒⳝs9뮻С{n`$_KnmڴY>%Kdə4iRiߦ!]L,dӓt,9zx[פ&[o~+s-oQlo1gqFF;}o۶m-{.\vڭhlm~9C r ;6mZ'oj 6Фk]wr)]1d7QG?E;Ȱa}.\rZWoߊNgNsN:):uZiِ!C2dȐMŋs뭷o7ߜ%L..gɠӾm2orVg=W}`ͮ\+-;wn#MhRr衇fԨQy';qo=r?瞹馛Vv뮻EyrᇯXx<#9ꨣs &O>jv6 rQgӪeɵ&J˷bsU}ŤEUK/&\vxȭ=PHm-XÇϣ>̜93oj?G}4W]u'A>vj_ӧ[uǎkW,kRWWX+fJRɷU?cVwϲ;̷|СCFs= @:?dijj]vJڶM~dw_qï{d;G?` TyW|+;ȍ7޸XkALヨԧ>{wou|Kɹ'|v^̛_IUf…9ò;6kФd„ N:)'t;vlQg3qKӮ]r33}%Gn[%?RV/~:Gx_M*@>Ϥ}IѣGgȐ!}WڦR}ׯ_c@_s Cs},eON~s'2fa>|xjkk{\Ҥd^{$?~/fvkq䨣Ȯ^M׭ZזR?.GnY w:묳{htof|>'N̓O>-"GqDr i,׺u[E B`&@bP @1(F#@bP @1(F#@`;So IDATwn^~4444(M /Lt|֦MV9r=I'otRZ$'ti瞍=@j7̏.0' $Nwܑ>}dҤIy׳ne}MU>ѣSd$N2tмYdIZVUeq}}va_f]vi =IY&I$J&/IM}}I32p}ӥKbXz$ya5GClWFz&9nٲkU{饗r'Cəg~M X&L$Mܚ>'W_$;7ݶaÆV[?Əޚ;6[ouڶi?><: CzԥK|CLܕI.N[Taߪ$+׿k&{'ǻ8AI.Z/4c=a` WGȼܑ~5+IEyp5dzuu$ɢE/N$#v$i$;'iА縑#7!j;6zh&Lأ U*\~_WSwܑW^}5SN)f$$WTUuv9c$'ON?%$+I],<ep TsgfҤI7J:cǎmx,@ڴilљ={v~wUU٬*//Y:wo'MJnݒ$sMHۿ̙3;w93_6ɀ$[%y>yYfmr144q@AUUU Oq2S,ΚخwYߕ-K2%I,+I>s9'o W.I)Ɉ$r '4tl \F[NvܬYA!I>o{SY9"TWne]w-16… lY}twmw,`lT4Q'sxq~4deI΂֭sW44o lHR-ִ[~3sa٬}TWUEuu,i:MK߾}εp\|ٳOlۭ[~BMS׮]Oa+ Єu)W_}uSTRTSWWLC$T7俧/}v뭹RU&>DiIv[`dj{6xllds=7ҐOz{i}~&923lذF oСC,5&wz#555w@y,{=ITn⟛r%dԉ'v|s?3_W-XZiѢE~KyagIEU6|xY\8߂<66yO-O~lIN7U /$_d ӟM}V~_}Vz粆u6_\[oݟACEr?&ÿL7x|$lѡE꺓%%K%?Gj7_mmornCɕt;ꓙ;v,UҢzu[n-;~뭒mZ| /^u M>6mdJ˖->o>}2%yUdiV]?o~2..YJ%Wߛ+p~Ҽp͟s@S"@jȗKof'~>J\n4Y8_byOw''I W2MkFm۶tsͩodKڵNi/3zU-~L8Kmm k<_9"w|j[̲EKe׭_ hvs=S*3%3[e֬odq/fү~?<2HMV?wqE=C3x׿^Ax`Zj;&F.]SOͩoO={cXWZn/| Д`ֳgٳE@1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F,.cƌӹsTUUꫯ^e?'pB훖-[jq>Zׁ6*-{/gرnһwL2%Je~+?3O=:?6ls=weݻwƬYH3gΜfڴic=V '|;iݺu'\رcaGMBUVM444qڴnC=WCCC-[MA |ɴo>:tHnrgfҥ=4fy V);Cv-uuusg' 7@qd+VK_R;\~7O|44`v)$IFs:IkqN:):uZiِ!C2dȐ :_Ҳs64R3<$r-׸̈́ ҧOR#C=}6D`'ӧOs=7x#-Zi}٩T*4hP5+ ]tQΝ^x!I2iҤ̜93I2jԨt!>l$Ƀ>$7n\ңG}+W^0`@&O$6mZ CgϞY`A&NSK޽K.4 6@?RzOә8qb̙+^ziFY(ii2cƌf}I}}Z=޻ѣGn4l(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F#@bP @1(F4˘1c2xt9UUUW '}e˖ZTSN{ۧ[n9SWW>6J.@^~;6һw$IRYe7+S]]={v#dYpaƏ#F.G^6F.@w9sdƌ~N8̛7/444viҥKLc=6cǎE]w;>alrn^hvҪU&{FEmmmZnc޼y;sGfaÆ&7tzM5/w|7/w|A4)ҥKӯ_l2{?H@ ٳ$ݺu[e]׮] / ,X IV{ W6mVEc)j۶mdѢE[paڵk?dlܹy衇{ qyqxi޾[i޽irGo}6|7/w|7/|N՞#@6]w5-Z<?|ŋGQGu떻{@Э[7!`i߾}f$IǎkgxսMY .(s]nT&M̙3$FJkIW<^UU*˒OSo塇JrGsM71@S,h>(FA<׾]v%555n//yꩧ1~ԩS:t~妛nڀSA}}wffmя~ <9_qٳgڷo.]du]Vϝ;7{lrd?0ó;}ٳgF9soc8\ )!aZed3%Ӊ]^ZFL[M3f\G\0nް y19@'7/:x._}|^w~WPPNgZ܄{WgM>])))ժU4dݻWwqG*;;[iiiZrUQQ_զjR"M0AwyrrrB-X@UUUz7m\ :ĉjllTVVԤM6Vuurrr.{l[[&N~I-Rtty=Zm\ :×z/^XgϞu7JVRAA~Gƕ3|8p@~{/-fMssscǎa̙Ǐ7aaaf…?޳f2׷MTT߳"0Z[[MRRR>3cYټy{ӦW^f֬Y ?lݻw˲ /x6jMrrq:Nk `! RSSuc׬Y#c^~eIRccd|wXXz表v {VFPPM6)>>^SLqhƌڶm~z1clȑݻ}t婼\˗/o\ lcѩS;vhРA*((Pbb"##KEv lϟ6͛7Or\Zfnݪ%KؔhjjR]]oX-𘲲2 2c|СjjjReeeGRpt-oРŋ;\^W~K^^,v8/228K/-[ٳg˲̒%K u~o,2e>$|2o 6֭`Oz˲̶m>TZZjBBBLfffR_ѣGu]gl Bɓ'5|pj޽p_r)11=~zeeeiݗ;##Ceee:vX=cƌQee\.~0~xQXX%Szڍ*##C7nq***4|p%''k݊!%3NOOן;wǒ/®u9WQQJRBB$y\;'IP7o5f NS555r\ ?:uΝ;G^vN߾}USS1^[[+tEԫW/|\T;wXO=ݯ555rh@0.\? 4S{2x<⏖XgMwKKZ[[=/ ů98ϟ;\u!J۷O[әzKҙ3gf1uz8qB4etMWMMvܩ+77׶h@9sۧ7jذawIUTT9sLIkkkSnnu=6rЍ1ZlYW. KgϞÇuaS'O5w~ԯ_?[`I&ٽtg]F?_AAAyYYY&((ȸ\v766 }=z|v/kȑ#MDDk׮{O?Ԍ7ǛPm&L`vn]__oMLL0<9xKUɗn߿KA''K.Xl`````-VXI&O> Ҳe˺: Ѐl/2d$ɲ.N !]P]]$9sF]E8O<[oU኉ь3r<&%%I1vt#xڳgf͚D?~\WѣU^^fh@^8qNnt*55U7o֜9s(,:s nAeee] ]рvy-]TPlltY;w!.xmZn~i***J.Nh@^۴i믻.\.Lθ ൐3o6g? ( IDAT222(vmڳgJJJ񼏼<\.555IJKK|rI#<~N koa]pA#FЎ;4~xYn|RIeY믵k.YQFрex$-mh@؆mh@؆mh@؆mh@؆mh@؆mh@؆mh@؆m/qleoIENDB`lmfit-0.9.7/doc/_images/emcee_dbl_exp.png0000644000076500000240000004576213066042256021226 0ustar Newvillestaff00000000000000PNG  IHDR (&isBIT|d pHYs  ~ IDATxyx @6v$EjkT""*Z܊*GOV{±cϱíR h1l I&q}g-$u嚙w|~'L4 BH!@#P!$0B!! BHHB#P!$0B!! BHHB#P!$0B!! BHHB#P!$0B!! BHHB#P!$0B!! BHHB#P!$A#`}rssRaڴiFNN6mԉQB Fl2'?߯~+L4 {;IB &"bȑ^ZX~=z-@dd$;:4B!AH80_8|0q/ƬY`!ЩVTT<˗tQZZٳg} :8jB!HW^ݦK/L6ͭZ]4-!DP㥥!++ YL?C(q1& %F-[,lڴ 'Oĉ'O+;رc|@L!$M7ߌoe{FF/Ƿ~ۙB BƁu  q1&`Lq aZ%=}$,,,hBIF!$$B I(`BB !F!$$B I(`BB !F!$$B I(`MZ*9Б !tSn 4I렀BH7= t$F!ݔ& -MRHG}\DDD~Gnn.0c 9s$ࣹرv =fl2'?qOYYx bΝhnn߉QBHwqv83 t#Gz'..QQQ툈nGfff'DG!ˁ&:N#11>(  $$$`Bʁ!//g>AK(++bf{QBHps= +CSSWn[lW\$ԩSqF&;gΜ QXXئBH0DG֕ 2ЧOQML9< 5k.s{BHXعS\uq`MM@>#f#Fs ;[li&L<'NX,L<3gbر=z4X̄ _w̹kkzK'$8X8aaan!t&<l7o~K`^q &FhbG~&]wu F!]zfs< *Y*S)DMF##W{}syc F!Ĕzc]] v옌;X(v㠀BHcvkht߁̔AF!+Ez+/FRR'gt`ZH#hlqnΜ]vqBB}=i"qnc Q Xjwc BGV *l6Oy}=(`{Sc`\ovf=!/hLFF ƍSOs"5t 7W]c"!v)۷ 9*+yw)D%`&, <"B!^P~Mn e˶L8=!t^B*Op>}D>>]IIJ!&&q_gA#j۾ qSUU>dW)sǾ},B$#Xe%X}y/֏kku_gA#D ?YYwoT",L\ѣ(`mCvv61uTX݌(Z #GsurBsu4ފ8f>umY) ;[,6VGG˸*3]ϑ,ҁ&L]}v1w٧> VZݻwcҥسgO%:kשR۶Rھ};vLUrXϞ2)??#F#9Ywj|`ǎ}@4VTTɌ7.l޼Æ àAo|IgJ?.w4VgVY)"G> |g&xR Bݗ'(`"DŋcҤI.+++uuQq!JOGGᩈX9X<ↆՖϝsl,1Q5""\rI>c2"7|gq7͛=z`ƌ.G" ! TWUzM}YljR)X_/crkֈHc~We/~!ۍv挣ֶށe|PSl_d VXkך ѿ3g΅煅(,,+^BHץF"`'Na\Qc`fL%TcTl6Ll* -M2FB\Xzį,DUVa…XnM;v,ߏ2ddd>ҥKݞ(`bZ;~>%K^u:q_fB륲o_Áw;vLzJWyUс9;w&hC=͆"`łɓ'"##ꫯGNNn6dgg2lBHR] GGQ`}#&}ؠA6l~ͱc֤I"<ʁϞ} ,"Bw{J8n222P\\|ĉ1q EVk뎷XJKQ\9rD 0 wgVY 䈘IWxJGNl n-3S?1Q } W/ ΡH80BLtt07VXbN9;L3qȿ-Y !ۡiR+z7A\{-|I"4%z åDlqhI%Fe}PFvXrSiyX_~ pMR^Xe(`={kRGMSB4:0Oj$&Jҹ:#C G 0BHZ8uJ=+bbsX,@^o+FV[+e,㏥EIšWSKա}0`<BH7Zw.F]q8$O;&/A2m%t;?'}Xyc Hz:k! 1w`ղ27̏4q`2*<ՁӇ %`{Hxr$EozG:0B¸K!*af4ˮǾT." $`? 8iɁGyBHQYwQX~Yo̻/\<֭B42xt(+N8IIzqL:&J#Xjj,"ۮ=l͛B&M,`ܗF!!&|o9hld=>1QǓ۴I&I;ӿs<ܥ/vF!! L& EJǎq0pylQQYBlٜ:A Bڂ/,+ފYO z\EsϹ٧铔w?c2܁Vl " !K8!bd\r] 1, xKOT{J 3^{M\8_7m?G(A#t  Z؈";E4uK!EܥVj/np %ŁVNe~Fx2qhK"VlK!:%} v0KJrNA%`=SjS^^k5j^6*OvxFn9()UE ;:yag6dW&Ov߶'l„ صkoߎ#F`.DEE_Į]i&kسgO%j ̬ J  iă W)6G{r` 7{T>/NP XQQ%qơe43lXT*!ۢ&-FYW's*+;Z+ CQG%ŋ1i$a֭pPfFZE**;k]'')+eEEE8nl/}YxyG1cl6L6 -Bs1BHf+IMM9JJJ }t4StXt^K,+vZ;wr .L5gΜ QXXoEkyܰ1BяRIW;n'?93)))AramcժUxGn:sSSin$%%_t{0G#t @JOr%"%'<\)]2ٽ[ٝ,ly挤 t 1z6 EEE(((ٳ'Olذ.+V d؄N9rsM-)'%} f_}2K-U+n@qq1ફBKKKgE ,ǁYlRpaK/NӦz,KB3#!xn@ w˥X||  V(`ID9sq{c.`"Z2ju}  !$dPsm55 YWk@I9* !/ZZ>0njG%`55W}^QY)$UUQ*0B_44<#فY,Ǟ= Ua B#Ec<9>ف8!)Hݭ^D !/|?Xq[}L&V '_فUUɣ;hIP!~Q-eg>x)}JXSږe 1XBWf[gJv}V)T* GZ?\tQ' ؁2woQTxw+);K< 8AtP V(`Pqv!tu!R.ׅ)qD`L90&0B_46XSP[ RQR"kkUW'ƴIKϙ22d.'kK /0B_46Æ9t2bKzq1pJ9Q3 Rx;LIqt`))1)DP,\ړFY;+#C& +Jm2%? MtGFsu`bi)p ]@Y㵛t4q` sX/!%] !]瞓"QJ pL#~nWJ`Xi*Bht`}'˗L|vS*`aa#zPh0r%[-9h tǶh_:C]Kĵpt`*}hYH&hCvv61uTX=4ZknnFAAnNnuo7[9aQ4M+e[deJJr:TieejPT$)El6=}hֽ0avڅ۷cĈ?}-Z1/@)ɓS9{uH@C]L]iYd8`)ĺ:Ba9.=]RT7+=zxܤk4VTTp gܸq0+_.Biu[2W2bFf;M1Sq.[L$ϕ;uJ~jj,6o$2xMϟtF,^_<.\xA!ͯ2Ó;vLokD~R{XKb  _ ̘!cbč}ut`;vHe#t !//geyУGP>3G ju\XXb1jlԯt]l"r"h? yYY2[ϟtm";bW%Kb ]7O?Ŋ+pic̙xM3g΅煅(,,lm脄VtŁM4bn^BZez29"Bw޽u'1!H())AbtybժUXp!֭[h}}Y<uw+^ҝp[7M'BDI!Չ-nXo$+K`r݁ꥯ8;wnHz衇`PTT̞=`X0ydcXH9j~b}yGc7S` R9R,>^ޯ&.F.f0eۿ lq1YN*|)z& '+!Ł_/Ȝ9Yel>G RV<^z)b/J2#Vpkm"fE Xf74+[ KMv/\*0@:gr%P邨"~4()C>;{xUa T)W͘[}.Vᄀ'to(`tATD~z!ǟػP\>`V3gS¤R))64::6qTz4/2uNUI70B D=9Yt4b}Ӈ~~Uw`uuRInsep:(HqBH X]UT'zT)Ċ BYڤgO73#6x):F:{ ԩSaU98QWWiӦ!;;999شis2Rn^죏ӁѣE 22t۰AH]y ZTz17W*##0avڅ۷cĈ?~կ0i$ٳ;v@vvs1!mC-4髀m,f;'EGCE|с}󍹀 "{~ V^t$A#`EEEpƍ }V+֯_xo A}%lRW_ﺠ3W\!.h dqIU,-M"5 IDATJT !W2qs`0#/ƤI\>|ɸ{qc֬Y[/cܹaIEJ p}kkү-wElL+rtd[z;vs> i/:U| ̛7=z3\?X`;&]3On!FoS8Ot<^ XL8/*03FH4l322P\\|u~~>QZZ K{BE4TCSV}>=xPO*F\F=Ie*:FA:U^C/_}%{ x]80)Tk^]Z,`R'11F]Zjk̇{BKzs89"(`#:?_M3sB4D +˿ F)AR( (+>Pġv|2vHS)D@\֭2NV]-gHbqN׾:0^>2yZ1 e4"qʕo~Vne!Eg3:)gV)2rT:;0%`2&J/ű%%z*;V:tr=IWK с0FGWeKA஻[OERjBsutr?~\})#2I0}HN8F8}qG]z--B4UaFƠTCS(;yR::TV0$`FHW"h;iMFijrq^2qOW&oÁ_BJϟ;"qbw~ }v!ʒƌQ4Y$1Q2 XAkCBB.-`_~ \{)Muf̘S"Ձ--Տ++e+Id_P Ν"Vii:6LtN*TS=!].-`͎bV\>-J./ %`O˼-N֧Jۥj(`Ǐ 9 XctɡC͹0U#+ѥkL!v?׸Ǧ&W$v4-[d{^rS3vXC'5UR/6oc`r`80Oԯ}lt`ѥHL!v/N.DD.`efX+]>'OAdX^SLM70@w`8#ՓIK‘=\DN!~kRRJF\o_9WS.`DEI1?)y&}FƪT+*`XB'&NyC=J!X:Ѩtet`(QS rۿ_OefJD%`FL9-[b֞=k!'l&tG֙b]*(3K!:;uq YF0@4 *< ˹4>=]/0x#:Z&ZSHw .ߤO0g|;7.1(SM XޒsM!"`G: j[S#)F%` g .pt7F{1dgg#??SNXe`E^^f̘3g| 5fwYǏ`< }*PBMj[RPXG ɓrDbns&0avڅ۷cĈ?>eeex7PZZ;wP)DO,>-ib"#uf &΁Fų%%I3>}ssiE_h1:A#`EEEpƍ }ݎn#S9|@Vf62V۷5m gw]ǻ})W)Č qYBR-.N:kBNŋcҤI.裏b@BBoQ)ĺ:+d`v,NHíPW'(`& ''gerM %`zEʁw~޽ɁB|Syyy.?˗/ϼyУG̘1⥗^BYY, l6{=oL!FEUUI_;3q4,oi~&IK7ۻu[333]Kdr`f Sfs2v:uի=dXk׮5}˖-+;ԩSqFy睦ϙ3BUxcPqe2iK.߫}W&&$xS_/7Ę1jNIac~ s 1&q"3IIe(`/l$ai>j*,\֭Ctt>#G3<&DGGc͚5̨2N ֬/܁IY,yZ nΦMwSY z4UuGذAZcRjqD?Jz #GΕ*./۽[8~D`t`Ւ4K!*S ]TCVBЭW/y4:0ERJVMMFs-Sk; /JMف%$H+ǁ͛eDBt}_Zs89wtwׁא} )v(lpuO*便7C 9,ՁL#g;yRA:%_F'?/NiFy/,L^oԩrN< 10O򅯿^RK'>\=p R7)4"q80B}(`ɺ?/X^ĠAR%7mݠAc`6"}=/BHVÁXVLrrӛ*;{V͎i]u\6q0BTVF2Dޔ%&\S2R L#tJ^{^2mL *EW_ wrLJUk '&=@YY+pTсiT^z~Ͽ pY22k!_l**EgOُFHpwo4q`:|ѩeaB4qo?:Ǭ>-&]ˁ-[v0j2DQy=j.`SJq:%{in5A%n'`ÆIsƒrhrmΜ:Ձϐ!5=dΘ;+t` AӉ7ֿnUVTϝ۹I;с:%UOcBƜ9M7I?C_hh M'i ,9Yw` 7_7]2"* ! X޾9p=$?Ǐ;[ı8!)ľ}No{l*R&#zv`؟j4:fEj; { ˄ۥuǺ?$UP 75ɾS"`U*+s @~_sLSSijܳ뢓ވvKN/+Fu%;BOQiO>fԷD9عs]ݙ`i寀rLk8}ZՔhZeD頡er`&ȹ2$$vVUJMMrWUn<#R"#N司64\*B0M:fX3={]9!n +W:6h56awM!&$ ^ݏTVʜic_:0չ_ֿ:;khIJj脅qrP%hO?|3]wM[jFÇ(UUzk(uW =ԄW"@0wX,R;c`B`wSc[ XLL XL=ؾ};mۆ)S.k܌|VݻtRqaAR*{4O! 9*+f(Ό'쫯"Wkjt^Rs HX~'O: SA#`*fZ͛1l0 4QQQ'tfHHB1 7!An*hBr8޽2n=72V-cguuVU,`ii""z);ݻ76m~ee%.߿?vfxe:tU"8ǎh)DoEsۻWjZYIYn3BŽJdK.u{N7[B+.UUI#}*?yR5'N_*oIE= Gw:95k$Vg;~:P8;:qAc s^5;V.-džm}9'?ǏK˗}Hc`.`_.UPDBkYɓ"ft۴ ;qaOLq8۔c27n"`Ł8 ֭C@R>Cf=ZRyr`=z^9FBH!hCS7ŕDE[ݨpN!n\q>R)İ0WS|0UJߍ6d5*bb$m wJ|/_BЁ36qREIIol1+@#5Ձ]z.`K b@W4zYJfV(l. ~A?SZ8M##6 ΉQ= Xx▕xJJwEs$p%2"cQiicVfOZ=j(1-M>Z 2k,`8]! Ѯ :SB,YcvtU"Y-%E}L`>qBR"RJDEI,/ *jks}U]Ϟ"qqr ށEDNlq`Fec=@#x90@4 3gUEGc76VF&'8!6pq^K/ILFջeORS%X(N_F XPl9zIpsv3S8!DZIAd́"`R_-ثol;sd3G_P2:ZDF@Bys*u?_ 5ƌR_<[jDTdY=9L Ir\I)wdt`2U,v_HX|1ۿ! XHHeA,<\ƕ|;qq3 f B9RƖ6m@%`r΁{rZRڥ^LjT%Ç U`at`r]*/}f!Sm@ݥzS "1T BctSy0O5JV݁ л;y;. { !ޡqO,:ڻxK!+P l߮;#GegKo qq"f9ޗg?x÷B=ǘ1cpuסer\s5ŨQ/ R!!AUý$ ́efȩ9_C1d^ާT'*ٹӼ 1bKw wFBJP ?۷c۶m2e ΝOTT^|Eڵ 6mk= MݸQw*+1 |IDAT :xP^8QsQH{'l `GE!",pGlgR1jlX$TB[JSRZs [s q`yT)D],%2E/'G6+w(`TO= z q߲2lݺƍQ1p&*J׾}K΋,>^T`>b@YLt!//gyѣ{#=fôiӰh"hHq;mt.Ձ륷jq݁%?Wwo!Nzj1c&Md޹sp-஻c~̉9s\x^XXBB XZvbVwEt ,X_|J!(`>%%%()) t"&2߿Ç|'(((pG4-ڝ0 XG>ٷ7 S4+Mgܯ9?!$p87+ Vj '@^^ƌ łɓ'6l؀w}_} PPPUV,p`j/vMy Q)$mhbq|(ʁ}Ǧ322P\\ ꪫҙayR"\utŨs_<⩈5I} !# *W o`x8p]ܝl/>ļ"! XyaY-KO." q&,Lӷ *H!BiZ*Q)ȡCz Bi/BI Μq$"L  /B !F!$$B I(`BB !F!$$B I(`BB !F!$$B IF~ic̘1P^^vfo !A#`?8oߎm۶aʔ);w}-Zubm$!1c ;W4{fC?71VTT`Ŋ/~2-1c ;Wh =0m4dgg#''mngw^\#77yyy1cΜ9萰h"aԨQXhQ@b0W֢#F PWW|Fb|Zii6jԨ@rcǎi[n4M#FhwpTبi;wN7n~G$ ڌ3o1Сhi jjj 3g|MMwXWWt4ѣӧOkiӧOז,YИvܩ5JkjjΟ??^;p@av|Ǵ{N4M[`.~o߾Á43lX,GpY477#111D`V+֯_Gf :YYY#..QQQ815 ׯGmm-v;QQQИUUUHMM*y&x͆iӦaѢE t8ǶmPQQ:mmu uV\֯_pyb(--E>}`@@q뭷:S <wqK̜931@zz: 997|36oKӦMCiiiV\K.Ɂ[lW\$DFFbԩظqc}݇-[`ݺuHHHE]:~8رcHII pDuGNN~@PaԄիW 1=(//Çk5ҙv444_EkZZo>2攛਄K;tlڴ MMM4 k֬ T'Hסe˖En&[z+loӵ=zh/^萴kaaaZ~~6fm̘1ʕ+ӎ;-??_?4gJJJ СCZ~~j>lCm۴cjGn栨BlZRRV__P.si999ڨQ3gjgϞ tHڏc-''G׾ˀĠQQQ555u] >\+**N:| !$L!B I(`BB !F!$$B I(`BB !F!$$B I(`BB !F!$$B I(`BB !F!$$B I(`BB !F!$$B I(`BB ! DѰIENDB`lmfit-0.9.7/doc/_images/emcee_dbl_exp2.png0000644000076500000240000005376613066042256021313 0ustar Newvillestaff00000000000000PNG  IHDR (&isBIT|d pHYs  ~ IDATxwxeևI!$ i{"UQBP@QQ(ElX@(ge]We]Ŷ hP@wBBKd?of&3i$וkfLysbXPEQ:[m@QEQ.0EQN(ITEQ: (R'QSEQ$*`(JDLQE)(u0EQN(ITEQ: (R'QSEQ$*`(JDLQE)(u0EQN(ITEQ: (R'QSEQ$*`(Je믿k׮qRdȑDEEѥK֬YSTEQ\hϟϕW^Yq=Ce׮]lݺ(Jx :w\1YYYo|'xxxФI(₸$$$cr%0n8k{X(J-POtt… +tsظq#Ǐgƍ4nܘ3gVEQWFCK.͛7y#G*`&JREiX,Bpbi0Zh={Xl]v-:K/˜\u\:&SCW]elhт5k0l0 @JJ Æ +>we̘1İuV{(RLM7M7=""Eaݺu594EQq!8cb*`Եg1Lu.(RԥNu`(JDLQE)(u0EQN(ITEQ: (R'QSEQ$*`(JDLQE)4Pq(,\*`( [o֭\*`( L?k{$ (J$Xqڵ+lܸf̘A׮]fќ>}G(z֭?/?ULtt4+,D>C6nȶm(,,/Q*cT|q`L5Gms'Oddd NQuٷO@Xĉiٲ%f TREUS*+A||<? .筷"11rssϪyԊ("8s6u1FCK.ׯ.#((#FzjƔ2eJ8tEQWBXAx{Ê xx$иqp90[,;wW^ooo-[F>}J)۶ɚBXAʗ8ƍaԩ3jeϟO-Xf Æ cȐ!0l0bbb뮻իݻw1+T_p<7+B~>sn΃,ٝ:d*)$kEkCp͙O խNq`(lͭk|F+9"@&uӁ)T3)`9 _@jjUmC*`(S!'z ͚YQs(b50EQj&+XNX뮃HUEQrN-%;Ch(8Qyl0mZ PSEf!/O*^Tǵ vܧq,?9C}`5(Rdg"Q׶ !֬Y9[ICTmv.~?yՈKVPEOdẽUz0|35^_~ nB7șr2iԁ)T#LDKX&O%8CAV0yFO?Ί+^@\\BT(RKEӦ/#9ٚ"_Z0O淘961CTﭫԁ)T#]< iib%́Y$1r&^A!}q߿3wϱTkF(8V.;rD2Orw >'ho߃Or^AuX`wqWShQQq" v.;1u^[{熄Hhցyxڱ:ELQ: &$&B./D׼u-XIRQ$\b=7 @:1[@L lrqWS)T#UƁ9#QJ#9:t1F|ս&̃v$.a*1i$aĈd2d:wLxjx e.)/cxGmzg@F\g_SSԯ8`.kH <;ve:vȌ yGXd ;wd޼yڵF(J]g2OvuYqfqC~*gؔ̿=5$]wM7m"+K>>cNf&O_ihԨGv8d;(RRSq>,Mv$'99Pš/:;o!3^dQJQ={({? += G[C_%žs`^eR"""XhQ!C0dȐ(4Ykv~J<lݺ9s$jm+eJ:#E<Xrl"`-ZW"*`48,Uچ>X_?aޤ,e XF(RHNV([3XpTXyY7$|X /uJg8xSk6Ddz_i_-M( ) $$Y}Ȱ$& (Jc"|077 %L65lk|7>ǚW߰MXV/0Y,e XY@LQ+|ak=!DMΪt JɃØ1|s=M3f,.I"T%+Ϊ%mTEQ m#3␊$Qhy]άEQRPp._h^u+:S`0diֶ-R\}GETD RL%SN`WՁGiل;aa[£:C۶}XBd (؉"F-GJ !a'&1x$S~?e#q/Q U+)Ku ]8l (}2\Yk%4(J /|KNWy8׉w8-. wByΒ;.54TETāUJ.]ؾg©N-Aн{PR:*` Dqh%[GV$lAH)䓼/{ζa~ ڭ*Ar XPS*K ؤI"&&#FpLRRW]u]v[nl( 'e3) iɧx"eaV''G*Ń4,ˁm+k*+`ÆsS*K ٱc[lcǎ̘1OOO|Mv5k={6v*Js`ΊfdH3/F/-6ng/,Č wVn잞uiJq)MԷo_9pLXX=zϏ(RUEQ,Ƣcg(33eWrrCpM(nڟ\^znֺJRf˜9s:th$&&i&[CRU1Y1+Kȑi>z=w>y-ZٟGqqIV R9f4<ӧOMFF=zteȑIU+-rPATo'1A[mx| $$؟/=+k(lҥe;w./fsYnfn,/jʔ)∋pEpm+VAǎ,q`/9wruС0`uqӦ>X @BI#,K,aĉXRrJ- w}7AAA曥^d2BoMQj$/BCÉgv% ygz\߇y3vhΝdKcӧ%K.56arss'66°aXj_%66%KE!Ξun+U}}ŁeddF}{p{_X÷1S 쓳v%U2\w^#""Xh_~9EEE59,EQ\x)7~{n$\v8 cWq巘 Lo]\<\ʁ)E~dpا]b4asO$sSMH_`TW暸SE)irdAi+/~0m9Na۪,F)tMԁ)Rg0xX#xw ~<\^hZcf :0FLQJQT/X;.(GC?[H^뮸;ヶ>vGhTւ*`0EQ*ENjÁwFkDZ>SThܤK]B)R)Сs$=cEQ={wVƍ,dc5^*@>>"\0EQ*EEWaBm;w•WV1>\BVZ Sp4C29J $aD0DLQJaes'Y#Ͽ^֏?c+䲲G`p6A,x K XFFBBtUTEu`?9#Epo[!5zLVtAv_}%e2Μ;T\yq[i{ =:uCׁ)R)*#`ɰoZN Q%>?_ħC`xV_ ]8f!?.UW ρA~RSRIBpdUBdd2Za!{rw:/^5ݭv+aDgf80 OTEyyU+(twIHHZV̔T`R, pi56Ρ{dAvELQJۋ>]qh~;w,kB|83Sڃp Q6?{/4jTV.#`pa9ŋ8ߥ(J K2|-ou+^u?_VOL`X#,v?Ȑ49ib<<~Je̖9s0+.O}iӦѨQ#F6|KBBBuWQ, !ʲ|l`8@y.sNyyoum-=DeJؤ \qi͚c[`u`mw]BԨ-]se,_իWw߱xbN:Evv6wu~LR<.. )DEXbv0F|-adeؖ-E|}, @Ƽu+SFBBB5.Swɒ%̚5+Vӧ3}tVXoQx)JCRY9fHx,k"GC=5l讦~F13SDW‰sJz[Z,YG J~:uj D҄ %>>XƏ@JJ Æ szf!*s23E\ !fg;OQ)OȦӛ!8дcuy4!JMf2 {)>E 8wB0r J=e޽{n`ѢE `(deI…⦜}׳X8gɼZd >k>o;hmR,ss={Evڹ h!{⾌.*`80EQ.YYfDL/b, ,͠_C9LoO,M;ge-` ͳO2KҲ̉HE!!FJELQ!FGp52=&8Xؙ3烣;֟{@cض kq/ +VK IDATS'jk (]iب)J=H&r kqH/T3ĉ=ϏP2l{'`CH6ay?d+3idA* 0E)!!VɱFAFGCfXWg\?+23%ݽ,[oueXnnumQ[\&CQG""L23;͎3q[RrY3xx=5_T5:0E|IRBx|;{Mť2RZ!RF@u`=*`R16\V!Ĕz/?/Ev+m׀4kf&q\*`JITa,@Cgָ1Z_= 6nYg/,Dg**q!hQ)΁)J=(a*́@+\_tLRz n1ȹ!SJLQjwށnV.5/pt`Io''wF$߯+>77N߾}9r1YYYo{xxxФBʕwRUrs%/;۱dIΝ.xl׿$ֻfl׵fw_%2EEE*oBY呒"sNYnlx3xxϣ3_/(lBj쯨9s`RWqw^#""XhQ똘UPmx84o.ql.a>#顠f8lkWaCڴ/L1?̈)s0rؾټ^/Btw*`J}eXujKTtY 0i?}lH5J~UJΆ+%aHN"HQaf:*`J}^ k'`ȸW~M %! !I0c%(Ee?`ߩ׊w`U0j@".B|.3 K> 5XqĨIءχD+Y=*_l+!DvpD8v?s拏;Dc2|󍽀]r8 BKvOÇJ}^ ؖҍ :=*`Jiهwa/`%q<,uQi0c4=ξdl|9vLeW,/OÇJ^ Ah{wSJ)k[믗E WU" WnKK9(An.t_ ᱫ'"'4u`e -D4xi?u(*W✂G ժ.=4|<ߵKZzG%" f NKyN&A- "`WK;Z$ Yqll( )Ql*Xd …Bl;Wz' CBuio 7ŋ &ƺp>%E2a4, ̛ݻsس->\\><\dHoJCD,8ر̡zJO:;TJg`L|-Bl8Ù3: U IaW_Ν% 2t>1 K9‹ 0m|o6{ k:`x8l&b&{wF,+^Q+Z ꫁n4MX&=]\عsNWe|q`:%붌>Y}'m"Yv쨅ĭ3{?6l>}˳I[ lN\if$rTԁ)J}^*$Gy$<Wkty,(pt+"lg΀s[^ӫXN\Y3 m<<@@ak^YƜ1kڦуVzՁ8)8XZSځ9wExo][cRj'gOk[+#H2Kc`ynZ檂ػл7[BKk &lӧ X>-ߖ0ItyEiHk'^^|}2Q_I;%f[ޠ<kTUP`={Dh<=%?0/wwn:%^ſ#&0C8A7; Xfh80Y, [ÇJä^ XIEK@.VGT7Fʺ~,f!`F,ױu`{ZC}j9ƥc5[~%5iil ~=,Z$eGF"^2vl+e iPȯk>O?^b ,^mW edcUBMullV&}ۏK%~HMN$Q}L&l&x,VS" J||`}׻iݿ9=f R-fWyf2.``83>< L´?8s8nZ ۻfimʗzNSؤI"&&#Fe[ۆ3fеkW=z4O=|}!' b^]Zsm8vL&㕺OIf 4…-4 2$xUB=aFLM[2232DD-Enq_}U} ~[s>26x`v-[ر#3fp8&11?7m6 /*|Ǐ!wu&w8q0W)Fq8s`V3gJF`AT(́IF{,ױ`"b /Bh_ ҇ѨcX"\9RqMӷo_9pL@@s9󉌌=bL,ey*U={`ܸ]CᅲY9p ~损whqd""B\V&ッo!(Ⱥ- @*k(Ru\Fl3gCuĉiٲ%fU"b̄-9ۼ-|AebvlTk( _)V"#X"ύ4vM+x9^\~^$8#:n{E85*`DGG;,\iӦѨQ#Fpy뭷HLL$%%\> !ffʇӡGfI1yǏK]"kbSP a)j\)!ݻ/, ن##Ssrdܗ|n(jψN;8ED{ߙ,WKܹ,^˗;ݿ~z.2"1իW3fO2y\\>>q[vԴ;S79vL ztd\T:?dTѣʒA',1zH&?˾I~~ K$ߍlLKq5HHHa\.S|fɒ%̚5+VΝ;+PPP7˖-ʔV-Lzӥر?ޝ0 ;y*_W{P*Κ5p%cN$'-X$+Kuɿٌ]O8g!; ?yzM'7cd!4\(F\\qqqůNZ{$.36arss'66°aᮻW^t??T>>VV!!?fY3)UBXY.t)[6n(p~[.I= KOktx7c%dXӦrS(Ջ8{:E_?So!;ցG~ XU9qBqT!'alsKlo؉Oop-5s +si/X{0KLQq`5|X5i"s!'Nwf)Z4N}{L:0 !VQ2mV;'2e[$%I#s oaՁ]kbhpm$^5Ǝ l"ɺ.0EJFI>7K|ܩ=*q`FI%~YM*sUF88)IDnNpm҉ցJ6HJ _p+/z)8smt Pq3$xEQʢA ,%ER.ƥN'UmXD^5r\XXX~<={CC0/[ ::0YJ1;kԕ,Uߗ.`>>p:6cߎpI^-IkxiQo;޾7}4 0c\_e.OQO&M$4l<\s \{_ ÆJvaĔɈ+ȡ!Ŋc+`!!V;wN,:ZDukqXFke6~i=.$X:.LJrXeCP~?/EQ.%`ְ|,_.s&] 狢ΚEx|gȼٱc:]VR.\y_V֕))`FLMսV۶f %I;woo~%d"7Wj#?.~~J0C+#`T J@>m ^}mFqߟ_=­rNhhų1sRbkA[fHaBlB*ĺmx>y&v""jH9\80Eq _I<,xnzֶ,h{{q5fʩS.^X֯.mV22[7yݶ?q";3s`=9ƶbx8M&F)VZ7AUipVҁF0DZtˎ/.B%3ϤT(M !p饕??钬!CE{48FZp&]۴XA, @>˪Vo8Z\NUqɑxǏۇ B-^2.b1/Dr+|AϷ ΁)RwP nnLn)d=k6K2V2h6[ ’eMWHpUfTkN֯ԫ0]dJMu`RWq{G 8$-YΝ;ӡC^{%z3;.KiSa,xu XJd4\-c25K*.`Vdd ;pƌn`U;Xf66e:0??y(uz-[yfnFm yGXd ;wd޼y*a5a6CU ^J7i,9YcDd0 GsǕ_|J XAd$Tݻ~y#90'LCRp79@nn.F?v֮]Kiݺ5vm,X&,kBI >?Y>>VBP~"GE!4{;tH抻zŲ yYgè{_|ʱF̅PRDE[L<-['38ONNͤ}I6U5+HPHCBQ۾ҴIG.;XVs%{I97W+eB٧1ug#g_gص2nJ/`9yJ ؜9ҙ@QE X||<? .`ڴi>|{'x|S9k|jNNyw GpșbVZb8S$\lkBɞXN~O;c,4-; 7z[>aNM麜#3rtJ΁yx|LQF+q,]BǍ=C:lKHJJynLR<.. P֬K˘ E~:HY<fx֌l!Ǐ;&UoP||#AUHXk)%w^:t 5;ЫW/Kbb"|̛7k ŦY3g_>ϪN}9}ɧ_ҁ-^,-oQ;~\Ja<)<=eTUydfXA‡:Y{ru(Ш̙\u{Qت^GQeoq=""E2dC aJh(^- 30nenĬx6-vr%X]1'q&`MعSݦM߷-99dݻEϗ*(`D\;t :kIUd!&MHE֭צ0cBф ETb]v0m<Ypc|-NclDc D23:%0_3e L&Nus4e^0dboI:6MO2լ[ҁ9[Xܦ$[lRQ Ҭu)nӦu`y-K?5nI2lNV֨8$~gbCElZ}iiRн5?|`,8{n;䊗Vn.+wK77,3g$d VeO3ET.g $gT8uJẙ3 &M >W7Vi`9͕:dv$øqRV 6a,ej>m}{m??y٭>"ҥ-2*`/ @[Y(*`LPΞ0Á SS#`v-:p)HO\J6V2 'Gٳm ʕrn%-YGЩ/m<0w>codX"Qyf" J0MP@qwm D|mN k`>}:#mdf zxiV2 ;[m.V vne"X^|\lj lʚmi1gXp;&^PƑI\ɩ(*`Ul3́yyp@}{ga-2ejl<ӎV38J΁6ÁنW ΅-mXJ ̛'cB~>cEd%W/rrMi#=%'9M%\"hݻ5vTA2iu[f|%a1OO6>#eE /h %D=/D\CLM*#B4XdڿxΝپe+.\BMZG6nޫm[0[h'aCYnn0#|^0EQ[T3f,Q۳ZDC5y1/_νk$x~$z >P4%/Qu`)gFζD<wVQ6m˧g3lDQ67z͵%1/O楾 MJ%Yd,1q`(UYΞp-2"B[ֈ2 a6̀MLh^[77$X,ΏRHvFyi |ؙ ¶5mW`a)PYxmk~5ZS{3֊eg1LN:{yXe6ƍ5kSEE 4i"kLN>-;z^K>yx qOonmDt dq?_cb$R׭@}<=e,L.U?\!`YY$9# @΁ݭNlk&A]=)R>*`Ulv^x*@ ɥ;v.Nڋ\өS"^M%] Ξ.ŸpBC nbdADޒ1=F)&Md+ @ݷO\Syf6ۋG877#uTE(X41p֎2v򤈅L&ޡx0د+qz'NR]I֭%10A˖_~F_95o[p XIAv=uAޓ ( ͲD*('>}{{3ց&'m`DpRSm\BB];}{ɚ:T%%$HlXfT+*`L׷r)Pf؜ +Ud ~ah^:w5k$lfV2" ? wo{B,)آ!*`K wyy0g̠m[h-sg!Dx0Xdv&YYVfu`p BB^Wi^EQG J0o,<\90ma;tH_T)Aڞ=L bv}Сp|a(RY\J^xbbbѣ$))ᘤ$*vJnxwja,KI<)"gT08 ڶ7n,ن"ZF_">۶9B,VbQQVJ-EQK SO=Ŗ-[ؼy37x#SNu8ӓ7|;vffϞͮYU-]*.,77嵳":!CrA.2ֺ5lj{).%`6;ɀ P~~~DEEbl1*قeA6m%CmȣB oץYi8s`(JR0ydZl'|3~Qt`M|ߺtAVLQע,>>h 0m4>=O MӚ#"HJJjErr7Y:fض]+S)DosӍ+wu[}=k:H_ܷxΨ Xjj*v;N'\.eee\v ˗i4MÅ eXžm)Yiy ɷD`>myee#>""U 5;~x CVV`„ /c}SGM!ߟB%~o-ʱLQGM!m7XXX׮nQNnyD""UX`Qr2 էK$_X; K(,""C fՊ%POou3;Y`]SDDbs'' ED>,0""2% LFDD#""Sb)ȔX`DDdJ,0""2% L0a88NL:%%%M0sL&$""#1LYnBaa!fϞ7zlFFV+,w.Kuf 0f.fjfj;2 XϞ=_܍ϟM#>Y 0f.fjfj;2 >~zdff[nqFǤ`q:""2bbb`ۛ}={i&cҥHIIiΝC~iF_DDԱ yGb̘1w֭Cff&Q__̛7jf{( X -2L=zݻw͛l+W`ǎ^ #55vN. 2ƶ3e 3#""jÌ:Jbb"aUG*))ɓ ͆]vzDEEtj"55Uu$/]>h 9aܸqxUWW#..#Fjmu宯}TBHHN'G1bux=ѷo_ʼn{ׯvG@@T`Ȑ!0`zBΝxǃ+t}DEEk׮ԩ&M'N\ݳgPPP(QG8NcɰZ#y/T3Sb ::cƌ޽{U!((˖-èQb x<ձ;x1зo_Z DXXzhl6n7xRTTT 88 ʼn8g@mm-␑=z???W^UQ/Tv ={vcʕGݑ:}DY̟?_u|yxb̞=[u/ 66yyyJs\~gΜh""!!Ai& aΜ9yD@xx81vX@\\eggc Ryyy?~<sc!11yyyr zaÆ@u=P^^~)Nm,0$%%j"99Yu˗/+p%h4͛QRR";v SLiq_x}*CDFF͛UG*,,1cȑ#eΜ9XX[[+RSS:֭[jfyH2qDZp8$77WIseΝJ:uDDDHLLzJIDDdJB$""Sb)ȔX`DDdJ,0""2% LFDD#""Sb)ȔX`DDdJ,0""2% LFDD#""Sb)ȔX`DDdJ,0""2% Lb'D95IENDB`lmfit-0.9.7/doc/_images/emcee_triangle.png0000644000076500000240000057656613066042256021431 0ustar Newvillestaff00000000000000PNG  IHDR<<sBIT|d pHYs  ~ IDATxy\ " . [YeTnY'SlO\Zm;YYYOY15Dܵ.K( *(Ȱo ag}ݦ2DDDDDD\. <"""""xDDDDDi)R#"""""NTu&%H5""""PVVv/%yKUK+^GU.1EDDDıxDDDDDi)RB]AYUEDDDD. S6){1/2TZ#"""""NKGDDDDD8-qZ <"""""\]\^III_PNV$""""r(iӦW*7mҥK׿EFF:uСC|9:H"##]=xp{ŋ:t(=zSN9;3#G+:88:; qZ <"""""xDDDDDi)\e~mF@ll4*2yd7/ ;Ñ剈\r =,]^zQV-rrrL&<==UES๊}P\\7̡CYEFttKh <"""""xDDDDDi)R#"""""NKGDDDDD8-qZ <"""""xDDDDDi)Rj8q".CDDDDRq}C 'Ͼ{0hРR#(8[o+V\ygL&nnnUȕ=>(<DDD0w\222hҤRxZj`و2nw`U"""""UO5EϞ=]H"""""ⴴsMf|Nxxj-22HG!""""s*?sz >}R#"""""NKGDDDDD8-qZ <"""""xDDDDDi)RzHIIaҳgOW$""""rn 6lDDDDDΏ\0FRR>>>8"3S&~m shl߾ݻc=ƴiZhJ[51m4V+yyyL[n4kNݻ7m۶utgԮ];`ӦM< <""""R(_vwpwp;?qZZ9ӦM3>'<qňZDDDDDy)R#"""""NKGDDDDD8-qZ <"""""xDDDDDi)R#"""""NKGDDDDD8-WG =sl۶ xWsaN:N+,?q*#"""""NK+5kAaa\1 <r!@BB-[tpEˍkԨrDDDD* K.e޼ya6iܸKq: <4tPfϞ2DDDDD6S y6myxx8EH"##]yxDx+FDDDD&"""""KGDDDDD8-qZ <"""""xDDDDDi)R#"""""NԩSܹ:000V$""""DGj߾} 8;r1ڶmW_}DDDDI Zt)/:ח-[nݚ3m4&""""NI+f͚:~8V޽{;(\annn: \W"""""W eիغu(\fbҤIr-tU l6es;*d2a SNHDDDD\qvjժו,MDDDDe`ٌ Y&[l!,,\&Nٳ]Tcv %%%ygÇ;jo?~^zSN4;;剈H5K($$ L&ZwutIՖ7VbժU$''Ӯ];FСCi֬+@F.ڛ0a&L`ٲelٲ'N7#""""EGoo}9NGDDDDDUSVVd裏%%%r~>S6mۧMFZPTUW Obb"yyyƴҿX_}'N߿k|\Rpy 9u52>EDDDā+WOӭ[7N8/Hv(--宻w}Hs]j.peذagW_WN<޽{ٿ?O=eEDDDD>_HIIaԩzo߾믘^4iaÆ RIdd$fFaXVT NSn]vJHH<ԨQfڶm{^?w ,[.PϞ=3g7l0n^\yNx JJJ壏>_`ܸq3{l>#jժ 禛n"00J+V8111xyyU-''&M0uTkK.ŋxb<==ɹg*+++stٺu+-Z_~s72j(fΜ @rr2ӧOg޼y.v'&"""Rm8 ODD#FgaDDD0l0mF.]())al۶;vI:uxz*""""R}9 ς &117vZ~ZL +1^{KVx\]]Yp!w}77ӓ2.]J.]xwqss#++KDDDDDӍ3f {^#++@zAtt4k׮ Д5(3\VVƌ38qM4n ..ѥT[N<1;ulfɒ%tMq,\͛7;dЂ_p~g:wcW_Ю];ZlyϣrbUmK[vv6%%%<#lܸR)--57rHFŽK/d|[ x饗]^z~3V:x].1֭[W\k>.vu"""r~mK[ݙ1ckcPn]f3Y6m,WpÍObDDDDzrrrXn ,^zILL M4C8T bۑ刈jf2eРAdeeѱcG#?????Wh̪R-Uux QDDDj7ΝG}DVV~)waÆ xzz^ r6g~n;gggWZ+<~o.oߏV-m̙3i۶-mڴaA]#UDDDD\Mvz)nʔ)S4hfb\\\upIaBDDDDjx*'|{n:\]])))յZj%55`Wrf)vq8+QF t:ޚlV+͛7Km*=Vy.#Oi-RQdd$.CDDک ))X/_s{+U}x3DDDjx5jʕ+(..V y8W`_o[ DDDDDKL ;>cиCF?m6c"""rb111OMM5DFWWW\\\^6޴T@W޶f6}l6[3mΟ f8"vq!nG#"""s.DUW-""""b`qW'ڴi߯rMS jb f@ZZZb}ǀ3sVPXXȮ]X,nڸϹV՚vA }<z(8&]J䤥!\:JJJ4iqqqdffҷo_zMhhE5^'""""՛UcV{o, AAAg~Mf+((`Ϟ=<#tЁիWSTTtܹucsHHH (( rDDD O5cfaf-\[l66t6ZbccIIIaٲeܹGҧOx:v{9v3x`|I9z(GgaĈXVZUz :^zX,<GFgـ[5Mvv3\7nLJJ 7n?tpE"""r(TC^^^F;iNsoo4cLȑ#4h_=?< .bqFfϞ3<Í7HRRO>=z0aƌÌ3?~<&g.''OO3Lhh(yد}/\\I >>Я_?>{ XcǎaZYjwy * ̞ǫJII*@S.M5OB餧vލj%((͛7ӹsg/_Nn*LII L&JKKOk;pss#++ƍ_C=u]Ǘ_~i<_ZZ1%m|,^m۶Q\\lIJJ [lo$77C= F+,,j{{n۷od2QN=J^^~o>0޸Ʋ`>s^xƏo\Dg$W)SO111YK.tr&"""WP}C?OZHJJ<9V АGhh(۷gӦM|Wo ƏϘ1cڵvwi&ƌC@@ǎwޡwh"7oNAA]vcǎ̘1Mc~ct6l~a2ܾGN{~H~~>}?03gdĈ`*ͮӿnʩSxDDDUVVV 6… [;OCXt)z"''Yfg|駕:Gڵ֭/~$&&Ҿ}{Zl7saΝL&]6%%%ԨQ(_M9u%%%̙3|&Mm{0;rSNСCF;w/N"55֭[Pvm4h믿Nȫ+Wnz!"""Yٺu+tM::Bm&gOoDzTDEEkIHH ++RpGKXX`޽DFFKpp0[ludff_Mpp0EEE3WWW:tO?Į]`֭xzz;裏ҷo_^{5HHHUVtl,Zui&Fʼn'pwwowߥ_~}SrPTV-ߏnݺU;&Mرc4mڔ{Ǯ]HJJWWW233 SNmۖ{e˖ߟh5kٳ)++ѣFYY1f裏RTTĺuشi>,;v젠!CTz6l 55z󉉉yl6_suѳgO~i|AJJJxG:u* .4YftЁkuVӷm޼{tX  cg޽ݻw_[,6llݺsI~o3ĦM:t(7ׯ'%%ثc7h Yf ĉt҅iҤ ٓ5k2zhFɣ>7/?HMM{~'0,]oR}Q|qqq!::(Oѹsgrrr8vݻw'%% ra.]z׳*8M""""ry9 Oii)tޝ:uꐐ>KڵIOOg̙iaWvWBBB AAA$GK.ddd#3221cǎ}{nRSSc۶mocL>L233IKK#((oΝ;m6JKK޽;ڵ3yxxsKTTO>$6\u/>>%K'0c &ObjJZZ:? HEDD㴁 ̽KYY>Vbʔ)t֍u裏6{{{yv曼l6,Æ oeL23g2w\ IDAT~mnfXb?[ɓ|L8yQn]mF:uѣ;<<<ʃQk֬I&s뭷}vZjO?Mzz:,Y7|777^y#} 2u]GJJ _o_~,[ne|' 4,N8oO?X,b9x .͚5.˗n:n&ƎKDD_=qFmȑ#Yzbw뭷Ä x d٘fƎŋo),,VZ3 ի1L NVV*?sK𹤥-h iRM(oXt)<|8Vr6$faz8W_}ywy+_p~g:w\)T>>deeC8u7￧VZL6#GJDD}aذa^krr2ۗ>ӧfuܙL6lٳlrJ.\Hݺu[Z :>}FNNޕwjbz};Reffrw3~x s';;yz-zqƕɓ'ҨQ\ӦM3>4l5s=xzz2a„3'33ӧatv^^EEEԨQ/WWWJKKK,l6sIpqq!;;LcXիF+e˖DEEQPPѣG)**";;3~V+:tN:۷V\\>,'N$$$(oo69{xٽ{qȩ}HDUi wX9jxwΌ3]6wWLJub2Xv-+=zzڴi44vaԜҜc XZZڳcbbbϸ[{2-޽(;=۷Ņ\\\vO>???j׮Mxx8l߾ &pf3aaaNll,u)oZjᡉLaa!{!88ƍsax rss7l߾ǏSPP@VV=z0V|}}4hǏgϞ|Wdee?pBM<~baȐ!4hЀc2~xNƌäI*?VZ|8w}76d呞;kDDD^^^lذ]vqRfM|Oaa!999xzzRXXȩSJլYR\]]7AyHLLbDÆ :KKKۛ76l`L"*N۵kyyy^{kUŖ3fп5kƚ5k裏GYY111ШQ#ƍǂ ڴisdzX,fR8\ʢ刈_T-Vx*'|{n:\]])))~?hԑNby,X?BCCΦm۶0g{ ?O<{fڵxyySve=O?Hjj*Ɗ͞={珍͍;wLzz:O#'effװuݻkԩSolڴ(c-##{bXoZL2___o5jA:u5DGGvZZlI-֭cv 5r$WZj1uTNfc͚5YY"""R8>%{y9p+VFЕT-l7`7oNv;77< sǏgԨQ9Ν;n:|Ih۶-P,88"Nf35k֤k׮[߿?V#GТE  2F`ۃ/±c*6vڑBpp0ѩS'.@͛Gxx8 44Ը},Ycb1Fxgdds 72f6mb۸6w\Ν #""RU$bccY|C_U .>>bz͛Gf>|8۷_|Rl6SVVv₏5_ǏsҨ[n69;ɄlLJ-Z… ?~ŋ3x`{9#PcZxw -- J^^̞={缧cV A B""""r&bQF\+f_8}5LooXr%=zG~<#N=x饗puub燛`ӦMUiepuueFK۾}ٳcu&''Ǐ@ii)uPn]bcc)--j-))d2SO1uTIKKdzc_$33OOOeȑ<ٓ듛ݻٹs'-[W6V84**o???6nH`` &'NPTTD^^PRRBRRǏN:DEEA߾} 1V6mʳ>Kii)O?4nnn̝;Fff&Fk`'55q!)>jUP۬·~H ?AҪU+yxwXx1|xyyxM7p5kˡ/66}pT78rܹoooJJJ͍|ZjE͚5&..7770̈́vZLg}ƠA5jɸqUȑ#L4_~֭[5Ø Wvs*RW|Uk4~G> ĉqqqM6<5UVѺuknFV\ɚ5k8rPޮVn]|f͘L&>L~~>2pAػwqF04"""HJJf͚{l۶ 5L&c_} 4lؐTBBBXb7M6lܸJz1b{СC^oD58z(@kҵkWx 7n7^=MDDDsM=[Ђ޽ɓ'3x`lߎ7g|^]v'ݺu3#,, (ֹsgPPTTDqBO1L֥5)ࡇ"<<ҢE oNIKK#::OOO?N۷/eeeڵ(. رc^{-}7oYf8qs2b5jDLL }c˖-4jԈ={/ҧO](Ȉș(\BxyyUZmؽ{7<쳌9nݺwBN_Xl=z8ЪU `;Ӹ}/׽#Ν˲e˸iٲ%fs?͆5j`ƌ$&&+PNߏlfܸqdee[VV?Oc2[zlƍ{㕆$Y={_d^yK:j`$"""ruQไ<<<*Yq>&L`ƌ9s}7裏k(?æ~,_O?vL^^!!!Unn.)))˞={Q1u>H#ȑ#Fٷo6maÆMnݸ뮻Xj{fɘf֯_o߿PZZM7ĤIݻ7yyyDhhhCC{N?TDDDD. 9*d27cːjj͋znd3~ixz3g ]ݻ7~7ҸqK~DDDΏVxn36[V3ݞÇiݺ5Gw!'';h"|A.\<']6|wvKܹ3;v BBBqhcYTT...{|\6p ' ++N:m6f3fbf,o[b;ve˖<ԨQ1cOJJ x뭷(,,p]wZeggWj5;~>4Þilݺ+V~zzE0ݻS\\|E_DDD.E–O nٸkX,ԪUky\π8Î *bu]R--3ny-̮%s]"S%1aG`oDE~x5JR(**ݝ޽{ӳgOeXm&??̨>//OTF5k<NNN_3vX%ˣCt IDAT8;; /ʕ+QTL>PBCCM6,_?GyB&"V9ٗZjE6m(--eÆ <ԯ_ϳM6ڵKIc`…+7|̙*;{t҅ٳg[: !BX!Ix)55˗/ӬY3bbb!((V )8y$ʰDN<'|/L\\&L୷ޢiӦ4oޜxHNNfѴjՊ5kp=p1z쉋 ?3ϟj5V"00퉉AQXXHʥX[6d^bȠ1ٳ׳o>6lHLL 111DEEVСC:DZZPVRRBDDL<}) W6^С+V`ƌ&;w>mTnTvB!HSeSj:SkqT*U[BCCߟ0~w>|8ɤ1`BBB59 4W^xbN>hk׮Jl͚5cӦMӸqcrrrr E`ժU4nܘB8@ǎ),,sFN>ܹ3*JI\$%7ƆP:vH\\4j(\׾}{5hƍ>|XY'w^nʱc]or5;i!BabcR=jV<<<(w]FFiiiqͦM(((aljSNՋ_ ::\8uaooOqq1lܸ@y}i233>z=ׯFLL ?<]tQÇO2~x.OLL t:rss!BQR ֕* 6FCRR2],22gy9s0c ,YB;fΜ9 8كEEEzF#[lh4R^=5jO<˙bٷooNǹsёgܹ֭3{l BRRR_]vjՊ-ZηN!Be$ k&#,1U2d7ߤdeȩ~W_}EӦMy?>O<Z+VV6l۷oq;v]v/dT*]v%##шF!//"5ٳ̝;Ye1s=ٓǏS^=ի]taҥL:vڑ̎;P3(Kbڴiݻb>L``:*K&ڵSZB!I5ڵ˗/ӯ_r^',M5jDzx饗 >|/^̠A4hlݺWWWT*Ҷm[֭{Coߞ}™3g%55T*FJEQQmڴ!33͛MQbΝ;Gff&T*%88aÆŋy'Yv-nnn2j(ȗ_~Ɂ:u*~~~,[sѿrɎB!wR={6o׏?P>ؙܲ\sIɓ']բVh44i҄ M`` NNN< 99zGll,=ׯŅCO݉_~!11Ri޼9غu+...xxx(lllBm۶Ašjߔa燍 8Ν;Ddd$]vW^|嗸c0xꫯ7 60e(..& NtDGG}B!B5Vٶm'NΎs2zhXtiM\p///prr4 !33bhݺ5{%66;yh4:tСChҤ IIIhZ>#.]!!!riFMQQ/A~HHH 77(c̙@ڣ/?O->|8?#F믿(|JF[!BUcѨL sqqa۶mdeecLf ۷ogL:zlll())c*67/&Z HOdd$%%%dgg_j RZ;~gZjoczYp!ZQF#JBRaccCvvN\\j<222ʽ&YYY̛7K.ѹsg̙CӦM),,dذaL2GVTTgzGB!Sj,/9ezXz5[?T˗yWyw۷/رcTdjFד`P{wپ};?36l`̘1?4 \rcr t:͛7GѨQ#HVVQQQDEE1w\Ο? ϟgڲqF}]JKK/9}4Pmۖg}@∋?cǎߟ3fG=aԨQ|8993|p~gt:] v>SUF !BTc-m]ӉӦM:MyzzңGpss^Ύ+|z ZM0[.\K/DΝ9v3g3gk׎|prr$;;իWSZZʼyXp!~~~8::Һuktٳg9s&ϖz ___ƌCNNQQQ 4i҄p̙Æ OOOOO?[oE>}>}:/?GGJ75U#B!jZ%<||\t ~WwرckTU+Fg}2e Z T*me/ݺucŊ 0&MqFY`W\KcQ\\\nnn=z`Nݹpw;wDrq\]]_>WWW:;^5jRspp`Ĉl۶ ?dʾ<0lذJ'IB#B!,޽;ٳ̞=Os]۷ogڵ WWW-ZDݱaܹ<#DFFboo_ɎVRki=ٻw/3gd„  իǚ5kHJJٙ;vqF4hj &sr e֬YtؑΝ;?MzHOO' ͛7>#>|"K\\F(55+W{G6mxGqvvʕ+4hVKVnZ"""XlgΜ!88 !ZxӠAړO֭9w\Mv… Y`Ӹqc~gBBB(,,d?~+W^#ؾULm_gϞe֬YꫴiFi]t;,~ONdd$OgQ&\>}>>>x{{sc40a@֭),,$22O?ӷo_Yn_5k֬[n?૯df3f TWlDdd$L0I&1rHڷoϏ7r~'6oL~ܹ3:u_~O>!//v1|p~'|'lْٳgsA FVXv-Ǐg߾}DDD0qD.\X.It6*P6;$$b6<3 #,,a!V-[e_BBB⡇TI&̚5իW믿Npp0(ݻw'..([gӺuk ȔXk׎:G׮]8uݺuテFei-tZ6mPTTDpp0O>$ }2M61tPȺua…[7z^>!Bq#53g~'N @͹{HIIqTuCRwwwT* ,`Ŋ^uJJJؼy3O?4}Q6 xʕ+:tqq %ܹ3<ì^+W2k, ׿EFhݺ5!!!bggGϞ=ر#>|ݻw+Vbb"OB!5Vxn7RT*666Flmm W_}Ŏ;ؼys:S|||*HNN17|l4 z3tP=Jxx8 oahZj5QQQ888?ݝ'OɁhڴ)}!-- +|4hvի?#۶m[nlݺ(1~x-[#u$=B9oͦMfZ_گUɨlz+3g B>}رc...t5A˗/'99dڷo;dƍ<쳸)kO~7vYj<Je˖;v,7oqƨT*@tt4ӦMcΝDDDн{wڵkC%99~"mlwhF@VVMm ,BQ&<F^|E,Y߯$:&1aaa7?&i]kٕ&=III@>7]v/dɒ%V7uW* !&JKKK-(**ɉE{n`۷~ΣRKdJlL[j\oNT𘦺(ccc),,~`Æ 4hЀ4BCC;v,P-[֭SNU퉋cҥуIHH 66T*QQQ㈋ ӧOݻ3a„rҩS*EEEqxB!B$liST0d233 WWWpuuT vv6޽;ҹsg6oC=DBB,[YfNhh(ݺum۶ >ϽKLL /_^UggϞ[<={ .p!x0 zƍGqq1垏i"O*VHOOWrJ#B!D]eu i @ii)G&33 6q8|vv֗yGGG%1o2ou ёǏehٲ%#ڵ1cOs1lmmw믴k׎-[K/0tPGdd$;wG!00Dȑ#)((`…almmt|jxRSSqpp_6=wSÆ \X͛ccSV`.))!33UI&)C!U}0~xwǒj՚LH۶mǚWL ػw/K,ApYpez)f̘?̑#Gh4``ܹؐƷ~ + %::W_a0t6mRԙ˫uz[zs.\`0ŋ;v)S`4-B!njdW^a 45k0tP)--‘ޘ)زe z*7+))Ii DדDJJ 4m\4h@^^'Nv1vX d9s&Mзo_._̮]Xv-/"/2?3)))L8~3pe%i'''GKHH ;;Õ*^G)?BX j*VZEzVW B!JVldg̙9sR^=/Zݠli{e5R 4Sܮ]puuI&p=DXXڵ###֭[Ӻuk%y81qٳYz5mڴgϞL>!Ce-HtZl#:,Ο?O-<<<;111 [ .B!Ͳ )ٙ1cQQQٕKͅ 0}gҵkW%1z%19z(3f_ɓ=Ν;E퉉}:u֭[jё:KG47߿T9{,{/~~~ 6ll߾^{'ȑ#yGؿ?:tP6T+6xr\xf͚iVFѥK;͟!:ڶ^fbkk[nۻ cƌSN1lmmٹs'}͚5#//$cVH IDATL uƢEٳgqqq,YDeccüy ** (@\r~@e'N… ѰaC15;&B!,*TE!66볳ʒ'OG\\ڵ C6m={6'Nm۶zRRRӌ7{HΜ9'ODѐc=Fpp0K.wwwwԩS9}4\p%K`kk2e -ZP6 䐓s_P!B!_(XL-lZPz6lF <==/I&|1M6Rhذ!~~~4jGGGJKKիSN%@퉏G0|ӧ/f,] &0n8ЦMpssc˖->}<#B!,M*<ȍ6ԩׯ'==sϟ/XtU}?W7(({H˖-?8|0)))w}8::ABB]ΎN:[cjyB!ҤS dgg+k]̇dgg$jQFo2oSvѣGٽ{7v}_V򔔔޽{y&))_~nݺѼys"##IMM^z\|YIh#B!j3IxjӆP>1m4j Ю];ڵk˗ݻ7&Mbȑ0h ?Æ #<>>p%HJJ"((^{ɓ'3zhԩz"008T-[\]]INN.iRT*mz%D]2m4eEff&_;::*w!BE;◺kUM*2Mi3ô?ϟ=qqq,['*ؼ "((O>`^{59t'O,kYٲe | ˖-Օ$j5vb͚5iӆ&MЬY3JKK-k=HwDy~!C Fs)-B!5IZ<2oa3 )(( ##ݻHll,9 6$)) .SO=iРFe=-ԩSt Vl|<1c8x [JZIi-$<*lllhܸ1?0 B!y!?55F/jtiԨDEE||G1A@ZZqqqxŋS^⊎ёSn:"###ȹs,-KIIK._Z6 !B($LF* ~'(((P\\\HKKc߾}hт'ҪU+;@IIIQ@YҥKlj'*.ӾA漽˵ĠhnXHa08!4= mrJ G$Bs֪8 .]VUYӴiSeMQZ˞x߽VXE5 -[Kqq1QQQL6`>-88X޼T_R1 B!D! 0|лwo&O-+V ;;@jjrSq& .`0e%!ߔQǏgСtڕ-Z;<ѩM/!Bq$*VTL:wLxx8...jeZu 1 e۶m >(KPj5iӦ1uT4 NNN2oVܷچ&mlB!VIcRĔTl-kҤ M6FlmmBѐŋi۶mdf/!Bq'IsDGG\sǁoBjovvrɓ'LMi4z^_n_r=z(6l`ѢE8;;HBBڵ#''rL(JFl޼J} 4Ȃ !BRT*øi퍷r; iAPPr D0lٲ1M۶m5R|}}jhZ0 0R$έ;wr9$$r+Ο? O>$+W$>>!9aaaY: !5 ѣG),,wwkײeK޽{-JT1!7oB!]ڵӧ_+NmWvLZJV10Z1 $$$KvvfИZRSSRRRsTl39y$j\K( .'{!B ϑ#G8q"k֬{UV)))p/V>ΔZozNʪGGGGEĔxyy)s5R{v97IdB!DmW3gЫW/݉7NNN`-mHZZ^^^Im$&&sUzrVj%={})C!BK ɓ'gܸq|rvٳٳ'dڴilڴ K[-Iű wwwZ 999*zbbbHMMҖ6PGo{n;#F5jB!5N&7r;6p3f0~x G$BTŋ/ȧ~J߾}e޽cggLe[j˗/gڵY8ꪩnkަ*LL4UܽmۦTr233yg,2k,N8;$B!,N%<7fy饗pppoiӦ#u6RY,iJk6;j|:]x+We` dٲe899Y2ZA*՝͛7[8"!Byw3JڨQPRhР ,dG_vnAXNc͚54lؐ.]0qDjB!.ucbcch֖3ffTn+V53T#Fovon:On0kĵȮպV56iqM%B!b ϱc a߾}t֭\cl4quu/IlsU.r^^^^>;*IU#VKRRm tB!Ym“h_dɒ%WUzLUN:ҹKֵk1bcc1 ʔꪘ0 *&ͳ\0>>UE Ȁb߾}PRRbhB!nUd dgƌ={~;;r(cJ<*Ty&))Ii8=>,h4\n_+!BkdcŋDGGuVIvvRh44U{~ZjEV<{h Sn[r%[ne֭R9AK.U^+WZ:!a5 Ofؾ};vvvzQ9NYZoooZTrꠂ/^Lbb";wcʔ)JYӧO'##DƌCQQCB!V[*hժ-/11\eF{@߻ŋʢwh4fΜL QF N_>W. !Α̡QҎ IoJ듛˓O>ɬYC&BL:&nXwb3TqkjTpBqW egghFi2Z>iii{L4ɂ !BXf~<ડ:yUVZĭ`ʕ+?p&MDFF>'99OOO G*ߛ3geYET!}fJ3[zMObXnRs޽;cƌQٳ'#GСC^7=#Gk׮Vz!L;6}J,UGmWbϭrX*Lbcce˗/'66ӢE  hs%66dΙ3g8s ?3\mzϯvk)G߾}oc4o[ B!DZڬPMU<(oŬ['OOzz:cǎeҤI꫼kEӱ|r:uD)..h4dRSSc:88̀1bE1ooo-ZĢE]OFFL!;$l2꒓ׯ:Ç/wΝ;+}C Ɔcǎ1sL&MD~~>=z 66.nݧ~Z΄^sϱBQJKKK-DmR,rWL>[VBG!BQg!B!D% B!ΒG!BQgI#B!$B!BY!B!,xdqdqgK.c. OoQ#ǩXn8jRǼzZ*ƚl[x+םoX]x#uTx\NNz-ZX2q :{{{|||,B!u B!Β r[j|ߐsTGm{{j==HW[_m67.!TҰ{]*4LjypvgP&ʻ秲[ڀJnv|٪kϏ"+eZjگɋN=B!7 kxB!uTxD6u#mB!' RvF!ꤥJzeݎt:G!B'QyT}꛸5iRB!9X-ZIwwfooOoGHBQEEEw}M6~`DB! Ix\e_edqQRwavI~~>DFFsEL͛hԨ#BagΝF bPjTnn.P֊fڄ477\굥[ʎy UVr_oCR?5NXI&ѱcG>|8:uۛ=z7ߐ=tB!]ٳ3gl2KR*6y{{["QOߨ#a>r_VTw?Lv6l .HB!SOx<3<æMҥ \\\#1h@RRR߽}R,KTVqcW3'DmеkWزe H! ` ;;WWW?~<3` vc,))ɄZӳq= 6*Quk;֨Q>$&&b4B$j%FTw%BQmuvÇsE G}D޽֭?0Vߟ]v]UDox;OUse3f>;U}Lbb")))7B!DW'+3e O?c>8::Ҿ}{KzCZ'''rrr8?x@=''d vGQcJc 뢬nnn;[M<̏WPP@||<Ν]]kHDD=~#Ba LK[ii2ZH&M5jgΜaРAFׯرcus*CBB ӎVu04lذ&U\S\\ =U|EXXaaaUVt899)NGAAUUS}3tg.zGyGxp[!(S'XnOJEzeOK.L<~֭[ͿZBN&TL͛wWlU6B!bC rssy_>ƍVYspzi^Obb2@tvt7<^'""B!Ui코)mv K.3kj鐄BaVYiذ!_|#F0eƍ7|9y$?< 4p5+77X:tp}LSݜ*0\9ZMnnra233j~` >>{{* q;ۗnݺY: !wLx\)S0vX֮]˩S8ʒJO-gJVZn}ê=zBR驛nudqMmu]Ix\]]ٱc]FmgO>$׿?~i\cwP^{|&7LC6Buu&KyXRRR >M MӠlQd"_7Op}qT*5k>͜TvCu=JZff&NNNzΞ=K&++ m- IDATL+((}~BQkԙ5<̴D+ovv6(IO?Ĵi0̚5 ///zAoxnӾ.{Ȧ}HZZZ%''Q͛7'33gV;6G!A%))))'&&b0h4@Y$?sa…7Wu^OÆ ߥ\ MӕV鉍 DFFRXXX(lNc~]AA|^BQHcARRRBll,666j5jDzzvFII 5"??$RSSIOOggg̓O>Y HMcrrrprrV.55w؊SڤS65,F٠ܹsdggV ͥ6mڐLff&s=V)((ٙ &ɏB!jIx,H3vX3<7ZZdzݕ摑dggӼys<==Qz*ײv&eF~~~dggs<==qww ggge^///IKKLJ_>vvvWggj !B yEq}f,E FcGMb7$j9c-1K<&jԣ%bl4邀R?vXҎQ}]33y~<?x>5oܸ.]A~:t(.͚5#55$jEr߿Oee%YYYbbb½{dƍh{{{<==dRZZ 3f :N)Z ZS .AOr9eeex#;;@zn߾Mݺuqvv&33uR> ߿O (++޽{899aggGtt4꒕+7ТE  EhЃ}}@z~$k֊ @w#_F:~k$~WN%Kk.)((ؘFIzallLFFrBFaڵ۳{nٳCћJ Dlmmٿ$x%g.kkki 777RSSl!}w)))ۓJ^^^-۲eKkJJJ8}4nx{{OF&::ZAڵ777ك-ZiAawl2͍:u<) %A=RSS9u9s8ѣ?3١T* ##񙙙@mAcXd +W$""ŋSUU\7nD6 uov֭\?ZԇJe-uKMM%<<\]ʪUpppɓdggsu---Z8q۳m66mʂ HMM͛©M 1g;Ʊc$-ߍj.kK+wޤ~Ғ5kHQQd2;;;.\@qq178MZSNX[[3bNJbb":::@uRĉQ|'RSMPTًET*艅>WNxx8999C->}:ܻw)eFakkKFF|G̜9^zQVVF@@wԯ_Ȏ@ <?RP(${Y??u\QQ$Q(ܺu8͛7';;}}}D.sNyMRyfRRR>R ТE>|8#F୷ޒܸjcōuS45m 9~g2dd2nݺ]pJJ ?GQF8;;SRR\.端KKK6l3ѣ㋊֖i~r )]SoiӦq},X3@ ѦrK}hߔ"""Yfl޼ 6ЦMHNNۛ~pUI&l߾MҲeK.^ȤIFOO###v͆ C&abbB9r$ [[[˙9s&O࣏>bĈm6^{5^}U4i +EZDt铗'}֦.KQuc055֬YÕ+W5jf͢K.ܼyf͚pE֭k׮ښ޽{JbԩlܸΟ?Oz7oiii`aQ,xb 0@jժg8@ h777̰eΜ9䄷7 67 ((k׮`6mʗ_~ɶm8|0ӧO%@$aoo_ 8v|TTT7ЧOd2:::ҧO Bxx8;v` QT_ӧRpuu///.]Zرcy?177ʕ+ ɤedd<Լ4-- 7£MknpφNQJJcŅ95Vzw{ODD+/_>S144ח~@ K#xݻGii)Ҷ*)矡f;;ZiZڅjPUUEYY۷g͚5L}ƍK4m+@ |Ҿ}{ZlѣˢQsssΝ;G^ 60k,~'ڷoTVVbii T7<]ի9|0Æ ӓf͚i&,Y¶mPz;wJŹs礞=ѢE vҒʇiIKKC.cggy2  &99 )j7b,--5js5&OL6mZ|L23fױ#$$Dr!##3gfu@ ޖ 67p)4i¥KXv-_;666(r8[nq9-ZTˮԔ H C&ѻwoqwwGGGb)5mȐ!deeqǎhpqqylGammX繚zG͛7' +++166f…WOɣJj5YYYԭ[@[%%%E>>lْrssy׉gϞ,Y1c͡Cc8@x Bm@*TOOO`gg.r 333$G/֮-imU*@_GRa8uԄΝ;R-Zf$$$ T {m[=GGGiذ!!!!R)++ JKKIJJTj۲eKRSS1337 ^L //IHH~3|pVX+pssk׮$%%qʕ$x"""رcM4رc<:=XcccØ1co?>֭clٲq쌉 NNNҘ4@166&22ɓ'Jfh4xzzbooOEE߿}kpEf۶m9y$F޸r (,,쌡mB 55k]v!-jw?%q(AknmmMxx8֭[3sL?رc000:uꄳ3nnnٱcGWWW߿Oӧ7oSn]\\\HII!==˗3vZߡ<@@Gx!Sڎ?ԩS͚5cݺuRرct z|ڶm˵kxW>>ՊP #-BBB~I@ ^\^(ŋiРdffrQrss7nsa˖-,]*emZEP???ܹÙ3gٳ'L2pArIJzz:iiis֭~:tcǎZqBh4RWǡh)((`ʕRGRR}d&FVpttӅٶm .DTҴi(-ͣ~g_|_|;wػw/1w/--/swԉk׮rJj5 ݝ-Z/[f?^rm$$$t8s ڵu>̝;BCCs?֭[Mu?UVܼy\[.|W;vRz-J̔+,,RJQ(8::Çϥ4޽{K![hAdd$W^ooolmmڵQ(ܿ`ƏOÆ y7ٶmdq]RRիWbcc}6 ~y7aS[ii)ƍ___Zl'|ɓѩK&/iApp0x}mvJ׮],g322RW Zĉi֬re޽K~011LJ p]Ƈ~3s_ӧOcmmM%uCCC˴j !::M6vZ:tʕ+x"+Vxϟ}@ Ty>(J9F߿ORROΝ;yfhذ! ハ6mBV֭cؐMG4 eeex{{sE7okٵk̟?===J%wޫ՗>[ϊT޽ M$r R ?V>|7x???Dgϲ}v;<==t0"^TՆh4*++144qrrԩS|7uV9{,?^Jͥ^zTTT`aaA֭)**"""zIQDž 8s yyyR###֭ qZv<<d,--4Ntgp x)OaٳgYz5-bȑnZJS۷oݻw]jjRSS9ugϞSN֭[ˋsN IDATQN!//Rw}Gjj*\رcÇڴGP?.ټy3Ç_F @GVꫯ/pG?TTTHӶm[#GEC)]Gە^ˉ'غu+kܹ֬s1|WL6PFEYY~~~>v^̝;/$XXXT?~___lllߟ1c```@II 7n?DOOD 7|#-rk6Yx:u +++uJ2&Nرc8q"{@OKK#00ٳgs5۷/9dĈ믿ҬY36nHcݻw4^{M;E g?Rrmۆ Ceĉъ7np&MΣF3pvvĎ6MyժUY'һwo.]ĶmpssC.?\.g…S~}J%eee888I޽)//GVӥK;wGJ󈎎FTGAhh(qqqTUUKYYѴn)mڵL0ƍ}vӧرJŅ 0`cꫯ[oŤǏ?Rf͚?$O8AFرc:::w5..ÇcbbBrr2;viӦViҤ k\~}}}چLJ/bjjTfii)()m@ Hi&&NȨQصk7o$66ÇKM4.j.]\\?-_2tPF;vH3k,>iժYv-ҷo_i!׸qci.7DWFPTx{{SXX7oe̛7l6mڄ?.\###ƍǎ;>}:C ӌ=777quu%%%_~&ww -ڵM6L8m۶q<==Q̚5qL&MHLL䧟~A̙3M6Igȑ8::)åEee%}}}t那#ܺuC%Q@ Z^>퓊/0d)ƍ̛7$GX9q111ڵmDTTEEEЯ_?>C[Iϼy8{_vdlڴ GGG~m mzz:9sm۶agg)//g̝;sqiiLZMXX{FRr7S~- ѬXNKJJZD'@ ZJ'((W^yo=͛7&((,2@uOqq1&&&@u9999(JBCCiҤJbnFCn ZիDDDPPP ־uoڴ);v سgJ;wܗm۶¢E7no&&&;uV<<S>3L 6Ȋ+ݻmSSS***HMMdddˏ?HLL Pm5> BBB011!55LzIll,pI_$&&zQ|Aqĉi߾3@ OE?999=z@@0Kꖖ&-(..Ãbˏ?_u] E3f̠@>fϞMdd$CШQ#ZlI\\)))DDD_ШQ#8s k׎Lƍ9wOjQvZL޽'~~~={wRhԨgϞTJOO GGG4h 9=xt8xxxk.СC$&&7`ff+rR|}}S7%Ë ̙TסiM8r9ZhL"95 W| }}}tttEѼcgI^2RҥKbJ Ǔ@ xybQZj]ԭ[G>wJR_յڦ,YŘL&C&q:wL-ضmN:^-[pB HLL$44LʀHkBqh4 SPPɓ'122z᭸-ZL^^~)ӦMN: 9w 66VJOOjKY2<<Ltf48y$ sssÒ%K㊊(!;;tuu)//]v̙3'''K\]]s:zDisч]tiӦ=<_Sz< _ sαsN)u {TUUq'ui9ܞ.uONNFVκuaՄҠA.^(7]oAA GfժUѣGy&+iiiXXXH59+V̙39󖕕!HHHCPQO&M޽{իDFF2h 駟 eƌlڴ LFӦMҥ 'Of̘1C6ŔM*iFȗ@rVZZJqq1SNҥKҮ];-Z>1&&&I.l׮]RЎ?NBBIIIܿ}qM鸼<;hŋ}Q{ڴi#]˭[$ ~_kS ѣ-̛7h"#C2كZ޽{4i҄H}{LMMڿ;wpUZnMnؼy3x{{ӡCBCCٹs'rWp V\.  ԚwȔ@ '?ӽ{wfϞڵkN[RO?2l0d߿4oޜJtttPՔQRRfffHAO>Rws@ҒT)'Ns]Л6m{Gfͤ4___(--N:}>dffWnDJJ aaa:vȺu۷/Gy???ի Mg8Ӊ 8c[oѪU+:uĬYhi@ iA`` ˗/㒍? '333)Pӑ,##C X[[۷/FFFر{[oQQQ\.͛.\ ??J%u֥_~߿, Nbd֭[GBBL:233h4TUUIŨr8ڴiCՂH.Ƒ#GpuuƍRaƍڵ+ׯ_sά^SSSرc>>>R}R||TS^) H2JKK)--"E$$$ЪU+"""QQQQqڂ pe)_~\bbbpqq!::?rYڵktЁ2ӓHO~~>899akkZښ<$'7&<7ndÆ rI+((cǎO4 B95Ӯr/**BPӧ ʊPLLLYxXQ"cxyyIٳWWWZj;.˖-#%%JE{.QQQRUUf(III]I&@u;Xnd{]ZZʉ'f۶m$&&o`kkرci߾=ݻwPX Pff_No% ggg ٰa!!!ܺuJxWٸq#_}RMЇ~HTTwo߾ TwEҗbT@xbsss~E4)G7c͚5|'4hЀ={Cxx8NNNܸqC:ڵk4jԈ*فɓpU:w̕+W999J.y3g# &Bŋۗ{h"|Mߣ*xw?>L6B4 $&&P(O?ěoIݺu),,ǧb xE@P qrr3cggرc>|8ͣK.~zmJ[N_>ޘKigeeecccvEAAܽ{F㉉k׮S^^5k.6m*̀={Jmذ!}_|UUU899HL233m4o###/_άY?>+WҲ} ɼeQaNNNsR"-- i۷9r$.8;;cffFff&۷F_~\KJJ޽;;w~///\bdd>III̝;%KOAAdX^^CBM1h ˊ+<@ R^YtRSSqss# ckq9yLUUG븺J۝8~8J-[VqppG=Z*@GG,,,غu+ܿ7SׯR|ڃK.p2"<==ɣѷo_\]]?~ 44.]tR֭o ^\JKKIHH CDx 5tuu111AwS^=իGTTdee3gϞExby뭷8s YYYbee>h4j5GGGi*++"<<,YB.]8/^Lii))))tLFNNdff/BRReee4jԈr=-[F5j%%%1ydkIڊ~:zai``ipuu?| 8y)))DGGӱcGN>>R#㌌ \@LLd^ === @qq1˗/'''%Kp1/^L@@ݺuc`ee%5%ўCCCrrr$c? oA?]k#fffRԥH*mذ!d27n%7ʊ &```+033oooie$[|߿?[II vvv>} LMMŅCѭ8 w^ƌ n߾Mtt4o67n 99{{{FAꫯ ޾kWFa,X@(J7n+w%//XlllPTh4HLL޺u^zHΆ.\}d2 4'NL\\о}{8p ۷o'x!!!YOC 3Bnnn$&&d,,,(..ҥKtZMrr2:dgg#IMMRDJqKQ3}LYY~!=zwEP.w}`jjJf̀jg7}}}T*M4Ņ>}p),Y>:::R A >>ٱuVS( 7nPIr@ BM(JiT@uEGGCRTTĖ-[ҥ ~~~\|oo Z߿?2 ]]]ڷoOYY2Ym>c3'IRNSTTDTT7o$!!VZIriPmpu)̒%KpqqԔPի<# bĈ 2DJ;>_ݻw'88ccc<<W^۷q"##)))AOO|}}4igڴi|'ǣ۷/J;;;!~^b"ⷢ&...^I&ٳi֬w%88]]]N<ɑ#GS;vٳY:?2Y L]Ɔ ޽; 0ѣGS~}̙þ}֭/QȐ^ k.?@  :UUUUz3:::ZtYOC%<+&-=[OÇyf>{QN,m}ZZKLJKK"33‡)D^>Se.mYV F[[g2ydBBB@KK8,Y-oTPԬYf͚+:'!!c}jߞg}O+Zkvvvxyyfoߎ)$113gΐJQv*wY_Vwb-q'֒DNN͛7GPիW177;w HLLƆpI6m͛ٸq# .f!Ci֬ ܹsUAPgxrssԔ4FEqq1tڕ~~t^6u-''GوFOOdرccƌۛuO?ѱcGaXYY &SLƍ9Rϓ #Ơ(ɕR\͵H,N'##C:}}}߿%H)Iyyyr%455ۤNJ+ gɀɽ\.acc#f~g*(( ..;wPRR€8{,gϞkkk GTYwQp2c!88\!55UJLMMETOVX`;vLJ7c B=ӧTJnoCb.]$}GÆ +pDGСSL /ZӧO{۷cǎѥKͥf͚ٳX5k`dd'|>C ~cҤI䠭Ç=z4۷n???\\\hٲ%ڤR^=@ucbbb uJԩ*+}iGZZR?[nѳgOZńҥ jBY|93m4֯_OƍeΧFSS >#Xd }δhтݻ~zjժ>@IOO'** qttDTEJJ 7&--.]Э[7ðaØ;w.#GI xF999iӆ-ZHxn޼YAgɓ' $;;9s0btuudҷo__ˍurrTT Yv-ZZZhhh Rn*ٳgYYYʘ1c C.ӷo_Xt)=={XGjj*.\VZkt]꟣XXXPTT4mڔ 233UFTP?N^^tޝ?ڵk5-bO|||-D 9122֖CǙ3gΎׯ')-- MMQdhjjGFFŤQZZcƌVZakk^A1| T^Ѵ .pM  Tf._3g&L 44.]{I *dKIil?fܸq۷T֭˃:t(/_/ʕ+ܺuvڱzjKpp0EEE[[[߿OvvƦ6{%-- իÇi޼9oߖcbb6\*/==+++B5>1EFxuY&IIIйsgnݺgϞmۏ9{`AaURRݻw'??_|2C.LNXf =z~Op5kF\\ÀAAb/7vΝ;qttM69\9EEE4nX*E HEpp0|WҳgO ƍ 0Pn{&>>o{{{d2<Օ|"##ɓԩSΝ; ŅB̙37VZaeeSNeӦM\ʦ?722ʊZjQZZJڵѣ :uL0۷o LFVV5ĵkאdhhhp>tuuׯgΜAKKKnݺ5hiiVAZUigtЁJJJHMMʕ+aϞ=ԯ_FS-.--/ܻwya``EFF>jlݺU?*##`APſiiiJܹsܾ󉍍%::}}}iH{닕cA=ccc1 of͚yf044$< +++^Zn\t֍׳aRRR(**Ϗ/Aѹsg{.zzzl2  ݀>xŋ3vX)8 Zϟ_Ug/_·~СCپ};C T=rj֬ILL :uٳƆDJKKQ*RCCCC144dӦM4oޜSNQF e…>}o]]]nܸނ{m Re#GC~سgPUb۶mǛަR f6IIIRJ4kt}N:Eqq1zzzdggvZ.^ʕ+o dС(J]Vnɉ`IIIRմP<=="11`(JrssYf $&&?퍞b֬Yq}RRR(..*-Y={{n^:(=z@KK{|rسgܸq .He) lmmNJJ NNN<|ǏRN:ۗ>}W_ѤI>333iގo3gΐ%}ݭ[7 PTɀ'77uֱzjΟ?ψ#عs'rb)-;;;ҪU++xO/U.n\NHH\LԩS9s&sEWW++Ǫ]~6mo>"##e1m4~^J5S( r9Ӽysڵk )\v 4iʕ+ڵ+T:wϽ{@.P(Y&r)LLL8|pG*}R@CC:pvAnprrb0gΝK-~m8v^[n{___)Q;ׯ_?dĉY Գ?f]6 ---JJJ0aǏ'77ӣGlll >5j 88 <\z'N$!!-[rYo.uwT<<<ܜ;wG˖-gŊ <|}}ѣ&L(WAEB՟gff&ԭ[P=}o۶-6665RD.MBBhiiItvv&::ZjtP(ضm˖-ȑ#5~ 3ӦMcȐ!RPP6%}۬] @G}γeڵ7o!C*< >>\<;%l*\rr2fb=ZZ{n8y$j?T7y>$''ӧO///G!55U.]ĥKPrvvf˖-#NNNcggG6mY<233'''/GGGغu+&L?,[E}sT)~eS'Fu055eС.T/ԩSWWW233qssȈ˗/cll̥K&==>KKK155Tq͙5kjՊ{ooo&L)L2Yfq=@ BOYlڴӧSNJKK9sLv>Wd?iړ@v8wߟL.^իW3f fffܺu 222t.\ 55www6m SHNN_~>لI3DPUzwXz5^^^ݻ333f̘A:uޞz߻vҒtƌƍYh.\ۛ]r!uFÆ TeǍǤIl:Ң|w2dgf߾}ܸqX%++cnnʕ+qvvp'hҤ ;J6lL:q+bvٷo!!!Vx7ATƣ4lؐL*͆ dbccL&O?_͛رN:?177?ҿҥc1+᝗Gzz:O,Ԉcǎd~ijY>dʔ)8pyfr9888 8}4'NT Oϟرc+>"O½lmmJ \Ǝӧ111?=K,ȑ#xxxpI puu>B@___Jmڴ)ܾ}POOO숋RۄkРA?׮]#11 /Ut=ʉ'7sss:w̜9s/9990n8;wNxx8R:( ÉٳhkƖ-[033#==bRRRҒJc߸qMMM dժUl28z({ӓbE\zU*;rH  gϞܼy .0vX~G @ff&?3|d2)M999RMz[Y"z)bΜ9oU$BuW=~[*'{J/<7eU7|/&&&n\ƍ̙39wΝϏtf͚֭c͚5̚5.]k.bcc|ԭ[ ZhADD|VVVxxxI׮]QZϣ d߾}IiqqqqK>x{{{y???:tĶMPë|ȃܜb"##{.sulmmLbb"r =Bڵktޝgdr9O당9qqqJ>MMMrrrhժ;wUݻw&Æ  ePW1@Jʕ+,[ ggg 8<3f̠R+۶mS=)mÆ (JƍǙ3ghժ/^DTbee%=VWt7nT>>93~x.\ǥKXp!=zbquu*Gƍ455ꫯزe ÇnݺL8CѧOINN.7Tխ[F0tP.^Haa!xA*TϪ86yd,--6m}ߟ5jp fȐ!DDDЧO.]ŋUQ"-[6YYYIZZr---F.\`ȑҾݻ7`ggGHH4nܘuRn]iO?ĉ'Ԕ bkk˟_|ܹs}u> g{6mʲe>|8M6E[[6m_0sLwN||<昛Jqq12lRRR 44TZkCF;w.͛7ҒpήBƍ^e B"*i ///&Mʕ+ٲe mڴ֭[deeA۶m`Μ9͛7G.cbbiii߿dhhhЭ[7ƠՓ J\d5j)))XYYh">C'gfB`Æ iӆE{un8c@D7oޜիW3o<={6>>>'вeKO߾}:u*vvvd888ЫW/@5Zvm>SLMM ~{Rd  oV# 6HIII!??BQذaNNN^H9By{XYfc&OL&={{bϺuլ>}:3f 11;wp%d2%%%XZZ2|pꫯ2d~)ŀ#zʕ+ՋѣGN a߾}hiiŋٽ{7VVV~ҒVX!5.Ab*i^jra?NPPTUy%Kʕ+Q(lڴK&XZZNJJ 7o$<<Y0.]Dbb"SĽ8"""СCkFMbb" .={RPPСCIKK_~3ydWWr@H0sss@Krr2gСl۶{Fqq̤]vp=߿ORRΝ#00tQ*XZZr |||~A fmm]a_AV"੦˥4iPU6٬^ W^^z4k֌!CBAAܻ͛wnݺFHHׯ_N:4nLƞ={5kǎcƍhkkb 8.cǎ`֬YxzzJΪUBOO/_̙39x .-Z(i oT@R ر#?mmm'V~ԩSRXnfffӲeKȁ3fgРAsy|̐  x罱WfĈl޼Bۧnݚmέ[Xr%fff]1bk֬aȑ,Y۷oG||K.SN8;;=.\w$%%l2bcce 0}re\]]qwwݻ4jԈiӦ (,,PSeӺukIqFF?|<2AAx>"^d}+\x?P*ӰaCU簰0/_NQQ\vʶmۤ󶶶KNN;vÃd2b׮]#**ڵk'2-[2tPzEWW]]]vG(l`aee%<pB)-aÆ\p---,Y/ $&&9'N޽{\~}`ii ȑ#ԫW' TI"`sz&'۪ұ 8x ֘`mmħηnАxj֬Itt4fbҤIQ\\L͚5 222BK5##ǎ}v122"!!/@&MP*pCddYYY$$$H}RYIJJŅ5kၗ |F RPPիWСpY "##MͩSO066wajjZèRrrrά],X mӫW*(PՈQ{Q꒗'N~}̘14i҄? OOOIII HLLDPЫW/ZlݻwiҤ ?#-[͍-Zˎ;~(6l`ڵL2Ewxx8l߾'N燙cǎ%!!LFBB&&&̝;W{dgg5k|SZaÆDDD0{l~YbYYYK=y|2Ҍ⯿ʃ0`JB'00k׮ѲeK鸕5Mx~zzz:th6o @RRIII̛7_~ [G<u\YXXVnKii)V>֖ӳgO>S"""(**"77ׯM\\={5j0aMɓ} =ʹsӓ'IMMN:ڵyq,--ӣ]]]̤)>}ܹs),,$44mmmJz6lիٳ'7n 55ǏBPPT `ƌ$%%̫PijjJ;7oޔP$ݻ7w%$$(VO54xϢ;5jԐu?X]&բw}WzA4jMMMv7|Q(]0iУRSSiРd2J%q&11&'O毿Օzꑖ'|Bpp0/TIbΜ9xb\\\۟-&&&DEEѦM  xU*S$%%Onn.! EGGbUNN999gffŋiٲ%ZQF瓑qҥ ;w@:~Xr%fff 4  C__˗we˖- 4?///߿ˉ`Rz(L @VZ<|={6;wdƌݛ8iG}1RR@@ԇ*,,ѣGuV&L[+ ѪGA*;T#xrssַ~TTJ+---uJZ4{lVXA۶mr ]ta…d2֖;ry"##㦧Ӹqcٽ{7...\vf͚1uTv͔)S7nL>=zKVVXZZkQ211 ..f͚ѯ_?eܹst)QFxxxvvv|wPvmqT1.)) MsAUO5onߏzefl޼uw^.^Hrr2SNNE{lv\=ִiS֭[_P(4h@KȌ37nYZZJˣf͚i6HJ5m&&&ԩS^իW9uׯo߾r"""[. 4`۶mhBoe+M]XX(S) U]xJKK)..f#|||ɓ OKK^%'')$@\^mR𓕕Eff&>ݻBZZPPqYkLc߾}pBfΜYQAx+TtڕaÆ1l0VX˙5k| ۶mcɒ%(J6n(5*5?JlА]cmmM||S^R¿ou`mgg'U[366&33SԩKߞ8BաGӦM{}?@: o?oR4oޜ<ܹyw:u*EEEL2O?ѤI mADDD"o!v 66VZ_" E x9cϞ=傞7n… IOO,^BULcWH>VdƏիW TvUr~ohhȦMeڵ7olG֭[L8SS7>^J +z_kV^TUxbL*gvrssdڵ^yaff*Ty75:СC~_T-}f͚Ƕ8pիW*PUـ, 6mөS9sF*{)>֯_XT*_z Be5|r_߻w{{{111tl2 gggk##ǶQ,Uշ(PiUTAOÆ 9v'O,̘1nݺ$ͨ[.2L=@Foz<_pJhԪU^AAw~ #A82RA 4UVѠAٛ P^= @˖-CP`ooeE $kKxY^jrk TWC1sLڶm7#Gƍ,_)SUAAuUڞi*Ǵiߤ*n 6 ;;OAA7ڬyR44T1СC?FDGGJ͚5+x   .*ܹs!˟``޽?>Si   O x~Wf͚E 壏>s)m[\\L&C.WpAAAx+W0o<6m)9vyyy(   [Z)))aڵxyy)..VZ[@ԩ\EyWe"-uyV򇸾UM*JТE 7oNII w믿_e֭sYΝ\R|/UWT8*yy|Ve=5WqmW2Ve}37;:x+9{7t>͇ T*9rF1tPr9rc2zhqttJQR  vOnn.֭chii1b{eqMlmm+b }* IDAT  T*uV ʕ+˓MMMXv--b˖-899Uۻ cy4Uރcū22 *︠M2Aբ,uJJ k.BBB8~8z-ɪeiG9>WE{S]\o;W~ކ׏P ϣ,,,شiԮ]>}   U[x@4lؐrAnGAAч ==Gr 4hPév233}mll\A#KqqqU'_D^^^uuu_x_ PUTԔG]C̙ T8^j֬J' YIiD#  B9fmR*̎HkRZqqKMcCWW_O Յx7n& AxP(^jNY7AxܦMt8gر德b LLL*hd ^|H7̌|ikyyycdd T%:ubKfx͛W#iDS=+n^%ww 2 GGǧ~^4MWWWWח> câ*7avAE6}OE25JR̲P3-RZi[* "(> wNXVs]^ Ù3~GB,mDIHԖ[`%$-~@HHHHHHHHߟ^{ tQzG%!!q?H H1 \Ȅ=;wZߤj qqqǧ!!!7͛7bߣyήC-DBBBBB! ' .дiZē򯚋>,Ο?@PPP-DBBBBB#  dƍDEE1lذ|ԩSȈ VY||<|}y饗%$$B߄P}>疐x\Pdggset:888P^^^31ݏT򽛟O=(..FPRHKK#++ Z:N-Y$$$$$j:/xRRR={66lϏ{ׯccc5LV#C*Xflmmzckk+ۑxȘ^G.#˫G VKNNh{{{{ ǁ:/xz=r8wfBTo؊T ++j{k JHHHggg~F#WqvrrƟXŖGuIHHHH˰a(((`L4~m۶Tko޼)iӦC}.JE^^^5 ڕ+WDW+WIIIFB1ˊW?{ T*}OBaRjCff&P@acc͛7?oYjMnn.cjj=:N'VՕz_jå iӦ1zhy틹9dʕdff֚h4dffV[ϱ4._'JRLzJMA(?B#//lt`ccCaa!&&&xyyڢꞜzaaaAt`oo/ 8&LylԨџ>T/ӂccc\]]cL2+WQpQ*sV/±6<=# (G!LmiiE< b#77\S?4k֌ǏSVVXBDԩSkyDO.uJ>}N)ڵظZ ظq#/\wwZ:Bzil45 ;[nQ^==ŋqwwۛ'˱ ??s9{QH =+]IIIbҜ$`$5؊qqq ""___5jJ"77ƍPEJJJZ|j]x"Ǐ'%%gyqpp ""@N>M&Ms֯__<`Wzdc{̙9sx;88Zˣ*:V^ """j{O8uFܹӧNG;L& HMM;;Z߱~ 5oդ.Qڵk=z+WЩS',Y"~XW}V/++Z.U5 ౶'X:>'! Qz}Ӊgtke|MAWtuΝlݺ\N۶mWWj}yT $,U՝k׮iӦZQq W{xb'66p~G5kƦM8vP=rz߾}tܹQ^JKK###C\QkzB@P qvvFXzPoUEw ǩ]z$۷oT*dhZhР͚5}[5AbnnNqq1Z\έ[0 @8m*XXXԺuXϑV%$$:uB1n8q2ѢE ΝKJJ ϱco߬dO*j#?d[nGFF@BB/_^^}˗/ʕ+|#,$&&T*YRRRDˊVVVTz'y7Ѯ6SJJZ7ߋQQQzڶm\.'%%P_εkh޼~%__nnnlgL>'NЪU+Nzz:r-HMMkגB߾}qqqAq-ʺkߐD"WGSZZ ~xyO||<>>>tI R FFF\z&M<B;]DBѪ֬YnC T?rHT*]ϓ۷/%%%bTmZZ* q^?Cxnpss#֯_O@@*YfuVr!ssj)!{n}Y;vl-HBB ;v0d  pqqd2d2~6nȚ5kj3 +!33B!2.\ې&:nݺEdd$aaatԉ0f̘A@@DEE1k, O>XZZ4A%IH< N:Ųe˰g͚5OL``NgNc3f ٴj 777.\޽{ټy3rSSSSΏ뗐۷/;vaHHH< KSTTĢE믉bĈ1 X[[;ڵksSVmU$TmݺcǎѧO|}},--qpp୷Bq?Ɗ@_.VXbɌ3nݺԩS?>7nʕ+nsssׯ}8ѹuvM~7z)))\z}d6I I%U233Ūiؼy3&M[vJxx8͛7SSS㿦jWaaa!t:ϧ~L&Օ֭[3dRRRHNNСCbg֬YT*:wLLLyy8CnnnqIRXZZwamm;v,/"?8)++رclٲ}6NoQBѣGOx饗;v,4kL|lhhh ۔T]tX5jĀ(**3h Νˍ7PT 2'O2~xZnMEE&&&p&MT7obee^JFot}j5}L6/.5]+IH< li03gvbٲe؜ի899U7N:1~x *mo@uSXXܺu BANNN+  QmRP(899l2yz*/.v0P^1=<<ر#V֖&Mp =ǰb wyꩧd  ĉ133*WvHZZ.4jԈ&M0`***ؿX8rÇ'$$D(/^1c """?]=$((GGZe"|ߢE 12$֭[ڵkiذ!\z3g/=%66|?{\|㒐+ܾ}SjժcYAx{{#8|0=?֭[dggW, Չ7oh$>>-[uL\\Py  @=g…:tɓ'3f G<8~8/ƍlْ&M0ydL‘#G?~c X`?3-'~O@@֭cȐ!sϟ?O?ѣGcggǜ9s̠Apuu%**+W?;v$--M?3e:w+?31NfiAAAtܹuܹ'G^ڮI~~~ےj5+VG !j3P 3f`ԩtܙ7xO?F3C ĄB]?www ¸qؾ};\|°Ct:#Qqpp`ԩ= ':#xrrrصk}B{B&OLnn.K.3Aiӆ".^jgoӰaCٿ?Zvډ#kkk6l… EqF:tN\\]vgϞL65k,J%Rp9Ν;Grr2TmTxdffbnnεk !55m۶annxƍ 6L>.h4:w̡Cj8p;;;GQQ٤= @^^#GZ[[3g[FM4h̘1ŋD\\NNNIHפ8u:#xٵk_'N&A;-X?5`߿777}Yn݊] FCAA bуĐ!C>|8/AL2h~FL&ȑ#L4 +++ƌC weС :̙35j}Z+/xȼy󰷷똛3c q\;I _Zho#Us$z^3gΜ!''k'ХKN8/ĉr222ؿ?WfݺuӸqcuÇ|2ڵ*l&M*/^ɉ3fuV8@rrXgĉ̜9TT*bﴜթ -'dddb z-~u6&kOߍwn:kFtt47o^\\`*W333:t($$$K/w^ڷo۷Yf vvvtޝK.w /F!<<BT=z4/j-Z`ńzkblْ{zJphfJ4{]{5,x7l؀YYYxzz2h zEQڵKVA* 777\\\ؿ?aaa8;;s1vͪUٳ'۶mٙ\IHHƍcF͛7iѢcaa]ֶy$x!DΊ0zFPXܙdv~ʕ[la嘚155 OOO~wF^t*wߥ֭[ӳgO+0 8::rRRRhVXŋС!!!,\+W%JJJsoٲoooӉTV?BGAll,g֬Y̙3,BBBx"mۖ@ok&K7!$$5oޜ9sXdmٳ1-gT*Yj///y7om۶A.S"&:HHHHH=$5I=gΝ;'VRRRPT''4 IDATT*nܸ\rBҰۛ={dΝ;GNh޼9iiijׯosΑEкukJKK155eٲeq lmm&((۷oosss{ڷoW_}%6Tݻ7Çg\vM|:t`ѢEӯ_?d2fff]M69Ǐw4lؐ;* ׮]qƢQ'x{H9¤ŋ?yfZlرc]vSVVL&O>,^>OF=*T _WUlmmqvv"]tI zXq޺u+9( Ctt4ڵرcj5jDii)׮]/ 44 ^Eƍ뚘Q HHHHH/kk&JP( 666(_`ŅӺuk^}U֯_϶m0`NNNs~w_͛7qrrСC 6R4̙3L<&L@\\M4ԔdڴiٰaFFFt҅_5jXr%۷͛95kpU<(}ҷo_>Svə3g駟"J%666h4$*DGGoѢE ?~<'N JJJdS^=z-!T=5jBեjo  ҥK [HCvv6XXX%V$%%w\\\Xz5֭rt:'N|ֲeK߿?ݺuSWWW)**opvv&55)-IIIo>ҖG\\zbԨQo|ghZ9w8::ɕ+W(++#$$l6n܈`03~VZEI?`aaN#55U\Ltԯ_ZMqqh7tss?(../xIHH=$/:z*7o T*&[[[<<<:t(6l૯BP0dƌ7gf\|`iѢeeeҨQ#BCC+WЪU+ԩj3䥗^o>ڴioTN,4h@JJ *L&cȑe y 7ˋm۶O`` M4!-- LF D#6mMKK 0f͚e^t7'vݻd<ӢZJ"((H3~xyBU ~$&&'EEEbb[[[8tj wؑL=Jjj*帻INN&&& Rdb:BݝuƫJJJ +Wdl'ZҥK(I7%%%c( ѶDC<RpqqA3F977Ǐ'Ҷm[dܸqnݺ1|pqc0@EE+={D.A%%%4jԈ{AcnnSO=IT4333j5FFF4hЀJKK8ph][d 3f믿fժU?^}i޼y5s t:QQQ``޽,[ r9FFFDDD1X`RSS&)) 333(((`@e/+++J%xxx™3gƆ#GЭ[7V^ѣytܙyGv033[[[yP(2ydMZZvvvbٳgD ɈҥKh4RSSŋXYYQQQ/`jj TZp;;;V\ɛoIƱ^ 333LMMͥ~s> KOOINN&;73)ZzEEE@e믿fӦM4lؐÇ;ӦM#66vډA;w駟*tvؑ{NDGGHVV]v%88/}]kN8Axx8h;X!W^ѣG~:5Ą!Cnc;Oǎ7n2W_}Cw1l0T**/ӧ# !,,dǠA3f gΜL>]m|U~WO6r\ƺTTT`aaRutԉr|}}cر!TC6lX~!ƍ4mT_s4mڔMv:‰'ر#999$%%͛7i߾=s֭ٙ[֭[i޼9*"/___{9f… T*: 96\BBBBD4_xg9r$&M*-3 %Ç'::K.FIMM6޽;۷gݴiӆ={?lܸ޷JJJ6m|mѭ[j?bccIJJ7z߳vZ~7 'NԩZXr9vvvX[[QiXwH}jZfݼ{ѦMn)d2?X \UW{*33칡=z;w ;( ppp[n,_d033?ChР6lsܜ7x)ShD믿r8}^WBBBBɣWx Yx1+VϏ 6Mff&&M OU TUսV@er||6--aÆ믋111X[[ӣGZ-̟?{{{INNf :$Ξ=Kjj&Ӊʊ )++kkkؾ};XYYѪk;uvvvbkk̙3qtt \r={V_G&QXXH`` +VM6ѯ_?G~~>˗/`ԨQ >;vOӾ}{F1chР666,Y.]bvKKKWm:>"̙3h۶-|ܜyW6m@$aggGqq1lٲE={v3gx7IKK#&&RIdd$Zʈ1233ŅF3gΤX1Eٳ+e֞޽{~zZ-;999̟?#GH{{$$$$_n bȐ!8;;]_xᅿu>a0h45ڭd2g666h4 e\|]bmmMNNh #88[[[.\% -[P_*Utt4_cccbbb(,,ܜ޽{RHzɴiӰ筷b4lؐ@,--IMMVngffo>._ Jk׮ajj3<lj"))1jСC,[ JEϞ=0`/^d̙۸SZZJFF~!^^^Rل W›DE.s1+ ZSXXHǎ}6g,_=z,,,jL9sppqtt \x̺uDI^^!!!|:4+++ׯׯ_deeaooJ"00J%K.5޽{ӼysfϞMLL ۶mGQVVMBBB B /ܹs;w.5"88N<TN }[$L4=zþ}HMMgeɒ%<#77{{{js9LLLhذ!)))T*RRR' 'OҢE Ο?OnW6ra~LLL033PxxxpU233iܸĄz#Gжm[GRRޘHff&&&&pud2xxx`ooV7"22ٳgcccCVuZȑ#JP7srqIFT2tP^u sͥo߾4mڔqcFT6#6lWF&066fҤIDFFrI<<o6ÇØqIJKKvlٲJEjj*'O 4eIxyyqt:jZ=zTh~qq';wdmۆ']tK.l۶~V_'))` BTvuPYϯΦp&O999@el1chܸ1GHL5(((ĄR&L9s>|/v{{{|M\\\ѣ7nd{LNԔvallLyy94k 777\\\={6K>Ɓ5Yj ҥKl۶^{#Gxbn߾? EO?Mpp0΢֖JJJB&(6Ljrss DݤNXi֬6mc rϞ=b*Aq½'U"W"ҩS'|||۷/:t̟? .O//`nnΨQ022:t@FFTTTp #X1\NLLϏ~E1#`nn`חC/rVѣG177GѠT*9w ۷nٳc.]DXX>>>b7UATKiFPԊЉ ""⾏-Nnn.#F beeEYYjiѢ'OɉAi&FP*T6VID[\.Į888b 9s&xxxIn]t-X\ P. ԥwDTD) {%jTL4vDcL4z%k4bIXb(ш&EH]~$1s_2SVFVHJJۛ+W`ffF֭iڴ)ǎ#--֭[N&MHVÞ={ܹ3}!!!l޼3gh"/^zǖ_ =3L,--%??1[[nѺugǸ|2n 991cp>7]zzzNOO:deeNnn.۶mٳ 4{%T*n߾%0x`j5N3grH$|}})..֭[xzzrիj `' W9" >>R)iӆWbkkD i߾=.]"99T*{ ԩXYYG&M0`@Ltt4ّ555{ļ$mۿ555rA29|Ej.7obnnNYY555 VVVc``@MM 7ё;v:֋󼎭;%`mm9M4iӦ,Yhƌõkܹ3ΝCU* aXh222YmJ 11f͚ѩS'<<< GGG033C"p<==ϟ>< ]wB'3sttD__\ Dpp0ܼy$j5999ܽ{;wRWWGDD]t!<<;T*  (<==i۶-*$666mڐe-5`llJ;;;3zhBBBhܸ1𠸸Dx:t(yyy>}2V\IͩG.CAA\ &;2c]~ -5Q&MMM ҲeKnݺVd9Nqq1ׯ^XtEBrt١P(1cǏ'<<ӧOxlժQQQXYY 3oܜ^zJ˖-),,accCYY-[[ 8w@}ۡC,Xk׮%88\`tݐ"vE~+bQE</&""]ƸqXd D9kƐ!Cؽ{7ա/sN۟N^GGGׯԩSL4 J%:'Nϼyhڴ)MPP0Jͅjaaѣٿ?JRp|TTR\\`>JXԧr)jkkqttdƍ̛7-[`aaAaa![nwޜ⭷ޢ򰶶g<\˛"":YS[[+۵kGhh($##YmB@Vn:V^/믿ή]H$Ԡj111?$22;vi2}!JiڴiÃ-Zɓ!Hd$$$ Jx"<@V̑#G&&&QFl2jjj>FFF={hժт17@PRR"\8prr"33bd2YYYPUUݻw@ݢ"122bԩ_KOPP~-FFF߿d^UUUܺuKnٺu+3f ;;[gx[@}]Ʋ}vhܸ1&sv"--4BZA&~[!IF͆ 7oϧ[nbccW_}W\AѠV#66j竳li17np 9" poڴ)w\|O?____ f  L[DDDD䯅/033#%%E>|g>f۶mb 4 cǎ/hd2\|~A?Q~ˠ|nn.RTs+HȲӧFC۶mdߟ={R[[ˁppp >>J$ >5BP9tЁ:APPoZڶmKǎ ,7x///^}UFp Dbii  ccc֮]СCH$|W`r=HKKIM2aOMM177IxQoD>룯OZZǏ' x^$-j֭[s t7uy2Ÿaݺuӌ?y bwwww9 nnnd2zѠkϏ͛Drr2)))?8šӧ}eĉcLLLoh߾=wϏ,)((ۛ@Ibb"r/h xuuuڵk7n111ݛ4'SNȂ 4$ ?3Cee%YYY6333n߾;ܹ*i;+u~9z(jJBMM 8;;)8 ___mݻwILL‚-Z˗)..fʕ(77-ZĨQx} +s[0pxl?/?]vtR Ɓsx?v}?AcffFzz:Zӧ P;:5  W\Aղh"N<͛JիbmmVǏ?3ر#z41Oxs\?jrRSSwW^ +DTҧOvڅ7¾Rl uu4Mpd $"""<6l`P$٩Sgbmm'Oa\AiYFA* 4/Ņ#F  !!Ah qdggsU<==%,,F1l0;J%]vEP`ffF߾} ]g'..J̞\h0m4_ڵ+#GP^^999ۂd5?~ 1i$rrr/xP(,_ӧӤIf͚'vԔDزe [lyl_uE]3lݺ={2ph41x`A+ϯ ra5k&FЮ];d2sut|唔`aa9۷7(o9;;SZZJ6mٳ'P_5իWT*yڵ+XYY ELNNIIIo*++yb\\/++:u&7^Ç:tpSRR AW\!&&k"h41$୥s+hp\[CCCU{zsjX~ sμ{t֍J"##۷/Juu5w/͍ ɓQ*̜9?X5}E^N%11ŋ#ɘ <͛73k,qttN<)dI;wBZ-.]ĉs]aBV#!SDZ*MJJJFeL䄞jbff&8s}>T*jC4k FFx{{ nvO*fT*TWW vOz_M_`=?XEyy9*̙ѣo100ޞD pB}VUueN9"waȐ! E\tlr\XXXpG||<6lLXIMMؘvq JKKbEEzzzWUQQ&Q6URPP~Kuu5]v!~addıc?~</^LJ֭[oøq0`$''ӤI@<9q2qD6lwW%))>7o _|YvĂ7$x t8qVVVx{{7йsg5kF-PՂ3є)S8r;8:[aa!8qZDFFbaaјR^^Ni׮.\[n0zhbbb̞֭=///ڴiÅ hҤ GB-UVrq<==p[nqEN:Ŕ)Sݻ0<_׮]bYwbİҿ.kѣG݋DGGchh(H ...y;իWYr%]tQ=c $,--g„ PQQc(--e͚5ӧ}63f`޽$&& !P_k׎/ MLLdԠP(h44nܘׯ uuuRTTD޽|2ZƍS\\\HnXd %%%ܺu֭[cnnҿZnowWe֭lݺM6ѦM:v(苈Av%';;1Yïadd'~p6lqqq|7۷gr+WzUUUpqA@݅e駟L;;;Ӂݻw YYYl߾\]WWW222;F9}4ݻwGOOPڷoԩS7oiiiB&Kh۶Sߧ/dG{?'xo IDATcooODDǏXzD"A&abbBEEtz*F/PcffƸq5jٳGGG&OɓqK,aڴiZ ###  X[[3dA...ѳgOwL&C*"Jqssggg3|po.ݝEqǶ`TgŲeHJJ 4Ha#"DyWFFFadd9SLaǎ :v1b.\֭[Ν;?~֭[j(**ٳXZZrM:t(DDDzdjjjpvv&))IUܻwPP 6ᑑPRR@}L&###OOOnݺ ^^^padΝdeebff??ׯ_gO|222ؑ3zg6]}vVXA(//dffP(pBK===lll8z(A>8tq`Z|Q(,,$??Jd2{f4i҄SzjT*:uFFFdgg{񤥥q5jjjH$BatH$ܽ{jkk_(--1gڵkǞ={dƌjˣydff @EEErq';;[8&*++ވ#fחL:v( >ppW|>uy$-ZĈ#8r5"55B!tg޽lS4(xyT6|p.]$Ȉ/'N(X'&&?hZd2päSND"᭷jP6jԈ-Z0i$a6HTҩS'gFFӧO*\I9?;v0n8ƍGdd$})))7:7o͛yEDD>撟`&)j 8s _~%X[[SZZ'#""TJ\\J///RSS9rRkkkAQYY͛7 .^Htt4CWY4aÆaiiF!!!\T*&&&lْx:wD"vIIIaС۞={2dPINNFVR(..RʄnOx4N\QZZʃؽ{7!!!=m۶ ]TUUQ[[+HñM61sLW=$D)-,,@XZZҡCӉʊqww 8vt |+++ݻǃGtqvv 333n߾իWIpUU#GSN 7i߿OZZ7n 55-[|@Y`| ǏÃݻ EμA:~";]V:z-nݺg"""y;B-ZyXYYѩS'qwwȈ[n tpqqB144Lxӭ[7I&Nǎ#??"۷/P?㣻S~u!4--MHƆ;w*M6   Q,7\-{ɓ̛7K(F6mڔd20۷2dlڴ Οy ^`Ғ,*++Q(\T*iԨ|7\mڴ`>T*IJJcǎr~t›oѣG K.q}ڶm+XMkN@vpp` f M&,Z5kp5A64DG7n bggE@ !uuu>u=oL&ŋIIIaiiə3gP òPjjjO166Ovmm-aaaGVV ܻw-Z0ydJJJbԩKA'''3sL;w.Vb $% ƍҥKP^^ٳg0ad͚5BAëyk׎}1a޽{~/^LN Z[P*s^yݹtRΜ9C֭iݺ5<5֡GN AD"[[[<\WшŎ XIZX1gԩd2N>͑#Gh4 W qjR$##LMMy?SYY8pƍSZZ*EEEAqq`‰'pvvޞ{q}d!hٲ% ET*ILL7n|r?:8oԨPФIJ`~qvŃXb]DDDDDTVVj*]"77|||HMMER ]166חqFƍeee۷ D#8]pD)((R233100`̘1lٲssǤIIItޝjܺu vڅZfҤIӺukbܻw3ydF`<0qDXv-_|^dffٱcsΥo߾tOD^Ltڵ;v0qDÉSN 7XYYq JKK={6aaaܹ[[[y.\,?I)@jikkᅬ!NNNjՊUV1`J%;wf͚5^?8uT9<* ~gꨩs=J\|Yd2:t@uu5w!44???Μ9ѣ1113/]DVԩSAqq1Q^^΅ """"/,^VK.]6m5BբlsssLLL /UV|(JfΜɪUС>}F!pײgϞvZˬYVÃXx1lOOk׮ɓ: 7:88pڴiøqk͛7O>_~B1>5QFOp'G"/7Bɉ+p=2e ={6mP[[ZtЁ ֯_Ϙ1c? 1rttXZZ 癇?O,E) 22_~fG}ܹswfٙXj5R+++Zhw;wFa˖-ȑ#3bn޼kFf̀Yƍ)--E*ұcG,Y!>>>wPDDDD\psi&N8Azz:?#RrdlllNoo.s']Νˑ#G000@RQTTĶmۨd!<++ 777.\ȢE8|0N"995kHff&t [[Apq>_ur Avv6邥 Gv?#~~~o.dɒ%@Ly뭷055mP\vy/`ccɓ'ywѣG G\Dz5qF&K_7l@޽Y|9lذӧOOQQ-[dӦMB'BAHHJ, Yj֖ кukqPDDDǏgĉٳCѣG {.QYY)Wj44M8#"""<}w#==* (ge<|{Rq;v`رBވ .$>>z'O"Ʉccc!촺c2vX,--~:|G]0=z4%%%lݺ///,aÆl߾Gbbb˜1cĄ'Or vE->}:XZZbii)HHw9%x8{E^^dggGaa!/^d,\wyGGG"##6l555DGGӥKBCC޽;>W"suW jVVVY͛3eH$hZ E"гgOڶm @||<999;`rss9r$'OP* VX]Xnpa>L qLDDD LGGG,--IMMjjj={6.=m۲vZJc%;wJŋ'--f͚a```Z\\=aeeŇ~ŋ9z(VVV?ɐ!CxWXf aaaL6 '''***ח;w2p@rssQ#=EPƍ`ٲe|iF'gӦMr΂ h4>}c舽~9"/sڵk5kL4|޽ĉi֬Z8(,,d? `Ν Lض;t@aÆrJ2228 :OzȟK_<JKKK-[??Gyi?7caaAHHÆ C__\1 bÆ 1c aԩS ͛7100 ;;$!c?O||S|||bܸqɓg֭BV \>YYY:u*ҥK>|8~~~DDDЯ_?#\@߿P uDC'=R) >ɓ'9v...899QWW/ZٳgSTTDϞ=055f!Ɔ|LJw}Q(0k,򰶶Օ';w免 oSLkk J‚}1'7++$ D?r?=kR6oތZ ꨬ߿/1.333ٳg)))5{ X [l p׮]\r/isrrQWWW޹scΣ §G'Nn:j5K.]vT*dUUٱl2 e˖ u]߃PLX[[cnnNVVFFF4k֌-[3sL~'&OL]]ǎٳdff͛iѢ555:u>q{BԾ}{f̘Å{zz:SLaܹ+@w\.{l;<yA^Y9;'u{j5 `[A,.PWp]U+,_tu \j2Lz$#{dR $z"3s˹>󜳎1cưj*z*nnnywܹ3=[lQGT۶m㭷d2n:\”)S;v,&>c28~:}vRRR`۶mtܙ>J@SZZ7|+w[npbcc[ gRf,Y{Ǯ]Ybnnn_&996mbdǏ'**Í7s=X~g1cC%>>DzɄ (,,$((HM Y~=+V>8>tI$''N~~>~;{ 8m۶{n̙Õ+W۷/111uЁ\8p Eݻc0tR&;;>W/ҵkW T#h_޽{tR d"44TwG:vHǎh4;o~ زe ֭#11{/)S0k,xw6mvK,! Ǐs ٳ'OߟÇ駻t领3pBz=j6ilܸ?O@>hcAgwfL>]=ɓ'cƍf ̜97ԹѣG:t@?_~͛>|8Ga 0?@ YIv 7`@aĉ̜9'|I8p K,aݺu\|R|A L>}(((P?k RZZz穽9*YYY߿˗] o?ՕC!I(j'\DDnnnpI "00zlڴl7EEEƶmۦuIsk``Ϟ= 6luޤ` 667|>},m:'""E uᐂ~l2OԩSYr%V*Q{!..wy?y橩K(..&774ODD:uwddd0|pF T{[>̏?7|Cff&̚5T[ 3WbgΜ_~9O>gggΟ? Wyzzc NU&ѩS'L Sё#GZ NyyvҥKLZZ;wuֱanFX#Gx ⥗^⦛nR'-IPP/*RNJJJoU5Ć Bnn.O>$=bذa@uFhN>MNN=zoݻsezEii)]t[oeĈ>|rСCkfb倦`'+xl2f͚Eݩ`֭v+v~Сzh4c6y7prrR'g۷O  #>>IMM7g&::d,YBXp!%%%޽cDzw^5vaa!3gΤsdddc L6M c0`z PdlkO %نӓ+WGjj*ĉ|<~E54%u`„ L0oK~0L[ ]r%>,7pcƌa۶mO] տ5<:9948@RRᄇ;0g.]JBBzFERR!!!: u{L!\m!)Gpp0 lܸ~aG"""///СÇc߾}۷WWWRN8A!馛t+<,Zݻ3g D: `w嫯aÆY '22@ZZ~!O?4G%..>}0p@?ȑ#Yj˖-cL8헸8SO=EXXZgY*cbbx2dΌн{wfϞͲe˘7o, WCh4RZZ*m -L<_͛7oks,f&'(((PC._ Tω4hK.%99BbƍߟSNrJt:O?4o>u=''???bccիݻqƩso3i$vO?M^tYf lذO>CRXXƽ:ˎ;ZUp 999'!!!tؑ,nV:uDnn.aaa{nJJJx'xU/ C(9r$#G$22͛7?k.ƏOpp0ӦM#==޽{snup#-"**?DEE0LNNONÇ "&&@wN^^^^{A___ /DB8ڀĞNDDD222PzBCC:u*?Ԛ Ǐ' ;;'x@fΜ; 2Ν;SRRBǎyG+VPVVƂ 8|0 ,ԩS`…,X=zR|˗/1c]tj`PL&1bP=m4yw|2'OV駟&..%K0dt:-A%BƴՋEɓyGaŊ|Gx̟?_~@|A.\ɓ{]8r~U GdffޤжKhx{{ss1e[#v !!!xxxOAAFQ/c4 &11>SY~g222(++#((05oaڴi?OnFfϞNvv6tțoɨQ>}: d2YXXH^:t(oXjcǎUk"\|"\CFGVZZJNN&Iȅ˕+W8q;wȑ#:ga۶mjX1c 5.i=/tڕw}+Wr xŋYp!C a;CQ\\Lqq1| ߟ^zj*z)IMM%""wwwT 8;;SXX>>>ՙAG)))Q=ABO+PXWΝUQ<==- x?coͪUxwHHH1Gy8&L[nᮻbܸqVbTUU1 ^{5 lٲ7xg}޽{c4`ҥ]~>sy Dhh(aV rss$//OM.裏u^O^^zb͚51D5SNt0cǎDFFs1u:tP)IۚQ ã uz F cǎf:&Gxzzy'=zZGϏ~ 6_^zݻqF8v|ᇤsN׿"jܹ<>>~N`0pe:uT+<3>,ӧO'''ݻw/pQz-nt6:A~KeT_z777&&&777\\\ԩpuNDD"((Hj'kmQUWpe"6lP9r$cС?~-MKrss#PP;`߾}j"<"Z ;v,/[lᆪ{DEEq1uv;M6q4i\x%K0e&L@zz:˗/端b֬Y >ÇâExg{sεMhh(~~~ 5$NYf=zgԨQTVV@zz: 嵩+%vec>Fۑ{9r$W^/O>$iii$&&g[gŋ1 tޝիW,A DJE$""ш`P )ۗ, ٿ?&MRW_}ŦMTh… +رDYf o=z؆7,XKZ@q6 deeV:t(,]www͖3}O淿-B֮]Ν;xӟN~ʕ+DDDPRRBdd$?#//d/;d2QVVFVVV-[c/T{{ƺuP-C^ Nsz/u|uYNyy9j 7utvѣϧAqy6lŋ9}4g+OΝٰa={$vŋ3g...;w͛7O?1dMǹZB"<<\>0"""Xf 'N䭷"&&M61}t`6՚A 簰0e^c08}Ǐ3AAA7BFIyy9QQQЫW/(mx 22RTTDpp0 ~}l),,$++={zٳ'*xغ6ZIii)< III̛7[rb >SnVJJJxPZ+ق P<@suon: NAAPWSXXHpp0<SNpc=˗Yz5aaat֍gy˗՗jnn.%%%dggӡC"##G5=?Z R%4#iVZZJ`` f5khh(TVVJjj*7x#={$33 u;RgGptiqwwh4rEgII FL9&cǎQTTĸq8{,ϟg̙?l.^H~~>z .NAA]tjgM@IIzeI "xZt֕e|V\\ )SԊBmϏ#F0fΟ?w~ʣ>J=xٳg<裌=uTד$/@Blf 73 IBBz@TTпszꥮE06->111xzzIez= 2pa3f*Dk׮f5;[@@@-acN¤ge-AhN@n~W:'N;`Ϟ=kTUUsNnf._ݻ" kq4 Ȉ5b4똓}KVVfY哓É'S(ۈAf- @EEf7|?_~TTTг$.\T{rf3f:`6_Cõ "kBӨy?NQQÇ[n@u?~~~xyyRk= aف ~zxxXxе+z ՐрF#.zo]͎{ァ鮨5 %e/ Ngk3ZHKKۛ}RNNN6I6BݻRNk3ZQӂ<<<СAMW_Ms=ҩS'{s\\\0zzGXiMBRTT]^^dP ECe$UNII͵()͌ 5]IhpY ڥp3f 66f L&)))tԩM{!ڼ੪d21aY`FR-8;;Ze>11Q6WWkJ|| 3k܀&eyޕ%_zz-!Ahش{xx 2d} HiSPNzz5g0h":s%&L… mm ،6߻t1yd)++{ux\4U? ŁNd2.!Ahxc,NVVP&MeĈ1 I+m^TVV騬ɉɓ'b Ξ=O?CxzN8T|b-1bDY/GƖAQQ1PXX-e4),,$..{ o~j5LL&|}}ՔJ5gT5k& xΝ;T?klbqu@II*p,B̴ ES>>vF$8hj U'ACSbN>M^^zz=;w \ʽၯ/N> @߾}Y4fj eڅQ߿?!!!^۷3j([0 @\/QkOziQHTC{) 5zmCK UV?Չ!ƎkcuiӂG cׯz'|e˖q=zjcc+65OCzupB$77" C|}}kY FVTTDjj*{V;0lOzF#j=IF -HxxE6Eh.^᪰hQ{y]Zau9u>5oЩS,*4U cҤI 8o\r BӦzA{존OOOqrrR縺2rHNʍ7 &M+K@ԵW'!!A秊hd2/~~~TeHL:uqqQ~رcjm`u A~9{,ArJy@ciil]iV[ao;,J&DEE O.]ҥ |󍍭fφ 1c#Fd2'|3eee._~;`0PPPl!eG+j"~)+]C; \\\L^0Lzr;%*P&[yy衇Zm¯,^?+ eڄ)//O?_7L0J-i&n& ϟLrrr3Z}(BBUh5#bVٳg5zHIIQ 5mKWnQQݺu"MKEEלIoms-cM4h{ iS2h Q߿r e'۠-Or=0w\Ճ(m6!x\\\߿ח;wYl{%..&m_qW"""5o!:uh$>>ޢcAJ"ܝ Ի|Ͷ1 rz}|k mm[B`MdhiCBg w-eܸq7NX>Æ #))Y-\={gϞ|6FZ>k׿Wr7= 5qHc6Yd vb|kt:FOoGCO:MСCdee':uR 6Qӂ`4W!\BCCܹ3yyyZ ggg.\X7{9gbGvhӂ=BF}ٙc69vX QⰂGKpp0˖-c֬YQYYO?d7b AZ[yꩧ0`@OhY$̬Y(//sݻz&N:qp7hʕ+~ ؊6!xZ$$$qF~fвA w=߿!؆[sw=z4t֭u߱c~-lݺ?XeoΨQdΝvEWUUUek#\&N;C߾}\l6[Lo %k-z%u } Kz Dߋp {cSm6'x|||HHH 00~8vڵk8<ڵ>}ZAAAZ6%xu멪ÃwqqLСC  8|Z'OàAprrٙJۛz1cpa6nH@@@1|dl絬R$''{{\/)))4zh[Z|ZCl6m}e6AԶѾKleǵ^w}CSltk׮_cǎDFF2h M3gΐď?H߾}N`\#rǫ4.[橯նekKnm\g[PiH;l:%6~6ի^?-[0f\… S8;;ӽ{w=d#  c㰂ӧOprwsU    3mۆ SN`0p&MDddAAF8t6^ԩSt8q777233y   <<Ջe˖׿ExxMAA8$6]Ӧ    K.x;@   m<   YD  fiYAAr 稨(Z#XC  `̟?_;99dΝ͛ ܹs?I톔RRRAA. G^㡇bȑ6]QS/X"xAA0aNNN'ڜvAAAh!֬YCUU999̝;KD  B 1vX !iAAAhA(((k#K)**m#KW]-z {a _r9["ha416Ci˂=#m!ShQZ7\cGAAz '66:׿2燳sk)XABm[AA.&؞ƄՖ i=\7WckDDDPTTdq=Zػ}L:˗_W D||<}eʕdP"x__:Ō⦷ hWo{oBpi0(..= ,!!!8pCxb[~(t`Ƚ`_(ף[n6Dhޝb[Ӿ QPP>wKTh},:q4Xj]nMkӖidddHAݻw0yd\BTT/-k!eڐ75>Pe (**"##///u;Z+W,FknXKHOOWH~]/xmAH>6tDi穩V _$PQrΔҿ:Bul'.\PRQ)Rz-ע)mZ6,Z?eQFv-kױk>CςLQ36nh3GY3l0lbk3M *t:z*<<<~ǧ~Ǚ2e )))=zj+U(h uu|}})..nT-ؑNVVu.#TBShu(\ZHee 궬Ҟ9JZ6kwYlNc˫Eo}b UA Bɓ0h pvvHPSO=Ř1c8|06l 00I?wrr2{n\DDb>OC_@JJ )))^5V[樦r(sg݂1\Khkض=OAԘs-i׋6ȃ>Mm[`_`0P\\|MϚԵr}||\>5tvv-KJ}5kymi= -km{h(!KHHڶӓ3gp%zY]j|PӵkWΜ9S2~)YYY|MGUի믯T8qssc̙o#66$n&\ŋIJJj]HQm JGM4eee ߔl6=LufՓ+N]Ͽ/Qnݺ҉XOIjyS: {ѣG3zhu~F}(MZ m;)*'B IDATv5,K(ϡl˳>˴iAAA3Fh+x8y$}UUU|L:> .0iҤ﵎4CNUUk׮e޼y+vm=F =mJliJjLxRS׫ Sj(ԴG<ǵUR}m1שfjLky@Q <cc5OcbmT1/DQQQxyyYt˾,~ӇW_},jXXބ_\ f"^}U[^~eZ45K ewk0Z)֞m^^^ڇ5N:ŬYt|u.DgJZ1}9WANQQK.O>cǎ?[nH$53Gpp@G}(v(5jʀPcI[kǩE777nVX̀lmRa4Շ?xg(++cΝdeeq%u F#.]"770zƍ1cKNN>|X^yc2ԉגhʺZ#G8rFJqwsArrr#22p9rj#Jtkl^:~GG{>ӭڵkYnZvڏTׯѣ=z7MLZǏ9¡C?eӦM )4C;+Vl2x뭷زeKue֔g쉈h򳧾9&m hqqqцqa6رcs7zjquu[nO?U?p;w$00@bbbj,))QjkfP7ɄlZ,kǦm ^^^䤆Nj јB׊-u*p)N[s@[Ç^ѣxzz… jS (**BӑD>{0Qٳgٵk{СC2c KQQEv˚!5K "xxA!]JByt:۷>xgggHJJ/ϰvZ8v*x|||غu+899Bpp0꾴3g)))L2Cj9ԇ0k{sK2&5ok۳̕s 7b-HQQEK͗OqI222 k׮>C~',X@NxGnS_S[+Vv}^ooo|uݿ {IKKח??ٳgǧ~O6l9dȑۭ)T>/[k~lRdk`˶rnkRzg{fae f6<֖ cȐ!jPQ26[UU+V`L:=zY|9#G8ve>""x3I<2Ry ~z BCC)((`BCK1-Zh^J?|Ș1cqFc㛭T#Rwך|%U2zh8|{--- UU_]]]R UUU YYYEaa!yyy+ x>Ϗ dLb`ii۷y1yyy?^ ܻwsm\B޽'޽;/_΍4~O5xo/go:*ŬXݻw#(((`ĉK|]zmYL\\\ aϞ=QVV.3{9w܃Q? _grihРo>pvv_zEQQP䠢›7ox \v&MУG~gzɤIJyHHH@&QXXΝ;gӦMhjj,YYYݻwIOO[nlْ 6BVV] /l1{I}p("!ڃDˈ`-p 88 Bz%mmmڴi#nqq1iiiԯ_W^߽vH=φD5|~vTvm^x&Cĉ>|EMvv6;wÃ<:v(HNNzzz$$$`]ƒ%Kӧ;w LFzz:gΜٳgdffwѶmS2nGHfff¤1I!u}}RjKR Ko+TwzJ]CN%LLL000>y/_&==ի(KO.] ]PE&MUVq!ڷoĉ)(( **VZn)*&)~C){9oEA&Ndd$O>ŋ}3g[d2˗/~-h4#8quϜӓŋ3~xV\ɳg@0{Ɂ077,Y(Ξ=… IIIuڵرc 2D>duʕo5R)ر%)>(N6={7IB`` ݺu㫯 :zꡮNÆ Rhh(ByLJtl/zXѣGsm\/ʢnݺ 8777"""񡰰-[ЩS'Nc [wlLBM bڴiܹs;vpA.^X[}aB2޼yӺukرc޽T,X tǾ}󩪪Jxx8QQQL4dΝݻwS~[UUAXARRo޼䦧'hL~OW:eQ>e<1 i+zikkAaaIihhp~gëWё;wuVh4CCCȐn:?8u |[ߏr ))2&ݻÇSPP@DDnnn|cԩSL>SSSz͛>|8M6\DKk֬ɞ={y&7nDWW;wM4((.]ݻwgB-Qؾ};SNeРAa-nFxxxЫW/ԩC^^oߞӧs֬YAÇRNQ+ CYʵJh:R{Jw壿-} I3gˋXƎgϞٳgٷoƼ~ׯ_-Xh4(++ãG8t3d^ȑ#IJJBIIѣG Zh۶mo߾^'r! 033޼yCJJ NUc]9k#f|hP4n$֭wd2_-lذUV 6333sΌ?ּyжriضm=zeee9w+Wd޼yԪU OOOÒ%KJC lB&M>cƌJ:xi*z),,Zg6{-k811Q(/? J⧥k./2;JJJt֍pTUUYhԩS~ӧOٳg5j@WWիR&nݺ͛7y);wf=z[[[laΜ95 CCRYd2؋̻(9g7.oNqƍDFFҫW/~ᇿzX*;<iii7ͻSQQQ(++ A(Y(h&33L9t萠^^^L6=c100˗/+^FIIIDFUUU7o]tj&իG˖-9*((ЪU+LMM!==W^a``=YYY8p@PFޅ/-e˖+(F RBIC(()=% MMM +HOOZj&gϦk׮?3|hݺ55j 믿q4oޜ#Go></_ɉiӦvvv]V̟?O=yAaff+z~<yE2of~c}%֪vǓȸqxͣuXXXpeE&EׯYhjjj4oޜڵkǏsy˗?~[ĉ{{FAA %//ի9/.륤^d``@۶mٵkSLMCRTKJJ* A&&&~p===ټy3FFF(O IDATٕrvIMMrcdd$>[fܸq[/_&,,T:uꄝ...eOϦ(iiiSF I'pQPҒ6E}/r>T_PhkkS\\Lvv6lDEАAӧnݺx:n:BBBx 6dGGG">>"?+b :v숺:_&11[bmm-=~=z0x`[nܹs >;w3KӧOSjURRR\21Bd7779z(gϞI&hkk(X(ïꢮ^^»KK"ӧOFSSS8wڸR' )))阘`ooO ؽ{7GA&aiiI>}Da˖-"s'E/`̙|7AahhHzz:VёAfcǎ퍡_nn.jjjhjj Ebb"AAAoߞիӼysϟ^%&&"dy.P+VRɭd*}H,H<sGW$77sssrrrNKll,FFF"`:o߲tRϟϹsضmNNN̟?)Srrrw6ly樨pAϟСC100dժUd$11ϟӴiS2dݺuq`` k֬A]]LRSSy&DGGӵkW6l(2Xr%lR^ڕl UK^y1|R5e]3 o:S'Nw^\]]ٲe hjjGu[.&LbmmP; I&äIHLLd>|iӦvZ <㈎f˖-SZ5x=s޾}KFFqqqXZZuI||؃}ʮDDDиqcڵkGHH {DI6IUAAa'IlJ( ĭU0ء4J* 8}}}>|ݻС[r :oZjo߾L<eeeٲe ׮]CQQ7oгgOTWW'O+ =zߗڄp]T:8pElllDG;qnݺApzzzTT L6...XZZߺu)S0|PUUeΜ9;v|eee.̒5@m(޲PPP@vv6FFFqqΟ?iҤ d ^dbkk˸qaw9qJJJoߞ0"##9}4(++Ν;=QJΞ=KFJ$$$кuk4551clX,(xACC㓔~ eef>TWW'""ɓ'cffFϞ=8y$_|q-[vz ΝcԬY޽{l2իqrraÆz~xF-jڴi& .k׮,[122̚5K4ӿv̙3qvv޽{cjj*.\?Zёuȏ?X*dnn7.5|uVVP, ࿷}h?)$HU iӦr)n޼IEZuuulmm177^zlݺ/// ?KKKpo߾EKKUbbbŒ3oٵkOM6dzsNASwrr"""###@8VSSCEEǏ@J044(8@XXÆ CJС?3֭;;_UԔY33R5N9(wx>~xHOOg۶mҺuk@0`K,aΜ94i҄s[.gϞ%**JpԩCttt}:pw9F_I{ UΡ$$WWW;vŋ`̝;L^LvSD!CBB_~4heee._Ly-?&==%??sΉ9 >iӦ@vv6;v}ussc4oޜ,V2+VSQQA루XP?ѲeK*W̰a۩S'ټy3#Go߾<|ƍǥKظq#3f`"! 9WWWǃ_~ٳ'ڵb2PE&Y:'[JJJL4:0`.]Dbb"aaabmmͣGFt҅#G2uTv튍¿""##}0K /$&& iӦ9rooo<==Yb>>>P~}$::e˖abbBߣTaoo3^^^dgg3tP cڴi슒uѡC}믿l߾???_+VM6sNڶmKpp0tЁT8ͥcǎ|顫[fMd2%!()gDI0I ֭[ÇECGGGϟώ;0` ̙3t HHH@OOh8{PSSv 0cbbBRRSLà 6K.]^:>>>4k֌,485k+6}DXYYѿѯddffXJ.,,*U0zhd2;v@[[}kKApTS PJJ iiiӳgBQQ166EQQQ?~K6mɓ'ټy3˗/{Pzun߾͎;T?#ә5kժU&M0ydj׮ͰaèPhiiQ-_~%cfΜƍiڴ)˂:٤ITl۶ӿ@---y|$ࢢ#..qbbbDXkgCSS+W2ydQWW'88͛Lݺu cĈT\uҴiS._̾}v?P 䴟/Bzz:$##RjUeȐ! >6mC}1gZj%T8< C$][IZρ]Һ{B dz}vw^2dpΝZo0`L:O SNgϞ}:;v`Ŋ=ztv͉'=z4/^Yf888A*U1c4j---!Q.ʄ 7w%11GGG իx{{tR ŋr+7n0k,,,,VZL:ŋ딕3qqq޽_WXr%k׮eĈĠB TT"`feeQ\\,j%.99A#Z? RÇip9lϰai;2̝qvvȈ3g㲳iڴ);wfժU̝;k2orIXX***t1у3g[rrrHKKCOOL0\]\\5jp STTѣGyƌ5J|ڵٻwՔ>ׯy!DFFRXX!ZҮhii}|"% Nj,$[ϟ_JmAA/^ٙ|ʢE3'Oɓ'O|_4 MHH@MMI&իiѢpy&|׮]#33SP.]Td2DSA oFFɜ:u ׯOʕҥ uŋ\t >>,\-[|r?ĉEiƌٽUTTɓ'Wܹ0k,4559z(ׯÇd24448x |'i@@ Œ;>7HNNFWWWt  ޼yBZjŦMD%;;;zEiڴ)})ݽ{&::ɓ'@ll,*ۢ"Μ95...ԪU;ѣG۷/zzz 2SSSiܸ1(((qF_AP4i[l ggg@H?B:uR(fr动x:tׯӵkW@.ѱcGpuuܹs|OOO+A,˗B(##Ν;ӠA8wnnn <*hLLLc?(,,DMM}_܂- ,uyߎϖ0a:t **TQ4S[Qfظ쨁aIؽ{7Æ +_@QQcjj:t'W^l߾ѣGӠAUƮ] _XFxB8,^z ԃx)=bԮ]---ڵknnnlْƍ(s֨Q#ϟĉ7_RX,qrrCHP[PSSEs)aHdf6oތ"-Z`Ŋ+Ү];6o̖-[ޡ&@ٴiNNNܻw [? *~%Sd-nիW*U\bEOΤIعs'0{loXz5L2sJjjI#S# 6FSÇgdÆ \cҸqcj֬I͚5ٽ{7gܸq:::L4cǎaaa̙3ec1bRBOqq1EEEܸqB زe =͚5qtޝ;v#߿ϹsX"w%==C(I|B=%9%wɒ%T^OOO,--1b{sO˖-#66V9pNNN9QzHZrr2W^e̟?Yf1m4CCCXb W7UVo>;Ʊcؾ}; XΝ;t֍C@ll/*iݻw?A'?? rRɓ'80?̙3!nkk[Nץ[;>3eL„ J(..~r[!m+VYfԫWMMRRK.lܸ}qU{@4egg#1bbnnΞ={DTɓ'\zwUm۶ESS:w =Yf<}>}sNT :9E_[n{1UV%337nc:w-x{{Z֭[3b.q IDAT޾}˖-[8r/^o߾x{{Yf fҤIĠ:[nޞ<0''/wx~m|d uH pss#66>LZZ;v,E~:-[ n"00jժ@~~>TT u266FIIA9v\e0zŗ_~ɒ%K _~Ĕ)SPVVFMM RRRhBTT˗/'99___wqqw<}={r-7n";v@IMM΍\Bff&UTsԪUKԖIgL>͛7pB͹}6:::"ğ]^r)WV+f\tA舞 ^ZJ222={`aaAjը]6^^^?o///QIFF/^D]]OOOLLLغu+޴l,X@*U eܺuZj1n8 SSWA/֭cܹhkkSF Nʹs֦jԨ[M]Fy9ϧ;tR,-- ѳgOlmmż䠤DaaUTTVZš"orr2)G9gg'++24h m_329ss~'/^̉'Xp!,X>}Fcccʢnݺ\|YGVVzzzԩSӧO1RR%t޽;\~uajjgСieee|||x)ܽ{[rE{jԨ"'OfÆ lܸyѿ}6'O޽{e]y1TYGV9АYfQPP1ch֬{rR񽥥%ӦMcٸ{RR2e˖̛7o(**DEEѪU+2d`ff7 DDDAaa!ݻ͛BŊ177'33{{{ hڴ)W2 8QQQlݺX4h*;v`رdcccѣ˾}hӦ Z"##M6ヒ puueմokkkq]>ƇK5nLӧٸq#z"22/_l2 )ɓԯ_'OP^=N7nXYYabbBXX`.]jjj\pb``:888pima׮]TVb>TrQieϞ=(**2l0ׯ_JsB䔕OLL˗ر%K``` ˖-cРA1c z%`{Ν;L2VJ||t֍TΝ[e(˧+)?ikkرc9q3fVP@^M^ ɉ$a<|={`ff,_}2~x6nH߾}={6!!!ͼyDɓ'hggLMM>|8W\wޤʕ+Yٳgxyy ;wahh)ߧsܿ޽{SfM֬YôiD1k  88 (xޗ{9;vdԩуǦM1c ׯEJHNN___N8Gx-[}ڵ1j(ΎhA.][.3fƤfff\p5;wĄ 2e V"%% FIrr2W\a̘1:u9WXZjŭ[UV닋 5k֤y昚rY! grssfر⻥z?^BH5}μzQF1}t}:::Njcbҥ_ya8qXYY/Ƭ[Zj zݻwiݺ5ܼy"UƓ'OPUU%00ϟMѣG  üÂkvB˗XZZ"PRR @iy=z`dd֭~ܼy r1z?~=4*/S*1*z2j(""":u*NNNL>CCC._̣GY&QQQ~fȐ!O?1j(x %*((Μ9#{ѵkW8}gϞ;v 777 XJPBCC #++mr R )))xzzr!lllV^^^ЩS'FEbb"b6l5kښ )+s)J%Ǚ+ ޗ[M0))tB-h֬b혙Caa!***L4<ÅCq9BǎE-ׯ_iӦzj={ƈ# ssHOOe˖bi֬>}9sxb455jժOXX{LJHf̘9=~JAA+V 33Kf8555.]ǏyڢŜ9sļѧOV\ɡC֭hڜ"ɤ h9_ˣucoo?Oˋ3fcr3999`jj*=1dnnNʕʕ+L8nݺѡC0a0ضm]tAGGGD9uyyy(((9M6%??+Wʕ+WDHBBBJ5qFbŊ4i---rssKE%q^^,_-[H~LL lܸKҭ[7d2jQF Əشio޼AQQwG%U<əhe5*PV?‡%yGUoFzT )$@ ޤH ]Q, (pDޥH )Lze?e`9z~9GgO#~+MIP* 6> :uDRR9sחT8@EESLTݻwCAAфNn֭I/f׮]ݻ144dժUr-ZѣG144P( ҒW2|n ț]͛ݻ7/~~~>}XF{qqpFIJJbС8::uԉ7舉 nnnDDDbzsssٰaӡC9.--%&&5kӧ㏱o߾:u 6FBB3gRVVF~~>9rCCCΞ=˙3gM6兯/4mFJZ82Ç鉋 q1BBBիlLFDDxyyq1鶴 |w|7)]/_f„ ޽*=cnnn3!7oM=P*ƬYP89M.W__OQQ [RRRnnn >%KZJE6** RIEEwΝ;k׎*Yr%P:D^^sASSYxe:<P(PWW>cϞ=Dǎp;ww޿줧Meo 4[ \+m[RIzz:^^^>R뉈cڵܿm۲zj!A\PPk֬b$`VVk׮Ągϊ?x̬Y*WWW>S>Cf͚UUUL4 ϏLLLw344]vq9ڷo/֙ɓ'siu׮]#""*֭[ɓaӦM<~\_}zzz{`nnNff&r:RcO555JJJѣZ{ZoO>h̶H@se… 4Ç 9X===<<<{d2nݺ%u9-["00DoݛsQϟOXXUUU)]#408ڵk[lŅ֭[Gjj*ϭA4/տd2Yv->dҥ<~oooJ%'N@.3glllEjXYYm۶C߿OZZtܙ4zIpp0eeeY###83wk׮d@p  /**gϞL>]۷ʕ+$%%ѩS'&Nȝ;wׯVyY> SQ]nڵhii {t ???A[ ܹsp!5dhǓė_~)i'[_FOOO<$<<h"K_𤦦N\\gј2 N IDATh Zl?O^͛79~ovv13 t)zLjH>&O,$9[jEVV7n|L&ΎÇ퍷7nnn@mm->} p"00:$gΜ555ǏРo߾hiiRطo̜9ׯ~ÇgʕL2ښh>|Bccca`KƆDePVVƵk1bS۴볲:M}jkke<899石qFXnsΥ .zj͛'D tbccQSSO>?؊ zOV[[+VΩS000`ʔ)ܹsW^yJE֭E?sX[[󮪪Fda nnn=4$geeQ[[KTT[nرc2c 6l؀3DFF@rr2=zTA< ?A~~>5Ç3rHLLLʢm۶ &&C"#] V\Jb׮]YjtE$* 022 ccc a߾}?;gw}֭[9cϞ=?vL6ٳg?q$?}tzIff&BWWj(k@?x`HNN& T M_|g̘1z,XqwwGSSK.Ѷm[q0155%** 333011aÆ 5JIڵk8991grJs///o W\BADDQwuǔnݺuVF3gl2 qpp ..1U*!!!Fbb"tޝ(+y>cG"¢Eʊoŋ={_}Z%e u1[lQ°0T*XP{Exx87S-055^襥֔Җ!h 2lRSS󣼼\{?~ر#tܙM6BϞ=)..f׮]Ѿ}{RSSٸq#%%%)%%%ED߿Ozz:TUU |CLL:]Ze̚5 19s7n`aa!HiiiP(?[KT9X<<tBRoI ?F&qI6n܈hhhpQt-T -,,߿?xzzRUU'==ׯKuu5ڵZ  h۶-o/OL Q'fee; \z`ٳ'ׯ_7ȑ#3KKKT*nnnD&` C[[}}}4448~8<|P,RIIIR^^ڵ#))IhN]]]8>ӦMctڵ(JGP+\zhT+((SSS x!.]b˖-\`llĉ '::z ---rrru&&&8;;R~$Yn"k$M ~Vӎ?IƲߧ5QRkөS'֬YÆ gʕ INNߟLbbbBSSW_}#Fȑ#111LJK.ѻwo Ԕ`aa\.'$$Dq^_||<%%%ѣF>(h 8:: kkkŅ YPBJJܹ3'N`ƍtؑ<򈌌JѣGYb* oooLBee%~-_}oAk_9/As&MbҤI/_D}}}}QD;m46o,?^-tZjL"zb`` j~LLLhhhT,a100]vDDDxb233qpp@WWG2{l)..gϞP__Ojj*3f̙3(JpttW*o^LZR*fRСC888`ooOhh(clܸO>sss444DQQQXZZs8shӌeeet\NTT林2,,,>|8uVY|9o?'NlFY cnO+œtnHE f JuZVPRq%VZh̐!CD!KTT;v`…tYP F=z`bbuRسgjjj"2+)9allLii)YYYb\4+(..nʥK8~8ݺue˖iӆ0r簶[n1uTe~fp(Jrss1OiƏkуR aܹ,]C9@ֽ{wQ38}tΝ;!{ݝ_NQQ8~ڵk~`HsH :t@zz:۶m#)) LF6mHJJBCCBQ(TTT0vX=*B|״mۖ"9{,*[LNN[X)@JJ/MOIמ$0&Sc্:::6v7P5AWWWPmƷ~ˁ8p 而;333ݙ9s&ZGvZZlɈ#8u>doҧO԰`ԩƊۀ,n988ZzzzHۖBܿJE-9s&ZZZ\zUiܾ}ӧ7R0aFFFFSSSݻ7iii|ryױoVrnzOᑔ$ꕶ6 [n%!!L\\/]|c2eB={hhh@.Nvv6Jnn.:t`ݺu(J,,,D$@&ammMxx8cǎEll,vvvՋ͛7cnnNeecǎ\xclVޞ 555X0 kkkѪU6{ҫЯ_fδ$$Dnn.XXX43񵴴DTr]f͚裏FfAA , 11͛7&?444PPP@dd$ g5׮]c̙XYY;ç~*t$)M-**"==}}}4~ ڒLn011!,,Ӿ}{rssb޽DDDzjT* ܹsUVa``̆wlyiuuu|2X(]T*bbbBٳ1b{%((l6lK/$nbD gWWWuuu'NCC(\xiӦ\.zQDN}}=jjjTUUabbB.]O>aٲe 2s5 ¥K3f ;wJ_4E]]6lƍL67?߃ܟ ?hii3j%%%iРG"8O^gٲe|78;;ccc#zdffbggׅsN"""(,,חbZlzɉEѦMvACCϟe˖rrrr8r?;S\\LIIȚDEEn߾MJJ ...vd2r9reٲe|gg!z,7nuVtuu9s&Fowww<իYx\Us {бcGr9 B8 * ===fϞͰaÈӿفFAeeeq}Q+M%%%DGGcnn.r<)--D155e…;w޽{Ƶk׸pl߾CCCΟ?/#QWWǭ[ OOON8kpttXu87nAQ Qi:1#T__ϖ-[ E___\4FrssEKKKIQQnϟŋQ\\0h%xO΢Ed8991k,"""8y$˖-cܸqJJJe7/9' R9 ;;[,p#B+cOlٲ>}k.zѣfҥ2gLڵkhkki&QLϺuXlS\\Lnn. .YR&66VH ?^ȨT*jkkE݅a*){uHtbbbDa(T*100 //ѣGSPP\.Lƶmxwׯ7o͍vɘ1c>}:C _yXZZfMbb"ׯ_LJ &/\Brr2|ᇘGK/ď?5NԔ .ХKr9<~d>$<۷oSXXHmmp>ڴiEsnnn魾>?555tttСCRpww2vX QT|899Zw}W8v%%%,_vOݽ{xbbbhݺ5tڕw `LUIQC1o<ΝKݟI{4wI֓'~H㽼\# ڵCTDYYV"77D=[o%E???/_Q( AAA̝;www>SJ% ?oݺ5/^ԩShhh`hh(DGmh׮wАR166HM6瓑֭[CSSSqqq׏T̙CPPX7x{{3uTd2w>""u1p@|||pttdÆ ܹW_}wwwbbb066Q .0j(jkkqwwGCCCdQPPph$r HIIY۷os Q[[[Ņ@.]EEE 83ga~m,,,pppc2}t&OO׿Mǜׯѣ(J455QWWGGG}]єQMM =z4w說nݺI||v؁6̘1y uuu899 \.$/\ jO.D>>>̈́YKKKݻLb^  OII <[n >333N8={5kaaaK/[ݬ())]]]J%Au]r[nѷo_l¾}ӧܼy{ƍ7۷9}4mڴ!44\&5558::ҡCBCCYt)DDD m~~>ZZZ"$91բ ޽{j pee% e6MMM uQݻ ihhҥK" ?ESSjkkE4͛듕%J9mmmZnͫ*^O*5-;H ++?L“h2"3)4>^?tL& SN~zT*r޽{cllLff&gݻ|7( .\Hvvhb8~x>| ).Y[[ǏݻX>66N:q=!Q__υ AMMÇI-7n,^XWw!88QWW'##;v`iiNjW\bS).)I窭M6mx0߿ϥK޽;X[[W_ΨQPSS#??;w믋yk͚5j (ѡo߾ 0c 7 fJnƒLѿf?E'&&&ÇP(Гaʕ^:177ݝD1?qqq!<<???3f sΥsܼySٓqEZZ ե9s0f ĩSضm .|ff^ [GCCyfk׮sINJjjj3ŕ?gMzR^^CΞ=w}g}&zHֲ2^ؕ+WNK}}=hhhmJKKԩiiiܾ}+++gggmh4wEC=4ڶmB >>R kװAGG 0`{ɢcSݻaر|R$99\]]E9sPSS-PWW\f=)= Ǐ@MM¢rڵ+111ӥK<<>>ӣGN?A9~ .RZn- ?srss9yPL-..̢"""">|8ӧ>|8F۷o Qذa}M+mmmttt9s&cƌo!..ݻcmmƍ4/l"0cƌZ[ZgT*w΄ ذa)))%畕E^^XZZ6+LMMQ]caI9r$WndԔ|ZhԻIP$??8:5W>ۺ] @" TVVINNVVV|'sN,--r C > **VZ?,'E5jgۻv=N:Nff&ZbĈlܸQd3Heڴi,X,X@EE!!!̚5Kl+-;wfϞ= %C3rHFͤIxF.=X[[O>篟ר}ʔXlllD-jm=[n^ruܙ/---4h:t… |HLL ǏƆk׮QTTDLL ~@xR4`rssquueȐ!`jj* L&cmm+V@Y N*Ջׯse;;;233ٶmŨSTTD=055m\}i;f8W^PrxŅm۶5ݾ}:aÇ)))󉚚ZZZ֢)aÆ-*@Ô)SС8;;ӫW/D_|>g?=W*ͲQFqE_ެP__gggΝK}}=>>>@cSAAPBMmm-fff`dzPCg#ڏk|c,!;+-[Ѐhcgg qqqt B{UPx ZrT5=x9s0tPF D;_f#]v =Æ {---&LL&cٲe$$$Annp *4EWW̙Ã'<<\(өS'RRR@JJ 444Uyy9;v --Rjjj''' 7cgJtp.--EOOrrrra<66llldbff&xxxp Q0~"##cу\nݺŦMW^8pٳg)z; fffB!J4æm7ަgN\.Ԏٹs'X7aIJJ q$11 pq/^)C}ysBՐ'n ifffkkk߿Ϲs{CEEaaaP\\,h[͹s077GWWGRt}}董Rx!={R(J233ټy3tЁڧee?~ḫ#!!!ܹs{{{H?}{\.555lْgϊ̹s稯TTTf+Wi&yT*WkkkѿKMMBBBz*$&&bbbByyO9ɩs玐޼y3H5(4*:˗/ Ul9x [fر呝ͽ{2d+W qO"Ď;8uA#^Evo'2d=W2ՓCpu{x2L&ߒʾ^>"v / [//-x1^Kښ[n_OOrvKx?gՕٳg3df̘!C`Ν4~ ٓd2ٟRGmff&XYYqAvիFYӢE K9x [nϏ@֬Y|@vv6 q1fرcnGGG\]]}ܻw 3G&s1ܹs}߿R;vLp;ẇ~/dƌL2uֱuVi۶- :K.A~0`nnn|ߊT#%E<$=B__a1Q߳}bc)"df(33[n:cРAcjjJzz:ӧOښ#Fйsg)--aaaܸq(fϞ͸q㨨ۛ,177'""KKK֮]ɓٱcxxxPYYرc0`>hѱ~ˡ8 L=5oNlT\ڴifff?y&GۻеkWttthѢ::: Lhh(лwo._yyy(Jf͚EΝihh`ĉ\zUd?2"** )#eKf #""X~=wCCC222ۛm۶Juuuؿ?UUU̞=[Oݺukg!Xd 4sΉ% dACC^[S<8#zwŨQqΝhV䝔ܸq'''XnǙ3g3g*FǎY~=CE]]KKKBCCc<֯c2t %T,DcDFs5&hb1;6P(REwy?ξ&޸3gSg?ϳ._fժU\zb/^̛oINNMT;Vw5Oׯ-dk֮]K}}=7n3fƍСr,ݻ,_/ȑ#yw{QSuUV5 ???R)3rHJIbb"ӧOo"G'&_7nJ o"Y$~nq]QQAYYUUU ABBлwo.]̙3 ''6l xw4۷o.\*^UUEdd$JR? 8W մjՊ'NEff8f===nݺE\\AAA 4x|G9r"Gfh߾=oꫯrE/^T*%11LFͥh(988^onʎ;6moB^IZϲeX`xxx΃077g///ndkk+b``6w|dffqYY͛7gDDDУGvAfu$ tuuz_ffXؕ6Ѡ/T*d HKKѣOm_WWǞ={Ң}Mmm-YYY`!ܹ3gҤIM4?5"J7odca!4l0,--Yr%ݝ#G`nn'ZZZTUUѻwobbbͥy꒛55Wvrju?H; ]WW&NchLZff%8KR***IHHێ3>|ȅ ϸW^+߳h"z-011#!Cжm[RRRhӦ GEGG'''R)DQQ+W$??=zO$[[[r9~~~XZZr5 AKK 7oR+VpAܹ@Uq> /I;ss3Lr汱SUUEǎٳ?4řL8K.QRR"ƑT*eҥZ CCC0`/+V`ܸqKM#`ffT*}ձm61XP-4'{4~kʙ(66[[[Nʷ~KUUjhեB%MZwӄhATT/_,7nܠwddd0b:t@֭ٷoNNNX[[&{Ҷm[,-->VVVd2زe cmmĉٻw/yyy[T^{56l@]]RTTӯ4Ʀ $8GqqqTVVRTTDee%w "">}h"7o.䘓r #F >>JA]\b6l`̘11--&U_х jڶmKmm-ZZZ8::VϏ Ο?. IDATd\uֱw&IwqV,.~.ˣKKs`„ 14fq2dsükl޼w}ɓ'ckkˮ](++c̙^SNѱcGڷoOtt4|@ÃիWtR B<~.\=zVxh_666H$:߼!M&4eee·%$$DV|w KccclllLrr2ϟqƱw^-[B@WWKlll7`cccT*bg,vsss ΀N<ɀd8991uT]ƛo qqq2{l8#G/044UV8::ҽ{w9vzB&ѭ[7(--%11 퍁$''V m T<==5/LFFXFFаBGG?΄ 8{,oOTTmڴAPc<ד֭[IOOSN 2///\\\ӧ׮]#..'''õkXvK4hSƿa7ǻ!ɰkֲ~zݻGYYӦMCRѥK<== 3uTwuuILLd 4QTtڕaÆajjӧf(//ח{4֭[H,CͅJdii)< 88cll̙3gD2UVIѽ{w{ 槧'tؑݚ*&ˣYf|'|'uWƬ={w`x~#E_ӠTTTI޽{~zFlذ)H?>SNeݜ>}>0BCC)++p>3ܹsT*V}#Fp˪U5kFFF( غu+===iӦ cƌaǎDDD4Yhpq߿ӧIIIaܸq*, c['kP|gxxx+pظq#[N(蠥ɓiѢ;wdʔ),[_~l233!!!:z-<Ȍ3prrQয়~LJm߲zj҈ԩSl߾kkkj5'ODGGGŢE(,,DVc``{ӣcǎtؑ .h9̌вeKnݺEHHzĿKTJ5NNNEmm-/_Ν;lٲE|>11CCCQ=L:QFm6ڵkѣGp?mڴĄS2h eرl߾ ,Xcf_&s2d{wra^y=z4>>>|ᇴkhݻwwcDFFҾ}{<(-9x f]vGhh;00ɓ'ӻwo85k?>rV\IeeH2Μ9S¼̵fqtt};B#O/xC4%&& Gm\6;vښL233O>L6l>|Ȱa@NNRjСܸqOLL GT18vPVVF}}= /7OAAJ=z`ccǩ_~l߾#G H|d7(//4ڶmKyy8/ Y(Mc^YYH5ickk @wo+DeGHkggGrr2gϞE[[SSS8"@8p k׮ü,vɒ%deeP(8|0'NRUU ;A=z333N:Eee%?-,,(,,$##Fyf ^3g_-\~SSSvUUUR__O\\TTTpuڵ2l0V\ɤI aРARQQ!gfM5b hiiaeeśoIQQZZZd2ܹÍ78}0vXtuuy1-Z׋{JѣGyw2e sK' :wwx~o?zRoߞ8>cQk߾=4k֌!ׯ{ڵΝ;ʹiӄ؎9ɼKz1233qqqKKK˱<ܾ}ĘjCz E"M6 0iӦqQLMMz0ܹ37oСChт$tuui׮g&33 6ܹs",Ν;:u mmm8~Vry ;^<+E"4J<CPPqKRZnǏ@c۶mS]]-а@?~<;w&''###.^H˖-&;;qСCQTlܸ1Ӿ}{h۶-qRR%%%lR(Ǐ9ܻw>}r-AK4hM&S{{{DXȨ _漾=4?Ƃ6̙3Nʌ3dǍGAA֭cуYfNII Ç~( ~:Vu̘1^߳aܰ!!!???233IHH kK 䠠 8y$Of޼y %ET믿Nhh(FFFH@@DGG3tPBCCٹs'EEE̜9Ν;c…Y+WrgQ\]]H WVVrvI>}عs'*n߾ͥK022m۶TWWSZZJMM uuuH$G">M@II ۷4.//ǏCddϧgϞTTTтmۊCZ-z9r鉤LMM=Ǐ3l0?~'|000@Ti&Ν;'EEElݺFә2e #F (( d2>|XHeݠkmxW_qaR)7odЩS'3}t>s֮]֭[:u*FFFiӆP9Fkoo;$%%vZtttx7nHѱcG0OM>hbhܫ>cɓdggciiIaa!tܙŋ3gvJN }‚H>c>S~ QQQ:rssQ*hkk(,^ѣGH=x뭷>|8BzV<:ĻsТE f_JHY Օɓ's̙&剅ܹs9<* > ),, 駟<7o_GGGcǎ=TWW;;;!힒B ..N=<}1100Yfhii ix +++xZZZ0dL"2{BT;tR_Ε+W|6k׮̙37ۿt *h\5d,\P,<ȤIĜO?ѬY3E ASNtBA||<)))"gggtuui޼94ƵkHKK#((H>UUU<~:tؽ{wJ<4?$%%QSSCiix_͵kט5kIIITWW3n8,XGP̛7[oquܹ3C !**ߺqKPcOL8 ru>|BCpBHyy9Nll,2rA~LMM#;;ZZnD/PT'B-믿PRR6ݻwG"p%anѣ$&&e֯_Ν;ټy3/_fĈ <}}g~|F׮]9t_~%Կ#^4jljVyӾ ?~\ addāˋcǎQ[[˚5kXt)"]\\ؽ{7B.&&iA^ 4d% =oOQQFFFۓFMMhFVSZZ\vM|=ݻw󤧧sm233Y~=ϟ1֭#((;;;(//G"/a)߾} /y~?h&Ǥ$ XUTT_}9991BTPXYY!9~8/2>M L>:uDtt4={̙3jԩ˗/glڴaÆ Ç)IIIu֘ pց/BDψJbp}&&&h`ܜ˗/ӬY3ud2\]]4PWj5<|}}}lmmjPKOˋ4_J&ѣ,X$˗B'OR\\W_}ܹs ---ܹCjj*R,VIMMeӦM4+ϟ?Ohhj*9999TUUq1jjj•K~~+ϛwyի]vĉhkkK/DaaHA2xb$ ^^^TUU ϳ͛SWW'zzzk 4C2`_Α#Gä#H)--Y:!˛T5jy̛7wy''' ۷yYlSXXHPP/3i&6mzzzDEEY"-|47֬YÄ r YYYVǽ{8ύ7D;&55UhF D˗Jx{{s-"##99spڵkGVV[no߾xyy ųTr\>s\U۷dLxC4iӦIɓL0/mۢT*TJC"pI/_oȈ;0k,.\D}6;ZZZGP)1ckhȶ{{{SUU֭[Q*xxxPQQi~jM#PVVƍYv-zzzN>}߿?yyy“B"P(DKUU6Q2663kԵPJ4Íݚh.](++VZQ^^΢8**7o2qDʊjΝ;ǪUرcGETAͩ={Ҽys:t={Xp!K,Ã^}U,Y˜1cP*dffr]Zl)dh׮iii8vk$--:OVV*o>:t耶6K(9XZZ2dAѸw SSS ɮ]5jh>~"###H$GNT"00'w+++<ȉ'011͍۷chhHrr2ڸL[pssCRѷo_ٴiZXX˗E0`gg'.\ <[nk.$I5c 4&D뉌$!!IHHT1!addĴipttݻܾ}RBǏ%KGGG>N:-45ө"99ӹsg$ ÇP(\xLƢEFVsy̙3̹s \ ]ߕbRCyԴɵb Z˗/ 6m%DRڵ+GAVS__/DӍJ%>EC200KKgr5Ihk.1rd2!!!7QS(b$&&ΐ!C>}mi-[pQwpp0J4TYInݺ=֦[n>NּysΝ;yyy\3gpYA޿?Ge8qhx.R8xx~wޝ[n5 ◐@HHNNN̝;SbkkKff& gP&NȞ={ضmB(CaÆ&aƌŀy^TxC4Vi :77IͤI?Aqq1^^^ahhHnXbhv444$<<4ILLdXYY ݫWRQQ3'$!;;[M{8t@QקLLLHLL$++ ;;;=zDee%W^IcooOLLȂeff"h޼9###ׯcmmСCEJ[vv6Hҧ+_"+=P 7C⡱6 LoB'UÜqvv&??ccc2Rؿ?gդ)))Q__ODDk׎Tа>~8AAA,\*H۷/8::i&,--100૯&AQQ4dgggd2X+-Ʒ0ߍ{addرcIII!66 .9|0ΝCCCΝ;Ν;YhZZZ`llLee%rTTI{.6?OΎ޽L&#..m۶HXXIII0vX>j5̘1M61j(_.QQQŋ)//]vj9q(JjkkӣT,6~=z!iʊoFHlke5tRڷoO~x饗HNNφޓaWvGR/? zk:MEE:uU0ѻQX\lgΜoA& pTsձm6tttiӦ 6l ==ckkKAAW\JųE\.'11Gq}j5 \agϞ#˩G"P[[?8p IIIϽBrrr044̙37$ΝJޞy닓ׯ_4a J<~X5FDcHB%( %&&^z1y&U5\t TS hw!I@1qk׮/dʔ)L4 [[[~6l |^P >>^FWVV'N ""777a^jbb"Dr@de5җ۶mk׮hkkcmmM-bӦMѻwo6[[[v͔)Sܜ6mڰb J%{e#AhܣX?lϟ_;}***000x*|}:tիW4144D& ejBCCҥ w---P 8pƍG~x7%>>^dwg̘Aff&޽___quuC"ghC^V )___ju___BBBp}lllppp ##SSS/^Lf-ogϞ|w޽m۶Q[[K.]HKKJN zy_-xuּ,]|||Xz5;wGGGy^{5&MĮ]Tȑ{n֯_OZZmڴXYYP(FWW ՛w$ZT*ET tHaR\.'22YfT*  ''KKKΜ9òe/ ++K,ٸq#IIIs-:vɓ'ٹs'___Ac"##v%&5&rw} &PTTĻˤI;vS)Y413663339v 7޽{9s ۷o_/ '''Y~=ܺu:VXB( 䬽psscӦM0o<֯_8::ҢE suu^3*Aikk쌏V$_\GGG222|2eeehkkӦMyxxʱchժ6ml޼ٳgӬY3 5?R)NNNdff2tЧƽS@'soA޽Y`4z֭[޽{ٻċf1᦯\vСC>zBBk׮RӧOӓ]CT*JZF&ajj*P, 48{,ׯ_'ӑM^ȚGvv6󢨨#GpBk~ ;;;ڴiCzz:[l!44www,,,ˣx^h/999O5CkyC*-w!::Z,TUUaΝPZ~=of駟ٳ $##Rȑ#:t(YYYC~~X@BB[[DBpp0{ƆHlmmquuE">|8'N$,,f͚1wܧn:Ǐ=z4ӦM+WNΝ>|8BjQ bݺu,_ǏsQtСCqtt[^^s0gpssͭIXOLL k׮e 2˗/Cpp0*@ )((SNGToV '??4D5k׮趂%KBX___°ʊj5-ZC'++X~Gdk?mڴar sڵke˖-bqP{BV, 4\\\7'zDBR*4SUjgh,YŒ3ԩfffBGm۲c E/B###tuuQ*yeZn6T*69r$,]k׊>B͵V,[ ///3f G0A*һwo>LQQ.]ՉիJn޼IBB DB{?PZZ- wx~'<9adgg B! RHR"##=z4_}]t [[[!-(((B%iihVߟ܏ƽ2 '''̙C\\ BjƙPSyҥ dee 6mPPPȈD^~e222رceeeKݕsU7oN˖-Q(hii1`h׮ipvb5ooooa &&6y߿ϨQpŋY~=...D#c``/r={`ooO>}8}4={$66;"Ɉ TիWT!8;;C׮]???[oILLPqq>&OLyy9999u Fshii=khԱ~h$ݪyqTTJJJpww.] 2nnnlْ4wÇ)**bܸqB4ٙm۶ѫW/>JKKYp!7oޤEL8;;;'5Yкuk222ӣ333Φu|GBTmۢP(w}ѢE ٳѣG4iر|}&N(hl͚5kBQOwo4jժ8ihhGϚgijʲ& 4FƢҿdؽ{77nI3f $$zʕ+ٴiSUU%b/hg999l޼ &D"ՕF}}=8;;>:wG||<~;wdgg3vX o)++O>駟Ҷm[ʞ={ cccn߾۷iٲ%F"::Xy!X BxyyÓ zOOON>-ZP[[KAA9{ץYe]C{^Ύ-Z0|pӣy5B\ iii z?ʕ+E'!!, ӧ,===TQQQ 2333444DrWE.O s˼Ԡ5[_211A|_rʑ)ʕ+Yn?&MV8;;Mɓ̚5~ѱcGfÆ hтl!yHprrʥTD vIbb{sss!?Ă x wE__?{p9FEEq֭\]A[dd$:::X[[ʒ%KP(KKKߟ%K΁sϞ=/_>Bޭ[h۶-իWG&΋/Dݢ"ձI&nݚׯ_Ν;yFF3gDEE ,Y"UTTPWW';; ʗ/OjDM.񕔔077Ϗ{baaQ䲠!*Xߛrkoٲ%;vח]ry~7*A%pssc,\0_ηaZjLeʔ!##%K2p@"""r>}^ݻ@II {{{455ILL$!!LB]Xr%7ofʕr222Xz5:t@WW4ķ833kruN83HHH=(E(EOi5*&&7&A6j(Μ9C>}P,XM6q-∋eN eݺu,ZWWWD Y{޿C+455ꍾ>WM6ԬYiڴ)?_~aҤI4m4GGCC#_켐y)mOQBQMpkVQsIhAi˯Faaa3РSNݻիW zԩStï48EMIMMe޼yܹsGȄsUVZEVVIIIhтΝ;s)9ɓ'144uRwEOOW^,XXXP^=:p7à 6ŋTV .`ccÈ#ߟ7nArrTZMFRR2e=)UhР```@f033#$$(ԪUK;E~>JیS?Z Xiذ!/_̂ .?}v3gSLʕ+Lƽ{HOOGKK+Wpy s %ӧSdffrI4i#Zc6?k9E2fLLL000`"c?ZZZJVVVC.]Xb(++cFEff&IIIt֍.](CE(D)ߤٙ{n/^LŊ֭ AM=РATTTE:j*ׯ\.gݺu8;;ӵkWvxJ^nnnhjj)V322066fŊ>9>#Fu-Ǐgɒ%̙31c`cc#>^]A4+nWEKFQ O[AA'%Ҫ[<gҥKa7o<ѣYf ޞҥKIII!<MMM7o<|Pd$1###n޼Ihh(Ւh[&55YfqAܨZ*w!++KЀ߆(!$WKK OhRRRu@.ߤ¢0f=UV0l08p ʕӓ۳`t\.g36lȱcǸz*YYY4h===Åhhh(7nŋ\t uuuXd fff8<}???gW. ضmzzzٳZj\D f̘899(Q$&&RxqSNCQES&q$IkPOT#Iz~`m%FCeΝ_'n:X")^& gɓ'nZ.7&MбcGիWYf묩.\ &&͛7ŋDEE S*U|MMMF{Dѱ?rK,aΝtڧ :::~~KԶUEWNi"lll,,ڴi#(_FFF\v`tuuD]]N<ڵkET71k,^ʀan8|0/_FYY.]`kk˹s爌dٓÇuVlmm9t!qttdiӆڵk~&NHjj*={%KbggG^իWhтKұcGʔ)رc?>/_y4oޜ5k0ydqorJ}i& "##9sx1зo_.]Jň={*(o.[ٴi_ceeErB @N&f͚ΩOl޼9?=zPti͛7'11͛7 O')?>+VbŊC&M066رc^;;;TUUiܸz,ԕׯQQQ)Ci%\*mZZZWseˮ]F~]6'N`޼yxxxбc\Nعs',\)S党K.ӦM# %K-eիWg۶m\~ggg*U+Vqtؑ-[`BرcAZZ~~~bL`ѣ/_ӵkWd25jחcǢ=z m۷0auEII7]hh9p xǶmېoߞSd/ݬ7РA9ڵk)[,Ǐرc_\vFɔ)SpqqI%={6111 ɸt={)SP~}FӧO{98ѡ]vyfFEǎsŪUؽ{7Ǐݻl;ҡCu֕ʯl@aV=y7$ʓk͛899qyZnիE@Vh߾=BŅ͛rJJ,Ʌ Xlݻ O?СCIKK~6i<[[[ILLȈ+W퍡!ddd`ooϤI9shݺ5&MBUU5DEEQn]ƌC.]:u* ,xbʷFKl"11Ǐs5L||0eOFFΝ5޺cmm9s m۶4k֌_Y(VϧI&b]_U2qDZnMppz%۷ogŊ ogϲ|r֭[ 2˗9 уׯ_}6mӧO;;;= (>d"##h!Ν;ӿLLL([,fڵ4o9"Xf =">>555u놵5͚5xxxвeK*T˗/gԨQ㏸PX1*Vmۖ,VXAxx8/^ܹs8::Ҽys QF 8~#GkvɓQVVfŜKؿ?g5U_S e,2d7n$00ݻw&w>jPpAt$9 Æ m۶T\+++\]]ԤvDFFiӆ'Okd2***+VLȨzxx`ee˗/pJJJꢢµk f͚ţG}$$$аaC ~ܜMRL\Ǐ[ڵ x$3Q333]ƃ011y!BŽy.Fax Eډ}jj:>~\*e\t#GҵkW Glȑt֍ɓ'caaARR)))TRnݺqF233ի;֭[3bFAVVəkΟ?Ύ;wSX[[FٰawϟCTTTXp!]vE.smr9fb@N/%%EܫMU|_H Yfffx{{SjU!O~Zh!N>۷ٵkժU%%%6nȩSɉORti/_N2e([,BTR,[Ν;oパp=z~~~lܸCCC=zi˖-?ڵk0d G|ԫWggg\\\066ۛΞ=Kvv6 VZTGvO"D'lIXsB\5&&&6+ T=yW*^: .LlllWQQQ<kkkƏτ Xl^_~֖3f۷/&&&={'OS~}.]֭[񹘁%;v||۷177k׮lٲ=JժUY~=j [[[nܸ-[Xh#Gqƨq9:ukײsN"##ӧx{{IE4nhٲ%-(WDCԩ ...s.]ʰa(>'*UJ1>}T('99l,Y©SR 9s###/BCCٻw/k'5y˗ԩϞ=ٙvqEYf SN8昚MΝƆA˱c1b{eO{=>J[,[:N~wT^xfff4jԈmL|"##3f k&;;?CItnOOOTBy%]to߾,[ ///nܸ?w姟~jpuu%88Gׯ+.\ pttCDt AեTRdddرcQVVF.cdd-SN4jNq{$[zΒ,3xWT cccڷoρٳ---6m/f;333Μ9O??b-[n寿"22#Fлwo ĉ)S UTKoooƎˋ/X|m T틱16ldɒԬY`ܹ&M~dggST)֭ڵkٳ IjXʕ{|Xw%KT+4p@!c >SN1|OrӱcGhݺ5dʕ+ڵ+]vOL CvT-͍={`eeEdd$VVVl߾kkk6mԬYTw5So߾='sUrvHNN>~Tƣ#?zSttX\p,-Z#ǔhr9TVMIry#BBB055իWs=Az~z_؆}!8~87[{ԫWUUUYnDDDm6J*EժU % +dxHMMmvA pvvÇ$''2xV("ku122~ooo*U˗/ٺu+wa„ ~,--}6hkk3%J $$Uș3gdӇsoǒ%KpsscŊm6vcӫW/222e˖̜9SSS6mʉ'y&t333LϞ=_~0n8"##___*Wܹs믿s$(f:!f --MiY%%7hJᕾ'_C*Ka|z}\\kDkdd˗/Em}6'O$>>===\\\Y&())FJJ 6̙3o:w֭[qqqc566Ɔddʔ)üyI fԨQ룦Fdd$wASS5jvژ?6mԯ_YfQlYJ(իWz*G.05"|hii--w\ttTTTpuuO>̝;;v >̨QXnSN(&~< zw+W$:: &PR%dhiiZ~nժ;vB=x>mrlBٳ'JJJz zE``}ЬY31QlР3f`_tСPAOQAAJ٧/A) (>D&+}㼒/ⱳy1cƌQF"3Ųeptt$;;\]]122b{nvMÆ Y~=UTaȑclliiiTVyYmۖEQti>7olٲ899Eׯ_yfF)MMM,--QVVfҥLvʹi1b"{&Lr*b׮]iӆ]vѹsg*VHxx82}uVO.eSNG@OFFvvv\|ӤIBBBc§J SJJ |8nnn9sX޽KRRiiiB-++f͚Q|yCΝM6QdIN8-FbӦM 0fɣGXbr1'͍=z䢌ݻɘKfSn\yQP̌>my~_ꮣ# .Ԕ1ccqtԉLdWZE-155%00>}зo_W˗iժUs-^}}}&Oٸq#nnnX[[3{l `׮]rw.jr/\@ [.Ύpq;wÇ k׮?7oxWET/_i&.\HΝԩ#G$!!CYbE.øOŢdE ggʕڵ7oa~g?q\tI(Ԣ+ٜ?2epud2vʡUUVSV-ΝKhh(>>>S~}Ξ=+<)111ҥKL2>|'^}ٓHy%\tIEGGSR%Aiz~լ0CݻwEZOJJ Ϟ=_~ 6aÆQ|y"## jBҪ4ࠠ ʕ+):t` 4Ǐ~zjԨ3g.mĉ YYY9p2dHrQn߾MՁj,BBB:u*/^gϞ=zCѽ{wJHHʨЦM um!M>6m)111())Ŕ)Sӧ$++ CCC^;۷O牌w,\۷B5tՋ_~I'i۶-ƂƑM=HJJ"00w"Yr%M6mVBˤISjjjԨQ1c`kk+ɤmcH7$$D?zKKK}0B mH J(,7+m۶̜9777ͅ_Sƍ9q(՜>zÇcccC@@Gŋԭ[W(ၡ!@8]XD?7G]]+rM5kF*U7o BKKkؼy.(Q"d| ԩSK.ܻwOLlmmE <--M0a#FI&)S{{{qttիّ 4 7n[[[ٙ#GD=r?~ٳ7oM4gggLLLZ\mllst^S^kok{އR"!odĩHa+SL?i$ƌ#{)"wŌ(*W,)SI@@ 4!+9ҥ _e˖/_^zyyѨQ#~7lll$V]];w2i$<==** |)~NfPpX7)/Vٳy^ŋ=˗/ wwwڷoM4!115kpIôiD%88\ rϳfџ8@TT1114hJ.Mڵƍ?3gҠAbbbWCYYuuu8uǎիWtޝŋ 5Y|+}Elppp`޽<|;;;5k;wFTRŋ"..g RJXYY ܼHNNf„ 7.Wb9rパJtt4&&&k вnݺˆTD>uׯgСL4 SSSΝKHHcƌRJncc#SiIANkd|)|SA LMM :׵(:w< 2 cccq K.]pwwe˖t֍y31׭[SKYYfk..\Ȅ 9s&dffr:ѣGHM6 +++,--Yf L~o;{{{._̍7x ׮]cСxzzҨQ#6oLZZO<ښ۳m6Zn͌31(^3nȈpF7666 0 6nȾ}4h BxxGYf? ϕ[111P剦*(,fFqy~sI瑎#J///Qp ?Ndd$;w{RZ521f̘;044$>>~u)QCFb['''N<2DEE1ed2۷oLm$TTTu- x$4o???ϟϠA(]4UViӦ"y`[\^=T #m/Q"##Š* :!!bŊ ͣG(U ,Ύ5kbbb"P , 88sss֬YCvv6͛7 [[[3IJJ"22R(abbB*U_7nhтŋSX1BBBFCC\NRR0GqIN֭[ < ͹so>ΝK=:t(accCf͘?>`Toٜ={^z LQyſRSć-$n]״uV|}}֭nnnUVdɒ̛7yQn]:%/_;w ʕ+2\|9G}"˗+hTիsMZ '''5jDnprr̙3ٱa(BeIk355 |w^ov&==d\\\hԨ-L"%%ETYŋsNl̈qƸo>V^_EΝ`<|={pQfΜ |qrrsδlْUV #\zE׮]СԬY%%\Ri%d^Q RYq(dKP/AAA;F&ȑ#INNF]]%K2{lΝ;'؅/)H x3iET:"8=z4OM6T^ϟ&U&6)Q/^$&&+dtǒo^HAGFF%|DFFlt=8sOw ; 2T">ь?LT.L:ȌV9" RM믜>}%%%.] m۶PrﯢgRRRRq/շ nEtڕ@={ƱcPUU%&&RJ@B $%%III!))r1}t=u%&&SҠAjժElׯxzzҸqcLLLG-DGG SSwNƟ={Ƃ ҢM6o]M?woe*8ESS1(;v,UV%""իWS|yjԨA\3f,_r/&&&0`6nHӦM~z~)3~w S~ǮW^ aUVōGZ|󇇇3|p w^!.A~/x[3<;v`̘1XXX`nn30sLp}=^!XBݲg޽۷???:˗/`ĉXXXіŋ$3|ݩY&***Pcj*P%MR oɥ|A''+X7oή]8~82)SP|?FGG:SSSDFU]aoJʕٷoaaa)S\Y8uuuXr%$&&~z|||H˓'O(V.g%\V ߜwAMMMv9= 5xzzʕ+iݺV C\ޗhjjҧOݻ7tЁrqM|||pFA㊦63o#GСC/@޽p}Xh&Б<3}kצ]vo>6oLph"'>u;0srr266&55U ䷿L& cccd888PR%i~tttB2dttt$PISR155- ,PhfҨH ˙8q"!X0e{ jjjc|||Xx1 ҥ)KPlw 2O{BaI2 $)) sssa@ 5ׯgڵ(++ӪU+ϟOrr2'OԨQ6mڼaBOa422"66VL, x=> fQ2I#FFFdee) E:u :t( [ndgg3r\89888qk׮]HQ~ז緍Y|Æ c.]:uPV-qtte8Pu WRR zT8{UϏEP<|`hhDFF nرcPl\Ʒ?%%X_ǿiWA]FSSSlȜ9sܪoo;D (Kҳ;aTDyzt":з 3}kHII,] WVQX1R _E_tG߾}X"˖-C]]c@022+>y'r]~[mRQPyA6>"BӧrCǿŧ#?xM(K u%wwB'k֠M&Mt3z_7@׻~ԩS%%\^<_y-?(奺&ə :N~I{S-uIVU(H%-**4AA˫" )-HrJ*s">X2֣G@[[;Wp>VPqppW߫MFǏGCCCwQ+E~*﫰'--|[111<|8r@-eMLL lE(B. Sc"_--- jǻ)h>W!~^ R^Q~tYɂVORH*Zu}?1 ź *)>M)O&mQ}V>X$))ؘ,444022YLn!'#) JOE(!|xۀ7ےrAĠ 3@EAQ9Es[\.&҅9·oE"|8uFwS XJ"|{7 *뇎m)(Y#++Kk*\!9룩ILL b339UX<t/\F0 QĤjժ=>WYll,<~d2X[[ )(QJ>4K7n 55###066&%% s]E֗Ǹ)))bQEd<|###d2B5-ꟴoQHNNdɒ(Q}eɒ%[x֬YC.]hݺ5!!!+VOɓ(ȏ&;/M v&D;{_ Dk)BX&allLTT;b_-|(ƂUwPDFFu^dŒaE/9y%Sn##\4]d)3oǕ+W憑舌DK. 41cquu. /݀ Eɓ'?9 |\| hddc?}7ZSаPm~_W_K>V; [ ;|osÃ!C0vXٷoǏ[ίܹs9r;wPwQQ]k_h1 "v#*^[4F,!FcDˍ=cYv{! b;hTAߜ; *m [˕030sfO7XdGABCC_-''GWyO o}xkS>Pʔj^|I>*dzW]s]~6*tgϞ *eHSʶ{]}5궕>OʼN6{-m3rvNe9*~*o,Ֆ2Y ڻw/]|bbb‚ HOO_^e&ំm۶N7&¿:S>&MuWe˪{AOe9WFYr0!-nTfzȻ~EMY}鰲/TdzϛVcY '---ISS(11ÇH?3i޽ԬY3*((C }.Z_W(..J=VWRi>~VEJJp]v"n{ی3/o߾}bG`O]]]ov_~DDԡCRWWf͚Qrr2׏222Ɔ,YB۶mvMԭ[79rdۼy3oԡCc555#zM1[o1yyЀ-v1yyc₇1c1xc1Ƙ₇1c1Q#wHKK;\ԗYʞSՏUP!S_iiI31\(CtQPdd$RxxQ(<<)00P(KÇdԩ0|Ro(??_½2nTk҆r)%ooocmU}t%"*;]JLLGܲ]~޽{ nY޴~z̔sHa !HДMpp09s2*shʔ)HTTTTzԩS1uTT,~~~hݺ5.\;bӦM%/:we˖Ex(9 $$8hܹ3"##{o L4 k҆ǎCnУGؿp… 011A``h*ⶪR<{ ڵ5Ν;''H̙3 Ν8!")K:}4v L0III {nY}u?~S=k޼yغu+爊rE( <<;w?ѣGu)66::: www̞=;`ڵعs'^]*]+L0^^^mNNNx˖-[cO[n уZhAw^rrr {׆ ҃(!!lllCdeeE6m"UX4/W^LF|Zt)ijj²ݻwN8A4n8@{t255W_#DB ={6Ӂ̌>S#RӦMΝ;4rH֦=z|@'OAJKKחJKKk҆t8p 鑡!5hЀ_Ndff&+)>|fϞMDDtq b266Vx|Rs9rDJJ:ߟ455o߾t!JHHk׮Q=DSx_N4l0j֬ѩShԨQiNJyȠG5i҄-[Fݣz Sm(<<ĄHQQQte :M4c ޽;ݽ{())vIIIG?ٓ>#JJJҥ }ᇢSSS^zQА iԤI$555*((PXVVFk׮ԭ[7jРSLL QmkйIDATАtttH":PDDjՊ:vH JPtt4PVH[[hܹdgg'4G֭I[[JJJLJ DWӤIΎڵk',)66nܸAVVVj*8p mڴ>55MԷo_JOO'Zp!9;;9444DɘIM6b:~8=y @DDԨQ#:v 26l(kN&&&MgϞ%wwwiGgNՕn޼Ik֬!S :t ccc DBϟ?Ç7|C5,|v4iByyy!---JMM5k͛o 6:]tvJZZZr eff҂ (::ƎKW&### 6mAtARWW' VZQqq1QVJ˖-'DB666ԦMԤ yEJMM% RWW'uuu$""}}}ԩ\ڷoOqqqN ?H6t;-͐BIII4p@:y$%&&AY;{aBL6 3f) & **J8=}tܸqC<~sl۶ ĸq?3Og)___4o˖-dggcÆ رcd|%7lmmlJ.~g1O>ĉE 6رc(**B^^6nܨ4_~'O˗/,YDxL6̛7HOOʕ+1sL<|@t޽{ɓ' {-Xj.\(L<~8~W1999߿r/'%%aٲe5km555_BQQslĤIp cΜ98p`sz:t(K.EAAܟ(C˗/@JJ pMaÆ!<<\9n \] AXX 9r$ X`k^xQ{8|p/oVx8ufҾ|-4o}Qibfk{yya8rԩի{ؑst>>>rrM !!@ԩS?bёFb7򂅅E}ڳgf̘WWWoh߾=BBB kkk<~L۷oGvv6Bƍnݺ:{=!8p@KMM'\\\qF}*b8`ܸqpww_+zh۶-ܹ|(.\@V`ggZF.xٳgann;;;8:: SَR\\r]ܹs055ň#0|pdff( iӦɵ) ޽{aff&JѣG¯4'ݻwa`` ,xb^\A}vXXXJHH@-$III8uΞ=cʔ):u*lllp-g| ,--=-JKKEm;vC WWW#=='Oƴiʵ;0ydooppp@DDrssaÆaС ;C }Ə t֭077WHȀ-+e{bÆ B^^(mL>)pEDDD~Ϝ:uJ^f$ RSSѲeKmk׮!$$ lݺU}7oŋѻwo +;ֵP={G:Yfvԩ*.tucڵB6l@.]RVzZZaiiѣGCWWWn <<ٳqA PRR˗҆UxxOr ״izHRͩkAAA0446t_~%+an#K```# +TUVVC>"??-ʕ+ѫW/gϞ>}:>3̙3III%J|H2;v,`Ţȍҋ/o>̞=¶E 1~rW[Z=YYYQnDDaÆa޽g w}9sO>?>`mm/^P|[={ܶ1!!f  -¥GC{9&L>EEEr[ڵ+޹^d BoooXXX`3f m&W1WnnrT|턬KΝ0bĈrS*~ת^v-/^,L}6͛7 ڴiH*{yyEEEx!={&JF,ٳg0a6n( `ĉ,+%Eʦ?N!TB{΍quuO?<}T(W^-\b7P6ݻ7F]q~~~r=ӧJs~~~rO7n܀gѣϟ?/j .5ǵk`ee+W[| !}MΝԩS-|F]}}}aG+U/]NNN:Uɨ-īr^ڵٳ'988D""z)撚%&&ZYLMMvE3f ___:t(RJJ =y,--HW J8255[dmH]]JJJhܹTXXH/^(wXK.^BBBtsΔ*J6mJDDDTԤ3gЌ3(??_v3Њ+(##ֶO?3g҅ СCt-""ԩl. Y.oz16m(t?otB[VH\}MMMMh#kkkڲe P 콒V~tz9M2E=""={& 4UV_Eb ~:I$"*[(44T9hdaaADDtJHH2)E+W5GII m޼zMk.ӧӌ3EFFIaÆQiƍtz%YYYѐ!CϐXmikhhjڴ)_M}L抍0*..sҕPi̙tM S˖-ڎVߏ9sZ4l09 Ԝtdddk׮?glO-1m(mׯ[uOߒDFF ]t%KЪU+"66V}i{Kƍ|ٳg!tbd-CX!}*$ .^{{{UMNNNVH.lm/Fv'(%+!{^W_a033 Ej% lxzzbr[Qr]M%8qb,m`)E-TPLbرBy1aѢE%+#2r#'weBEEEEQ%9Kaݺuضmr@,\PĄ_Ջ-R|X`AINNFNN0HvQQQشi/Z\7nT乢fMsmڴI*f=p lٲ}w bbb`aa!iBs|9rBX*kEw^QA;C1]yδb8pNNN(((Çz2r#'ʲDL :TM6mЬY3ajFFFqFX*~n޼cǎGQs)c&eൢۈS^6¥KvTM9bccʚذaCW# X ggg"OF3^]ȀR)Ks)c&@ysʓs9|:::U2EquEF5@jT1"޼yFN$HźgT|ԤId e̥7dgDBjjj\|C<))Aݽ{Ξ=K5*w8c1;.xSrsΥ:s9c){>cR;c͞>}Jc2`bbBԦMK|U˨QښhǎDDdkkK"'c]žմiS#"FQ)))I䔬>Zp!=z,--i4`j޼ر [v"""ѡ֭[Sjj *:u*=~ B6l;NGxXdff瓭-]tZlIDD-Z#<ַʊcǎeN||< >\8CDLׯ#֬YCba?.xX䐖ihhPLL TV-dɡ]vcMm }FE... r2Ƙ,ƪlȐ!$HԔݩW^,X@۷|ե+V3DZf ݿwN{nz?>}9͟?Kƍ@ե#zJoShh(ݻ,--Ғnݺ%vD"t1c1Gxc1c* c1Ƙ₇1c1a1c,.xc1c* c1Ƙ₇1c1a1c,.xc1c* c1Ƙ₇1c1a1c,.xc1c* c1Ƙ₇1c1a1c,.xc1c* c1Ƙ₇1c1a1c5%uIENDB`lmfit-0.9.7/doc/_images/model_eval.png0000644000076500000240000005271713066042256020560 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATxw|da 0غPZUAڧ>ZJ*Dq2"dC$ ðQFs{|ޯW^+>\"h4*pAƒ5p k( \C P@5p k( \C P@5p k( \C P@5p k( \C P@5p k( \C P@5p k( \C P@58?_tըQCgyz!:tv4H4D˖-S=nM/jȐ!z뭷lG\d;@P+:r}]y晒*))ф gթSrJ]LrHJJ$)--7nDURF,* CFFg?Km޼YƏ; k@a 4Hk֬_-a Co߮J}Yկ__ӦM?F;p# =z^|EYF>j(MsJH1!*...vI***:󕗗_~{lcǎոqlǀKwx|W딟O Cu^{Mk׮Uv=;;[ܹI3Tn܈ RSS!wp8׿x wy=zիiӦiƌոqcQ@ҹsg͛7O>{1>|X[֟'{カVP@t9hcIEYYY#E\pz (; `` ;\ʎ5p k( \C P@5p k( \C P@5p k( \C P@5p k( \C P@5p k( \C P@&vhTz CJ<8h.ipi01b C_|~U1gԩ 03#g!-_nFA7ݾ}l}xJHH8G~~S#p{z4a)-,Bwmݦ~s[IIn6jJM4 7馛fNͥoW;]5Kz:O>DԵ^k)=Yh~}'/瞓ӽl,M4IHD#GV_뮓Z>׵n-]{ou/Q@\TXXɓ'?Zha;/7F˓^zXxE3gݻ~T4*=}g}1E&MR*U4|pQ8` iziԨM7II+W: /dzտխ[v6MQCυ]Ms,.X.y뭷tС2M;vRSS-++KYYYNӦI}Jժ{U33mکw/;;[VPP`)MpP@\2qDժUKC 9׎7Nݺus!xٹSSoy ,rٺ~gTLio/^XS\c͙3GW^yQ1}TR" T4|P@\ꫯݯ6MCjܸۤԽ;@@qIԨQ#]r%p@a4cte.3QX\xW~~"('޽/ {HQ@Mӥ]+~]XL*i43QA΄sS/^DJ˓֬}g+?WQ@,0{}#v*ays65`ԫWW/  ( PAǿ,Z$> TвeҡC/  ( PA Hɕ;xݺIIIL*hK)%%~b* TPǰd]k+ k֘ h( P}f>;U@$i7Q@,6Z}n-5h4,@0Q@b?"w$:@pQ@JJ,'_eĹ Ӻu޽R=9H{ H( PNKgctl>s": h( PN˖Iii)E@P@-aI;S@CrZT^i 1 ÊR4hTZ-(K鬳22 $(eˤvzuX,D a2wtD (uoNXѨ{ ( PF۶Iv=sgiNiv'Q@bS9; ҥRRV=ff1:;aelԱن- 1b $("s"rQ@ ֭NY:|d( P_}e>u}U?6F2XZSGJKs5j6; RR$cG") @ -@PP@ ( NcNind.Q@4b# Y+ f!x۶2kg2P@~GXZȐRReHIZa{z A@Ӡ?8"izuL&ŋkȐ!_jԨN:XhF;Pڴv*.v 5kL=Y֭[[ڎo[ܑ ʠ8d޽O_@^-ը!5mj;Pt饶P1LrȤI_$8p@%%%S(UȜa[Bɲj$T!sQڵyfo^jR:u_B~x+;`Ű( YvtWhz75j(?^7txʈ@|!ukܸq+BGO??j*R ^پ]ڳGSvʏH=,Xz&b ?b!Zr5jtiiio;vXs[VV e֮5۵h?vt9v@egg+;; ,  Cw9sh˖-jwo/yyy {Ǎnݺ9_/IjNZ M6J{x̴(ÇKss=d]xR(6ml8Q61.]hԨQzUTT?_믿jܸN@Q@4~xhB/L-[jܸq;mGPK}Nq6m߷8())I<xQf[l&8 ըa; (ņ W CFra( PFL6 ( PX$'D֭) @)o [ P~ɑl'|( p\dO( p/oVq֯-l'9-D ( p륌 SB*9dX1# s( phTڰ_$QoGidkI(; %6m[9ʂx~D~oneGٸQjH^vӫQCJK3 e&U+)ʮU+Q6nZZd/8 # 8),6oRQ$ yTRb?wbS6"1 ƍR$"ha;Ied,DiԴT$eW?( mV?wo [aQ@@R^G@oӣ\ٯ# ?^F0ɯ# Ӱ@E܉Rf_fRB @уͥ$I/9dga+^_P@@݂7x~A_>B@8 S Hx@~iDx@mhMO:Q@ަMRF9ϯ-x122Q@^n=-Q@#  oNٶLxASBBB .~"I7$wuzqmmڴbST@rrvfd( .8tUWَ99R$"5kf;I~ց)X.FڷolGp\IJI*jU( .馛TNO>?ۑ|'(;`Ű똂堪Uꫯ֠AԠAXB_uyiҥ@Q@pA{V޽ߗ]vjuYo4}tH^l M^,iF_~Νh4j;jҖ-8=E oq$ 5k#GY >vXs[VV܊B~TT)XEE@¦MmVvv1XJ 6lؠRˇ$7Nݺus9>A:$@( P9xbeffZJ LrЎ;N/;C~YHh)XG1BիWW޽+WgQ͚5?v< rrTvmIvmN ( +5qD=ڻwtWT֭mB/h[ư/( 3fƌc; n4tW@h1( B) ~!Q@ҁ+E i~ol'D3@b؊e[BtQ@RNTf;IIU2&J99fD$b;I%$qHo--Zd>oV6 b$( Jo%uyԦԽ4b@(P@RNԥȐ.'غU6i4i ibi8ix}/@HRr$ΩRVig?m `` HD"sϙ| RIDPn-xc؊ע^{͙nP0A=[׿y p@NCd"'ݻ{}Z{ p'"suXF@l1?sۻ#5Tu$>֭:{I*[J) R^^8F|<7_i,)1v$`0Ba.;|X^K)@( B% p˞x´< Trrz5m'q^ZRݺW'f]ƙgNF*aق7x]~Ԡt}Q@ EZܾ|g=>@NCwQ$bΕnEZn8 ЈF;N .nm֢Q@ΝҡC+E Ai.Iฤ$׿^]Zv8) Ј:иFaCiAAU&qRA4P* ɑRRnaѰ"?TX(M`;  4rs͚ۛ)1?3;aٮ]҅J˗Nr&M+Əgd;%l;`p^xASQ#IJwҎS@( B#'Gv edHN %%fta03͋>v8)` F@gKKn; @(/kt$SRNҹND Ea:0&3=Sn nG3@b8 $&M,I( B!'GJL6}MJ x5in]I @(_ēB^rٙfÇM Rv`@8sGLE{!-Koi; HnV!Vt҄ $ P@B?fΔm( Pˣl*N+7 &M( oVRRb Pݺf.a M=xL #/V@Q@\+!!A:u VʺuR4j;E (լi2( .ٲe?FD"+5h ըa;=5jHsH#u =$Wtҥeǯ~+{***Ν;mB%;`ŰVtt饶sϙ"1₏>Hoƍh4ರBa0yK͚N@qXqqƌoY:t%F@ F@ʩ1|$(Lr㕛>v Qb\0[omN:vF@k.=zT~}qPڱC:|"!ehe4yHMNBq߯ h̘1?,rili0I p吵kgոqe˖o?|9ծ][u={ǎcnRVV㹁ȱgtn7Yc-*IXcn+((&8( ٺuJJJtw;<[jc 6n8u͍@Jի%îA)%@ʤgO)//؋evΝm'<7/^LKN:iʔ)lFuk?6mXLCl YV;aK_4.m"-X`; 8~O$ 2H@(( WH_oFzm",BwY$ BEBx,#.TJL4( .;w.]j;rY ֕.P2v!CXKwS@!%8`; <+>0K( -xOtV.ܜ>}$B 8DFx Ѩ4kt$i\̔zv!BXf-iS˗KKsNaäb)Y3)龗dJ# :UYSvwwB ,x]_?jUI ( 3@JY عSSs6Q ,RLnd; @ JyyddH[% IDATy]{wqcI ( iR lj;GJ3fH]f; @ qqqV( 6H5͛Eu Ȑ,-3Ŝu$#5l(Un;Ԩ!5hJq#N ( 3@N@PK/5;q2:Q@( (eIvI}f; \!<-XRsT4s$ pQ!}={l'PD prrYN]3RB;u|txN 8-x#I+ V3g'Kl'С)P3̖NC8l[6xC,v% azYddH6NaE7HND({-[Z4޽lL)5Uv% @߲{B7 o4dF`@P@.o^zv 8|XC) @l$U&5jd;5nl݌҅JN @( e&>g^, NO3UmLI@lhV ((0P@ʮeKNEJKc;BXv*'n:$-^,N? R~fG,  Y sJڵӀRq)rPIq"5lh;@֌fv9RZ * 08",D=L#Q1}l' QK4;`_V/ gKݺIN@@|w/# Ѳ9?ol'q@4jF@~Al[qފ7/Ϝcq%d;. ]L…MM Fm' ́MN6IիK N? 9" sѨYO㶓1FRq9 H_l@Q@b 6LmڴQ5T~}{8qh@lXѪUNCG|'}񅙊@qPnn߯oQODqw߭4kNwx r-c9K4/p=mΓԡրAk. ͞m; hTZO[͚fd,Io}wԪ$ѪTP`[!2B[lGo Y߾҂ ߢğo [nRzP&aTT$QW$:KzI+1QbiBI;X$p!5fس϶$ܞ~ڼ#A[l 9s6o;I1 ( ]=[l < _*,rs) NhZɑl')"k߾ʈrsb Z6mn$ep9 _?IeDK֙D4{ڬYfAf$2u̺m' -$yʈ]ڵRVeWRyn׮ Ov a@)K1Id$%EJOG[ʜhɡN֭ڶ"ڶIm+Uj@)( |ȜSsڵ3qq$$Os> w6o60✶m#Gs [~҂Ҟ= ߉M 8'2 ҷ>7vD;kךYW˖9NX֭6mXTn[:-)ɔOx[߾P* a,wxv' &M< mb; k yt ҷߚ!xWffl'1R\leymJ{p+Y6)JE+[a) ΋mŻu$Gٻlگ$ ؔ `9/{jּy$ʾ}m'T['%&Z4ϵzϚ_ɶ_r=9 _YnjCSrr5kX>G+.OҢHߡ-, Ӯy=c$"u,լi; +ﶝGP@Ɩ-9F@ӶtǶI3gN#( |cĞsTH߾ҪUdtGWZ$I ZZ2}*eNvNXӧ A ev.d 畔ЌqYQ@h"=Z:tP͚5#Fhڵe{ڷ7`VttKI4&:Gէ~aÆsדO>nݺiС툀/0bO_Zjܥ_|  CIG-1b:u?c1VIUH-[N^-[JZ\rKڸ@tҥ|,!Im۶YgUVij];)1vJJ2NXM®O>EQm߾] 4 v+;a!>[JO7#!Bⲉ'*//O#F kg x"i l'`EVwܡs=W7p8/ovbľ͛l'A dp%۶mӥ^u_W$ 5kgF@]5*KӧNe={hڻw>c5>ͮ.cǎUjj1eee)++ɘ'}}rԵ,Z7ӰF(UvvRࠀ8M('t. fdN lI3oNB)-\x/ؼY#݌ IJ2xgI={N\RT= l1 ) ճYuk)8i9ˁWQ@x@s Ů +W#G M}Լ9.5kVJ4IJM =ֱ#J]+ .Uj%{( **>={kYTtԍ&HLhT?_ڽvD` xbqh%jn _@Q@XgLIPYZt;^ ח.seϤNm'Aeը!uH nIZDKITU,@SHˀRZ OQ@XwW w$d:#GlPN,Zd6GϞ~$ovO@9Q@XgRgNx9m~W1-(N=g; rO; M3|{6|vwKge .qڴ^ZMŶ F}TDl'PV|o9O i4c^w5Q@t=0`իKcRJԣ$gjR{Qjp< vءzHWV.]$IIҼyRR* . 矗^UPp< ӵm6mܸQ=8gK@yi6[%kbUREiii(;t[Tڳ2~IҲevc'vRժ9Ns:wz4f |ԫT$/VfJ bꫥ^iP@D#RRb; B!1ls0!qZ\ڽ\` 4Ǝ5|$N5 4vXs[VV,%ֻzNm|kg]xԹ3%leggs[AA4AqƩ[nc7,>^v8zusΕFHw%ڵRvJ{x̴(5Ҝ9R~-Io=#'I0'|R˓$;͕$y睪]xϗu%4[ (=绔 V_Hy5h`;P@M999H$)S7T$OS Bet)-Mba|t:LaCs) p͘1㏛ÆN8mܸv3{O (^~_`{IW4ȼ؎@}~zHSGrf  ǽԸԥ$s5Sj*v*5j4,âQiT o,ڏ%$QS (hT>驧l' X!Z%]}$mP髯kpU$")GW_5.5KH^}vH|#=$@Q@8&&ORRvVy-Ll^22[n}Tڽv ( tf4|$åիel'A(Rqm; jyUn]m'W\|yM0 V4j$wҿeWW]%%'Nr;tH6-sTa,.ysW- G,^,_/a; *MS͍]!['-YNZ5Ǥ={ 'KK]d; -?_zip7.ȼ6&O]esUGI5kN@ܕ9CJIIӠƎRR̂]$'^yżVE"q7{cΆϼxqZ!7h^#s8:uzr_HI#G:P{K; \( */Ozs3|_HļF~,9@\jl'A')!mڸ_o^+/< ngFJMR9{\{T%ϲpiP8 nf2 ovTHÆyҦMX5{4j4q$@Q@OKg-s$=ΝY2DZ;;)CKӦIs]$b^3SJ6N{IN̜RG5[p$n0G*M`NIai͛_~+s6Pի/ mb; B ?|̘a9 Lcfne҃YIDATNqoj4%4kB6m Jٶl:v)!\OsyjZkgYU \.$ JarcNڻSjccvm'$խkF [  k驧ѣ9x aäveNtuk_2-@0Q@To~cF?vR4jN;W2Ev3 Np @,\(=?7q4[L=ԧ4TyM=yJJT.][npC損뮳Ln՜>zy^xAZH?DipJcJȽNRf浵h9_^3kT@m~\{N2vr;d'"W^-22AA_}4HL^CDrw. <\v ?088tظ&L7!%"bџ(ʄ1ntDv :8qBtؼYv*U͚TT=>,@ZUCv"2swwݭFFŋXr׿D1BԪ9|2$; TEDfnqdz˭1.>O._.d޺%;Cdebh7F1 D`` ;8x9Sv"EG}5;[|#;Q3.\&Nիe'#R +2 VEN ٱݬ7OQ[+x:rDv6ehjb^NBA^bd~^|X.]H5,@h֬YK/a˖-q ш`4nV[͏JxMGqf49Yv6' -[>pjDD̢),@Da޽Xn֯_ٳgŒ%KdǣV"55Uym@1С@a bkzJjj*p7p!<2pp0N'OCB2hUvR?zxyy5j7ڱ{ĤgOQrsE&yWƎ:u;sFJ/+~(*btM(S`/d:EkE(HԅSOh^O>X|xo N-,@޽{ppjcǎD(8yS\e7-7o7nEӿ%% Gqg׭{9x8xL_WWwoc,Y">Ĉ6}c扯 PПԩ0yXꀂ1޽geZҥ]][:w:t,R_m8ҳgn"<=ń]<+MkNexspOKQ{ͯC:6s-}ls.G4~ EiNQ[+Ij6[[,nkB.TXVK0X$7, NUۚ4q?w\w''6ڶ^|֢Wo E@/{qco;%~탪)扪):,Z}ARRrssq ;_O=Ο?/)رcطo6o EQhdGgTTT`͚5D7zɩZݺuk޽{wڢC2bQ СuU(o>L0=z0=}ŧ~jm  зo_8;;7h :uJF,R((//G׮]eG!+1Ŝ9sͮȀ+ѯ_?sΘ?> x^yxzz"&&}w^$&&"..\PTZZׯcСօ@BJըVVVv$R2^ZvD\zuuu4ifϞȑ#غu+giZ8qǏGpp}ٲeXjd^M/} M`"ٽ{Шcǎ~? ,-;YAee%VX+V]v۷oݻ7o6o 4i߿۷cժUݻR1n8Ν;tYX`dM㳇ñd/ԘSt5K.HKK=ԲeеkWʎBVfzj۷ɓ,@ڑ… jDY__xDEEMrJ;"nVK{75j_n޼q֭[8x w.;YAQQv܉X˸|2jjjp}\r7nܐZӳAfVs:""w=휩xAz  … nОk׮~!1rH Z~i磨A{jj*lmm1p@IH-SLAzzz(**´i$&k8z+cѢE@JJ 򐙙^v#L>#FѣGKrvpuu… tȚ5k;v,6l>T$IR, )sqAnݺqrsWe˖I$IoM<s3d\r%~픗O$I k@Rwy+_>~Wpw|rtbBI$)x"9rGwܹs, VbժUd$I;#8#Ž, )rGR]]a;w>kVZE>}Xre %I({,&Lk ;$I H sM7qM7E$IJ "B6n~[-oiY@eݲnY~K{"I$)0I$IH$I D$IR`, $Ic$I $IX@$I$"I$)0I$IH$I D$IR`, $Ic$I $IX@$I$"I$)0I$IH$I D$IR`, $Ic$I $IX@$I$"I$)0I$IH$I D$IR`, $Ic$I $IX@$I$"I$)0I$IH$I D$IR`, $Ic$I $IX@$I$"I$)0I$IH$I D$IR`, $Ic$I $IX@$I$&?$5Z***&#?h "H$ųHƚ5kjjn**f.#j y $)k3|#Y> 55c /$ HHUU5wG6$"Ix_]YnqIR, )/䟪IRϯ8Zp\&%%%;$^O"׍HRsI$.D)PSSI'-Z޽{pBzRBIB xB.kmuױuV=Pӻ6(e!|{śp䖔v<_^ Xaa!g}6ӧO'H%I⣏68la Y!4c TfpspAd G֭[ٰa۷ѣGӡC9r$#G *$e[a}C<N`.О] .;ՏG/M.\ih6ԒĔ)S2e}!0a/IRs/`<:+6UBY@|2z+TT6/oҾsz ~%KOpiHZ{oncAN4]2yx~ͩ+I-W@RmRZZJΝ;};$e-[KtQAr!z !yoK), )xdzvZ:ẅ#~wݰIRz!#oFGХ n #ӎ;FJJ>s4n  :wkkk)--f,Зtbە]Yz7Z,‘$eW^E,Mmx~td)xķ9$e $)L;mD8qMSSo`&/m8ީ~j"Iw$eރGk7f̸я!11ju_{Mmm-Q\ϡ_L\f9ُFw=%}*vvCewu$)$"I8;3['N+++(,B6769p `WL_<.IH2'Bz ߧNg5t:53ʯӜ|NqnŻk"Ir$)DETWq"烼|¡ 8֭ʲeHחLIRFD"54qKl?8q\ʯ4l>N+lF0wݱH2cAa!%w^?tmNuJv"ILpِo 3/8<]IY@$I Vs <d+m摤Lc$eN@lSA&'UǺە$톻`I2cСٴ "9JK#I+ V[[Kyu[a^ o\ ଳGN"Ii+ !ײ)'=z67<ee;FҖW@$Iik㍳7 YӉSﷆn'gUI $)m%|D)1i}{8t $D:h(3HÓ KÇܹa'e$c7u|Ph O;$- $)m< Dc$3^v7h.a'Y@$IiL?= ^$, tTWfeq$a$ŋaXѨqH"vI D~^|  ;I4֬eN"IH̙Ca'i>'>Y@$I%ٳ+m%u Z8 $),Ze_饗>$ $)̜ %w6?|FI$)4IRzyzVa'i6_GU (/ڰIR, ;v,t=(mKȖ5k(--cҤ,x)ГcWfҤᔖYB$8|r-k׎HRzZ6lȪcƌӟЏTTTPe o~O>}H8J+zTUU}|r:1з$̚5Gy &H$"IAIIV?rKRaI:_GW", a'iVuWWVr7#?o'J7׿`ʬ+ hHցb !#?h "H%)u, )'pM7qM7ѱcǰHRzŒTVV0{v55cIez%+VxPOuugMHJނB7x#:uk ;$9s߅ΝNҬ"TFNQPvƪcXWAXI;ly뮻0a|o޼[{qAq!|GC;<6rHFܒ,\(0qⸯز-mXǂ&_їJ'iWL”)Svx?)MI'lJ⋜r)ѣG?-ZD޽Yp!h JIڭMࠃ`ꪰba< ][OJx"ݻwGaD"7O CL(IidBdz HS;⨻cI^ر#g}?~<Æ :$X ڶN ;I`֟ԝo|𭝎#- %$ BIY{Pʽ@}ã@+$T?}9sf$)4 5*$T\Lݱo,', p^ݢ40|eU;$[$Ij@د7?/ƍa'X@$IŨ;Xnjxݺ xQ[[v?ׂHR6,IR͞?>ĤIÁJS멮b2b,^Q\ ?p`i$)^$g&r,?,ԏTTT/򒷞<I>IRx, ?QOxB_$;$"I O,Ɔ<^cWsON"IH`Uɨ'?.Hrr KRa$ayx<Ѣ S- Z $) }Ā), 7PYYZ4"I GƒO?Xl*FMh(]h(FM-x׿?,[}vIJ9HA.&Nv` nIJ1HS[[Kyu&x1|w;.dHRY@$IXf eL4wۖ } KRHU~~3 ǵG>89}HRHU4ZVr4REy ǵq"b$5 b4b@eeE2NIIrma'fa$5H$B,6QsVX׆NQ()͛aٲHRp$E"&N/6E,{≰#e= 77GH~ $)5IsI]k]")kX@$I;_m%}BtIY"IJf +)^K g$p1קdII$iY@$IsIЪ %e $…~jkk)/!t;<^+Q[[v4I/IR[֯ >Zf eL4'Y foIMYB$e4 $5.@+j̘qrX@ '.kn2|?, `t :$#UUU}wxl>%QOOKRfвe8(,,]vtؑMRk|x<+)b#$ed3j(It~]h$iY@R33ᱫ޽{swZ@$ee˒Ϣ"\,^N0Ijނ\>hZjvIJ 7z ;Iƪz 7[oE=v|y& IDATtixȑ#9rdP%i̟ZI'${5йsi6eLcyHi$W>rs5azd$Ij $G6a'^-Xgn)5 EѻweoJگ=m6>:vHqqq$)wG{,t:I+ )u1p@᠃o߾z 4(xԼ/Nn+)D"YH$)X@RcHR0,BV>ppaIR?z|rW\")Y@$Ic|Ƴ& [C(/ɍO$)k*I3X)f[8~OgP]]ebSD"aǔoI[0+ )5f8jjnQE>, 55c 7$ $i-X]$UUU}O 9]XpoqIJoI?z\R< <TBB܆㒔I!I xUq(oӅ(U GKRzH$EE/?OvW@5f$Yz SE,&@eeE%i, }V[[>kMW;""TFNQP>4 Cr ^I9 }8֚1Nc3zgRX$aqO6n࿵ I>IΤKTxU.ΤP۶pPUJRHIUU5tP>c>;O@w&E`ѯHRHI\@4q-% $iTU%gP(t=@%b$a2 HoU|J(n,)X@$I{oѢ쉒* hUp$QD^, 7~rG'頲_|Ѽh=k"xw$*1"cyN:s>ȒҖ?9$I{ ;ӱ{w8(?Gv[$I{gx]q, x‚ $)MY@$I{g| =6$YI ] ˗Dv"I;srNmXҘD 'kHҔDy>΢Q7/KIҞkͺ W~x1lvIjDχ|']驴d 4d$9ݡbHR, ݪҋͦW^xQ[[v4UnXs熝Dd$}5kPZZƢN Q?jz& JK- ҖDƌGM-m䳐$|f,aG>H4c$}j/XLO6SѾ ǕVK~*4d$}x<ȡ1Jw:p\i#c, ҒD]iԓ_J.F~%)-Y@$I(-4Q@JWZ ֭a'X@$Iߨ:J:>G7l#~=xW_}5Ŵoߞc92~I-Y6Y@2X4Zc.(%y %)Xȣ>_sf͚E^XlY$͙['g(#UVVPXx=1:ѕ9Oz Fa TVVQR 6)_g.++{`!h@ئMI"T]q=<ys:t"--x%BMܶХKx7CH$I{!s ;S$;'?#HZ8o X"࣏>SNaG][ {"';/DY@rJŽ"ISZ, xI$p\uUߟ/88k}tÀ~}rw3I $ WfȐ!r!L6#IҮ90P`찓Hj\/33}N8nFnFVXO>=TZ yyɒy aBY@Rhɒ%0c f̘ñ S_<9mbi믿Nqqq.]0u ׾}rY󟇝FR eI3gAk'PNNNJʇ6`Lv I-k@$I_5 Z4\vwSQQ֭[ÎONX@$I|CBAAq&3~xbŊd y Bb.Hp}ѳGZ͝Kb#5/gΜ9|gٓɓ')3uɫ] $`k׮?)_|1 ̡89?aرvŋs]6XgH DZŋӳgOx ~~-Z;7:{ #55c #RixUpY@$It|u^_С}c6ovtqй@$"I-st|/ԓ_hP__i϶mŽ~rr\")IBxqƱiӦ?M]O<=zyg4t &Lo߾ >+W'X;BI)g4eN^^ӦMu^uDm8u<2blv`  =a', W_}5/fva~h7>P{NLGy r5ׄ'XCm-,YvIY"Ii;n#UVV04'4NM ;۷/vsK. ;Npm KRJ9P+µ^W_Myyyg$7N[׳}64&$hJ'`oK.N8!(iN>9Y@*,R"Ii_n7}yr .\rYEFo 6AAAi$e!o45fyZj|oP\ e rI$e) $kd9}ݯGDRX@$?N ;YNzDRX@$x880$Jwëš5a', RY=6ovG3ロI&٭Y2l0,_834i8eI"I!Zt)W^y%'x"ڵ7,N4'YOy:*Ñ[yy9\r W^yeMJ3f55,?h>x$yЏTTTQRHRH֭[yGn_OxG8Y|ՏH{[ok׮wy[.8ͦ,m8.I"I!H$\ve\~}\xش?_wG3+((ࡇbʕ\~$#5x<amy8Ƕ;p\DBpw3e.;}~ƓŦ5,>WԬvʝwɃ>ȴiŽ,dzs:Q㒴, %Kp5ps{mu 'O? }@ǎԴ#GaÆYDE<$a(3k8.I"Iw?xƏͣ YrrhӦM1Eee1>Pf3sxQXxaG, ￟3fp{m x3J`:8Zj"TFNQPD>fpS\~߉ŦDŽ()@ZvӖMiAaP fI 638C=\ްcIJ%Kp5pe1rpB<_3+vTUU9rA^{s΁jX<$2$jkkz-z@HYkݺu?> ӧBÉzO% 4A~c  BGy$Ws,\#IJ+UV` P] k|uϯ :YWPP?vӶ-~z6 ; jݺ5;w셇ȕW^<@׮] 1}:k֓œJs իN")CY@$ߟCbt8, b@܆z Fa TVVQ?Ny≰HPIwpD"b5t:5Xl*H$T; Apa'\"Ibth: H$ĉBtpEwvI+ -ON ;G}v}DR H=z4:t᱑#G7S@R_0͝;G7?яŽgڶOvM3L”)Svx?)M &ЫWcHڅ?O?ݻ+&%| v\E8ꨣŽg.'Y| ;{wU3ð(A"dLf MM&MѬn]Qoݲ[fVjK45K4DPp+*cAfYΜ33|ޯ׼sf̙<x :uPD,P\\cСd. ΐLKի!CX,ӭ˕\ [@lѢE(((@NN`ƍ?III`_m"Ca~6|$'k2h4:t6U?dg?/y<${ׯǣ>I&?T:S,U:""r*E8{,@2H,JӧѴiV48p]'|1cO>AbbCLpde Y:ÆǎG**KyWH(O6|aT,Z5N>tD$tL0/C6m~yѵR5ʚ7SZm㽯j<&n`طoƏ6mڠsJd^@L@bL@"//Fǎ{9l?&ֶu?49֑^/e_b; IDAT>hHN~w8pp3zb"pФ MDDfbذa(--ڵk}yXKahx ؆莩e퍝;wbܸqJb!C:u ݰ, J(|WU0u[QՖtoX[O]h4.A0o+%" 0!"2C`޼yxG.]"X[;[G2d~lF"8:~ncBD$d W( OTm-~=DZ? >~ ɭ!Я_?1:] DXoDGK & DD֭[0udn@@fEJ|&JŒ3waƌ0j[_34"r1L@`Ȑ!X~ҡnU:Y߾}pBhZ,oD 6.34"r1L@۵kƎ1c 66Vp[ƌQ:RK/1c^ݻeۯaBhɓի )L@V;z(z)t -Je;IhH!* -Bn0p@dd3 a !$%&-K\DzQ>}iӦذaɼ-[CW^Q:R6l؀&MO>Ȗ@>j,^ \p^" зo_j|W!ݜ9@+ 9zNj/OOOYij&N4d 0e#""͛7#$$Dp.5عHV?6l؀F)Ju!!I xd9"R"̙[V:̙< SJGBd_ΟpL"]V W:;wռnD.⡇} #rGDx&#"rvM r%SG?t$DDBD@HN"==eeht%Zme3>mS_}.L"CC+O(&9 & DDz ؽ;Х,Xԯ-CN>sbܸqݏ|8Nq_ڵsh,Dڕ+Wi+e]ab+f#9Yk~/˖/ԭ`@BBAZt 'B8$"r1b1/Zk53}z~0jZ?1bOKs//6H[Yjbcc1d,[LtfbmZz#y104<<L[:s+ӔL`D2=._o:t޼yxqe$fAAAHM]wöhSwh)7|wr]7Ʈ]ЧO 4Z֮dq11]k; ZLƻM*U7lJEҕnvE\:Bn}?>FCQQƎO?:|MAAAH8|0{61C鐈/oMGbi{AAA50 ϛ}Z욥B*ނͦt-;UEպܭv{n'WƸvrLNTj#}S<6oEEEHKKC\\rJ6 >pʳ>4^zmX׬F OODݶjru1W=i&WԅU -C!MUEEMnrڵď?^°aðh"*^~8|س T:"ڵk-[H]c]o[o!e;mU\W]ۏr]ٹYKMݱʚ CR!J+Ox%]~L@mI2U͝`"rU>>xa!r.l:fd/+ODDVڷ ʥw Zk\uk(ެM{B&ƁqCq S*aWOQ:Dr1/^=ʏ+}@ !Lu!|P! ȁz̔~|c(_}Um;X^^^y9|(','<_)"" "")')>8Ҳ$@)..z^0bs%DA1y&rk F#^}Uq-i7>[nWV#"UqC'""Y_.H>zoRkX/kcDy@;v)ŗ_~i^m$OO!6nth|Dr+..oZvv3g~` J]'cUwKHْ"U`{}Hu^dL@ĉ8VJ-l)Dh(hqQlHoҎ=*(rrrٰ^/+~`| 6T- RmG[b5R,=~L@hW–B,S9*,,obѢEBٴ-%gNn ѯBYE@+|Mq 7 1iᇶtsBRkR!]2c{}H}^ 8KhBĕ,S%SYYXd^^^bԩիvmSc-!G͛3r劘2ehҤv47NJ+٦L322$g|xAԫ⺃$ Oh[܏iW& cD,9mJyEl)<ßpgMm)((AAA"..N>}Z<-:޼)DBԩ#֭I~SN'D|BHn a\rQVL/ z& cD,9mR ʥӳ$X8w$˒%g%FBt.DݺBln%ʄ=CkIB-Dž&Im:)w!9 8Kh[*_J_]g+sʻqI,}\ϒw{ gQ풝-^/'QS %oƶs-]L's{Obb?& NĒږaX[3]Л+_^q6b><_e̥:%K̋W9佒'*z[Æ'&$qSv#r5z^޽[… m`=! )I\Rmm]}Kyot$~L@=z撐b,ܔ̿fpI{CV'F6ѢՕ={x1U8+ym/3!4S^%b.E9hKR$el!AzIH>,1q",E:uDTTM>[ I Uzl4yG/V{MlxѼ_*9RqO>i۶o -!UH~;v5W޼)o /DzB̞-ŋwݦ2ϙ Xo 8ÅHNNK,111Sl3HrakaȤiii8txwD~ģ>jSl޷D1`2Q&ՆF8cOE +'CbuX%Pf5F˒-Z)fb?& &T*Xpa岢"&bbbY8[)F>aIQrذa6m޽[ EϞ=V5 "MΗPV&B!u 6S >1J6tbܹgϞ[u111Yʲ9D(kD38wr{x!9ӕJ~$?L@AN*<==׫-3gPT";;kܱgKLqG)",Zصk}06Ï  !Ǝ"$D@-El*t㙨yصk?h޼v)o" <$uo/ԩ"igNuUr6r[X[*yƞL@Az%"##k,ߺuPTbӦM5y@[Cvƫ78cS-I_wW_5qM7o\s$ӟuCBv&QHK^vgI<'Ĕ`qcQ+ nKl#b .*y's$.ްDYC"88e999f_z ؽ;kT5Zm2vEVlQ*55d-3PVF.]"&ؾM_޺VYYYEJ|F@YI_2u,Xcv;\t:< lۦ^oj~uAƍ-f3 h#JC.Ֆr|F5C e_<uP_jxr˖@!!IO' cgILHbɓ:yx%='nDȹrKf͠WGr#<ƍC8Ԭ8 ХK22P>>O<ƍ#44aaaw<ľ3L0$!LJ +hOY\ dgʏ;EJhߋFExf@N@Ӧ&߃-I%9K.(!..rQ/O'zhWN q|[nD'.^=@4lbK/ព-OOqdc}4@!8z;K?–$& RNX^TTTޔc+V cm [kVs*^lhj\ SN?FAhB۪<0pϴE0/8q/nѡC@ZZD(S\@p}V|%;_Mzm6T;wzѼysիn8>5 +8%8B=pNh[V><|燢DhPY|LBGoG@N@~ORk͛M@߇Uw.k}K@ J){O7~/\QqP=DwDɓb- |u +^(4CE&8uKx'Lh*PhߡxP ڿ`}JZ Z TPPPT:u.\P_UU*T*#""ktaX^&Mѽq M6`hC?oX?~:z G~q.%x/ZjdfݝJTdz=zm۶woѿjaz}X|0">~"-Qh6Ce0_6 H-Y Kn?\_ kz"n^ Uq1T%%P*je'Ut"QU8;` t;v_<-- о}{}eR̝ Μ `: K֭)5^{M\rll葈SyUzl_9 IDATWx˗1gG8|$KCddK$%=R^Y=ClI~0+2WQ><==]iFXu:5< 2 4^yrL]ob$:uh[?s-}UM2_틊PT ZJӝuW|_3_ 0yYnnI@jKj`<0]/f{$A >~Ü|XR4w t˴qU YPS@@woz)TYY0ŋk&V 5]Upp{v PXXXm٣q,Y]y7tW2^kT`eDGG}MQJ!SHɡUU5˖UfUzCӉwBieqB&WO~0b@EEEbԩ"88X(eϷwk='=VU]*J}e]Jc',0>qsNhe \.{XN-kL@{@ZZfsئm۶9~93wKU{*Wz=7$Lf0Unȱ9Qj.-Y H-gfna8Хެ,uM~0]'y"r^ r\-Y el֎[f?UjV[T^HY "b")'eR;?ׯg݇Y5LXWIm!e5.̲v^w0>=YȠD (k 8811띮⊙+jwJ0r+=hcyjyB˕O""2]>ֶl]Zt8.- d@]inv.U2L` ^11Wrhː>!7+I -OEԩ4& d1|ػ+IEKwbFD ."۱ YPXY{3ki  Ō,'eȲv*!ΐ$&cǎJSC~~>M_9[r eK5W.Xd19&#rw燈ò6L@*,ld W:"""""I1qBO#::I& NI +f#9Yt0d|$$LEddj5ٲEDDDoBwjQHOK yyyhaQt!b SSC Ӧ/O>l""""bhtJA6HOπaFc>L@ZtP:Jeb-[= NI B]t0dC˕$-[DDDT{ h1 y 3\X˖-"""֮};vT: Vݻc5{A0lej5& D5HN"=-y@ѡKhl"""ڋ !%ea9BDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDaBDDDDDa .\ѣGCVcΝJEDDDD(& rqhZm۶JpTDDDDDb ?0\ǏcJCNjJ@2]]}Y {Q: rrSڵ k)RTBtJVCRAQT*t:ɏ Ɇl8bL6 !!![.v튭[*9}/"22~~~h֬bccth$ٳgCVM6JBrA 8 4/ڴi_ߏz !!!Ń>Yf֭[JFvqx PXb;v }􁿿?4h{.]9b.XN ..֭ɓ %%#(IhȐ!HMMСCѶm[bѢE(,,/HC$FVVѢE 9rDHb[lЩS''OsU:$7n\gϞǗ_~8]:t󫶼sÇ+H/aÆJB0qD3֭[sΡUVGz JG{ѨQ#$&&_Źsf|GHJJLP=?xkܹ3:@T*,77rrrdrJTN\I磏>Ÿ~IPȁ233QVVAaј7ooߎXj!BBBg:t\ka̙ FFru+WDan݂w>>>}?~&L@LL Ft8/_?@ 7o ,^3gDXXQT.^},Y `ӦM={65j &(!9REnu8& 1QX:u6U'tڵkyOzаaCL8QP*븸jxb/L@ȬYpy8q!!! ^Ǵi@$Gg`ݬ** 5r/׮]C߾}?>C"Ē%K0qDdgg̙38s PRRgիJI(5jTmyͬ?:8O07o=nUE}\4hЀf0QXp \~4@ ɓ'i&nZAΟ?^$lٲ򑞞'NE5kaD*nFή"SPP1㔖B]eeerD2}X]0Qؐ!CW.+..FJJ v_Hj:HKKW_}(C"jӦ 6l؀aDFFYf믑t$aÆ.]Zm'|OOO3䓠I$I #TUUUtlk׎={2}H$I ic쩧 &qF*++N%I$%K-;w.Gy$}۷Yf4oޜlٲ%x$IR°Բwyr ƠA1cW_}5?0999AǓ$Ik^jYZZ>cƌ7ͷnj{V\I۶mwzΚ5k3gmڴQF,Ii&VZ9裃mm/FQOAAneΜ9\~1(Ix'˂,/㏧֭[tc`ݺu=OswСC*nr-cN=o^p8s8:t@.]bTqE~͓_=9uOnӡq~-1b>N?R~}@*I$)8R:,j?Q^^N޽Yp!ӧO;c :$I,/1I&1sLڴiÃ>7t4I$)aX^b 553~(+_=9uk^8>9uON~ݥCgy$I,/$IE$IRBH$IJI$I "I$)!X^$I$%ˋ$I`y$I,/$IE$IRBH$IJI$I "I$)!X^$I$%ˋ$I`y$I,/$IBj$I2rs(**ddK8:$i,/QZZJ#))B@%EgLw'-HRP,IJcN..݉(NIrsvW_SO‘GB -IE4n{ۭ>g@8 ]VGu ӧ($i;ˋ$)i]DB6p mҥkё1c`Ӧ~\"IJ@{.0m#ᬳU֢L }j9$ɑIRH r_mL٩s;}t<}9 /֭е+
IJfHF^^.ٔL % YjZE9o$2ywW]1OM#/D2z ӳhn(Y9!\{-sC>]'sPUOJ#/4iw6m 8dƍ#7玝ωI7 /f͂CcHRұHûL A^`֍BvL*뿢Yn;uLN'&Iu$Ii„Ԯ?B}` d|CƻhN3\JR[9bʔ>Ҿw.&J8OY#/p в% Shv(kv"uٗ [8aҝ>~w.$Hџpu^q|sX,˗?GM ݰ|N['}jDw.+>FE\**7ҺrIKFii}TR ӡzꀞe=r͋$)<\tGiv[qW1I:tIRa!*FPax(f CywCgy$99iK q8 r/"ݹGqW1I:tIRa7JA_=mkO^> dtn^J %IuΎAc0L=Dzh J1gdo$ˋ$[J 3껱ǝrrh8u*w8A9%Iui[),f$OW@0Ȁm]s Z ,/l…_QQQ$N>m֔{g1z "<h}4ח紱O~gӵHR~<֚W-iZ\}55lt"IJ(ի?!Iɣ W(.]y%y'<pCi$)w󺭪HRrXJJ`ذca`I!HNN͛7QF׏W_}5HTд)t]s 洱ZְaC..B>h/_ЫW/^y:묠#JR4s&\x!4lt]xatǠsHRUUUU"ٔpgлwoktڕ^zѢE5QF*$%?N)S`Ƞ٘10gNtj[(tI5hʔ)L2ek_~%t%dcƌlڴ.?疤CCpPV͛fϞ>:pATf8m, 'x"[neƍ4m48ͣzVuoҶgOkq8\h}"I{FY\$0ңHJJ-YC;ێ沲ܟ#;N#I jYYYn^u}Y @"I;ƎX]\)C;T蚉oB쳠HRBp䥖eggӸqc2339c(..GiӦAǓVTTLt;+)C(*}04gφ(4ye_|1k֬n/ \r ˖-}AǓV^^#. x2 Hǎ>9':uL_Բnn)T'VUl/0Kc6UqnP7:$5G^$I +##(a8 ǹCaf;7$,/KZڝ@zle(2a@qqڵ:&I"IJXpHd*Gಓzs4kyE=HdjnCa, :$5׼HZ8fҤp0#+  'BQttI[ ]=.( @f&j1Iڏ/I.~Vz`ˋ$EχwCar() :$-ˋ$)͟]+ҤII݀РAt$i,/VQ @~A'9s 䰥VUl/0oсG%gQ\ܭ~%EgLHJ*N$%SB?6ed;\ 1/;ߍ̤ZI"IJ<_~ ˖Չ)cyy DJr](m,HJ>IRY*+b}p8L$2ѣgEvCǂ<+z$%׼HϼypIpA'1pI&ta3o_gTVȋ$)̟2Vֻ{iҟrz$%ˋ$)|9f2/?SXLgZii 0$Ş$IeAs 6G 4"RR&~5is^&YRHС|Ij_22}b F2-48I]E *+XI,/PR|/ :$"IJ Dw7$ӽ;4n}$gy$%ŋcG8ꨠNÆл7̝tI E8,=N{C~>ltI E֮߆s :I6A$tI E^y%6KN;uLRҳHpqЦMIb/%;")Y^$IazP($-uN"IHߖ-_ܓqvE\($ˋ$)j$syi}x堓HR`,/dI3 :IpB!")Y^$IoI$X}?_~tI Eߪ$'X8$ˋ$)\ kX^N9N8. :$"IoKP Ǟco?seeeAP(:uu/Tj$IڗM~&!"DNC})~=ydi$)y$ŵ/g?ςD D|udy B߾^\") Y^$I񫬌֯c (**im 1II"I_z)׋]x}݋%%!K&L@JJ :u :$ŷ%K4>{{y@%1W_:$Ŕ%>c>4iB($)-Y‡; ( HeЧTT%A'OSz~#IkfXk"-N TV߬"#//7AiZv݋cyE3RUUȋ$˲eu+$3HOϢ]g1z&yP(:byd<%F***馛kرcq$)-YMgNMeҤA'/}7ƍФIi$)&y~?{'(ɹ3x!9eeeAG?}@y;IR2ڵk?~<ǏUVAǑTZZJff6'g9sc9/nɓmUeⴱ뮻8裹馛yr -ZڨQ5jTMƓ0vDJJӞ8tdyNۑ^5eLӵ/24u奖;?͛ٺu+|Gy$-[> ]te\I LQQ19, ^}EE-n |FR=^k׮%;6V>*++9SWTTʕ+9]#I@yy= 9,udͪTNm  :$ń#/SN̜9sm뮻ذa/IKK 0$Ň ѝoth*:uN#IRZjE]xC:$ťt iA{:6B22RR/.ڗ$6P(!\׻TƑdէ¦MA'ZK@,XtI+pHd*K cwʭׯ$###Ƨ}ah74T,/ֺ0g'1~:uTtER1IR t**%zEN"I"I+W—_Z^V풷n :$*ˋ$)~DO?젓$>}`fX4$T,/QP=y$3τf͜:&γHGASEj*=R0ˋ$)>loay9T{Ò%P^tI5IR|X,ۘ-GI$X^$I nC$2rrc~6RxwPVVt4IR)I$!ңHJJpm%33Hd*p8蘒Ty$i؉ť;eЋ7yrs'I"I [^BQQ1mkMKKRby$ [}?N*/ Л%nHWPiiZTtm3(",/IuEs;վP^ϼR]BFF:PCoqI{,/*--%33ɓS\$9"I]w$«te wɪ }/Gϑ:"I]wNl?ߥ]jB'A'ey$ԎdjNKa}=!HRby$Ԏdu#@@qNh<3Eˋ$)v%kp\>K=c=zTTY3zvERncv>EӃTsiԀtr-#/`òeЭ[I퇀ׂs(.=TR³H7t:e!krDwPI "I Fa!ԫ]NZD],/`Dwj8$uʎ./cJJlIR0 ]R v<t!}v}PI"Iu{?VeC@KiM18w=TRbHbo[G^j܎B% K_!ˋ$) eK8Ԡ9;ŊhJn񘇀JJxR)IBȀV=Z恋zER$).q1 DE[%%v]bsa?NE[ѷH&}»Dk^$IUPAVA'I}~,~REEŔ#5tr]/)!X^$IᔱS~i0&=B@%Eg1IRlFt:N@׀L 77/pt,/?ܑ-p"n7cIE;ppA'I:GЗ{Byy摤Cay$Na!t $lhʿ贗RIjjE#IAHb.Hg!Ht,/SC׻$//ZE=VU_"#//7tt`*YTAۦ IDATѷ"sӸyqdI"IB888Ġ$۷3࿻vHAsژ$)6w X՞sυ N!IR˖/_Υ^JZZM4UVу'|2h;t]A߾jU$%ղ? 60zh?xOW\U7n\%-_7%zeh&4tP,/lРA 4hk7p]vGHJ=E:(8Ա :$ %%O<&)Y@NдiIѩc B%F֬YCII <s!7=%% /}{D%Fn69N=TƎ˯~+cIR+x-Ǔ}^=;7$tP,/1r뭷2w\{1;|8/+Vଳc|A疔>CN>9rn򫀭n=?~:wϏsw `РA\xtڕ'χ/x(?6oi&K!*+b)iB?<2Gy>?Yz5>(y{yyy_>&Kխ4k1I ߜkYYYn׶mc=FVرc$vЎ:^wU߿;MFYY-bРAu]<=iԯkyP6Vˮ:kzg}ƓO>ʕ+4ig,)l޼ɓ'ӿڶmǔB* QȎ;T?8קW^Ջ4n>}`ye#G$%%w?SN_+ :$3gҶm[nϟǥVUda9UV?t'p-[3gEau PIqq1-1IRͫhy E]IJehذ!ݺucڴiAG;/UA @7"tdyX^$I5֯жm[ 7 :Nyf}X́**IicĪظq#MkHRR #f?ahҤ O=l%ޤ.wPQI HRںu+W\qÆ _#8㌸;= ⏾]U6|z1twpIJB7n䢋.bڴi\{AپX_ !##hOoѐͻPQI"II/'??dgg oC5qUkryB,CE%@E)--e}5"ѷ 6yf/^LspIfUSz>iqs^&YRHRXb |N;yHa8G[n᷿-t n ?Ƶ+Vpg#I{dy$PUUENNM4_O pCu7RRR˜1c(++㮻@aXZ :$"II  SOѬY3Z/PXwU{QKRRRx9c뮻شi&LHsPUAX^$)IiӦ_7aÆ[](bܸq4nܘn ANJNO瞳HKIR͉D 5~[o[3nܸ#NVQzN))U$D"pYиqIرc{o˺u낎;YYfwIRHKYY99wб`VMy'ދ_VVtv]w-[%v22a֬Hn,/TXJKKfOͶ<}L<:Q`juxT  gDvcy:ߧ_~qTVV5ǎHI}@wS@@wJJ&aYY|9~I$i'IJKK0`7#%%6ދnda5'UV}_ ghcE4h6l_ckd1!NfзERܱHR۲e _|1./'|rL_?5[Ƞ|zp~DxׂQ{aHҷ,/***+Xd f3όytYl٥V߯{ DIIIqjGVlsDey33Oӻw@2咖v'x4u*ii $Wm B/E 0>,H5邏S'I+IJP^z)K.eذaeD"Suդ!m]LzzG J8,[m ̙3͛73h ꫠ#ռ,ߡNX,/B]t :ᣎ⌯[YY/I&]6mxXjÆ c˖-AGYYYv-D"A'$"I:\WtQw^lԩS'f͚E$G?UUUAG9p1N7,/Ó=쳃N={?'xӧ椤ұ`ڷJǎɹIJBA$%_8"$㏧gϞAG1= ~Z6Kޣ-PIqqu~]ȋ$Ź 6P %IW^B?0A;?%[h@))@nn^$%!ˋ$ű[2l0rrrgnyȹ̧YEEŁ䒔,/Yh\sMq,?B!#$Ȣ78N/Icy8u2yd&MD>}gpYмyIT RS+*f3s/p$ŎESO={˂ww9 ni22ҁB>3w:VX}_b"Iqfɒ%pW2nܸ{+[o :A%-N L, !-myyAGd,/GJJJ6lݻwGo-/ 8sx衇x衇sP0TF4g=ן؋ѣgM@x΋$őM6qg0m46lt}[N=Z:I3f r iii\xAG:`pI&F҅_ߗsE駟μyhժUQ.eĉ 2lЌgA',/n ԫW'|SO=!C駟egDRHޒ%PU{$4mڔYfQQQСCotp}~:$Et䓃NpN8fϞͺuXjUqިQ⋰vmI$%!ˋ$m_ϻűΝ;o\rItmHJBI G}DAAA17ҥw9L 1y)A';$%!CuV|MիtSX喗d6j\}5| pBi$%G^$)9r$VbW\ :eE 8((_ ԩA'd,/C~;saڴit18&??T?BVpNs䑤ͯ~+z!tCu+D"NElٲ%7j,[tIIK.ocǎ4mڔN:ly睠I'z뭌3&86n~NR'mذ>}p5PUUt}26I1ey_̜9?_W\wu,Z.]|Ie>#F`L818gzΝNR'5mڔ7<}A٧ x},:vLNMRnc1psg-fvv6:u0֦M+s͋$F~3N>drrrRzI9~Jw&S\\D~~6Tp1%A@ffnmۖt~RIP(Ę1chҤIQφ PP=C*77믿뮻sg7cN>^&rBWL 77/舒(K@9裃"IfѢ. B׿ >7x#H;)**LF4}NT,/y'Yz5AG3w.x"zjIBjj*ӦMSNaq .dVq. Tߗgy o 7@=ꪫ#I|hNӇоPh@f͘={6?я8ꨣ ,'oґ껕%`?>3L˖->}:Ph[hѢNFŨQj;$lr)nutv p ?>;H-?W |'|DFFz@M2)_n UFuW_}E߾}N^{5vʫJ.]bRҡ;w.&MO 6 :N],Ƽu߰g^@;G|:uŋaĈI,/1p3k,Xf O TVߨ"#//7|I?X^|1{ltEJ`eeeAǎ>X^$|׿Ν;TV¼yԿhk7,FRiذ!3gΤM6\p|AG k믃N#R23X^$SO=ŨQ5j?858 a6]*Ht|&M";;[<rsp).ʕR\<ɓ]fFxEկjc&1ˋ$U{饗+CBVЭ{/FU(+z㍐=U-yJKvKI^e6zVA]t3|ݻwlquLoYZ}mܞڸC)Hu 3gt?_ T4WUʕ0bn g ?lwKuG9ն68mLDsp*v]4*úwŋ/I˖-cW_ Et-yMը8@2kJQ||U7O'*c)a廬}IddDGLŴK")lܸF%}ip!IdKAGQ tЁ~8v/ؠ-1q{. 56P sM&cD_T6c(/ 8) L}oga92ZVzlZY^$%Ryti̝}. /:Nqq!;jfmܡ(NsӇ빠0 mݖX(ZC>,bY?=JJ +WgϞ|Gdgg'>͟-0C^wu.̓G :R^^.iiwrUY}fm$s!44ӧ㩶0`ّe| IDATOiӦX+^Fm90rdY-&qTv=tڞ;.vRST)r-ΥrSZ"{6)gz4fsqc4@k.vYYPfR4%/"R!8pK_gYG_ٴi K.ӿ"W ~`xE6ʲ _,v\@ 0\jdDIW1$iTw睺VFgun/Qf ,֭(kVq9[l-[[KII1;ѹzfG!.̙3ցZ-u֬, km5$dl:e6jdofg; 6~c.uV[[`ݭh*kU@BB5 Oy,+l&$$zL|||c"Ywe@+/"Raqѣ V\R5Xd &Mb„ ] ؼXX(6 !&f78ܦS| #;K3ot\qyu2.==e# PCkx԰\W_ZUJ^DD*b$X <<-<"6xxx0ez#<­m{-UF瞃[nF\CY%QsKo_U}MuA0u̫sPk@#8N*WcRJ^DD*({/={QҭԫgR.n6vm3qU <}ZXiJxQ A.&59KO6jYM{0WYKoi]# 7МqKꫬ[P\VfL)԰aCw^O\}짟W]Pi941د3K$(?[$(?#GfTd28M~2]1kia?30H\[sSJ3l.)+J^DDGGӳgOf̘]eeڵmn^aa0m|:Aiw 0?.vOyL>!z$[j7Ňgy*3aى6 4KJCDmdddo0uT7oΆ ֭abmGh ]KXEjXc3/wmr4C=FQvlؾVի_WRS}{A߾Lv7Z m[m`2YE_ED¦MxG''N\ZQ3 ~ !!@رc<3b߆c`0X c (M GYNya/A/˗1pУLСx]3#GcޒM)U=.M֭#r6&".^k׮xyyyfNĥbf.p̉ $t}WV &--M5,v}plbv$RI,_Q1/oVa{Kqplc1i߄p#,O*;]tvIXs©?pU T-8f454Vb/QQV\ʆRY9s?~%KУGCΜZ>]ߕDql)Μq=&)H e( x4,p8iq̙3۵-ɓ~QHf !+Xy k5sFcRt}W6T*"Nwi{=}]RSS5jM41;JW_Q3=_$؝!Rl Otv[:gL:|)l?@1[$&J?͚ƌaϿ‘N qj,"N hڴ):<111|GJ^ov2˝-r. /a͕۲Rަ_ڱ-t +(fם*0oxtAp/Щ|:dl K>ѱMʋ8Exx8!!!x{{O3fc-NHxqv^N.x x /X23mjtd tc1*IDpcY+Z/,,dq-{Fz^99_z/ {UW}l)b6%/"]veڴi9?? ;BFYHN̙=;C\P`GIW60O w/>o RfF"0J%9/uI! ӎ 7$V/{enR'RVS4oޜcǚ[g%U ;G}Bvv8F3~5koٹs:dzr<_ ahVkQ*Giei9˥%dLMe&^%3j֤Mǎ;~>=(sZ8`(q]Fԉ%%/"rO"##yE9|~= e3[C=ɾ}ۨUk%۰xmy(q:{ jxmԉ%JvAj'jk.~GٵkT^Ğ38M[:Μ aJHKkaQ^j5w@d!e'؋'dZݹq|}/卮mK5U޽涘HweC+/"R,Xe˖l29Bj4h3foJ*f)]wQyE~+.]L~ׯ͚57nO0{6嬎ԯ-[B@k˖P.xyef3T ^11D&' zDȯ[a'ב}$6\QEPM퐥BP""Œi޼9{/W^Ǟ=V5"ۛs3zhڴiwA^ѣ A + o7ؿ߸PV [z|`bjxP!]ۖeԪ(_*>%/"@FFÕZjqAJ'F%e&<jք~̎D\~~9s_e˖h"yܹs:v4n@rRq1ayRbZڒΝV-T|J^ 550"##"))ٳg3bCJ*!!m۶m6nʶmMY0>s݋.f͚{{>| 6Plժyu0}v̋rlײ(_* %/NȔ)Shڴ)ڵcڵX,^}U/;ȷk׎Ӿ}{09R)sWþ}gfG"tM4ᡇ*~t҅ Zn͵^K֭iݺ5\sM-Q%Ię8Aƍ9~8g˖-t쐤$>>#Gp!:LJZjBvС͛7WRzcڵ={l2N:biӦlݺ:u\0rZ6 8A*U_>`)1cưk.8~8>͘1aҾ}{-ZPŕ?{V|EjԨcƌwĉ޽={CZG3UsΝ{2p營գYfhiI"R"R,pnp SXEJjj*)))$''siԨ۷owǩSV=zaÆ4jԈ rWӴiSj׮]o]*>+6;S^=zA=7HHXʕ+9qN"+4tN ݪUzógϒw ooomY Aɋ {^[\s5vxb̙cw~|__d߾}v{l5xBBB+N}iݺ?{j5*s~߰aC,Y}رlw=z4&MC5nc۶myկ_-[RV-j֬Iƍ>?ٳTl؇",{茶F1)g<|8xzzၧ', fbNu[RRR߿?% oAG[r,[?1w9| ;vwyg>ٳ<_cɴk+VеNpRRJ^\خ] }]yTâ9xzzȥWsX,U19jԨA&M }~֫WѣGڎ{yyaҠA.\H*U ݪVJ*Uah%r"arͻ̹{zE\{[+%Aڵ:^F V\i|fff'wy'K.%##L.\עի5ߥ_ bЬY\ejE} {VZ(xS Dv*<[ncǎlٲ:89BqE#GcΜ0V1k@\{"qOBE@ $d ]ߕ q.6Dc*]fy:)R/JL4BC ׶0Ht5"gJ"{m8NVT`QG1%|~3UBB8V8ŦI,T""/|ܗxV)1sT)i]ئI>&O>|{$"tHtt$pịsq?%)/-Wj)⎔8[ošCsŒ%KXx1Ç+yBٰa110x`Wݳ4'z.aa [ĥZHEҹsejT/R@ lذa2ÓO:1biۘ Əto+11 _~テ74ST"J^DDL1Ζ.9 8wΨqx ODD%iۘ 23=RG&O8X,+""Rq)y1W`vO|as?S  Ztn""".Bɋ :w$::R =$'LrrL>n~* A2 M5/""& % `dori!?nQ$t,3q Zy1? rLvh<א8^|c`b"""R""bfϞXINX/Av EDD* %/"".B;,!q@vyI5/"".s@ ?N O[OLȜ"""V^DD\HXX(NŇ4F%JBXC1϶7p{hNT:@,:w$,lj,""WT]x fKQ͋ػF{q̎FDD(yqg=@0{6X,E?FDDѶ1Ycp0DEA͚fG$""⒔m,Xڴ1;mc""fGeX>qiJ^DDpFˌfG#""򔼈?a?WDD(RD $&&FTT4x -B˖ݺ:msyy{=<==ׯ١Te=swҥjܯkSR΢X`:o=WiӦHPC-m=W-Df7/ Q`~]DDD\rpB?wjժ`_Rt> 3xXu@+kQ?@uMqJ^Y\\5*t<رS IDATcǜHӹs ёu*s{ V͙ݴ<˿yc~A۶9r\kا䥜?U:w^D.e <}>v@^oŬďIWjto"""Χ䥜]q:wޞ^xڵk;6l0 VAo4ϝ ?h]wջ7/80f{|C_L,""NxxxcIII&ES(y)g55,..ƍ}YСC&Rk{g$,pu0m<4lXsqW3 _6oݺ;Qš䥜oߞkגB5GFS۵kgVh"j$, _;lu\NK}GVV~iޱtfϞM׮]iLYc*im»BNp:(q 1V^YΝyIHH srafϞmvx"%S[R`\_O?$k׆&m[B_}9RU&]DDDԔ8W_}ū_ӧXt)=z0;4IHH{L`5kbqb'ӧar#YHN`@*U\Ҹ.\6jBL[еeK9rs  s,.ThPB ۷/@DqC#Y8ڵ+q̶rD1]ʋ[TT4-'nvUW#YYe[F 5> 9VvUۨaqs;i褈yH9Ibc?o"##\"E඘&dQu0|8uw۶a""")ݶl%%C9s#/&p Ѕ~VVjjpQ_|jԲ/H!LDDĝUM+z@3i 3o)iۼDm&K o#hHdt cV0w)6Gݶ5^N$-D_Vq;I q~6ГT|/y%+"8qϷM"""Kɋ sVDD,ȉijgOqӹD?78-*[.`WDJ^_ߌHO![?#"""R"r>IY*m+9joA:/ɿ5O:B!.eEL)H[F33"""b.ռHȑ O ȑHLL4;4Ə"צZa:vIs&͐ r;) ciЪ@nbJ@ښ윣@DNZQ1V^RpU Gz>e9rVիѣ]3@߾V-PSdgxZ~j,""~H#kor|q]xnJ$$ڵa ={oOU GJ-EDD܏\j_\۞rYHɰ~d?^ {_ދ+N/mG5/R)!IM19X^~U. ?:yְ?KʋT E~JQQkV""c [Ez;.HS";nwq{3gXEʂm.&+k6icԲTRMDDDS"Wg[AA.d%]#3U|9'7Ÿq`{9P"BE"d"A`VӇ54 t,llL`7rvM bhK$&&yEOG3R"n" W#LCt2d379leS%osqDDDS"JΝ[o>QQ7>xyS%dAJ22R;OɋT(82OR1k%7Yt-pPՀsnZHrrAKl77W#"""qi%paŎ95~be dgCӦз/}@zҴy+Oɋ󇄅}/I=ݎb\?y[ dկO?ǫ9.aV-nA/'##v~sqDDDS".1t2O(ɼKc$l?6hԩcZyNp]FJ30Z8F~;_zz o_g\rl ))Q8t_thZv6Iytz$/ūL`Xo]ެ#$._ctFF*ϱ.v `Y\ؔ2x.soON6Zkְ ěe}̍d @+Du;@eWR[Cɋ,`5kUW5n[֮&>!8-\tO>ȯW~h \a o[sMw/.\[" xW"""".Cɋ,gqUٵ?QQg YWr vc~nMTUғ,tM#['smkVR_Ïͯ{iEDDD\qY #Mٲmɓ,޿4 6#S< ‘͚Y>pM0~< ;ݧq"UXAygSR8eÁ2k |dej8v Y+O?mtj$0P)G]4}^DDD(yD1-{JPPµ8YYƊJnF}JCFJϞְR(銔d""""RT"_z]inf %f_8gd׮Il"""""ŵMLp`;׽K]DDDDٔj%==Xߟ+vRW1q6%/%n:uݻwӪUz^xc@/Na970{ZNxxxcIII&ES(y)6m0gΜbݷaÆzfꫯ[!ļ+U_ۆ ưaۺu+;v4)CK 4hЀÇ;5]Ů%""""7-v]5.8ԩSصk_}ׯ`ĉ%""""N8kbjbX/X,J^DDDDDIɋdgg0;P""""""nAɋ%/"""""[P""""""nAɋ%/"""""{#Ǒhv("""""SŜ9m4+11 3;S)yq ]6;S)yq dfzlBDDDDTJ^B$;@"xf#""""b*_ $d1 7;SiŅ-\:t0; q J^DDDDD-(yEDDDDD܂q J^DDDDD-(yEDDDDD܂q J^DDDDD-(yEDDDDD܂q J^DDDDD-(yEDDDDD܂q J^DDDDD-(yEDDDDD܂q J^DDDDD-(yEDDDDD܂q J^DDDDD-(yEDDDDD܂q J^DDDDD-(y)gVbԨQjՊի?MDDDDĭ(y)gǏg <CwѾ}{O\Lxx!Iss)=%/l֬Y߿3f0j(MҥK>0;|xۋ/?ƍSZ5vʯjR 6mg!((___6mʐ!Cطo١M6 zC'غu+Ϗիs͛73h 7nLiӦ SLQ "55I&qwPn]<<<;w_qԨQ???Ή'ʋ 6l-_kalڴ5kpM7~ڶmK\\|gϞ? (( bcciݺ54oޜ;w 0;2d|}}ٿ?V_tԉƍORn]6nȜ9s8p ?!e:x -ZiӦ4oޜk2g~oߞ:usϑ›oI&MۤwF"##[oKKKlڽ{w#qF ۷o8ې!Crw뮻p%''[4h`c{9t$=Jbb"7xcs:ub۶m&D~*EѨQBs;v!I;ԩSEÇYz١۷Ln{1x ֬YORR7;D)7_~o>ĉ>;> ???.]ʴihРG69Bqk8E\q6 块ߟ:upB>Tp'N^zlذ|LJ '|2e Ge޽4n0lƏϰaè[QJy_{G5/.QF6.1~IŔ̝wə3gX|9 64;$)G>g%66rAСC>}0~7h B_+~|;wNuDvkKUbP"ڷo޽{IIIw<22vڙ8AZZ `,]k쐤=zl{9Zhwb޽4oޜ)SB|swzLR.\@VVILpWϦM ҵ^1)yqwYYY|yә={6]v+41:)/YYY 2H{tbvH_=K,~Ȼ-Y 6m?>jvRx|?sݻ QIyС[ne߾}I۶mMLm,]4Vb߾}&F>,VGͨũ ’%Kx `ܹl޼UVѣGÓr /{1`Z? QYzɓ'?Ec=Ɨ_~<@^Xv- .d„ 2XAܹ]RfMy֭ҥKY|9?8|!JHJJرc|{y)=5k$66SvmyRRR9.c4IDATs&M4aӦM6V J^\Hzz:*p L2[oФӇheXln3O>pM4 ::^z~Uҿz-m-&%/"""""ꋈ[P""""""nAɋ%/"""""[P""""""nAɋ%/"""""[P""""""nAɋ%/"""""[P""""""nAɋ%/"""""[P""""""nAɋ%/"""""[P""""""nAɋ%/"""""[P""""""nAɋ%/"""""[P""""""nAɋu@ vyX`A^yX`A^yX`!'p5NIENDB`lmfit-0.9.7/doc/_images/model_fit2a.png0000644000076500000240000006665713066042256020646 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATxyx3ɀ8 `d"@BP ؀uIOPZ[W'Rmb[ Z }T$` Y"fXML2?fXIf{88<|IC{|>O`dH! e ,C`@X2! e ,C`@X2! e ,C`@X2! e ,C`@X2! e ,C`@X2! e ,C`@X2! $֬Y1cƨu:묳ԳgO=s. =zG}TM4_|-[. 0"L[uUz7MD`Ek2M6MtUVV 0!/Vf7ߨ[njڴ7o;S# aꫯֈ#4w\r-9srrrLIMMW_};Cӟ];kҥ q V4jH4a„*'L^~ad۶mڶm%5 tڵSvL Ҿ}{y<m۶6mHs3۶mS߾}uVKj@ڷo>RG۷/^͛7?vhsp ڶm ӟTO=^x 2ojР=zwT Zh:N,| o ҫW/r-zU^^K.DK.՛o~Xs@"h̙ԩ4o)-)IR,PRejBNr?z̀nWa',rtR-[v?Q*.~ !@qn+//ʵ`K+ĦuKq/RoZNCĽA> ԩO*'gF[1JKz!V %X?KR%\"N'LCĽAfy+ԡC*!c?jj(.:Z'MD,@/* 2ru櫤m*77/#z/'jy@#^AEe^'jq,Ľ5P_%qG$Ԥ@C;vlRZcaȑ򟨕^@5N<"UT.IeѾ}3o_ojlxZn+EnKY*-&^b:*/KհYZ@5ٲen$ WÆRIۖ I^7N$7ҭiWPW@1uӮ~9UI`8ԐӮt cx]c  :^ tR :ڱ?PN >އjSCq {ׯ_kI> n 4Hcǎ5]čM:юbϧN5r/a@հrrr~hРAU>}L1} tghܸq+ugDӧOנArJt c>j(7N^xz!-\`uhDhT]uUϗ3]`)f@ ر9I&O4I-Zrm„ 0aU%@ڸq^{5ٳGӍ7ިA. @={fϞ]޽{ U? |jԨQCf̘޽{[\D'8siWOڼy.R޽[ڵS5rU U5k8L zO駟jZ(++SFx>)-Jy<*(Raaݳg.ϧ?\;vd  ƍ+==]mڴ_5iDO= M'vc޽{9rn6]vj{t=.bVyyˮ?Sj̘1?X9w}+WjZdG  jlY^?ƍ>$uW6m4dmܸ1#Td(09v]K,QJJ~_Gs@ RjÒ %UVJ*TjTݮpg롇+G@#nWaegϕ1Z]1ZsC:nVkNo-|؄jvVGFҙgSꮻԩSգG@,#'|]qar6oެVZ@a  n|5j|38CӦMS۶m @q㥗^֭[5qDӥ Byyz)7c .̞=[_}Νk@ ļJF^z.Pf@1o޼y/.p̀bӴi4l0 0_jݺu~NùbZee&NnݺYy}>F~饗^s@,cRRRtK?oRRƏsСC5z3Yii#խTNdy^Az߿_ ,zOYYӳ4kֵxYYUzz!@!PG]tk)SrUZW% Pi4\n *Azݻ/.HqH!++Kz뭷//O񙏓[ @s9GÆ ӫZV!WH,} @1E?ձcGUTT2t:$UTiboDCĜ?X]v՗_~iIeXRRRNs]JM}XRJI>Fk޽ԩRNnp\.Pyyl m|X~loHr` |>͙3G]wl5fە[ZZHy<>UA2wK1?ԦM4~xӥK!TCĔ_]۷WffR%ސBN2WDPl] BoƏ~-!{v " h1@ tyt.%RM|X?2B6b@5 kM6:xRBҾ}{=j۶R @QmѢE֭7nl@@Q\/W\a@@QkժUڳgn@@QkѢEjѢg@@Qw_.f@7:8+˭bSdU bz뭦`TYY22ƫIInII*LS߾}׿e~KX0jʔ@ \jƌW.˖-o~|>ӥq M6MٳR j{$2zU`<1B۶mӧ~j0b͛7'Yg? Nm:묳pBӥq[1c|>3 p!(hQ`<1B+W޽{MF@"BsnV.RjÒ %UVJ*TjT.sŅш#TQQŋ.9s6mڤ%K.nWa@'q:rn.1,:w=zhѢE7nrHڵK>}Qnt9`\u Aå\Iґ#G԰aCÕF}GWw #Gg{t)`\*(Ra㢋.RvvLb;@"fÆ _3fhǮ>|XG_f͚e˖<;i$hѢʵ &h„ "j% Pi4\n=/vZuPpٳ5{*8H| K.СCkgҤI׬Y>}hݻwKK/URh{U;{n5kxV̀DHϞ=5o޼*G|>=#ڿ?(55``4\lzM8F֭[몫:3<#I3f%QV?RK믷2b$HHk8أG{mݺU* g}f tiH@@8p0;{uΞ9Zzz͛.56nܨ{N `~ɞ}Ym۶())ĉ5but9`)f@Qe˖r8˰DfftRӥ Xyݻ7@B"`!CtRH8 ͚5S>} `u];v.,Eu+''G_R,7yc^W.[fnJ/͛7k/~aRVV*-}R[RJy<*(RaB1˖-$]r%+.SÇ=@rDtRnI=Dl2]z饦ˈ:):>q8&[jÆ 222+VK.!$//pe~̀ŠBײeK]pZ|R  $H@XqSdffjڵUN xDRjÒ ?INpr+.effJV\i, 8n:us=eX`ŽK.ю;jrأlr:r];1c=}jԨQK://NmGf,X~ֺuLj R<@4#,СC6\#4&@t#,|r5jH_|RbM2˗/TÆ Mh @|Zb˯&`/Beeez#x1K,_\IIIJOO7]JLԴi*׎6yy>  6@ܹ|A5ot)QoڴiziӦSh @:tjpoѦMԩS'@X(!ɿl (cս{w׫JKn(-mrr&FRKB HYY22ƫIInV)VAA ٠ z0@_ٳNtSz*-&J 4~)+W<I@t ~]vZU^3'K@t` zhΝ;^BOՇ8D |I|>-\t)1[nt)Ɋt:ZKSQQ+W2anKK*TZ)PSv'a1%%%ڷo$v r f 1˗/fS~LvrM*))u]TuYjݺ222ꫯ. ,b [76] J0A6mz7u7jƍ:u /_qƙ.E 4b1ʵK}_yfmڴ*XeduQ 40] Dp8a7ydM>3*,6 zպuk cʔ@ Vt\.u^t)P/̀DmݦN\rڷo۷W_땗%@{8^I?#\.BVjjR^ 4~x ]vYf߿?jذaz)/O"9r7ͦ_z#DPVVLaUHBRo5lh}M@8IEՌ8U@uvBI%}snы%X:*,St7ڲEz}jm :=w}}_EzF,͊+4p@e ^-ڵki?ʕ+O{K `¢QFڵk|>RZ /ȨZ$)90"¦qƦKHO{_^-Tk 3p@^ZZ$^- c#G裏>{TJ*TjTz0@ դI.:ګ%;{uΞa1f)==V@N1@ 4hVX Q@=v7))q+B[l"< IDATլY3@1Z:tիMPNfΜIs zm6G?2] @RPP .@Z2] pZ^W.[fRAAjD@ jTVV*-}R[RJy<ϿF_N W ,hʔ@ >GJ @m@5*.Hdt4h;ZY @5*/O񙏓-יg;wcF6[$_ѿn]vޭkVK.5] P#!(]rIY¹瞫Ν;t)P+@nRST(2pRRRSv+LAnp]*,#nĄ7h }ڿR8-ݮ\e AB~.2@ C[f 1.)))} ^W.[fbY" )))X2edtwRO  XIEEXt)8ĉ{6|HҔ)1@ǛL&Kir@#Bg***L:*.H ֿ`"IAA6l(iQyy|,90A@әgiԑV!d20AԚSAA dԃTd(0A_|;v@bRjÒ %UVJ*TjT.s{ %%%)##t)ݮ9> O#xDPk բE ӥ ϧRx$nW^^KvUWbyN4{tkÆ Kj1t 8t(??_]v5]HӦMշo_.E 2DK.C 2D;vn883p@5h@K.5] @9묳t: *@CC '|>QAVw߭45iD;wVVVg)>O=<R)Shڵ56# Ok޼yn|޽{tyP+6lo~}צKA4ie)hDA<'欬,SO=jgɒ%JIIQffRqA\ҥ֮]k"]~~N6mjXrأlr:r] |ڱczi8Jn3] ,RVV*-}R[RJy<*(RaBza^}UmݺUYYYK*))Ր!CLLN6W@ڵku]w)##C7|rհaCedd.).Hd`%Xپ}F-[7XDQu}^}UFLz(//WrrOcyy|,90uG}4b}*((9S&MR-\0a&L2$`up^/c.ө%K_~fS!20$ٳgkUݻP5aѣ_h޽i1czmAuWuQɒ*P.[yyC}tE>O NCOpTNGkUuoYF}1TQ|`HUTT(++KEEE?X4hL~ۥԇ%? ? :Un+BH̀D< hڹs^y*7p*Ƿ!C? xnWa~'NA~`-XXRR@`|Iv;KD K"(??_3zt}.|JJ G-ۥ,N/H&EY9o"Tm @qիFiJDѣիW/=KJmfM GRSc!Co߾U7očp6 u#@Kc.ğÇW_Վ;Զm[X]a:JZ8<+@ p$$;wՍ7hdj=<3[H?KH7JH7 @IHR6mԧO-Zt)0̊^W996RݺQZHL2gi֬kKϗdz@f]SX_JQFi*in0 #&q5sLUTT(%Deua uF#b3W]%) ,is5ux8H ui̅4|pڵKkx1",.3,5hXWe6eǎҢE%-]Zs}J?i`H]s!> 0@͛7עEԯ_?2 !_YࡨL7S)G7U2NyL}m_NdT\,KIiiuPoH0'1YPPVZ>f;Cݻ.EzYf]fX\ItҬ钮 h?(K'TJ/zYiPkWyw+gr̞ >uUR`-s^׊Sզw}e%x( 6b4O͛_:WVg-]pAӫDAc^Z{Rx",.3,C%ɧLCt6Smնm'̯U]=E;H:l+Xgƫ.3,UBQt2{seڥ:CJ=!_f@ -\P}6Nl%\3^uakt@mdiC6sOD7P^gDhUhjTEE}]y睦KA [byAed\ ϪH47ni<3S-KY*-=SRG~H@ AZJwֈ#L |ƫLt}S/HYlT%7zޤIeoѰlYa?Goe˖r:KA|JJ 6Z:,W#}ǒ%+ICWTlJ(BݛRuIxI}]C":ĸEO 3Y^RRRtM7f㽨DW;wֺuv *W+%^,46gʔY/_?_͚uӳBgNV.tNWg#_WK HN+Җ-ztW `&2MΞ+cv#cV;S}Gwu gc=fafڵk͛_ZE]&1sΓʂxնKCZi(WԺO*OWlJ͇0 d>DիW$V^m1";AT|Y~tƍt1.?;v I7|t)1axb%''kС*F4OVgj^>K7oUZZ-FzPJ{J#kBNOtjh.)f"?JYF}իջwoCT֭5|ӥ N/B/0bwރ0b}ٗU^N1c,3LÕK=th=bّ]B'hoxV̀@زeV\^zt)#,z؄qQoo#F=FEܬaU7#af#G˨~i`eK˥Ukvw S N\&I(KJֺuUR:vlBԴi=Xorտc ͕i8U +6{@ _2vJRk?a}QH(ǸfLnd{}\w.]tR5q!` Щ/Pޒ4XqfR dr!Ѳg!ICմ!<ن<^C>%* A mHmT~v! /ġSmMe(oF=zo+2iƧtjϋZu/Lh}2BUN>Ғ%R~^XXȦ=jyگ!Xrd*@8tN Ncǎ:K/)H'4;woXWg"'|9%M.%'K}*?޽5k_-9lo5?_N+ 2  Y)))I999zᇵgl2l;X3P&H^* $5o.Ij!뮫~y+ԡCz @ [ g?Lٳg;4]'.gl|X-ե3S5j۶JJs&@"r***Rqqݫ<|ͦKLcq9+ԬY3|nmw*b2|dgKv$_J{顇?vr{՞GkVm8 <8 /hĈСR3ڵG:T_:osA!#@v qli?ѪU[o2ٴɿg?l_xr5U熃BFB&MR-\0a&L`"Vi z~5JJJƍO2vR@ufϞٳgWw^CH1cz׳{*Su Q5_*jǎOՑ#G]7t6lha@>,=?p|!]y4dtRAgğ9yQMFƺFMFX W_.@y ]!Ռ_ny჈JKKSzz}d.iL+{:ZyƿIh~hm\@i yvϋ,q!Pw"[t ,|>iÆ}8.UJuw/ԏSpj>nw\ Lk׮Ur2b>]S  N>$u]BCquRuGn:͝;W?<U8 -_~|Reԩ4t4j "Yp q!?ĨӧsM7dD_&N98nG? [h,˦@eK6m8 ڌ/]~8  eeS@t @ 1c7not)BE%eU]&=@veSy1{̙3u=YfA$TV=i|2FƍLcG@@ ~{ヲKAwRÆRztNZлᆱ#F.@#@kթS'mt)[nƌht5{+… 5|pR 9ië^wݻRD֭ǏŽziذhc+B^z~]vexTRVV*-}R[gxUPBN݉k^t_p4r"%))I<^wuD!:W@Ltr*-&m8D 7HmH?? "TV&?ر+/X999={.@"@{ovVqĥk^~Yڼ??K]0G>㏛.@"@ɒg3~+ojko:t(Ӯ];=Cz~z IDAT2B/he`Qi KZo9SڰtuQSSO.@!@8IEAFȑJKn(-mrr&VjҤIO*jo7}ԴSҧJ;v{rF5҂ sϙ.@,ۥ,N/HJI e=/tSyC_E]4.XJa\]t "npN9r@_|'XGU=+//WW7=: }qo_T֚CokYYh Av]yyUTq*.~B>O'NTZZ~_DθI_}uG~mdI^*aBHHXmNzrJtw_KRS ht;~:Vu!R{4i$qf5j$m"]}?p\zԢSa-Ν%r8ouio"$w !͛չsgӥyxd!aȦL˞ PQjP6G VG\@,j)Yc¦!P 5@$!}$u,1Ug9cbb2GRl]Tg_V޽駟*00м"=Ņ W_IfIݺIKH.]*iٺ뮻h- `0Xqwq>SXUXvޠJڵ3L>-=ԻVm_\:|X[*QIӧO5qDYP L`;؂wKcqږVk5j-[I&]@ϗNZr&M G56rHMpK` `ܧP{7!Cl{8#|T{oBBB… f@kedH4j$u"͙c;#:ZZ j׮k},:U\z~Af ̀.])S'Ԁ.N֮&Oڷ~{'|B@ T@ffc|_g0D+((_|&Oӧ7ߔ7[;'}k[>uzǎnHOV+9yIIJJJQ[+VhҤI:uxf?hvǜ9R߾RfW LSf^XTkUW}$E(9yc.tR=>`y'IHH^E:r䈦L'xB#'GڶMzL޸1a۶mo~] bilvG!^7կAZ>Ej߾JϗزEڹSrEj@ڷ7n&gϞzC]`i*;7_$E3,|HҴiRD4TҞ=ҙ3҆ TAǎ+**J3gT^^e"f@|@o=Ô{@ūgOC3ӦIcJݻZ^^zZzz~Zw` ^ }h̑'j8?lRC>HRfffj-F6ovn6N@5aX4}tm۶MǎSǎ?T3 Lۣ bb֚[5m%m6׮]?O&KzK.敚jۿQ|Gj#!eg/22RIIIZ`իgv9*bZ-hۧnݺi޽ڵs@{N?$*CIݮyTƍa{^F>LXoq 7*Z1F999;w>Ceeesz5`KuR\Mnk7Ђ ci˖- Vtt^UVu6m.]hӦM駟4em[[5@|=OSKICH~*Se>:rԟguYzwbvY@dݺuӤIJGU\\N8abui{au:vիWkkym e{4AKuY3\5 j5uTiF:uDM߯2]:z!IղeK3J/˳H:$GI'[% TW"5VneS7Սx=Rll6mڤuKj,ye_;y%BU/ܱc,YQG(EwI"i),~AںU>]j+ޫgbb>n^@uװaC1B#Fd[|h"ժUKZRppՠA#=\rEeP~ڿZ7%,颤sqzxaFFիW/6V|HIIjr#VnE K=.SDv"s~Qlvmi }RϨL7/(ϗ~_rnPfԤI͚5KÜ4pTN*00P h nRvm䔹]tXڵ>RÆ ދw;vPLM_| ,Ν;ӧfϞ5>WF|!Cv@>ϱm6͟?_Vyg˖-Nk5k6mڤ(??l2ϷZ޽{_]}@a}I%ElrFҨQ$پRrrIT|b]},7OMuNW"P:bފBA7~{UAA222t1?~\ǎӧuYկ_wܩZj) @'Np:/KǧԏbQDD,Xഎ#F=>'={+b'|:u8|[o͛7;ߵkWKRTT/oO:w^CR?GVV@ܤyvYKZhk-[d$RߜǪzbHIIhIX8w;5㵪 5JZtiɵXBfF8{VZ^6M 7dU]},r={s=ӧO+$$DVǵb tiBi[*IjN_;W׶܁tGq>@/>C;wN~6nt/-233O$쟨> z'=[n){ SRRl'_+i-p} )q2fC)9yl[$JJPHŭuOΖl3"XCcI y} U3 :}z~(dĨ8d$%%hݺ(]Tg |$E(9yctT8˓-vڴ*TQcj%|PUv͞h0_6d\D(IR/%$^JAjvrZ[v~.iOFJ{xQ7V^G} JHH-,S_;EUZIlKJNu\%(PL[4V ࢏;A!(.S Ev9oGSiIQR{C>˺W=pp睚8qC*;x6x`ׯhUR %͓-8@k~4ݬ5Ϲ&)nenOَK\<]vWOB Jڣ h2=dU=0%ih5U6Tf6y_+7C g)33 vFLLowԎO~NQii}EO-mڬszD=[2:+][W;p \B֕qb)*<|>H>:W#)Jk"u11kKNetTon%=Bjfqe YW Ҋ/K;vzǭwIIU68IzF=Z^l /eKz턢 EA剳 xT l)./K͚IK[k ? Xx-OU nř>]Z\jXW_lCFWWX$} EMKo-{Ƶ8UX(%&f2 /珿V2JO9*28h?IyP1j˛8;GűZÇm7q9#H{#x,W. UGAMKo ҲuY|?T$??GidHvmC?eadT[mjG-dd(5V|EWwzNԬ*\Mڴ){{Kb қY& Q_}ڢ4"iӵ]RF\{Sb }Ko[N]k:^$[@(Miߣ^]]1~xj *'m.NpG ,IK]׸aھ+^P;q┼]1~xj "6iڒ&\-<|*QPkH֮x?#[[uÉy鷿^zI_[T;*|ux_}IWZEKl!ijFGqj?>$;Wf3^P}媖gE}u|}W%g*?~RRyGK$ 7Zl ؖK>U^ʁ-;T2I=u%Z_=د=-F="ؖKQ0VϪtJS?Ūb_[z1KIשWq\_{ ⸳~`_JڢP$ڠ{_{RZӹΝVUEKe8~Z@vSb3~~Q-ݭڬz^ꌬ]z|ϨuD,hp,XVEf߾}֭ݫ]]K}uG̱^`ܹ=)-MVǏ+G}dD~#)WTdֹa{PSU ĝh{YWq<8YgrEڵKlo%meSaaCt*9*7XUT듽e?GG\ _?i۟N^޹ii:u9Ȉ H p={"TJJwK GxSRR{7'qiקByaCǏny%#6Z^Y^gnJJ4jtMO8C_놏ӧO+22J+WTRF>ʕ#RVHٺp]-W*yM( H `8n֭g);BW-z%m۸zbM7;w,V,}Ib)W]Qh 0!0 a C`@Fg)33R"x~Z+G*22j|$E(9\Z -IDATyc.pG륄$\|kv@ڷod-^X7nM]"`8f@dѢE:z?h„ 7o6nܨSNiffK},k~@@;(s;TFt!*'?X5 w(?.^ .I&fbE)//OQQQfM`ZSڽm6+R߾}]X= uV߿\=tBCC\1b:w˗_5ˀA},k~5㴪XVExSNg;|p5hРSSSէOժUK;wt~7==]ݻwɓ'\3ܣEڳg7onv)^FgϞwܡ,رC!!!}Nzz ѼysG@ҥK߿+66V]t1$t7>| M0̦kذa&mڴeoo֭DŽs@rrr4{lhBuQDD6olvYpݻwkڴi Wz(9r`yG:u2ɾ}4tP5nXuUNo]`Ϟ=6lZhu[ok+W]ҥKz饗tQFѪU>{U~}5nXcƌљ3g =Zׯ̙3վ}{XBwVllcvypQF)..N>:wt-^X/^w}pKCQ6mhvIpM6iȐ!֭T^==zTVUo~GC-Z?Fi׮]Zr?QI)))j۶զM}ZrƌSqiiiҥnF͘1C.\GjJ 7x+LoX,?O%ײڵv啺vk``G1*%**:`k߾}v~kӦM#G4`Μ9VbMJJ*u}رVb22TUNNԩSVjݳgbXWZUqOt EFFϯԵv),,L2*a۶mZ~-Z$*bvIpիWӚ7o$2BԮ][tM7ެY3VZfUVd5x`|%~*44T~f߿_W^=z$}fYV:uJM41IAAO'̮ۼy4hTuA 7ܠ)S(''b&LPӦM裏~Pjj֮]w}W3f( (N8Lu޽̽=zh&T=Szz7o^z'O] ɓz.nڲe٥9| >\=,XXի..ԢE ܹStRr^Ыjbe0Bzz$9c]rEeGu!M:U{رc.npY͝;WsUƍ.ntE]|YO<-Z$I>|rssdj׮UUN:Ol25nX7nԼyԴiSM: N @LVvmS%Q=eddhРAn:TS/4iӧ] ܬףG.u}Zd;H5kĉ:|Zh!8 5{l=Z52JK?*= &k޼eVS{RC/_Yff78r䈖-[ӧ+--M)))JIIQvvrssu1;w2"nڴiśY]W/;vP.]wzȐ!|2{8W㵫q~8A1Y.]ta]pxIo~3ʂeggkȐ!:z6nܨ;]ĉ*,,Ԍ3Զmے>|XmڴkfvpͨiiidxMp<ؽ.IFlRAAAڽ{w{ ߮bQF@K.-+V(""B-[4:ZAAoի%:u 6?/ٰa?\>eEz!I{Wﯾ}Pܥk׮ڷo9R5kΝ;T2rHmܸԗ|9|<'{(mذA3gTHHVZ={owavypzJo b_N< Uh}ٳg?] \￯zHwu[[Ns̡]55h@ӦMSFqF}ך8q,Ybvŋ+++K'OԻᆱxdVcƌjРAI 6ԓO> .h…jժv,'  ''G/>#;wN~^{5 8bӶmldXNׯΞ=DKkZbN<֭[kԩ1c٥ K/i׮]V۶m5vXEGGLJE&ެM6:v$4)>D~RV$IIIIz駵chРAӟĒ 0 a C`@0!0 a C`@0!0 a C`@0!0 a C`@0!0 a C`@0bޅhQIENDB`lmfit-0.9.7/doc/_images/model_fit3a.png0000644000076500000240000010023713066042256020626 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATxyxT{& €@!7 Ȣ `QvH X, TTR-ڂJ). Q ?AD$BIL$3d3y!sgϳ1nu@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ O;wTRR.25jHqqq[7ߔv2dbcc5vX;v̂b3 nmݺUr 9rDuIm߾]:u$:tH]tQӦMu}t'P\\vءH? `>#u޽Dػw.rr-Zr$iҤIZrkiFjZb.Kw.ͦ?XԲeKOJ:vv?eA9 ?Yf^GUlwUWO? ty@P!TK/Cn$>|XԪU2۶jJǏW^^^@k vޭ$[cǎ$Hl_~%~ 7ܠMl6$A29}tm9v6lؠr5rrr~ *RIYYY2de˖Ϲ^by:|=\EEE 4f̘/5꥗^o~˨ Çk޽zwu%xuj޼vY;vP.]||:!!F2e,Ybu^GFFƌSnC@r4j(m߾]ꪫn7rH\R*q={hڴi徇{UBBvZAI&|a;}Pe<GDD{傂!#䜜rs9O?111|^^?^bRQ>N4%&&رczK<9sV^~ =%%E;wָq,ctEEE_\ZhQMN#G(??_*(((~KG/B#G1F.w[nUv|cΜ9Zxw O_|{L7o-Z]*==ѣG>Ǯ]*O6MiiiJKK+;z4uT͘1CÕRpTfff6mڨ}>_7hĉ֩S]޽{uʕ+cYttt+/Xdddh(22R5*sede*+VԩS>h\?2eJ ߸zOԭ[7\7.KLL,Bwx>+77W66]v)33SNS(sռy|z 811QM4өU wV}* ;_jŏ']pڻwoׯt&Mxպur_߮];ZZppTu}A,X;r?h߾}Ks{OSLQVԺuknZ^{mmV~ӧO*o P 9˥?\wVFFvޭݻwkϞ=ɑ$k}c8qb@"I\sN:-Z(!!A={o[]pj߾.r_B+E (==]:uf̘s[ݮ[m۶:sX%pDs\ڳgo^k׮]Wtt[nΝ;Z@j*3FԱcGSǏW_.Q :nڰa*nV"~gmܸQׯWǎuܶYf4hP#$٣_]k׮rt饗/41,oW_} jZb  .!`&M{aÆV}Z]U'Os=EY]  5O?ĉժU+}JOO$ }ԨQ#mٲE;v$@@qF]wu Ϸ$@@[7p飍7*66FDzznV|Zvbbb. `&k׮Zvn\pEfӈ#.`1.A!F:sePc-ZnMiiiVR@X|x=C9rPm/^M2E?P-Nw}|Il6K1|M׿ѣ|rB@jҤI>|^xEDDX]@͛7M6Pe:t@,C0Cri߾}V@|A]y:vեB`|zOhɒ%j֬B= 6lؠɓ'{/RFҐ!COZ] @%=zTÇW\\VZK>}Zկ{O!@HSk׮Uv.ŋ.0Cl͝;WCUllvV\Yf;Cv̯N:YP5<R ǎ.]h>_yc֤IT /H%nZGQ-=z622RG`uP9onEEEY] 0ԢE w\r:XT?xz׭.f ԩSjܸ4iX%%%);;@;w5n8r-V3 [uU.Kׯ˵k.m޼Yv;5=oQW\q~il6KH-Xpa?5J]tfϞիWkԨQU [oU^^^{5կ_aK2el6mܸR9s>п/VSHǏW)S,;zhVPeo}Q=k.UViժU%~iQ5 'OԱcԼy ]dv:Onu)Pgx'[nUUrssu2?G$IC tIN:iɒ%,= l28qB$d?~\W^yF;J֯_uiذaJLLvjJJIIс$I6Mznvs91b6nܨ+W@^x{1M6@*i߾}n/a00!@ٻw%B/;?"@ػw&NnM]vB3gtme˖ze٬. X B3k.m۶Mru[oŋkɒ%֭P.`@v!7NÇ}gu9Tuؖ-[ F 5kR  X]~#!!@`ԩSk.KZ P<3Zd8`u)T _iӦ{í.j!@رcնm[X]iuqܹS[lQÆ .jg}~X>ziu9\;V 3g Wc*@ l6%&&jʕ1өj~ڶڷr:V y0Pz`@s:k22'&hٲ ڴim[#aq67= YRCT؈$\!Șٳ<)+y-UZ\>r QjWTfp y0!X cbt vi651F6mjԬY)JKۢEEekĈZp:yHym(l6EEeK`]]lY/ZѲeԫHx@7  R@gʈeoz}>}nVFuD Λ`@b|zꥣGZ] jIm̪ +!au:{En_%Z`Z| ڵdQ(+~A2MUUey!8@BN~;EFFYfVT[dkb_q8ڶm+>~ڴ))i{^$5S76=![I:V0<d4Ӎ$nu)dڴi~fVe.te$c$יK/h1Ƹ\ZoE{/uz(5>'1M6&>#-YD<.A *᫯&oߛt&&WJO{˟+ʾzX$ع(QM MķrZ󦦎UM4Aܣ?DGNNIHH0=z0yyyVJ~*]">~@sUeng!#]c"#1]W抽[ZޮtRM^w﫦7o=W\1oWE~nS*++$'5XsoD_m$t?WvJTrCMǎי ,0Ajlզse}Fg:33ZCJ!W\&&_O‚tMއ+e}ט~^? 4k%iU$pBO?5fVZR _qٹ&<`]QwU. 5YFiui@q(ڵ؜Q:qi2ӨQR,U6?G{Xp x@J#s `y3Z@'4N:ex sKA-F1p\^ԐT^cĉ3L\\cr>IIk<^竡9HM`Vrpt3Z 9̢oƿ^8sLa|cwWaO ε4˾HѭLVm,~P`תD8ns7|6`K^ɯʕawútAɹbuJϽ– ?B74+>n՛S~QU_gPރ>Kg(\WyZ ~0x}muYRP>;7ݾ}TrՠƒH!ir8z/jINg I<^jyV˖Vr\ ܣԝn' O?bRܫU$yO |$}WJk~jwHZ9պ_J.i7=oէw&/sH^qΜiP6jԨ!GII*餤Nu"9jk?oTlP]_|w0v˗_~ >q,?(D *}jÁ*߇oW[aUC\JBvJ{Ln%2}o(]3yqMWxzaBUް&_+a){3ۼPDqq8u<|Nkw}`U<_cvvQ*#^H!@j:tЧC<7,CKF.36[O CE&{Qy&އ eib#:fc+C|}n-3qf9&"RlW~>?ZU UY}\;(*loH_s ?Sal +^hUc탁'|nݺ)==]]vYl!C}p8ݾANxL.PG%iH= C1}ޥ;33տ;c:ʡIrF5*Ek)OQS=)Ԩr5iPgU)L~l2klj!Ȯe`*zUquоZ}]|i |{*??_w˨l^+2bE˸"dE&: egwQ-mQ5tUdd6wrro$#|IHj/~TRm܏%}*)56Smy2-zfKh__jKڽg=q JINIH%˳osJDg%(%,)B6= R{(2j/:!.rԮy^{}ӅuU&kjY 4ngʝ՜NfJQZ(**[G(#cJ<»2?>_gIJѨqFMOel{^ۭs.jegKN'Oj$Q{>(Q=i9Pޙ(Mg<P@22riZɥ2S+2^q:Ԃє IDAT]`S?gJ}|% |#鸤#2BR'6nm[ItFRgud-栤FEqmKʒSIٲuA6ފ*s/h;$*E#=:|S\ UOY'eԲg1 EFnVtӲU."##X} I#܏={d=+Idzy(JQV#餢SSy7 {_P Cۜ:uRZoVޜÁ)^Iw4]dTCV9Nu5okyAcۙ3f؎V ӛ.J7j9Oߘs4k&R윇CNJro?9;_CYJ5H%ݔLΥ&^P7~,2ML̕>Ty_!qP1)}|O:!^{$U;)Rs \ezfȋ)9:_ñV1(9_l}59"͗qX1&t璵M\3UafʝR6(qŋ wN6>Ǣ7tv~av029L*Z>8xʆ :̴תD @h=z5GW=dZkzi>Cu2gidȼ>f&ߪ?(4_)8&"rS:xMԕeoW݁n'>.!f[m/26[4\޸<xoK&Ǽ^yuFn_qgMV}CJ󒡴U|:233`}"&J/{ Xgn(DG_Tju `U$@oIfʕV*{sH1CyA0? Qsͫ:ܣ{L'}nl*0WN'NSޕW瘳wR(ڮdCjwߛUW Z KUd\\ B/_SYFifyw=Wsy~g=&<!P2תD @hp:&.. 8Wm៊w2c~T1c[~g:yƻƖnܼW[7*3[Kտk~NEClCӿ+Y\\ӯc)estDES!4_sv*.*s^.H!aʔ)AoV澮pF+njӽfW&H{{}t8 &+3>)qsv~gZ5#QZـVCCeTi~k.zKEߝzcw(z՟^?'*ۛ{EÅRL8kE "۹sV٫.1rzҹH&c֮53g*]K8 liV1[(wy+EUUfot&{~W?VqEwaM/`H[y `}T꽉F薙Y z@D @t:c=f.%UyVV:ic Ozlf[.Ys7+ U uUTVcU'%=dZ^n΄x#Z>yޕWXx`ɐqD{k~ȗ?*ڟ*B) BTyA1/lL\15q1Uk3ֽ*[We WsW>w̢?I0oZ_ ; '|.sϓRnoZ˟o߱)NH=ձD{ Afg\.cҘk)|W2fJWi6j:[cPՐS1v|gHK'TѼ%cޛX*i=VB3{2'Md5&.zsmw^&H!|quI&W6sX~(59g{-jSeBNEW=0joX s'ycVHunX0詼 #NhOE?]n(%~fQ^^ I)/15_l[]p8uj%%mW| iK%Ցoj[]ᣈ5D[˳1E.`~eo𺍷F Tcfu܌ڶdp7{G}ҥ󼆏R[s0| NWBbT0( N+}@M/0$T֭[5`OV6N}v~#Qq .H$=5,W/=ӶԾM}vءnݺY]NXHNezKWt"mkN6hXjI[$EI/~/kwlQ22디`^p̂MŁZ1 *Ӝ9s4i$GϘWzQF#uVڵ5 %,iylr:v#BVddw˝@)kU1 ^|77>1*iʔ).%$w:O@lP8Xpm[)T(:z%maX$,#)??_C QRR T/wP]џ( ",cUzRSCNM җTr  JL}8$mPF}뻧EXjĈZlGFriEϟ1jY[VqސD`}@Zpn_ž-S[ z_GG ITdhܸG7g%|@p ,p8o7Pvi=EIvC]w2G:z꩹CF-}}^V`=xrtk߾}V7ܿF7?4%ݣVE*hYi@{N))).%8g2wk\=\io==(Ԧ/?x@pa:?ԸqԷo_ Ҙ1j,V4"nAYT, A$-ZJ̣J[ȾywٳTjJ(> zgռys }$͛'͜)+D(@]:zTz)*jE6nWg(?I6jɓ]wI]'ou5!Ќҏ?J6I yA*X}HKJ:.9UBvvΝC*66Vv]+Wݻ5d9jر:vX+k8N%'UԶԾ%'ϕΜ&NTUWoycǎiS.]yf:tH}UӦMct'_|;v(2 t9N5RSr͓N˖mЦM#~k_kCk_#2lV u-Jhݺ9-Z(==]=z… >Lmڴ$C /YRr #wiݵv\dd͞.JR-*^ËÇ$__|fVҶfN5D[jD 5ѣGս{2]uUO- 'NhԨQ1cեcbT8!ZzM_ xݦMyy YBCjÇ%IZ*\Vtq)y衇{RBԬY):r[IFgSQz\Oi6)Vl'rJm(**U D@jXNN$)::s/ކX#==]˗/O!MmxJZlN8Q.RSS%,á3gjׯ>9Ns7nkĉ馛ku)!iĈZlC ^t~MSpn WJu۷Oڵ$eddhԩU^= >\)))j޼}N9 ֔_]sO=SnR\}$,mۘ ^>z@*i߾}~mur5m[ٳTjb]<~?}#Fk3)zJM]z:yAIsԨQ+EGVbbo&@$KG4>@a) kGf^-'H_"|H*8X Ps @@9uꔲԲeKK ?"#VWR9W.]cu)ᥠ@zipt|@HꫯzH 4xe+1z@ c^o^.'H~tnu5 FK/i[]NxyU믥^@@H5m4z8p儗C!a֬Y:}/^lu)atݻ=SPr\9NK):oϞ=zg4|nr†T7˺Oכ?ѲeԫHB+:/;C{RʬY):?iՌr QF͞@H߿"#YW#Nj5zlwտ6.nB@0kߜNz&]ͺQIҦ2f+ ۬Y)Ș*cjv+%h~eKl oii[r VRixn_>Tv_1ˋdT-!?I2d%Z`u@sKK6MQQ:OuI"#PRm۶FNoԡC}VFɚ3[Cd>ԇOMM.edLOZ]"!j8qt{rRZur%s(5uE"jv]fR\\"#'+Nf|BhCjtSlk(cl6%u7l6Fiua=##c|E(**Ce̚22;UO_5vvz%&B@]E@RaǬY)JKۢzXW*5׏J4DMgo>*@ezi$F(Mq:?I% KEDtVRGڶ*@R.אdK2J֟޽VҵEϹԶ -]54z@JK"kOzr=봹һv} h\.r-JKKbQ^^ vMWbnto)}]ѼiT A_իcu)af)*pȕ۹:1:BA?HIIۙO?ט1ct[]N1 S+B^>U& о}hy@@_JIIpt%$,ݾNӽZUJHX []" D@XnӦMEγp8m%%mwWhM \jTNNn]{;.'9-]:Oڳ]x}mnuID`GyD}z-tZn~iٞ{J!XsZh.K$!zՕB= ,umY]M3Fb)d@-˜1gaRS#G ,0t:5kVҶ(77Z'OTO8^xn.lWZA0t:իHedL5M͒W{]~Pwy\Z6d]@`YRIOJ*i:&zU)=I"-riT~]9j(Ir(5ueuB@̜9SiiiV1ˋdd$>֪~ Myy KLR&@͛裏￷eaTxVckll6Kj.ZwiM0A}.'[v?V]QϪһvg 3 IDATz%& |*Xj݂ o>۹a kӦ0ri:g_h #}h5 MԪ>L?fΜ {C۶QRv]wW+qZAJJZCZ;C 9s堈ҥϿQ4q{x20P j͢EkW5g޽K/$ ִkNWnݬ.%,9N%'UԶԾ%'ϕ}W0PPknvK[NSz,/v't麠(""R_׳vZ.GJ` ; |N]U^b .>rE`f;HDD|~]DK2?}`c(40!,‡XN|b?!!!lذDJd>inv s9?rQ$'B_=\q>ZnmQ5"R9231އp7y~!}%dڴEW+""RzA.CDj8#Q@t4+|Kq" ;Frr"Ӧ-pX]He%<<Kx58&MHOJz:p.""UƀT(ի_ϦM.IDj p|!""UH%SC !==K_5\Ö-[.O믿αcǬ.C΁$5u q?ncR<_HR x뭷;ׯ?0:|o6vK,9KNdd$T.9dH !aBTi ArE1`>#1V#\vv6FbС1r,M4 IK|Ok>7nwYYy.QDD$ B-Zp)=JdddƏO |1B ENb4jԈyi@5l:<Ә$.AzE .d…>>lQ55HԫW0sLt8q"_|֭aÆV#gU{鵇 +B3`T_o޼]ZTQ͠[*m۲e ˖-o߾T$7_d֬Y\yV#gtrSǽ M2U*K= `ᄇӽ{w5k֭[?><5j#G9Kc? I/s'""R}iH p) bѢEԫW꒤=Ț58yߓK$v <jK= "5Y~=- / EhAyWs"R͙3ٳgK/hu9Rܺo$'nZ'""՞H5ĉ{.E*Ú5u+<‡ "nuRYKgO+ ""Uپۻ¼y!4]D q:N!>7/lL#NDDD*Ht:IHLFF1~Ys!!aB ""z$uI8s۝DVx{9K)7jweV!̻lD(.&07I뺸I,]bEDD*H53p@ӭ.E*ؤIʚظ7inמ6\1U*""R1@DM61h ԩS.G*زe ‡ 8 ygy^{Žj-@D~n:[ofuIRAN'Mf׮D4?vJ{Nu@DD xw_%Iȿ3Bab@>暂 vJڵɴi+ZDDD o&77UVѴiSK tfG+q=g:}8WE8 &Mw}L||H1oã{Z7Ws%3nZIDD$xlufCCDDj+݂%RAwѣG.EcGa@jDDD, rM7q)K֭.I?g˩D>Cgݺu dg3 pEV#""b9r_BRRW]u}V$U$5u Y>}.7bp:V&""b9svy=z4Fb4h겤 p:$$ &##ُ||cHH"""9xG>}:3f`لj84i:YY{<9Wv'5{EDD,"rRRRXlǏZcٲu}t.kj$.]gq"""׶" / / b1\'` ϓfza*""z@DD*f#,4 hd, ""R)T7fc/pS<+S4]DDj-~K!S8^8 U8!##A3bH"ŋgŊV"ɸqOઍp?p#ʦDDVSr1ƌàAիV$ŢEDiCzT4iww͈%""f)#FcΝѣ5XXJT81c #Gbϙ4#N Rcxy衇h۶-7n}V%UdҤ,['k'vw+ $22usȯ1KDDj%FɛoIjj*< ճ$N' ʚ==\G2/2N8' F~ xر$'j"""Uz_~V"UܤI G0 dCW3 Hf3ss6ݾvf2m" ޅ@1b%H5l:D3h@_?pA&\#99ip8XHՠ""RA+9xyQQZODDYl6aaGý.vq/l.""R:_JVݻH5=ӕU4lXу?W*<#X|l.""KDj72vX0yd)ߙ`vIJvL`0p3bٳ"5ΡC4isΥSN|Z\w+" K Ljf(IVMXxsєc\ 6CDj<^yyN:ŬY;v,KytoL-҆m$t.xMLL_vXV7 L-31Ջ?ng}͛[]T33]A2>,翅Q,p(|"5fOݺub#=U~1=XMG W"""gnu"e Rt:޴hq IM,y'bAeLdobj+qd?+UF*֬Lffiif`n-1 xr&4ÕHD̙cuRMd=ʆ۝DVx{칀u8l1 xAUQ™|> SbM'XP)j\Vk֬oK/eŊSH۰W\i9v%67Prg #<(6[]"#[8'`aq{ D7lPpqHb%o01?5رjTפd\ckQrW]V +ˋ"78aedg&##߻\u4C¨_+O\\:u˕ݛ'rnSzp%5c&^T% 91/'2a˩VGw,$<pT+J9eU;vFҥ *zՑw-ʳEE0T11DT$Vr(Vt ?}&'O!5ug嗗f6r%>W"""RFFM6lڴcG1M6-[^kBCXfmWNs=ӡ ȑ#q~ӡ n_Q+L}.mfBBB̍7h^u[4 WZtp9|I.'&&u>ƍlzdˌ7˫΢?n_wܸ>~Iu؄]\3gO}[m^c|y^w{_^HVR{MFVŧ%~?jǀaڴE@LYE4-6<{|BLLO24_́hذaży/{pf̃G~7k9{v]2sdddM=iif` nww`#EU1;\5cHc /q>|zE= q8r]6MST(x }%ٖ)Ƙ{7<~ IٳgY`y}|3_@{˻/>ů^7&y>|p簤ϗkҫ:9rIMbZΫw/pDXXuL6o2%BL>z!!ߣr.=:""R@*ɓ'?l.njz][_JkH7-=6naDE0Q*rJ}gv`S6=ޙ6&,0R6[rrrg3[Pzn/mӹsrÇ)&.8DG3qq͸qMtt?6MlLC3'M#Q"עrooE@*ɭjԩcy3|h̺u>lJeiH W.-  \iBC-{ظ,kp(-T=.%#țA IDAT7G L1@ ԤN1999~ϳͶԭ{3?_.x^wA1P#{.6|m1 f&.w]x^Wk)/*䚋H͢R~ `f3fn;qiݺILL sUq{5Xe&aJM+Р],7%=.ƻʻvgOh{<̒BiџXpoZөS{}as>A]{nf*1[ia _2s\';+""՟H)TzȄf~@GG_YA1:5Ѵk׫齽mZFn/}fK:3_Qk::~s(XyHiJ_ҦM"##}_uUd9>=Hv3W@bi}dڴ@!6,q`p> cٴ);{5s`5 ?>SK[bٲjEc }YcE^"p8df."%e=qq?l9s=3@Yy"ޗ3F ȑ_k)cM[gz#G 1ܹNNn.|^NݒK7B>pyб#GO~8|rv"%e=g Ys|> .O㈈H4`޽DGG1={rO#cϑ>E<,[O',ɉ>S=?хQ7Fo.bu|]y#obڙ|r8->mwgcCCsq"<L+A:o(VteSC~4i:˖ɺMݺ ֮ȷNĘ/KɘOp8HOJz Ԣ-x Aϐ6mQElũu}q:y#v>t0NM~C~ Azz:<Ǟ^PS}~1_DxΣ i6ڰX~Ž{ `xs<} /oa֬)ŮM)x~q @YDD:PǏnݺŶ׫WmpwgOfΝ\{~Jm62yL22&/^ xNaUi{+grEv "꫕7ۘ4rsXgd߰t駔RŽI7>n/9ӳ8]Zb"0$ν H%T To#5)fر}gͻ|C0ۻAk>dc Щo|n]:8i}Ql㷙w4?!'ر4n e !v;;vbώs]~y\.~!z? +xiy{q;:g/b^#~0lMMBFF0}))IO귮WDD pBmĂ5^Y4 l2yI=[S'Ԩe {S޽ۤN1Eg*iU~g5N}(}3U>Kϳ,_%/XTOk}[hSu@{m'O4_|޽{ t7!!WKV߰*y146u-SȺM٦{-4%OeY/Т5^ K:7w*usY$P,K.Y,y7}N9&4~9>nb-(in.""R~ dذaN:63ݻw7u1~i ̙5"J^]omM}\o$ݞXB =𢆗\s#&${ze@A_M/@Ell ]ϤשNo#gŻGlw>EYχHEQ)?JrI .ڬ^ނ,zsoԋ\[@uxn׀>@)ޛ0 hRS'9(eYɾʳ:*}oF㗶,-ܸ+d!sR~ZԩSgy;N޽ ,gLZke:1gk$XwM@i:0)a- $6g<6_3z#,l6Ej)XLHOQ9.m?S6ݾ]=Zw{}lr} /-pL"$SUyχXCJ2PT~ (jvXͮ]Kرc5Sq8EJ(8|Wh$9ЃDbc{ӹsdA㻤33" 2S.${+D fܸX[{oo -!* N?ԐN=ѠA~W/}i:y^/:ڷEZڃe:>PƎT!+HTom6o ;8"=+7p ?Oަ] Qh0 $3))aÿ3iOPq~hh'RR6p8 36=t0QW LfN{sǖ-Oo0yz< Ź\'˷'pem=Ty.uwIQ2,;ʢ"SMt^c$J@Ҧe=n0gE{\Jj*^e=~EO-|*|ƀH@lϛ3ڰFUŒf^*LFmk<`N.^ u*r+k[!""R~6c4Bؼy3]v[:Mݺ'HNNdڴo1J碢SǞcu\#) >?|D+U6%-\bE[W=z?`l|]K}+:y+JeO{mӦMtr%*ڻ1UV謁DyU||o pQt{o\ AjJjSDD ̻AWw3KWzzqO$#cUA93^=}~]?"""R94 T9U1[Ҕ^6!t7Hu"GIS~ l[.ʹL+"""R,J-,3sQ>cVy<<.zjQQQAD VR8,""""5n)@!CCDDD8                                                                      J+`ۋ~LT6z8 6 *@= ())#GԩS겤 Yp%Hz.޵H)T\neHa.޵w-Rv u]GTT 0۷[]4DDDp]wѳgOشi=l޼KH)1:uL֭[C2tӇk4fϞ])Tu Xv-={,u?FVVmڴxbb"W_}5|Ac?~s+VÇyfː ]tk]N)K._.Ӿ%>ޢE mln'5@׮].AH׻v]tkl.ZcEW^y%{88U#<<<ՉHi?Nvv6}γjI8pޣ_~<̘1âDDDDDR ڴi_W\A شi , && 6дiSKH%DDDDVSJ"""""4 USxG!""nݺ^T_7n$%%K/Hbcc>|8եIaԩեH%ڼy34i҄ӱcG^|E˒J}vnVZhAi׮O=և=ʔ)SiҤ v~oIJJpФI8䊫݂U1wyӺuk^~e6lownuyRg}СCԩ?3/_[]Tڶmn'..V$'99.]0|p"##pO<@wcǎ4jԈ1cиqc233Y` `V(觟~">>XZjſo,Xw_NN]v5tˆ  r{f33f(v ӺukhaeR233ߛzoݢ$nzm:ӱcGˑJpӼys3dK HKK3vdeel~gv_-LԩSf߾}c6nhl6yWw}ݻwnf3ZՑnoMhh(G.Vn]n233ɱ:hݺu+H֭СC*[v-fͲD:'-- cǎatAt:h֬͛c۩SeI +v]ywׯ111zE6mx뭷*jOb_~%mڴ!22gUW]U|j5&55ѣGӡCˑJŮ]K$**crI˓ vua=[laॗ^'<<ٳsW{쪫/Cb{%::h1ٳǂ$^{5rrr[.E*9sعs'O=եH%q\ 0owyロ^zV'o߾}I%ۻw/@6ܡCp\.?~u^^ǥoIII!116:Ĕ)SE]dqRk2d7f夥ѼysƎkuyR.5Ӿ}iԨ?lV$lҤI4i҄K {]7sȑ̝;L7{a߂r-#0b5jdqRY?sl6]vEIe9y$c,_mZ]T1O||ͼy :u_~nݺL&՟fذa_~p3y.R/^ŋYdIOeɒ%}V)hذac_}quYST6m_}vovN:YTyw}tٶmÆ O+WÇgɒ%<+oܸ5k֐huyRxy:thZPSϞ=9xVBFł :t(^{-}-GUW 'ЫW/7nLJJ M4aٲeZѣGK/Y]CFF+999K 4/TwK.4hРp%ӧӲeK6lؠ[JR:u^{_~N:1m4zmuiRzڵk>;_j={r!lbu)R xY`{!66ƍguiR 6nԩS/8x y߀۵k׮n u$ )8cojǎя~$۶~Z|o $ )4iRҷTZZo|9 u7ԩSݷXR]ZZFŋzjÀKx{7C6$-Z . ݻw+зm-X@%%%qYvUZZӧIZ[7j*uv)x%0{O]݊\C|ruu-V}J/H@`yO~"˚:*W{#B*X=Ͷmc;їOhٶ-63 QXޓ|>|.H@$^37K5,{ݒ{ؠʳRzlܹ<Ā$͖tvzKd:Tqe2ͧ$(D^/[^tuJ1Ds&uwΝZ*  Op{$I$iBttqzFVOu4n6IH#iT]-ܹo[FEj~(˧P(@>-~g%55lXoKv?lѨcKVٶddGqqizLXox}rضaǮYF۷/'>چKdާRO<?O>vqsR>>[:זl)qL2GG@<{>,.,tFt}ٵ vqdr][ېgK t Q@؎kl!X*iR} "鼸dZDT0:n/[J^L # T\Ì3y,ӇRjY"m&z ZZc&vؔW?>>l}QГ HYvAMeiYi˖$ʌξ'>L+킂.5H Mt^xg:gOmWٶvM O2R^ƾ2GG@Гn AMͲMuiQ.&M~"k>Krz ;ҳ*Zs&u&}ݻ׮Yf'XhItew]=teRx-s$ y4 =!HxiW^Bd^Oju0ɼx'K4TD'AqdV9fr58v_rW۔L2GG@4N6gﳵPAlsJ5H6Q sJRKTg*,ˊL:'}H~&u>~3fVL|][,Ic'QZH@h2Yjmm]Zq#T!d/"2X`mdv/J>-GB/߁('JRIrv1+䏭!XڹdY_8MT7ޭ/~|o}1w]3jCdjpNŶĴ%둝x-s$ y4k3#}k@`}QͶI S/ l:)1I~E}% 9v 0#5$g C@N>_d!v֩hVBp lEG=,"=^gRq{#%6itɿ"vk##|]|'L8ٍI">&L'0;NߋxwWG߿ﱜΏ7qC) HNf*#NIf6eʗ쫮OͲGP$`;'h>߯SN3[q)쎕\? )#I@)~89N`x-sEayY"&.ڭRgg[ں=/ ib}rnXU./IJT/zdz7`plێ9?s03ں1h;pq=~4}t|߂u mPk-.WTRU*Wu3 *-[}y.%%{LE9j55I}qWHZsַ>=iY֍}oRR+ :`۶D٧;F_]E7@tu-V}~ 'Is{E~$*W{UT̔alT{6$|LTmm~{Ǣ%&} m;-ҳ8}IoޯDwwZfH@ +Q HJhk#EHBƃw#St1| t)^7-a31p<0YcO~#潟vV*R2f &`9x-S$ yܕx„[FVMUh&w޽v8; [}NjDfcv!O3PHv+T%p^TۍMD3Y-$vK sya)=p@g:/EJ}V!_}wʅd T`grttc$f2Ymirğk"#$ x3 RYґ4h"flY:3Ppݻ7+Ƿ>g "M^^x#d!#$ R]O2IM2KPcJTxWG%wެ/kz7T^tfs\j@r$﷗-[f&L}>,6es]YYicƌO:$|X*b%BNϫA׿Q`r Y\oIx~[q'a@RmH#MBttYVV2ܹIs&Jij$X]-al6NԯoIeOiʔQʧ3~mc{Ċ#Ku?O΀>~뭷l۶?qg@>#}o&0 7#vAvM )MgH6wwJMjzEլ@:Q*pc׭\Iul!2S%GN80^3 )4iҀ93]~ȶmuuu*<$I$iBz3nv³ՒS08ZtXKUZJ>*SYtfuLTߗlēij[oձkLߗ}ڷo;\pE2͏tIcgx_bg5uL}_98)ޖx-C$ iJ6yl0+bc@겹e)_KKI) vd;չlTx_%|6ee}-sx-S$ iJ&y#GϷCЀnj$ _슊?6!#՝ K6ppo7uꜞKlu.gJWr-M٘m튊 {Ԩ#mH@24»ꓡm۶mWO?]> #zիWk9mIq4zn-i^kҫ7ɩm|kua ڲ-H%\n~ZZb\>)r_U G_3ԔY{ ߨ-ڹVE1cw0$$kঊjm # _{]ϥ%n `@WW?|wqȑ# ZgQߐeL]ݭq꣏~O]INOCI*;#Նsb3%m{8Iv' Sww$]v$iܹztG?}B`t;ںQ7W Y-8MsޡJg)aIO˲nmUw>xVfNF.^ڼJ]]vTh06 <۲^H<T4!I_P} l[gG楑q۱clqxK.D_۷kƌzgY`بmPkk2ޖpRo8f)}K҅ 5H|ʶ'U=|R ?;7)).>W;vȜi=-}W%%|)8K'5_defSeرcۄB!"!QMFNg9~]f$cJϷZyss::.@$X{Dyd6w?k--C5H$yg;{}J_iTȝ)׸q}}$4yršNk2);x*:{w**K/-Q}ʸ/ ͒Dn˝>kb%wu-v] GNExg,cr΍FRggx㮔(|vؔVum=g]`9f@JvF!Z2g9#23qBlՔ!x.9+;cȞlՔ!d Γ=99:c0Ğgۡ;PqG}}nC[`$ A,)iLܹIs&'dۖIי|ҩ) :N8jI;[slӎع R)k"?N@ט1ߏfIGpqI\ |3 cVc1hSП4ñawv.i\ΠC+MI4ے+<" 7b NX+NM4*G+&s\jKGSl y7 $%^^5n8)Ma: Q$ W|>$9%!ຊ2 q3 <na,kLT] [ YVHW06t<+$ Wzwnш ?VS[PFpEֻt =QKKw\A ޵yl   zA9Djhhмy4qD{7m_z%+hĉ⋵g#zwczٳG˗/K/iӦ9g[t5G՜9s5*-]%Xޙ[gݫ vJ17|S&Mҳ>N;-횛uA=*,,$vi:sӟT_~a@^lS}JR08Z~ֻ0kҤI(s9GҨpa:50+^u޽[zjN?t=sD',{7$I'Owɓ;( H@#GDm,5j$?w|sx+|vUWWX?5~x.=cןtI>7M۷zG/Gϣpy_#ɲҫRho&L ߟ/[p.\@/?AW^yס@֬Y5k\{m۩--lӟT_|quGu/|ʔ)***ҦMs1c}YM>=g[͛QF顇: k$#eoE^x,RAAaKRڪ{Prޮ]vIjkktWf͚E4MXBroy=+ bhŊzW%_v֮]+I袋z'd?a?_+V@_$ )ڱcGR+--s 7˲dW3Ǐu<  g۽g$ 2MS *)*)uh 3iJ]]KdY|lnUlS 8JL]݊\C|ruu-V}J/xuZ-qocYjofX<,@Vآ`pFد={,|S08Zms `!d̩C: [~fXȘSORmUVR|AȘs~IeUZZMMW# ? ۶ QeV֘1O(-}UVTS[pDȈ@ޒN|WEřjjZƍ*T@`  c3e{eJT&io(Z[t_: s$ 57/Ui*zIJZ"\RHRh> d,MTPHAp/GȊ@ nkGZ !6 O$ -H$M`#dUlAf@V|UsTX8_sT]M4FmPmG PKKZZb/@LTmmJJfhJJf!  3 *uu-e5*֍ڼVnEOQ޾t<$FHKGYܸYV֭{Jo>#3@lV08F3} ~BG} H@)/[#F$?5^*zhI,Ģ %in::(#**fj7v-@,@7ZLA˲$b1/HZ*C$`bH@۷Gw?VxA%X$|plۖȑ#/~3 $|? )Ap q3 < Kln2dY!I_Qd,ؠjjj8R@#$VHE#F*,?[MM[Pֻt =QKKwj@ %z׶l @H@ض}nݻuwhϞ= 0 мc1b Lލ8o+F_tG:| AShݪu?aYּ~Kn( ^$ 8ew#~SmI@ r?`T׿"3FZ|f}wuxO PKKZZt9"Ɂx@W\q^~eMPQYYgz//K… pœ 񘦩آ`pi-f͚5ZfMe{($z-M0`P'ի5}0MSeeU=~ںQ7W%l@CE۷o׌3 7$` |_^r6oެ\ X觢b cc c*+o|IfI1H@K"t c3!d0֫txPHdzØimPIl-PIl6H:;T]MsTX8_sT]--x-bj@`JGKKZZ / SH# 1\`  R.`^$#SN9EW^ye M$ 0LeG"sn֌zH@`FRET ȸ c@ ^z}*!@N~0y7x:+^"PH  B*((: @!eY$ ~H@9,@<20fvΎ,@<$ 0̘VQVmmL 4MUk,QO֍ڼJm Yy,`ȬGaLOdY 'ekWf1:fxȬGkkLsβ޾%k}NӦMC  quu+z\͕4F3} ia:$ 0utlI>|HrJ0l9%(d0۶ Fz̔1m c*+r+40.X0|>Yz)DeTZZMMm !b #2&i9*8M۲/N!y6oRWݳn@R cLY[Kp 3 0uvz稰p稺zn}(gǺuaÆ0x1@ PKKZZ…ntڪ?\9,  3nm dbȉP(@NXE,/ 'CÀmۮ?&3 xe!4M6ddjkd+Gw}@`2MSeeUZ"jdu6oRgg[λoܸ1 ǸTW'(W8$,\]]U_  A[dYs^gYjorDbjji׮˧`p'PCDlӒlOBl9%(3 9}vUVVjĉ3fN>dq^`))~alPeY@3 9㏫RӧOײe4vXokuhpGcϿJRx$Rn06t<0ܑiKTQQ_^`m[. HjR*IUPCjj8a Vw}ڽ{%I>Şr?GD@RM֪hZZnt- t=X$~hܸqڵkLcjܸqw? Q3eNu]غuvc HU05o<=Ct]wK/:<CTsRaWL-XSqB!G H߿_w^Z`}nI=P٦jo_`pUY9ӓ˲H@Q$I_c.}$@@--ji {# 0h"Ɂc9F/:ꨘ'M$Izw?~|e .… (!F,0حYFk֬l޽E3t3_Zg?{_]O~2W^ӧ4F5`޾}f̘QDCs9pʶmg?O5k,o 3 90m4]z饺{ /~Qo֦믿^G}!@]uU:SgH@rֱ{G?=Xvm:4pEd@HAAnp ^`z+\LTmmJJfhJJfAiz0i*+RWYV$$[ys:;o@@"̀ VW'(W8$,\]]U_-qroq9"#Aʶmc;їOhٶfX$D@Sa?ɮXe7|c  b3e^gTYyݻW'O֣>  bKUZJ^3! cJKWjO B$g_:;T]MsTX8_sT]-x# HAA'_A.Q-- ݲ,I$ !$%Xg2%X'$ c   XpB: Ohԩ^3$ 5j/x 175$ \C5$ \C5$ \CȺn~zwgH@YM-z ϐ. I @,~YI@ <oH@YgY$@$ c  cùm^ЏQG#Fx ϐ djkTR2[EE TR2[ 2M$Iӛo'z pj 4UVV%FI>IZ[7j*uv)x%1Dd֣pErIɲյX+ H@`z4'I:/,\[  PWg\Ic;їO,L@"AcKOt@Sa? )A[$ lV0=1SƸ5 <˭H`@|#>IK%U;Rn06tڼ 0@ELFd# M6Is$U pk׮լYAy6oRWݳn@R cLY[G믿~0y:;T]MsTX8_sT]M[>Wɇ$B!x 1D PKKZZ…ӕeY$ A()<bu,8!dKNH@\,04uTC0HضS,~\ݭ;vסsiA%%UT@%%U[ 4-%z.r!vrW_2}z@2MSeeUZ"jTykFm\7M1w\͝;0y{'Cn:ynEOQp!I>YV~$ 9dYjkk:@"ˊ?k`YZ)# H@r;ԫ˗{ |R󟥽{FN>Y:Ug$@\k֬њ5kb.ۻwG >{0wSO|(<I"hɇm@z9Ӥk**³ѷݽ[GKя U\zse|,B'NTeeeW^-ϧ **fucO H_m5Ag^ҷ%m$͜^vuLao')St'`0!%#˭5?t;^cJkJK{ `"uv9ڂWIO>'guw}oc JԀ@l[ 7ۥQ4YUEOφ$f@cq)\lg"Ԅ+^yh 矗韼?/ K y` |KSH+wE ne 77$tȑ^GgK? =̡{ _@>ٶMiٲ卆i4Hjii}q`|DAK3:H7,I B22؆ō7J;wJ='d{>d HUB 8= K^G믗?^2H@H@kn8J^u492ܳguo XںUnü&3g!UW7ăH@Ko.8C:`ڲHyt5Yox_~YڴhyS}~Lu4YUҬYRu H$ PHN;Mַ&|>Uû{ЃH?/KCuN- yu!y:ߖ>yɭziԨ Ac?:;pTھhy?Kw8(qW/Y"ٶ\.D i:xK?,57KѸ:H@ |O.-\u49wyp i; H@ {T}qڢ -"\dNP2x&cJUDpJUΟNA2o :7@4J|i6-9!}?}!$v"<^Yf ;˗ջ{`^{oA_CBvGc MBBB3,GDDbh{ غ|tjP'xҢؓOW_YN H43{/];6v.!-mYYq\vGqngfC0qAHLP""MvInn_n]N~?ٺu9}wd%!!`ԯfoÊ&""S""-?> 'r˛3p<3[:a;#S|F}<))SiS8%KV 4g08t =}/d]`""b;% ""Ѱa"}7qcS6QFq0CVVݺupDQk)4c tkpt`pJP/[xa޼&""1A H-] -8˂>|, 0t ]OvG#""P""I0iС'ҥη) 18oӥ\fμ͖pcv{{J@DD"o<k)U)))Y̵m$3s-k,$%%Ơmֲ%L =[DYča4jݻ 'ǻP;^|DĄ ގS*HH̞|7r~~AA=~шH)NʂoQ]$TDD$̴iРyg)Sfwk~vٹs'51![9DD$.)דInHNNC3oD$|ӫg4'k\vIVt|aIQQXh^`7=?%ܟ/IHH $6m\u4nDDn} H>:uD׮]˳)*ߴ_ d6sxQ%X )s:P{< `Lطu2""u ޽N:0D|Ӯ{n)\f#w)w|yXS|RS|vL`""X^ ??+PDӮ&`S}\j|#eF X F؃uq<)X>w %""1C 6mDff&\s5v#"dj) `9uxHrrfmд)L æMLDDb(۽{7CiӦqT.0PT^՜LS =ӫԯ N[Nz3x$n],nv;- E <VZEV߭ '++F"R ${|]b}ya}~)"RM ,`8`S4a1U?Mj/>+VpgWƍݻ76lW^D)"55kF<\&>pə#|XびφDX+DD&^ `EaѬ]^{Zɇľ왷Tl5qSVNMaa!iih5s\p:alX^yhDD$L&L`ɒ%dddw^^|ŀǯj"p\ICxjrX̟}J.cʑq]2jN("rS_|%Kdɒ +9ĉ0hEs8JWeeM' 3<ԩ3îC.pF""r\(xp!D8[ܹk|k; fVE`$x!;ZR""R]{%at xȿ<3ŰE3ܘm6rrr(((]~pXtCDDF E߾#֭bnÛw$.>eN۔~ޥ:ߦM[׬Goy""5J@DDL2 x<9\Pneԇ+쓒š5 \Kj@ڶAj@23bNgt7w]#"" % ""~|Ng0W *hBN lYoerrrfԹw{/}(% ""%+Zd*9--[X""RkJ@DD|~wͱc9k|*ZRiժֽI'y+c뼈HL𷃈H 36ޜ94iBNwa|̈#1bo / W^iHiDD-'&MJ7+8 _gшHJ@DN ZBwn*:$rrs&{Hs\deM'-m]BZrSn[MIU-[z^hDD$rw$yyxf+Gie4|uk6G+1z4w_?oR"""1C# "צL]| ƛ|8xs諫[w# S"7TKD$(dj<sYߛpWd]|ڱc֭; ƍᥗ/aHΞH.sp:<<ßh>t)]1smvwn7Ng z fφhDD !"u]&aJIIa͚dfeJ578%z'HK< vh2afӔ*m!)))䌾{]Rvt)\O%lݺܾ}/Q7ou#a#ԈP1Ԃ몚Y(?FZq\PM~_M@{I .`$p.а8 ػ[rsύQX4tPOnws:ӰN; HDP",aS&wj$wӯts`O x^=HƍaHL;":A HC&8 Nt2M1G2CyU{$$,|C9@86CݣHmyϙ#{J@ִ7Em!Bԁm;ԁdfv[*_#N5/7Zz #iF4RZ` 035tR<$pꩰl|-!""Q> R#.)SfdjtΞ> 1(;{"+W$/M!280,;DoԼO<>/C'߅LbG%Ю@},PyE.A`0ԬƍJD$.i8 wXcTh?kz!+ω,g 8,e.r}FCJGb}I">?MD$:Č 6lذcLAA?~IMȴmaRS/2O3#%7B?~qIy<Zԋ42r9~Ǥ4]/6N[<8o]/.ϓ84ibL>шH)&5+ q\-vx0a]Gq+zmc  aGgTwtxE5g޽vQ{}»7@z:lbwD"" HgO3N!G[SYb)0p~;a;uew}ECDmǘY \e9<&5jUsSp?}FژiҘO?; F@bT4+/:> #W)^r0%#=sQ5,?<~︚b*<3D Ϋxp:K'б#\pą8 L4Gfm)w!Yq lz.KCBMي`Is-= v\L-|~O|zHdn#2Z+!#F DDk*gMϊqLF}P)uw?b۶rsrHͧQ㙁;mW+_ ]bj;ҔXq_F?wPTԈdd3s'Uа!wmmyd-Xݑ4bg` `K|w׽zS$j$2AÇ5ݤ(i(7deM/-Xr"LX)M/5^0))C~_5l %?S۶scf6;DcysGB0C; kO8iDO H Э[]c%11&x,]*booIaqx/Mźş:ߕ':7Dc23gϞ& ðڵWޓr@c֭;"% SC|'4sjE%w/vb(IA+FG|p&}; =5-hY#Mfosl0soopD"1׌{j{yHP>% QRXXh&Mdڴic6lh9|J)K@6[)Cp[=j~tʖqmuyi_ԸLY1Ӯ|ӛ@򽹟IfM̱#5k*=cTq1tW/vG&"$|J@+03'O67&))ɬ^:>`8;zԤ6 KuFiNB՟VrlH`8z~U# :\X.I |~2w\bޡqُӼڸSīE,MU:1f2,0&%ŘqYDO H]83gΜmG5:u2!T_ՔS+Av8O rAi^.rY6#5?έ[Ƥt7))MÂ2A`GOo$%)Tp^suizIDATw>0k8˸q5cngi֠#9X|Fu3cwze/~=76f0crrٸј"J( (M׮]+l_bq:7 _uրT~8c5pdGbCmFʏ63Mhc)8_ ]ѧ$y7I]MѭzWwtn^֭odԨ!̜YyvDVI^mp:!!!"S&px3NuڷO_/Zoߑ%g;&Xrd:^783x<!txt-7L0993W` d[!ӟ_8|:Ġ?S_i>MhhK>-.O2r @N^pI@W}] ҾtҩV&I߿SvyV~ܹ;|p 8.x^5shO lphwo Ьm~Ab7nXᵚ4iB_B >b> .zT8F>$qR1@ׯ5gy?cHxH01@?$QD"8$~ڱfD|Ӗ|qo`_|v/^\{͚5իW|<==oSf@=[S~)$&w2i$;<ur*&!ip  'O5222*}9BYj>`a3f O=TK{gn'{PXXNL,KF~&+?U=cDT.ƟGazew8%DA֭ٹsg?#mڴt.S& 47%)1bv]šhRw oBҨd]$7N_b)hL>wsx/i i~BZYj NRWW8JbQ6iShѢb&=cS%aC<%#I$Y5.z9. $֍UxӬ:v wǝ{(v7{_Vw_W:CÆ9&8Nv qK`8q=<{v8?N'n[vp=ŤQI,9B[fAFv]&$p,!„>{Csܜ | &R6r6 \"~?/wcrrf0swTkxryGC/{~y*d0|x:ʍ.UfAK׿fȑvC[޽~~qw!e>tXQQOqq/*',n/X,Q (*)8bܯx Vvvv`3.`-CK4U=7fi&! 0ak$jӇ" 4))C.>^ii;ՓzW~b#ò8WнEב6Vc~)[jqzr$ZEDD$|J@.VXXhN=TswB;.C_o߯쪪8Uuq[>/u][8~R{ɢa"ݿ/ \l7&p,Ewpt{V^Gb9]DD"N HDѣMz̤IO?m=\S^=jժkDIL\"ۚ޽mmF!G=jV >0/?b8+/s[W(IUjӰ0w{Y3*Hu) (),,4&M2mڴ1 64sY|yO@*cJ.X%/n{eU%XUOH@u{~I'6))MrrOr))MJ}Tv*YuU=U^ы#H) Ӿ'^z̚5|>'|€jj~d{ ;IMH۶#HMHfq:tCFF`Eo Ax6lOJJ k,$3sm>k{W쳋HK@v6)Sf=WGO?}̏?EA3x}&TV M1b%{$W_]_SVt\.W+El c|ea^ޭLp;2G@|S~G3&1zMsw<;58Ŧ拝k3PPP`23 @q(D]{Tw+)SbevmPAF@§B uycwǏ_G6A.U]2B6+o9~ Nt23oQ>Y㏟ݐl6fG!Wg:P#XN; ^Ixtg !ڴQ,&&ǿ"""b3{WVJ߁L)ϙj4e{kkJ[F\»^33k^bEhsjMu+E3ڬ)O H W\jW5 gLQYg1 ^XCW V^m``-x«3^l}9BXm,""u)!Oɨm)VWwKzLnW^ibypV7 U>6ؾ{:X؏+""ߔ/_RV5JII!'g99޹`|$+SUeUOՅwjo?JZO';{")))%ծfXi)?{hn ÇRP5k2u,^_lo?|_)`Ʌ̙rH_)WNbU~& o|^%1?fw kx*;"""[T]L.`:0O?J5U"|/_u=ٴO?rծU PSy?ƍo}DB*fE?1c/ ʊ9sc0EŁkT/bZs-خVy,^^8*[p,A,Ck@§:& x X  !VHvbzՔM*?Lgx!G6q=nM4(1F'"#;{"][0 H'!!70jgx.""r|SRs}[ wQW^ŋ\_qII8"me 03O>Ydˢ0PuoÖ-پ lYNN 4a_HbY9*Wm rsҷȈ$G Hz~+Y5^;ot,βEڥ7ZNv-ɹۖ#x7J㿶g[G- DhĈ_͚5#//φ$VVݢn]>% 9t䤓N;(ܹs)**+;hz1;vZϭ_~~!scƌ .dx"""""% U߿s8ѹs6m.G̟?8r։!`ƍv!][}4uԜc"޽e˖U빗^z))))߾};ԯ_UVq'W/o۰{㸤$JGzz:`ժUtر}˲eHMMaÆD)""""5qnʠAT\DÇ߿?_5>={;$$ ./^رcׯ_cɌ1žDDDDDl$ ضm[:toqD"""""A XFEDDDD2J@bcǘ>,\sMٳ'M6orCѡC֭[Gb}dVk׮5̙3tѣGMNLzzI4YloM ~;+3 0tp$ LV_nw(blt:M^^^t٦$\ǎ3w6~zp8 ϻLƍ͎;Jp[HSlkȸqJկ_cDzfmN"O>tԉ]gSTm~!-G;_|={ x{BM2[. -[loժNzD@RRR5E1l0ڶm[.sf=% 6ܹ3>%޽[T!++qѵkWÑ(ZbM4a~$''ӤInF O"_~ck/رc O>$7|3 6;D;wg: }|g6DuPb֭[W޺uk1ܹӆJ/\qv"QOm6^C(o)**bĈ 2E1vX|IZÓ4h{/˗/痿%۷窫"++ٳgDُ?n߾}YqCclvׯ_a{ Ji&233IOOMcL6f͚D9r7psK.~{SN9(%RSS i֬K.%;;VZq7Dk$K:^(YÆ =zqOwfС4mڔW_}awHaSLydffXW]uO=k֬QG^~e?yһ\r nɓ'sWҴiShk,nݺtϟo[6mI,PPP)((wޡUVv$yfϟOVVlݺGRTT?S"O>9`o1OЫW Sp2228|9YfٓolOp8Ӧ$Z 6l7ofҥviv$Q1,HKKcǎ];j]Hݻ7@ꅾ|-Z<&ݻwv+l/..:$P6mhѢׯغutV% 6)..駟.v1{9PMѣGvZ^{jgu믿믿oQӵkW:toرcS"hc_}$%%ѯ_?{ܹ3}7oK/t:ѣMUFɛopaŊ|7=b:ǀ1cop-vB_~=+W$==$n}Q2225jTǯj+ߟ~Iԟ'}YF\{… ;5g>#."5kFff&͛7gɒ%,[qO!77||I.2~_EJJ ;vW^p gϞMYn`UB H 8vwu/G̜9DXC>l8_Kٷo_|ݡHn>}YvIdv&Q~zf̘g}O?DZZq:5xƶmۂ>eڷo@^^&L`ժUԫWaÆ1{lMsrE^IENDB`lmfit-0.9.7/doc/_images/model_fit4.png0000644000076500000240000011555013066042256020472 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATx{x=I29 P (\9KKv[nO-+=Xnmek-T[,Ds9 $I2I&d1 E=<իrww|>0M$ IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4IC4zWh"+77WW]u]` HW>-Z)SV^^uqKlci]D 0afϞ'xr/~ӧOF)r@I{N:v.r婠@_mwym pB!x㍚?|I}ӟ#۷@e;H`PܹsURRbw9C$FݻwK.^VV&I~ܖ-[t뭷&>=?2$HL:UР*'$I~رc%E4iRVX5k]{x=|ٳGz o$,Yo~=r\qm4iLJaB~?ᅟ{a#$5\e˖'?B̙^xA6lНwީ#F]"` H<裺Due/]`H8Nu]뮻.H "ltRK@^y/ Gl/ᅟ{x \8!H!H!H!H!H!H!H!H!H!H!H!H!H!H!H!H!H!H!H!H!'] N8AAuvv* * iԨQ1cޣD Gjǎ2 Cdf'NVӦM   gGy.0,B!mݺCE]]ٓ`!Ҟiڱc[Zؽ{X ?@ڊ}ɓ=:إE: \y6mڪP(WG&OKv_ܹs2335bĈAV@i#hZn~cǞז-ju yc[ W 6V_{|U!a=ڻ7Hd۱L9O^-]\PHw+?~LC_G<0 Cӵ^ $vt:.^~~~oרFpvUWҥ˕kO#wIRw~<Uo u5Lԉ'o$>O)t~hԩvi+ɓZf-[ {>&g*{UmWt ~3=P~۶C_Ry_0 8p@SLIַi&-ܢkjƍk뮻N{ 0N8nǘ?I7mOĔ)VXr6oU۴E'Gl㎯On ͓^W_}̙~zg^yM:U/2Ex|z箻Bh}LH΀rr":z悸+u@/]7:VI&+L 5zc$I***t7^`$@KKˀ#E3mjdjQÃjl.Y56nӑ#2|Lt^TQ{]Sf]]z{{{tFH3F===P^^y[b -]TK.Mt0d07yPH3x@ZtYU .ܭɺ%|UOZJᬬgB>@Z~֯_wզj$땝C֬YÒ===:r9+'8(CRlp@!Ԯ,CJ͹Ulެ7xSSEEp pl .[kߵi&͝;׆ >|XH$S~?YC,I[ tdUr\0{ $G>n]{*++Ӯ]Pyyy.Ҋi:p@5G(9:˹oxI%J\(IoQ^cᆸ`ܬ5kK_x r-ڹs&NhwyV^ukmSvk|$zg|gueUZ:K^ *-sWMrnIRȑ:>c&72`?#pXI˗kvBCCC|iꩧ5(7Hpz{`*YoDك {M}MoױٳuvvD",4Pw<Owi]sݪ֯\5 tz.=qv?%=B}?e99smXxs U=uvlZLo~}B ?ޫ{o\e6+ 0N8*Q;vn|q_q ֯/|ĶlI/jk>Ӕ7=֦_]vƍ^cܤqmݣ@ p$V@CR ЪUh} tp^zn3 ?쁅NSYYYr:VX=4tCߴQ7ʹݐl b}&m/?8< awݬ{jmQ8B?/Ti}5 Cyyy2enuh^~e:hvoA+SjjgTW5_MտH2 bڴi40 رxJgVBL9O^1۶)Iqǹ\0!M_whfI2ty?i$]zu ׿>O ׏}@TNND3}9h ?3sm}h3IT]=>@_;vбc$y]宭2't&i5i^m !%覛ޣ^W nlDxJj咢%>}Eo2 CW_}?.4lPG5E+- M]z7-9\ZhV^!FeffKzW'pXOtrkBytv5~xƎk8q9]ʥFݢ_*֓)Ӄu @CiV(Ic/DMTUUՠ}휜;Ӯ~[4A4Y)p80h_ 0d+HD#kkub404rAﻸU]=.n>szZU iUWi:q"Ƞ~}H~%I޺:[Ztbs3MS&L>{ =&-bw_|t@boo !;՝FQQJJJRԩSUS%͝JKgA+U:Z81!5P)X!! [+ vԉji&Nҧ?eL)gOz?iUo;>:4M:uJW^yeBHi@@+Wޯ'L9xynihЫ9ggg<5M4IǏ]de)*%Ї~z{{[a  e͜XTC Uc6y\БN0az+,,ȑ#VYf̐!:e]3M>8 V_{|Up@fZKKBPRTF$0ruqIIVRJtd И1cKKKV\NVW+t6,Il~ p,9?]nKW[nm2 ⦎RѣنUwZZ$g#RV~~~k/kӭy/fn ѣmmX'Mi*߱úmGyr  lCfWkٲv%EW=x @MW\Q;w=GD@)4Md^evtq䨠,gozkTgӯ3 ڪ^IҨ;?~u?Dr; qdetw[W'>HYֶ%ԨZ6M6LԨQlaǎUOn^{zC`Ю e@)+@WncNNw?33SvvmXNBe ۰HQ?vRTӤIT~s6W]Ft RT]䫬T8;ۺ*ۯbކuzd9a'>!RZt.5^ye}ө2*;۰G+XT + î %@))@ SV ɓ{ahԨQr8RX6,P*׈._nQ{"N'Lo9gUWs\풘'LP8+˺oFaWyoچuzdݻ%? (ٽ;0 ]r%Ȱ7VVVfYVK.Q <rbQe45zhJ{SCcƌ; >0@)%c.]I9r]mXW]ǕK477Y؊H)R$3Ӻ_RR~ :+z[1MRJw~JJW1NS%%%"s< 0@)%@UfG9Si?$*;mX+ eߞTk \UUY cWyoI\*66*)I ѡP($)߯p8lWy` e4770 y++6VHiŮ6@hjji*ݵKUVZRvڪcǬk ۫6Ie}Cyؿ?~+ r8;4i҃r8Vl%dfj+5=z7:|wZnf\LSʕ+U\\˗] &K]Xhۯb}-_C#F\')oU۬ӱ E"g Ze@d]@:C]V }nMTWWB9n+Xb Kjҥ ³?$ k?ڵKPH]fJ9//z5khʔ).lޮ^9Ut==ө"K2ڵK -PnCO rd >d W^y o$&O_W\_rCi6TBG8gx߳:vy[7S3g.NXH *޷OR4HW@ҝ=%2b"yڳgVzRq:嫪H`Hػރaڦ \$2O7nMfiI+%)RdFmkkS8<H( ~ Ðw>˩Wuy4 4 ð'NTV '%EWAZZZ,HXz+Wa9)#- $li6,IHk@RE";}ah9 ñYNrkDU146 jmmi9}Z٭*qV+S34iVrX+;VhD {J|Is>F{/oߐs@$tPR4;&W{$Sv B@R|h B%-[ve@JKK*_e$S_xh#,@^N_V=c=`0(0TTT4l‡t}H[_/>H@ 3>M2 -[nʕ딙)|a'k !EӴx~!JJJ[*+ $)`p1 >OٚT5Wg!0t饗]Feuu -)VTTds0xX$5X4婯j8/**z X#zonFY'aш  ]=}ZYWTH.)):eff*77WR@B1 ~33.|}4M.⯬TrHz{{mp>OF_oCGiz {(ݪVY)G8#G{Hf)o]|}%);;[nR$^vLD D"jii! e".Zǎ@$B$TkkLTV@t:Uط5WYB#:tB$T{o]LÐ8^l'N!IRWW 0 y6zz>Dy{4H@B555 ؀^PP +K=^W9R!a !tB$L(R{{*k< aZZZ$):X/k@\aX/~ѥh/ivH^ ^zu20k5~e isu@ kթe8.$pXG"^VAhD Atmo>) Js84X#z׫C#:*hZnN¾UeK.ʕEprЈ ]@jgW̗dZQC]zgxOUUEgD"[hD0@jӦDZjUk"=dm3bJA<)I 6Wo0hLT(+ɰMժZ y͵ơjD?^y >`!CҙmBӴS;5O23;i@-j ݆/PoZp͒:jM$9O}򆄬,nI"o. UCߖi$ip<{u]mph(..>,WڪH_S: EOz{\sru#S%ܹf.7 WT 1IR$Qkk˰@֧>uf7R$c$em-+09xPI6s12M3(m_Yi݋m+›pvZnjN#:TUjoBR3?.\FF%Ec'aш`#tfvElilzb+F =*GO$M}M0@GW;QZB+ oMFtG8#G{---6VTՎzk$egg+++ʆKq:mX ]4H$|8wb^qq =@@w߽FNp*l5m~^9sC0d4@@HD'O%__]@ 3ᇯUc6|j{ʕI#:!4VzVtI4+Wޯ={HdŵI:whP(P5{9R\mڴUܸk;5MNEL$`h"$ݻdUTT(77W3g~]$T[W׀+eceCi r[٭+)Vp3+N0@ȑ#joo'?I=Ce-ZGv &WE70 0ruH2㮇ꝪV΀$V@ M-_\SLу>|36U*4Ux옜Ҁ,\8Km9VZ'T]^I H1c08 @ڲij7κG[SSs&MzP3:beå*?-z$K]]] @c<5kg_owY:pv0EEE6W7k Z/;AR콒'NX`a V~zG%IC/\$F )btXДk]kFlٲED}^zj!߯QF].\0HXBu ᰺. ](R{{==*:s+VPaaaܵKjҥ..J]xo}"NZ/̺G^WMMMWThƍjmUwaz{{ѡ I %k֬є)SQ z\v"}C 8 \rշ䩯}+~?H~W4uT*JlJs?n ĉͣM@/,,[I,+Sw~ 0 @ )$>9Syy^uо}*''`fQ8A?}999r\ y߈@BC $>я?y577+??_SNw}3 k2LS#xi@\aWVj/djiiQ$a @I%Khɒ%vI@詯WofF@Ucc|a>ŊD"jkkc#!Jo5N-:p8TPP`su4MϦκGE?S_N ( _Av|Vuxivoh핫]=}L@OP(Uֱcw/f&wuYmv^}u.oM.q$1=Vz@Ǐ-\jʐHd[;%".Cn#GZ oӦDIvjmw8pQ|>t䗿åOkR~~oߠ/~q}Frٙ]_.-߯#F]*+ rQyK\Sc6mrn vܩu뾪>|">5RnDt)xB~_4]CDhϞZ[kLg-nl#o]( U@oYKKjki&+vjZHd6njSu/++Kn[䫬G:s42*-knnV8}'0@$CP/(vҘRG%):igi hvN'L\̤H a*:tȺ; R577z~g8hl*><LTۘ1̴@ Pssq /-RWW>_jd Eqo֤IkzKMkFt3#C-Ʃ`~=ؓ=$,T^^.;ospNYԤlӔsaR8'[WWoEo\.檣Cc9|Ls$CMM֭ۢ_yH[d{t@S޾Dj f5׫7+KmGKn͢`+Sc}wL9O|5@kjj68 2N뵱(;;[Z.IޠY6s/1 *Iթa ^NN233*mXVFR׫{|2 C#F |H9.ijmUncՀN pD+*䭯Λ9 @!.Hss䫨`}$I*yHD agyp4770 y՝β2 쯨+TɓֽXpTA)4tO]]tUwaDtߪTl0 kp$ MuvvG2My䫪(#3MU`HyH,8@*!T]ӧ00Z!WY)ֽVUxSSa7aۺ`xSº:Gzj57O G8,=@ =06C[/>GiK՛)# @oS_*g~Mc=Lkۂefd_Q3HGju:er?Vc6mro+]"$neeeIoDQ04Co~?~fȩ2J2,СC_תU]"VA,wWl* 2MSk2ީ.|mܸ _7aB@hD* Too$C3]5' B9X#zǣRmb !TBPNRS.W ð>?WUeHRKKe@༚U]=^$pl֢E( TNN$yy IĎS;@ܬK~1pg(#G{4HZZZvP.Uily7tmھ}.@ZƎU8#Ú@B"4M*9tH,Ë4Mn}D q2~|d V@Zx2wa*..4"P檪]]]겫4DGlN8oRKFF $I'*ieXنnbuxE23{ǮpJJJUU B`7z@Tww4Ӧ'b+X\NG ܤ?yQp\-Yrjj`pXGVKN?$)//O.ˮpb[]]CTv0C=Sufh 6W `8"m6;µzIIrigBfMSMA7מ=+j `x"$4U:^Bi5Ăbm!m'N]W㞉Diƭ6U`8#$~%2Dx^zY )C3YO rd- 8>@詯Ƞqy())P7]3@1ruX3C Y P[[˗ke]|#:DHUMMM2 CEG('.ux<'qghl0@[~_C=}sz5e޽ >}:oj@%##CKT^~bdkȫfITQ-^}e~֯_3K,UW]o~~fcup~H:׻ZƍS]ЇK/T(]w^p5m8Xq؂3f8ZeeJٳdž~E"I ӧݏ͗P\\l-ҭuKJ4M-u-XIt)Қ$I~r'`-֦^I14ŎNWT(rd^IP[d =4o<FqAb ][t5@"^<߁.Kyyy~\WWya-\ Ƨ>)y<=gã*ӇL&! !BB/P ,YOPWKVtEqa}UdU %"(`PP MJdȐBʴ$纸9>s}]vnI& QN`` J)@F.;; ''|Q+Vb .]hI@ӧOc+ӑZ,X@߾}Bg9&Sm6֬Y×_~˗[L@… дiSƎ3f >>>ƨEEF@)(ypk=>tsQD 4r3 IDAT<@ll,k֬aUe,ݔ6QJt8fAAAzj&L@pp0&LK;v;wV oN\\FcǎY0aAAA,.`0XHh/!~ Bא7 ϳi&ƍGZZ~E !Drrr((( _I(7;x0` ǏsεڞiDFFMtt4O/DՂ|rU#(.c(xB428Ç4M6iӦr%BSp9UGT-9r$G{v~Νyg^Q, 3g`&C8;bPܞ%B84ro\!p7?ϜҺuNM|+[B9-28IшI"/AzIS`ɒ%:ziӦ7ݺᛖOi3"p2I@#77$<#sg,^^{ @XTTĂ :t(Ovu8J ӻv@& B4r޽f$IR##mK2ydGff&}aٲe^)-\ǥ6m:v:-##$ Bшegg3yd-ZzhV[1`~'>{1}Q]VP: !@Z׮ѡ||VVBB42!D#O?ѧOv͌3xO,:ie 'l26l@>}] ;-2f xY!E!hoM7݄?o&Æ #1:vm}R.ͯ*#?ȹs\3 4k (N@˼@"E9y$wy'#F`…o"14aʔy~Fg:ԩ=:c4]v䆹oRul6Є0 '}>4,1=Gt3n +[(1z`ΜࡄE#6-׺8 ql2-[ԩSe_{[k_SD3nbU…Ys]PJtRzJMIIA422KJׇۛIe$;v,^^^Nޱ'ۛyջ>-wqzw0NX`y,Z $ B@˼;,Z'V:R#GjduzfTQjҤI1m4:w̔)S\K(0Q:˷ #)ŒQPRQ'iBǑ&XB|̞=7|SV9hyc(h(e˖UNʲeˈru(.i^^4%X2BӲ%B8$ BQ3uT^xk_GP\ݺY-!zGhQp5VcE  F:m_e5! I@wީSѮ=p2 s̤St1ne6OF$BaO!DǵY,ePe߀4k OOO)܆v-V=s=œ9D0 ]!Lf3-r˖ RXXob"?v$)))]D!Yt]d({)M85M#',`Z9bONN #B4T!D#rYE:N|6dG5kq,[]>?p5^) K!D=]eXx9/3Emw^{>b|ᇮiʾJݛf xoHJ !=I"ľ}h׮򩩩(b:x ޙ8M?^hM|&@v& B%K{1pZ)vTtb(t-DF.`?!oРA{|G2TCӼysz=]GM9T\D!޽{1cӦMcĉuZŋ4 "7أ$8x(?gI&qQzP` [7~ Ea !JFBB7w1dϟ_(HNNF)E_~ASiO`uc61@*"44dH`B4iժB4D!K/W_}`zF3u?sM~~~|4rd"q8MHHhф% BV*ZNV)B&wo4Mhٲe!귦M @v6ha3*zAAYYY OH" \BBȰI@RŠK0k{鈮iIII.NѐH" X~~>>` Ly"JZYEs*P)(fB8$ Bрv,ݺa)#00}LSNPtDt(_IIVV.OpH,!pEEExx\ZժTBB|Gl 6\֭[~ñ@`` iiid6iY?~{9ӗC7ҿvJ=\7 Bb6l999Zh42c+t06mC̘ YYY"q&M~$w?aɒ%|ǮǮBCCc֬Ŭ7MddĐG7n2Fa !9I@…9”)Sѣ5^h42xx/̹sIHmgp}֤&arnƺ͚5۾4&'NdҤIL2Aʊ[#I+ Ο+f0$ B"F￟뮻w}V5mb 6ҰXFsLbP#wo(iiZi%jfѢEDDDp7ɓ'Cz=a0PzXB7z0;Rg"w'**/qƹ:7n(:V.cN~7&gBאD!W_k׮,X;v(:]Lt-Ч?D6Ӥ}=x_>׿B66N 2{؀N5ZFEBԉ$ Bd}6mI&u^ל93_ĺM,>#C^ ,'?DeXrG/'8x(_$1-s'̙3 ooo]Q'2B8oJVϏ=c2+itn ce4i"wE:uĉ2q"xd4flCBIt tqBH!XU.,gRSSfZgFFfBBj׎V?@yi۶ BWK!DZZAǎu2 YK]Q:k8p aʼn4BԖ$ BрXh%'(ӥrz;fFhh5%18MJJb2D!D=% B4 O- q k+ <<3رz>աJHHߗڷ''8VX?3$''"4!D=' B8ȑ#Gx뭷bRS$Ul)˗׻ ޕ^OR~ͰJh$ +˜1c D駟:,!>|ӧO&''[´%Kӳ+bƍ{(k_~TiiJ3񏏧iI ^Nkf(h$q4^{5?_/~ Fxvʂ [3bcfhIRa2Ի@݂ 뮻\FmuW/<=mނ(dL!DH Z"99g2w\ <3$%%j*BPJᗐ|<[wC<q2oooV^MϞ=]JY̚H[a !D1 2ؗ̔)Sωpvl,"t[+_Ƹq7:3DQ] +q@O+3(~rE]D!dȐ!;=߭bcIۗ%}>'˒%C >Ja={nAヒoJ 9!!dddB;y"عs%wozxx"ɇKIIquTVi{t钋i8$qC ,o߾CQ222\^NG4Rߵ 7 7`u.PTǀ2d="<+|G_/-[dݺu 6g}{!Ue˖xxxPTTo&bF~4 s&(֭;BTJzO4Mc_G}T!%KdhFO\X,X8;۔=W|å6mٺ.mڴ{qŋyꩧ0`&MruH6*}vjM7Cff&.V$qgϺ:!8pS?'x!ۘ5ctO5,)^|u O6n܋ѨC7r[V{GyɡՏ??dHTM̙3 !ܗB7U6צ0jr6a_F-gΜix{{h߾;l6;}UťA~̙3.W$Bk׮u۱ N:&˧v^eҤ{F4ڵk`puA4Mo7ooS}2fsSNM/_d"!!a ! I@˄ XnC)$''45GFe)ԩ 0fܹ͛s㏝kVF !'(Ml>}1 !I@ޞ={xyꩧx]N9O6jOz:gof7oO⩧#~Ӷ[yh^ϩ޽x[gddPnN!D믿rws7h"]TTٳg~(u6ҳ'YWܹ"Φi-odܸq;v)۝3g&rMBJvo?Wh;wmyyyf7)p!xFM۶mY~=[;>Lg9q6xzz:tv~<==Y~=mڴa;|eM}M#6-&M#9_GNPDL&)zB IDATp!,ƌNc֭:rR3._ɓʎ󘘭=O5ags\j(~ r)u؄I` ! m{֬KnFS|Sa&.9[&>>ls'uһ8npgaҥN$$g2 "bFN8AaaCcB'I@ ֧~Jǎ9uKi^,QNXFqޫ>pQlތEQ4ͭw 0o<&O̓O>ɲe;=thvulFxH"hV\ĉm'p&/W_Md~y99ẗ6Y2"":4ŋ3qDqV\imT87\ 'T:uvK$B48֭GsN4 W !ډl6ۼ\]Qf)"""hht:|av]usG{_~!AT"oAh$B4(˗/d„ ,]%GcT8MƸq7O7`|%ﻏv*}?Dz.]yXb]_q:ط/)={O+8uvI$B4xGxGpm9sf9n+W+tDDEAA: u6q.]G^n./]JnP'ƍY <(jÃ??$''uU:TĔ)IJݗ_ZWJqq$poRW 0uT}Y͛7ؿ-ظq>&C.Ggn~x3-[~YM?ޗ^r՛nݺ<ǎ8{P|]DXəCѵlRӧOӶm[z'h\B;1b֭cn|cW9{v;.l 81\R/-JāV$g&MСC/G \Yq=Ǡ~ i6NB4<(M6JoDjCq9"*ݷⲥEYܧ1 <ŋsvǹsYx0h4:Dl"-ym.=zpK.buU]mL(b [2rz$'Ooh&.94˞yh42c+t06mC̘J߯N!̚6qq_f;vHIŠbwqly擯MeK5MߟpW*3f0p@>lU^w/0c1t0D g ]'7v֐ =$BLqQNXFq^OO=u?Dیy,O|ךOFOy+o?S̙3 ƍZ=78˿K<7ۂ oԻIw?_<\4䪾D4~hln#a2B)śoɽKzz: ծrss9}4sLeԨӅvi9s u]G``#E֭ٳgG{aܹu:o6-G~7ۏ'҄(=y<;ff[p'F4y>jU}' hE18`ȡ/DGGj*(8x ooo֧=&pyh&Mooo4MϏnݺ:dj*f͚K/?^Q+*裣m 6q8hl`MͶ*n7Ou-lCO;I@DU.UmAưa]Xr%˗/[QSϟ'%%> x]D(ewKt:^{5>sV\9{l[z[MtjLd)(xЦիem V7ϵ^ɕW M q "UF\m%,֭|bccreu? d)ipURI-\V%88Ϗȸqkhr(#}da m5j9BBn/򔾾5<ٳꤶɕp<D4X ,\ܘ6ظq>&C.Fc~-ZCBكl'fT~iի]*T!lݛgرfl+[{Z^?HtuڪU_v6,1NOk짪əUTv7n(ggۜ93ٹs/̡?\5M#00.]8sw3OzoѦB^P?NB?/{{{sC9|xmn$]6}*gQjvp.CF4u Aaa]Eg5s9㓖3gbn:_:7rYnDGG׺\ofu{4;f?u]! H#PèIet -URRO>$7|3t޽p\ hb3IRRRվ}rƏOS|S"--={RzZnϧ`dVuAZO8$ 8ZmN"]_׷TՑ?tYh}]Fv\ NgdΝ+,d[or_| 4-[:$^![n|,ZӥK[tޝ6m\@8ũ;%߹:)##]vQPP`po{Sɽz)&kmv_z%//͛7&!+Wܢ::0eMi&>郿Q;!!A͘j~x63^6*d+Aj?z`/[ì`Ss$;I@Huܨ^+[Ui[ǐz`URUbY rzz]\/71c>SnݔKz G!˗նml/P~R~>\skaa8&ڞ#*{H\?Py/${`V=ss$;RԦ+:ToCmlNPTD%%rϺU=vizZ}uvZ,no1[7wޙΤIqF̜ID̚EjtB߾}xYmFppz=4?NLݻ5:Rk..\`8տ&ڞ#*+pG]50U}~ U.\$Gj{ʊ5ɫr/0lpJ}8ԤJ3.J&#cK|ɧ)l`.7|7L&z}17:GW߉)St:t 0޽{K!D'x:0w\*`0p7ұc+jno^"QJa6%66BiR|tu 3gYo$]zVˤ׺Jj38>GԎ$ HmٹCMo*z*?ὀt['k:NUBI~̰ZR5e67Ǐ}vhȭf)&W8_G5k1]vuo!w};3Ν;X,6t:C޽m>ЁoIjn }Mz|9Z ĐR88z6eW'}MpuVi%q7\U_8՗TҙkӷjתpѶuJwմ5˫K_.I :)@AW8Mm;״3{ffꫯyLL^^*;,LM2JiZem7׋JlBJjj7oڵTNoQażDnݺr?2t*S'l]Od2:>{;wa7kjS)HIFjVrv XT:\īw%?k\jw~TW+hQ=Tq]gTݛ ٬=֬Y֬^vGGNu[պO?U78BزX,oU>j֬JNNpLSٳUFJ0hi[lQIII:6hݸ;fWwR`M[{jrlHRwR+ug, {=9rI2I.ݶ+c~[,Vt-* Wߡ=Xӵ.|ӧΜ96olI])Pij+իWUVuJrssn6ɓ'˿ YRNrYW'CoR<;vP},7x[_^ۮh]ݮ|}oy^$.IRwRJXUXXw>3233իgf.s!۷oۜ1/\–NibYZOm3&Ht<6n܋˸qC=vki45m6mڋرC3gfQQWJ)ڴU:Ox\N۬*ʾ^##G>N\se(tmDD7"&w8jT'f(?.i[Z >lS7={*:s:xv5*}w6e}at:|vw_1C?x0(Lf׬^}7KҔ?!4vJzz: <;ҹsgڶm^'//-g}!"ښGҀ(M#00뮻Prrru p*W_c<<.f!'JéGG\o)I@o\Xi?|չsg5tJ+=w:KݡyJm_i;ٛ=ddd׫^zI|GK~jܹuWnMu|L&uo>fJ':Z6L<=nC3o4P>SgWVvR.i"(Dcg6տ/u+///빭k׮U>%!,*45)>jjÆ ꡇ&]e*\.kσ_ui,MNx`PF7xCt:_rUչs+}js2rEmۦժU+5~x5w\gϞkC'u=>*)**Rjˏ>R}V6bmB)PYaa_U[{wYi3HXB>|X]t\]nnڳg;w:i+<VZwT&//@eo&wUMȩGphR$ u' 1Bu޽;vP:N}.w] ;-TmOFu$^ UTxu9s樀JӢsssՅ jTSa͒LN>~=zT_N9S5J]jDvX:5z՘UYRw]!\ZjXjZjS@J+IFrT1 U3yC79RfM#[z^=M]JRw.kՀ%%%V0R$&&^s^-19sdũ [̞\Roj;@a fvۢPUN={6)*J %% LB>6ma-P;uuzp( Dks|Fn>=GBWNЃ_x iKrAu2CBHޝ#{wqF*'2M.Qsܔ>7ԩSLrRɌŧdiazs!n'ejj4'}F[>;/V<6y c_~|ZP츲 8~щۯL^هu=zrbccQ)Sep)NeyY슎#FTpl6c6X,oަ,#w,~5Tp Ax@!^Mq5u|$xyѴiS o/ݱ[Lz1lؕ( _Υ A+߶U2j۶O%csgK-0y[CLJV4x` %,0i+S@v)()()l0<<Ãg-:I0`Focҥ)tz4^q}>tҥtx鹫̿3@th:hthƐ!CjΜ9c-\iGnl?d*yzڴmKH˖@qpJۻsMI$Z PD`,_@e(iI ĊSӎxʀ0Pjr)H 6I:K:%A&n &d잳}fv}I><0(<%xzH:!C);:fMkȐ!|\ĉUYY_-wޭ &hӑu_I7\u.$yd#CVt{ʊ%oT.\.yo==zhO1}[KWtF):dQzIٳYOj}*+{Gqqq ښ>0(&ݯ6MozɓO?(]|Y555W]]jkkU__/ۭ%VU)J1/*ZѵFQ_kkUs<Պr(*0d{u%Y\o7ޚ i4]HdffjϞ=VBBBSd233 뽷L3dIqJIzn]]soKJJ,ҳϾ6yDW{KI+zVmmmۣ?JO n4رOϐuLc-:u\s|#kmhWT%edܢqMF{nΜݬ'̴ꩨˍ5|7<+foajViر̙-45޲,Y%44%}oei^lE7LTTT\.W-::i{]q6^Ess'i銊jzEoٶG.bckԳgO?İ<>:]ٲRFkpv_#ѕ|wx^zzUv{\UU 2y<񊎾Q̉+8B{eok[me6˲gkmh~OTTT?ϟc⾶={LZ}}{{Ouu3Xr644hϞC:vt5  #o^zκ[1cƴ*17vLȬENБZ;:;fTɝ5Z{3.;aw?Q˾C `u$HfΜiX-֭[g3Ɗs;:_4u'9h Y䱭e[93%rGoW?>3|) j4]E :kѢEV߾}8{sk>: 젷a;Ic=@h>`yE32&oh.h\ 瓧t9@Epٷto- ]E !]] 3u{:vvգPvL ˖#Ҙ6>C "["C !5$u@;|)=bPk{:wO8 t@ho$8@rkL+99{B4~zg aDŽӑD]=]9-k@tf-{-;MweusW'@jZϒi~8uܿ_hЗ;]k(/BgYx6KGmLC^2\YU=}WVo/ةڪ/ةU^h5d)˲ڸ%-EA]kgkYӕbMT~S6Qyym.Dm Z;0 \ I/Kz_̓ad(6I_ᱣڮuGIr]jA&-y!5u="DggKTV]Y:G T,^e?UFpaU/ޣfmk]epm;6˾%2>#G:]NX#]: n8^ w%T\"/uSߵhM~--@q d!`gJ{Y[!;>y . CơC4rHЈ#.*}*-]Q_?]uΨsϽm>; DٷDP﯅H _hvw2%rC-q :;_,``׀ !hʔy_*KNZիwO& HH2NRiB=KNNR~RO-LSzF@#0wm2 )W[;UQgdd D<HH3v0dJ>l-Hr]b0}zdf*'.dYxwjlB!ɒi~C_囜.d\K,!lHJM]bmRbb/Kk4b@Bw߯RمLCF@DcDmR^^&_JKxAU^ЪUW.LF@[> m lC`@؆6! m lC`@؆6! m lC`@؆6! m lC`@؆6 3?z%4w^G G_Tee222d%!Fҙ3gt-\r~mKޑY@@ >>^{v >" ;# h?@&BeYocccc\  ױw^?3 CB(//Owq4`͚5KǏw4ؠ@i*##RDRNNRRRÇ_w,AYYxr-СCl2ևs.]ҥK5yd4M~{M4IJII#sKB|ш#4k,%$$?^~_;]ɓ>|4o<%''H:ult'N(==] gZBJJJO<*0`euy*CW[O,˲JJJ,07|+>>:ydS'|ba_޶z`9SttΝ9s樨HV@=zt#" ҰaTZZPU{jzW.A?A| $I/_IVUU$;N>}4M8Qrڮl޼YSLQ~  ;uRSS[ʲ,UVV:PqFUTTp5k_jٲeN ;~nNɓ'k͚3g֮]{`Zlvܩ;S׃>|\dN6pgϞ1Qlll=z4ݏȑ#SVVVΞ=KWrr ȪUSSW^$M6MuuuZn~_U"4vX͘1Cڱc ԧO-XDp.ֺaqqq~kkkGti{JJJҟ'tI%K(%%EyyyNWf>z7TTTDF?'?ʚO6M ZxfϞ$Du`9,55i9_[߾}. 6x&M/?T>}. VVV+??_:qU[[+ۭ'NܹsNoY˚5k4bĈV\{[}dF?L;vL-8 0Pe:M2Eeeeڱc tI Y|+==]Tqq=r]H73rHIj5{ZndJ%%%ڽ{.O^SNNrss[C9P4~x9sл\رc׿U6mҳ>ˈW7o>s=JNNV^^RRR}v}G;w֮]tիW󪨨ڵk5}ty睒|%&&ɓ1bnᆦW\u P___ڸqΝ; -_\&Lp4w67e:{>3KA444hŊ*,,Tee |XgΜQzz~駟irI8KOOח_~/B$ꩧ)Shʕry! m lC`@؆6! m lC`@؆6! m lC`@؆6! m lC`@؆6! m lC`@؆6_WWdžzIENDB`lmfit-0.9.7/doc/_images/models_doc1.png0000644000076500000240000007704413066042256020642 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATx{tk AYp(d ((ZSUĪ᷵vWbժ-TERO*V!I&Q I ;~bEYsm@ 0A!0 i LC`@4!0 i LC`@4!0 i LC`@4!0 i LC`@4!0 i LC`@4!0 i LC`@4!0 `VҸqԱcG%&&jzg. G}kVzGԦM}ھ}եED}o߾6l,X`u9@D` A^uiƌ[\`-A>cmV_맳>[ڵӝwީGZ]` Al٢ ]ꪫ[o[nы/)SX]` ΀$))I_~='qz饗yf q AZj%I4iR&MK/dǎڱc)5v]Z]FE1HnT\\Ν;x~Jv]5;vPZZSj@uM+V 4 iii㏵m6pp8jfǎok/6VXgڴi5ke$|c _;vlܸQ7tvAi$AnF=_./JHHХ^Zk/b <؄*a!|c _  -ܢoPFF.] T.].0@/;<͞=[ozYfiԩVXb ݮGyD<եFNэwl[z#Vl[z@ LC`@4!0 i LC`@4!0 i LC`@4!0 i LC`@4NRYYiu  T|ӧ?VQ@r矯{L{챺,*Wl٢ &ճgO=:x@T bƱcǴz]xӟRM:U?.*GČ|P.KǏk~Ν5c 裏T^^np h"nV%$$47|6m$aPu; k.?ѣ5mڴf62=@Tur k @ZzO{Wcƌ (ϫzǭ.P-XK/oU˖- y4i$C?D#V@Q+>>s~1 @h_7oou)l@h$-˥zR p>-]TVh Ǻ X0@8{4|m۶r @Qcʔ))SPJX7N))c5e*//7r-JLLԟg>D ի5g}AvlI6I~)wG>[4`&mXDzJmk׋\ )Υ6㧧묳2@ ۷ڴ.ih+6,@@Ϫuj|q8UTěY .]|>@T8p^z%P˖qun44@B7=ܣϒ,ٳ~M:U} <rB9f8Ç 7`u^uM8Qw(T=_:zT͕ov쐾&g).N3G @@WVdR^^/Ir8z+++[>ߣ^)3YA;V;uvu.HZ\5J˓?5UTThҥrJLLlOg@L0ekNZȑ#rJKaաCw8={6lx_}6lx_g /. |bM:@)2 8__Ne~>5+п xlR&LW_N:iÆ z'5|pkРAVc\'Yk$JJSu }nMs+H~n$))Iz74qĦ< JJJ4p@edd>1j*jʕ$sN?dvv~ߪmX@3,%%%SNN~`]T9nty*6o~O .\}trt=Ҙ1Ҿ} 'NÇ7'у-Xѣ;M6ƧMx6i$M4ɬ :;&MjuT#NFu5.,ݥ7$i֬Y,@SP잦o^bB C69[4bsRVV>7ިGyD|+/`؂eZ֮]{OW^y@ttرO__^xA+ZtR萑,wPոnYziȑ9qD9rD׿:feffkь3/{Q6mOX]4K@@W\qO^G [o^q,IJZ`BUV5.ZʒʂM W^̔2`?Ν~Zӹ瞫 &7.BfP_'kW$3YŅ}!~ZHݸNG0AΖnMj@S @ twﶺ *otaÆ{}n.);;Kyy*)!i !l?i`7%.F# ߯ h񊏏=iri*^KC^|eee{SWXkb'{j(9=׈OlTo:fW>NphaP]Rrm?\U@-B4ovCPZ*4uwfOY>\Ak.W.MiSVVvהkʔ2VSJXM@[ Vh~|MM0AGzVgo>+q2=]lJjDاLyuoXB4 ;vP۶m5qĐ?~]i^?>tH3x ;_F땢[˿I8I.PVVv@b Y޽5lذۣnkjgVQ UWt2iσ+&CxoC^SNNЬlZ?=zFo}όYw@&Nj*[׊IP** /駟>9#SؿR"}gt?SYJJzPWvI??7j 6H:"S؟YZZaLU<-%'_})9ZM.|^mةmv9Z))cuAIuB93f=e˖q}\q8*..Eڨ1ZWE OPCN>IHvUTM)'w[HթS'u]-Ҙ1cFhn f';;Kyy*)vI?ݡ4XkJW"޽Tuv[=z-ZdX}؂hvG7ts_vzp8+] þN>_4A \!:֢Pe9 + @Ԯ㣵HgU:>~'ѣG+77WG10 @:Ξ-(cO^:~uR\aM=z9< @Dּ{4{ ԩ4baM߿u6,1ԺuB_K'כ_XC--[&;VTͦ+ f@cɒ%8pڃ#u._XC):$|aM0aǏ\XK.UϞ=u[NB8\rIFŋÚ>vXWBB #FvjظQ*- hK/,8@DطoV^#Fɑvip kQ$W:xJ @aҥ)%&^W)?.-_nu%Q .]w5`2Kj/t   "yco_ق  ?~\uoJHn:cFI+W$@ !!A۶mӭZ{0'Gr֭/LB877և~{\XqqqjѢE͇~Z^҅}d׮]ꪫtRC+@k:=5ի;<冹brr-jFIҎaM1b@T#"ҥgeu%W},''Zf @D- 2UV6:wȈ#>TڳA@z] @",SYYG n2ܢ0juNl }jHOzs!Ņ r饗R#,%%%-k}{)--s ~opa`>2:tv{́ի}Gs @Sm6 5 KTTTh1bDKV$ 3jTV&m`u%`)VҁBiPE 3|<ъDnnZnR^^tm֭!$s  K(!!U@甛+VW!L'(##`N5* &+mhu%`{ShZqqq*..}<>ltH3V^^l/Tc%q~7r8WbD3fP\\ `u)`nݺsϭh!Lnw>Z]^;R5gxݙ*//֭SUXXhb`,Imۦ{LuYR:x0L>S%%IrI)_yRI eeeڋ/Xmڴ* G1/ǣ4hB1i`|Œ{ OhCb4hkJ;wjÇMեi Svmڿ.WhHI@ ;vlWziJI~)%eLyD7oZȩ̙=V@:=9sKV+_>e))ggd;]vZjkyY<òT$C ~{rdhguH ΊjR+6$y<;sJJJ"h x:h:Հ0Nd:G;i˖0{|r@zU;U^ijI2Dކ5tPYF400`eI}$1PNgU];300`?znv𬻔$$ՠ_WII);;˴Z-S}$ j۶-@4[af̘!ouU=k7z<-%'_})9ZMVt_{2GڰAڽީ;w~8_ IDATP4= _5xRޒ!ٳg^_2$v +~5\aokrݒrMRRj˯ñ>}ςY] 0L~~RRRԡCԜ9ew>?3g!qqRzr10=1}L<&ɥ4T*PDp8RaaX 9# ~_D v4up@_5;:vo0`'/%IUm$|Z4U %: e(GUVuEIRUG"|yx^] `ǣ+..&ѼPSk)1<NgȓO>sX4=YJJzPzUV@by}`/rrrk\4-C^|]| x^Sڿ_쳰\.f`H@'tiN~>{DTf núznٳG7o>q"+ nNgscQvE}tf@K]ZmV)))zM0OKkJG54@UPP}=^$锎0\._^70h@zuW8Q-a- #FСCM[M@NS5**U뮳eKiРρ[ӟ . + &TPP U{pF!V@М@MT;w @|>).N<š3،p+&G4ۘB`s6mL%l k@M*))IP\q=|}Jm۲ @T"LAAnwÇu0ohڽ{wWkob$|D &͛7;=XTm1`5WN7aM߻w,X@?hRqq!I\ !OjQ [nĉ"5eJI~7{Қn݂ Wbb≛ R ФD%%IV;G6]+;S^зd5(833‡KMi n *$PVV5+Ngt-׫@ `pax@% 9tijJR58Ҿ}aMw\ڵkJKK . hRl'O+$U#,iian2$؆ @gȑ#'ntH UKvalu*))"pF;N:W_$9ɒ %I]zh|n@XX55#e]F/[gd͚5:x'IR^^JJf(];%IEJURCΞoaPz[RBB_~ecpF ԲeK 4Hp8oN,^|&O~+x#=]:rDڰJI8#] . =3p` 0JR ݻ , h:K.=PY)\3P^^)SPJX8Q[铧_PyyyXt5\%46o`vgjΜ*.6o~OyG&}aݙahʕ:v @ W}}`khO$$$I+U;KRVVvvѣZf@@Mo o_}{+i|bICj<+R%WޠAԢE T%4@6lĉDuQGsε40VQ?@EEW>+YJZY5~z-[z nu쫯ҁ4yduM҂ L[nC=du֬23ٲ+%tr]uTEʰޏomLH誫|~XznG??[]cÆ`|$fϞY/_|ͦT!4[Lp?+QF鮻wF)..rj9"})(qqRj}V"_~9rn&}5jMÇ[]4XAA*d|TQt#W@b Ə?4hРZӦMSSwM4I&M2DSAA HQ h~a"-M9S*+=j6o<͛7Ƴ={XTM Xz#..ԬY4x`3Ky^]z饡W-M)T!W@8a^9b@~߯ uM;wܹsyf͞=[V O^9p@ڸQ^)6[p@4S'? /;ԬYt꣏>7luy`:tuy\:xM,+ KOaM߷o.r?10+ Tffe9VZ 6!ҤGozwgu)77WW\q @X4"K$;2\*S@l6\. , C4"\SzZez,Ք)dn[4R8swKԜ9{x/;!Z~@m[2CM>S%%Ir'ҴB6IK%%3]keەoRpV>[JW,i$H=ϫFT֪U+ <r@vޭz->EERjǷ#UTKUk+\mJWAy<P|w}ڿ +Vv{`:G[[NFUu馛N0 z-_\]t\P{pN髯$bә,ߋ~ HaxRSSuM7fW$ԃW~~<O\{Q@ %y%ShSRCβDpZǏ5V^^w~LƷP+ 'p띯ɓRrsZeyp8.EZi]V@DϕՕڼe$}b8͞=3CmkIL8|hB<ؓb,_)h"[KK>_s B@4lٲsXIs[E:{R 9?f8.]hܸqWTYuSRO 4tizA+@5k,M>sRs%{u_,Eڭr*AW"{<~hbd@Hk׮ՁB8 m@tjHJ}sa@9RO>d V{OڀVp:SS{{9..NvwnJPCZ6oެ^'􄢢ُdz}D,=HuٹK=|D.y~0N e4dȐ|>)5Um$8ui@}غ;W"X|Ԓ]v'|8`Խ+'g@׽Lں(==="PݻU\\|#)X "P$N^+ IO6oPƍյkW;6~iil >}粅 #YR߾QlݺL-XZZnz/#D2S*,lK~hݺuZjAEX@\.ztp/ڵko>   |EE#2REE0i70"7`ԪTuY8Ν;kٲeA@uz|:Ք)pmXafi30"NLnwV2P~_jΜr3 !nP۰|>9bPQDH?3UR:kRRI eeeZ'rI۶)##Cǎ:^#$I7xnZ}bICWuICQ\ 0@={Զh @~_yyyիWxI6WSFQv?A$>>^Oj`a@Hڴi;edd+.VI^iNhA7aI`4@˖-S||\[wNt&˥W$)D)әlBh0[ZR:vJ@yyyJMMU6mjegguWQ/ɫej%=*]ku%P Zl233C;ݒCn/Wr8UTnәr8&W $h܆nu5pb\iimۦÇpZYNx-[JSZ] ,qݯ z§JyqܐF7acǎ'xRBBh^n/]J޽۠:ĸVZiȐ!uOz2(4F4$QF6 C]SJX7N))c5e*//e'@S#kWp Y*+/W*qqK7⅚3g:CW_n՝ 3L3ūc}$JJf(++;/$` yRRϞVWFUCuWu:uRrr-[f|bP74kZ4].z=Nu6## B;~\ZҌ:FBʐ@6mڤ2cs ***]wݥiF233eK͜9Swyg֮&4cNgB%V!IzO}D?z8q;vUPPK,X / R h)oݭ-:G{uT=C_|zeZb@we933S Oc 2ιVRjjV\ܻ*>4dHp岺4^|Q*+ Lӝwީ{jܹ4v؂eJeffPoiD<鬳K.4 o^߱cG-ZH~ߠ>-\Pcƌѷ~^{H4 >ns #Gw}O?Ԡ΀hڵlZp.\Xcf馛n2g inltav묳Ғ%K4h   X1PNN*++k<m:ii+Qo YgCj @?XLj"x)#C`5j-[ǏTXA 7Wr:VF6,@8"K #~_{B \0(cG)%%nTmVK,101BfRIIIݓ6m9 qn>НwiPQbbUo>5I+Z= 5βs1(1`ɒ%jӦ랴lmO>11`PBBB *srCU~㔒2VS)[Wj/ɫe]}hreeer35s*.^9sά7\vejٲT1hBX+ȑzk䷔|k5y[\OǴNj -SCn=kݺ.2F:IJ;-[G3&j-lD4\'"zW__P6m @abYu'쌺#o5 {p rūj4[Ϯ*;vLK,1PQ,7WWJ`fr5BmtPiZQ5ޭg{V>}؆ vܩ{G۷o?eˤ#) #xY$HڣvRUW_\ A >C=jѢEݓVڰW1(;wQUߓ lYD $Qv¢UQQAT4R-X&XjՊ(ڊVTjAX& - ɜB2!3;3'O.3;sss9)N)$%7_g#G?j"|/ĊG*N- NLLLQ6\|C|Ҩgmڴ᪫fXoD IDATy9b &KD$Ȝ>} 2nܸ7kh.7_)5֭ߒn ,"^ ѣG]|=>:lwil R[CWVG""Հ /N:YW<=hYG_uil R6DD|B H/۷/!!eo$Bpel b{æMgՑHS""DÆ vr̀ݍXwt?kmR-]w%D "eJ@DDHHHǏw/(%g1 ܽ+5hY x ҤI&OLÆ ]VH"$ [Xްh.:b^{5/%"F H5M!XCsV~l R{CN_G_`DDIMMa@l#v' zڵշo_;:D$(FbBBhWߟgذ.̀-A*<npB/&"D3T'c3>;5kfu4z?NZ*[ӦMi߾=}*pGƒRMp]*ZhxD$( pgϦ_~Ԯ]FN70v7B6HHXu `;v`͚5DF6&!Ojjʙy=/\=!畝MϞw3$-G> YY,_bD""f̘7% ""jwEQeq^TJAA(`Yȍ ӳֆqILL0EŅ raaSғ\g=<% ""aÆ\sEQeq}x ܂F(Z_9wy'ɞRDvve zv/ZIDJKMM!6v!Xo'@:$55үըQ#>c1^WDvve),ԧ+;n]PbbbHOŰasʘ_m!x ݻYj#@y@DDXqe1%%ΙdǏ6mm[CCZvV߀7!&&ٳgHE$) p*g+(>⾖-}{S4ȥ]CCCۙ={6/"6"`eau8χӧ];`ǎ[ H R""́͡S'#@7p = |^{-QQQ̞= H R""@~MO"Uվ=\rjԨ?@DD$|dffҴiӊ7Ȁ;|7 n͑1g-[D$) iiiCΙ=&~i3~ LNNo2p kָkfͨ_@QDDĺuXn'NxCc(cf ;n I. •WBtkWE]D>}*pzBKH>Qwg۶Iz7X >aaп[ρM 8q~>}EHH3f̰:, @|w#,|7;#/N6 ԣI5ѻ7ԪRDMJ@I&8p;v0eJ9T̙3֭m۶xM +Fv =TkM7T/Y&^x!8ߌ3?q ΅:uȿ* F$&{2˛o E!s^=#`wmP.[2|f͚D$=4hРԲ3x`"mXvP%k]w9ηg6mڔo4x/)Ru3gd̙9rĢh?4uT:udu"HOw|qՑHu1t(#jw>|8IIIlܸKXk׮sEKDO[rCx:wE|᪫L aÆLws \j7x#Go>>s~gƌC=䐒ʊ駥4mځ޽o 55U_}{}6Xl62^z ^qi~aj֬E_ٌf-[k.18&alر͛l[ܤfunm{ "6vs 6n B_ٱ 8FT_:xَ;ADS&!Нm&1f3DD&33P ] ^|Qɇ^˖p50c4% ""~"33 H^NZے9s鴢ml4O.}"Gݻ⋭FDB@!0HeN~#1|5$`E j9aT?VvGG%YC;~=+j=@ݺg=V*"DDOtxt3BVV&˗fAIKS!"70d.rƏEď(#111M)<''UضmЍRa9YV3Dw?kiDOw&9E6Nʣ>JxxB?.X"" &&Y 6[_u,&G6l E<1A7'k1oy7n࣏>r5D) ŭ# c֕MQ!>d!GâE~[Ѷm[nf^~e= "ĔBǃCVG#ՈcgIݱ;ysxe~`n7% ""dس~{#j1ЁavB caLy^zѡC^B#"M ;Vɓsg%Rbc';Lc Ǣ#Nx5f1n8K~D."F Eh߾=JvX&RBO\n]9MGz$ZnҥK=w"74 Ez-vE߾}+ /@׮pu L gD1z9wށw}j֬멭DZ@DD,pQ&N}G۶mϿCz:|l$"?Ѥ scR|^BɇHR""b)SpIy ж-zW{a&ҔyWxGiڴwa<?BTlKr^z1H]DD|gVZTn_/v!H6l:#z]DċrrrHII%33P }ry4hpر1+@͚X aa$&Ɠb21;:ZAn0EO(lzm۞RHfƌ9r䙡Ky%h񊸣NVV&˗C~=o_#<<aKDKƏRT)뎣R_ %%8x{y4";۶Mbм#ӢE :TňEjJ@DD$33 dm:`(O&1;Wov< PͻuƉ'4iۯ!"A rB;q(C.X"~RBl,X111$''osNw?DDK g-{z'1رMc*u׬}b?;v,<# +xIbbon1AGFF׿?3g"b=% ""^Bl -hLnn. hf >"",>󋉉!=}V< [3Ag;zϿ/$$$0j(̙S""%ӟHKKciӦd"aKPv? 뛵-<^wĐ62gSLm0oޭ x[Aexʕ+yWIMM-|@ey40##zQDbxyqӟ{59=5YSSJMyM7PDÔrrr*U$Nbt֍bUްF L!!|87YC4cZ3ɒ%a;z\gXS""ΦgϻfQSO=Ů]O -;ǙaKT^e,\ Eݾ VK;pxl>c }f;vrnYSRRt r+QD2O)uL%te#Ф+Ҷmr9wқ78^$u>q99rXvv6=z$1}deg˖ʚwУG )8ws[qJ.]7n4#,zЄ? d·Qѵ(Si&D0uۂ=*lق9 tJ@D2ڵk?Oœp-tذvA;.a;ŞfذOH >?J RHe,S|gUL2ɽ{z*'''Ó&sr 5o؋ 2{JmC]`$MD|ӧgP_ ,b:hO/<Qˡi&:vo~;OJ3V-@ Zg!v{~'οH(5p%s'pm,D^uԭ !*(kVt;} wVYg*6o$&&2p@~gW@尻U u T%A$Xg:G7&_<`:[:+kOsϑt)n[H3w\0`+V 22Lu r855˓ضm0GrQ\*OeI)hiE$X}!&oХш? ,֑GGW$cbb7o=zws!G->Sa3.:6wҽ'=1z`\](։urrrxXdj5qB<>蛀EIX|t#F'VE/g̙ 0 &0ydBbb.܅q4ZiuNbHK[oufl {u'>fsSr݊R{^YWh ݭ랫cq2Vuj&펈/u՝C;-`BCkXΘ1qqKkLԬi̼yK$?7ߴ:T ^c {-*h@LBezO4|5Ha3y`L8q+Ν;o~ѣGiѢ;ɖ l  §-x4.jfIGa(x=# OM<5;qxP<56ln@w΀fV-wx.J>?3ӦMcǎʟkNӧ1,XxD%ݘ2f3.ꔀʜTT+.D6b!w ϸ&r_(fgIcz6V-c-x,"Va1ÆjLZG^r̘1&**|gn牲|שּׁ*kA=\;84Z=% UďTvH- + 5:L?~GXÓǟ7ڿߘk1vmc,HiUc `3j(s2x7$b[y?oJ@N  NT_E޵~Wyw?RU|7u붫qU|x/0&&Ƙ.2f 7LD*n77&<ܘNپ/g7o 7W\qKalwwu$7\׎IٔT?RڝaZs^WTp?f\o☬=u>>=N!7טcYKse~]M$]kLV4h`W֯_oMDDy뭷n7x|F]^P^ ^φx8 sT?c#ˊwf5.rJN6[_ &*4/W1llLN^y6u9AD|_VOst^ĉ4y'1K!x1>d_J@N 3 Vrs8.z{X&,'T_1W5k@ 3`{ԩcL\yR$Ƽ]=򫯾2?1swO_]{=lzIURuJ@HeNu?`g6yIu֬r]_qOS3#8O6x[SVr[ H)񒌌 c/\,77״nٳ}zB[}kUpƝsIx &+7r/2Ǐ7U  cUYY'<~QGӮm @JEs(~1cx@+c\|1>k%Sޮ[Ό9DFFm$''o+qlw7)U%QRuJ@$99ԨQ;v^xl6gϞ2c HE-1Im矡{8;|f믛}pSNZG<1MtfJT+s1T,R9/oo.ܘڵ ;t0&9ٌhDp­kc̜9s}g5jdn6/o'ޫ,WA+oT妭S%7pIHH(|ѢEfYw r -vˁ;)|Ҡ?C>ϏLDD=af:+͛7W7co1g3j1g<1fHDWQcOc 1qcc$,yTs KLWBzBsС 3+{dX+ Ӹq2ˋ۷nm{HlL/O"=}111IMMa$mtB;AlIMU}rrrHII%33P IL'55{SYKCl6TҦxVEK+(u=@H\cbb,O0Q^tr'Ovڀ`tZԩѱcGjժ8fzp1w$g޽#6lJbU屦Wqa%'HHW<\IZI, 0 hd{-n 8δiӀIQ|M49\qp=wu`ؽ_-˃f"<Nf.i>;CNRD7l6ƫۯU#B{|]'@Rҙ}"#HOӦpeFRoܹsټy3[la˖-|/%ۜ:uZWYܴљ%j"//ܒl1/p=YO`Ѣ2+@kJ-ߝw SަŶ8lOc;k7ޝ Wt]q,წMuV.}l߾#G8]ߠAZjUWupCph5|?W\åq?WƄz%-]N Kvq6"9RuV>\v1\q',2!Xc _5EvNaa!ns4-n8%iV.X| K~>< OfI֩9{ $a'ӄ:5v` R0jаNmZ7kM:u'8q}O( Dr&wCX~-in.f qlRNSןoP̝0Ny'յgWH Fe|D bc3IOpvصϊp:v{ٷ uIKݺDխmu@ZuZA|<'Or,/^`bQ2ib9M ='?-:Q3"J h9f4B #4,PB !44=zpEsiflEb9 l6kt/Yyf=ZϹ/V-[=:n:bcciРAe1;ʏ?n%77P;/n7_Sdر㙝nl6#ջwoǏ?Xjŋݻ7ͣ_~֭]Ν;6G$P AXᑵ wDDF/.'q"9D4 n59.E6meN㉋>Ɣ]og?wE>|0A}~xZ!fٿeVttt=ON876M6-,{سI%X{uP<K/Tx=z٣*bD+OVVj_œfVv_z.u5VO>Pp6/@Tpr7>FDչ<9:X7^uqj [y䔔7-l]J>ۉ2#)'yt+"?\AIpUT/UJ@\U+*l##1׭V:+<{ OV8DĿzȓl^*;HUT?"u>ıcoC0Λ x%yt?/" "OvVR;8R(l9Yۇƍc6l.@|| ww!Vwi&>W 0J& -*[-[>ju8O- Ri+lv47R*W9o&u?+%RS#3sW&(N\gTT?ukҹsg hJ@TʕTT T'lq`I9 'kU`bbc'c3Vܤf:udu8eУ;Gձr+Ac7lK*xC0?#"Q"% """"RzDDDDDD|F 4h Ç'cu("""""1G$%!""""T;۶M"%%`M999 LBB?ڴ@BB?lHZ723:qCvv6={Ͷm8&oIXDDD- BB0~;gfW˖f', Y8&k,O""""ՏAbbA-W6'kղ%"""՗Kv ?:` +CIZDDDR jQ *ZlH?4{_ԩaH|y۶M,H lHD bbbHOEJJ*QPJXX!񤦪eKDDD/% "^CZ+zDDDDDD|F % """""3J@DDDDDg(Q"""""">DDDDDD|F % """""3J@DDDDDg(Q"""""">DDDDDD|F % """""3J@DDDDDg(Q"""""">DDDDDD|F % """""3J@DDDDDg(Q"""""">K8Oz]<% ^I C.XՋEw[򔀈( :@`!//RFDDx9Jmi&~7n89ڵkC|Dwz]}VuJ@*m۶L>R^tEnOƍiҤ {ۯ!sV >z]>4iBƍ#`)F1dOƍYz5{{7n """"̔xs=?ϲex'-KDDDD*6c:`fSfQXXhqt"""""DDDDDD|F(yyy?&MPvmw΢EK`ժU<$$$%\BRR[n:4I&W\au(%k׮eDGGSN ^u/Xz5z+M4N:mۖ'r)C*8qO?4}!**f̘Q7nO>ԭ[h /`3gƎ˥^JZZVbɒ%\yV'4h ӹ;i׮7|w$$$Xxў={hӦ !!!lْ 6Xx… ߿?;w&))H~'1L<ă~vJ&Mx衇bʕL>駟ZiΝjՊK.-[tRO^fJ={бcG6lȘ1c8v/͛7'335jXt222f3/rɲ\ӺukӳgO #oXr9}te[n5{(*񕤤$s 7k\~V#vQӨQ#swX f3YYY:l6s"34zjč3l7rHSN{e-26ͼ>7 fϞMXX<@ɲpFAzz:{0:=zVz֭[ϦM,J|aٲe̙3S'?$;;I&nv[jժ^XjE]Dhh(5kִ",5k|Bs[nYf%ˮz׿8}Yjy׮]Xnac8x \pա2zh~߫][hcݴiӆuR~}<hԨ#F`޽Yf[o1f̘E޽{ɡK.euڕނ&"˝xپ}||}J&[o?_[x֭[)((`,Y_#GZxP&Moرc'|g}waN>@PbSN^fyDDDz ^6mbԨQٓCZxCxꩧxꩧ:ǏsIFԩS8p L6g}֭[[x۷/̟?I&ѨQ#FeqMᔀO jժUn|nnnz N_~4lؐٳg뙀 Or0zhC/+.\j6m} 2qD˖-[hҤ H8v;ǏgDEEYxK߻p3 kܸqݬ 5 .Go߾/䢋.:$[;0zhΝ;ٹs'k.~W).5jTjyìˊ+رct9y r]kgۿ?juؑ-[pرR322Сaҿ~'ϟe]fuH%{n3fZjU򓙙ɖ-[hٲ%'N:LQSjyM$si ]PPPć6mJLL V*.33SPbAQXXo],//4wNӦM-N<$222֭!]q|'|%?| \r%|駌10C.}RSF Z oԩk׮e֭Ϝ9PڵkgQd+wq/ualݺ;fBIII|';Xf̘իYx1W]u=/N{Q]{:t~P~{=.j.]ٳ0aF 26l{ԫW~(ϟϗ_~{MfuRoGa߾}[~%cƌ^z%37hЀGycǎ1e7oΪUJ@@^^ӟ?ɯJ8q"{:4^zlٲr'6l6KիbÆ V"VPP?OZZE51cXxAff&O?4+W$77VZ1tPRRR Q'@ֲeKvP2HL$;vydee1n8VXAxx8_VP"""""">\DDDDD|F % """""3J@DDDDDg(Q"""""">DDDDDD|F % """""3J@DDDDDg(Q"""""">DDDDDD|F % """""3J@DDDDDg(Q"""""">DDDDDD|F % """""3J@DDDDDg(Q"""""">DDDDDD|F % """""3J@DDDDDg( F*IENDB`lmfit-0.9.7/doc/_images/models_doc2.png0000644000076500000240000010053013066042256020626 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATxyX{wM6ã ZbI[ u';Z)Yǎd)殘KKRiaAKŝ~fy~綹.{>n1 e( ,C` P@X2 e( ,C` P@X2 e( ,C` P@X2 e( ,C` P@X2 e( ,C` P@X2 e( ,C` P@X2 e( Nb OFFxL>Zlyֵ@Cis( hӦ|A1㘂eݮGt(  U| צMLG` +WNQQQҥj֬[7P6mvZ5mtDR6n7›dee;нޫ XbC=Yf)//O6{ %Ԯ][k6m1ˀoQ:~*UtբE ۷`:\L:uqFJU?|gQ@ۧO>D52V:tLǀEx w۶m#5nXÆ ە*U8!-x6 kW4q.ͦ!CAQ֭5w\vm<k@^Z_uI֭Ӊ'm۶ʟ ނPF~z͞=[ 64 # ;v|||ԤIQרFz[)\ ~jZd޽7n*VXjwC?֭[EGJLLѣ9 .b+Wj̙JHHng`۶mzꩧ/s\ 3Mhr-0a8`,'{g-_tXÆ Ӯ]aUXh?C7nԽk4*F@(77WGѣUF q#M>]|~m5ntǫSNLGDq_|Q5k39ݮ_|Qǎo@ 5o\͛77D7n'jСˠ8I5ԣG[@?a: Q@.ɓzw裏VZ\yiȐ!c1Kt >tRqa;LG#( eo*22R~8"::Zu[oe: A/R[lI*S O>D0,G6mhѢEj׮(W2e{\:t f:JV '?0,Eg}VNj: Xvx g:j„ V`) ԩStSXpEEE5kN:e: I( pBK7n4$˘ d: 8 `\XXF%~[խ[7M5qDJ* ջ˛1WTTӧ+::Z~~8þ}TN1D1111HOO/A'ILLU5 >}ԩ֭[ڷo|͝;t"@+**Ҍ3Իw ks7u֚>}(pExWݻwn+::tEq.Bzi޽ 3ţEEEԩS3g(p( s'[ap+Xtt,Yt,X^TbEmٲt,(999WFF |W ) tRWNeggL2eo)Yii-]\8qqqD5)((ЬY4p@ӯN Д)_?.ED(Hަ)%q>^%Mr͛{~ZJMpjժOӧOpYL\/Rzm:N|PڲE?KuRB4oIݻVX\QD59uꔺvj|y}ֱ|Mw|>wr%W/Ci?SEEE3g(P" tI.1ۥ?ix)<"IZ?dBBi9)ܷOuNRr 7M6JII1JDx^֕tA$ ikQF(88R >ܬSW_(-]T2"tg[i4Hr.v>HU(-[X!!A1]uIdpSG5OPYڹg`_Ԑ!C}Zp9( 2z(wR||VQVX9ւ1ұ^ohF?KK*Yy=ntڟ,պu T ZiuO>/̡<dž Ҝ9Keʜ\ N\ 222(gKUw*RV/*U$9(:5Vqqnld˞ 9OQ#)6[gr.p]wkIpaqUFƫ( tz}:zB ="MS*tu.k-FIIIQժUn,_RmDwѓꯏI 5_uuuN{+eە+$$t` ʤG*[ ߩR5^#T]oq jj'?հl;v{=Q@p233m6EEEqzx~U--T'Y6GO辛Z^ziΜ97( 7sLUTIf' PO4?U RPP7?K]oQonOQ^ٲ{ \Çk妣k@iӦ3fMGQƍ҉<[y]ҩÇKSJK.篚4i+%%E:u2cpٺut >6,.Rn4c$lqx9 JR~A}{?1DQQQ՗_~i: /G 0Bjذ#qdvC'u뤯2<͚5ӭުQx9ր\VvvZqjHW;l6ԒnݤuIL9fS\\ʕ+g: /mذAO?UR%r-o:#V:}G#mWKmx' ,%%INsM( NkيЄ kʕj֬nj:LIg]맏4OÊﻘ;b,'zԲeK9&&FM4k?`:p}sGzD(YW.vmGiii0DaaagI_}vC|gzW<_$kj>R?IE]PLRV$r( _UfMQL8QF;$$H3_W2HB.K|y<%%%i߾}1._ժUetUNg$%U(EF䡄`B۷oSO=֭[+0{lGF? @Կ, }2DRz4&g6m~tp),Bȁի+%%E6fΜvکF2hʔ=p,W$2RfΔF0<&MnMGe( 8|:w#GhժU.CUjκXgoJKK{g:OҚ55EJRΎiX.X@6lؠ+VC1|ֵC.xƏ8ى'ԭ[7ڵKK.~$$$Yf 3gԳgOQTlYIwo顇ݻ[n1,zɓ;4pI%}yf5oP"'*,,TLL֯_3f(441sL{コMGΕڵ*W6t*+璻aZj9s( # Ns)55UݺuoO>Rff\L>\iii*,,TQQyjΕ~ylݺ9֯TU\iX,ESM'zUJ;䡄֭R\p ,ZZ:tȽ 䘆կ/RݺӜeȐ!ڽ{v;# 5w2t.)ӰBCCM` 5Ҝ9_jդ܎FLi{;o: E1h Ǜ0wTBOнӰJ$ȑ#JJJO2wcrL')]'oa( IҼytIEEE"8 _1ӯrrr4`^\;h1 ,GHOVZo6E .]L'f Qbb/M?ػ* IDAT_n_C u( 9rD ,P޽MGq;WnfMIȑ㕕5NR+P-JYYc"kn$}駊44w\?,WB|=_]Y dSB ?on: Fhƌ3j2)/c HA?1. ojrw>Ga 46cǎTfPQ@9rD .Ttt(sJ J NR* %|0RUu I1:rd23iιL56|޽Onsr+Wֆ #"I3!I!!A֟P~ZO$Jڐh}wڶm( l6"m G8 )]R$ uV]QֆtQ+Wf\ǢERjRVOSM t׏ >$u <ʧxս{w qnx.i$ @S?ږ|}GKxDQ3m۶QFrL\Ñ#ҺuRX"a:j|UPkGСV\ sQ@!-M*,""L'DǨ&ǿ8JqƲM6ϳƸk)0P6I,Q="BE5kNTϯP!!AP@K?~\+V4OKx$G>;7ߨ/L0 ^(''G7o(wK;wzW.]o5,C/|d˛t{/X`: X^O?UDD3XX qMN 7,C/g^Z=(Ҳe^yt.N4TXh\^>zi:W_Ij܆ TÆF(''t:E:vLZtUV\i: .XeյkWU\tIұY$,xJ[MR233jU=|K;qLú~iS^=O?UvL/m6}׮3JS>2{k9ʇx{j76cEׁl6=C9sN41^$==]իWWΝMGq8vL7*##HFt,m.$%EP@ 8P{쑿(+WZ -@QAwlǻd$% wܡdQx xJ*ŋvo"yKժI.[@$(Ȝ9st1Q9 %KֿIʸ7WHH̉plGGyyy;w(`/Hj7D/HJTT|HRG)>>\F+EDH.ml:InVnZ*py؆`+##Sri}_ed_*$$H_J+;Not-^X+V4,֭(+kxGYzGpSǥ)#kX2j4%|( LXb壕l+BKX5}\iZ( o߮]vQ|G$}ZE>.%"B:uJZtp x^zI>y8N:WU^rǥ4h |cx( xC?W߾}MG)>.I rR\]/9Rl6( ׊DǏט1cԩS']wuG}d:/2}t:uJ<(yNV)Mr׋)3ӱM1x W^ю;ԴiSIf3 7ILLTǎUvmQRSTIǵ\>.#!KNrQZbĉԩMevܩttIR@@ӧꨏeuS؂j֔5su ǏWTTMGf( NTlYժUKd m>#UZU=z0匀=X*GvVyں M2qHQѥא~)77W7*,,ԩSէO'5k""liI.qj޼MGf( 9mjm:I)IܹsgIҐ!CTJ:˗;ߵL'q;->W |M޽[d4{l͚5K6M>(w8|XڸQz1IKD˖I!d?TTTBot<d͚5z'u1QF(88R vדM"+s KNbZh*Vh4GvvbKs\|zƎк+վc!n: x#Ghƌ߿lX9^YY$4-W'e0NqqF󹝈知]L'RA'Nh(##SR虯S7JS;IqWs8qw﮺u뚎_R>l*Iaanw?10 ui˖-MsOijZ*wXOh֭Zf(\'k֬ Д)r{,v.䗤j7*(򇇇~zu=0p˥vLp;.䗤%P9t>>>\:u2$о4,8޽{~rqiiRӦRꦓxv0nnd„ T}QQ.nw_9G۶Ӱ- GjҤIC?~\<(&HmژNq_;ڵs23SKaa1.]Bh͚50n@ э7h:ťI͚IUNqFqZjMrRVXśxA:tPFo0 YfizLG88UFFPe(DUE/wC& 6Ls.^nװat]wrq/Oq_I6Oiju!O}շo_լYS 0nm۶m:ƥI=N %9q/VZUE]z)M24@IKZ\y.7$i$i: NiwwmO> tҊLr8 )]?t:htR||鈗G}TN~LG,=N1B4LM'h2eٳԔOJnR>$AjР a tIR xpǢŋ/"( N:SNq?tRԪ[ 裏T~}=z Ne :H˖)g~ 0Bjذ#5`Nga | Uew6-M*[V 3t('[vU/IdT ZtY1.&11Q{ј1cLG|iiQ$ާE /[N%CrŷRVXś砀 9yƎhsI9999NBϴ|}\uuP!Tv6md:P@?ѣGrI ѷSjQ~T%&RXX %BR֫pGg ,P-aQX.ɓ7nbccd:%9^YYtuL1njuUjWE_J[$?B3];oK/d: P@EL|$LjHƍUVK͛ռysmڴI͚5:2\ynݤᅲ7yԼbԶ4GkO?kʕӠA_~`:(˖I7,NӚ6jtiX<I+5h@*U:z˖-%I_X\_-^L~f38a-X`: \I߯ڵkw}Y ꫯԬY3͚5t-m( p-]H_}%>EQ@$//Oʕ;ﺿn׳> t|fs|:9FB7JDqɓ]?qęӌ3j*%$$McZL Ja5jHaaM;]vӬ/IS;tPUVk-ݐ,hĈѣڷoo:[Lt \Hd4vtThٵk>3⋦$''+99k2sP@䮻Ҋ+tQU\K6mz&$$x 8p@o(Wd+^xAKǢt7eTfԥKqEJ6zLr(jҤIgc=*,,Լyt=^{M3gP;(ڵRӦ򫥦 (=}f6:w2 R|gǟY'O֘1c竀+@)(**R߾}E׃IINg}$ժ/xuV+lz饗Lp|DW^_|O?T㔮rrNL'ժYS 8wԩ_Vjj8.z/sΦ㔾 ʕ}u*-^,N4/zGyD;w4P@UZU|Fe:s,\(Ke˚NktGSNUڵѣ#(JAZ>҃: HQ4kܸ/^^[?`:U( PoY/֬Y믿tkc ^xCK{wUq5lb`&&73-3RCm`vs/oYW^M[-mH\*K2& 13#̜x?y>0~S]:tNNØ8I233-wη~Kaa!{o5;$ZC )SиqcCqO>??͎D\$##S#@oב1'$!۷'..p J &J@DD5k`@W-1}>z+ 0$Z*RmMv38d2X v&&&=Ϗ?Ț5kCFo]ׯL2xtbvXcy\vҚ)Ujg„UtO.?.f?$.}BBBvmqڸPHl2˹s믙7ofQvle-# w?}"!!!,[6{7p\^Ͽn^ɇ/"o[ncǎ<8qDnV-[Ʈ]0`xϜasUZS':5;eXHbb"< -⪫W^!//DBBB0aDsT8UjaHO7;V^=fΜIRR~;ӦM{P""" +b=(YT+ |ّxPx {M!x % " `˖-=~p\uq@Q"*R- ÇÛoWk{CīKDģ;{n:tѣG{] u\:z9WHϞhUZcV{Z1>LiԨ١x̀ȑ#Gxꩧ4h 4LJoD֑#GXp!_=W^y%O=W\q| 8ڵp㍄iS*/c ,[6OGmrMЬѝl̙4mڔ#F|rITJ@\d߾}ĐV׀rҖ"RQgfڴi4lؐ7| ֮]СC`udf֭0bّ'w4g_$##Mrh"0 EJ]G?~}1m4zO?4lذ{G β~=DFxQS#1ZhԩS̚5#G?p[)qӸqcHEEE$&&{͐!CXrk rSڵЧFk[7aHVx'ٶmǏg dAAfIFQkF||<ݻe˖t֍ a푙Itt {-C'V=z4u~ee$kę6lȰa.y 0o<"""h߾=mۖ:u!ZQ""ѣG9z(dee1f|WҾ}{FAڵ+M4qSA߾cIN~.8c IYlE\V222d[ %F*E$$5b;}رc˗/̙3pM7'8|4ϠWbAnnnhD*0 233-wٳ={=zf1>Sy;ѣGKSGvG}Iny$'?f w@GDGǰl泞&fqk$=zG6 4HLLnݺ|MRTTD&M QF4lؐ ҨQ#Nzil:D:u)߫J@*oa}כ:uho-[׭[/֭[ׯӧOwÇwx /p㩧r (ŝ1c_f͚U o7ov?NQQEEERPP@aa!z,^EEE4D}|p#88뮻`4ir-44Ty 8He">~Y(y2uw| ׈'X, 7Pk^~e233KgO:ũSHKKԩS|vӧ'::u닏EK/9o&//wb)|!Cؽ~/ĪUҔT@ǎ`3^ͫ݋c-ZE~b8\"怀+9vO| )yᛥacܹ3o~~~:u0___֮]K@@E\իWz]r={:dLGA/`a8sg>6+y|PRh#}^#jպ_~l޼|)((d/JnJ?LVXXH6m.Gˣ?%`-Y+kmYb+V(wl޽SZVV\w_̀otޝ]vѭ[77F("ENHHXDq""""ٻwiJ^#`!ygiodFD4^s-+"RA0s_0=#LK<5%O!40;&7^ /lv$"R(-~}]fG"biO͎FDbr ?H `ّS""2338I:uFi'>Iff;Y;K,bS@<0=jv4"Ŕx "6v IL\GBƎOI֭py"?Y˱-2;bJ@DDHN~ XINKttлB˖Я9JФ sx)% ""^,>>el/!!!fG+^7dsL_ѽZ@&O~&Mx % ""5ҥ`ĉE7d`; )Wdo@c"&, &bAyy(},.ѳg ۱\肾Pk?HTXw0EJUh%!PHM[ofG"5TLLtƎÇ\8ALDDăg!3Eyy֝nj@HHqq3a*""" NDD$&IkAݺp}ڠPܮB 'Pa`xK |k,.a48p@U((/6 ,?uI> /PFEʶx%JWdg//ŤÇ1-ԩp5зJ5O '}Z#\om,\`#Z{+ rc-1\(##>}EBzב1'Z@^ Q$ #TnC֪mI(~;OO3$&9*4 5kc|3Sܕ^8mI)l=E0gKQLSlgPXN+Dqnpae[RyYȦl-ُ1%R8#%%N>_O 'QU1lcWfJw#Ugصkv2;1AFFѮ PhX--4`Q~17 Nh6c„'_j[ (*}m0Ȁ2 3Ɔu5 ; oV0p{KU?==NvjG%ZKDC8*v'c/vkE~<`.zCKÔ(Z7 S-%95ao'QU1lc3髴ߍTZD0&Lx˜za1Ƅ OT=gKΌKdhժѺ|mg~.%-FD-N{o 3aG^tY52"jݿ4^>x-W1cXf$R~Ni}JJN+X?^HoNш%OuGy{0LIl(l61aª 'jcBX²k7fS%u+کiBK(H¨O(G%0g}gԱ&%E[cS~&תO3 .2}t3f ۷'99 ~z{5kfv"MVnn zC iBdfA ӹO+hc<ϪJɑ6t\ՖիK| %cl\ב +^$riѼY' λ0R %PhHvG_2pԯ͚i۶|RyAW3cJj*% .`_7 7… ={I9u }FK_Cxt{;['O3 |T+_9NA6gN]#gmh?iq"NX8QZtj>=2;ރO(i"+/ +E$4BE:בF3u?BKY&E.L>zطo ך9ӚfG"RmfFJo=ࡌ$A K"xԎ?ۃZgm?i;a֢2=<fL xBO6:_C+"Yc|!7dOAZ-\{^lE̺TY߁LRy껑QFO&;;&Mx]`BxEhhDQIpѹc?>7y?PN f첶yÕ5~PbbٺJ:& :ќ#_|\:;'?i2'ʕAuA)f~~-o_..Syт '**PDM$fa!<td-;waG6J_ vƀ R%?ǯ³&QvOH/-y!_˭/X"ฯ? "48BsS&"" ##=S@ez_2dnjTa䖙2t$00M6sxj/Z;w֭令E wȑ4lذ߇_~uV+}ӸqrƍǸq )~> lx ?"Rή]a|5lf_~9pо=mkFIL\/q`є B$L:/`'鐕uc ˁ0Ж#4'f {n24lÕڵ{)+>U䎸^b+V //=zsNhjPBǎdeeeڵkFf)p>_~qW~\HM۷ƍG;vٳsuAMFs5jd-{SHkK>O 9ŷ_ GÙ3puźS=+ ОӈSY~t hy ӵ#+3j2.sEv0kՠEΜ9_ظq#]v5J@Dj3 4jt-Z(:pd뒻S;d0CR?KeU\v5yizkz fCl'q8F0AS V]9ArJqN7\d4^]wŎ;{ٻw/{-=נAFabt"k3.Hx7Hxj1"R u0k-瓑B(*"j>PD>9*>6XeM>4>Q$'3\B^  He)q~ҥKYtis[V"R _I`>efђW^ n%"Nb(e7%WSz%Te Y Yt]RYJ@\_5;1b9y`)F*=MY6UBԥKkZ΁/P*;C`Sh 5 zLR1R""B: G*pm%vm Ǝ]Ξ=OÆ+Smx^,% ""nV|ɋLX"QنhG80W^6ۅW=ڪ|I6#""f |:CxMT-R]`$ IDATEl(֓E>Qdff^tܩGU|޽J+l{;N6mS""f11 6p)+ߎ6;DV~6d:<*7whڵaOWvWKDLU׍'d^9 {Ú1-T-DLE|:.w24*+gx% "bGM7G9׫mÆaߟkײn]#j6l&cʝjR{KDLS2 V|pv-({N:a ;1'6}_O>֬Q!?(٨۳e#"" NDD$&"&R >/=+EE0>̘CJ>DUܩ681'6}:R鞕'`xcx)=+,U٨/:5$ MIPDLM8ڨg]`h8yҚz lݨϙICDiB=+A߾Ф ޭCE*Q3U=l"NDDLmMY<'ƍ-[uk7F(RTC g& &)T%"f5~+CSyark""".Uٍ4x['Q""^ϋ{V Fx䫫-/wUC g& &IT%"^ ˖{tbFpi­Wvן*`qzDHefj-/K[/CTuC!C%J+P[9*aL)osV wI)\ cYI~4ƿY CeUl~"""e)KqT¶qmX,8E\]V"G&OGFpИdSu Y3@+`بQITmPi l9w!/ : sDDD*N X4(Ćy%l@;L*oͅ$HH{ Gj|P? ծ'9Fʗr}[|υ3销HMBO\Eq sۜ2c!9ٚp5HNYMkaxzkժ\x,;˨sDDD*N x T]ǯ0︄t+Wt5ؾ}{F 8xjM0ܹ_+cGؑ\9J_R~gZ>1b8V[\: 8z.H(RR$<}8m8FJJjq [xp'O.ɲKsЂ$[rҺ$q=7.}<_?R|p2Rԅνe$um@`\uP)[xk) C@@r+_, XN' UTW֭p @/,@`2-I?ЂOhaZp+J q9YF&M8ĕ=yF-uk7hp< - n"L+c DDDZVX~)R0޲qI+v;?0UHHqGgq(~:yڼ!îϑ#eY'hR?F(ć#40-H 6҄(NGR6_.,ڏO|+};͛/FJ@jO\a/۟nٹzo(?۰?n]!*-!,+m^(8aa>BCE hтQgoAS(sDSY$* DDDZWX~k[Jf쭢éS99Ld̖ooCPN5(X0 0kBZ]rVhe1GhE-xV*ɄJk)^a2__ H;a!Q26{+2%$PDS2%P#Phq ;ǃJ9??H&!,  :TټyE#dR UI&N}V(B𚹪Oe˿엿dc@_JuKf*vy[~>`bC.hJ3KQeEXȠiEWJD*a)QK ֭}=y Uð+0 wwؽ{7ݻwg׮]t}-5 k7`)z}޽8IbcGa{ DŽ .V`.cw ZUɣ9|Jf7vTZdfZ1JXg#˝]~9owJ_hAH>f<8cF(33>}aKڱ"5qL3 ^*fS/[/J?ŮYf+ K(ʕG5OO_iRk4Hyhtg_BA/ C6onMrsfJ3ʗڇ̍EDD5x \Y_.o >}#wp==e-Ҹ$_->r)BI%:κBp0eYDYC0'ցu$l%ޥ͜ՇEDD</S8sSJH úҧ ͧ  K$~*Ngܔ#ϕ~;!1s_DWי+Uvf~uroX%*gQe.5e-[Jc ҙ+2 8qv"qᱳg_۠A%ew/ħ_%2 93FN*H-3kxןLeudw*~yygHNhcDXPDDij(2SY4YB %a;q=k?-7>lVлwefKn%$w#?}E4x쒒*m,7e-|3lnjv6,J@TOO* !nr<:OOqlw%J{-s!;pIEXuըu+^.]ZӺtxF~3ǨQ*Tr [ei'>Yq렾[KgQ"6mb|dffҰaC:wO<СCS۶~ {X**3k? b-B#R ':_n,Hz/~Uh֭`S2mT2/{Fv)FXPDDs(q$xi޼9Ǐwaذau]U~l{SR[3}w`aKܳ|#@zlFcǬ%[7eP͚ѯ(}$ǍcU(ٍ3(_TrP"&MbҤI=Cmۖ%KT+R=Nd'&rbnX uO헙Y|e>~9GtFo/_j]ɷbfLTFpgZ6fS>Ѩ.""""աč֭K&M+9ܙ3-}\Boc.ߗ mۖ^Т8N*alb@qfҸ4Jz8&XVlL.T\Ξpu9mW]4.xV+PbN"//G[oHLOHO}ƐC2PaB#negn]{23K s:Ѣ8e/Aͥa3^G~ŃaT^/ [+p2Qeg_v>۶}q1HP^=>K7A#G\z8֤t vaX $~hxۃ/Z Weś-abe0Ƚp ;~ѣo,Z={n:nƋݽ{7ݻwggFXPg(ârUam^[mx%33>}Ͼ_xڮ]tpf@*oa}/~ҿ}t֍~D2u*Kqv8Z;6 yT@ǎ}7on? deeѸqc:u*W|geW`~~)(X59{yI'xfvTR%"""Xb+V(w,++ˤhj% ЬY3<ֹs{ ++Wr4-=wa#?uY""""4n8ƍ+_RR%UȠiӦeeeѥK.r~ᇋ)[SxWz\>tOWDDDR}qCrWҳgO6moƲe̬P9')8?W^ْVyLf̾(""""4i , ++`_ g˞֧p3<*^3Uv_~#TC=ĦM //4>CqlsV}e$a+/HmD*,&&vf`m6/*>Z^m^p&>>k/-ϋ>* ľO_ƳEq'% R)֗./iJD\@2"""")qˈئ,PmJ@ڰ˩_FDDDb*@QEffለ8 DDDDfRѴa,J@<6E Gӆu""""R(hڰNDDDDj-nX8f@J~*~J_#)++ݻwEw8,:/)==?B9r$;wdȐ!Zk\MPP 4(wmZZ=z 55թ񋈈󄅅sNBCC+)qX^Y`SLxZZiii MDDDD)44TG5(qCwߕ;f?[駟sδm֤EDDDD̡čZnM.]Xn١Bb1;SiDDDDDDF3 """""6J@<@nn.ӧO',,.޽{_;LN_>Z"**$C7;w.>>>\s5f".{nNpp0kW_5;,q;w2b¨W;vdٜ;wФΜ9ó>7LPP>>>6?s7ӠA{8z#>*ƍ㣏>bڴioߞe˖c6nH~Oh1ftBZZ .|tŅRRRС>>>iӆ={8"##޽;QQQԯ_c/\wuĶmۈeY8@۶miժmڴ믿&66{RRRڵ+_~9SL!;;ӲeK7;jb1^zc999UW]emf;dw}IQDEEC 1htpN}WUW]EDD3)*qM6G` Ъx5`ܹU֭ @ӦMo޼98A@@@j8(裏[+J'<<>qz3% &~_wu|f%nd4iPE yG ,`ȑxbf͚UW]er, :7x`֯_ܹsi֬?+.5Sbխ[|NNNy9°aøYrzjgy&M#Xq7n/oUR̞=ÇHXX`M8>}:ƍ#(((UJk W51Yhh275YN<СC9u}͛77;$q$x yRRR8p ''<<ȉ'SYf厗4깮YlB׮]/=ٳgYÕ^JKK#88X(1Y׮]ILL$;;۷pךPNN߿sWÇ)**bʔ)m۶Obb"mڴaf)NRҌRxɇL!!!nI\'??B Q- aǎldɒc,[޽{ӢE g+,,$**۷ҫW/CkXz5k֬)^N:ѪU+֬YäIS;w׿g&D%ҭ[7vMRRR+Vח.]˨QX~}K3fy>Xz5ӦM]vܹ/8ԩSyWtw9v?١w},];_rJf̘j={лwo6lȟgX~=}'Off(հpBHMMeѢE~SLaÆ;7nܘG}l͛G˖-ٱcJPrss9s&'Nwgo4;4qAi&Y,R 4cǎgC'+((gٲeҺuk~aLbvhM0r$٦Yݏ)X奼y[vԳg4K ZlY$~AQQQ:zۧ^zի۷oy;v$լY3e6sN}ڡL?|Mo^ ,7|#mVN=/11Qnnn^] dd7ԳgOlRfJ=޺uk/_^C ќ9s$ٞIJJu<==}-66VYY_FpZLطo.^4 ,_M=ﯔ]p!4$) ƪf͚LuVJCdBrr$)%%%>^zuIҖ-[ԢE[nbIkn:}f̘l_~7n1 |s߹ c޽zKyHLT5g曩O<׫QF7n,___EGG) RV{ C [{]~.|%**JSbbbtqIRDDo룏>ҳ>mի/uM 4(ZT^ԡC5mTׯ̙35b6!@Dرcu1IdҢEpBL&uE1b-'jrssSڵ5c 5h z!WWW;V111 ԸqRr ]9"""2\"(}@;w2r߹ ܅7qC0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C-!!AÆ S+٬iӦ{bQttUypzgk׮{Ν аa4uT޽;k?`F@bbbtqIRDD5h ͛7Oڵ;#ooo}WJIIш#RHK:tPӦM~z͜9S#F&ݻwg}{O+Vχd}Ю{Lҥu1Idd۔d2ȑ# $9rD К5kz飏>Jw8nҤI;vl{tgHo۶m $}wj߾~G5ik H6VׯDm۶Mf3BytLL&ƍCxd'Pvmծ]#c>p p 8!ժsjӦMFG2exj՘1cd6qF6''W'd6駟j˖-5kq 8 ]v8pdĉ=Zϟlt C( NL2ׯFSN['7dyyyiFGy{{+22R+WT||q]vct( 9@ѢEb b;vTƍէOݸq8( %$$hذaj޼|}}e65mڴ'99Y*Ulرc=g *T({(&I_|?QF+22RWj$~@?\'N&LPnTjUEEEnݺѣ<+9r>ltpt9rDcƌϝ;H 805dh޼yڵM^zIOZF@FM~~~+꥗^Jk*..N={LsW^JHHвe=tU@ݼy8( ao5nܸcIR͚5lΝ;1ڶmYf(( dZէOuIuԹyrqqQ…wssSBti{GmUHJ7n U\Yȑ#sNNjZ(WE&MѦc4YuUOůcw* 0P̴ y5J)%WȮ( VJꫯ*))8S,Gf\GuWw~:uJ f,/*sߗC 6ϗd+ g3 nnn:uj׮?P8+dmN+DjKW( Ek]%OOy(0( 2իWjd2 nݲaڴQjV|sK)͘a{@=,L7UR( Rf3ȀW_g;)`=krEfitA)$DuB6뛥~ @d)Aͭݔp:^fj!./#%&_1\d  9Yjrt^vVR>R &LPKQsY,CqVtE"ֵWXԭ#^M>WB Q@yT\uk(ը!͚%] Y9PZ< ȑ#1bntxsJ[ˠU]n|2R+rvWzu :T#FЦM'%EZԊ+U}n,}67m ! `uEׯ_7:V믶YW{e}ʔ߽#N(̱ߍ$ U~?pml;Ѣ֕+$I_{J?TʈxmP@0+VԨQkFnߗ\ 46!wDoi=GZҾ7 ( p޽{qzotoTjմ*)#jTSGe{$0Pҳk+DCfM2EjRbbqڱCUK:UNکH  CL=yoߠpB$inۊTcު&:zT/~'FLFAƣ-zDZXOA>6b;+wbtn @:( `;vH&Te+MdqdUJu׎1頀l.U/MnN|SʛW{KR\cG@$jWd8IJNv `v5GIRt$U E\Ο,q يҐH.$5on[wߵ ԪLJI{]*l}):ڱ7.d}հaÌ< p|Եk׊&L6SO?I;6Q@nKHHаaԼysl6kڴiiαZ:uBCC|jժut;ydS*TPTT#>S*R>C/FGRWMbtTK ޶ FRΟ?H߿_ժU$L4$$$7ŋգG?^kְaԢE{9auMUVUTT֭Z4hի_~Y/_6:vmWe~U8ʗ.I3fȒtK vC- @gΜё#G4f̘tqww׆ 믿jРAڵ&OaÆ֚5kRMLLԐ!Cyk׮6m^z%EFF*>>QihtzetXҭUw+U`ۃ˯IZGըat*@nCM~~~ z{iFo߾ck׮U\\z^z)!!A˖-˪9JR3gj̙F2ߥNMQ\'[cʕ3M!ݸat2@nBgΜ$.\8؎;$I5kLsnppfv鸀Nsܹz쩣GȔѱj(PA^UU@:r\܅F y$66V...iJdi)TN>N/PΦ HIjΣ<%JHU6{YJVGF'&yF5k(::ZީvOݕ計NG ,Q '3uT`AlʕΜW[3_6:}/o'W7],0~GuE!!!ꫯy_)))pBiXIIIS@@}ݯ_{~T\b=|٪qBiTEO͞*iFGlgٚ={vcd( aӦMj۶j׮ylw z꒤-[y6d֭X,{gܸq "9YzUߤ̔}{HUt [ӟQϫ9U5 S2i޽jժʔ)K=7n,___EGG9-///jqؙ*-%ۨz%#=Pŋ۞9tn={%IǏK1r(ǧPǏK"""d2ԬY3ʕK'Cի:t蠦Mj9sF@1i4qRÆFGz;K>d2I.$oi *]k+"؃z]rҥKرc$$ɶ)dґ#GdXTLLt7+s IDAT|7ߤ96i$;VGQ``ztgHo۶mLzu֩f͚ʛ7QU&/k%֭(#=*կ/ *h!/V5u(&iIL&iÆR k'ؒ:yRɒdl<RP!7N_Νktr11 vTԠё2]:X< O00 GtU;vԛoQ+^/}"RvёJrX۰PUڎ ^( p:&I&LPBԩS'%'' P\nMI~u?eHKmU~+ ~( pJ М9s}v <8ȅ/RR;;ʖ&K! ,P@j׮QF?gIdޖ,jײ*ߪR6N;JJs+ھP%J0 o:FGA. \)Y{tԶёIٲ+yvU+xݰ /dҜ9sRmaP-b@0:#S@<۵ ȱӣ|6mƍ>@YH || o{K='-ԥKҵkF'DȠ$)<\ =,ӯh6mU/Ya%'M,~mf͌BC%I~3ғOʶ aӦR|FZEڰ^BV9Vbb8 =s re~=p(ŋRf̘at))ҡCR kJ-[>ڶUx2r r$___5h@ݻwמ={qC?.65kJ=ft,(QB RޅF'@H&I_~ʖ-^xA/3f~ enIVяTnVHLed1 r,///-\PΝӫ*bt$8l^8ItIjHvu k.a( ʕ+ӧkɒ%=zqʕ\~X.*$ժet$n[bt@CA_ իWNX!5o.ɮ*ʥ'" դIM<(pRH5J;vWTDzVl2:  WpqqY%1Ѷ VÄɔv?OGR::o*ihtr r oooi3Cl~Y.ծm<x򇅨k4: 8p@ʣdn/U"aNFHM&+IY=a9ƁR%??)88%S&jcؤt̍s_6Uo`t@%G߾}էOc I^ڕ+MWHLeF'zUTї_~(Ȇ퓞_!,5mjtc-s(Tn4: Q@uM=zP^믿رR[֩+07y('G$7NO=ڵk'ODl4{ZXU.~u[7BO :7' M/n෼Əܒe)))Zzڵk_G\۞jU1ײZctiѢEڽ{w.jt$):Zzr_V푮)SRJz4uT+WN={3L2d*^b8#wQ&O%KѣFǁNzۖ5Z7o֓O>7xCAAAڰabcc5k, :T|˗Y)Q 'u6;w֡CTti@{JM?yշ~|iΝZx֭+S ͎;S>RPSA]4,ã(\`fԤ#]k̘1ڰa|LB zkȑN V3R.1,1:dG/Jח||Z^///}*QgO?JV*^\:W'Tf#r(! t\>wSUϭβկdҰa_h6laYnM}oXscQ>vo]Zd?z+WhРA Txx3T_F.K(' ׮]3:jƯеŤU3<S=z[o;v~)ޫ?}K( @={Qd ԹBA]ѣڷof͚{+WĉW*Py]8.{rkGpg=yxxD{www!+) ख/מ-UX-[VJ}vѺukɓGV&M&O+<,|Үd$͛vƍ4xzz*))anܸzd|$Jio *S[wyGW)榝E[H11 g`$L3n*T\]]SMIIх LJJJR\\mO>>>i),,,+>YBrsz*T0{NWfJŊIφ'`ٚ={vcd( PX1)RD[l͛7ٕz꒤-[EǷn*Ǎ,L C/~Z.S2F<ɤO?TO>>s 0+VLZ#}ԣ]/o߮5j(g` V&kNK.ɓ'SYFԋ/zqUtttGGGKZrXfpRpA\7;\z-EFFŋvWb3emԈiX %**JÇ7|#I5|p]rE4x`͛W<󌢢4rHz'믧^CZt:tI&W_̙35dȐ{X!gX,5kA6vtԲ.^> 6LEF}7&O?IW~ŠTJL&dflNcR?͚5zyyY}}}ܹs^믿VXn-_um۬۶mZoYnUuРAFGAFi.myb)Slׯ_o1cb/}ԩSvǯZպo_?̟o{@v5<ˑ#G2t^Jr OY_xA'jKbKJe0VÆ 5vX_ӧё VVt1ζY¶v"E(,,̩V<{w=}=j*ǫVMjn lksG>-[6Z4@۷Klwӧշo_-Z43BfM~%٦` >\GѢEd6;׌ svǝNԺҭ[R.q/j.P!ֽLE [ugۛÉ=Zaaaz?b.…5jJ*/rs]@BC8_( ِ{d1y]!3Gd{mِN2͚2e5j֭[k׮]FGBz/yFʛvIM˗נAN+&>-F ېaeʴiҪUFǢdgUH]|bFBfSٲeաC wvMZNjRtd2Ek۶M8q7svŊ1m K؞A *Mdt p, Hv3Ҕ)e>кuF5{lw'))I6 =|Az뭷ԠAeDÇ{ ,.^N=2Mjt:u}yNW ܆, Joҝ0ͬ5 YL:/Үu&bzƎ50S.'kZvm\…gz^u}Yzbl?<9s@hi] ~6m=-Ansۣ1CH* Ҿ}RVsx@nBq"&T~?HWJZiWe{)YVjtyZZ~}ۦzb{)'HR2eԮ];}'Yt<ѶGӎ VʺguWRRRÆgml k ԫ'm",Vƶ{zi z$0 h'HY<[*ޭLHr[u!s֭y l/_.]b{NO55k$)86FP@LoT.D5ӠRE~x jĉFM[*m*W-^|pvTN5lоe|y/TMk{l&V-8~\*Q6(nI??=ݼy3-%oo9aovljR\vk6sfg۾y\V=p+ gTu<%}6NyثEzAOTju( NնWtt횭l h'}LM, 3Lԭ[7uUӧO7:Reݵ[N['-#9THHKW0u=ԯnmw4w/hy-e `9O؞DiNoW1 ՛^ڶUEs  }m޳Wdw3:JUح o]a{ #Gl˅>'͙#J#ݸ!N*!MlB/j|V~ڶ^~Y*ۿoLir1zKjDJIHR?FGiORX㏒>&NAs٬޽{(9-Y'Վ:LnjcLҮMiɒw ON-lnݒ,:tjԐnRوPiju(mm_oۮ-*Mn{Oejӈ59<׌͜ 'e6KӦICږqj5 -9]zYMM֟>\<\ի<^4:NW=>-i.۳ltA?KK;JnRkKIRQbrrmŒ]QGsc ( N, 6'U&mf]ױj] v;F?DVT89^P4-%YWΞd__rww2TT)iS%,\꧍yug36,QBX ϤIi;־Daֵ=M^%/Z)eTMKT&Q蔀1ԪVZ|49_P4FGېQ]'ʗ78`&Y}?ڶ)Sv٬c~3mR H<_ M._JozȋzmC7u\<` H"/#[&!I ~BwKotJ< ժ={9m٢|hV2_{kIuBut;Ⱦ}K#)-\E%kFi{V/#{L:kuU|>dØL}gFGlV=&O̙FģXxU|#3oR]2ʭSF'V֬YJ*iǎYzݲem?\o "m߮CVTT+y&ʯ/jR"_ߌM;^iǫVhLJ49$2Qɓ(IŊVĺ|Y5o+up2ҥ^yM̞/L,-Tz?9ygu]]m?RetLRʶrtzҮnYHݺIozS'ƒ2`TY^Fo-oԑ,H $2l>Vz@rҪU*|^k_V\54&MzK/z8] "XѨ( bDTklh4Ko{bk;XPl(jcT`?F\ 371}p O?۷/zX/h7h *UӰʕgskZF0mWqpHݗKjtytC7uF!2)@2Ν!(~Vo+]uB<]I_(N/Y\!>… 3g'˗W* qpuueƌ ~s'%J߹:/YKRPHț܆`eV6BHII~!4--eХ^ԨOIp\ _id!ĉݛ]@|<< ͟z\ϒ% R'3ԍǏӸqcJ.omȰx1ʟgf,)N%C?ȡNA-'P$Wh3+-kL "$=Sa,VeY^H5(HI }cˠ3vX֯_O֬Y_?tؕ}LeGzѱ#XX>5Gr<ԩCCZwh^”}.VeB H&Ӂ-@N`#ι:-AAbťٳgw4lؐ{2f;vL{T;@I,]~.33ϧnŇ;vJ\ZdI`(l2v …Ԍ~Qvgs !>D$֩.a<3AeBbp钆Gt|lٲcǎQB?uT(P x4}{ȗOT>}3D#6Vʿ{V0;{j˫X~= KKK *'O&ms|+kR$ŶDg̟yHm^S:QQZ'Օ@×_~֑Rխ[H;7LO{??xzoT^h: y0! ;C :{]Kɉ!CСC~GJ(AVN,YIGst^%ؤIrp%tЅ9uR yUB w^:uꄗݻwOҋh곙ʹ~gZj:7{tׯK5/@z(,\}i#@uzNJ 2cDzuV߿GL2?>QdY*e !DD$X1ծa"?ˡ=bORo YLMM={6͛k)Y>`z.<%WW)@>GYf R''hтWhU 9w~(VL]wZtPڵk3YŽ]tŋL05k&}bJ{SI"% (:EJLL | ƍYftNяϕ5kVzɂ xʔAi݆1ۡȨQXGs:~pBpqqIYj5.L !Dj$N>M9}4L:U2j(<==_F5 e 4\]]?ΞU~ &FcSz5iCϤ͛ԭ[5kְrJ}Roh,X*7( (Ἐ17M6~XP~QL )YR=Տ+@f̘A.]֭XZZJv,S<_XvFB'E|aÆ):N9w\:uRt:EQwJlٔׯ>' @tʜ9syǏ+rirEE{WQ.T>^Q%KB\(/*J|6Ey~z%^?-[(yU˧!]+]XitVZE&MUGI׎bLPPUTÍXGSJ;ʯ2`._̦MRyO(? #%޺7XDaS/EF_(:׍5^)YR\{# ˗/ۛ~I&P z1\xhKp L/+)JvN]/_> XYfѿfJxx8w%+Vĉ$4ŋϞ 'O[Orqf*s%S#vR׫Y)ˋ͛7s}*WLٿ!{aĉlڴ|A00߸E^̦J*T\Ç ^cizwGk;4lb/Z=M)nÞ˶..<WT\#G2a„T/>(_ԩUI)\TݻM+Lo]S'Cdd;S200QFlݺ .PNCbbbӧܺuCtRŋS<!p,s6VH5\۶}ֽvT ~DsScsbe1d:)K/PI/t:fȐSղ- D^B>|xe߾}8;;cccxFXp!'OለDGDD`ee= Hp3Aߴٲ}DGGط\]zu%Y@y $He%J9:t`ƍI>WHR4S` !dn4&Eo/҈!A{ OT[|MGL<VjVZ+O { oo(U zx֡׿?|HŇ;5ϨPX^=oܤ?5 GH?P'gy)-[dȐ!ĥ-,@kzȗNHbB?w;Vݕ9r(YdQJ,?^Kٳg777%[lҡCwk(-Z /Z٣|fB$[\)(j(q2eĈʞ={R5~UQ SAʿFEhlJ8AE16V;oo~a4R3u]133S?^))4TQ>U~RC񣁲s 25 "dTVp&LL-{N1%Ν0p T[sm1Wn` k'Ȓ% 7n\~"֧,0> =''Ul%ֿyoeo)/geXv-seΜ9L_ 1K=|H9 %A`ehΑ<ShS{] GjTٳa`dMj't 69׺kv_J9$^A۶te 8puFf֭[ $èusLx6!It$wU0~GR _r>\:u@rl)h~~ZTpppkSXǏ1?űs.bKS[|}!%K^zs)>B1-H"D߯igP=Kgptn0v,> i.&=|Y]пMd: :uq̙TܚBJ1Ш-VL0ydvŋ؜6CTQ⽤iGXcI^`Ir '3t FO(қ5J"\llRLp8O# ?GG?֑")@DaKG]k4 YUkŘ1ZJl,/xRi;tJ"44T()l:F wɓyֱ")@DR:Hkgc(s4k֌~qm0k,_ڵkɖFdi7y3P(B BnR}ȗp։D9sQ!R胙3g( =zHS{̙Yhq000tZHֶF[{d"}D_oF HolDzb wyئ' Yftؑ˞i,A#? $L84i$]D !27)@^*WͿv@й3 ܹܿpRG)udz SSS5m4&NQ2C܉Ő033cÆ ڵKXBLN ʖUΛ0}:uvv0kxϞA^vg&۱=̢Z"gΜtNuL%_\V[UK?:"D襢E!{v t:oّl]eP<3 i]|ٳy--;a>x!~[ ۗsMx!4$K'O9vPm,ov~W3cq4lڔ`Q =EKfA>@A͚52dQ҅ȡ<|73sLc !21)@*WKCurnn8Ԍaɢğ%KÇvW⃂Z*wޥsZI:.Vk+ٳgk׮̝;Y,'@ ʕS hX֮?0˛Vѣ1oַ޵' ccu-DHN+ LҨ;%lݐ)=y$EKm۶jժannΡC2M137dz:>}5N&ȬzlYuǬY ͛C۶/`p,\G]eT ڵկeVԶ-n N&7"# (mۖ&MOGLL ͍*Uo>lmmS8~{R Ǹ*C IDAT^ZXBLJ ʔQׂ|T E0!E+7mzf$=sGs~l qe8 HFӧ{TR,Y$Y!G|̘1)SOΜ9S1~Tk֬8"D-33pvVY{BSgx4lCQV/HiP Ȫ7lu /^ÃkLH"2 N-dQxN(CsX΅E /^$2탦MV2^3gpau$$6x1XD'J6*l4)D;enl {UƜ9s &4СZRbnp:RE(VL pK_ D2p$yUSvo_f=z P !2 )@Dbf.. yyO!!0mrJVFTjz oEBt>~?]95&DQmcniXZ"GhLYH iܸ1VVVd˖ GGGO`177ʊ;r]~ ͚`n΋?<</ jzЏHYHDNT}.'I(F&Z"˞yS̛vfffk׎ a8!Df H2m۶Ur]Fɴi <<9aaaԨQPƏϠAՕD榎pcO=ff\oM"+wtNggkRa8:7ֆƍ&Dfp;eDy3D۵kWٶmɄɣGر#5~yƍ#::'N`kk @Jpuue…t="dk02RGAzV;ۃCq$r+l\njR)@R}߰wu[1ǐɮ/ԽXʕɿ寍9diFND`ͣUot: BJ4L& Irױܜ9sJpܹW:+VīD;wڵ xzy.KE=&v<*ǣQ8;>^yUHBsoob˱."ӯH#iF[o߾=?;B!H2KӦM_>k֬k׮̚5.]@]?~߿/@977x~QU<+AyaF>Х&'oߛ"" ɓ`i MB/ )T娈"n8 A"H OΝw/^`l '~qX!2rs\B&.H[+lll8wKp6d|^L05vzmm ӧiCW!&ԽUJTuX?_|1KKDIN"ӰiG d(W]veٲemۖ3fкuk/_~)ݰa033v?VZ[_YS-Rׁ?9sBz/ R8Rs0]nAqv^'2:vT[φP wO&8X},jgLZ'H{NFtU7?k׮Qvm.f9BT#H2͚5>|Ĕ)S3fslmmٳgvvv :oB?tA`:sԬWH<`jaʭc(O P:ӈGԪ6ǃʕѣ:41?Kp0dw^]u4!KU;(;%_|Q:!DF%H21rH\³gϸpOt[lɓ'ܻwŋ'O  (ȱcPEǫV=D 8#')SP-"΁ֳw/tF Μkԩ^.W_ӚEp0, w!#7c !2t(dz퇀ϙҾ}{-ZD> !-)@FFоZ\o vvjq!8]Ϛ8yUmj:ژ!uW?:wC˖ukBt\oKUio! a 7odӦMBdHR:uGԯ*@ Peͪؽ ?/ÇE? XZS"6oVݰApvV^w\]Z Hw ; {r율B|)@Dja`i ǒu֒%ɓa^>;Vv-عS]PjqwJ /L ˆǃ){̓/BTNۓ///o ф B|_UkWeU߽:&MPxW0a:Q4oN u)8?ۨzjl:.@={{3nr> s'<5|V_Bzua}r JAڵk/&"ÑDP.{;7_]ԩFJظDžS=q-zuw-PksRG`&#ɿkQ[8~)V:LM_6՟n!<f<^g:4= va}k,ZNCim=!RN狸S˝PML( 8::%K R !g V#={VEnj8dw3a}\ )|sWuXҐ?$W.+D0oşcp4 z@["l!/'u)C qQ<ܴ?ɧ/^ ~~~iLQzUws^zYe׬ 5GZ֣gzTׂ*ѣyVVfj෷mGeWvm9WWPG^NNRBh-O^J~}ۼݻ7ܾBLG` gt:^.U/WTլk^> ov[ΟWGA?g[;ͪ)I>߶m[LLLXV{BBKӯxϿoF& ZBE1k_xtȑ֭[3o>bcci߾=+VHۀB#B!F46ëk<5j122͛L2% ! B!x/X@U>o:tÇm@!^D!WXXʕa֤Okذ!vvvL:5m ! B!x?cc_WvħҿVZEXXXB)@Bas8ѣI֥K̘1cFB )@Ba`hHp,,`۶O377ˋٳgzA !B|%|%S@ǣGؽ{wB)@Bq<< 9|8vE4h m ! B!8At4 M;}uB)@BqJ{{XK%"g;v,8::&z.88wwwͱcǎܽ{WB!D i 6lʱiF aaa7lٲ=WF BCC?~< WWW^xQb!35k񥲏7#GFZg Zj&7nќ8q[[[*U+ .{ZDB!> R1l 8S +?^)S(JիWS%J`ʕiW!Hд)ά#6V ! ..~ѽ{wJ.pܹK*Vȉ'"B:5u*p~=ÇS?"ݓ̚5ѣG'|DDO\Bj ’fu Ϟ=~c٩MILcȑ9++$ω$s B!4mBK&2h {.wG?pm|||R9".Xܹs2e aaas]F9^Oz5mXYYall"1OOO<==S'B!>S:<2СO/Qm۶exyy%9K@__IGGG֮]客( >'O0uThѢ-",,u+;vI~!"%]pjM]p-K߾`l I|@Rhݺ5ƍK.dɒ%m !)@ʊ&M$:>yd7nذaXjkf<~~ '''tfBb"sk*AΜf8::qFZh6A,BO:.Fٳ;;;۷o!B_/d+Vv]_Hkeʔ!00͛]P!D"# )`׮]Iwpp`˖-iF!H660Vx]꺓3PԻsvvNBGF@BI Enǚ.iKI"BObcsRkJxfD~R!XX@֬pd{hD~R!t(\0.DAR!(;t,ŃVa_ BD!/cb6s*<Xr%OBE !B|vPg׮}=>}:JBtE !B|2 ؆~ IDAT<7bɽdMСʕcǧJN!D!B!>٫''}{o CCCOΑ#GX`ABR!⓽)[ț]Æt3ZիWoaСDFFxN!D!B{|ǵ6ca͐ÖCNCœ"CIORJJo|>r3ɩ9llc6lٰٮyo.{]$n]85\з/R6qq<_w%55W_}`+)"ܲRͦkG7P*???^u&Mƍ "Rh(Hqqa_d4NMy>}ذanZðD0)PÇD}C-V?-[AD0PUݬsG;*"R)H*]v7},P8ʉ)H7+')Ǿ4bcaGLDMDDDD \n,b#6ֱS(쓔t?^С;V"h """b 7f a"ow/lE!@DDD&éq-R[c̘1̟?`+)"v""""6SP*|az@ BNx9p@VRDJDDDDl 9sY6{@, SL\rtܙ䂭؍Cɒ4)p]Ã={пVkSDBDDDDltiߟ}N k2~pk[Ə_puQ6 `rڵ+//v*(u_ȁ ѣYh5j(ʉ=)]}-'''x؛؅fK΢qꈈ(/E|Nܹ8Mr+|S "w(]|4 3ggϞ6MJӉv#bǎ~m?Zp|U㭷ۛ{we˖E$@DDDn*U2`h8@˪Uhذ![믿.H(XDxO2eX`}_~ >6%"y""""vS,. AA0lG\\\/OOyHHH(H(]@ZpWI/Y ^|&X, <+VJblr=瞃-qcX,} ֭=^֮]Kmv?3Z&[C0x0\dZ,][DrO$6lСCY&ҭ[7bbbk.ڴiCҥw?~)ZEKacGWIDlL$yϟO˖-0adʕԭ[7ˆG4i҄3vX{9~GZlU8DDD.k mC+v1Z|"wʣg}g֭[7nƍ7|1c8<[l! 4e˖|<HaҼ9890a|3C6oLϞ=X"}фuQHEFFf)((0vޝY6o<ڷo>ZhApp0g϶[}EDD 3h-¬駰pMvHzc"##0`5kd֬Y۵"w`Z9v^^^9rDl֯_-[ػ"""V˖t):@0|8kz2k,lBygɜ/Ed `ƌѭ[7v'O<Z'a~mU'"" zj8p !RT)ݻ2dQQQ $َ/QDcDDDt W?pOV({bbbxꩧVF$=Jv(Ws\_ ldqȝ w޹j/F`hxmϡVZ0k?-pN>̓>ș3gXje ux<==qqqGGݻӽ{H2n] ]XQ&ezC]zꩧ s;:R@fΜ̙3:uA):,VJnRRRhժ[laɒ%4l01*TiӦ̚5+KyHH+Wfټy3cӦMԭ[f)bcn])/y9}WWX2,iFiiiiу LZԩ?0ځ:ŵ ,[t)111t^m Kɗ ˖5{:Dz. t+V8W8;;3k,?>|Gԭ[ˑ#G]MBC= y4b&L@r р N:xxx0|p?~<+WfÆ 9R7cnPrenôK=W,]fa.X Z]pիWpB/^̯J2e]-) yԬY3V\IN?6BZZZ;wg~ՕvZDDNP<Wʿj1ǗEc}~o&`5$Vܹ@J*MZiz-_<dž?۰6"""E'>cZ2'Mxgp.´$7ڵkGll,kצQFDFFҨQ#V9$Rh:zAf0x0?Wñc3f$.gwL_}ʏ?LZXx1QB:vȺEnBbI qtE2iBD˺ܢ֍_W2y-4KDDDn>>x1vKopBMƀal MXev.z̤{2|Ν;ԬY5kҳgOJ,i*K!X"""R4+Fزg 6m^Ɍmkh4eLfҥMvZΜ9CLL cРAO?1dG"F= """Rd/.6`@m.%auOדK</4@V6sB]l_#GaD3ǥ0qrr"(( :uYM*;`:cRfMn"wHҾ=-ӶSz|CovKѵs:͚6ƍpP}z@,ɓM],|ԪU%K`HTTвeKfϞm@DDDDcРgu,ǗV,/Ͷm8j,!X"""RСЧQQ?+"h\G˳|2IjwWA8u 3+eeHI1xz~@֬1{DDD+WұcG, Jhh(!!!秹(E-DRc4Js8ڼw(s{ӴC ڵSoJI1&nnuflXtA2>賺 fN={?={{}q%/Nrr2>z@DDDFm:@T7x7% m@*,^lNY.{ٱ 0 !BfIUmۂ~qf̆ ez㰒#GEwwwR~EOllMO<ɓ'^:AAA9)D4DDDDH BˇJ6;,X%>+|̅SP*Ra!;֞r/@T,i -[m1 +- >Lt>3ϛ^[Za4ѣv BBBhѢM̙3̚5ҴiSpwwvL>*!J= """rG*^//FbM ~y-#i2}>mNߍS(Qצ 30ogV3!J3+w"-|]d>?$ԩZnnP\ń0Cj~1yAX\#?\;p wLό-tٻw/111ݻ//A̙CժU3pS,4fʖGa~#DO˿jV^Me4K]}LX&դruW7!j<7}:8qer3f +6m3ü,3Q>4<oivx p9| \r%s&8x0L}rJ5QFٽ{7o&gϞ,+_(ʔ_9ua wqHa""""r?Gt $̴ 64[nCV&G\p=X(^ћٳBD[..`~,0N[rgx˜cPŊ_J$UXB%a[Z,4jtYj= ,] ۷!Z'1LɂR3ԭ{In3g6=T$c~/k)cZ]-0|| !zh~3$-fcf?0C2+fnH^+[>|С?W۷xϋEhoGŊ_csGM v I/lIS}xN|_=@ NNfhsϑ9|**_|ծ3Q6ѩa^{Xg*sl6% . 8m[gaZ[+D3WE^ԟOzK{>l =իǏgAIK3gO5Jա)?3o@1fJz [Fahꙹ@R@DDDDr(U 76uk5oR2P׉?ۻ0e pF >86q<8N._ 3h =|LO?g}i/Fpe_H5-@iYN8üyf?_ VߤngߥOLȻ\v$iv?s/4s|fA`\s؆H.V̇+$0u]ի}gK4tRR!z0x{4x? : &8qq#;q6*ŏ@\gl7 p9 ]rs__C1_]~__|*pŊ/6pR z1 Eо}t>gte7{@/GO?5@lGDDDDF:w6Ym&Kp'1.Z0ؙ<.|.U 1 4SJ2Y,fܔMg L*wvuj;ʊO1uQ>156r(ܞQHHδʜKʂJZ|_~7><Vp7!>|_ڷ>qA|rPЕy ˖zYcszת>,LP [2U˾3_~1Kf5̻\h\Y3:/'>Rjd;w(3! -Opie#Gy⁣DU=ƁR={\wRߒGqTkK{IɛM7{/·)Y·g~[mRD3\+,|fx]/jN޽; LII+07Ӱ!gBGPt3^=WBlܕ>|%:g]QCqh%Mn911Kq ̚ȞՉsMg"GI۴IgqMC=./ž>zS"sI^< yr/'vzR#5w?5L\پ^<6o~};͊Q;wrkX37cDn~ND#~Zj`6'f:΍: 5jP ͬh|5UK}غ^y2#D&Dֿ%1pxض 3f$+Og-S.]jjX7>8s&= `x 92;WbvY9742l8o>#\?o6(\@g؅//PxɜG1|b?W6k?N'xqnl 󘱚2"D $67COsZ g&H(޹fӦf.jAŊfhYp 7;vWAk_ryYM0 3^s͛l.&M棆͇w7)gg3*/#>̑5C?kL$߹Pxah41$c澄Nrs """"wxCCMpe IDATJ/H^HT<:ٿfMsݦMIKUǎ@+Ɠ'IN@DDDDp$ïl!*ש蚘 ۳F65 ZҨ9>݄k1y_^/NDDDD{@6ɭkyn6|,^ :=?aaW_,#,"""""Tv{fz5,T)wha@41$%/:JMMeԨQSdI5jĒ%K]-"cG&Nu=7 O> 0m[-@  ۗ>^z1ai۶-WvtDDDD#aӦ_9?:M /7e b#ׯg֬Y7wyl2y]=)$fΜ*,j;ڻppr}Zݻ[f~[oy˗=t 62w\+3\]]߿?k׮ȑ#΢,jqc]ۄf]AFlBpp0Yׯ֭[Q- 3z7uu]*>>??leqqq܂h8{ڷϺ19<9 B,QD""""R/~DOFHMMVڵfԩSl޼;Q{YwCOFrfmIQOQwE}qԩS+VDҥ3׭[@DDDsظqcfHO$,VJEׯQF?g}0;תU ooo֬Y؟z@lAtڕ_|Uƴi8tSNutDDDDDB= 6ʫ]6Ge˖C(h'tB 55QFOɒ%iԨK,qt$VXS_ׯr]hӦ Kӓ޽{sq\nܹskiӆĴir<6/m;ejԨL8і/Cr)ݷo5jjgÆ :5kN`` ݺu#&&&۱zorzoҥKzjk͚5֋/f)(QYvѐ{i͝;bŊ1p2WWWڵk9rk'jĥKr|~޼yoߞ̲-ZٳUMɃŋܶ9y$r!C8w?cɋܶw9sǨ H:8$((0vޝYvѐ mٲ`ݳg ٺu#%_~-[7777oΦM2;rs=Ϋ_>[lgUm3|uIF)S xzz2tPΝ;jr1k;Ks@,>>??leqqqWWWtB۶mbǎ{w}Ywɓ\xQ@nCyixWxq<==mߟQFQn]Yp!~)۶mcŊ8;;o33f ..z {Am[PqꚭD)22۷oO.]_d…{ )^xquuտ1cdG%88_~sҭ[7md 2(]ޠ-h<%%%y):UFǎY|9V5}wKۺq…#GҥK3޷GҮ];ʕ+ܹs3W>{h^{_`~~~9vetۻJbc*U… ;w. ?z?nSyi[???Ҳ!pN<nc%J|}|3g?EύzSIIIY׭[@DD#%6~pwwbŊx{{aÆlǭ_^K֩S ۱7n$==]ncIII?~oo2wᖒBػw/ , 444zo-7k{;@K._d2uT5jDŊX;ɏle۶m~UVe;wff-]vjmm7oN4iR'MDRh׮,&555/F @6m2ޅWZZݺucݺu̙3 xECn[m۰Xo\nݘ?>#GZjL67tR7n-j޼9%K$22v_|+k׮%$$0;֩SNRRǏrlذAC 'r)ԩSo F2eԶ&MbȐ!t҅VZj*ƌ /ਗ)ݬO^/Gnf})k^իW*UZD wm7nҥK9^S]4m4mrrrr۷ܴ۶QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ & IENDB`lmfit-0.9.7/doc/_images/models_nistgauss2.png0000644000076500000240000013147713066042256022117 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATxw\u9l܀ 8s)NT\i6LB2MoL-ͻ;Z sJSsbU8dp:s.n#"""""V CDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFTFE=j2}?}Mff& 6j2~|:u* 4LJu2i$G/""""R,(\rIٵkM6bkpС^3h 7n̤Ig7߀H1rIPPǎy'fȑOKK^#22ٳgO2}t~aIII) """"@.$00׏9{~ҥ$''3t<LJ Fjj*1117_H1r֮]ˌ38quٴi-Zs<,, ͛Z+R)$3<Ã>H֭{]bb"nnn9鉿?Gut""""".iӦ}v͛ץ9///QKS)g+/t|||=HbbM*""""QjUVjvŖH!{dffү_?<ÇHNNAժU&)))0 hBóDDDD\XPPׯWA p!N>MF97fƌ͛iҤI^"֭gϞ׭_͖{J=z3gҠAǽq#F dttرc< 7Hνޛyꩧxӧ5jK.1y<dɔ)S^z]  bŊ^"~.~.~&MDJJJ Yf4k,krb5jԈ޽{&::aÆѯ_?wNll,fb̘1TX9oJDDDDą(\a`X?>b0p@ʗ/_ 2Əς  eĉ >勈<+8pЯQ6磢DDDDDJ mD(b]8ߥߥ""b"*].].])8qqqqqqqqqqqqw y34n [9bh~xuK g㏛[ȟ,b9hV)SyػׇիͮNDDϩDDy]8svX0}̭MDD('૯.\P΅6dg3bD`nQ6]kN"""!X""n!8^x*W6\egcc6MBvvժ]"""@DD\If&<<< $<_/{8ܦ/>/= }BVVKk M_DD/h&}mwj}yqb1FcS7w SJƵí6DDD5m1CjΞ^V- צ""bÌ3w7 qOd_J"""HDD$Gy/{;<' 5nfO=m}˜?oɢTDD( + "}C{VoV+DGSizzy ""@DDLph6<= ͛ssKo`kR1AWQ=<:;p-7ySp~a)""R@DDno,z.{qu͏oi&$g[ kx% ?6ɛ 6o.""r@DDw9߀-wauO m׽|a\DD&)8ݰ` H`kn?YCϝk.""B@DDicC;Hd ~FDDDndf#vXUdl}l+"""@DD(11p<$G0x0|9kQXq 8*eL -ZpVΞ ǵ]:DVgp\C""""" 6AZ<d'ᅦ(1;`#c$6&""R@ ""kxxͰ>r|DDD HDDAvf͠?;$PG@r'f:1Rqݻn]vf`A5<|aya~7(""@DDd.WWWEF.FV@9Jv_[b99 8u ^];|5ˡ _jO>\}}:v5,""صxlb{?? Ú9~y CDDrHu_?.8unXS]8K9;a|(8bcp}#@F1xaٓ;XtRD&|׼DEESO9CFFFKOO% O2q2=ͫ.KDDJu~Hdd$}5VJvv6IIIyaeddLPPu=bĈkV0` (7 "EQ'Ԥ|:fs]!!א Aw6&@lvi"".//s,%%ŤjJoqҪU+fϞzmGRfXn]!ׯf5'V􅋈< #w-\TH>FW5.W7nvq)UH;vW^ԪUEu;wϏɓ'9>ydʔ)C^Q89qjeŻKVjۻ0}#:ena""Rj &M"%%%w ñX,y睤/p!DGG3l0G݉e֬Y3FNa0[XThft\u ~:~%"" W?~<X,ϟϼyX, 8ÇX,9?cy6*2d? ĉ>|ޓ8ѐWG PTNH&A}nG`|3>)@pfQQQDEEhI"~ݯfʔ瞃6C !3<<̭UDDJ&AIIY8~t10n:(~>rl>78a^}""R)ܠ+vKڶ5[+ufuŹsHQSA+V@PiӯftC*T+G|XciSGQAЩ},[Vl_'86Dt`@DDq@DDnsq#S}9Nժr:1bEqz5lRZ] /ۑYN* ""8 ""7 6!`R(kél$[,SR+V@vYXV.vgr@DDa@DD )- ֮knKL9٨#9B#} ""0 ""']=K6onvI7%'xwiV+-SQ)4x8_ayF1/ ?Q5ޱ$%!KDD)ɓlc&z1~`k:Qm2v;IIfW&""%HSGǎ:LMh8HMb~:|9xy?b"""""R@qqж-ԪomvYEbEMґ "" ""tT%o%Νâq JHP`N8u :t0$ؑP{]@ ""G@HX,UED`B̮DDDJ HLK= qqpmPe9Pr+HDD2CCի Kh2DDR)1iرX;ٰ#!>RDDQ)(_8P{@.0&ۖj-8tP%9T:lǚ]0 ""oJ%*)Z ""իeoWp9x'N] ""p4Ν+$(W`&W#""%_HM56>o|>ܠeKKr8oo6YXf4"))@DDB 5WC2$ UgXxjDDP 9W\~u%N>s\hv5""R(vBDVV58`v1""R(oɮOcv1""R(Cjcmښ5.ǹ,Ѫ"""ECDD/$$@Ra~,a K@DD/kKxӱn`v%""R( 'l+3fX+@DDO;4XZ0sxxpN8Ēnv1""R)Yg4k>>fc6c.EDD9.8mKK[٥H1""r~gՆLܱ-<9 ""1s&g.%fT< f#""ŔH>ΜWkUZ>Ω+MDDD+|xJ$|\%W "".m@}zر=zP\98p III^;uT4hueҤI|"R6f=-(iv).+u>s f"""Ō%'O$::]vѴbÇӡCرcy[ndff?fРA4nܘI&7nSޓܘrG8*]lӌT|ZaX""R8f*8vlذ-[{ݘ1cHKKcӦMTV VZѭ[7MƠAHKK^#22ٳgObوfTX9oND a|O&pSU=#&kc.GDD\I`` v͝;ХK֭4.]Jrr2CaÆJLLL)q0DPa*.GDDB8r'OEלkٲ%6m}׆aZټycz5+$-fW|}aW^.GDDBHLLjժלZ*ɹ@qss# usQ,"[4 !"""Riiixyy]s;5iiixz濂Wu"BaFvVT)rU|o"""R>>>\xsy!##sq#dfW *W"'sDDDU !gUP+%&&ǥYUV%;;<ð222HNN&((1 m^ lHT q"{p ԬivI""E//s,%%ŤjJBrʬ[sk׮?Yf[={_~=6-ϵW8q"aaaEXH\lI9o2Obc@D7Ҽys**4~-ZÇs-Y={ܹ3~~~L<9'OL2eիjۍpΜA= P2IF4DDD L= W4i)))+T-XNyWo;xg9w.M4Ͻ7 6~ѽ{wbcc5kcƌ&"&>3 Q2> D|刈H1rba̛7)_<ժUc}N2rHnH)R\X,=1kElC^s[7x-%R?[$-ްpg}KHff&{O>fѩS'̙cv@ %ҁXJ_e\"@Ο7F H _̆=kjصH[fco@8QQFIIqҵkW:u-܂;k'dժU|vC#> nZM/ 0ysqln2Χc[DR)F4xCm/-kڞ=&(RWqRF4Ok]#\je] p9<4DGmȲjD,*` x Т恈HiRTh?ʔG-weHaq5k쭹~+:@pkWS>:dg|seFs _}e,P&lb|hϚ""H1Ӥ OKa„b'RlxlX&thq)gW\ժ܌%KaDIIP/*r\_@PPFYYz@D4QqQ ֭xKxxURWmiS㼆aО=I;{pݍC{ nݺ,^9rs[]v4z<zx޴|.yX~@D4QqAvѣGɁ44}USxmhؐg~{^Q) <:XϞP`ǶmxGqww',,H9g""ƊߖfWP+Wb_~]o)Z||ZR)@\baΜ9/_={{I//|8YN: "ula+7}9'믿2}t}mڴaWfTCS`ݹƍƂ_?|رcpmW =SY\{qT(|u$n""\2?IIIӇK7lhʙ9/3z?"R@ޛNjyeǎ+FKgRvNbq^vÇo]eʔ)\ɓ' #]'8z5Ǝ˻i9Swm|lVQ:yX5z̟a9|Oj#Ek "R(pfΜٳyWxA9س`VhЂuxXx J'"E%;n-Vxu wj}/fĉx{{;;#Gr1Qe# oͿvsPTIK3v^HQ>/cuXNWBF-iC*HR L0qƱb {X0>}kZ#?#yKqiI VL%6xٳw13f [mTJlI6ť}TիEx1c !b\[hjYc_?ovSA* !5%"R")#F`ɒ%DDDP|9ld, =|JcG\^HI1zEĐ"5yKtww/>q_*U7O??ph[ݻmdf?r=!NYG38~~є2E\l6:9yU)T,k]= -[W񜈾d ԭ !Cq8ɖ-r06#\W@^>p0/L!"b& 33Kի=3gzmGoMӦg&+b2uͭ]IWKa,}ui}CCgH\:o 'NYqgj'*=';?vH""@<3v!9IaX-'̮Z$IIv]LWiun~n7z@j.$5㮪୷ݵ&`,ś ;1/I,lxhFӊݿR), {fɌ=r`<8x2_z zGb2j^ @Jvo… {9sm5#{?tƹsFHHH 6lz|4l#FP\p$|؊3wXzADdR)=z4o&| +^aL~s\;$+ :uH{JM/_+"R( nnn̘1vѻwonݚ'3j6SY6nĚqմuxyС-[tlCOäI믐p[OBVq{ cNLHqI;H% *[!]U&V~21H ԩ93# mHC}RZE/{4- 7j֭\gyqܠ3h >#Ο?6zjՂ7ޅ=ޞfD-dDюөS'cV+[:?Gd<6ED̢R/_o \{ۛfSq2@Vq 5n0s? Fn9wovPë'?Ҍ)PEi+`_4qWA/=E8 )"bRux1K.GvXqfΜtիWO>|؝1[{ɝy^ly |15Qعcaʳ\HR osˮO_Zؠf*&DSػNT2e;"0l0/_<=aH>x5f[SLȚ5Yev6m"V+$ty){aJ-"l P`[kgl‹/w6)6.m@TC;{/UVu\#E;~|Ayc^(&~7_Zikԁ׸)R*/=0 &g> ΩU䦭ZEzF"u], }tw{`vY /fbJpK,Y4p)2e5q>/z~10s2g^fb*k9z "<_cm b̻h__(_ޜr:1Ks )b СC=z4o5MM Ƥ z13g^ҕ=# RR`8V[ \W z9sl1(׿``c]a\xu=IL4z?o'2W,S)BD)B*/2 `x7?ze#'-!XNecVqʣ Wk>6S>llvA?/UXHu0z4X,= [ }`+DD(B_ > :z!5s^W;sƘ/TZ&;j䇳sϻBGq'niqՈ8RÃs2qVVACZZ={.+٠ѕdyxCXCXp!)))<l۶5ktR5ھ=hWð;g]lMB F@1 Қ/sk w jXsa.:vN6`u挱+:ze/'A8xz:3fЪU+ׯ;mFݺu2eZ|&4(A5g݇O椧É+pktgw5"Yr;{_MO?]+ ">b?~~~1',**yqʙ˼>??@[v8Oc2G_JO2\٥0W͚gԏ$'h+iG:&|:6p@v;3gt^aaд)~ʦMkje4F .1 fMz5ʆk ).@$_ʁ?R&@fߗzIT`|hD\\rӧsw;[`` }aʔ)v4jA߳%rsZel;o- ,3wAϦH1&:C r]5jd7sI3kz3CVP?V\+){:u3p"ؾ};}aq>7gGsXV9;UZ,Ɗi9= f {Q ذRDDn\WPP;wΝ;˵ xe@K ۩~Ϟ={tҵkWBCC;B,32MD:˦^9\@]gGےb] QjР +/… t҅Ki3Bq];vP)$);&1qj-Y?B2d`]b<]v9u y7 ȕ' "R<ߞN~zCPPeʔADGGv^;vG+WHRRIUߘ5رZc,X3g0f_yyW={6[laڴi澉BYX!={.&!!;abM`2Eݣ̚enRx-g9s;aN7u\7%֮i=^tPb=jlz@rTT5']H)ϥt[pssns%22jWFҥ ue+&^&/8qii;.Ѥ ,XÇCf.؞=x>Jkk_ӳ"Cv-ZwdL$1bC^G]#j= eBŊ;,Y?橧 =DD Fx T“O>ɖ-[8t_5}ÇLJ#GpIZhq[l&3w*$ooC н;{n¨xW[_"}gmgDGÃð.\0H|96fv1R9KyN6v1$txiLf$~k_n|j^wӧIhUB)>@ !((UVsN5kF8:1Cb3E(UC--~C+ڪZ7:tޛ{o[$2 2Nr2\|7}Eǎ裏% IDATntʘ;AAAinHH 8:bGz<< |'Ӿn aaz mθxeOwWϑ>߈ Hf3 nnopTY6 d ^^&.^46/[GӲR,0ցl%+V""iH\zMb6ߘ;w.ݻwݰc??)N v}O>gc} >>kp"%J@`A* 6%l׋/K.\ҮC*Ù&sM1M7G~4Stj{Hv z,8hϕRui`VE$J`` ֭G+tڕ?D"""?]d89. rAik jn Att*Bk/Q;N6URxqv]z?+W>_`Loɿ/c" v24wzDɱ\p"xMcYI L}NJ=vKd s*HagҒ͛7SR%gBp˖-믿طo%JMz˗quuO>Ĺֱc8[}᭷\yF ҅}g6 @!![ |V?~%ܺuKݡ)spp_~@/E^d2&<7~-pk"i|Pϓf[(/ag>}Ԩ@v ~wnH["i}#.4vY"ә>}zko߶R5HDFFctDEE?~rΧ|sc*V5jI/?Jy-%se@ݻa*U+y때kxp?7$9s_h]9xט4i~)}G[n ׅɓoAa.ZXs>z6e<~ooWj>eyc@D,i_ٳʕ+[ASۛ={p8קO-˗M6,^Ƕ$Yf 'O]v)ZsJd ɓa2tܹov͛6K{ڴiԯ_Kwݻwرck)Ae_bSpmV4֚=k/>ΝiSr؟,K  SÆTJSD$PIcccCڵo?~<͚5ctޝy0h 2eDz7n~~~k׎ӭ[7+S\9֭[wQQ,rq͵ݸrscJ] sdr%֯_oa~ӊɤIRu;t0䓐8k̓'`ڧߤP'z*Wj;Rdj; ٺuG8/_SR%~Gٳg6l&Lxà 6PhQ #hѢVzlٲ[췱ܺ%ж-+Ç[BI,z k[3gbooku1@2[n̜9{_k0x6SDž ~wXAc2\3ʕU̙'|=7nX,xQIjժl2ܹCDDGe盵ҥK|rBBBy&'O&W:Yʔ)Ê x3sf޺Edf؆g0g?n %?ȳ*T0} ҿ'6Hz-BCC={vfbд)D):3ڳq9b,"_ȘnG` վlJqجZ %KX)i _> zQ%"i$RJ1gfC{u; f$=s֮1S#| oӦ ~MK<==iРGҥy3Tڎ|RbhЀm.] )W73 iK/_""i$%J?7lҥ8~_|aljibR(u%o姟~ YG̉4YiYzұ?f0iA+V-JGdz]5՛Ҝ֣4GqKy!m+ɪp¼bqq(N^oqva` e$ԼyЭluXtZ5~oލaO8;W:Ůfl)=;kX1Lu7[ (HS8u aO{!CC~XCbhVy B,.GIBWdd =~=&K9c_(?6 3ww.d*AQNDRs׆mqvjՌ)Y=%eDGõwZ ?v952Zޥ`q 3hxLx_o2DD^Hk@$YP l/\1=)Nj<իP>f/nkGи>r6FCe3vA[n}vl] +W]s)Hʖ ,~"~*Tazk'iM` 4`5ΙH2[X/V1Y32zg]UZȋ(H+P-"j~USGD. ^f Q5ꀃ>|8Ȓ~v%Sry9+7[R\M̙ɜy2[@D{fMXψ~N:e>ӣ۷oPVs;w#F0e6lRGZnSMD`Hgt%,lցH8n߈4il>WX[x7,gzs]J7|CΝ[.߿?E-$-" bU6}`ƛL_|1l$p?kti9m4ʗ/O2e,gz7o^?~KI/Npp0!!!ٳ^zl2O I:|ؘc?E^SD$1@ĺL&LFa2~({&::ڕIP kwErܽ{ ұcGݛsAkBCC.sTT ???N:&LC\#ś{d5 KDR/>[[2 j,& {Z*I.^Q.ymڴݝqYduV7o^>/Tݓ571&VoII(IBT)PIjbpr ЧNJ:uX镽=AAA.'Yԭ["E뛨> .L-\ٳկV$@D$>@$(]+'.'V$CH+W{_d$\TõxNwV^MN,_FЫW/4iK#GңGwڵkqwwvI% V{‹EDKDR=}QGNp^;ڴdfkW&JT6VX9r0k,ڵkg3[Ȫ5syP] v8;…xd%ڈ|rIJX#q ^MzY|9\z"!-(kSƌӧ=zE۶lh""I"i ˉsOhƍSdߓ+9Kc6'=L:rm#GPpa9bR?FXʕ+G޽޽{r\&/Wj. ˗5Va{.4iB//̈́^įZλ.EI ,XN:RbŊa2ꫯ]Sm۶w}+9sfk_ͮ]Ȕ)̚ı5qڭ"(HB[g@˖`o %u2G) ۶(f͚Exx8;w\_|gf޽.'^}UUƸqRUtqqH"^Z-"X &/h)m@MM-\/q4llX5rE ]vTR7l}=^}U3g.)E~&΄s=.ED!IG X֭!*[fg}+He_s,bZP=9sBرcl۶ݻ[@yޞ#GaÆd9;bbbڵ+GajO7+J&.:I=@$M*^x<^`w3gNZj䩚4iBfׯVeȐ!̙3SRR%֒Ҝs|8갦|)pe<"i)X_U?95Sn>yG 433X7yfw$UD K-jٺu+Z f[BX@DҰu=+o*l߾,YPF V^͹s=I\mXU<=-ӥ YdLg\_j Ωjǫv| nJr_^lMADҬ#|y! WeP`Alق/M6e޼I1+ ڜ͝ 66̏ja"ilf?>})MVӰD$uP4xq8{aX5·`@4wOk8![l,^=zxq/p钵߉<̙Р/ZlD$˓'ݺuc̘1I^og'r f/nS{w(Z؉oFO!gOΎ &P.ʕ+ hVjk`&"^yd(| ׮]c̙I+/7vCd*IIbvi ΦF&Y>_\6qf%1)>f3] 6sg݋4"̢E]E/^&M0v$\gswPu"""iV`PړmL6&vt){;e(WrNXŋpԽ:sv@# 牶ׯS^=u۷-gj{noOBV>\iX"b} fB2P v͚|g,o oͭm|^F@R6~ =/44SZ@<1Rzuz-ÇY&] U:4mڔ"E0nܸ$S3l*IDDODҴŋa2#xqYB͚r LȩZo7])cq`EGGӰaCZjEppp/t i7X3.$~lf„ 4k֌B YNI3g.]JŊٺuk={,m۶sδmvܺwƍqssKR?a|rn޴Pe"""BÆA6Lsġ4 g֖~-[PzuN>۷$8Lɐlڙݻįعs'{޳ldZb߾}Qvm~m{BBBf۶mL:L2P₯oS8|H("֥"BFp.lg/2б#-Aܹmƍپ};TVuм@N&xo_4[ea8F>u$** 6ШQ#ÑBf9XN"qŮhĘvf>99zR-:[Nي-JZ_)LKb}Z."֡"򀛛M6wλ.34ڴ3O8Feggǒ%K8p [֭[?n^%;q 0 `ݩ]Չ~]ve&f_p[[θV%j|v-,ի06rvlmm6l/f˖-x{{a.8y]:yѶ%xoOP֜G:ŋO"Tvppp`ԩzmmH QI={ЪU+\]]ɜ93ʕcرq=z&M5kV\]]ҥ 7nܰR-cO IDAT_>>Y!s\ P&r%9f5 r$7oޜ={&r'xΣ =²}Ȓ*VL\!!!TX#FXPT*{jՊiӦ%|},\ȋ)$ʕ+^:7n`Ȑ!3-ZN:9s???ǒ%Khذ!Z)cor%ԨYjq}:pNuҥQP!6oLop?-1FbG@Z.S9[./Ӿ}{+uԉY{3RM 88.]вeKg6laaaݻqs̡E/fJz%q||};ܽ >z׷A֬ ۶?^ir(U8D{/m! Ǎǝ;wrΝ;ǎT)kFb…q~)|aܧ?;'v ǎALGTX6nd)hHOx7ٳgYfz=:]}|1ҮlE66Fv?ߏ=E?؟>n%cu"iWǎL6j(k)$@g&MsޞuЦM/^'Y'OҮ]WGʱyѐڵPbn؈mŅۼ/gXŋg֭Ӈ-[r5Z4l 6X7c%W\_~Z*);x0tǎdLDI PbEwδiСǏ}̘17o^ DLWƍϏvQ|eIU8:¾}ǎ/ ÍRQPd3Sig/^Ν;9sf pB]4gUHT\9J.Tqr{s)HRI'W_}v5j~6lذE2`FA-Xj Hh,=QZ͚ρXCu,ْN1VdgzP:Ln>mZs֮=|)9=k<> vԩ0tqXd7`ܻw/-fK5IQ dggǐ!C8{,?~>vKf億pM&OL\P$f`F 1F@-X ΐ͙}30p t>̚[¤IƱ"_}再ͣk>XR;&,>ʔ$:ʢE}Ob-O|A""\@DY3cڵF)Y1Ve|/iru,Z=W9{wx]fo&gusB;g̜iM S,ZHzQhQTٳ}O۶/7̙dNDD(Vt1T)su޼F@lG˶[-2Tx|VqX߹sgdZ5Ν{0*(8pM#I%ѣ-DvڱtRBCCվIh9kODDRIf`>>݊+:w[ODDo&ŊcذaQ$)R}c, ܚk 8@D饗%J0FAf2Dd$hi(eP 8 dfU}rNiۉjժ 2yu>ܦn3}ۗG2e,XHSFcSݗ }:.ID$~}cLk$vzB|Ѻ5>lǃmtA#pȣ??# UTa׮] <???*W̎$$`xTfƛ):?O&LqXb |=wTUD$3Fʟn݂;w⎀ i9r9W;C3<\2@쌑|޽'''WΆD̟ 3Wocؒ%qGLo90{oM$H zg NUE!# O ;w.n2}:ܾmlE% 31Z [$S:ȗ.ED9 ʒe3~jֱ'qzNc*U_? UcY 6?̙3Of9R1+gƴ͍ih]ۇQkT'Nإ"b%N/1Zćo-zY3cmWs11~| k׮ q>j!$/ ˟? ӯ0|9>LLUrvoԹXfl[Fb26me˖cǎTX3fvm49s+; kt#`4-[z-/V b"o,_ɓ'>蟼H"ba%J-paV,2mPƾ#&oBN!wpu'2@D,,s6hA KY/!Νa0,Ĕ(3…ǧa] }:U%&fg?xqӋD҆_njٗŋiboo ΘLO~izIjՈf۶m 2[[$ӕ-[///xݼ*1Zu "|@DҘ8g cpY~7wqFBЁW|ItxnjeaҮ];{r Vh([{W߄/%1oL{fri̜G[~7x7b…9;wc?yD۶m?>/ltvJ;T$4igNߘ^?sNv^-9΢EP1xq1 X18}$Z"Fb =6-K3̦7 k֬:uѣGs9铨CE$ڵkGPP֭{a[8×ǵ]D>1 ,BB~5< ~H],.\GA[vT^'ylQ5-_!x)oUsd8P'uvqÿ`-[6\]])Q˖-{f͎ءDB -ZٳgӨQV:vM)1۞?e߻ȚA# U)8*^FR# \Cb;[&b s<NU9]f$ӗ/\gu+* );?G5ccNhŋR%7ݺM+"ТExmqi ?""@D$qw7v:{9&8y/Q.|_8 ?Z5'`#"S6q%zVk""166 Ǐ?>mL~=Y>-yb <tL]Zv7MJ{ӧ/n,"@ "iPӦơӯS*Hwމ{jU%Kx1:PD,OD$ z]v 5H`u;PtUS "K>`̭qIJ^ 25kŘvflD;ssٳsP~ !"b I{6n4~Y*(`LúsxzΎ1]DGDDDDիx{{?AP2λ6QցH(& 7S6nb3L]"(Hթv>.FD"5dܸabD$-RIʕ+sGI&d͚WWWt m-""iYP<^W6rviY@@Æ #s̘L'S9rϏw2b<Ȏ;R"""IT6]FL  D$ G5zbdcذaw^<<<V 6䯿gϞ(YDD$!˸qs7)Hh V"mܸ9s0j(f# s̡E/fJrEDDl6o>nݺ䓵klBtI0D?gϞ)S~:UTy⹪Uwޔ(SDD$тZ*SLyɼy*E6*H)$ĉpC}/_ "222YkI WWW7omD=i',I0y&C aȐ!>MXXO<Hj[o{nUfbbLܹw*ȳi^I\` /c~k=hŢD$SDqs-$ ED""""+2up۳"E "< """(nn)J%ȝ[DDODDDD dNMxx()HҩS'.^ӰS@{g[lX`&Mg4 "B """oYf7`ҤIDEE;v !Jf""ϥ"""" ;eȕ BB`m&7Wr] IDAT&ܻg*E$R\2+WfĉwZ S;a"l """`>˖-4ŊMgDi<$Xǎɑ#ͱs _@D@DDD$ѣ۶7Hժ++3)H|'Lp0 4kF3(3)H͛͋ѳ'Ԫb?D VMDR/IL_!{5"dGKZ^ """b9ٳsѳU*)E]ւZqKȓ@DDDĢ"pfv)" )Ey,QJ{squfsډmv2Fl*Nhѭt;B;"M;nR(B gs9{`~|\;0l5׮~ϵ.>'N""e-[~¹sdgN """R"&L?LZZn=@?ߒՀY)MHNvr%E@DDDD<3:u)SpM8@]s0q9AQDODDDDJDhh({_ǯzkߏϪ/ݻ1G8"| """Rb{9V+3f ;/l .\]@DDDDDDJPݺuѣ&LӷsjܺkG(H 3f vbMV{KoyuagNDMDDDDJTFx?A׺˦W+ """7qqA[0gٻ5gSurwtfM= """"",>vDQRvOrdf:B"L """R\]{w"6|svDę@DDD=0ВZW&"""";8N_fhMNDDDDJ]Vv6k֡ssgWGDHDDDDJb}{Lꈈ)HsuueԩwvuDĉ@DDD!Zn^iNnꈈ(썝A:gWEDDDDDD/.K*4%jZV#"N""""S:|Z ?ή88?,>Պڵ镚]%q0qȴ`{rqiirvD@DDDaͭm,'έ88=:[z)S ;۹R#Ga>XЩuR8|hZ7tvDā@DDDaʕ?= ÇհnS%"""""'CZPoDWr#୷2e  rr E4)C ;C}g9:sa>ʗ/ɓ]M)% """P=fVߝ<*WR%xm2d/vvUE(S@fo^p;w&>>""""N kׂ! oArCDD:t`ή +ˋPIJJ*t֭[С*ULJG}cǎ9"""eSl,:)goރcbTP8:쪊H QB&L`1i$ ʕ+a͹8p֭[k.^}U}Yr+);bcu鐻"V5Xt)Ω8WgWz3ЬY3\]~t4lؐ駟0n8Ξ=ƍY&1}tx _DD, @| w5aח0nJŊ]U)!B-Z(>j׮-¶mrϟO.]r@۶m>sX}EDDʺ| J "7`8|0pQ6mZf͚qFGWQDD̊D|}!9URRf͚jP؀?y """Bj*l~`];^"R:@Ѷm4h~;}ٳ:ã1"""7&M̨aX*ر0gN¢~ED)\CѹsgUƼyX,xzzQLjT(??_ᣏBÆfœ";䩧"331kUҩSر#OfժUԨQ#1+PV+>>>]CjժzIϞ=K"""e /@|<,Z:ʙy ZGqssc 7WD)Hp}rZ a>ؕ f'CbXc…$''ӿfΜILL QQQ_T_LDDDDʤ _7`na!`6#y\ʟ'<<'¢E!$$D_Q2k(8qn5_^O6X[oY'ҥѱcGfΜy=4LK)H} >n:u[/YRk }{bcci׮&L 11F"ri """RS qw qcҞ> ӥsp}'o))ul6z쉫+cǎYf0yd~WKP2zuxKab8heCyŦ<%ŔBry^v)Çh"?ΪU:t('Ç'::^M@DDDD*%֔ڑ qqp9,13㏼seO[|yZlɋ/ʕ+9y$+WnyG!==ʞL""""7ʕ97,\N7t37P*M\9޽V *ЪU+*Tp BJ?$!!ku@DDDDn,q#IOAдiRu= Wk̘14mڔX*UDLL }c*"ήHIqsf]_u<ԉ]ӱio?p+Ӱcnrfȵɓ7 1!)KOOgӦM_D<==/ysaX(g( ;ahf|ғFRao_JW̤Msg#Ȓ%0z鉉6e{4hЀFq뭷ETTX{k!X"""rC8s||ΧpIXуsbVҤ9i!XVkfرԫWu1|pڴiCm۶LEJz@DDDҢ٣woMx= Z6~+4Di|@vMOHil:t&&^fyK eعs'7of;v Ky۶mPJURJj'ĮQ#-)wF[X^y gʟqU$,lDhB͚y禧èQ}+ Q~}ׯO݋uNNؽ{7>>5i ߲_^z\E,{_Slo2珴0,Ix5Yȅ@~&Mo-ȦMY2׼ ,[fbݝ/'|-[ԩSW9)ϏC'Q$~Kv58bCC-E_jd? MĒu+̜ycjl/ٹs'iiilڴ>m^^|EfϞƍIKK+-[6;)5m { #i{{7#처53"-sͅ;fiZcGpq)aX2<ԥk3 8wΔyxxаaCzAZ.y~RRSLW^Ehh(:t`СL6 0=O}īܔBḂ=߹ݼ~!O-f ?k j"6ۥ3#Z[J'df SSԩ`lorzjĉ/L>={%Kx11˗Νq l GEDDչs|u+ {+M/2v's;=pѯ_(=o w }]6>+ Ьs򾲳Mй4K T"WiifNKΦG]UҼys7o^<''}$~0JZܺu뒞N:ur"##soKbֿ9 """"煆ywVEgF1}9ΧOfV.pwѡC5 ? qc3{~ 5jy f^\0@&YN̈́uOMyv6mkz0:wnLV !A_ߚ`&;V?F\\\ض|ߵ+Lf&6)SĎ;HJJbʕX?$`֬Yի+'N!X""""煆U죂jZw Upo~m);xA,>|3tz&C쟭L*8_M{2rrL@7̓f.t1&depwr sZ0K#l&x>lY,~FԩSYb$5572gZju/Znݺ1b>C.]Jrr2YYYD(fz1P)ooky3Po}5~IIiI5|b IDƿ}!.l"gs'֔ʕ3Ý52=|xyA˖&@kcO ͛V+B~fHׁG$(iCժyJ+l7(67桇"88䐚ʂ RxzQ,'O5,m}lx5WQh\BÆb[0 0|Qt>6m`ҼXժG1U+6_6ۻt{@3?8` (:؀F`c3 4GN6L3"8?4=,QQ澯ȿmzVF6Rk۶vfؖ-[ ruuVZԪU;' .gqPfM c~%_ᛘy+W_ :2{7 i=0~ڵcڻ:p nex?7PlBgQP.ԭKHye͊H<{$ޙ )fVM }}&%'//pq< DDJ\#F@>?aSK_s֭dddo>ݻsooΉYX.IDDDD$-0(LyT>o<إa9,Z!& |wx ߙ{<{HŲue)ky",4$zDF2Hy= 99yIL1[:]]w &|mkzY"#٥lnn5fXWcfw3!s{w > { iiyebnϞ-_72ÎÖV3#2{dLb>T[*W2'_YYݼ+vqn &۷Êy =fVkݷds͐ELp7! $ү@"#׿v 3¹2vvң""""R(x߾֡CfƚƓ̇34ޣbc]ڵl\u;u<`c.U=Pqiڵ!"&g#Pjr|#G Yfĉ~۶^/zLZ?ի/\<Hq{@;{ԱgHP)[n1/ll]c СfmbU6-J; 6~.yoT&3 &M7ʓ^V-^AR 'ʕSK/93f /\ˮ^=ٳ{p=EsL 3h=^Α#f(/y~-)a """"ZcU3cZ1`M/Գ~~F '}i+ɱ<rΜaۻd=[r2.${!sxaaFa$>Ν}̌]ycȅa^=3$m݁&( şPͼ~0+zgn3d@kRRsZnpZ- CNKر 9zrOn wy?Xdz\0CpLB0C`vf3e3$,̡_{LmBQݻ7GJH)W^|LnïJKHYRwUQm> )*|>,? ڜTu+χO#vTIDAT~~jo=o^G~*nB%L.kmاz72='fv01AxDͫuZ{@ڴ1́1ct7f ߥx@DDDDJ&Wx*-y 8 k:vtRC믛ﳲ.yçB.j0tی*އS̄[&’Y9s<Rþ}fSPprW%~ gJMv:ۻADļVg̘{[k7O0VR@DDDDJ+̜i&]׬6EXL/ѣy"Eqs3eV l$^qؿV4å컚7h`&lfիCx8ƅa\x?-nD+ IŚ),y#>~ك;3>2fBuB (s!AD}[U `x{ )0Rc׾[y֗T/ի xeYadٷ/iƄG!:׺ק3"o}SͰx:غ U3@L %g8dAfLqwۜpϞC@JM@Ý}̕FL7l w;{F77ÒfŢz@1=%^]zI@DDDDnrr%KKÆ8Z6fߑ/xNӦ&{9 pp3_/)M.řa_/ coo7sGas(mY we6!Ծ%EԼ9 `zGiS矛ի|lVΒk""""r 0֯\3d \LzPY+,//3?ؗk""""r-[];g埴^jIOxυ+amPwEE*P8:u戀 W:7E SBLߣjo ٬o/R2\]pfHUq{r53E?ޥ 4AnpHIPBϞ櫸օE{~reh%QvU2225jTPne˖9Z""""r^ǎ^G 3ݾd\=Rԯ_?z-äI(W:u⧟~rvDDDDvaL3DH)YnsaL0~PFI1{lgWAH}sQ{\7*U0RJ͛+ -swwY'N usQ{\7GsR24 lܸH 7;¯JPP3&""""W[7غ`gRJV+Ec/;x𠣫$""""WB7ٵqhV)9{,=<(ǎsRrxС޸0cƌ"㏩_>DFF2y|RLm~~_~U{= <( %>>B}+n{]4 ׯgذaԩSiӦѩS'/_w52d͚5+Phݺ5ժUW_%55_u*e=zcJƍYbqWҶ׿8p ݻwgeʕ<Ӝ9s#G:|ʪTR8w4a֬YC=[ZL<~omo{ĩ֮]kX,7x#,==VvmĚɵZ|bϟhXme˖-Y,۔)SJr222ll6[bbbf̘Q3gl>>>]8w6///ۉ'JHqkTe.~g[VVV$w޹ezozo< ryʀr߿?k֬!%%ʼn`HMMܹsE>>|tB͚5sڶmKdd$})W|}/m|r?SO=UA7|S¯@DqxNNO1jﲫERvmnmۖ[ zo4'۸q#xyy(_Q-)A=UTӓ6mڰ~RRR8z(M6-t^fظq#*%J#gΜrTZLZZZcÇ޾]vzo,q2J@@@r{]%)!tޝN:͛yiժ?37j\wdeeiuJjR\B/_;p dԨQĐŋyXbʕP{_gf͚yWot7]@ٳ*}\O-ZEtBݹ[=z4/m(\mϞ=K勼N7zHy͛G||<:m6 N߾}odE7]4<==(T8"""{Y|96-};p㹒$33뤧w:6l0\\\sׇCѹsgUƼyrW>{t%g ttIZZZnZ:u%m@vvv=2339~yxxseߩSر#Ofɒ%ԨQ#1o`_~i*W|Em0h wNvXj~)ƍs˔.Ǐ'::^z德[/^Lǎ .ʤIڵkݻ7penˮ={. Q򤧧Fa yxxؚ7on]-F&M5ocsss}Q[rrrc7olk߾bŊ6ooo[>}lGqBlfXl...6ݛ{ܕԩSmճԩc{wr2.'OVN[Ŋm Əo;w\T{=wuWn^RXioKz@DDDDDa4DDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDFDDDDDDa-#IENDB`lmfit-0.9.7/doc/_images/models_peak1.png0000644000076500000240000007660613066042256021020 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATxy|"KH@EHH Zu.L;vf:m:]::3VneLTjGkqc_kwRQr;qrpT>q$I$)Q$I>, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I 8|0{/^{-={$##_'}N<n`tڕѣGssK$IѲ:>^u b'}Ç뮻سgy?~<{/ӦM"$I$vA^^唖s:v… 8q>Opyq/2eʔ0cK$Is tЁ< ju*'n&jjjP$Ij, !۱c{8$I> H?@$I Đ!Cxgرi}ȑ#7n\)}P&% H}}ۥ~߱yfnbSN/<3'}aNyN$I, g;6m 1{lz)bwq---lݺX,W}__[@$Iv, ghÆ 9---!$$IJijQGP{Ma{MJ)M, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"I$)4I$IH$I D$IRh, $IBc$I $IX@$I$"IiףN!IJIJc??Q'$ $+!ꨓH҅D؊D $c6ػ7,`4V] FX $), t|СD $ۃmWȑ΁Ha4ubc̘ ΍6$)Y@ާÇsrҳgO222/~q]z5^{-ݺuW^q޽;Ētjе+ +?'dTudSWW}ǠA(,,W^!nɓѣ͊+Xt)TWѐÁ-pQ'$" TPP;ˣS~<ѣGd?k~O}SaƖY&M >>?cm>IRjr ԡCyo,SLa< )I鈴VV@Tpu$> Hl۶:JJJZii)zPBƌykuk$I|Kcccر$M'n{Eo(x\:GbE0dޣ_<88&\gIΝ;pvر>GP]}W0|[+ $>'^؊jkkի׻ކwƌtmL>mJJ[p ȼy0y2'KR:5kf:Z}}}DiR$O>}Xl^[t)3gdKJ;csFyMDR9_WTTP\\QG>³>?̋/Ț5k#L&)ݔҥo=yફkFZ=;xn]b3J҇+ g?!l߾wl޼ロݻկ~'x+|[b̘1yQƗfd5kSϟ{JJHS1"x\*xHڊ |;aӦMb1fϞSO=E,;{ 0W_}+_ ;v;λHR[xQ0 x`5+mU\Ǔ&Y@$Imr6lpZ7j(N9/* G,_p9P_Ӯ3O0p \}5|3dfҥKp)k$ߑ$)U8"I)9wzi'Zn!%x>JK iӂ:4(1GD$ W@$)l MMaC0Pxx_vCW=Z',Zwg塇,^^'K~"I)f>oaa7eqExa Uk}!C$ $VV>b1ʂ^j(?p bq_kWa(G`^ fG, `Ì 8L`g 7N'a~# VAV fJP~KegO0$pakȐN:Jp o~ ;_G?'?VSIB, 6n W F71c f>g˂`gƽGya *+:$)X@$) @MMP@JKUǠX i_/>.IJ/IJ7}χ ' ,)9_ a $Y@$)lw҅`$s[p`^я92( KΔDRMl]}#: w g>صlKҕDRƍ _BaZҗ >yر nÒ$9 $+ p=wKK FSl&q $Y@$)gz`f /HΘD܉[w^녟>2O~mKK҇D܉2hp(ΆmkK҆DܦMA=;ؓO&>q:4ٱ#1o!IJmIJr;w##կK`ذļٹrp?<1o!IJmIJrwk|c }Ns5ܘ$& $%:xq~oXFgr_x<#IJMIJro<(LFkW\p%kf%}$I)"IIv m򞇯EMU "IInnxlΆ =rJ򖒤a${5O)։ׇ|^CyKIRHRۻzԑv._|&)P %II"IIlnOn17i&pZ, zh$ sr82J $}HRۻW3>sy#yIRHR^*]9LFS@:Zh&{K$)X@$)Y{d $s̅l6dO?Dcd3d˹.-UD*zOe?@<YIRHRZ^6<Z1 Ja͚HsHD՜94Ų:HcsdGC, s&5[1z ¬˨04$HR2jn^̫'(t+mǩ6$}HR2}xmS|Kϲe$oIJ"ǎԩ94u܆ G)?C->y $]Y@$)l/Cy]ͥF ƋSh?X@$I"II:q3j>H ':u2` }f$_IJ"uup1 q^{5uu &3h3I/ $%:9.cǨ~#r{>nÒ$# $%ݻajbSЫw{N!6y2S_eժH+ $%C[1L:ʩ]~9C N"Ij, Dz^@q⊨H+ $%汧S uS8=cTݫQ$GIJ"泾.\sٻ7$"IQF^Ǝa</L!Ul_UuIR;ddt)hdˢN|r2s"Ij, $^~1梨ㇰtXjQ$IDD+X%uwc9{DvIJt(_<.wü7]N 8x0(v"IɠϥuȌ7Ò%QG$3IJӜՁe& H ؟ EEX@$)̛ǎduDQyo`Il"q $X@otȑ#8zh$%xgM˒b0yE%8v +VK/eŊ̘1|I&q2}IJ&6@m-˻%!Id_:$Ɋ:@o~CCC9r$'iiiGaDRRRh4ig9McBu ďLj-Z$ܺI;//#33:DKR2ZjsO??0';FΦn9.I:$A.'> /_Ζ-[xx衇,(/eD6naâs.6Nr]t H`jjj(**bРAL>ロ|;QǓ,*vHs3 uw%IjGGNX@dΝL6x}ђ%P\̚ Qz&]b$&;") ͚5Yft-g 477:@SS;~̙37n\²IJ"-&_PZ $.[-b--_IT\QQAqqqDR$ȸq㨨`͚5']5k3&dFm-l &vmr PZ Ⓢ KҞ$A/e]׿u?~ϳax~GOR2Xg+hhH ÊHX,8v?~<=\1$%%K`~:vd +-K`$ $OMMl.ȷ ,u33~;!??0g/3(z $; $7 P]͡%45AtR5и@Q$IHR{k@jƗAˣ"IDڛ2dC@꬀t0Ct GGx/:$)DIZee0u~Eڕ+ ;z q$ $E]FP3{~9³so6 K҆D"TV AtIJOIRs3j*)zs! W@zNDߵZ K҂DnC!ݺRdf%dN;a57ÊQǒ$"IQeL!\'Ò"⮀HRʳHR\* +0C~>,m*"s'FG@I [M  TRDϞQiN8"I)"Iak1χM kDRDVUa;=zD}w`DRDVYɎtYYQius΁}, , x?AA޹֯$IJ $if#"I)"Iaj^"?7v,Щ۰$)Y@$)LUUǺ#ca,GHR $XEE7pzK.=QǒJ(,dޘ+ f̘qg蒔ʼJ \s=еkW֮]˶mۢ&)*UUpm}W@СVw*bcv,IRJ$ȁ;y'#=س'B/*bpdfѰH47kAIIԱ$Im-X 裏k.~>LKKKĩ$Ejr(QW@NeXxnhp$( H̙3ݻe.uFNNǣ') UUp9ÆT7 IDATy> ȩC#, , f馛6mO=wu=wyg$EƌaLS"hlCDT H:t#GO3gpM7oo 6,┒BUU^ʞ=SW@nqK"r^ p$)e ;w`']?|šgGaj(*b+ oׯt +;#QG$1W@UVѷoߓo߾w3f{ҵӧHJ"+WBs3_~o.]?)Vau,Iij֬Y̚5kI)))aΜ9lݺ?۷oO>3gdܸq ()D32iwP' ˨#IJS #J܂ r ?NӟlRILU{93--nz7kEKR*r$A 뮻NSS'OW^'_*:0UUc]î]QjEt{$I)@=={6w3g:0570o?SN k[" [ц$ Heeeq=p=DER֭ÇyB>UeNͭPaY@$)e8"I:PE!-=3R~\vM@$)X@$)Ѫ8}M9:40a(31+bIJ%IJ*j)b8^_28Sk, J, `J,dҤ$A`88[`Ϟ#IڈDib;w2p!_uqBaAUUA$Im"I'讀a|aIRHR"UVrCF 3PXrrU $ $%Re%+ İaZv+- *, @U,8\Ȁ}Y:9uIRHR8@TPĉQI^oꨣHڀDer*)b$h$́~IRrHRTVҔՑ}FйsaWAY(Z- , (lͽAQ'IjH, , (UUXQIn' Hv hl:$,Y@$)`J5qQIn' HFq:$,Y@$)VF^wl5 'KRҳHR"TVXz|,b}@wvHR HR"TVr|p u݊, , UU>"x<8`UUlYDu׿?,:VÆ QǑ$ $u!VuiZ`EmXcQZK ~F hg$gVY >F w]DZUf u0`@3"I"Im#g\pAaRÀ3v:$ Y@$-pw00=|xyRD,KR*HR[jxEVG& ݻ[@$)Y@$-UVBn.{1`tuQ\ fpaDDRUƚm8x"I"Imxu?ڐ! 3`Z:$ X@$26+ m 7k^I΄D~E?nIi`gQ+܆%I"Im:v#`%dF"I"Imޣ; 8H5]^u IHR[䅺">q32/llUDޕuI'r%Ǩ:Pj[DVK#\uIdr%&*(WäB@$) Y@$-TVȠ1uשwW6un$dPQсps\ An.TgY@$) Y@$- Hrr(8{%8"Ig/g[bz8OɁNJ!X68"Igk*8~=KɁ\(x6,IJ*I:[eeꎅn IN7M, d, tajtX!  w]DVy9ga9Q@ n- x$I"Igub Hrs]EPW۷GHt, t6Vǡݻq VHNls]DF:sgʂYG $% $r99]سb61(r]DFy9?47ؿ $% $`X` IdFط/H`3thʠ ܂_:^Um IiHe4A|l!w\ On.,[4duv$% $bjq Vrr`:h!-9- $, !`QG*b^y6m]SSgtv]$$[nK.bH:[ 9TM9ż2puQJ/'NC8*3AM 9m(I{_"_|1%%%H:[Fx%(!G1J$kknnsԧ #_ _9t~d_PbС4.HRȊ:@{衇ؼy3/RQ$XE9epYCF(}<5EGFڳgss7:Ӛ`o_1ǺAf'KR;gI}kݛ}sQGԖhj7UtNl[|PV]I{r VY'̜9[yرc444i&wN=3f %[M>ӧ'<Ӱt)͙lR@^<Ȇн{0r5Qǒf͚ŬYNV__QaIm۶ww̌3wfΜɸqˆ)L,]ʶcͱ}YYг'ڝ%%Kj3 #J, 2zhfϞ}-w8_8t> CZӒ%} }FD'A]0~<+ nÒv_~cH:SKBNK[@ڑ7W@ ~Ov"IҥKJۓaiG kbe7sgԩ$IbÒ%1Ϗ:N˃;`(xaxzU#Y($SHZ8x H;>o".:$, t:'? wS7lÇ"I3I:V#=6R:;"ID…0i[Ɂ]1h,4"IDMc#,[_̶m$ՆIPY ǎEG"Ifr8z^1[- dÁA,/:$DEE86nt#  KK.`Aq$I, .'%IQHJ{ws^7.}3ɉ,Ȉp8l+W^:$5 WW<Ι46¢E0y2Fkj+eH3IR:HJ{wàAz5zؿ  si- W\<IDRګ[n >^Ws84|--T\Z@|xcIRڲHJkݯF/} Z>$#`J :bX@${|MSؼ9nI 'BYYp W^ "IHJk' H>d7%"nI \ θ32:$ {71X4f:uhh/zRaIRȲ IQǡnW ?}]ZG.#;;g޽23'IiIik~8i liNz೟&kdXx~QTTDK҆DRڪi@ee%sa„ S^^θqBL)1c_mg{ ~c:ڝ/~G~n]z% y-+[Yd O<ĻIc\uQI~G?j;Gɬ4J:$`%yzvͯ~^#J&Fؽ&La/rl8\Fx~ ~ӠdWv&, |rb< '^~eiiiy?QǓ‰!W0*2?vބNaN.e>]GHRDRJ;q+=zpӏ6Ä 0`SsϝrSS&Iz, R=1tom5H###~of.z0x, RJ<w_>c ۢ rͰc7Z@s3̝KK[œdeRvcॗ`۶`c}ˣd2q"OyOK+VEMDRJټ9xa,رi[nh)dd-{qƎj|46{FODRJ9Q@=8>goww]\\Z- Y@$͛cGl`Lu4%cahWw: , t&, Rʖ-0p`0Wzu3?Е㜆}[^- Y@$%~m栀wK)c#̭K BϧүL]YreP@F, Y@$%k;<*;!$C%)&JSzSXX, "(vDbWD"(j()pgI2JS0K\- "R :}W^ XP;f!`i\GO EDfP""rHt6#FsC|DD͛{7R4n 4kL@R""ҡC@Zr;G\?̛}%IJz""3 @D@2]u 4lԯwk牀/0h(Q>܅>F;ǎy;q"")p.\`eZ59w&3\9o'S -<es]4B8fyjP;~ rX"yeYDl`+ "R%xWw:hYG:ux%]rYf~ Bb"ޝC, =H ED5 "oJ١CrU+'X6|8ڄ`G͚Y *JH>DD6mjޡC@ʀ>9+]$u숴A2@nY 6rJ$OD$?S""Rt4gzunr:o/lMDDˁ;ͮ|1 IDATf%my Ҩ"V__Łm2w曳2z40aBަYDHl@ٲ @>x _Yp 9(^ɖ?3p|5:!!je-ZdL̞I6 "X[< +\iwe2tW+7!C]Q`L 駜T Юnp:zOf @D$_9rx1n] "hXT+b  F&%Kz;r#+^x5oDV*8w.p=2lٓ>=X 1,$`B۠{%iSfaü^+Ǝ^xݻkq(ap8xZŊ4u*0xS>e|o}xǏeJ pg-" @D$X[usf s?Ҁ#F&z͚ڄQsez 恈HDDoUgnj*@߾@"Y&/{p_LgߚR%/ ̛gW""7 "g,aqիΜqEt&&?&v""צm[pϢϝ3=w2\MDLyy_\?3 _Md񄯾Z{ErEcUSyǏS7"|(~k'u.{p9 Qߺ%w= qq))8WAQ() =-w +r%{eOEN:c4޾>3,D VrdrtPу1U9y Eݻ_0"8:{fرV, x5or 5/ŕz@FDؾ3#J*˗sի]>+Q!_|Pj-ϳ#"+y#G:eT)N7ح-]Ha 6m JMyp`3d91ïzfP̎ r–Is" @ƤD5=%J@.^dq2S1Y @N aW u}tu&6c N<~__ছrw`l,sʯiW0A""#r ?}q#<gcX4AA@H:@ǎ<'$h\M3LoTb$%%o&_,()ffŢJ`T'ٯ/}r/ϜaLJð9aqc:qƎ0WOp,= t72gP\6)J8$˵:ucKذ!cUy8mR8wNN;Y80]Fg 6fځv~,&ij>nz@OLf=眯~ku0gz|β8E ;0,0='O2`7A $V8eY9}70mXĴ]!\@Ʊ?<{:2bӜ|Sqn$Rp|,fS oy;:~@'Wa+Ǐ7X1/s;w @RRܯεgyɃrr 7.]"s=anz~f?0ï5SX]\佋jAϥwd*[*4SEGeK|9`_ \;"EXaqmr>{wgt":ѣ@,"]x8,NQrM *T`\7 [ wU}:)=9W_ecSO1ع3cZdG~Y|^-ĉb?Ifa@̆= 䓹(Bv?w=Jyd @ {Y;E']SX_+\8 fRid}N͚:;tXq???~{ٲq(7`kiʼ?)߻JY@.[ wSӧ_\7.u&WD"P BZʲc:o `޼H5j~ٳ<hW_mw:4o@%L{m> aX&q7z[ . kT{0;3./9SN0FHglW}wwN]k~cDzx|SYHػpl^?ݻyj7΁9Q#z8a QQtDZcvOqq PΛZdS'?ȱW|,_΀#1Ox-WD"XD3e??ӯq7ǣ_?o:u23o?,K^<.F͛3> .j~?p33:-@ðLv-y}+ϳ\nEu˖8>R9٬xamْ|3͒a#sNIرҭ!XӜ.X<,[sZ`İQ91e wN?-2s}":}5+ݜIR` ={C~=`~v,:>ܐMY9iӆXѲY0q"0\U3gn^ƍluɓ?w۽*/%2dž X}X2-ii,D2hZSeVVW+w6ϵ9pYSz`mwӽ @;?o<O{eJvJsΰaW˚89f*35iٯZjcybB&y)`ews8C ng` L~Çp eFTʞɓy?y4pU}Ht4˒{9fŞ~>wg?av=@W;36eU6Ae}Xؿ:Y1݋$q yOHJNNƨQŋy?~ì+a<}LQ#Geg\|"f4-_0Ñ}/Kl-f+UY~9X t2vm}||Ӧ9mgݯ~{\+ yOH0`"Ek׮XYw`!P봏= 3T{o,s ΝlՋ֤Icr.89s8xɒ Ze2'{7u6s&3@EEq(00pҸ1+:ب(J;%Ht4k 5kr / ~gɚ`vOG$ Jf2+S?UG97q}6~ÆW&N8&pϑ^>jloϘa};xuʠɹtޅӧ?~cŽre;"e &MWMH-[.F@<ʌ!} ]IKc@3dWvd2%k56kƌ7%ŮϝcuZٲ 20Ξ{w~UX`uBc\{`fLQQ R>A}ٕoa LJԩ,tʕ8ܲX7jxq;ܳ@R,׮endS7)5t-Z5`KXҮ-+3ŋA @yqE+BU$5_~ <&M${Yɒ9xqxqF@ѽؚuhۖ-Y-FsV VØ1I =Y 1o7= 0,Zy{<'6 .\{@.^g[,kMpC汒İgd>?\2eMT͛ǠrMlpNN?pk-Xyz"#6|?`D[Brɡv&VÀg#dvcoٵI;0uV֊c6<~occOe dCByic/G.05k$?+W"&3Ç'R~2ddf%96Th(Ϭh+_KY202r_躆ݬ3XFfŖΝ9$(<\׮m"?u*1Á؛2/d6:wfnId peу731͛y!Xf=կFy؃R43C9 er9lf>D ?6m8^'Oskۖ/3x }eԩLox8ss8rvl))Lb |![N,߬ze8>|pXfp--˲-ᰬ?V,-/xn;O˲Jѣ-k"۹Ӳ.gYŋ[Vje%'[ĉ5i?}ڲʗM'%sϚeYiiL;XVɒuo?eU7=[eueooY۷%-f gfƍ/e ##/7cjgz7yxM716/Rcb,W8 [df]+IDAThY_<6{6oeYZֳf|#-jUjْ wgd ҥYp&,x/lY,O``~uVp0aew~?:/r~} s_??~v x_?*ZԲjrڕu繻wg|(~.EZر,?kُۺyDzΞe9䓖UWcxaCRzeI$!8}3pXlv-enlٿ:vdóiA1}Oٳ9๦ivԮ ??vTd+lܘ=UpH4= Mpr" ]e [~n+vTAAl0ÔVf[TLg޽|Gr-[2k 9IIgU({.֬aEŊx5oα3faA+vۿ6?^U+kGU2V[׵#;<⺄iTs΋\{#`ƽ g~_ ±GpL\f!3_.`'̠V>"11&`wwr<ʷ߲l`q/Ζz.c"*]:/f>r 5!!̗Opr%˼n8`ԩ;w5q֮۴ɞ X~+gaz\{@2DzyqY&&GK{!j՘ϛbs^Gֆ LnŤxyfvn 1GGtsC"W²1 fV˖,Ra-]W?z |*U8:׮3䓜X4ʉ|pZaWgG$!tkƅ eW֭+UrfѢv\9N*Ofaave{wN۶^B{%,33>ty'3?f-sRefaFS0|9v]n<ݫ}j嚆Vc^0seֶ-3 8w",,)BB\kfߴ) Xv;ם~]>/y )F|AQub΀0!Xfc;!- }N"PPn11{A4Tد]>iZ[t޿qcGaִ)'$$pY[Wր`5 eR_Ŋ,\r٨CYN^rF {8-͛3=˗eݪU۾]E8luk>.11P׆ =4:wf~6Rլi(x{Y28f^)_ݺvh&[&#FL]nP4J0W_e3Ѱ!ˢ(իc5k2^>}ö3c2e_,W/]b:r89(-حw*99@iCgpqw0s@@'K_zm0$b gT $x.J$P.19X@ {mB1_B8-}[= =<.j8::U}2OW97J]8u}/[ `7п6Xy(Q{8X3) $V?\X;pnvzQ\F@x%c1賁M^r P a:9^䰬ֱcGb{,X;b̙n 6nC0csrr8T_,^_D%XY(YMW%J*{RVkiϲo:Ş6`/9AKV))|>ɧ4_͒+#5ŋRJ]9 MeBbn:3nZҵ &8yؗ_/ě u꺞׮wā3gm|3g?̞4i5x)p`p^/v<@xxUJ.Zݽc{ҘX`bACƍ^ | нt8ZhoYKD82νMl}w;Vk8Ldꍈ N +[cl D3epNO- 5p <> ky Yysy(Hʙ^S3LfNhь`VbgVЁ-Bf%Jt][SJ@'ݛșpFȍ`NnSRNZ4bpp޿;]f<7RrY3V^%+AA{rZߟvnլ^yرW6DrXL_dh><w{̘qmʉ.]nV b=C9.WGHꫯ/믿ƩSРA̚5 [g265a?q4kƊ~9;߬~,ìYwLޜhˎfO?e[sEQH+/c6̝:e 3P* 7Nȕ իMݹN8Vwg}iS=fM~FK4h̪T-ZC߳i,l!{x/[g:\zGrg#71`Ln\9ͩZ洗YLa6pS ""E+hQ^93KݨQ^-W[7.6r$3ap. ]];{ |qZkOWfsZ&7y;ףzz>픈x:p8<|lL,د7nvH\mVD ߵV1vNƾ6ݻsK 2ס}{>YLm[ڷ5,q+ """7֭9):'~w L%d+ʸ\[@^lMt3ErHu~ZcG^u A^R"nn^l aX @/ """"rû6٤}CNKs@DDDD ,Xz;h蠟0Sx """""1 @DDDDDc(Q""""""DDDDDDΝ;*"qilذɐk)'veYND~?#G@ҥ>|0Zj???,_&..qqqH\`@H9<ڷo]vaѢEhԨ$""""u @?̘1 0TRٳw&""""E @H͚5q!xkԨ{!U"""""ޥDDDDDDWN/Z kbذaWJ,իo߾سgOs]mD 0ӦMÈ#PV-L<]vŢEЪU+o'O '|M4q9%E9vx T^ 6ŋp82mۢ\rxw>[nŚ5kPhQ/^ ~_|˱2ex"R3+WD>}P~}ahܸ1VZzPvM,իW[;vcIIIVXXղeK/L EYÚ6m"HrroYe[r8֔)S27tPDÇ?p8I&y,RpCYJtYbrlϞ=V@@\9|i?+W"&&ƋȲ,$$$ҥKN~~~X"]Ϙ6mwU^9֡C㧟~tJ?-- gϞDҤiѢ|}] nݺrLSe7nDxx8J,r ٴi7%QL+V ۷뽝$)bbbp1~kҤ 6nTIaҥKlٲ(_< {;YRYxPv49$I!޽{k׮ M6Xb6l$J!u'ODJJKuQFqHKKÜ9s0al޼/F"ED)[7|Z) .?񀀀+\-Z@-޽;z^9s:)L>]^Z~ދpѷo_/L HZ`5gqqq(_Z %O 00'OvR9s t邳gbܹ\] ^֨Q#޽ .W^ /yn(VXD*UB Xvm֬Y|N\BB? *x;)R@$%%Gػw/f͚] ^ֻwobҤIW%''ch޼9TIarر 6oތ3fSN^HH̚5 W-X{A>}2)L34oܹ$Pjj*իWcԩh֬]=^׷o_L>#F@hh(Luahݺ'DQxqh+VĎ;0i$cʕ](qibĉ >KFtt45je'DBB}TV k׮Pɑk'ODFЯ_+y9sK.={7/SO=?=zpH<|(/oSРAر&'|o{ٳgQbEt*nfo'O 5kpeeYp8Bj;vO?e˖ݺuرc5,Fr,Z2eO`ժUEjj*jժ#G#wy'.]vqÁ+] """""1""""""DDDDDD9!h9sq]\_+*+++$I$ȊI$I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $I"I$)i $Irmƍ7رci׮YYY_L=hѢ [na׮]U.I$Erʸ馛(..fСbZٶmW]uׯ_:sFodܸqQ-I$E.'RQ׮]Yv-;v#G&M0}tN>굫?oSr9$lI$)rv@@ƍر#ZեQFGܥ^  W$I@@lڵt!J$I3$wA֭$IRFr$nVN}GV.G$IJ:H?)_k>}%%%$2I$.]ХKHY$x+ ?}%%%15k$:I$]2c C2$[oe]ƨQx𱛒֬YßgX2ф 8qbe(dkM0|>SRRb9B?>\p'pO?4M49#???)ӵiƯ3%_kJ֤`9B{/7n.Ob ƏO,gƍ?੧}I$)@wbLIR3HR&կU]={$I `LQY Sh۶pPV$I"I7` ((} oɩKQ )&M]>};'.IRF1HR&ػ{ j{0u*|Aj$e$e7߄uӟu+|;?. ۰|2y5J2D2Cv0rdsl{]eGj$e$e矇 w}0{vx@>1x $@$)mcZ96m(IIJwSBEŇݐjFҧNM|at!et^k2O~7#4jgS$VIR3HR{8묃׬ ۮ!/C@9M;_$)#@$)[1x ~M?!j7}6$@Ӷm۸;v,ڵ#++zΟ?cҲeKڷoϕW^Iyyy+ѦM SO= #={2w.qpC7x"l oz%Ii/'RMYY7t={dСb޷j*N?tڶmmƖ-[뮻={6o65zIg48ѯt͛߄+>$;N>"I7ԵkW֮]Kǎ),,dzzر3gҽjsԨQwy<|+_Ifْ2׹ ѣ۶}.~W8z4ajHt8܂u7nLǎ=\xsΡ_~w ~b099PXh1pQQÇyYU} L:EO}*$ew לnj_zpgBI Lh1a0uKҞ#pqF֬YO>Ɋ+?~_<o ͚q>Ѽ9>={ %Ib4dϗᴅaI`øqώ{`b0kDt f6.-iĔ5y\2#|3l: \O?"I2HR,V2=4'°yO:\'K@$IGcx%)M<@bCɁ_=P~$:w%K$(@$) TV„ hr6Z !/~.ܹ (+upIR1HRXo5,|shMG@??(,$!$e³ْؓ7Z}nu-z'$@$) Tݍʉׁ̡#GE藗 #f4lYx 'gaT}ͅYKDг' m< W0<['/:ʹs~ᒤ`4|99nݶ/ oDlvx|IRZ3HRX F^HV>Nj ݺ%lNš3'1D /!9sҝyzl9I1HR۸6mv זkո1cU%IG"I).~o s /f@$IG"I).@Z $̓`"ع3O^ /vlqR: Çë}IDR\i)n!}@F96,Ia2HR+/M X؂ճ'4iߒM $I"I) N̚byq[$I"I)I Xq#F@<; fWV=$7 s\I$>$eiqR?FۻMEKy%I"I):/&"anÒ$:$  2y'`bpCմ5-Wg}jIR3HR +/<泻]UK,e%%ԒeVV)f #s bV^Hv^4<ϚՕ|~IR1HR ++ i<(r\ZŶ@$I"I)lh"r蒤Cc84N`OM(^Iҡ1HR k=FЫW4䰶e_Z@$I"I)Mi1-zCNNd5G n$$NS.WUK xpCm#Ij ºm_yt\ͣիaHˑ$5pIJQwm v64N*~2 ĿNH:$;CaCȢNE@Z4kf$}%Imrxyز.^̩OE@m cp|NIRgDRHYYxU̮!ҚZEY9C1c$Ij B䬳`Xb A΀ nRȑamƌhk$5\IJ!eegK}8iv1}OGV΁H>DRHy9kMW7BkY+3x0̛uA"I) =(-͛V(.`hˑ$5\IJ!8ܹ`qAӦP\LjUI*$rЁ@wK o_X:TVF]$!2HR 9xh$ͭ 6D]$!2HR @ KT7$Z[b))֛X2z$I DRĶmctj.mq!v@$Iu3HR߂~ܞa߾@ {q1]@$Iu3HR(/.qZA.+IHIJHbh"|D7Hb -VW bTk"Iҁ "ˡysYO-{ /#$@3fK.k׮4oޜ|xD$??"-ZTk}ҤIdgg3x*/!1@QU }7$I $Ai7o~>Ν;G]o_8IOEq#+]@ &Mw.HPRy6lwy'wXt)z+w_IJ!VuK ׿?,\HJ5Hs$F3<uR܃.BbԨ94֭f #Gv.HPl:.+.-I@q1F…1$0HRva, @zXѣomI"I +Wm ϋ~#z2%$IQ3HRv-tCкu%P7pMpiG\$)rIj**t!|#*ݏxak$E"I woh|lYv[0TgOuI"ejҩ"#2\tXZq]H@$*) nB!To5q͚$5IjNS];$$5PkB6xiq8. о}k^qMH@$*)1ާO/8 +++eD2DkS޸xIXIlIjju@R5G_ujLgjZ8vX"uH'a@$)@$;7\Bv-, @zנ@$IURpQ嗇ُM=)zo\ЫWaC֤iӈk$E$50W/wZίm>ҚJw/Y$e$5 ۷֭a@@# K2DâgOh&Mî]IDxg`JI%Kh:cdݺԉp ֖-@rsóX,OIR1HRRZ YYСs)@:v֭>:Lf4l7.TD"I"I Ⱥut |ޫWHu5[$)@$)- {o"Ib$Ȇ P^nD2DҪ-Xvҥ@,cGض-$e$5 Uu@, wgK' WwxHRf2HRp0cFإԩso\Ӧj!{@$)3D]$eM?#cG`|h۶@Hͭ1HRf"I93< óS'`| ۖEIX:[$)3@$)bEEaR˖ϝ:N%KȮCv@$)S@$)bEE0t(|Ƕ 3 Kz$e0$Eg?GcV@z4[YmY2HRm ͎0|? H׮Т,X@NЭ~:,Zuqd1HRf ?6bЯ_udٲp=Ț5pIR3HRqc0yڬ4OtIXg c”)pPVQ'IJ4$"4(j#xQURxh:w/D[$)9 z K]D2D"s'̝{@)+ 78 +.Y6z$IIg̙8h7OIh$e $E Hb>ՕP͚LJAt1HR0HRDWMX7=`*= pP"I"I),<`za; 9 {al62%,_[V/u$e $EvNy3^$~bAx2$IIc_X\ <=~5au۷Ö-$IJ$E`Æl׮b#+#]5oz ކ.I"I2gNƼEHjJkm蒔9 xmso3m%)@$)CVScq8jJNj2QhDҟD"aۯ6m+3+@6X vU"II Ƿ#eJ s yy $IJoIA9s ;;O$!C"I! IDATI t@́}c")<(] EX$) VTT_Li޼9 WUeIt@2jm<8ŋ.QRD֯ZL;+ү_x.\Q=3$HӦM(((o$5 : yVܠAaΝE X($I ڵ+ͣSN;v|;aڴiSk0#)lW^~A6հiSgCNb>F; I&1iҤZk7naI#F0eVZE߾}׬Y;qD^zu? ++l`gj9{.DRCP>|xD`%ȧ?i~Z~GF83#JR Q#1>gN8 gHkLvv_5@u $3; 2tP*?w^N?t^~eqz:wuN; z c@C[$S T֬ ha]0$O=ɓ98q"Ǐ4I(,|n=̞p)a^ɩ> kb:4$I/x999p ,]]vQ\\l2TY\ Ç,`׮pސ!Q̓U9@$)=@$) ;j-Ο~dР=1#7bI҇DZ޽k,nxƿTAn '^6IR3HR̘aUYOh2nDӟB}{(*.IR3HRUVo0kۯ ={Bn. 3gFX$@$).44x0X0oDҍDlڴY 6lٸój=.??V^AM0HRMyy5n?; qkkl ܆%I"I 6}zw ΚmqERSӨQ8*~2X>}mnÒaڴ)*:(n~UX P#++k2HR0HR͜O>@?X~~Hk{Z˃ŋ#IT @˗g^5n Q@j6 vyj-wWGT$@$)Vig!C–[u$($%ЊУfANN~-ZӰ PRQ]ze3nc"AnmX @+Vqna! I= ^~~W VET$^@$)A*+.3m0ض -^j64HRz0HRl۷@ !dĈjW؆.D҃DdŊ@ zUmÙ́x$$%ʕY+̘BfԔ>d"I"I b4n6l+@$)}@$)A'`eKkW@wƍlYRnD 5gNG۰u mÆj$$%2cdg;t]@mX A>5 zӦՔ2J?YL ׇ_X1C5jvGк5nuID`ׯja0ǡ5* W݈u%I:jIJx۷ja0nЌo]4bDҁD8lj޼jrr`HJmۆ[oU/ .w\.º$IG"I pa'YM)礓ju@HRj3HRט"Q]piܼyaG$)@$UT0w.i])g(ؽfqG8G#OtD TV? dO>9ҺRΐ!иq9qxH&PRam#fzY7ޡZC!4Cḱ\{mx;æM&I:bIGW^ g _a:Nk:\"IJ=PѝwSTqȌj6lܦIJUI'ʟz*dgW-ƿyvȜtRxN֭ TO> 4<ڷ9jT$5>}y90HR*3HR=)/j,oubA3 TO֯σ: n::\EE3 TO [{9~ƌ ϯ^r $.$Փvf?rtN:)L/X!͛k5E$I)"IdqFU o-[€֕7ZM0eKuIDF>WGSꀀ۰$)@$8O:zcej`TfzR2~X8HkJӦGJR1HR=@^yrr@/;K H6a$$ՓZ[^}FԪcTρKRDIu2_կ1c`,ؼMC"I"I2%KN?=˘1a76,g@$)@$lUu@^}bӪWcIJ=IׇgC*~b kDRDͰ|y}o|F]zsи1|ː>2%LUȋ"CǎkluaCugŊQ"?Yw 1*2gß 6p [.Id$֯_ 7 7@{"*x rsтa-,SuVst`I'tЁo}[Q"H_^x6SOҳ' /X}DR[dѢE<L8UVUܹݻw|rZjE۶m &ЦMZk$nIZcZxpn&֕Q>N0QۤI4iR7FTM0$ի`?{ń ~k'N$???eJ:Ba;wkM7EZS9\xrJVҮqv@$ջ~\TT#(=@dРAL<֑'?a֭s=; %Zdtر#|C9p33бWHR0$HKZ/~_$գZ0ȠA֔qڶѣcǯzb1/"AsO\ԩti$od/^eH:Jd:(*ݨ[rHR0Haڷ˫3τq")c  ;3֭ 3 'ŏJ$5,I:LWCEt<4Uc?*+ Ǝ%w3] )y3̟uq@$0B .)Gk%w +WF[$n%IO^-[ Q:>_*:%II: w?N~խ uY-~o|88$5TI: ӦUSOGkGoܸ0k=z@$2Haf a_5][K/!8"I Dܹ0r$4s }v% -''!,_%I:DêUн;asYKmp]'G!iSԅIdðz5i\pA娦. &=z%aIRcCcl#>n"KRMG !'O’@$^SO]-Hee%tTIND"$UhW<|Q\v>fӽD"$ի""knQ]>Zɓ D($U 0kн{.&OgOX,$I2H!*_s=`,[/aҨ$"I׾?)t)|&~}м9ypz$0HGع~,z;=.KysRt$50I~c6FozC~ hl6,Ij` {tk:f`ٟ$}B_ @$#<,>|üZuI:ԧl$.IR IWÜ9pɨ.7F]YAQW"I"I0ϖx.XÓŢ1*wIR$}adzo| Q#ҡO<u)*I7—rرQ#!.ET"Ibӆ}|b_7>}ciSPZu9$ ͟Bk~ڴ)?>Õ@$ew߅_SZ#G&(՛VOQ#I")MlTcQkX,t쫡{'$E")㕕}+5vǚ_\골 ~ˑgsʔ}}&[GVGn.ܝ^=7G]$e4WV` /v mDVInnx;`NxH둤LgˡgO?V~[*奭# i{wh -^ 0$E")㕕?~׻VO_2fIYYп?,X|[0obeIR2Hh{ӯ߇f?4 sg/uI 2Z|CgnoϗY%`I' 3f1?z ?$)#@$ex9Xik#dYh~˒d'`uhW/ŌarskתΚ5|%܌ukԥIR1HhH…4n a׀X =Ql=i] 2ZY4j~s8dbwp$o&p1QWrU]=gw{F]$eV^g."pnJ7/Tpul\LS$I")y u5; kh9vZ8T84V6IIJeAv@ѰgS΀zmx꒤LbnuY]X4Z]ӯ<7 M›oX; .$%DRfZGv~H.MjgYUziFɓ?b%!7 =u 27SX~[e:t8g䗥;t6-}UƅyD,IJ0{ìOISv %uYóV-b!̜ {IR3H<]}0W0Ѽ9 Wppӟz;$%DRfy饰[Y`TgfB]M`[`ӟ-NҘDR樨N: .h*D\E 3f7gn@IJSIo3; cp)pMaOG[$)̰}{E@Iۯ27^ 7B6Y{]weQ(Ii@iѢ={+`ѢEQ&enk?^a$?'o_Xp;z۶!JUNo7xO}S <^y78p`%Ja?>}KJ82[,\~߯_Ui"lJxꮙ$@keȑ|W0h ?yʊx0~<uu@Ws_:HYX̒$5`%ѣk>}0`,XQURyIxX3U/oBQM}ªUk,>7;$)m@R:tu)R۲ƏdX{ 3g$< _𬾜p0waIGy5kpWD]~CXg. c޼/YnRMpaş :w}-ݓ$H-Xo~r)|_)r>=??sխ}pUҼ9?L T IvZ.ڶm?N,$)}mW_ Fuؘ7, `|3l;b1ͅR80>a^Y}<+ 6mĸqؼy3;wO06mZ+(( eJ?{}X6,/XO=wnH|T/~Dx'7s"|K_[ۤI4iR7FTMUV5v>1fΜɔ)S8#.(**b*4 𱏅S] peKvk]©Bv!4n\sر_·ikG$о}+x뭷CR=(+ ǝw^*SeZ89snO~שS!}L{A~CEbIkzcR^^ΟZ$գʰ5f^x1{@yyiϏN#C ={sgdIRr$f͚E,㩧⩧Z,|DIi{_uպu!t?xbu*\|1Lf5F~HkTcI^z);p^w$Cqᤴg@׾cg?Yj܂%)[Ȣ;8Q;|$>ƍsgj .j؆կ:"I")u L8WǡIn^y%e1:ƎaӦkCoz/͛+RRDRяWíqݻa;ᦛ[JJc! :B _[{'~sፒd|+:p0ы/ ׮5.㏇֭qgN_뮋DIJ)IgTWoK+VgeeǡdϞ#6TiXC #SR$s~s΁_#3;K_aaj̛\=zQIAHJkքcv{su vXf3h.$+3T IDATO ]{oH,9眐z ^$; RCy9w^׿U:߶re'g˖%D;Z~oQDJRӜ4͡Ӥu,pciV`S9,  q A . {\lkggՈ1X8}:G0=AH5@z%RfJ3 "R%%1)^ @DRFܵHd$$x…@PЭpK*"R)-- n=3g F\ODLp0ݻv H,n:qK6DDJgO`VnqڤdldC4"f,ȤI@v #+ DD2 "R:%%[eipպueKy)<|ToB P6bQ""@Fgr=e@۶b 67sTP"ׁ}'υ @ , Bڶ"")]c~\p޲ӻEGe0 k8ۛDG@Ps֮?jvRF)=vbUj*;ky5:eٗ5 ަD\W[D\Y\E)Hb# `z+Ct4P.м9~t]PE3SP~^nZFH>cgE RCݮw67 VrAyE$11D׮@BB!Xwu:6 3.΢* @DdfO?UOw[""7 "R2;McGldv \l^V臉 x|9/(5OLjт'󦢢Wps ޚ5l"d ii

' K9Kn]WDP""+;2 kr(L|v836n}ۑ#:CJ7-C8̶m\Xyـ`*_6 H9z.`n7ms aZ^c0xdHP^+`j:ؚL௿wV{ℵ)_aaܒzXhl\)9 @Def4lt)S@39s߱`}wY*ls3acS(ظNQ@JJQ]D(z5ӭ^y[Cڵw;,HrES\kQ;DD\S[ǵigm٢+)~; >g΄̝ | Y'$8xn?ڵyy۷qc'~BRH\RSCy=D;\ ੧|~}I`&re [H n u! Nr>><2*U.sQQ|v#""R*)r[[n"ƍ \a-3yڝwZqA+V }{߾lߎכP:Ԭ L=ѣ5835""R(bc1cx<mmڴPOO@ja ^gqiƧ*Wqc2Ut),QQJ<0 "b1 C$>X{\9 "7:`筷Ff͸ԠA xOۺuZ@;ȍ"%Eml,4ޞ1?-ƍ˷kǴ9sެ3?~6횖\6d?; @|}3!C~)vB;3=s\kUtݴ\ÇyfD:~=ܻ(Wv//z5lL0׏#yɑ+xw|}1;C^^h'+Z@[]С^Wz԰!}GE`˝;Yr6/@ 0W GڵXyC6rHswAY(K:11qn42Uax ?u{`ӤI8zŋOOfNW)nkVʕ\2t(бviԈK3^w"Э[$=mX6` "c-[omŶQV CV"G>8kO[qH^)VSa b?#䭧8\:d{g sXP7W~nlĚ5u3`~+ +:E3?wu9*ˎXUZfpݛ3;:y8h޿?; E[f^8ΚYِ {I~οxeRnRDJ3g%ƍڴ8ߨU舡Šz‘ڵvFǔD^[g v<=GTSSk>tY? ~~\jlV*'b5!5Qϟs@7gnqf f#_~q;(,~f0Ökظ9+V/ $ǾhdZfVHH)f@DJBj*ax> {+2< {x:vDž i*;;efd i`~~u+w w\aYa x;7ЩSow$@͝ ug6&Nd9sDccյ+ʝt˖Z-s[4k7JIg.o߄sVN '1[&8xT}YZ 8Zr̕}.YD;, yo XQFDlt6HF Mر=ahj </p۰ YwWVɁ[oV9g4lxek_j㵕Qzıc${.krb45|8v srDN!|1"# >N''%Na.Lr TvzE@/ Pʔa k޽Y|w͙',XDr^S8SNpÆ LQgGW͜(=#Ú8K@%3(9=YyVL /GoY+grW[<yzi:yUER+֭9vr\Gƌ>fJK{y:rk53K4+5Yf@x8G;v犌dyȢ+ '5áC|/"8//6 rV <n].u+q6M@ԑ#DJ++qM偺OkrQ#Q׭y6ݻ_0JDG;~;#GeԹ'u^ڟ~TSXYv$gi GP;dy~}OK6jOdUnEqwL0@+qcbTʟ~~s#ٳkw}}YGڵ٧!9ziHGr\&Lq^{a͛.^dessckL=xdTX DVZXMğL+j20Á5k]Yy{{ts'&O/8[2>GD8w ))T)b @{pf9z~f;.ꏎ!qg4;fcʖS@:8ע \GaP@{ o9nogVF%wdfv9W2:pm3gfy,H 3 [0:$*?$ @"#0a0vNڷђ%3+V~5jomAkix[yYcuפIދg5,;ƺ @&N]w92eXΛ`^;u8e[rg381g g!m11GaOj@vhUSb$ZUeW22 ":d&QVhb=# XD8(eV0GwsIơxv׉h"Ѩ 5٭Se@Bw"t6;D[xo4ggcCeo[; J,y4kְ`o\l>>7"Rt*V䗹{n&  gN#F߻70 55iL8⟒:Ҙrtȶf,>qc$>A:vL ;чq& bVW_AӾ},-'zK\:@u:MB.'8zFơX3pb1®qs[hTE PMe-橒͆=g@L}ƎxjWlɜE>KF>KڊW~v%=m[o6 f+Ez޴9h߰!w>[fQ?\Nӎ TBW։(xmMnnCBո1[QK_o ƽ ;)xT HQط"r e21 []˴SwmLذ?0v130HMeŠ06TM#AA|[E[ˎqsv2 H0gOϞրo) adx8;fw.pk҄uԩ rYƍ`_zu>׼y=N槟:vL תULKcfnU 0U, [־}MM h;j&/Ÿqb)!G,UAXlߟ?9`fnob}2.`t YUe6VW@rيx@xx_ bsmȟY{Qd^6s:@̶C石ިO4mʀj;=) @J93׿AV͆`Q\ѫwBG VoF.Kcβ8{8s"yYsM;ގgvG_yT©JkJr00C\@^ܒ66dCs$\ɧOSg6۷~Ys-0'9ÿC1kcU ' β< g2zbgܵQ#>EΔ)÷{jds)977~ ;R;`}A93%gW[֬fE͖-,نT[;GrL댉K@6{s|r0Jyk'OXe>W: 13)[ç}z3 ٬d3(I:#|<.;>XISU ^9PW@*aV/ =ع66!!!wԱc0ε\@$gܹ|[_jnc EF:D OH1qW_!117[o;aB0_1+gV)c8k6 vaφspO;zUp9gCfs8b8, céɓ1E!nG{z; IDAT9}z 265qOظ<{jV.ۗ)Lfj~5|8_~aEZ,+9g+g,Đ! hkM0~cGV*Xݲ% wTmRR3Ul"R<*V9#q Y3ـ+|Qx͚LVAs6LVzfŋV}Ի7$+Xo=Sm>kBL:s?䗷7wOH5))PZ+_|?ܜ]ٸN줶m7- 8 +^ Ffg`ul/PRz=AgP4Vx>aggЯip:o4`< t X7|y eR0 @ڥ+?T,[frgΚ;gZd[/Ԙ1l m 1y?Zw#GrA}QSRCbΜ95j֭ӧgϞXb7aRIMET )NEo"{f*5RaKE8$ONd'"+9e/ɘw.}]EAv`Rqy#ǃ?~ @*i"0M(V[9p/ڰ5k0ֈ fv{X{W16-Z00hZ͓o\]ۚȶml;ube-.ݹ#<?3nԯVjlX )-ZOi9rf-RA~%"%fc'!NO?]s6kƺ,zVKQ.0`0;w.c4^o_{yr @:uϏ>ʴb0qmv91t(?o^=v&ُw28 v-'cm˖~y½ZL ܀/> [\Ӂ3g𷁉س> YI@j'!b"_g%gؒ1tpۅ$HNrz8K_ٰ!e!a?<^ͽ,?XKPa*n>>oon? >>yF#qqɜuOǎl$.{!S7pmEQRM6DŽ 0Ҧ=nVXvmn/_Bk"`o\e"/8ㇳ}qB%쉫$_ }F9}?z Sش ^~?N]ѓ^hz Wx2u+?js:嗁YS/A9}bd6pΦJ lw;tGxz ؀tNVŠ|)v46ntsv放kT/aei U0{aREEgs7le^tDﵿd*LJǭB^T Dtq\8Ÿ_ W:ɬ62ls1`g{95jĺ}R<,_CǍc֞%/ϳOH`pU.w4m͹sa..넄11͝Z9ε9[T~G[ך93^^,ŋ#Ec <׋p^ TgZ- .IJ0w ^|2 KA)($ǥoR)} k|2R{ w#ЃE|r H.}n>9y ipO {/L} wtm=ybB/Md,:^SRLfϞ www >ux0fĠj^뫯vOE'?xE;|~_b*( P"Rژaܙ6(hF<#wpT]rĬ[am; @l6.J_3}|M82s&Ӫee-3iJޝuX AAl;.kWbµ%{25zRUGkޜmΝ43u|khYÊpPkx2&aa쀛;aˁY?|8;C0w6,ƍ|ڳ'>uԭZ>v,׮eV`ҡb7+={8|L;)$/S޲%߇͛83ӭrirNcGNAKv]1 N뛍'g[>_@_t,g&l9רz72Gre81()mWgd~ދBQpw뭬BB?;"""w:?r`ֵ@]r0g8wu fMޝg|8{g5edp1;[m.10>4~`sXہ^<0o^y(~Dc?zO<i}~GP?Oķ -=d#;O<3tDGe`܋xo::te_ LJtT=[j:x$f @jKR,5jdy睹߽{aٌiӦm˖-c˖-a͆ƍ} 2m #"0uuO~O>ݻ cHH0 U+Ø<0l6HO7'yٳ \V;vr(^FF,5 XG5{5NG>a1 oo 3l>ca\G0:u{| lYèV}x0j6 x] n/ 㧟oUfa,\ȟ#^_gb޶ka;XEe,*˖ 'Y #..:rw_ Jկom\Ͷ߿Zuٶm7syw?7 77HI2Yxi1faT:0&M?1u o_>caT`?o!!1va [ǚmiVÈbW:E{?=Zj c:w6>}V{ynRR g~ܺ_T3h~"wɕ H19<<҉sO[ΝV#.\0]' ;rqd\\ݻ7ӗvvT{p4$v樆ynNL728żx1g 1CfL͋/ soكUrX۶-R?ٞxftS9RNއㅆZ3 gAuvG3/ٜ!h|i9+_uk>ǰa\ӣu[zd?X96Ul)vuxi#vrv1(F$!!UU˚0 o,ڵV[ats6}O oЀ3+VpnieqiiS]6eiN[=1#}@i \e'JPΞ}}| =1dG1k3`ȹIp0;92q?!!w @*W=e>f n{;~| m[Q*+>ˋ]kg^^qZҥ̝[ Hz @̷bEEfɑxxjqw iRa_/_<8\  tzuvڵc{ί{ 5۸ yVuݤ 4i5"[edb~ـ&My9{Ν֮[39fav>疷W",kGT3g~ n-Zp6<9Z~ʶ);1<׸qlg9gJtE83olٷ8xgӉW@3 &""@rr7n4Ĩo(Sf>cXa >k'g(FFrt^ÆHPkɲfװaQ:5)fU|J8r뭹JV +rDfa.TS ʟ 3s)<_/?o<)pllK^L0x .;@3,\n;Udv|sL @WA-8#r%[⌂ywrYofLJ3;fu+|F v͍}tx? 7AfxyYY(1֭~Qayyq_sb"I?ՠ` :j|/?~B) Ť4 L>[{,j+Ls{ՂksZ P~,Y46e߹3Nsz+?YYgNLcpC`y0LWb1HرpFrkt%s_ftf[q81m'&sp.G9PΞd6|M˖}_ g*N`[?ck5+uYg}?3+ @x32&Xf] Ӽ{Ҝ׊^_ϞL;we0*_kRN`\#WO)XŤe˖0`^y#<<3f@tt4Oc[f(| 3fRÌJȿR8裎#Vޥ A+sԛ5dζT\ ^^1gmlN)ьŎdl nтCl6ClyoRZqF6quj X~Mk3Mj6oī/%3m)00Yv8X\-FH1ᅬ6)6Sv̽ ^^ٳ5es2g?J` \ n]Vtٛ٣t DDJ7sҢLʬXQbJ Uib(ŵ:/p9[%GVvh5iu)َ3]y Ji H)b2asR)m|K"""zf'3 @`bϞY&NCpzIڕlh̀4n \;ɵQRJ-{mת4 w3)Lȍwop{eNAAֶрtvfGIЁU9 g@-`S5YkEхq=<׏חVYH` v~\\=̀S!!}ڵCbb"֬Y8NDDDDFHHksؿ?VX.HSRU!5IDATL^̟?Æ ˵\rӧOLDDDD))&kFtt4jÇKT"""""%K"QR dddॗ^Bhh(|||кuk,[%7+WצMJxrJMMѽ{wTPnnn1cݻݻwGrPbE<8uꔋK,׫ :i=נA(\6oތgy5j֬"***}U]DX :sQPn]L>={Ċ+жmے.`}Yhl-LBB|MԬYM6ʕ+arС; 99&LΝ;i&xxx@zR5_|p]@@+)7{ׯǀиqcaʔ)Ć ШQ#׮!%jƍf3&NxtN:^%͊+ f̙3"7 ɓaal6cƌOƱc._l2fӦMsYyUGy(W'7uEEE^^^ƃ>x:kWO)X%lpww/_{ ׯGLLL NnDa 99/^, lٲ̙޽{Zjҥ ի~)׿gggܹs(`ڴiww$:uaÆطoT]= %l۶mW7Sdo^Œأ>x{{sزeKIInp111HHH@s֢E l۶J%74|X"yt:fN< ׮ր8޼.66E'={"((wƄ о}{[M6-" *..Μ9LKK K/HdggcѢE:u*v؁+WL2%]D}7[o@ڵRRΟ?OO\{yy]](imڴs޽ѿ4n -ZTYTשëٳgc%T2^۷O?4nv<#T]+`0oooddd>=="%<<}+ ̩Zf=NJʨQ˗tQ:s ={T] %,$$i9"MZjpؘ) ff/..+V(+///TPgΜ)u$)) =zsxbTRm׮ 997>|޹6B)*UVEJy\mڴId:u *U*u"==w}7< ~^6 @JXiӦ].##ӧOG֭Qj,Hr]c̟?ݺu+ p-_QQQ0`@ Ln$7tEPVV7b֬Yhժ^z6C%n7oFp̘1/_vڕtѹsgM6ƞ={0m4xzzb[Jr2e > <7rH㈈@"99|jԨ͛7+UA 3g ""C \-Y-B=p’,\'{9|Ǹ> ^ @J ;_5Ξ=&M7D׮]Khr(<HkD"|_"Ic9I֭iiiIBI$)ux#B)C͜93te֔,I"e(Q+YYS& $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $eV B), n,tIRHR[ b1(/D), **G $)Y, M`Y$I"IF|d4DDHR㪫 /"IJ $e͛ӮJKaHׁH"Ij wr/_#w|k0~dtf9A[oetڕ,~_|sWX9S֭^{-uuuIN,It\_౵qͱ$IirmmƪU()) y՜}ټ;|;+_ O>$^x!MMMɎ-I׿3)1ȢE[_ǚ7#nqc萒t:@)**b˖-ٓŋ3a„|wYd `ĉ\x?s\2cKRg>47ɥ7P)wxkOoȭK$#G@NP^^={ ;4~K.p3l0~%<$cbehyr.xZز%HLIRz$MضmǏc&L`ɒ%RIxw k}j}>MM0fzN$oC~ 1%I555}Ӈ۷DRrmx#nqZ|VW-t{?TV&7$)Y@`ﱂ#II1gdgíQ tySsȮn7'9$)Y@]v8p}566IJ]{ _ΝM7l<YY0~<1"~r_D$7 I;ٰaHG}GyH$µ^KNׯ/_җ׿N~~>\r wy燮Lya﬋0oL> ׆~\ Wða .IJ{nݺzިQxgFavG| uSD"Ν0cƇC0 >U+/cw )| HҖk@$)47CUDW=ޱg>\s <|3н{| _2cF| ]i\ HҚ# fL9o {G@.<~{ 6>n "IqHRy?qzOzѓz sM;#IG,IJX!^Lz'womᗜ|$0 $X,~W7p!z+hnWE"Q|ˉY:%I"IiW).ZgܡCOyɏ%I"Ii`qrIv<SsZ|;w`A{AIRƲHR8|oT Onǘ014͠/J2D-v첂gYs`Ŋֲd:y͍KE%I"Ii`8+zFi7\"1uSxH6f Ӱ$I'"Ii`4idv ΈjN&KҟD0_n|ӷob3b<]7'"f4aLy}{9DsN΍ $)Y@$) vuS'7.a˃!== ?HҗDRܑ-x 99 ȑFiHNDR܆ O#,{ ;/9{[?w@$8Y@$)mSr$r }v¯7n $S7LSv>Lke[q@aINDRS[T Icyz"I:~IJa--Pr`!;MJu~r I$)uY@$)Xxc[@"^ȡז$e&%qg%A/IJ=IJaRF)o$)X@$): D /*L]Dt|, ZZ `]PXoNc;m[bTz5w$DD'o&$)X@$)U-/;y7 ʞnӰ$IDR…l4^SayljIqHRZeϠG1`Qp†$yIJE t)'ѽ{(}'A}=gy}$mIJEee+M PԾo.IIJE k׎wFA=y'r*XfXe];Dz1qf'~|=63ްH>DRȆ ?0o)cԩa3ŏoNd\%o4 $Ij, BmjPUM7oRa!Ǔ|cGL"I)d68dcSR>Љ/N,a,KX(t*IR[emX^s"??t/S`&-q$, B2"(z熎>cRP塓H* $HƎeX[ln DFY@$)ȐaQ>Xi)%kۡH( $+ɉj# k"Ij, Bzm.9 cƄz`׾nZH" $K>ڵ G2C'$EIJ!#ʨF_3~,cY*`I"I)b߮CiѶ HJ6v,:$ HRJHmqwZ$lIRdq2r'N .tXm$DRDdIkBBGp禲I$ImDRD,tw/?;$DRA,FaUrmywQJC{3I, h".rС#GncIJ5kgch$%4Nek偓HښUEESNٳgӵkW^}UnV/^%Jzr|zLB/97tIRbI|O2rH><](,, RRʨ1-O 丌(" $)X $={uwdgg"TUQQ6,;t㒛 5=P"tIRcI믿^z|KqF~r2k֬w $J3dH$ǯ8JĚ[BG$!)**b\c2p@fΜɬY;CǓJZZ`2cQNKXt;w iwBG$!eƌb1>yznv+tdHڞch֝$s2wܣܹ3PaI&?cqӻw%^ͫ{Rk}g!Z:$$Ș1cx;v,馛XnwqsOxRʕDy9rDΘQawD$8q"O?tRKڷg[䯲H6lJ"Bz 4Cq$ , Ԧmx:89ɽQ$ImDڰ4ҭ[$'۴1t~ FDڪ]ݴSC'ho;>Y$IY@$j)GG' l:$)4 $Q^>"t&+ Q`Vhj HDڨef䇎эCrb1 FDڨȲ *һw$ crrhba$I!Y@$-Ne1c:0V[@$)Y@$-!vֵ/ tV//.gӦY$IAY@$-`[.]_?P$e8 $E4fyIZϘ1ͲHRHR[TQ'Fz"I.~IR`YV,@? U޸+tIR@Ijc7[:M+:zY , |46FcAKV6T0P, thzoTRS:$) $! 0mtg+=khYL KRHRR[ Q*=0 u卋RL%7BG$b6()NԺ ӝz:$) $!u351񝰲WTN"I "ImdB3$4fHHRŌ[|(,{obz 'ѺwJtؼGdI ĈRAѴ/ PݹfX2tIRY@$)2p&: :Q9p@$)X@$)2(#g. p$hߧ9XVA,:$), о}YH *cG.50t cQA%g kքN$IJ $t)bpJ(.ogOxs1gUy3y&N%IJM'ImTYAx 1Qf6 J I JrDu/A{ kjB&$%D*+N[F0bdgӧ"I"I46²e00V&PPCyc߲%pIRRX@$)J8tF*Be @ht$e $RV+xm(PQA1 $e $RVFA̛~uD4 Zk a@/34ڵ[@ϯHRHRAEL<~'LuЮZ*].I"Iw߂ѣ %;FbH,:$), @}}ث"> СC@!E FhI `"sQ\LMˈ:II H(ٍ fD2DؾROvmM.@?…蒔, @}=LjxzCkWV:"I"IlU@^ :NXbWP]:$), @}=# 77tQTRY:$), 0 U\L}X@$HRc W#Qc֮ba$IdI2.2uFF? KR`y[hߴ# >JK"IJٟ'.Rƍ-BǎYv-6m MR`Q:w&ֿ?ck*)/ / H(ٽ{7^{-^z)=P8ژ*8PЉCGi3"Ŝ$5`%o~n}hii JR[|vD8T,IJsyԩ7ndr)/~Ed۷:4qQwws`0D$Ț5k8tW\q3fG{ OR@k GQvho8$)a\ {n9spWpA~o}!CN))kȣyg1Mw^[޽1pIR$нˀ~ƣ>ʠA3gf MRצV0tꩴ=PڵPR:$Y@(''[n[n%tIm7BNYF6eg2bK+Y $!׀HR,^?i(#!//l6,$ ~kaЉ$I"IIx1B p ?Tq1#cx^x!t IRkHR,Zƶ1P(ZX:uЁ$I"I k, 8~W2v,,Y8$UY@$)֭Z8 ȇ+*.]RG@$)X@$),G5C}>\$4{X]]Pb{WהG?"Бھh**;6Ӱ$)}X@$)^}L %I"I kTT٥{]qQ8t5()HR:HR-Y., g#aڰq$I"I aCط`ԨRE.ЯTVүl:$X@$)gO[YÇCAAH**nЁ$I"I TU_Be%}gԄ$Ij IJ*?X'֯=Ӱ$)]X@$)`LvXh;+FZ, X)Q 'SYJA# ., ۷CC i(Ν:èQDE߾IJIJOH@z˭x%)X@$)A6n ׻I+)r9d4aN~g;`hlk, &, UU02"--tnz~IRjHRTUY@Vdu p8p _, 6@Il ۇƎ% %)X@$)A֬ K4tVR)YL, aqR[I ~J o:$飲HR^ XM΁ GURbY$ID`jK|‘?uB)HR:HRZgw\kqR[$%%nzaЁ$ID`jW^[ @fX22 Hk))!wZa"XB$ $8vX@ZKI X)߅ѣC$ $*ut:F<._F.55CINDZ+wjBIyyr^bwoص+t(IɰHR+wknK76ZǸq@/,;$ $}>in RqIJUIj%wSGmܸ K),HRHR+ٱb1t H*.\X"I)"I.~e1r 6Pχ1c- dVR_?v{t,muDR%) V, †IWwk"I)"IzMU0~|8i8hnf_.IJ-Ij%pNEO, qx!m`ϞЁ$I'"I/]aqS~>DߐiXz, J`|w@OqDRDZI}]9*ƍe߭x%)Y@$Dj6wJq473rG@$)Y@$fG@+%xY@$)Y@$}{:}CGIoPRB $ $X F7I`'CdDZIJAIjv"pURLĐ:$Y@$ZnlX'ŤItYf e{7l9g8C; }r ?$I:^I:Iw_ 60z":,{gC$/ $ ~:VkL[Щ2GUID1m Ft, ItE4 ER+?wS72Ici$I$qtЁ[tJiHY[:@9g av:"I)$_W2e Ǐ'#05/ )`}\=h# B, I0|~a̙C,sDJMMP__ _gY~)U^XSWM7ض-$$Xss37x#=zt8Zɑ)?L5L&U$ٓ'sS-gOD:@{ER+:cT~ &M"c(g۶t:$/[n[n{sJiHurΚ0M+)%'IDR$oҽ{wnQ$#˪סo_/lLUP@st,Sx"I))X f>̙Cuu9x 6lSNt}={6;w>̙39sfsK:>PX9o)L]v+^Ilܹ̝;s;w &}X@dӦM0k,f͚ٳ뮻؜9s(--MFLI'lEBhYgOeؿz#?tIi.++cܸq HDQ}ѣ܍b|d޽|N PGQ[ ;6e EY@[n\~;wpe%;VT[ W:#avCDR$"7"@m-4.q2ޚ^S91$I]^L3`k@$H X yӯڦiॗЯ   HY@$^+\VM۷3r]B$oI:6. ?ڪ3΀mzp$EI:NCޗץ/ :>H~>y&]" $M+1i<1u I#'pϱn]0H҇xY;E17t".LPbO(H҇x̤J7o9._Љt>6\3Q$Iacش *+Nh/`y3=:t*NcS!U<:$=, t Ǐ6gy{ͤztX,tIaI:;LN$:NT=تաHH1 ^ ?\|q8: YK#4<4,Ij+, t ;w9O0bD8: Fv`>gs $I:;b\d|W)ixtX"] $C۴W)sgX}:9M0~8$, [o>Icv{8ܤgR=7u$g΅n]>_R$zaUł?$Io6hn^z;kNsU1~rXVG2DRƫ{=''rhcA2:G2DR۶-~<<$c $ZψpjΰHR``M&bO=͗йstaɠ+7:t$IhIo6'wKDyOX@@V f rrBGfњ_ _* 0b c- ibX3L4,I ")Y޽;|[RS"4qh⋰cGH, 2ڑңG V$M\x!<v  I2DRF;V~) V-xQ4 8o:$e ŧ`_HÆcU%77~Gn!{ξiXdIk.ܴ˟~w㈧@Pgs;`ncUV%I")cLƇ<:t%׿K 7]/=CǒajjSi@n(I:t1c` X.}~Khl M2DRjxm)YL׆M ygav~(_$IJ {)KBGQ;ԩ`08ln}֬ LқDRfڽen99(3=>Lj/pk- `I闿$P#/l$ _+ٝ|zuT, oOO=;2p@jV,+]/'opiP0w.(^x!?ϟOii)˖- O\˖'tC|jБ$)99/3ar3ꫯ& N,?&6t(WmEAc-).f t]x3$:G@hG!C0j(V\(y.]aF`xaط?e7qz"-EҖ$bt=t)c\ ’%~l: YݡHRڲ$ٯk6oW_:1jjǵK T@SFd1tzQxq$)-Y@hʕ?#SLӟt8Rز%~oRޫ[7cO]h$Y@d˖-\|t҅z\r^Ƿ tD$G@ ;w$Ii]`׮]̘1ݻw/ӻw}ٳܹQfΜ̙3SJ[[z5m!_AX Lmw.G>?o?ۜCGܹs;wQvGb!Ycc#WŒ%Kx4i1[VVƸqXx1IL)ӣ-<MC>y8pBS[T[ Og> j֓ף0t$Im}tNJfj.\- mZ5*+ᢋફ,:^7_#y?r-$&`%Зex .Rկ~u\sMdRhjl+oz,Y&/)XK>e,8 "I@K.%OOX$HI'a4ys?gu+NTQɟ_@я] "I@/BRf;x߻GALlhnt$ qgwwfA QDR~6fnwo5 n)t(&I:qIi[gX;VDFӳgTJU,?c_!v]a %%IRHJ+|{wB]Ϝo9N8I"ؿp}X0~˦$)Y@$:ٸ{>{+J>S) 97vxAx5**4$$ RUwevҙ, H"is> %%%V,w$)Y@$U}$wƾMR# Rցd :}CUk^[wqU?uX  8Dq+fUʑ*JM4-GeYf}Ӝ#(T\F!-_/^n~7X[]-Q*88p+ȑ@ژk7 5ktT8;NN s@spXO:jU( @B 0op/nZ]:l4ɂ,X~5SGTI>#"PQ*L_'Ϙv*͛w}nXwm.Q*Pirbal L ;3KqrX4CFGxDD"BC4\XY!,L* vv~01FrrV>"UHu)B& c @nD \ ̝kb{ @x~^qhK/ll["U _~ 3|9.;wԮm2cM @ԍЯ\@Æ2W( 0ci+ @܊{qhGi !W5j8S[nDUg O~$"*w8 ʭ޿`භe+ VkcN @^ݻ 0d LH'Х$"*Q4^{ ܙ!!냌J֭eՏ?YYYޖuxm|!>DVE Dx,"*"fMC,Z{Ŧ(޽@۶-Fԩt,`ffׯqXY3|FtP \R""*,@%a\b܈6i~qyk:Y)[UȎDfo/@רX[8p b m6 ތQeʇ4嗁3K5Cj`o/Yofx9&317>pwgDi.wy6nr|| Xp""#`BD t$źu}~~@Ӧ_SHrI?nlLȦM?NN% Νڵ.^}7ei"ʌסC@V<OB>>@@;LkB t Cwy!o-S>sGYFk( y'DD"2駁z(-Чl&f>>rԩr2ص kvL.9;G~z] S͛U& @𢢀=ewߗuuq\3PڧcDջLiڻWk@y,6-f `KQWf`!DD "*3$$8o2[`v`ܝVλu?I&s9UIR<}ʿ²ewh4ĉ8,hIbBDe毿 %@DЯ,?ڽ;pႬtWvL4055^F|x^ 0i'2TKR-pK1_L:v"J]J&> RVmTcs5RaeUqR2}CH tX|=o͛TQPhv)e{7u3.ceBFF<,ETٙ+1FHyS ZZ p>Hf7l(;gQ%ǡtT;uG"{wSѥ ){'KTY=mL ruVib;R6l8phe&"zѣs劌;i?C8k䔼…@6g~+ǁ`gq,ߌY`W^&Nv3U!";yRf7j$36Lܸ@p 9 x_{ 8qBD zh4Q3 E ǏmXΝm&Y÷cGgÇ [AA]\' @(,ӭвD Jd(8m OOY3u5Abb"~l׹=v @O۰OhdӧnnӦ-ve$/BT9"&c&&? [?,'^ {-ѪnТ |Y&h!zKzfV}Q(QO41 sc3tf6Hz9p6y.`V : @*S#)ǓeҺuKVR(r%k;0q"%u4wIai P,WK_^'dWx @\]%IKΝ H۶`+y{dȳӧc C~_*F`BTA^-ƍE?>cЫW_ ٱ#t`zYׯ4i";dƍ2[|VJL2u~U:MGy\w˭ȐcYYS @ӥӡ]; iS`r(7B1sh×MT#W@@?O`GVJA @ԬQ(֭}qisdbwAgJ?f%._ZԖe,nuӦ5j{P <6nSW +"Pk}5ó޽%c^l6l(DE Mw)rQ=X@NnL:bv~ 4`fK)z1!.\dP|(òc'$#r2pgck{Gb +p&RƊ=[WweuPggc5j`ƃ(?FDwqZy#\krry. o ?2W1 `V ddHl {sUx i93j`yUw.Kb*`h̙?~ hر73j֔DTؗ_J'/jѦMP*Lˊgse^ +ҺvX֬+%m[Erx.:!-)JFV̲$!F!XxD˅E``э`H~i\\\DE@̟'P QxN5@eq:_%.#}7b7pvvm2T.Xnv0"a=fcqpG$.yIiթ#Q /`ܧ.o 5Mr&ɭ:Èܾ]xQeږ-ިQG|Z↥M"ٜ߯E y_5KM}QTAA@2 |}ej*{?,5Q>P8E @*m|hӈ|Wpp]4FXoSKjeDl42gMڰsq&L! ۯtY'SV̀89177 |%/sGΟ1C?j0> 48~ꌊBB0z숭-p_=/g[hXI0,5Q'.K{+| ֐Zyx}uq-0;gu@RpHxd.7.:]Zii2|ܺ%u^eSҝs>4ŋXl*#_Шy|&?oMR?Vm'i%yABK](K޺@6{NnǻmL zY {Y6t3F2WO2CJF 7 ,l +I}wL񰱑:B[WタFԩ߲U__/ = :%'9'6sV* q`Zc< oq$Hʒ:Q;))Үfd|^Dt:Tܔ(`VV!!>+߇Y(joA-?# H(LO>Y>5pє"bDD H]Z+W]$c>otn,3ǍuCr:ȱZF@3d0 8:݁/Ncnßq56SV<)cܤkW bce[I[Iǎؑ#z > 㣏NmΟQ̀4`Ϟ ,]*:%C}|$( 9 |]+oH?p_֮#Aڍ88· <;!Gɖ-8T?߻~})oúrEncbb(YY`-ugLGf>sqڽ}Kމ: ?MLWA'Z+:xCl)!ԗg$T^5Ԋ#-t(/ԩҝ%AE||:r& ~/kiΞ#e7iA%էlw`oՆ` #f1 ) v 9H7v~aacDݩ8oZ` `:$[MrP~"z4sC:.\(J΀!-+:/;'$7 UHdcjՒD]GS$^z .?}alu~V ;BCnDz:0l?s,Q2fzu n.0K<{6`E0wc%ܺU 9S/*ZD.wǣGj : ՅJ.f3Dz4?=*璒d'_P\33rhі?ʞ3(3;WR*ݹd>% ܞ?u: :7G(@&\B0lqtwbMeÓ^^8>Sn5ZEtnb+ OˏUi^ME&;8g$9YJuŖ=NN`̀7y11ѯ~ jBDơg@d977>)GE$WH2'짟`Nig'sžHl;HM\K#rhZucY0f-!3 2]_|M$t}O=XzK$IIvQvC9|Æ2_U|<(AWދ{]xgeMX[45r0kj=|/j0n:[|E)]r6Զ~0`T[ڊ%Ǐ/] RWz,n!0){ @9wQ#ӥW@*U ^,=fnIYiuefI+ !ڶM*YabP,W/C#2R.ʇ Q)oPkRƼ޽eOko\ƍ%;|v f@ 25r~ޝ͉xg@LLۻt1p{FuHo8xP?,vmo4vڜ<)Ud>\߆xx;|X'&xg;˞#&mS1ozaq#PJ8w$@ H$*`<ǃ.:eKs9#uK͕+zOy!E`N @ ΀K (HXݺ߼)'W_jb] [HTaaaIjo`MRO?տ^p~_^y VQʾe3HcRt:M_ hڴ)f͚njP)7lO-[~6,Lkdqy+jOa11R_TH?M_n׮}$)IƪIRp3KĒwnc߱0Xv=~-Ww(:\eqET7$Yj҅ _]/ n~ |r{TRy8@d'N^~Y:T&aaT8_vSQd etWNRI;8֭%qpȿJU&&PiDT6Yբ~+HIkp Z^yEDISSOI]RX[D}H2N!ALN@NbM\2n^I+M8DK##oEuvqUq*)%ˣx@#4xYk)^v ojdFs1CB5qq ߖ9Kj'K3bDCued>PtDRt/ιst$%ISHukym ?HںVE @ܑ@)@{bR#Gbƍ4ib {EJ#`kI "LMٔ)RI%/ HOw"ŋ)jܴIzaNէי3G.hg};0rLRtIqCl԰OHJ !AZ/_>X%$!9i{Τlp\:9J@qtKd9WڍmQ `=@V@GSoҦ>|[u6orr0m4VI J33 rrAbH)߷j,_ -!!ĨIQ\]e:O5}(~qih!uMQY6mv*22$`P/$~Z tϛ ,>Y%vf͒`"-MڮQ2!hoU5#01N6/;,ݬUv '2on1ۨFgHa99 y.4Dt#24;2e;np;>J6׭vdVпґhb"Cwf@v9pu Cʪg]E]\o('_ i/˗%y3 7u㲴DEf  jөpP(?^r\&ڱ[01)#Xv-Νɓ'&MRnN@wL_}UҴ"R -]*ϿqC.XCB6#C?R !<( @:uwlfH ? -]Rwf2g$ HJdhR%H*\0HM#UkCco㜮rgLk{hGG0 Mvj04cZ;eVSC$S5p.Z5({OpkkyUW^,ի}|OlxE]z5yV3*ǬB$<\88MVRUQm1!*_ @SOITIC$+ac#K^jԬ~Ü9@ɦϝ+sEnޔaPEF^&wÞ=҉s\(GGEir @z<7G"*8 ' TXA陊/aQ*L3Ұ&VfF*Lm ަZTϮ:UWU..Tgmѷ-HTAA6 ^}=ڣ{kVk0lbd\RSUfw/KeJ \Ceg~~2VWGY<4X@6޴I͛KӦj+ژ- ʰ7|O=%ʕrg򧭟^?Kz |R>_TDu!XF͆_~]ȅֽWFGn GwHvni ȓ%5LtߵK:ӥ5 @#^]xCl.ۨ~OxyݝOgb+7û35ll\q;AV+|8OӱD|~"FKė&NX"b%6'>)/HN/$ARdtKߝdh^O) t-r~BbLX?Xg+lmmoժ̙3 &VVN`;tNcQ鰚vi:XN@#| _P jimaWejjȴƱd+cFZ!5~n&Xi+hl_Vwklo S[+kV6x9oX{5Z& 8"в/P~xԩ  77y֭r9~\h=S5i"&FK#?"`>LAE&0V+,N_Ni0k_C7I @\\r.:,QySM(VkD"7{7!]y['CH] d=N&M3'G7.{(ڵ2vm}imF=""CYZ~U7ߔaC X!&&[ҁzmc#hdN{`T: 9~Hž-X( iqi%4+#;aohP- 7SP&]<mΝqs\ZcOƙ9,,j917F0 @27jV~s+ܾ^?>0Av gc&I[Æ2ggzM z%yO:r@3 }JDץ1W26kk@V_c`ZU%Qs ӯո c! Fۃn}3P]BҥsՍ:wFh2رC2"2Eʕ|=?{V^XIv$ ^$w }'ߏ)nޔdXҢE2wKFA}@DFJ"$ɓe\!hTnL`HТ(II@O,Ky3 ~u^y2 uʇg)z)`Ĉҽ 77*ש_LhֿmJyַuGJӨQ#|+-y6k&;:%alCj/{i@_r`V$[di)]j-mI_4L[{MkS~FK",UK}"~Xri)Wu $$HPeKѿkk7Yjt^X!C?],L_ƵpSG3`m3sdf"#%Gg L2$;6g"L} Mvbg%Y⛅#0s2Ӳp80 fȂb\ ƍ+ݺu+t… FQ.]Z豓'O*GǓʥK2ixz?P%Ko\׫xL*J?S2hT(}9Z&m@dg+JN!C1[[Eyy~ӦSc(C*ʌrRQnܐ5sB=[QufRÇXjҿ3r(w37Wo)(RkkE -<y7('O.x9"ߔXQ\\?))7qCQLLp2y9K^;5Νv۳g͛\^;y3 eͭaVQwg4i"ǿ}s7{`Ȑ!2d{xҋrtULeQ{{7[ g@$~wq)ܣ>g`4}>Az-jԐޡoy ]89"[%kooYM~}IcocIj{_\&j%㯋Ӓ;OÐ f@bg'+{a|M-8ܫfMlOڻtx]oP:jRکuY|ꔴ66&sY^AU`lZX>wNbp>/WOwuW{iԶU+4_P/d V3J;Weϐ!Q\~t$%~֬YݻlX` [  R*Iq$%%;~J1}ps S;v36oތ!C `W}*jE_cixBI5. :WahI.ZTx^U u:]VѤI5 5=ԉ^^rlH_RvT4^_I̙GYMWF_UTVG7dԩwmۖ662OQQd`q ߂S@::J\VUJMYQu[7+jEf2M @N{vDE%xxeP !ږ2L %$HW۶LQEei)m NS ȑanof/xH ;;K tXbڶm[mʼ^\{y|uvN9 G&i:#%F{&]8s#NyhTQ @4 :u*QJ M,ѽ2:NNf"Ip7O6С=OTj\IHl{%{v^>x{ӺKpTj皛; @n 2?cLJˊO*;2__*H 3fHFf\}Am]]e޽eivR>l_Ϟϝ;Ru-{{YH :Z$m=8nć~7o+WDhh(VXQs۶ sHIHݺEj|TPs+e@RˣF07W]2 +-eR-..R*{Խ67NN) "l&M F]*ͅvV0xzFSxs;UϞ-nhF22^r[$=<$`ٹSQխ+äN{2dITZY&??,1C&O /PW8+K=zݻ%Q;輼d33}P4n RUVO>x`֭Gt:RaƖ>Ѧ\藔ȫzu(/8CaKKp/ *΀4bin;{=kݺׇY."{ LJ_`O*ޕ J\|~89raXp}lXvٔ(O.{֭QJ(uݶM:-Gըcn.<_~ٰel!V _}}=O!NΕ~jd#G5QVMR-oiLSС2qyF9vLiTH>r ȣdf&\&KDDDTѩ @aX @- DDDDkBVlJkWp=̀={7Ny*3f@`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @Ȟ={0zhԯ_666khcȟ]GBBooo\v .֭[qDDDDD HY`_`ј={6n݊,\#š5k]zLFQ:ֱcG888ҥKF(Q~lPY#Cgb`b@HJJBDDDDd @ hĠA]"""""$RP:TZZZy0h <ӏtDDDDDRؿ?tRs/]:ַo_4m?=_ŋTNSNg 52^=<( Q)չ/"V{?,, :t>\QQQhٲ%"##DDDDT6q (2tm!!!=(K.|2݋͛HDDDDDFؼy3F]hy*UЧOȈu"44EuAppJEDDDDd\ @`! r@߇;Ѷm[޽ŢJf߾}011)+ ţ *%%ӧOG\s/^ݻJ*ptt+X*~FYd=רQ##*ǏFƍakkڵkcРAzjsY=nDX97nĤI+VgϞػw/:t`Q%3qDj*߱,MT[na̙]65k}A:/<<O=U/III;w.Ν;TZ˗/wŤJ`Μ9ѴiSDEEa…ѣGѸqcBFu1E(=xyy)۷7bɨٻwh7(Tt:%&&FQE9q™h+W:oܸq{l݊FQ.]jRUڈ#*UxT9rDwի2lذc`ن `ffcj3f aQe( eP%`aaggg(r?ƍѻwoxxxڵ+ׯu֕y9+gM}<''w1DѨi׮O|}}۷cѢE8{,SSSc*~ 5kkA:nii8ѣЮ];k.~޽1`4m~!onQecPӣK/~㏱a 4H%ҥKx뭷о}{1뵇!XFfeeNWxzzzDe}޽{9A:2I&{1vQF^PZ5lذ!w5k9JMH@FFGSQ(Z^QQQpttd/!)KKK888 ..E $11=z;wc>z01͛ʕ+HJJwرcqT悃aeeUh!GF^:?^豀sT撒ի(TAGPPn݊ {abd @vv6.]{LaŊh۶-jԨaQer֭BΞ=͛7g5BqҿlݺكWbF,U&:P̜9н{wC*l 4ǎѦM"c4 ~ݠA`ҤIʕ+q ٳ~~~.U]t5ڵkgggbҥjG ]D.\DFFbɒ%ׯ_n߄ PjUy氷ĉj9TJ^84oC> VIDATl߾=zmS;?_d 1l0`:| !>>>>>9s&yc*p8;;k׮>}:իgQVn]ܸqr'h*FԪU ɓ'СCjի͛a1Tja8z("## oooxw/JΝq"gh4νz0!""""""""""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD  """""2 DDDDDd0 @`0!"""""aBDDDDD ?ݬuRIENDB`lmfit-0.9.7/doc/_images/models_peak4.png0000644000076500000240000010035413066042256021007 0ustar Newvillestaff00000000000000PNG  IHDR XvpsBIT|d pHYsaa?i IDATxy|$3@r*W *ip[V[=Vwjvnwv*ڪ]D@ $ܠwp$czqd擙y=|S|o$F$I@$IRH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $ICqr嗓GFF?Ϗ{L4g?\s k׮p($I޽իW3zh"q9tr {3 ?~<{/SN [$I Cɨ;vPXXHEEƍ{c7o&Lxا?iȽٳ[$I SбcG Twu\8`ժU (I$S۱cH$IgIoD$Ii5 0{l~н{q$I$ȣ>׿unVnw}پ}{I$dQTT:FҲ$gnf*|w};v,۶mK`:I$b/^l 9E8{WЇ>o~CFƻ/پ};۶mWÆ K`Jӧ3cƌ1|)Q|)V\?qon9E8Zr%W^y%gy&O?4'aÆQ^^tJw=z}D&% )Oޜ.Oi&."]vuuu-O=q2d;^'D$IJeS~7Dx'~G$o-[D=D$Iir֯_immM@I$)yx!B)MM6-t kJkRrHiJkJkRrH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IH$IJ $IHR`)$I"IiAnOC'$ $!I$I"Ii&vk$%Dرu+6$)=X@$)UWᱯHOIJShtpth$%DԶmiW0l@$Ia4ulģ4gi(*;af8 %IrٱcTTT0nܸw|<Ç_~?K/gvm-IoSS'ƾ>XGK_ Ou:vHaa!h]psg&9%47ʕ꠵᪫G$. Hlݺݻw3vط7n8X[um_(,ê l R, q}vv_QQ{9ѱ$)f:\1;/Z?v3<0OBi)$Im5 qpav_NNΛq!۴ .CN\Wyn_Ii \tѻ?g`!/Q^{-aq%I)Sձm6|I6m]wEWc=ƅ^?y8wJKKԧ>24+y7>c2rrx;69gx&jy|:]FyץGs# /I핿>G@NOqÇgsIz=v븴)nGQ:u]|~~.пW>H灋], bZZbFзaeˠ 6L GE}tfeKsO6wq7s[;õBf΃Dxϱv^/%I)]$)żzv3l8cx xaƓ{. L~a%Ii"I)⡇֯mI~Ο}Ou{Ư;|?Z[($)]Y@$)D0}: y0O#x'o+(I:IJ{@}=̛u[/8 @}D^g̚u'IJ_IJ6nWʊ(n6) 16 JҖDRkiuÇ? 1rOϜ JҖDR -v{-](Vj ʖ ]$)Y@$)l Qnq8Z":S!&yhSs۾$)mX@$)l5skp q9OG߿ח$> $ b# ~Ǝ]ɿ⸜260GKRDR/+/% }I $TX@$)}pVX2n_A׺lY#IJ]IJrǶ-ԩq=߁)4dvg܎Wt, ~KeeP\ Z@$I"IInFj%gspq?ߘ1DTsq?$)X@$) -!g|q?ر S9g|b$W[ eΊ] }„o؟&{Yq?$)X@$) gǶH$6 Eq?$)X@$)@Ip ;رa*غ5a$%? $%~ѱ.$a3~WwaGA$I'"IIv6#vαc^lUJ3I҉HRkmq/c3_?vx"<6ф[, ng< _v~B^@^)$%/ $%БfZ&'u$ $% $%K/<:zJKDXE/1)bxT$X@$)Y55s^f ={ &yFbdUUE#N&33LHL$Ä$% $%yhaWѨ1.7u$Y@$)Y͟4FQqnKޟDTwH^ac+aBhl FY@$)m[jD F)*?:_%#Ij, .~}|p4 9v.UUaH7 $%Ċ}y¢EaH7 $%284k>Na3&lLf.F$kIJ"7Kj kY%OlHYL6Sqq2{a׼uaI5 $%ݻJ:Fɪ}wb!BNt2M($]Y@$) OCF'-C'[n0YšSI+ $%cq,^EvvD1_p5i<2], DjwG9/2ɓ"QdQ$IDH-E nm kI$IDHڣ+ƍ ݔɤϦH) $%[7/{߶7;x$g]DˁHށDȀ 6 =61- ٻ7tIR{dd2bj¸qd DY@$)YlH^Ӿ H ǓI+_ EY@$)I4̍-@o=&p?et"ȅ蒤:$4]A!CGyOXޱ+$$XbRP:{-[JޑDA4JT0^By;gO(v"I:X4# ](_Y6$ݱHR2X[:u ~HgŋsR\\L.]6lwMRY(L_ 0n+I:`IMM 'OӧǼy{}舒żslR8LK9o(v'ijj#Æ [o_۷)%%V`i8t3j0NC#I `I ;ާO233رcXѺup/YgsbHiy웥KÆ$+8[ݻ7Yt)7oG䮻zH:3;2$p4BtIq, qR\\+ªU(++cL6~IJ&K\ܟ<ME5xم蒤p HܹSCO?O޽;'44l#F@&N(㬅CG$#8غu+k֬뮻V0m4EPUƱwg:Љ˃EtchhБ$I$NΝKYYٛ㘫g,Y.;}tzqܱiӦ1mڴNwS93τЁNNָ22l7.tI:)3gd̙ &uX@⤹w<pȑw}3(//[6II*~b^褚~uLKJ8d& *hdJƌ(QjpzSYYڵk;>sL233)-- LRRYz`I:aBtIR$N/>+r } QR2":j4$HI ,(*$X@⤴_|2pw~zx~')Y,Y!e45%Xde~emSP%I5 q4~xy1$%a:fMv6$ҰȘr:nj+駒y~zl- DX@$93u:̩{q.ȲաH $WK6{$ސE~~0n8|V),e֬i$IY@$b)/t7QZ?C$, 55] )* e"y^:$)0 $G+Wijbqk)q٠_]n, -UMiJ0x0GrPRv:"Ii"IQu5Egrn1A%RͶmHBHR{T]MmQlRJ cT)Xj4g=KrrBib+پ1tIR@Ijov;YS2G,[:$) $7ձ+/eTj,@?K$d:wf3Sjy=7WN"I "IMu5}gFj`GQuDҙDڙ i8;H)X _ h(@, Ԟ47z?_ʾ}1GFWt77x5BIJWIjO֬c߮]$F@Ǝ%aIRHR;Ҹ(@{EFlǨTY>tU $+ $#,eg_ɀ0`@Dm_5̝$)]Y@$VWQ|#at:Qͅe# , Ԏ䬩Rz$>"ؐ[Jϝ1tIRIj/Ӟ,RP:L=#re(, ^g)Ѿ,u$# $4gfsI{nl>3vwIRڱHR{Q]#(!t*,噣4ebRVwL h4tIRY@$=hieX-0t*,ͥP[ ;w#IJ0 $AC J.Dw$ $7+JRIKNg $! $oxYE+` Q2bzX>, XURMEs)@ʏĮw# , Xe%,eUVzX ؽVБ$I dV.ǀFz| 0WwoX] MMfM8HR` pJya ( aIKpE]"I"I:7КفICGC'J޽ᅥylW[ڵI"I-] %T8'a aح{9O')Cܰ.6:L}r)if5H5 qrAg>Ì3hjj?!72dHn "Ѩ# 1 IDATϥx8$)N:0mڴ~ $&C{%ҏ*ׁHRr$NYb{Maa!oƻ>wcӦM{[\aB!4u\@$뻕cDRx3gd̙ &uX@dر̚5-[pYgy|۶m];c QRb͝ ]^f O{r!Ipee%cƌ (58+NnF~wG?YYY\pRI bqRWRz7n)$%/G@dr-'?ȑ#L2_|~'tDI ‹K9t=ԿZC˧#Ijc8z߿??Oy'8p 3f஻ MR+|>38pvsh"/V[@$)Y@Cs=s=H ln(]͑t|&'!òXp- Ej8rH;\YwIڒ?%)**,q$=}KF ^FԖ, 04HiI(I,+(ﱞi$Im"IqW1ޗ_CUU06e8[]P]  8[# b, gTڧCI0͛6t IR[HR͛֐1яRZJ]NÒb87FEѡ$R6WzaIR HR[h3:Nr)-%rIJ!I*(eiG@N0{5օ#Ij+Ia4Kvg:Nr:Ml:$X@$)6mss923CI>]9tIR[HRm UFپ=tIR[HRmĠ.@?Utܿ"; KRD(kJ͎ l8$MX@$)NQ(ܶ$_u$ڵ+ja8ٻ6-`Э[8)#ȑq',IJIMb[6 wi5 $ $MQFq2z4W{I$Im"Iqz yAIuZȌeI$Im"Iq-@(w䴔ɠxgh0e8v):A~$Ν9w(#Two0e8m [ FA$:Jk^FU.D`8X~ƗQJ5ַ"I:MI=pfkD\r/( l&tIiHRl)HYI$I"Iqpp %5屷:HRHRd,[ڬt1tQNCTkW$a8q [ ~Ֆ:OU؋HR2HR[;r3jp4e[XC'$ $kɉ6Xm*R^b$ $=| H׏Ý9cٰ}{@Sa6J3AcBGI-&  Ht*, ԆMl.(giRPYTU uuHNDweBV%?? m{eeiqD?%@^tnGqRSYl! $%) $7ހ2*cߔ[@⬳sgF4UY@$)IY@$B94㤦L5!\"II"ImdCM#2$%+ $=Qʩ$2vL(=iDt , FD{șH\MFkhm Ft, Fw89QɁHNDHEEXDDH͕D8D.@jHu2/B$( $c,d׀ͅ1E:$DY@'##Q$;!#t`]qt 99S\XX[Gt, extB$6R*عz~r1َ$% H}n#F#[<.qz+d/jBE"б#1 8"Iqi&Q$;!\_ϗ:Q:2f}K6"I:8ڳgss);a4Kh9BǑ:Qsh|iA$a}k}.tImlN"AӋu &sDARڵky衇1c[lyxCCMMMlܸݻӳgϷ=wcӦMcڴiq- Z@,Aß[@$3g2sJ:, quVZ[[뮻뮻vA>}:of̘Ayyy"bJ:E;wGa %u5'MAc#dg$)E3&P`x܍F|k_|{cJ:81t ϥÆ& BǑ$ Hs׾p5$:6k& "1Mt\"I휋,x!B) 6]Cqq(zncWCG$G@^ARo>ۆN"/tPX'0bBG$G@$$72y1 6O 6 $?I:ITE6MwG{QX~Կ*ʕCIޑDNƙ#>:*t5~sO6ؼ9p(I;HIjye>k%OV(:jXX:BK'ѩ `ӦЩ$I"I'1mvidX}, NY@$$,~b3m ۥɓ UX@$HIxy ]5 veRˮv"I'[|wLwa(z':ĉƍ$I, t28/t ɓ9c+:ʾ}H/ $}8a {F:>@Cu`Ӱ$H j= 4NkKC&3ׅY@$?;ӣQ^:w1Llv"I'(9a }EBG|`2S2"I'!^KO߾}MLߖԯ:$H҉?#TuB׮}۩,oA$IDNĜ9)PaD r$"Io%j $#0%DVIz (*s#S\DZϿabmH"Ia\ٰyx:NTk./ "I:DsU]_bF.58D2FCG$DóU^b۠ɴH̄{# ԞX@$]l k5pN\z\1={ˆSdxHHһx %No/8 "IDo%"ZX#GqޤS4K3ʉ>:Ij/, .YD.Gr4zYC4:$ $m{)V%S4hdW#I"I jIbC\&Ӛu NX@$] X;9gSԣtӕ١HHKC΢яd7t(,v <<9:$= 7s&}7St5$aǶ5[0tIJ{Iionhi^zYh!g]*С.m/I ")ngzYGA2  2943HRڳHJ{wn, --0k#ݾvTXv HҜDRګ`JغX+- )_?w,vO HҜDR۽n1C#, 8]"IY@$WÆ OSi%"ˁ/瞃Б$)mY@$c ߆{{j2J H0!cWT$Ii")+ zn_ɋٱps'BnaIR@IiX۾UO3[k0t(ß_\b, q# 5yf\ `Ԇ"X5 *xUع3t,IJKIimnʂ݁^ r0+]ʕ 99\r ,Y5' IҒDRZMD?$s0Z[~j.$v|u|߇ $Ii")}tG4 O? W]!j3a H8@=iXDRZ^X:r$MGCxuu?MMcIRZHJk0֭bkrr܂7@N`?BXV, V45v㱶qdd~YUjʂq'- aIRY@$}bq^[Zy>ـ7S+ߌru:$ }; c[V 7K3w;v/%Ii")mm[ZtK/ G ҥ ԩ43g%Ii")mmv\qulչʅBVVæcow?Qlm$)~, V㒕f)>tԵ+L ?mo>k׆N&I")mKe+ EL ?^X®‘|.6 "IeZ[)[+^sdgN@#v9Q> rfMT, qh">2bvʀ馛XkRx/DAfF:%~N|דI3 H}['K/??k̙Cyy9˗/OJosdb$ ,KzL GfZ@$):ʾ/2n8:t_M7DII //ˀrPn>8KͥvwSnW4'W> YjUTRY`~{"OPT4ړ|22x/FR$(;w t)mZMMPUu/~A}yL 7z1I H=l۶n)t)ml]g6][|^\.ڟ;nc+HRʲ$ЪU;4iW:6vݮ\ GDsrUk/d}ƙ?P(, cJz?N$W)Q^~#?cottL$3gYKcǪq$)% V۷S~^~e󞏟>}:=z8شiӘ6mZ`QKK 7t*={IcLKſ.n||67-!j!F4ZG_yꩧꫩWqLJP[ {Zy󷗅Nva`\_o@IRҥKD"џNM,]ڟС$)5yN ?---Iia$PoK_7 'tϳφ#I")m— W\_}c0w:F׮Dn[ËO8#Gbkgr^z)u-Cx}%l(%~z/ bIR2HJ)(|;p}o?-d]L cCGS2׏Wc :꫱ \67&II")BC<<>:\Ym:~;|"I"wqQ_ǔ!37m3GikhYfZ9*մ̆Y9JrBsP)2?~9|pJXJ]:z5ka$;sg߶jJ# DT*NYM@ T'ؽڥ!"*UQ Ԫ7"}zut8;[t(Ym]R]"RJ@pabk^6+WqLXDDD"*uRS55 Y#GAӹEOOayx kT`BDYhh<<`.=<=v8&xykhRS`8Yիvna.uqCn  >&" DTlEzujwakeH^^ٜtNGzo- 3 oc.TbY/= > 7YFT)-[\X" uUf H},2>)mGhR[=* =J4~}ycTUeL 9{yn5H%WV|=*Q8v QCb@S_HJ}!lyO; 7vi#;vzwaC-~H5dfs]!9\ APv0bMGGXq춼e м9%c;~<@X!xy~ />(S__,YHho'N~sh|`}ؽ[VQ={2ݻg(aBTJʞII}/FiO?RCp@LVY41|=>[扥K Je`(_uB,.GZؼEkפu4`jͻ/cl, {ß֠$F chS'p+z[z{>>@zYnttp6mq93 "C 3?0sϵ7e \z% @JE=4gaay:<8כWܷx,0Zxi^А zo52[6zIfU> 4ȨbEwY @VgM;SR` ?D$*K6&YQ3~ǥs^JǹУQ)p,e C8r?s'p=p81Tijr2t9#11oP?|CAaw PE LHgƃȔFqdв%0p ?@po#h:o8fUBfGWFsE+ˌ#ݮv䞯cB" Dƍ| @%@ʻa3`z\ @n.^uj0}_~ƎN,BC;S-#f>y hj*Ujּ'$:矲篿1@2 B5Rqto?"(ժ!\?OAi2pVo{͟* 11RWi @ $.F!XhaBT ltT`"x, qqoϹ uK'662 K ͚$؜ms:a74oB  ڀ_L[ 11SO-s=aTd,rf 4֕aZ'k+poS|"phF8 [<ƌnH'Fb9}ƙ?Wv>)<\6Yl x\̀0X^}ɽ~]~ G NQdG6@QdȆz6'…TD`3wwoި :{V.j lތ̱/؍.x/`H)бc^w<~ &H#!V&"{Y{9,L2 2r|^SC6+ w~}VW̾͛@J3fHs  CפP렻ɀܺxzђ%[O4\:U+f@~'不s&:Zޭ]<(ᨫ@ YX6m+#e>իrws!W749fb'x{=^Q1@FXO23bRq 0 ʕO>˲5a;=yDm9p?$Cz2!3ҙ0a.-˵k20? K]|DU編7.[HtlP融#D-{~|x㍻+W$ ݼ/2Jdy))ơT</KrVx?5 /9uRiPjHh߭%C;eqLq _*TcΘ{c菟aAgzq'? z֭1DT|*U2ު//9+?:%H6{6Y= /uQvm鮞_G3ÈafΔ0OPh(к* nn^v[ @_ P0,5Q'.N;w: `rEةԡu)*JL;'uP>l~+ OwUj4\KJJbb x[Hq>EQ,Z$Cr[.$&vrV.Hdi࡞Ӵ,y1rE~( ݌1M7+=ө7 ss6 >go瘈(ؾC=$zXtDůzux n ^ëi%\ ^XXzekgmW^ vMU:2U Ώ;0  GHotzw.^94U.Ux%qܧ^4%C fAvOoɴ>//cf}[]S t}(_~=++8;:HB.eUJ=*42ɀ1xb߭TtW0^h>@"U͍x'XE Y3 HUع~]:;,XV?<\6$ZqK}cCrFGȐo_ rg: c\@۵kƎ)5Q~9]|; oܐm~5Uت^QQaC-I]%8V>#P{V/>ר(`J;.hoyo/Tș2DL^ؾݘ jՒ 0Eg.!0"c<{vjw>r7€O*$o'72SpV;O<̙<'Wu?v?D`-+#+Jܹ  2{tsJck^{ܬ^*իP̟e2y~>[\9/nE!,t$իnH2 !!i:^||rK#xio.ir܂~M=<(UH%륞W>(HZl"wGL_FX ggPdmRIIEw/=jj0HP-+ モ=#ʔ) `|Yeb .r/̺ur{l^#(@%àT2bV%&Qh2Gǁob C!hq?lF'*ϧCp6>ܚH<]4 T@46 SEwc 5qw/BDC+òxyI#l9__>Y4ٳ̩F{_I{~-$x Njmbgr <@d*$&b W6Q xjja˼pAT ??kz=}W.k URWR$+R5ib|ȑRQ3(Hr]hۮiYfΚ%uez Fja y{ܸ!''V̀$&4XF fMg'Q .~Z?b0}|_\+~I.ܹ+=7? %;S"ii2_rputABB(&Fzϊ_/?{3y+t!ڼY*Yd~)#K7ޯH=Gr=cݻ'*0 l'OʐN[ Խ74r t8u*_րc#:+_ CSa(bQP! *5GulBT\X xQIA̹h%Ls1-XR?RSޝmqJUFUhqevm+Jt,ה6mLWw%"BvۺEE /_Jt\ȃ%(l&:ۻ HXd ._6PDQ$$q9;4l(֪HLL_7m*q)wK9rw k  {,]*f͊g(0!XHcʔ)󃓓Znw5uWA9}7y*e]< @*P{fΔo{iTTw#0PnJJ2V))2nV ޽%AAn6Iĉct- \29t@YE%#= A?x*L 㦡;/b?^|aöKU+2-Q7^.~pCQМ>A&q؅nX/:uV+-txrruF˥f?ʖ5~svD5otxoϩUREɵok+@tu:GfێX<(ܬҊ}iy?az ]w*<ϴ5n?I[{ӏSdϪU=І\ĸg׬I5 fMPڿ_ƩS焅IF#mFjvR:5E @||>nd\F+, Υ{π){Ys繺Jc19+Y޽Y] <ǷlYjh~^~Y wHc=k׮ĉQV-,]{F@@y{?dϱc봭"{M|._J0>^t@={ʇ:g )OħO7|4h͍ݲ=Zza||I~JN`,%Xcy퓊SzǮ_lK/[%m+=ZSNG<"ǡSԏ75.G?nb bPhI[ + Lndu/&.UD+ⵏ+t\E4 ՗8JKfQW 0nݒն@+?h:AF˕+˦2|yhZ h\_~@%=]i=t,4 dϮmlP"=[׷v:%VVaC=\eE3GK4SS[dz~^h^K+ ^8e//  {J!ܲ#,t-uH-_L"mg5GٳGF%PəY^%GH60YCcө\ re~*9bMrS΢0)~ @Çc4i`ȑhذ!~m/t@zGER|I*WJ%d<5h\mzql^ &ٕ( hr jUyhR֤IrAzu9_}%8sREo%G 0%?xP. =z<3}uM% $JD$dWKDI8)uJmr%bx4>HF<:.f[gg'nz@[bh=Fq7C| {q寿@F ='SLӞ嘓4DŒ{5 rׂ2 - D%~t(mpլ) qgg_rR&Mܹ;>xU^mp֨7Ecܸ!׋4颢H(7b0śX,57Ѫf,?7Iwvn )ܑl][4;AeP ws\7::Cbv)ʵ?%PٴI]" IP|u58Vgz'.ݳ4d1cҨ1 !o He"yZ|xիHZ^5#c YYyrU"_7ѡII2a }[6}Mw劜?Ǝ; /c*s7HɿTt @ɚ5k`gg^z)N?w}PnBOJSH(v54ɓ;.FTR}|'O $"B*c2o!AAz:5jGZIETJ0yTB-[B"T)|#+\ZLIF)X( SX %7ϥ@ MFd%%c$&A GrW\P\SA]\O6<<OTmW=a[6;{ =~Y.,Nz/3]z\ =))ip0cW;2^&~C/j֔g52e@T 4j6\.&Ipp萼dy˗9uFǎZ<׾}3HbJj:},t(v:PԩcEEIВ\% b ]@}1lR h8Xf rрÀ0:PQo@ <ԀdKcM8<ԀA@5H5`4; :d9kN6^!:d:euظc{salht3<+:aK',\섀CNذIZNNX>fi0u\$W f7uk 8};vzJM9Eay{nպs+ܾJ?6ٳ)8XR٪%S ۲Mr{ӟ%Λg$P 2DAуѵ1W6''@x @ʔNQ~ݸRcFڮ,{q@ 1jV=z5Xq @Tp^<1hq羗jK0O(KXi8w4v7STQLMMj*-K>!#H=6zD]ӣG"lBpWQnoA-=S= Rq+[';_Y5ȴ.ZIk*0ky@Т3ZdEKZ2ha"F*oi_屹>jo?;teEv@K[yMU7^1s08Oۡ>[iaG0-Y_ ʩ{-퐚nOGb?v8s޾n _ءUU[;m̛vH3dآOw7|1)&\z 1Q8()Z9mL- Uhh.ZDi1vNV;-4:{4l{P3@Aqe}V*Z\ԡȱvXK4F7޷;_;.1@03Cz? m+JI@Ӯr?n H&;k'YQ?8Xz?줧cI; >y=Bp%EݾIwU3o2wHТ(IIUQծmYrf@re@V5J/%^Up0={JQH|}%\qh:oP[o @:] >9'gQz2, @:bZ@RRumD骿jP#n8"b&{:y֧]nj>+ 8GzݮGjPFQ3AF, &_ d~- ـCQ΀[0 v7 +݀)@t73 36 (薘 `R&snd;=|@b|X(;Y"/`1x[m}"ULQX4h@y?wh%Kرc lcJPL(5j嗊(ŦǛ6իV[[EiNQn6QQUreLǤsM(+Jfde6LsqQ~?4}ڵWPOOE>\Qf͒cr|믦MMU{{e~y?T嘇,+Ky%447|傟\*?iR9S"`E3h5K(:[ CT 6 Æ ңSVM&^[ծmӠݐQR&{>>y{< Gc:\ծlT}kpp7gt$wL&,U;V`|MRF!2!\9Yaük@*e%ŮNTYS-?ϝs +xyx{S#?K巺GqsqM]F.N ""*r -K˫Z4 T" =?O<1;dHlٲ)o\%Z gϏ?.נ4il$Cq7Z5:kc#m4  0=O-<2Ip(!AZ`̵AUm,?'$uRmOի7 GV{z}~/H#33Kr Xt)Zn] X[˚U 6k,F9?d9ɇM>/ THqxlذ|33fNT+cuՉ͚@QeaRt:Νs4tLy_5F 517AkQժ%oQ<9uzyclURJV& hĪ7,jU&Qe>}dx#^]nYC^Y٩qZ2/%+4ӕ_-瀔P Y݃2I5Ad@4X]"""SÈ@:{6e9|L\eqCFtν %_%1d5}%""z+8̭^qYh۷,cG^  `Y%5!""zTo/'4X g1*Wm@28PztzV+CKҊݻme7[f@, ds]4/Qin 3Qa1y#ysY5x[7p=쀝;MuY<3f@b0!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @Ν;1vXԮ]ΨQ^|EDEEYhDDDDDVcg&22( ___H1INNF׮]qEiӦ.1)& 1v<]]]ѿȊjժ!44ުU"$$ """"". DDDDDd1܈,H 1e [Ǝ;],z޽666f>lQ)>={'llll2^p={+ʖ-{.1VE_=zz^zV(5FGqРAJ*:t(zp#`Xv-&NZjaҥݻ7Ю];k2oMeh"sbbb0{lTRM4ݻh;sARRϟ3gjV(=&E_N䘛%IO?2d5jH|h֬< `v_C)FY`A4f͚J۶mX2z(FYvB^DGG+(GU4lٲ<+rc;vP4dJ5Jquut!r`0 V#Fdcv8֬Y;;;Kt:y"<<܊(HJJBFFB{{{x{{UTk׮E߾}QbcݺuCڵ{9+zVV-Q4zȴivvj֬#((({N8ڵk:Dɓ(=ƌ7778::k׮8v옵DpĠEylj'P*zL2pwwGٲe1n8$''[XT)hxyy`v8"##z,""ENѻwoxyyܹs?>:tI&."="## ߺ...Ô)SЬY3deea˖-op)޽."B˗/GDD>C+KMMNs!~M6hӦM}ѨQ#L:[lbacuPӃOvژ6m֬YCZdTZ^C۶m1j(`Y#z}iii5j(tL5ѽR1ud-'N viP)>}k֬^yabefY=???K1+VDzz:GSQ(ZN([,{ X988qqq. "nB^[|^? @iӦtL:t8.]HH,@TPʕÑ#GwasT쒒rY(TJ_~|26n܈uz0#33K,>tRn*TbaةS~z %GSO=7",,,Ν;!CXd0y:`={ZHT effbС8tV^VZ=ڽ(muCźu0qDԨQ˖-ѣGsNoţD׮]6mϟǒ%K:uXTJ}HHH@DD/^Ae(S дiS7@RR͛ʕ+ȑ#@ERZ\\6mÇgilق^zaӦM,>&L_~~ $F@ox4ngFݭ]4z|WX|9._Dx{{[nPzukJjժڵk=ASQh4\r+W?&M¾}ЧO,Xb _sssqADDD 33j³>ɓ's ^*.]58FAfffϬ """""!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @b0!"""""aBDDDDD,Y """"" D V$^IDATDDDDd1 @b0!"""""aBDDDDD,Y """"" DDDDDd1 @bc1wIENDB`lmfit-0.9.7/doc/_images/models_stepfit.png0000644000076500000240000010215213066042256021457 0ustar Newvillestaff00000000000000PNG  IHDR,d(sBIT|d pHYsaa?i IDATxyeי3a8:ek""{ *D?E)DݖP ݷ(ؒNeIeb0aիbڧ~^xƍ3ez-*VӧS]7}t @ڵ2e M6eС;6ןGDDDDVgq:'22@mFƍ9s&}Muݼy޽; .䡇ʴʗ/Of M>ާO~=JbryDDDDDnuaIˋ@q~!M4ᡇ")) [j 4(͒%Kr"""""!l:<[lQF-Z???Tw};vШQT4h;w̳~܊<t:od3ydw?ڵpNɒ%SE@@v=?ADDDD䖡MQQQDDDoѸqc:wLPP^r`+vɛNܢXKN={6IIIC|||&Vxx8˗/RJ^#""""-&&CѮ]t3n)dftr%jHxxxVZ˗/w޹""""kzݸe)dfL2?~<9ݎ~~~ԯ_-[СCnJRRR^/iUT 0'W6l0&NݐիW^9/fzw4oG>}hѢEÇ~=Fn?ŋ0of8*TƟ ϲr}XDD䖐ٳg t<'O$&&tɓ'ӿL߿yfڶm="""(^x-ZĬYX,bмyk~t"lذ!k<A6oޜX>:3;QQQѡC,ͮ]&111Ǐϲ ,w^.\gf(=eЦ l>yBDfN 4i#!ΜSk>\řѯZ$_m߾ m64hsfb9spÉH{,@~HHHp*T(CBhٲ%jQQQ9rL_~~~a]Dr_BxdۡJ(ZI!441缼Vm= p]saVp$ѳt7I#,""kN'gΜa߿~ƎKR2}_tt4 TR&MPdW@@61cMH"ԨQW3II0jԬi„oCN`|Db"fH'wys$h~w{ށeYۗXDD$Gok.vř3gϕ,Y*Up,8p`^tWDnq?O? o/'d | s ->kz8yvp8(pNىvNQ*1g e2V,Z`k Vy?O>ߓۍ(VZEZhժTRʕ+S4 q)IIpBSb mʕ#p}fףBfD_W/]<DzhWw;RjH7O+h^ ݭmL*ډVmTj'N ݾ=C\SDDVbʕA9{<읈74S7nL((]:u` oFb",]j zI83u$WO=eٿCR:xQx^UD)!3k>.Y<*Rg/4mzu4fuRWз/Բ4lA7= ,""N\\7ndŊ/lݺɿ/to ޭ)x%Sަ/=ZٳÌ~?˖Y.(F?abafFBNlFˍ]Fz' O0xP6lȴi޽;~~~=p! qqCrf#ʕ~ ~hZ9U̒J>.Όv8RJ3踃Q텫hMrsǙTi-Q+fYJà gP!x9!#|{FGR(ɐ!C޽;M4СC^p8pwwdɒ{yynσފHAGpp0K.|4m4%LqzZb1!͎}pfWuԌl 3fo7Ā~b8頊;qR2ej86B7RS+ퟲ2wfYfe_x9w&Mo\Ve(Xn̙3ٵk ,򺘘2B&&&&s""7ۛ{FqwwwDn}f]W7ǂL cOx8l ،~tpoW8x##DFP+ӛVr8WlC+Gd::nn_[=ٯKG>i En ,tyF+BٲeLJ s1aÆQ4r=zG봈8n*IR 5kx{f+aNz>l)ĉiРA=`Hؿߌ\ΞM Y~^R׌|seFD#?NZ9gEφ׵qÖdat1σJ`fu >Y,f;4ƍb޽M׿2!$_*o߾ Sn ,tQΞ=K ~3fƌΝ;S`˖-t![|^D$;+W(pq:ab2!ݎ`gWG'LeQxQ4kB段2SE[(KD6BFάl5hYw65;BVf?5k , V0,"K6 :]:vI}Yz)z!*U@V(QSNMXN/;vˮ-.11O>#GC=D"E[R9tf/7ZG;ձp:_?:/Cxlt"?~Q:s`qя3,p:PN=D,AӔ`+X)ry!ʤo˰3 <'yCQa%%5ƌשxq}׮o1n*{XҘ2e +xrS~T25f͚t9xB at֍m۲n:fϞ͘1ci\{ү_?~W{9F"ynOSAFfyÇ~-Z?|K{wظ|<.ȓɣ٩6S"Q _8$%X/HVJ׵r֧܎Y)dӭ| >WoWW?F̈́0ϑ׊1+F>74&LÇX,,\ `X۷/joxzz2aBCCP&Mbh~'"DƍǨQX"k׮{n-") 3SΞ53MxHY}=6mo1"}d9f~?dqD9Y~ĎOG:pp`O:Tȁ0"uqwiﰲ%qbrs+-zuʠ+Ks:j7@pHHiKN?lF7{|?w쓲o ^x!ṤP!=;{!,]ԕm۶^;|0{fÆ ˼\]PrΡCBHȭDt4cΟ7Ǽ+.414/¶1l}A& E;#R'Eʀl5RSW+_de;kPTնm3K ;fJYi͚f3fmͦ`>2g`zl6Sܠt9C#,"".ܹs>}5khT%|&Գ'Ԩ߽ɞ +$ԍ7lWV3o}_N_v X $}L4bCW͚1a&֪jFk &A'H+i^aIRӱ#̚eFVM_c2tfտqW""ԩݻqO;Fr]R̛g^ ,so8L|\zURԍ. V+JrJRPmjq׌xz鄈#!)FC;xmZ%0)ƎcV׵`C&xc+'ݬ8,6zl?|bO,ڎ'b3Jӱ#MA~fϟƆnn&dm Ç q5b(~%3[}D$o)1oYO3"tf^r,Yb>/[f]^N3MkHػ'J.頲s\s#<c9H /ťnxqZ wZ9 nj ZחB3GBP o^mJ  Æ^zR̳7mji> =5ZULQС̙kDv"""+sy\}gmҬwo’̇Ma!0yY)+[SՈ\`kVy;(~sQ%9XSs,JVvDʔ1󛀧BB=%g,TLz-8pjرfdxѫdzuS/Ӷ$8թwߍ/NL`3g""O2dI&v႙{ܲn#:.qrILpмY^E=$5svt'Mbh+TPҏ)CQ//.1'E3eS'h3v ʕ+[o3q3g[5uc1uv씈Sh;> wU,DN|e+TQzu, CpzۡcGu|X1XRyMh8V0W?}B+̙cV,K bJ&4jd12_}"" ,""y͍^z)qs0ruc\s@pTYyKa<c〻^ .i%VG~<+dҪXFߵr&DԪenٳf_À[-ZkۄMh2_˖fzWФ٣SkQR$,X` /""rXDD\\VN2; }\9~V.OeF |w7uQѣᥗ.{E^p# ={liju(|A.4#:""=aqA("WřS`ݧO&$PnsPhII}nص{7 dI\8U2=2,^}Y xBCWZ5diF"|}͇vbn&VH3] 1EÈfR_&0|9<]p:ѿ̣jUR%9pf 32Q {͌0*4onGOßݷl%KaVDDH:}4%=ی:|Eƣ#پl8j3ipǕN1Ì $(/ 6Pwǃޭ)U{O4Al,?}9<,icj=yS~ SfF4 |71ܮ}\'OҬY3Ff0^xnkX 0~io^q]"ֿV}C8V*=Ws`Q6WƥoNXs6,|mڛuv3 +N IWhh ՗.5MgVZ+DHCDEEѿ'NQC;u2Ӥ|}nohW֭+VaTp|9e5;*ػ>O{ OyyT fi?4Ac۶ԫ\… fe(32  j^={>{&oH: ,""7)11ݻ~z*W|npsނF=?lts}~;"8BOԢOHR2|s^z?MXx=J~6e5h`sՌgO좞3?| d^^ɒM6l?/nx14mJвd <`vbbL;)YbcMx}?V|t|~ \)Q4TdBJǎf/Fɫ:??ZLA]DDD2""r&O̴ih߾}sf%-m½)_:]jeصˌ$ongp9X&8oWRfH8Xɒ7-U*A˗/_d<ί^ &f~}of_}KؑzxIS$"""LEDOdx~b3Qfڙ1c/] }fRiS3f.jpqGr%KBnfsDDD\ܠf͚ѬY 9&<`,3&g+0,XfyO>1ngxIW~D\{7>~:]BfŰx_' ͨJbfנA0jt¼yfi773ʒ?j_ɋ/† f.є0_fcx Ifz{kFPiXWS'"""H,ܵ+|Yn8+cGԳ CX}wtTDD""r ŋgzΝfy,aphΝ3a%((g;,""rє0LDDDлwo7oΈ#vNS'U͈k5"""rXDD2t:0`|WgDL`,7*VMXDDD4%LD$3f`̘1gyml,{O>Mj`"""٠""6lk׮׼~.WeJ3ΊXDDXt)|uΝfڵ38z-Ǎ~ ,""i <;ww] waV Kg5fEDDKzdz t3a?l뛈HA_e~:z,e,"""7DED&QQiiKɓo"""M  ;w?S6CX٘Z&"""iED&iS/á[7h:_&""r;P`mٲe:tߟ7E%EDD$k ,"R`8q=zp;v,;voCٲ9GNED ^z OOOF}C?qˁ矇`:݋Hb fΜI@@ caC`"ظ~<=s"""FXRfԨQoߞ%JƗ_~̙3ܹ3*TH"Ԯ]ѣGa3f 88UƔ)SqD$ 4-Zзongv(Z*$o^DD$)piBBBطo.OJX,駟̙3 8ɓ'sw2j(:t萮ӧ3`j׮͔)Shڴ)CeرyL"|Ç6mZgРX~ v1p퉈Hzfĉm67nooo6n]wݕ|_~TTQFFV7ޠSN̛7/ڤ$BBBxg(VX<~}^yW~Smmݺ[oAΐaIˋ˛)8 LVҥ gUVAR];x`YdINu]DҥK)S M#>r"""K9q%KL>rEnFR]۠Ayel3C ?p7ΎM,@ϞPvPDDDRR`!cǎhѢXB v{^wSDncv5fHacƌ!,,S W&&&&("9lǶ$>pKmK&͝;7|Ϧ:C|||'˶ FѢESѣ=zNM+. +_^b͙39s:vܹ|E&X}ҩS'Mj%11T㉈feĉiРA[DnsN͉jRF+Ry4l0ztP ڴi]v;d޼yV֯_-[:uVz[7Д߈ymOݻ;Rre/^w׵lْ%J0uTǧN/;v̋XNӧOx~SDzR>mHjƔ)SL^+44#G0tP, ڵ#22W^yEzժUi)T!!! """M% &pa, .dX,KRRǎbk{O>jcɁɄ  B L4C3Ds=9VO'½$Z̹6EDD$S ,ipœk4&3l"? #͊uP`|dĈ9u0c@wʱvEDDXDҾ}{j֬IRrͿgbl,KWDn+[6oK!g h?ʪU[DDD)\1>TCHHZLDDD@R,Y=?ZhʗNpd2Mq ,"v;˗/t-%XӔ(W"".m„ tޝܽѢE,\AժPFNDDDgg1x`){7:tNG3bDDD)˚:u*.]bȐ!{Eӓ8yRDDD\&OSO=EҥsfA,şR஻rv"""rXD%͚5p^zܽz5< +WB6"".'11#Pjܽ?åKD ۷C{;HZ ,aΜ9EfM"1QEDDhED\NhԨQ() ~ :vd(]U[H()]4 pkǚ5ftE)/…w7[h:+R`krhْ_{"""XD` , 5jwDDD$-)VK];֮U"""XD`Z-WM4LDDU)Hc߾}y{ˡ];6m"""XD$͝;5jpر?+ŋCyskWN'Ү];ʕ+77]<}:ZSxVpZ&,VdFXRfԨQoߞ%JƗ_~{}@߾} 3fժUcʔ)">%Jлw[iXAFA˖EDDĕ)piBBBطoǎy8pÇdڴiåKR];}t @ڵ2e M6eС;6OIU;w?{ʕТQlݪ`"""NSRl8q@mFƍ3n̘1İcǎUNڴi̙30`111tԉyЯ_? gXbyp".&::]2hРil,lϚ5"""4’Yj53ϧSN`mժժUK&V""""͒%Kr Dn6Yfa\eAA%"""K%?ӧiԨQs7fǎ}6h777vܙ dIU0 Xp`ZӝZDDD$ױ8)Yd뼼n~E䪕+eK'سGEDDVM111x{{;WPTa;׉Hp6o-Yj2$"""צMWV3Kw.6665>>>gNlllޮ$RЭ[в%aaPكEDDD\V ˦+SL Kpg򵉉ODD5 FѢESѣ=z)x |yU?ɜ9s3gNcΝ˧^Xlٲ*U-[;y[ׯ-[СC[ڌL8 PE̻Ӻ\#GT"""9+_*o߾ Snvy/^̱cǒc%kٲ%%J`ԩ?uT|}}رcY$9N4iŒ3gΝp;4oKSL!222yP9СC_^… 7:uSO%UP!BBB^;dK&LX,.\Ȃ X,ʕ+ǚ5kxySNL0!~劁Ʉ  B L4CO>Zj"Eлw_schAX]w}7DDD(H>'H"y߁  ) 7', 2UDDD\p ?XV+TeZ-g,""rQ`\aڴiwܑ?XZ` ,"""݋H6mshغ%, k*""".F#,"|}}ƿ o6[ܾ֮%X1c IDAT~-C"""] ,"rZKidܞbca&hޜmjNHv)iK,kW~wJDDDKEDnO׃ԩömаa~wHDDDnSN1aΟ?ٰ6%&ޝݻXDDDnU ," x II&s ,"""*1IIIL>}UY7 spi92Ӻeܙ#+GҬ3~4ѐJL-sO T$0uu瑝7UyA.^:v^p߬yq@QX?on;"۵Ӟ=`nnFCaPh͛'o ;vH-[JʱGaP(bcc?矗b17+))b=P|rwwדO>in8ߥ{RFGFaP`?|I/_0;w.wqa=J3gI&f0֯ԫ'UP (, E?1 ;wJ;JZ29((9H{*8@frھ]JO  5s 5,J}{rI?(}d0`aP2deIR1CCȗeffOK/\{K/Ieʘ @|ᇺavCHrs{@0PX6ͦ ( @..v.8XM郅^6LP@0PXܶ۷ѣ:tQߪޣ ѣ m[`ׯ.]ptœ;讻Z mx-[!Cb/{IVߣ6mL mYtOOUUQX(a(,n˂ ԫW/O!!JlA) % -;{.\`_330GԲف@aH8*U_5;FNHIIڞq5 mqrِYŴe:%, _@ DaBCu^;@ Da.\vrv77;(lk.IԴTy@p\aaRŊZ݀`Pk۶mZtl6Qr Sf;Da['OٳeX̎&Z22Xp@IEapC'Nкudk~]Wk;J͚ Zhʕ+'x(J P۶y@Sff.\@yzz'0;[7Baɧh 0@wyʕ+FiĉJNNqߡCԳgOyyyG R||I[n::u>IRX.4h0; (*.fpDNR@@5j(UTI={ᅲ$ĨSN{ァDM6MWxx\]]MN[`5kmۚ%T)2R=e %>s%$$(88X5$ :TYYYϔ *hJNNVddjԨ!I Pݵxb 6oӧO~Ќ3ow0Iv>L”|t$jժ9W^]*sӊ+ԫW"IݺuS 7_`6-[V3fГO>ivVD`:%%v*I2dt)}ך;wF-ٳjm۶UdddqnWtGz-Ƃ{J8 K>C'NղeKժUK=zO.IZ$__\畞^#,LxԼa@Qb K>ժUK;wV߾}իWkҤIVF[[CKYxܮx_^/9cJ4 K>|W>|'Iӧ4vXC)))}.I ^},QXaΜ9jժUvYwZxݫ JsjV|||n:2fUP!ǵ@;XXRWV,؍ 帖`R’OO֤ddd;P*Uk׮\E7:3gTV (It;@-[0rDDZnmRаaCEDD(::: 9;;_Էo_^Z111lܸQׯ_fn&v'+K0>N=&1p1’~'w}9r*UիWkڵ6lW.I?~-[]꥗^RbbN*=&@N/bcc?ƢexQN8wR|֭[kΜ93f~wM(lzW4o<ܺ0unu˛";vѣG5tPܲBu((,@)`իWO;w6;ʭIJRKؘ@iEaJ/jٲe2d?+;YY*Ӊ(] [t3Ϙ喝]$ӝ=6MW޽kv[jFM͎LBaJ={h޽6lQnKţa:V<|X[lQƍ͎r~ziٍ+H ,}Qܶ_lk PX'55UK,ѠAfvۖ.LIn;@aJ+W*>>^Æ 3;mȐ* Zm%'yę?:vF֦6t0`%o 68$sBtF(A(9)q]li 8pN ppׯjv|z4:)JaPXvq >\[n5;JEDH*a= ϟ˫fGɗ˗Ç#U.F\(,JKKӧ~A9%lR?XFa)=#QrԬY3}99tz)///hРA7)1J+W>|Q-2RtIQ٣ n:[[ք cǎ)666uIziӦi ܹsuI&fGɷoYYDaɇK.iРAݻ/_~&OdEFFFu]/ְaÊ+2J#GhӦM/̎R Ҹ!F<1%,.]3ghҤI˗/++++}+VP^ˊ$uM 47|SlyQ̛7O>>>۷Q-5U:p@jbɈ#%6lؠԩSjذTBJMM$ٳjӦMmV%ȀG(/RFM5cXpn’P>}Co5w\=쳒$*I|___?^Ś%G@@ne|MDT2qpCaɇ$]rE/f͚%Iӧ4o<;JNN$z'''VD/D  1’ׯ>444kSĮJWTTqb%tAU˛WOp$95zVU>>>7]3f*TZ```8 i>yP#/((HAAA9%$$dC6ma讻ʾ'IRTJڵ+բE~3gUVGHɩ!q(~֭[`JX><O?4 U]t$WWVLLL=7nTttWly{"RX#,ТE 3K.fG)4kH}&-\(qXlb1;JxQz9gOg$=+<(ov4Uu1;F;VJJ>DXdlg, @ʒXrW/n*թs[GaPh4̱+(, Mp,m{… Ҿ}o&8XjB*W;$)up݅[+k 88 P̶nݪ+WfP9#;²y1RBlŏ#ͦ7xCf*1\b|.,KRne#bm64;J jԐjּzafc 86FXb_={4;J tMk0}駟~oQ⦃Ivlt0P`L:U5kOdɱfc (4TTI;w6;FZ8cE-İ1(a|nꅍ%ggS'2@"#%ooV6m$//Ss@"#,I yt] =LJ |pAwe˫~YPAj\䠰E`Պ2;Fۻ]X֮5p&-(]rECՇ~hv"ip߰pgOcO>D?~Q\dq ,֯BEa Qrr}=S[q\d_֯4n,y@Ba ѧ~3g護2;JrE:tjaٌ+LRH&M$'''5k,cRϞ=% 4H&DQJMMՔ)SO~f)r3Z/R\@c+Bɓ'\rX,ԩ{)11QӦM.WWWR-\PVTHt0iSI;u2;(a(,^SkdJNNVddjԨ!I Pݵxb 6̌(d:u  XDFKVeLo S h۶mZbf͚%͖keŊիWvYnݺAo;.֬Yw}(&{}R};W@@ffFaÆI&ٳgզM\mVŤQFS1Ezo²n&ev,P1%Ν'OjӦMy>nZ%I畞:8{TMI0իgv,P1’OΝӄ 4ayOrr$-cW_p$K^^R@LiG̎J(FXVʕ5jԨ!RRRrܓ1cƨB 9*000?Bnԭ'TJ 帖`R’њ?f͚)))JKKӉ'T|`צ]jo͜9SZ*o(DiNjT`v,L#""Ժuk|UVVFѣGzN:z5c UREvuOxxZhQqBe!=?흝͎J( K>4kL}]-m6~m%%%>P %K(&&&{k7*::Z)QpТEWf)VIuJlǤCɓ͎J0fҥΝ;g_Q˖-UbEKJLLԩSUfMڵ+)a׆Ô0;էO߿_R2e̎S6_L7sr̎=]`BdXrYF mݺUӸq4m4Kׯg;c+Wjĉ?.=zu:تU{ (BL +D7ozƍvbN`4n8kf)vUoyAڶM##܆Q۶mիT(׭ڵ*lY)ee1(rOzԵkW=f)v҆ W}tխ Eӑ#G4cƌ\kJ={.ͥ_?#RܢM6i={$WWuJ }͎ic IDATJְhŊJII1;iF$I;J~~fG#,-X,0;iit*`PXTfZ)3  WH(.r:bEapSQQ ʒ!=q@)Ba˗/nDEI8}&ut0P(,@^|EuE6(vܞU4(/~'-[L_~e<ΟY?W[9>q@) pd1BݺuS``qB^3]W4;(ea*66Vk׮et3?)s\Rઃjԩ?~4h`vQeg̝r~Q@)Da$eeei]Ǝkv6ǾҞF%'ŏ)a+Vhǎڼy͎c72[uOR@R߾}yfu(v%e\=٣Q@)@e寎gFы7; (acUEcX4b@.?."Ջp>^Ě` l*(A}?\.QX0gr9҃=zw=R‚Rjfǰ[wIn9|(.߿}Qإ3gP+ה~8Ν;yfإkNZK9;!!!zK:u2;]*;o,^4vQ$QXPJ$$$4aاb|;B/OHbJJͦ^ϟ͛>yHṬ̎wn(,XJAAA]qӕ+TCԸKUdcJJ4ͦe˖i0`qעE\zUmۚODX,iv,M ˖\GU`vx...rss3;3GM(ɓ5d~8X`PXl4)9YG._#,PXii 饗|OԪ١r0;cy]L7kԸev((,(222ԫW/NUK,]6mfiȑڸq:wlv%t]/+5UڷO,vsXMyi…֭qߒ%ΝҦMR2:GJOZ6;@n-[Loz-=fDZI. (u*IڳGrv779@(,pX6mwy87 c;v4<( }9%E:p+~1ԣG=X,fG64t~bѨˌ{Eaâܢ+ᅲ|}s--5l(M-ws`$o|xWնm[׿5kLSL.Ip@Il2uU/5uTg5#:]J4vI=dl]\Z[l6!qOrE1B~,@aɇ(Y,ZJVb.,5j֭[+hܸqrssS^4}_rY^5J:~\W7y^PW_ӿ0XOy> .QXaͷ|oƍv"LrJ'{'5ܢ'W^V>iri~C? թ#K3g5hPL kXP~7u]=͎c7._6֔ɓҋ/ #4XXuߖLi:cR%cR˖Fp$L͚5K͚5ӯu֩cǎfDz'PvIÆI+aNKKf.McG %THٳG:t+!C޽ٱƹsƯ?IIIK;J͛˶fqjқoJ^^MM5%0Xs~UGz/wPxy+ UBBƍyiӦھ}CӴ8uJZլQ4ʔYYIglV˒,=.WqN5u%%kS~"?tƟO҃JǎZ6vpDPY,mٲEfRDDCŋ%__HCw3ϚeU+c5&SڻWW&NWP\~[iCK&ۺz۾PUjI/dZ\tc*YDt1Ϝ1=П=$6r#~;sƛ&qmdcddwڷ?c:u)^Rk#Py!e]Rl]ui*?a͟QO˗K'/I7 w7_LRE3ab7ߔ6m2Qgfl6!SDDZn={UVfSZZ)Nf9sXҨMJ2J@hԥQ Y9p%'=+EFJ\h=uDEu3guI[v-W4w͚e<|t#:<"-YrkBT1s12qkE9FXp[222aC}64/g5'ޔc/HISHQQR~j,TVV$c՗_J-4*^sB N3tq,qqIAw7>l)ժ?.͹_p͹aCcdXrei[;PAzeqw7vA(I(,%IIIZhf̘JIY͛ dekH>|}q˖-F[W^Dӧ#5kH?Ӿ8,~B)&:YGZ58cg''T 8!/K?_;$ԾRt4P{jWw_j62:ed+?(-chi ŜWJ rgcT߾>9shɒ%|{VzMb)(cd 8ؘv5jqc#GV۷kK:uV<=0j1+$Xlhdy\*}s4iX-NW[mj$\ԯ4XQUMk)Z:aCH}E5vIuI$ݸdZݥ8c^{M3km $)K6[\ڲeT#GjZ/7F7BBr͛KeJo%9!qm ԭsM$%&J?._o| o+zU}*׵qR\X5u.ꮊqN黋9wOo_ǽ~Oo5O 2J қE˖I|"U^ ?e嚷26`HP0}TBe͙3Tu_|\nnnEz4R|S7>64KCS7~ 2F7u3nkjոqU'?ԪqU䜔 }#C<<$??5'65ovAQD6(7I @`$56J׹sOatM̔x8p|iPf,wX͘QYfLj¸jHe)^aaƎW&_Q]8UNQ8mkUqr>cI⤗ƖW}ΖS?5+o?Ke|rnbhi\`{(+%9ymۦ'|REfxX,cL5:p@ZIjU>WWv:ƪ^$U>gխrNV:'K%)j xY6K&~ bѪ*EpHFoHmpgwxmJ{>g$+Xw3Z%͊͘Z 6ѣX,OGe;˗%US8}U+ɪVT.].ҫϷ0"r4`1O R8acSH~+͚eUqᇍ²vq Ο]QQh˖,խ[WEuyoU_-!Vk" GYJ4?Um+5l!j?}O?}~~ b݂ Ŏ}4uGiN)9YzSlRƕIQ8bw[G1SNwK'U;.Kj\N~Rя-\%=,og ۤdHJ bFMmj~1RAjv_U1ޱewr9Vy5H~S ?y3 GxM?kSW]?KXq6mmtCB~{w@صtVRuI%%XdxWEeJ[)O/޳~n'^Sgw6Y=S]}W? ˖5&S= Eac;~Xޫ-Z6mt1W^~M Ȼ89I.= ơ{ٳ%wwczP(,vĉ9vqTɽU3kkWF09C3PaAԮ-Yc‚{abJEa`(,ݢ[vnQX- Ea`(,ݢ[vnQX- Ea`(,ݢ[vnQXAjjƎ+???-[V۷׆ ̎= K1xg4sL=S'ggg=ڹsFa)b5e:t6mڤZj70;LPPPxK'^҉ K[|\\\se_sssӐ!CX?҇׼tu/x݁H5h@9mVw^3bRĬV|}}s]v-..#RĒ뺻{bvCd?WJ̡C6NBB"""̎bk^:Nϵr`(,E7i_VUǏKX`Znmv3^҉׽tu/?;aQXX˖-e%&&+zXX$EӣG}]v#0:~zavfl6Cdj߾NW_}Uq}ӦMUJ_OoΜ9ziɒ%:y-Zdv<1R RSSK_|.\͛kĉ޽Fa`8ݢ؉T;V~~~*[ڷo 6 El׮]9r4i"OOOժUKWttP&M$'''5k((bzGrʩYf͎";TrԨQ#M8s9J˗/zJ*IK,CgϞ򒏏 bN옘f'b 3Fwu-Z]vi]= Q~/ժٳg+))IjҤQbbb԰aC999N:ڷoّPD֭[޽{u߿<==u1l6M2x(NϫRJ ŋ#7;" [jժ:uh˖-Zx 㾘lR=z5m4լYSruu5;p6.,,fXlӧOϾb_C&&CQ msww 8ФT(N=.]ؚ6mjv[jl}5; ѤIlvן~ib]xѤd(,ӧOl6m6b[dI^x[rlNʾab}'ŖQ1%,_\...z粯iȐ! QllP]~jܸ>lR*m۶iŊ5kl6,ّPD.]3ghҤIi$YYY&BQt$jժ9W^]*SPʔ)fҊ+ԫW/ըQ#ZnԠA}7EQX@dd4h OO۶m+Iڻw`ͦӧOrfGAԨQ4l06lPu)5lP^^^P^|EEk׮!C(**JN_sj09!CllΞ=6mzm۶4!c*__\ׯ]+H0ї_~8((Bsɓ'5qDDGG+##C}C=oVܹsϚEG8q֯_-[VZ ѣ5}t㡘XVI{+==c9Nrssu=qֈ#ԡC=fA9w&L &8(IIIr^x͚5KԧOi޼yzwT~}S(ԪUK;wV߾}իWkҤIVFav<kn^7FayN HII~%YP۪\Fevky)44R}W>|'(YYY;vUR%S]zǔ0;累kCCɕzH.]ڵkUzu#DGGk5jbbbtq?~\)))JKKӉ'tc]wZj9_[k^2͙3GZ޽{ʕ+Q-%MzVU>>>lRGUbbbaaaQVIDAT-Z $%%E{ֱcǴzj}fGBUVVFufwQ?*bQi04j&g+-)`AY1 ne j / á`P=ߟ^]ϞgǏ388蹖ö_|Yqto7{_~M|y՞DחV^~{,8vXnܹ|z}uRx^zǏg޽UOdžh4233h4k׮lݺ53339uT3ƒ$[q~ݬ_>vܙoߦn8Q֭[ݻwWv4-fggns ?x}!h4rر#<ț7o2;;W=9w\nܸÇĉ t:y}S葉ܿ?ccc9p@={'OҥKvZ/^dtt4[lə3gy4<}4}v n޼߿g~~>nʑ#GjRղq7oڴ)gϞ͏?2==Z-R\|9>̷o߲gϞ\z5z=422ϟeSk֬FFFtݻ#J^|mۖӧOVU=jZrJt}| .˗ٰaC:ׯ%X(`%Xb X(`%Xb X(`%Xb X(`%Xb X(`%Xb X(`%Xb X(`%Xb X(`%Xb X(`%Xb X(`%Xb X?_섵IENDB`lmfit-0.9.7/doc/_static/0000755000076500000240000000000013114357470015752 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/_static/empty0000644000076500000240000000000013066042256017020 0ustar Newvillestaff00000000000000lmfit-0.9.7/doc/_templates/0000755000076500000240000000000013114357470016461 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/_templates/indexsidebar.html0000644000076500000240000000140213066042256022004 0ustar Newvillestaff00000000000000

Getting LMFIT

Current version: {{ release }}

Install:   pip install lmfit

Download:   PyPI

Develop:   GitHub

Questions?

  Frequently Asked Questions
  Mailing List
  Getting Help

Static, off-line docs

[PDF |EPUB |HTML(zip)]

lmfit-0.9.7/doc/bounds.rst0000644000076500000240000000671513066042256016360 0ustar Newvillestaff00000000000000.. _bounds_chapter: ================================= Bounds Implementation ================================= .. _MINPACK-1: http://en.wikipedia.org/wiki/MINPACK .. _MINUIT: http://en.wikipedia.org/wiki/MINUIT .. _leastsqbound: https://github.com/jjhelmus/leastsqbound-scipy This section describes the implementation of :class:`Parameter` bounds. The `MINPACK-1`_ implementation used in :scipydoc:`optimize.leastsq` for the Levenberg-Marquardt algorithm does not explicitly support bounds on parameters, and expects to be able to fully explore the available range of values for any Parameter. Simply placing hard constraints (that is, resetting the value when it exceeds the desired bounds) prevents the algorithm from determining the partial derivatives, and leads to unstable results. Instead of placing such hard constraints, bounded parameters are mathematically transformed using the formulation devised (and documented) for `MINUIT`_. This is implemented following (and borrowing heavily from) the `leastsqbound`_ from J. J. Helmus. Parameter values are mapped from internally used, freely variable values :math:`P_{\rm internal}` to bounded parameters :math:`P_{\rm bounded}`. When both ``min`` and ``max`` bounds are specified, the mapping is: .. math:: :nowrap: \begin{eqnarray*} P_{\rm internal} &=& \arcsin\big(\frac{2 (P_{\rm bounded} - {\rm min})}{({\rm max} - {\rm min})} - 1\big) \\ P_{\rm bounded} &=& {\rm min} + \big(\sin(P_{\rm internal}) + 1\big) \frac{({\rm max} - {\rm min})}{2} \end{eqnarray*} With only an upper limit ``max`` supplied, but ``min`` left unbounded, the mapping is: .. math:: :nowrap: \begin{eqnarray*} P_{\rm internal} &=& \sqrt{({\rm max} - P_{\rm bounded} + 1)^2 - 1} \\ P_{\rm bounded} &=& {\rm max} + 1 - \sqrt{P_{\rm internal}^2 + 1} \end{eqnarray*} With only a lower limit ``min`` supplied, but ``max`` left unbounded, the mapping is: .. math:: :nowrap: \begin{eqnarray*} P_{\rm internal} &=& \sqrt{(P_{\rm bounded} - {\rm min} + 1)^2 - 1} \\ P_{\rm bounded} &=& {\rm min} - 1 + \sqrt{P_{\rm internal}^2 + 1} \end{eqnarray*} With these mappings, the value for the bounded Parameter cannot exceed the specified bounds, though the internally varied value can be freely varied. It bears repeating that code from `leastsqbound`_ was adopted to implement the transformation described above. The challenging part (thanks again to Jonathan J. Helmus!) here is to re-transform the covariance matrix so that the uncertainties can be estimated for bounded Parameters. This is included by using the derivate :math:`dP_{\rm internal}/dP_{\rm bounded}` from the equations above to re-scale the Jacobin matrix before constructing the covariance matrix from it. Tests show that this re-scaling of the covariance matrix works quite well, and that uncertainties estimated for bounded are quite reasonable. Of course, if the best fit value is very close to a boundary, the derivative estimated uncertainty and correlations for that parameter may not be reliable. The `MINUIT`_ documentation recommends caution in using bounds. Setting bounds can certainly increase the number of function evaluations (and so computation time), and in some cases may cause some instabilities, as the range of acceptable parameter values is not fully explored. On the other hand, preliminary tests suggest that using ``max`` and ``min`` to set clearly outlandish bounds does not greatly affect performance or results. lmfit-0.9.7/doc/builtin_models.rst0000644000076500000240000006310713105400626020066 0ustar Newvillestaff00000000000000.. _builtin_models_chapter: ===================================================== Built-in Fitting Models in the :mod:`models` module ===================================================== .. module:: lmfit.models Lmfit provides several builtin fitting models in the :mod:`models` module. These pre-defined models each subclass from the :class:`model.Model` class of the previous chapter and wrap relatively well-known functional forms, such as Gaussians, Lorentzian, and Exponentials that are used in a wide range of scientific domains. In fact, all the models are all based on simple, plain Python functions defined in the :mod:`lineshapes` module. In addition to wrapping a function into a :class:`model.Model`, these models also provide a :meth:`guess` method that is intended to give a reasonable set of starting values from a data array that closely approximates the data to be fit. As shown in the previous chapter, a key feature of the :class:`mode.Model` class is that models can easily be combined to give a composite :class:`model.CompositeModel`. Thus, while some of the models listed here may seem pretty trivial (notably, :class:`ConstantModel` and :class:`LinearModel`), the main point of having these is to be able to use them in composite models. For example, a Lorentzian plus a linear background might be represented as:: >>> from lmfit.models import LinearModel, LorentzianModel >>> peak = LorentzianModel() >>> background = LinearModel() >>> model = peak + background All the models listed below are one dimensional, with an independent variable named ``x``. Many of these models represent a function with a distinct peak, and so share common features. To maintain uniformity, common parameter names are used whenever possible. Thus, most models have a parameter called ``amplitude`` that represents the overall height (or area of) a peak or function, a ``center`` parameter that represents a peak centroid position, and a ``sigma`` parameter that gives a characteristic width. Many peak shapes also have a parameter ``fwhm`` (constrained by ``sigma``) giving the full width at half maximum and a parameter ``height`` (constrained by ``sigma`` and ``amplitude``) to give the maximum peak height. After a list of builtin models, a few examples of their use is given. Peak-like models ------------------- There are many peak-like models available. These include :class:`GaussianModel`, :class:`LorentzianModel`, :class:`VoigtModel` and some less commonly used variations. The :meth:`guess` methods for all of these make a fairly crude guess for the value of ``amplitude``, but also set a lower bound of 0 on the value of ``sigma``. :class:`GaussianModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: GaussianModel :class:`LorentzianModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: LorentzianModel :class:`VoigtModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: VoigtModel :class:`PseudoVoigtModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: PseudoVoigtModel :class:`MoffatModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: MoffatModel :class:`Pearson7Model` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: Pearson7Model :class:`StudentsTModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: StudentsTModel :class:`BreitWignerModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: BreitWignerModel :class:`LognormalModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: LognormalModel :class:`DampedOcsillatorModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: DampedOscillatorModel :class:`DampedHarmonicOcsillatorModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: DampedHarmonicOscillatorModel :class:`ExponentialGaussianModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: ExponentialGaussianModel :class:`SkewedGaussianModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: SkewedGaussianModel :class:`DonaichModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: DonaichModel Linear and Polynomial Models ------------------------------------ These models correspond to polynomials of some degree. Of course, lmfit is a very inefficient way to do linear regression (see :numpydoc:`polyfit` or :scipydoc:`stats.linregress`), but these models may be useful as one of many components of composite model. :class:`ConstantModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: ConstantModel :class:`LinearModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: LinearModel :class:`QuadraticModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: QuadraticModel :class:`PolynomialModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: PolynomialModel Step-like models ----------------------------------------------- Two models represent step-like functions, and share many characteristics. :class:`StepModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: StepModel :class:`RectangleModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: RectangleModel Exponential and Power law models ----------------------------------------------- :class:`ExponentialModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: ExponentialModel :class:`PowerLawModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: PowerLawModel User-defined Models ---------------------------- .. _asteval: http://newville.github.io/asteval/ As shown in the previous chapter (:ref:`model_chapter`), it is fairly straightforward to build fitting models from parametrized Python functions. The number of model classes listed so far in the present chapter should make it clear that this process is not too difficult. Still, it is sometimes desirable to build models from a user-supplied function. This may be especially true if model-building is built-in to some larger library or application for fitting in which the user may not be able to easily build and use a new model from Python code. The :class:`ExpressionModel` allows a model to be built from a user-supplied expression. This uses the `asteval`_ module also used for mathematical constraints as discussed in :ref:`constraints_chapter`. :class:`ExpressionModel` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. autoclass:: ExpressionModel Since the point of this model is that an arbitrary expression will be supplied, the determination of what are the parameter names for the model happens when the model is created. To do this, the expression is parsed, and all symbol names are found. Names that are already known (there are over 500 function and value names in the asteval namespace, including most Python builtins, more than 200 functions inherited from NumPy, and more than 20 common lineshapes defined in the :mod:`lineshapes` module) are not converted to parameters. Unrecognized name are expected to be names either of parameters or independent variables. If `independent_vars` is the default value of None, and if the expression contains a variable named `x`, that will be used as the independent variable. Otherwise, `independent_vars` must be given. For example, if one creates an :class:`ExpressionModel` as:: >>> mod = ExpressionModel('off + amp * exp(-x/x0) * sin(x*phase)') The name `exp` will be recognized as the exponent function, so the model will be interpreted to have parameters named `off`, `amp`, `x0` and `phase`. In addition, `x` will be assumed to be the sole independent variable. In general, there is no obvious way to set default parameter values or parameter hints for bounds, so this will have to be handled explicitly. To evaluate this model, you might do the following:: >>> x = numpy.linspace(0, 10, 501) >>> params = mod.make_params(off=0.25, amp=1.0, x0=2.0, phase=0.04) >>> y = mod.eval(params, x=x) While many custom models can be built with a single line expression (especially since the names of the lineshapes like `gaussian`, `lorentzian` and so on, as well as many NumPy functions, are available), more complex models will inevitably require multiple line functions. You can include such Python code with the `init_script` argument. The text of this script is evaluated when the model is initialized (and before the actual expression is parsed), so that you can define functions to be used in your expression. As a probably unphysical example, to make a model that is the derivative of a Gaussian function times the logarithm of a Lorentzian function you may could to define this in a script:: >>> script = """ def mycurve(x, amp, cen, sig): loren = lorentzian(x, amplitude=amp, center=cen, sigma=sig) gauss = gaussian(x, amplitude=amp, center=cen, sigma=sig) return log(loren)*gradient(gauss)/gradient(x) """ and then use this with :class:`ExpressionModel` as:: >>> mod = ExpressionModel('mycurve(x, height, mid, wid)', init_script=script, independent_vars=['x']) As above, this will interpret the parameter names to be `height`, `mid`, and `wid`, and build a model that can be used to fit data. Example 1: Fit Peaked data to Gaussian, Lorentzian, and Voigt profiles ------------------------------------------------------------------------ Here, we will fit data to three similar line shapes, in order to decide which might be the better model. We will start with a Gaussian profile, as in the previous chapter, but use the built-in :class:`GaussianModel` instead of writing one ourselves. This is a slightly different version from the one in previous example in that the parameter names are different, and have built-in default values. We will simply use:: from numpy import loadtxt from lmfit.models import GaussianModel data = loadtxt('test_peak.dat') x = data[:, 0] y = data[:, 1] mod = GaussianModel() pars = mod.guess(y, x=x) out = mod.fit(y, pars, x=x) print(out.fit_report(min_correl=0.25)) which prints out the results:: [[Model]] Model(gaussian) [[Fit Statistics]] # function evals = 23 # data points = 401 # variables = 3 chi-square = 29.994 reduced chi-square = 0.075 Akaike info crit = -1033.774 Bayesian info crit = -1021.792 [[Variables]] sigma: 1.23218319 +/- 0.007374 (0.60%) (init= 1.35) center: 9.24277049 +/- 0.007374 (0.08%) (init= 9.25) amplitude: 30.3135571 +/- 0.157126 (0.52%) (init= 29.08159) fwhm: 2.90156963 +/- 0.017366 (0.60%) == '2.3548200*sigma' height: 9.81457973 +/- 0.050872 (0.52%) == '0.3989423*amplitude/max(1.e-15, sigma)' [[Correlations]] (unreported correlations are < 0.250) C(sigma, amplitude) = 0.577 We see a few interesting differences from the results of the previous chapter. First, the parameter names are longer. Second, there are ``fwhm`` and ``height`` parameters, to give the full width at half maximum and maximum peak height. And third, the automated initial guesses are pretty good. A plot of the fit: .. _figA1: .. image:: _images/models_peak1.png :target: _images/models_peak1.png :width: 48 % .. image:: _images/models_peak2.png :target: _images/models_peak2.png :width: 48 % Fit to peak with Gaussian (left) and Lorentzian (right) models. shows a decent match to the data -- the fit worked with no explicit setting of initial parameter values. Looking more closing, the fit is not perfect, especially in the tails of the peak, suggesting that a different peak shape, with longer tails, should be used. Perhaps a Lorentzian would be better? To do this, we simply replace ``GaussianModel`` with ``LorentzianModel`` to get a :class:`LorentzianModel`:: from lmfit.models import LorentzianModel mod = LorentzianModel() with the rest of the script as above. Perhaps predictably, the first thing we try gives results that are worse:: [[Model]] Model(lorentzian) [[Fit Statistics]] # function evals = 27 # data points = 401 # variables = 3 chi-square = 53.754 reduced chi-square = 0.135 Akaike info crit = -799.830 Bayesian info crit = -787.848 [[Variables]] sigma: 1.15484517 +/- 0.013156 (1.14%) (init= 1.35) center: 9.24438944 +/- 0.009275 (0.10%) (init= 9.25) amplitude: 38.9728645 +/- 0.313857 (0.81%) (init= 36.35199) fwhm: 2.30969034 +/- 0.026312 (1.14%) == '2.0000000*sigma' height: 10.7420881 +/- 0.086336 (0.80%) == '0.3183099*amplitude/max(1.e-15, sigma)' [[Correlations]] (unreported correlations are < 0.250) C(sigma, amplitude) = 0.709 with the plot shown on the right in the figure above. The tails are now too big, and the value for :math:`\chi^2` almost doubled. A Voigt model does a better job. Using :class:`VoigtModel`, this is as simple as using:: from lmfit.models import VoigtModel mod = VoigtModel() with all the rest of the script as above. This gives:: [[Model]] Model(voigt) [[Fit Statistics]] # function evals = 19 # data points = 401 # variables = 3 chi-square = 14.545 reduced chi-square = 0.037 Akaike info crit = -1324.006 Bayesian info crit = -1312.024 [[Variables]] amplitude: 35.7554017 +/- 0.138614 (0.39%) (init= 43.62238) sigma: 0.73015574 +/- 0.003684 (0.50%) (init= 0.8775) center: 9.24411142 +/- 0.005054 (0.05%) (init= 9.25) gamma: 0.73015574 +/- 0.003684 (0.50%) == 'sigma' fwhm: 2.62951718 +/- 0.013269 (0.50%) == '3.6013100*sigma' height: 19.5360268 +/- 0.075691 (0.39%) == '0.3989423*amplitude/max(1.e-15, sigma)' [[Correlations]] (unreported correlations are < 0.250) C(sigma, amplitude) = 0.651 which has a much better value for :math:`\chi^2` and an obviously better match to the data as seen in the figure below (left). .. _figA2: .. image:: _images/models_peak3.png :target: _images/models_peak3.png :width: 48 % .. image:: _images/models_peak4.png :target: _images/models_peak4.png :width: 48 % Fit to peak with Voigt model (left) and Voigt model with ``gamma`` varying independently of ``sigma`` (right). Can we do better? The Voigt function has a :math:`\gamma` parameter (``gamma``) that can be distinct from ``sigma``. The default behavior used above constrains ``gamma`` to have exactly the same value as ``sigma``. If we allow these to vary separately, does the fit improve? To do this, we have to change the ``gamma`` parameter from a constrained expression and give it a starting value using something like:: mod = VoigtModel() pars = mod.guess(y, x=x) pars['gamma'].set(value=0.7, vary=True, expr='') which gives:: [[Model]] Model(voigt) [[Fit Statistics]] # function evals = 23 # data points = 401 # variables = 4 chi-square = 10.930 reduced chi-square = 0.028 Akaike info crit = -1436.576 Bayesian info crit = -1420.600 [[Variables]] amplitude: 34.1914716 +/- 0.179468 (0.52%) (init= 43.62238) sigma: 0.89518950 +/- 0.014154 (1.58%) (init= 0.8775) center: 9.24374845 +/- 0.004419 (0.05%) (init= 9.25) gamma: 0.52540156 +/- 0.018579 (3.54%) (init= 0.7) fwhm: 3.22385492 +/- 0.050974 (1.58%) == '3.6013100*sigma' height: 15.2374711 +/- 0.299235 (1.96%) == '0.3989423*amplitude/max(1.e-15, sigma)' [[Correlations]] (unreported correlations are < 0.250) C(sigma, gamma) = -0.928 C(gamma, amplitude) = 0.821 C(sigma, amplitude) = -0.651 and the fit shown on the right above. Comparing the two fits with the Voigt function, we see that :math:`\chi^2` is definitely improved with a separately varying ``gamma`` parameter. In addition, the two values for ``gamma`` and ``sigma`` differ significantly -- well outside the estimated uncertainties. More compelling, reduced :math:`\chi^2` is improved even though a fourth variable has been added to the fit. In the simplest statistical sense, this suggests that ``gamma`` is a significant variable in the model. In addition, we can use both the Akaike or Bayesian Information Criteria (see :ref:`information_criteria_label`) to assess how likely the model with variable ``gamma`` is to explain the data than the model with ``gamma`` fixed to the value of ``sigma``. According to theory, :math:`\exp(-(\rm{AIC1}-\rm{AIC0})/2)` gives the probability that a model with AIC1 is more likely than a model with AIC0. For the two models here, with AIC values of -1432 and -1321 (Note: if we had more carefully set the value for ``weights`` based on the noise in the data, these values might be positive, but there difference would be roughly the same), this says that the model with ``gamma`` fixed to ``sigma`` has a probability less than 1.e-25 of being the better model. Example 2: Fit data to a Composite Model with pre-defined models ------------------------------------------------------------------ Here, we repeat the point made at the end of the last chapter that instances of :class:`model.Model` class can be added together to make a *composite model*. By using the large number of built-in models available, it is therefore very simple to build models that contain multiple peaks and various backgrounds. An example of a simple fit to a noisy step function plus a constant: .. literalinclude:: ../examples/doc_stepmodel.py After constructing step-like data, we first create a :class:`StepModel` telling it to use the ``erf`` form (see details above), and a :class:`ConstantModel`. We set initial values, in one case using the data and :meth:`guess` method for the initial step function paramaters, and :meth:`make_params` arguments for the linear component. After making a composite model, we run :meth:`fit` and report the results, which gives:: [[Model]] (Model(step, prefix='step_', form='erf') + Model(linear, prefix='line_')) [[Fit Statistics]] # function evals = 51 # data points = 201 # variables = 5 chi-square = 584.829 reduced chi-square = 2.984 Akaike info crit = 224.671 Bayesian info crit = 241.187 [[Variables]] line_slope: 2.03039786 +/- 0.092221 (4.54%) (init= 0) line_intercept: 11.7234542 +/- 0.274094 (2.34%) (init= 10.7816) step_amplitude: 112.071629 +/- 0.647316 (0.58%) (init= 134.0885) step_sigma: 0.67132341 +/- 0.010873 (1.62%) (init= 1.428571) step_center: 3.12697699 +/- 0.005151 (0.16%) (init= 2.5) [[Correlations]] (unreported correlations are < 0.100) C(line_slope, step_amplitude) = -0.878 C(step_amplitude, step_sigma) = 0.563 C(line_slope, step_sigma) = -0.455 C(line_intercept, step_center) = 0.427 C(line_slope, line_intercept) = -0.308 C(line_slope, step_center) = -0.234 C(line_intercept, step_sigma) = -0.139 C(line_intercept, step_amplitude) = -0.121 C(step_amplitude, step_center) = 0.109 with a plot of .. image:: _images/models_stepfit.png :target: _images/models_stepfit.png :width: 50 % Example 3: Fitting Multiple Peaks -- and using Prefixes ------------------------------------------------------------------ .. _NIST StRD: http://itl.nist.gov/div898/strd/nls/nls_main.shtml As shown above, many of the models have similar parameter names. For composite models, this could lead to a problem of having parameters for different parts of the model having the same name. To overcome this, each :class:`model.Model` can have a ``prefix`` attribute (normally set to a blank string) that will be put at the beginning of each parameter name. To illustrate, we fit one of the classic datasets from the `NIST StRD`_ suite involving a decaying exponential and two gaussians. .. literalinclude:: ../examples/doc_nistgauss.py where we give a separate prefix to each model (they all have an ``amplitude`` parameter). The ``prefix`` values are attached transparently to the models. Note that the calls to :meth:`make_param` used the bare name, without the prefix. We could have used the prefixes, but because we used the individual model ``gauss1`` and ``gauss2``, there was no need. Note also in the example here that we explicitly set bounds on many of the parameter values. The fit results printed out are:: [[Model]] ((Model(gaussian, prefix='g1_') + Model(gaussian, prefix='g2_')) + Model(exponential, prefix='exp_')) [[Fit Statistics]] # function evals = 66 # data points = 250 # variables = 8 chi-square = 1247.528 reduced chi-square = 5.155 Akaike info crit = 417.865 Bayesian info crit = 446.036 [[Variables]] exp_amplitude: 99.0183282 +/- 0.537487 (0.54%) (init= 162.2102) exp_decay: 90.9508859 +/- 1.103105 (1.21%) (init= 93.24905) g1_sigma: 16.6725753 +/- 0.160481 (0.96%) (init= 15) g1_center: 107.030954 +/- 0.150067 (0.14%) (init= 105) g1_amplitude: 4257.77319 +/- 42.38336 (1.00%) (init= 2000) g1_fwhm: 39.2609139 +/- 0.377905 (0.96%) == '2.3548200*g1_sigma' g1_height: 101.880231 +/- 0.592170 (0.58%) == '0.3989423*g1_amplitude/max(1.e-15, g1_sigma)' g2_sigma: 13.8069484 +/- 0.186794 (1.35%) (init= 15) g2_center: 153.270100 +/- 0.194667 (0.13%) (init= 155) g2_amplitude: 2493.41770 +/- 36.16947 (1.45%) (init= 2000) g2_fwhm: 32.5128782 +/- 0.439866 (1.35%) == '2.3548200*g2_sigma' g2_height: 72.0455934 +/- 0.617220 (0.86%) == '0.3989423*g2_amplitude/max(1.e-15, g2_sigma)' [[Correlations]] (unreported correlations are < 0.500) C(g1_sigma, g1_amplitude) = 0.824 C(g2_sigma, g2_amplitude) = 0.815 C(exp_amplitude, exp_decay) = -0.695 C(g1_sigma, g2_center) = 0.684 C(g1_center, g2_amplitude) = -0.669 C(g1_center, g2_sigma) = -0.652 C(g1_amplitude, g2_center) = 0.648 C(g1_center, g2_center) = 0.621 C(g1_sigma, g1_center) = 0.507 C(exp_decay, g1_amplitude) = -0.507 We get a very good fit to this problem (described at the NIST site as of average difficulty, but the tests there are generally deliberately challenging) by applying reasonable initial guesses and putting modest but explicit bounds on the parameter values. This fit is shown on the left: .. _figA3: .. image:: _images/models_nistgauss.png :target: _images/models_nistgauss.png :width: 48 % .. image:: _images/models_nistgauss2.png :target: _images/models_nistgauss2.png :width: 48 % One final point on setting initial values. From looking at the data itself, we can see the two Gaussian peaks are reasonably well separated but do overlap. Furthermore, we can tell that the initial guess for the decaying exponential component was poorly estimated because we used the full data range. We can simplify the initial parameter values by using this, and by defining an :func:`index_of` function to limit the data range. That is, with:: def index_of(arrval, value): "return index of array *at or below* value " if value < min(arrval): return 0 return max(np.where(arrval<=value)[0]) ix1 = index_of(x, 75) ix2 = index_of(x, 135) ix3 = index_of(x, 175) exp_mod.guess(y[:ix1], x=x[:ix1]) gauss1.guess(y[ix1:ix2], x=x[ix1:ix2]) gauss2.guess(y[ix2:ix3], x=x[ix2:ix3]) we can get a better initial estimate. The fit converges to the same answer, giving to identical values (to the precision printed out in the report), but in few steps, and without any bounds on parameters at all:: [[Model]] ((Model(gaussian, prefix='g1_') + Model(gaussian, prefix='g2_')) + Model(exponential, prefix='exp_')) [[Fit Statistics]] # function evals = 48 # data points = 250 # variables = 8 chi-square = 1247.528 reduced chi-square = 5.155 Akaike info crit = 417.865 Bayesian info crit = 446.036 [[Variables]] exp_amplitude: 99.0183281 +/- 0.537487 (0.54%) (init= 94.53724) exp_decay: 90.9508862 +/- 1.103105 (1.21%) (init= 111.1985) g1_sigma: 16.6725754 +/- 0.160481 (0.96%) (init= 14.5) g1_center: 107.030954 +/- 0.150067 (0.14%) (init= 106.5) g1_amplitude: 4257.77322 +/- 42.38338 (1.00%) (init= 2126.432) g1_fwhm: 39.2609141 +/- 0.377905 (0.96%) == '2.3548200*g1_sigma' g1_height: 101.880231 +/- 0.592171 (0.58%) == '0.3989423*g1_amplitude/max(1.e-15, g1_sigma)' g2_sigma: 13.8069481 +/- 0.186794 (1.35%) (init= 15) g2_center: 153.270100 +/- 0.194667 (0.13%) (init= 150) g2_amplitude: 2493.41766 +/- 36.16948 (1.45%) (init= 1878.892) g2_fwhm: 32.5128777 +/- 0.439866 (1.35%) == '2.3548200*g2_sigma' g2_height: 72.0455935 +/- 0.617221 (0.86%) == '0.3989423*g2_amplitude/max(1.e-15, g2_sigma)' [[Correlations]] (unreported correlations are < 0.500) C(g1_sigma, g1_amplitude) = 0.824 C(g2_sigma, g2_amplitude) = 0.815 C(exp_amplitude, exp_decay) = -0.695 C(g1_sigma, g2_center) = 0.684 C(g1_center, g2_amplitude) = -0.669 C(g1_center, g2_sigma) = -0.652 C(g1_amplitude, g2_center) = 0.648 C(g1_center, g2_center) = 0.621 C(g1_sigma, g1_center) = 0.507 C(exp_decay, g1_amplitude) = -0.507 This script is in the file ``doc_nistgauss2.py`` in the examples folder, and the fit result shown on the right above shows an improved initial estimate of the data. lmfit-0.9.7/doc/conf.py0000644000076500000240000001321513066042256015624 0ustar Newvillestaff00000000000000# -*- coding: utf-8 -*- # # lmfit documentation build configuration file # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('../')) # sys.path.append(os.path.abspath(os.path.join('..', 'lmfit'))) sys.path.append(os.path.abspath(os.path.join('.', 'sphinx'))) sys.path.append(os.path.abspath(os.path.join('.'))) # -- General configuration ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. from extensions import extensions ssoextensions = ['sphinx.ext.extlinks', 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.mathjax'] autoclass_content = 'both' intersphinx_mapping = {'py': ('https://docs.python.org/2', None), 'numpy': ('https://docs.scipy.org/doc/numpy/', None), 'scipy': ('https://docs.scipy.org/doc/scipy/reference/', None), } ## intersphinx_cache_limit = 10 extlinks = { 'scipydoc' : ('http://docs.scipy.org/doc/scipy/reference/generated/scipy.%s.html', 'scipy.'), 'numpydoc' : ('http://docs.scipy.org/doc/numpy/reference/generated/numpy.%s.html', 'numpy.'), } # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = u'lmfit' copyright = u'2017, Matthew Newville, The University of Chicago, Till Stensitzki, Freie Universitat Berlin' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the import lmfit release = lmfit.__version__ # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = False # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- html_theme_path = ['sphinx/theme'] html_theme = 'lmfitdoc' # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None html_title = 'Non-Linear Least-Squares Minimization and Curve-Fitting for Python' # A shorter title for the navigation bar. Default is the same as html_title. html_short_title = 'Minimization and Curve-Fitting for Python' # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = {'index': ['indexsidebar.html','searchbox.html']} html_domain_indices = False html_use_index = True #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'lmfitdoc' # -- Options for LaTeX output -------------------------------------------------- # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'lmfit.tex', 'Non-Linear Least-Squares Minimization and Curve-Fitting for Python', 'Matthew Newville, Till Stensitzki, and others', 'manual'), ] lmfit-0.9.7/doc/confidence.rst0000644000076500000240000001670613066042256017164 0ustar Newvillestaff00000000000000.. _confidence_chapter: Calculation of confidence intervals ==================================== .. module:: lmfit.confidence The lmfit :mod:`confidence` module allows you to explicitly calculate confidence intervals for variable parameters. For most models, it is not necessary since the estimation of the standard error from the estimated covariance matrix is normally quite good. But for some models, the sum of two exponentials for example, the approximation begins to fail. For this case, lmfit has the function :func:`conf_interval` to calculate confidence intervals directly. This is substantially slower than using the errors estimated from the covariance matrix, but the results are more robust. Method used for calculating confidence intervals ------------------------------------------------- The F-test is used to compare our null model, which is the best fit we have found, with an alternate model, where one of the parameters is fixed to a specific value. The value is changed until the difference between :math:`\chi^2_0` and :math:`\chi^2_{f}` can't be explained by the loss of a degree of freedom within a certain confidence. .. math:: F(P_{fix},N-P) = \left(\frac{\chi^2_f}{\chi^2_{0}}-1\right)\frac{N-P}{P_{fix}} `N` is the number of data points, `P` the number of parameters of the null model. :math:`P_{fix}` is the number of fixed parameters (or to be more clear, the difference of number of parameters between our null model and the alternate model). Adding a log-likelihood method is under consideration. A basic example --------------- First we create an example problem:: >>> import lmfit >>> import numpy as np >>> x = np.linspace(0.3,10,100) >>> y = 1/(0.1*x)+2+0.1*np.random.randn(x.size) >>> pars = lmfit.Parameters() >>> pars.add_many(('a', 0.1), ('b', 1)) >>> def residual(p): ... a = p['a'].value ... b = p['b'].value ... return 1/(a*x)+b-y before we can generate the confidence intervals, we have to run a fit, so that the automated estimate of the standard errors can be used as a starting point:: >>> mini = lmfit.Minimizer(residual, pars) >>> result = mini.minimize() >>> print(lmfit.fit_report(result.params)) [Variables]] a: 0.09943895 +/- 0.000193 (0.19%) (init= 0.1) b: 1.98476945 +/- 0.012226 (0.62%) (init= 1) [[Correlations]] (unreported correlations are < 0.100) C(a, b) = 0.601 Now it is just a simple function call to calculate the confidence intervals:: >>> ci = lmfit.conf_interval(mini, result) >>> lmfit.printfuncs.report_ci(ci) 99.70% 95.00% 67.40% 0.00% 67.40% 95.00% 99.70% a 0.09886 0.09905 0.09925 0.09944 0.09963 0.09982 0.10003 b 1.94751 1.96049 1.97274 1.97741 1.99680 2.00905 2.02203 This shows the best-fit values for the parameters in the `0.00%` column, and parameter values that are at the varying confidence levels given by steps in :math:`\sigma`. As we can see, the estimated error is almost the same, and the uncertainties are well behaved: Going from 1 :math:`\sigma` (68% confidence) to 3 :math:`\sigma` (99.7% confidence) uncertainties is fairly linear. It can also be seen that the errors are fairy symmetric around the best fit value. For this problem, it is not necessary to calculate confidence intervals, and the estimates of the uncertainties from the covariance matrix are sufficient. An advanced example ------------------- Now we look at a problem where calculating the error from approximated covariance can lead to misleading result -- two decaying exponentials. In fact such a problem is particularly hard for the Levenberg-Marquardt method, so we first estimate the results using the slower but robust Nelder-Mead method, and *then* use Levenberg-Marquardt to estimate the uncertainties and correlations .. literalinclude:: ../examples/doc_confidence2.py which will report:: [[Variables]] a1: 2.98622120 +/- 0.148671 (4.98%) (init= 2.986237) a2: -4.33526327 +/- 0.115275 (2.66%) (init=-4.335256) t1: 1.30994233 +/- 0.131211 (10.02%) (init= 1.309932) t2: 11.8240350 +/- 0.463164 (3.92%) (init= 11.82408) [[Correlations]] (unreported correlations are < 0.500) C(a2, t2) = 0.987 C(a2, t1) = -0.925 C(t1, t2) = -0.881 C(a1, t1) = -0.599 95.00% 68.00% 0.00% 68.00% 95.00% a1 2.71850 2.84525 2.98622 3.14874 3.34076 a2 -4.63180 -4.46663 -4.33526 -4.22883 -4.14178 t2 10.82699 11.33865 11.82404 12.28195 12.71094 t1 1.08014 1.18566 1.30994 1.45566 1.62579 Again we called :func:`conf_interval`, this time with tracing and only for 1- and 2-:math:`\sigma`. Comparing these two different estimates, we see that the estimate for `a1` is reasonably well approximated from the covariance matrix, but the estimates for `a2` and especially for `t1`, and `t2` are very asymmetric and that going from 1 :math:`\sigma` (68% confidence) to 2 :math:`\sigma` (95% confidence) is not very predictable. Let plots mad of the confidence region are shown the figure on the left below for `a1` and `t2`, and for `a2` and `t2` on the right: .. _figC1: .. image:: _images/conf_interval1.png :target: _images/conf_interval1.png :width: 48% .. image:: _images/conf_interval1a.png :target: _images/conf_interval1a.png :width: 48% Neither of these plots is very much like an ellipse, which is implicitly assumed by the approach using the covariance matrix. The trace returned as the optional second argument from :func:`conf_interval` contains a dictionary for each variable parameter. The values are dictionaries with arrays of values for each variable, and an array of corresponding probabilities for the corresponding cumulative variables. This can be used to show the dependence between two parameters:: >>> x, y, prob = trace['a1']['a1'], trace['a1']['t2'],trace['a1']['prob'] >>> x2, y2, prob2 = trace['t2']['t2'], trace['t2']['a1'],trace['t2']['prob'] >>> plt.scatter(x, y, c=prob ,s=30) >>> plt.scatter(x2, y2, c=prob2, s=30) >>> plt.gca().set_xlim((1, 5)) >>> plt.gca().set_ylim((5, 15)) >>> plt.xlabel('a1') >>> plt.ylabel('t2') >>> plt.show() which shows the trace of values: .. image:: _images/conf_interval2.png :target: _images/conf_interval2.png :width: 50% The :meth:`Minimizer.emcee` method uses Markov Chain Monte Carlo to sample the posterior probability distribution. These distributions demonstrate the range of solutions that the data supports. The following image was obtained by using :meth:`Minimizer.emcee` on the same problem. .. image:: _images/emcee_triangle.png Credible intervals (the Bayesian equivalent of the frequentist confidence interval) can be obtained with this method. MCMC can be used for model selection, to determine outliers, to marginalise over nuisance parameters, etcetera. For example, you may have fractionally underestimated the uncertainties on a dataset. MCMC can be used to estimate the true level of uncertainty on each datapoint. A tutorial on the possibilities offered by MCMC can be found at [1]_. .. [1] http://jakevdp.github.io/blog/2014/03/11/frequentism-and-bayesianism-a-practical-intro/ Confidence Interval Functions ---------------------------------- .. autofunction:: lmfit.conf_interval .. autofunction:: lmfit.conf_interval2d .. autofunction:: lmfit.ci_report lmfit-0.9.7/doc/constraints.rst0000644000076500000240000001562213066042256017432 0ustar Newvillestaff00000000000000.. _constraints_chapter: ================================= Using Mathematical Constraints ================================= .. _asteval: http://newville.github.io/asteval/ Being able to fix variables to a constant value or place upper and lower bounds on their values can greatly simplify modeling real data. These capabilities are key to lmfit's Parameters. In addition, it is sometimes highly desirable to place mathematical constraints on parameter values. For example, one might want to require that two Gaussian peaks have the same width, or have amplitudes that are constrained to add to some value. Of course, one could rewrite the objective or model function to place such requirements, but this is somewhat error prone, and limits the flexibility so that exploring constraints becomes laborious. To simplify the setting of constraints, Parameters can be assigned a mathematical expression of other Parameters, builtin constants, and builtin mathematical functions that will be used to determine its value. The expressions used for constraints are evaluated using the `asteval`_ module, which uses Python syntax, and evaluates the constraint expressions in a safe and isolated namespace. This approach to mathematical constraints allows one to not have to write a separate model function for two Gaussians where the two ``sigma`` values are forced to be equal, or where amplitudes are related. Instead, one can write a more general two Gaussian model (perhaps using :class:`GaussianModel`) and impose such constraints on the Parameters for a particular fit. Overview =============== Just as one can place bounds on a Parameter, or keep it fixed during the fit, so too can one place mathematical constraints on parameters. The way this is done with lmfit is to write a Parameter as a mathematical expression of the other parameters and a set of pre-defined operators and functions. The constraint expressions are simple Python statements, allowing one to place constraints like:: pars = Parameters() pars.add('frac_curve1', value=0.5, min=0, max=1) pars.add('frac_curve2', expr='1-frac_curve1') as the value of the `frac_curve1` parameter is updated at each step in the fit, the value of `frac_curve2` will be updated so that the two values are constrained to add to 1.0. Of course, such a constraint could be placed in the fitting function, but the use of such constraints allows the end-user to modify the model of a more general-purpose fitting function. Nearly any valid mathematical expression can be used, and a variety of built-in functions are available for flexible modeling. Supported Operators, Functions, and Constants ================================================= The mathematical expressions used to define constrained Parameters need to be valid python expressions. As you'd expect, the operators '+', '-', '*', '/', '**', are supported. In fact, a much more complete set can be used, including Python's bit- and logical operators:: +, -, *, /, **, &, |, ^, <<, >>, %, and, or, ==, >, >=, <, <=, !=, ~, not, is, is not, in, not in The values for `e` (2.7182818...) and `pi` (3.1415926...) are available, as are several supported mathematical and trigonometric function:: abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, copysign, cos, cosh, degrees, exp, fabs, factorial, floor, fmod, frexp, fsum, hypot, isinf, isnan, ldexp, log, log10, log1p, max, min, modf, pow, radians, sin, sinh, sqrt, tan, tanh, trunc In addition, all Parameter names will be available in the mathematical expressions. Thus, with parameters for a few peak-like functions:: pars = Parameters() pars.add('amp_1', value=0.5, min=0, max=1) pars.add('cen_1', value=2.2) pars.add('wid_1', value=0.2) The following expression are all valid:: pars.add('amp_2', expr='(2.0 - amp_1**2)') pars.add('cen_2', expr='cen_1 * wid_2 / max(wid_1, 0.001)') pars.add('wid_2', expr='sqrt(pi)*wid_1') In fact, almost any valid Python expression is allowed. A notable example is that Python's 1-line *if expression* is supported:: pars.add('bounded', expr='param_a if test_val/2. > 100 else param_b') which is equivalent to the more familiar:: if test_val/2. > 100: bounded = param_a else: bounded = param_b Using Inequality Constraints ============================== A rather common question about how to set up constraints that use an inequality, say, :math:`x + y \le 10`. This can be done with algebraic constraints by recasting the problem, as :math:`x + y = \delta` and :math:`\delta \le 10`. That is, first, allow :math:`x` to be held by the freely varying parameter `x`. Next, define a parameter `delta` to be variable with a maximum value of 10, and define parameter `y` as `delta - x`:: pars = Parameters() pars.add('x', value = 5, vary=True) pars.add('delta', value = 5, max=10, vary=True) pars.add('y', expr='delta-x') The essential point is that an inequality still implies that a variable (here, `delta`) is needed to describe the constraint. The secondary point is that upper and lower bounds can be used as part of the inequality to make the definitions more convenient. Advanced usage of Expressions in lmfit ============================================= The expression used in a constraint is converted to a Python `Abstract Syntax Tree `_, which is an intermediate version of the expression -- a syntax-checked, partially compiled expression. Among other things, this means that Python's own parser is used to parse and convert the expression into something that can easily be evaluated within Python. It also means that the symbols in the expressions can point to any Python object. In fact, the use of Python's AST allows a nearly full version of Python to be supported, without using Python's built-in :meth:`eval` function. The `asteval`_ module actually supports most Python syntax, including for- and while-loops, conditional expressions, and user-defined functions. There are several unsupported Python constructs, most notably the class statement, so that new classes cannot be created, and the import statement, which helps make the `asteval`_ module safe from malicious use. One important feature of the `asteval`_ module is that you can add domain-specific functions into the it, for later use in constraint expressions. To do this, you would use the :attr:`asteval` attribute of the :class:`Minimizer` class, which contains a complete AST interpreter. The `asteval`_ interpreter uses a flat namespace, implemented as a single dictionary. That means you can preload any Python symbol into the namespace for the constraints:: def mylorentzian(x, amp, cen, wid): "lorentzian function: wid = half-width at half-max" return (amp / (1 + ((x-cen)/wid)**2)) fitter = Minimizer() fitter.asteval.symtable['lorentzian'] = mylorentzian and this :meth:`lorentzian` function can now be used in constraint expressions. lmfit-0.9.7/doc/contents.rst0000644000076500000240000000031413066042256016710 0ustar Newvillestaff00000000000000Contents ================= .. toctree:: :maxdepth: 3 intro installation whatsnew support faq parameters fitting model builtin_models confidence bounds constraints lmfit-0.9.7/doc/extensions.py0000644000076500000240000000044113102710340017056 0ustar Newvillestaff00000000000000# sphinx extensions for mathjax extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.intersphinx', 'sphinx.ext.extlinks', 'sphinx.ext.napoleon', 'sphinx.ext.mathjax'] lmfit-0.9.7/doc/extensions.pyc0000644000076500000240000000054213102710340017223 0ustar Newvillestaff00000000000000 Yc@sdddddddgZdS(ssphinx.ext.autodocssphinx.ext.todossphinx.ext.coveragessphinx.ext.intersphinxssphinx.ext.extlinksssphinx.ext.napoleonssphinx.ext.mathjaxN(t extensions(((s0/Users/Newville/Codes/lmfit-py/doc/extensions.pyts lmfit-0.9.7/doc/faq.rst0000644000076500000240000000571613066042256015635 0ustar Newvillestaff00000000000000.. _faq_chapter: ==================================== Frequently Asked Questions ==================================== A list of common questions. What's the best way to ask for help or submit a bug report? ================================================================ See :ref:`support_chapter`. Why did my script break when upgrading from lmfit 0.8.3 to 0.9.0? ==================================================================== See :ref:`whatsnew_090_label` I get import errors from IPython ============================================================== If you see something like:: from IPython.html.widgets import Dropdown ImportError: No module named 'widgets' then you need to install the ``ipywidgets`` package, try: ``pip install ipywidgets``. How can I fit multi-dimensional data? ======================================== The fitting routines accept data arrays that are one dimensional and double precision. So you need to convert the data and model (or the value returned by the objective function) to be one dimensional. A simple way to do this is to use :numpydoc:`ndarray.flatten`, for example:: def residual(params, x, data=None): .... resid = calculate_multidim_residual() return resid.flatten() How can I fit multiple data sets? ======================================== As above, the fitting routines accept data arrays that are one dimensional and double precision. So you need to convert the sets of data and models (or the value returned by the objective function) to be one dimensional. A simple way to do this is to use :numpydoc:`concatenate`. As an example, here is a residual function to simultaneously fit two lines to two different arrays. As a bonus, the two lines share the 'offset' parameter:: import numpy as np def fit_function(params, x=None, dat1=None, dat2=None): model1 = params['offset'] + x * params['slope1'] model2 = params['offset'] + x * params['slope2'] resid1 = dat1 - model1 resid2 = dat2 - model2 return np.concatenate((resid1, resid2)) How can I fit complex data? =================================== As with working with multi-dimensional data, you need to convert your data and model (or the value returned by the objective function) to be double precision floating point numbers. The simplest approach is to use :numpydoc:`ndarray.view`, perhaps like:: import numpy as np def residual(params, x, data=None): .... resid = calculate_complex_residual() return resid.view(np.float) Can I constrain values to have integer values? =============================================== Basically, no. None of the minimizers in lmfit support integer programming. They all (I think) assume that they can make a very small change to a floating point value for a parameters value and see a change in the value to be minimized. How should I cite LMFIT? ================================== See http://dx.doi.org/10.5281/zenodo.11813 lmfit-0.9.7/doc/fitting.rst0000644000076500000240000005676413066042256016543 0ustar Newvillestaff00000000000000.. _minimize_chapter: .. module:: lmfit.minimizer ======================================= Performing Fits and Analyzing Outputs ======================================= As shown in the previous chapter, a simple fit can be performed with the :func:`minimize` function. For more sophisticated modeling, the :class:`Minimizer` class can be used to gain a bit more control, especially when using complicated constraints or comparing results from related fits. The :func:`minimize` function ============================= The :func:`minimize` function is a wrapper around :class:`Minimizer` for running an optimization problem. It takes an objective function (the function that calculates the array to be minimized), a :class:`Parameters` object, and several optional arguments. See :ref:`fit-func-label` for details on writing the objective. .. autofunction:: minimize .. _fit-func-label: Writing a Fitting Function =============================== An important component of a fit is writing a function to be minimized -- the *objective function*. Since this function will be called by other routines, there are fairly stringent requirements for its call signature and return value. In principle, your function can be any Python callable, but it must look like this: .. function:: func(params, *args, **kws): Calculate objective residual to be minimized from parameters. :param params: Parameters. :type params: :class:`~lmfit.parameter.Parameters` :param args: Positional arguments. Must match ``args`` argument to :func:`minimize`. :param kws: Keyword arguments. Must match ``kws`` argument to :func:`minimize`. :return: Residual array (generally data-model) to be minimized in the least-squares sense. :rtype: numpy.ndarray. The length of this array cannot change between calls. A common use for the positional and keyword arguments would be to pass in other data needed to calculate the residual, including things as the data array, dependent variable, uncertainties in the data, and other data structures for the model calculation. The objective function should return the value to be minimized. For the Levenberg-Marquardt algorithm from :meth:`leastsq`, this returned value **must** be an array, with a length greater than or equal to the number of fitting variables in the model. For the other methods, the return value can either be a scalar or an array. If an array is returned, the sum of squares of the array will be sent to the underlying fitting method, effectively doing a least-squares optimization of the return values. Since the function will be passed in a dictionary of :class:`Parameters`, it is advisable to unpack these to get numerical values at the top of the function. A simple way to do this is with :meth:`Parameters.valuesdict`, as shown below:: def residual(pars, x, data=None, eps=None): # unpack parameters: # extract .value attribute for each parameter parvals = pars.valuesdict() period = parvals['period'] shift = parvals['shift'] decay = parvals['decay'] if abs(shift) > pi/2: shift = shift - sign(shift)*pi if abs(period) < 1.e-10: period = sign(period)*1.e-10 model = parvals['amp'] * sin(shift + x/period) * exp(-x*x*decay*decay) if data is None: return model if eps is None: return (model - data) return (model - data)/eps In this example, `x` is a positional (required) argument, while the `data` array is actually optional (so that the function returns the model calculation if the data is neglected). Also note that the model calculation will divide `x` by the value of the ``period`` Parameter. It might be wise to ensure this parameter cannot be 0. It would be possible to use the bounds on the :class:`Parameter` to do this:: params['period'] = Parameter(value=2, min=1.e-10) but putting this directly in the function with:: if abs(period) < 1.e-10: period = sign(period)*1.e-10 is also a reasonable approach. Similarly, one could place bounds on the ``decay`` parameter to take values only between ``-pi/2`` and ``pi/2``. .. _fit-methods-label: Choosing Different Fitting Methods =========================================== By default, the `Levenberg-Marquardt `_ algorithm is used for fitting. While often criticized, including the fact it finds a *local* minima, this approach has some distinct advantages. These include being fast, and well-behaved for most curve-fitting needs, and making it easy to estimate uncertainties for and correlations between pairs of fit variables, as discussed in :ref:`fit-results-label`. Alternative algorithms can also be used by providing the ``method`` keyword to the :func:`minimize` function or :meth:`Minimizer.minimize` class as listed in the :ref:`Table of Supported Fitting Methods `. .. _fit-methods-table: Table of Supported Fitting Methods: +-----------------------+------------------------------------------------------------------+ | Fitting Method | ``method`` arg to :func:`minimize` or :meth:`Minimizer.minimize` | +=======================+==================================================================+ | Levenberg-Marquardt | ``leastsq`` or ``least_squares`` | +-----------------------+------------------------------------------------------------------+ | Nelder-Mead | ``nelder`` | +-----------------------+------------------------------------------------------------------+ | L-BFGS-B | ``lbfgsb`` | +-----------------------+------------------------------------------------------------------+ | Powell | ``powell`` | +-----------------------+------------------------------------------------------------------+ | Conjugate Gradient | ``cg`` | +-----------------------+------------------------------------------------------------------+ | Newton-CG | ``newton`` | +-----------------------+------------------------------------------------------------------+ | COBYLA | ``cobyla`` | +-----------------------+------------------------------------------------------------------+ | Truncated Newton | ``tnc`` | +-----------------------+------------------------------------------------------------------+ | Dogleg | ``dogleg`` | +-----------------------+------------------------------------------------------------------+ | Sequential Linear | ``slsqp`` | | Squares Programming | | +-----------------------+------------------------------------------------------------------+ | Differential | ``differential_evolution`` | | Evolution | | +-----------------------+------------------------------------------------------------------+ | Brute force method | ``brute`` | +-----------------------+------------------------------------------------------------------+ .. note:: The objective function for the Levenberg-Marquardt method **must** return an array, with more elements than variables. All other methods can return either a scalar value or an array. .. warning:: Much of this documentation assumes that the Levenberg-Marquardt method is used. Many of the fit statistics and estimates for uncertainties in parameters discussed in :ref:`fit-results-label` are done only for this method. .. _fit-results-label: :class:`MinimizerResult` -- the optimization result ======================================================== .. versionadded:: 0.9.0 An optimization with :func:`minimize` or :meth:`Minimizer.minimize` will return a :class:`MinimizerResult` object. This is an otherwise plain container object (that is, with no methods of its own) that simply holds the results of the minimization. These results will include several pieces of informational data such as status and error messages, fit statistics, and the updated parameters themselves. Importantly, the parameters passed in to :meth:`Minimizer.minimize` will be not be changed. To to find the best-fit values, uncertainties and so on for each parameter, one must use the :attr:`MinimizerResult.params` attribute. For example, to print the fitted values, bounds and other parameters attributes in a well formatted text tables you can execute:: result.params.pretty_print() with `results` being a `MinimizerResult` object. Note that the method :meth:`~lmfit.parameter.Parameters.pretty_print` accepts several arguments for customizing the output (e.g., column width, numeric format, etcetera). .. autoclass:: MinimizerResult Goodness-of-Fit Statistics ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. _goodfit-table: Table of Fit Results: These values, including the standard Goodness-of-Fit statistics, are all attributes of the :class:`MinimizerResult` object returned by :func:`minimize` or :meth:`Minimizer.minimize`. +----------------------+----------------------------------------------------------------------------+ | Attribute Name | Description / Formula | +======================+============================================================================+ | nfev | number of function evaluations | +----------------------+----------------------------------------------------------------------------+ | nvarys | number of variables in fit :math:`N_{\rm varys}` | +----------------------+----------------------------------------------------------------------------+ | ndata | number of data points: :math:`N` | +----------------------+----------------------------------------------------------------------------+ | nfree | degrees of freedom in fit: :math:`N - N_{\rm varys}` | +----------------------+----------------------------------------------------------------------------+ | residual | residual array, returned by the objective function: :math:`\{\rm Resid_i\}`| +----------------------+----------------------------------------------------------------------------+ | chisqr | chi-square: :math:`\chi^2 = \sum_i^N [{\rm Resid}_i]^2` | +----------------------+----------------------------------------------------------------------------+ | redchi | reduced chi-square: :math:`\chi^2_{\nu}= {\chi^2} / {(N - N_{\rm varys})}` | +----------------------+----------------------------------------------------------------------------+ | aic | Akaike Information Criterion statistic (see below) | +----------------------+----------------------------------------------------------------------------+ | bic | Bayesian Information Criterion statistic (see below) | +----------------------+----------------------------------------------------------------------------+ | var_names | ordered list of variable parameter names used for init_vals and covar | +----------------------+----------------------------------------------------------------------------+ | covar | covariance matrix (with rows/columns using var_names) | +----------------------+----------------------------------------------------------------------------+ | init_vals | list of initial values for variable parameters | +----------------------+----------------------------------------------------------------------------+ Note that the calculation of chi-square and reduced chi-square assume that the returned residual function is scaled properly to the uncertainties in the data. For these statistics to be meaningful, the person writing the function to be minimized **must** scale them properly. After a fit using using the :meth:`leastsq` method has completed successfully, standard errors for the fitted variables and correlations between pairs of fitted variables are automatically calculated from the covariance matrix. The standard error (estimated :math:`1\sigma` error-bar) goes into the :attr:`stderr` attribute of the Parameter. The correlations with all other variables will be put into the :attr:`correl` attribute of the Parameter -- a dictionary with keys for all other Parameters and values of the corresponding correlation. In some cases, it may not be possible to estimate the errors and correlations. For example, if a variable actually has no practical effect on the fit, it will likely cause the covariance matrix to be singular, making standard errors impossible to estimate. Placing bounds on varied Parameters makes it more likely that errors cannot be estimated, as being near the maximum or minimum value makes the covariance matrix singular. In these cases, the :attr:`errorbars` attribute of the fit result (:class:`Minimizer` object) will be ``False``. .. _information_criteria_label: Akaike and Bayesian Information Criteria ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The :class:`MinimizerResult` includes the traditional chi-square and reduced chi-square statistics: .. math:: :nowrap: \begin{eqnarray*} \chi^2 &=& \sum_i^N r_i^2 \\ \chi^2_\nu &=& = \chi^2 / (N-N_{\rm varys}) \end{eqnarray*} where :math:`r` is the residual array returned by the objective function (likely to be ``(data-model)/uncertainty`` for data modeling usages), :math:`N` is the number of data points (``ndata``), and :math:`N_{\rm varys}` is number of variable parameters. Also included are the `Akaike Information Criterion `_, and `Bayesian Information Criterion `_ statistics, held in the ``aic`` and ``bic`` attributes, respectively. These give slightly different measures of the relative quality for a fit, trying to balance quality of fit with the number of variable parameters used in the fit. These are calculated as: .. math:: :nowrap: \begin{eqnarray*} {\rm aic} &=& N \ln(\chi^2/N) + 2 N_{\rm varys} \\ {\rm bic} &=& N \ln(\chi^2/N) + \ln(N) N_{\rm varys} \\ \end{eqnarray*} When comparing fits with different numbers of varying parameters, one typically selects the model with lowest reduced chi-square, Akaike information criterion, and/or Bayesian information criterion. Generally, the Bayesian information criterion is considered the most conservative of these statistics. .. _fit-itercb-label: Using a Iteration Callback Function ==================================== An iteration callback function is a function to be called at each iteration, just after the objective function is called. The iteration callback allows user-supplied code to be run at each iteration, and can be used to abort a fit. .. function:: iter_cb(params, iter, resid, *args, **kws): User-supplied function to be run at each iteration. :param params: Parameters. :type params: :class:`~lmfit.parameter.Parameters` :param iter: Iteration number. :type iter: int :param resid: Residual array. :type resid: numpy.ndarray :param args: Positional arguments. Must match ``args`` argument to :func:`minimize` :param kws: Keyword arguments. Must match ``kws`` argument to :func:`minimize` :return: Residual array (generally data-model) to be minimized in the least-squares sense. :rtype: None for normal behavior, any value like True to abort the fit. Normally, the iteration callback would have no return value or return ``None``. To abort a fit, have this function return a value that is ``True`` (including any non-zero integer). The fit will also abort if any exception is raised in the iteration callback. When a fit is aborted this way, the parameters will have the values from the last iteration. The fit statistics are not likely to be meaningful, and uncertainties will not be computed. .. _fit-minimizer-label: Using the :class:`Minimizer` class ======================================= For full control of the fitting process, you will want to create a :class:`Minimizer` object. .. autoclass :: Minimizer The Minimizer object has a few public methods: .. automethod:: Minimizer.minimize .. automethod:: Minimizer.leastsq .. automethod:: Minimizer.least_squares .. automethod:: Minimizer.scalar_minimize .. automethod:: Minimizer.prepare_fit .. automethod:: Minimizer.brute For more information, check the examples in ``examples/lmfit_brute.py``. .. automethod:: Minimizer.emcee .. _label-emcee: :meth:`Minimizer.emcee` - calculating the posterior probability distribution of parameters ============================================================================================== :meth:`Minimizer.emcee` can be used to obtain the posterior probability distribution of parameters, given a set of experimental data. An example problem is a double exponential decay. A small amount of Gaussian noise is also added in:: >>> import numpy as np >>> import lmfit >>> import matplotlib.pyplot as plt >>> x = np.linspace(1, 10, 250) >>> np.random.seed(0) >>> y = 3.0 * np.exp(-x / 2) - 5.0 * np.exp(-(x - 0.1) / 10.) + 0.1 * np.random.randn(len(x)) >>> plt.plot(x, y) >>> plt.show() .. image:: _images/emcee_dbl_exp.png Create a Parameter set for the initial guesses:: >>> p = lmfit.Parameters() >>> p.add_many(('a1', 4.), ('a2', 4.), ('t1', 3.), ('t2', 3., True)) >>> def residual(p): ... v = p.valuesdict() ... return v['a1'] * np.exp(-x / v['t1']) + v['a2'] * np.exp(-(x - 0.1) / v['t2']) - y Solving with :func:`minimize` gives the Maximum Likelihood solution.:: >>> mi = lmfit.minimize(residual, p, method='Nelder') >>> lmfit.printfuncs.report_fit(mi.params, min_correl=0.5) [[Variables]] a1: 2.98623688 (init= 4) a2: -4.33525596 (init= 4) t1: 1.30993185 (init= 3) t2: 11.8240752 (init= 3) [[Correlations]] (unreported correlations are < 0.500) >>> plt.plot(x, y) >>> plt.plot(x, residual(mi.params) + y, 'r') >>> plt.show() .. image:: _images/emcee_dbl_exp2.png However, this doesn't give a probability distribution for the parameters. Furthermore, we wish to deal with the data uncertainty. This is called marginalisation of a nuisance parameter. ``emcee`` requires a function that returns the log-posterior probability. The log-posterior probability is a sum of the log-prior probability and log-likelihood functions. The log-prior probability is assumed to be zero if all the parameters are within their bounds and ``-np.inf`` if any of the parameters are outside their bounds. >>> # add a noise parameter >>> mi.params.add('f', value=1, min=0.001, max=2) >>> # This is the log-likelihood probability for the sampling. We're going to estimate the >>> # size of the uncertainties on the data as well. >>> def lnprob(p): ... resid = residual(p) ... s = p['f'] ... resid *= 1 / s ... resid *= resid ... resid += np.log(2 * np.pi * s**2) ... return -0.5 * np.sum(resid) Now we have to set up the minimizer and do the sampling:: >>> mini = lmfit.Minimizer(lnprob, mi.params) >>> res = mini.emcee(burn=300, steps=600, thin=10, params=mi.params) Lets have a look at those posterior distributions for the parameters. This requires installation of the `corner` package:: >>> import corner >>> corner.corner(res.flatchain, labels=res.var_names, truths=list(res.params.valuesdict().values())) .. image:: _images/emcee_triangle.png The values reported in the :class:`MinimizerResult` are the medians of the probability distributions and a 1 sigma quantile, estimated as half the difference between the 15.8 and 84.2 percentiles. The median value is not necessarily the same as the Maximum Likelihood Estimate. We'll get that as well. You can see that we recovered the right uncertainty level on the data.:: >>> print("median of posterior probability distribution") >>> print('------------------------------------------') >>> lmfit.report_fit(res.params) median of posterior probability distribution ------------------------------------------ [[Variables]] a1: 3.00975345 +/- 0.151034 (5.02%) (init= 2.986237) a2: -4.35419204 +/- 0.127505 (2.93%) (init=-4.335256) t1: 1.32726415 +/- 0.142995 (10.77%) (init= 1.309932) t2: 11.7911935 +/- 0.495583 (4.20%) (init= 11.82408) f: 0.09805494 +/- 0.004256 (4.34%) (init= 1) [[Correlations]] (unreported correlations are < 0.100) C(a2, t2) = 0.981 C(a2, t1) = -0.927 C(t1, t2) = -0.880 C(a1, t1) = -0.519 C(a1, a2) = 0.195 C(a1, t2) = 0.146 >>> # find the maximum likelihood solution >>> highest_prob = np.argmax(res.lnprob) >>> hp_loc = np.unravel_index(highest_prob, res.lnprob.shape) >>> mle_soln = res.chain[hp_loc] >>> for i, par in enumerate(p): ... p[par].value = mle_soln[i] >>> print("\nMaximum likelihood Estimation") >>> print('-----------------------------') >>> print(p) Maximum likelihood Estimation ----------------------------- Parameters([('a1', ), ('a2', ), ('t1', ), ('t2', )]) >>> # Finally lets work out a 1 and 2-sigma error estimate for 't1' >>> quantiles = np.percentile(res.flatchain['t1'], [2.28, 15.9, 50, 84.2, 97.7]) >>> print("2 sigma spread", 0.5 * (quantiles[-1] - quantiles[0])) 2 sigma spread 0.298878202908 Getting and Printing Fit Reports =========================================== .. currentmodule:: lmfit.printfuncs .. autofunction:: fit_report An example using this to write out a fit report would be: .. literalinclude:: ../examples/doc_withreport.py which would write out:: [[Fit Statistics]] # function evals = 85 # data points = 1001 # variables = 4 chi-square = 498.812 reduced chi-square = 0.500 Akaike info crit = -689.223 Bayesian info crit = -669.587 [[Variables]] amp: 13.9121944 +/- 0.141202 (1.01%) (init= 13) period: 5.48507044 +/- 0.026664 (0.49%) (init= 2) shift: 0.16203676 +/- 0.014056 (8.67%) (init= 0) decay: 0.03264538 +/- 0.000380 (1.16%) (init= 0.02) [[Correlations]] (unreported correlations are < 0.100) C(period, shift) = 0.797 C(amp, decay) = 0.582 C(amp, shift) = -0.297 C(amp, period) = -0.243 C(shift, decay) = -0.182 C(period, decay) = -0.150 lmfit-0.9.7/doc/index.rst0000644000076500000240000000533713066042256016174 0ustar Newvillestaff00000000000000.. lmfit documentation master file, Non-Linear Least-Squares Minimization and Curve-Fitting for Python =========================================================================== .. _Levenberg-Marquardt: http://en.wikipedia.org/wiki/Levenberg-Marquardt_algorithm .. _MINPACK-1: http://en.wikipedia.org/wiki/MINPACK .. _scipy.optimize: http://docs.scipy.org/doc/scipy/reference/optimize.html .. _lmfit github repository: http://github.com/lmfit/lmfit-py Lmfit provides a high-level interface to non-linear optimization and curve fitting problems for Python. It builds on and extends many of the optimization methods of `scipy.optimize`_. Initially inspired by (and named for) extending the `Levenberg-Marquardt`_ method from :scipydoc:`optimize.leastsq`, lmfit now provides a number of useful enhancements to optimization and data fitting problems, including: * Using :class:`~lmfit.parameter.Parameter` objects instead of plain floats as variables. A :class:`~lmfit.parameter.Parameter` has a value that can be varied during the fit or kept at a fixed value. It can have upper and/or lower bounds. A Parameter can even have a value that is constrained by an algebraic expression of other Parameter values. As a Python object, a Parameter can also have attributes such as a standard error, after a fit that can estimate uncertainties. * Ease of changing fitting algorithms. Once a fitting model is set up, one can change the fitting algorithm used to find the optimal solution without changing the objective function. * Improved estimation of confidence intervals. While :scipydoc:`optimize.leastsq` will automatically calculate uncertainties and correlations from the covariance matrix, the accuracy of these estimates is sometimes questionable. To help address this, lmfit has functions to explicitly explore parameter space and determine confidence levels even for the most difficult cases. * Improved curve-fitting with the :class:`~lmfit.model.Model` class. This extends the capabilities of :scipydoc:`optimize.curve_fit`, allowing you to turn a function that models your data into a Python class that helps you parametrize and fit data with that model. * Many :ref:`built-in models ` for common lineshapes are included and ready to use. The lmfit package is Free software, using an Open Source license. The software and this document are works in progress. If you are interested in participating in this effort please use the `lmfit github repository`_. .. toctree:: :maxdepth: 2 intro installation support faq parameters fitting model builtin_models confidence bounds constraints whatsnew lmfit-0.9.7/doc/installation.rst0000644000076500000240000000525113066042256017561 0ustar Newvillestaff00000000000000==================================== Downloading and Installation ==================================== .. _lmfit github repository: http://github.com/lmfit/lmfit-py .. _python: http://python.org .. _scipy: http://scipy.org/scipylib/index.html .. _numpy: http://numpy.org/ .. _nose: http://nose.readthedocs.org/ .. _pytest: http://pytest.org/ .. _emcee: http://dan.iel.fm/emcee/ .. _pandas: http://pandas.pydata.org/ .. _jupyter: http://jupyter.org/ .. _matplotlib: http://matplotlib.org/ Prerequisites ~~~~~~~~~~~~~~~ The lmfit package requires `Python`_, `NumPy`_, and `SciPy`_. Lmfit works with Python versions 2.7, 3.3, 3.4, 3.5, and 3.6. Support for Python 2.6 ended with lmfit version 0.9.4. Scipy version 0.15 or higher is required, with 0.17 or higher recommended to be able to use the latest optimization features. NumPy version 1.5.1 or higher is required. In order to run the test suite, either the `nose`_ or `pytest`_ package is required. Some functionality of lmfit requires the `emcee`_ package, some functionality will make use of the `pandas`_, `Jupyter`_ or `matplotlib`_ packages if available. We highly recommend each of these packages. Downloads ~~~~~~~~~~~~~ The latest stable version of lmfit is |release| is available from `PyPi `_. Installation ~~~~~~~~~~~~~~~~~ With ``pip`` now widely avaliable, you can install lmfit with:: pip install lmfit Alternatively, you can download the source kit, unpack it and install with:: python setup.py install For Anaconda Python, lmfit is not an official package, but several Anaconda channels provide it, allowing installation with (for example):: conda install -c conda-forge lmfit Development Version ~~~~~~~~~~~~~~~~~~~~~~~~ To get the latest development version, use:: git clone http://github.com/lmfit/lmfit-py.git and install using:: python setup.py install Testing ~~~~~~~~~~ A battery of tests scripts that can be run with either the `nose`_ or `pytest`_ testing framework is distributed with lmfit in the ``tests`` folder. These are automatically run as part of the development process. For any release or any master branch from the git repository, running ``pytest`` or ``nosetests`` should run all of these tests to completion without errors or failures. Many of the examples in this documentation are distributed with lmfit in the ``examples`` folder, and should also run for you. Some of these examples assume `matplotlib`_ has been installed and is working correctly. Acknowledgements ~~~~~~~~~~~~~~~~~~ .. literalinclude:: ../THANKS.txt License ~~~~~~~~~~~~~ The LMFIT-py code is distribution under the following license: .. literalinclude:: ../LICENSE lmfit-0.9.7/doc/intro.rst0000644000076500000240000001620513066042256016214 0ustar Newvillestaff00000000000000.. _intro_chapter: =========================================================== Getting started with Non-Linear Least-Squares Fitting =========================================================== The lmfit package provides simple tools to help you build complex fitting models for non-linear least-squares problems and apply these models to real data. This section gives an overview of the concepts and describes how to set up and perform simple fits. Some basic knowledge of Python, NumPy, and modeling data are assumed -- this is not a tutorial on why or how to perform a minimization or fit data, but is rather aimed at explaining how to use lmfit to do these things. In order to do a non-linear least-squares fit of a model to data or for any other optimization problem, the main task is to write an *objective function* that takes the values of the fitting variables and calculates either a scalar value to be minimized or an array of values that are to be minimized, typically in the least-squares sense. For many data fitting processes, the latter approach is used, and the objective function should return an array of (data-model), perhaps scaled by some weighting factor such as the inverse of the uncertainty in the data. For such a problem, the chi-square (:math:`\chi^2`) statistic is often defined as: .. math:: \chi^2 = \sum_i^{N} \frac{[y^{\rm meas}_i - y_i^{\rm model}({\bf{v}})]^2}{\epsilon_i^2} where :math:`y_i^{\rm meas}` is the set of measured data, :math:`y_i^{\rm model}({\bf{v}})` is the model calculation, :math:`{\bf{v}}` is the set of variables in the model to be optimized in the fit, and :math:`\epsilon_i` is the estimated uncertainty in the data. In a traditional non-linear fit, one writes an objective function that takes the variable values and calculates the residual array :math:`y^{\rm meas}_i - y_i^{\rm model}({\bf{v}})`, or the residual array scaled by the data uncertainties, :math:`[y^{\rm meas}_i - y_i^{\rm model}({\bf{v}})]/{\epsilon_i}`, or some other weighting factor. As a simple concrete example, one might want to model data with a decaying sine wave, and so write an objective function like this:: def residual(vars, x, data, eps_data): amp = vars[0] phaseshift = vars[1] freq = vars[2] decay = vars[3] model = amp * sin(x * freq + phaseshift) * exp(-x*x*decay) return (data-model)/eps_data To perform the minimization with :mod:`scipy.optimize`, one would do this:: from scipy.optimize import leastsq vars = [10.0, 0.2, 3.0, 0.007] out = leastsq(residual, vars, args=(x, data, eps_data)) Though it is wonderful to be able to use Python for such optimization problems, and the scipy library is robust and easy to use, the approach here is not terribly different from how one would do the same fit in C or Fortran. There are several practical challenges to using this approach, including: a) The user has to keep track of the order of the variables, and their meaning -- vars[0] is the amplitude, vars[2] is the frequency, and so on, although there is no intrinsic meaning to this order. b) If the user wants to fix a particular variable (*not* vary it in the fit), the residual function has to be altered to have fewer variables, and have the corresponding constant value passed in some other way. While reasonable for simple cases, this quickly becomes a significant work for more complex models, and greatly complicates modeling for people not intimately familiar with the details of the fitting code. c) There is no simple, robust way to put bounds on values for the variables, or enforce mathematical relationships between the variables. In fact, the optimization methods that do provide bounds, require bounds to be set for all variables with separate arrays that are in the same arbitrary order as variable values. Again, this is acceptable for small or one-off cases, but becomes painful if the fitting model needs to change. These shortcomings are due to the use of traditional arrays to hold the variables, which matches closely the implementation of the underlying Fortran code, but does not fit very well with Python's rich selection of objects and data structures. The key concept in lmfit is to define and use :class:`Parameter` objects instead of plain floating point numbers as the variables for the fit. Using :class:`Parameter` objects (or the closely related :class:`Parameters` -- a dictionary of :class:`Parameter` objects), allows one to: a) forget about the order of variables and refer to Parameters by meaningful names. b) place bounds on Parameters as attributes, without worrying about preserving the order of arrays for variables and boundaries. c) fix Parameters, without having to rewrite the objective function. d) place algebraic constraints on Parameters. To illustrate the value of this approach, we can rewrite the above example for the decaying sine wave as:: from lmfit import minimize, Parameters def residual(params, x, data, eps_data): amp = params['amp'] pshift = params['phase'] freq = params['frequency'] decay = params['decay'] model = amp * sin(x * freq + pshift) * exp(-x*x*decay) return (data-model)/eps_data params = Parameters() params.add('amp', value=10) params.add('decay', value=0.007) params.add('phase', value=0.2) params.add('frequency', value=3.0) out = minimize(residual, params, args=(x, data, eps_data)) At first look, we simply replaced a list of values with a dictionary, accessed by name -- not a huge improvement. But each of the named :class:`Parameter` in the :class:`Parameters` object holds additional attributes to modify the value during the fit. For example, Parameters can be fixed or bounded. This can be done during definition:: params = Parameters() params.add('amp', value=10, vary=False) params.add('decay', value=0.007, min=0.0) params.add('phase', value=0.2) params.add('frequency', value=3.0, max=10) where ``vary=False`` will prevent the value from changing in the fit, and ``min=0.0`` will set a lower bound on that parameter's value. It can also be done later by setting the corresponding attributes after they have been created:: params['amp'].vary = False params['decay'].min = 0.10 Importantly, our objective function remains unchanged. This means the objective function can simply express the parameterized phenomenon to be modeled, and is separate from the choice of parameters to be varied in the fit. The `params` object can be copied and modified to make many user-level changes to the model and fitting process. Of course, most of the information about how your data is modeled goes into the objective function, but the approach here allows some external control; that is, control by the **user** performing the fit, instead of by the author of the objective function. Finally, in addition to the :class:`Parameters` approach to fitting data, lmfit allows switching optimization methods without changing the objective function, provides tools for generating fitting reports, and provides a better determination of Parameters confidence levels. lmfit-0.9.7/doc/Makefile0000644000076500000240000000722013066042256015764 0ustar Newvillestaff00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build INSTALLDIR = /home/newville/public_html/lmfit/ # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest latexpdf htmlzip .PHONY: all install pdf html: cp sphinx/ext_mathjax.py extensions.py $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "html build finished: $(BUILDDIR)/html." htmlzip: html cp sphinx/ext_pngmath.py extensions.py $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/lmfit_doc cd $(BUILDDIR) && zip -pur html/lmfit_doc.zip lmfit_doc epub: cp sphinx/ext_pngmath.py extensions.py $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub cp -pr $(BUILDDIR)/epub/*.epub $(BUILDDIR)/html/. pdf: latex cd $(BUILDDIR)/latex && make all-pdf cp -pr $(BUILDDIR)/latex/lmfit.pdf $(BUILDDIR)/html/. all: html htmlzip epub pdf install: all cd $(BUILDDIR)/latex && pdflatex lmfit.tex cd $(BUILDDIR)/latex && makeindex -s python.ist lmfit.idx cd $(BUILDDIR)/latex && pdflatex lmfit.tex cp -pr $(BUILDDIR)/html/* $(INSTALLDIR)/. help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo "Running LaTeX files through pdflatex..." make -C _build/latex all-pdf @echo "pdflatex finished; the PDF files are in _build/latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." lmfit-0.9.7/doc/model.rst0000644000076500000240000010060713066042256016161 0ustar Newvillestaff00000000000000.. _model_chapter: ================================================= Modeling Data and Curve Fitting ================================================= .. module:: lmfit.model A common use of least-squares minimization is *curve fitting*, where one has a parametrized model function meant to explain some phenomena and wants to adjust the numerical values for the model so that it most closely matches some data. With :mod:`scipy`, such problems are typically solved with :scipydoc:`optimize.curve_fit`, which is a wrapper around :scipydoc:`optimize.leastsq`. Since lmfit's :func:`~lmfit.minimizer.minimize` is also a high-level wrapper around :scipydoc:`optimize.leastsq` it can be used for curve-fitting problems. While it offers many benefits over :scipydoc:`optimize.leastsq`, using :func:`~lmfit.minimizer.minimize` for many curve-fitting problems still requires more effort than using :scipydoc:`optimize.curve_fit`. The :class:`Model` class in lmfit provides a simple and flexible approach to curve-fitting problems. Like :scipydoc:`optimize.curve_fit`, a :class:`Model` uses a *model function* -- a function that is meant to calculate a model for some phenomenon -- and then uses that to best match an array of supplied data. Beyond that similarity, its interface is rather different from :scipydoc:`optimize.curve_fit`, for example in that it uses :class:`~lmfit.parameter.Parameters`, but also offers several other important advantages. In addition to allowing you to turn any model function into a curve-fitting method, lmfit also provides canonical definitions for many known line shapes such as Gaussian or Lorentzian peaks and Exponential decays that are widely used in many scientific domains. These are available in the :mod:`models` module that will be discussed in more detail in the next chapter (:ref:`builtin_models_chapter`). We mention it here as you may want to consult that list before writing your own model. For now, we focus on turning Python functions into high-level fitting models with the :class:`Model` class, and using these to fit data. Motivation and simple example: Fit data to Gaussian profile ============================================================= Let's start with a simple and common example of fitting data to a Gaussian peak. As we will see, there is a buit-in :class:`GaussianModel` class that can help do this, but here we'll build our own. We start with a simple definition of the model function: >>> from numpy import sqrt, pi, exp, linspace, random >>> >>> def gaussian(x, amp, cen, wid): ... return amp * exp(-(x-cen)**2 /wid) We want to use this function to fit to data :math:`y(x)` represented by the arrays `y` and `x`. With :scipydoc:`optimize.curve_fit`, this would be:: >>> from scipy.optimize import curve_fit >>> >>> x = linspace(-10,10, 101) >>> y = gaussian(x, 2.33, 0.21, 1.51) + random.normal(0, 0.2, len(x)) >>> >>> init_vals = [1, 0, 1] # for [amp, cen, wid] >>> best_vals, covar = curve_fit(gaussian, x, y, p0=init_vals) >>> print best_vals That is, we create data, make an initial guess of the model values, and run :scipydoc:`optimize.curve_fit` with the model function, data arrays, and initial guesses. The results returned are the optimal values for the parameters and the covariance matrix. It's simple and useful, but it misses the benefits of lmfit. With lmfit, we create a :class:`Model` that wraps the `gaussian` model function, which automatically generates the appropriate residual function, and determines the corresponding parameter names from the function signature itself:: >>> from lmfit import Model >>> gmodel = Model(gaussian) >>> gmodel.param_names set(['amp', 'wid', 'cen']) >>> gmodel.independent_vars ['x'] As you can see, the Model `gmodel` determined the names of the parameters and the independent variables. By default, the first argument of the function is taken as the independent variable, held in :attr:`independent_vars`, and the rest of the functions positional arguments (and, in certain cases, keyword arguments -- see below) are used for Parameter names. Thus, for the `gaussian` function above, the independent variable is `x`, and the parameters are named `amp`, `cen`, and `wid`, and -- all taken directly from the signature of the model function. As we will see below, you can modify the default assignment of independent variable / arguments and specify yourself what the independent variable is and which function arguments should be identified as parameter names. The Parameters are *not* created when the model is created. The model knows what the parameters should be named, but not anything about the scale and range of your data. You will normally have to make these parameters and assign initial values and other attributes. To help you do this, each model has a :meth:`make_params` method that will generate parameters with the expected names: >>> params = gmod.make_params() This creates the :class:`~lmfit.parameter.Parameters` but does not automaticaly give them initial values since it has no idea what the scale should be. You can set initial values for parameters with keyword arguments to :meth:`make_params`: >>> params = gmod.make_params(cen=5, amp=200, wid=1) or assign them (and other parameter properties) after the :class:`~lmfit.parameter.Parameters` class has been created. A :class:`Model` has several methods associated with it. For example, one can use the :meth:`eval` method to evaluate the model or the :meth:`fit` method to fit data to this model with a :class:`Parameter` object. Both of these methods can take explicit keyword arguments for the parameter values. For example, one could use :meth:`eval` to calculate the predicted function:: >>> x = linspace(0, 10, 201) >>> y = gmod.eval(params, x=x) or with:: >>> y = gmod.eval(x=x, cen=6.5, amp=100, wid=2.0) Admittedly, this a slightly long-winded way to calculate a Gaussian function, given that you could have called your `gaussian` function directly. But now that the model is set up, we can use its :meth:`fit` method to fit this model to data, as with:: >>> result = gmod.fit(y, params) or with:: >>> result = gmod.fit(y, cen=6.5, amp=100, wid=2.0) Putting everything together, (included in the ``examples`` folder with the source code) is: .. literalinclude:: ../examples/doc_model1.py which is pretty compact and to the point. The returned `result` will be a :class:`ModelResult` object. As we will see below, this has many components, including a :meth:`fit_report` method, which will show:: [[Model]] Model(gaussian) [[Fit Statistics]] # function evals = 31 # data points = 101 # variables = 3 chi-square = 3.409 reduced chi-square = 0.035 Akaike info crit = -336.264 Bayesian info crit = -328.418 [[Variables]] amp: 5.07800631 +/- 0.064957 (1.28%) (init= 5) cen: 5.65866112 +/- 0.010304 (0.18%) (init= 5) wid: 0.97344373 +/- 0.028756 (2.95%) (init= 1) [[Correlations]] (unreported correlations are < 0.100) C(amp, wid) = -0.577 As the script shows, the result will also have :attr:`init_fit` for the fit with the initial parameter values and a :attr:`best_fit` for the fit with the best fit parameter values. These can be used to generate the following plot: .. image:: _images/model_fit1.png :target: _images/model_fit1.png :width: 50% which shows the data in blue dots, the best fit as a solid red line, and the initial fit as a dashed black line. Note that the model fitting was really performed with:: gmodel = Model(gaussian) result = gmodel.fit(y, params, x=x, amp=5, cen=5, wid=1) These lines clearly express that we want to turn the `gaussian` function into a fitting model, and then fit the :math:`y(x)` data to this model, starting with values of 5 for `amp`, 5 for `cen` and 1 for `wid`. In addition, all the other features of lmfit are included: :class:`~lmfit.parameter.Parameters` can have bounds and constraints and the result is a rich object that can be reused to explore the model fit in detail. The :class:`Model` class ======================================= The :class:`Model` class provides a general way to wrap a pre-defined function as a fitting model. .. autoclass:: Model :class:`Model` class Methods --------------------------------- .. automethod:: Model.eval .. automethod:: Model.fit .. automethod:: Model.guess .. automethod:: Model.make_params .. automethod:: Model.set_param_hint See :ref:`model_param_hints_section`. .. automethod:: Model.print_param_hints :class:`Model` class Attributes --------------------------------- .. attribute:: func The model function used to calculate the model. .. attribute:: independent_vars List of strings for names of the independent variables. .. attribute:: missing Describes what to do for missing values. The choices are: * None: Do not check for null or missing values (default). * 'none': Do not check for null or missing values. * 'drop': Drop null or missing observations in data. If pandas is installed, :func:`pandas.isnull` is used, otherwise :func:`numpy.isnan` is used. * 'raise': Raise a (more helpful) exception when data contains null or missing values. .. attribute:: name Name of the model, used only in the string representation of the model. By default this will be taken from the model function. .. attribute:: opts Extra keyword arguments to pass to model function. Normally this will be determined internally and should not be changed. .. attribute:: param_hints Dictionary of parameter hints. See :ref:`model_param_hints_section`. .. attribute:: param_names List of strings of parameter names. .. attribute:: prefix Prefix used for name-mangling of parameter names. The default is ''. If a particular :class:`Model` has arguments `amplitude`, `center`, and `sigma`, these would become the parameter names. Using a prefix of `'g1_'` would convert these parameter names to `g1_amplitude`, `g1_center`, and `g1_sigma`. This can be essential to avoid name collision in composite models. Determining parameter names and independent variables for a function ----------------------------------------------------------------------- The :class:`Model` created from the supplied function `func` will create a :class:`~lmfit.parameter.Parameters` object, and names are inferred from the function arguments, and a residual function is automatically constructed. By default, the independent variable is take as the first argument to the function. You can, of course, explicitly set this, and will need to do so if the independent variable is not first in the list, or if there are actually more than one independent variables. If not specified, Parameters are constructed from all positional arguments and all keyword arguments that have a default value that is numerical, except the independent variable, of course. Importantly, the Parameters can be modified after creation. In fact, you will have to do this because none of the parameters have valid initial values. In addition, one can place bounds and constraints on Parameters, or fix their values. Explicitly specifying ``independent_vars`` ------------------------------------------------- As we saw for the Gaussian example above, creating a :class:`Model` from a function is fairly easy. Let's try another one:: >>> from lmfit import Model >>> import numpy as np >>> def decay(t, tau, N): ... return N*np.exp(-t/tau) ... >>> decay_model = Model(decay) >>> print decay_model.independent_vars ['t'] >>> for pname, par in decay_model.params.items(): ... print pname, par ... tau N Here, `t` is assumed to be the independent variable because it is the first argument to the function. The other function arguments are used to create parameters for the model. If you want `tau` to be the independent variable in the above example, you can say so:: >>> decay_model = Model(decay, independent_vars=['tau']) >>> print decay_model.independent_vars ['tau'] >>> for pname, par in decay_model.params.items(): ... print pname, par ... t N You can also supply multiple values for multi-dimensional functions with multiple independent variables. In fact, the meaning of *independent variable* here is simple, and based on how it treats arguments of the function you are modeling: independent variable A function argument that is not a parameter or otherwise part of the model, and that will be required to be explicitly provided as a keyword argument for each fit with :meth:`Model.fit` or evaluation with :meth:`Model.eval`. Note that independent variables are not required to be arrays, or even floating point numbers. Functions with keyword arguments ----------------------------------------- If the model function had keyword parameters, these would be turned into Parameters if the supplied default value was a valid number (but not None, True, or False). >>> def decay2(t, tau, N=10, check_positive=False): ... if check_small: ... arg = abs(t)/max(1.e-9, abs(tau)) ... else: ... arg = t/tau ... return N*np.exp(arg) ... >>> mod = Model(decay2) >>> for pname, par in mod.params.items(): ... print pname, par ... t N Here, even though `N` is a keyword argument to the function, it is turned into a parameter, with the default numerical value as its initial value. By default, it is permitted to be varied in the fit -- the 10 is taken as an initial value, not a fixed value. On the other hand, the `check_positive` keyword argument, was not converted to a parameter because it has a boolean default value. In some sense, `check_positive` becomes like an independent variable to the model. However, because it has a default value it is not required to be given for each model evaluation or fit, as independent variables are. Defining a `prefix` for the Parameters -------------------------------------------- As we will see in the next chapter when combining models, it is sometimes necessary to decorate the parameter names in the model, but still have them be correctly used in the underlying model function. This would be necessary, for example, if two parameters in a composite model (see :ref:`composite_models_section` or examples in the next chapter) would have the same name. To avoid this, we can add a `prefix` to the :class:`Model` which will automatically do this mapping for us. >>> def myfunc(x, amplitude=1, center=0, sigma=1): ... >>> mod = Model(myfunc, prefix='f1_') >>> for pname, par in mod.params.items(): ... print pname, par ... f1_amplitude f1_center f1_sigma You would refer to these parameters as `f1_amplitude` and so forth, and the model will know to map these to the `amplitude` argument of `myfunc`. Initializing model parameters -------------------------------- As mentioned above, the parameters created by :meth:`Model.make_params` are generally created with invalid initial values of None. These values **must** be initialized in order for the model to be evaluated or used in a fit. There are four different ways to do this initialization that can be used in any combination: 1. You can supply initial values in the definition of the model function. 2. You can initialize the parameters when creating parameters with :meth:`Model.make_params`. 3. You can give parameter hints with :meth:`Model.set_param_hint`. 4. You can supply initial values for the parameters when you use the :meth:`Model.eval` or :meth:`Model.fit` methods. Of course these methods can be mixed, allowing you to overwrite initial values at any point in the process of defining and using the model. Initializing values in the function definition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To supply initial values for parameters in the definition of the model function, you can simply supply a default value:: >>> def myfunc(x, a=1, b=0): >>> ... instead of using:: >>> def myfunc(x, a, b): >>> ... This has the advantage of working at the function level -- all parameters with keywords can be treated as options. It also means that some default initial value will always be available for the parameter. Initializing values with :meth:`Model.make_params` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When creating parameters with :meth:`Model.make_params` you can specify initial values. To do this, use keyword arguments for the parameter names and initial values:: >>> mod = Model(myfunc) >>> pars = mod.make_params(a=3, b=0.5) Initializing values by setting parameter hints ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After a model has been created, but prior to creating parameters with :meth:`Model.make_params`, you can set parameter hints. These allows you to set not only a default initial value but also to set other parameter attributes controlling bounds, whether it is varied in the fit, or a constraint expression. To set a parameter hint, you can use :meth:`Model.set_param_hint`, as with:: >>> mod = Model(myfunc) >>> mod.set_param_hint('a', value = 1.0) >>> mod.set_param_hint('b', value = 0.3, min=0, max=1.0) >>> pars = mod.make_params() Parameter hints are discussed in more detail in section :ref:`model_param_hints_section`. Initializing values when using a model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Finally, you can explicitly supply initial values when using a model. That is, as with :meth:`Model.make_params`, you can include values as keyword arguments to either the :meth:`Model.eval` or :meth:`Model.fit` methods:: >>> y1 = mod.eval(x=x, a=7.0, b=-2.0) >>> out = mod.fit(x=x, pars, a=3.0, b=-0.0) These approaches to initialization provide many opportunities for setting initial values for parameters. The methods can be combined, so that you can set parameter hints but then change the initial value explicitly with :meth:`Model.fit`. .. _model_param_hints_section: Using parameter hints -------------------------------- After a model has been created, you can give it hints for how to create parameters with :meth:`Model.make_params`. This allows you to set not only a default initial value but also to set other parameter attributes controlling bounds, whether it is varied in the fit, or a constraint expression. To set a parameter hint, you can use :meth:`Model.set_param_hint`, as with:: >>> mod = Model(myfunc) >>> mod.set_param_hint('a', value = 1.0) >>> mod.set_param_hint('b', value = 0.3, min=0, max=1.0) Parameter hints are stored in a model's :attr:`param_hints` attribute, which is simply a nested dictionary:: >>> print mod.param_hints {'a': {'value': 1}, 'b': {'max': 1.0, 'value': 0.3, 'min': 0}} You can change this dictionary directly, or with the :meth:`Model.set_param_hint` method. Either way, these parameter hints are used by :meth:`Model.make_params` when making parameters. An important feature of parameter hints is that you can force the creation of new parameters with parameter hints. This can be useful to make derived parameters with constraint expressions. For example to get the full-width at half maximum of a Gaussian model, one could use a parameter hint of:: >>> mod = Model(gaussian) >>> mod.set_param_hint('fwhm', expr='2.3548*sigma') The :class:`ModelResult` class ======================================= A :class:`ModelResult` (which had been called `ModelFit` prior to version 0.9) is the object returned by :meth:`Model.fit`. It is a subclass of :class:`~lmfit.minimizer.Minimizer`, and so contains many of the fit results. Of course, it knows the :class:`Model` and the set of :class:`~lmfit.parameter.Parameters` used in the fit, and it has methods to evaluate the model, to fit the data (or re-fit the data with changes to the parameters, or fit with different or modified data) and to print out a report for that fit. While a :class:`Model` encapsulates your model function, it is fairly abstract and does not contain the parameters or data used in a particular fit. A :class:`ModelResult` *does* contain parameters and data as well as methods to alter and re-do fits. Thus the :class:`Model` is the idealized model while the :class:`ModelResult` is the messier, more complex (but perhaps more useful) object that represents a fit with a set of parameters to data with a model. A :class:`ModelResult` has several attributes holding values for fit results, and several methods for working with fits. These include statistics inherited from :class:`~lmfit.minimizer.Minimizer` useful for comparing different models, including `chisqr`, `redchi`, `aic`, and `bic`. .. autoclass:: ModelResult :class:`ModelResult` methods --------------------------------- .. automethod:: ModelResult.eval .. automethod:: ModelResult.eval_components .. automethod:: ModelResult.fit .. automethod:: ModelResult.fit_report .. automethod:: ModelResult.conf_interval .. automethod:: ModelResult.ci_report .. automethod:: ModelResult.eval_uncertainty .. automethod:: ModelResult.plot .. automethod:: ModelResult.plot_fit .. automethod:: ModelResult.plot_residuals :class:`ModelResult` attributes --------------------------------- .. attribute:: aic Floating point best-fit Akaike Information Criterion statistic (see :ref:`fit-results-label`). .. attribute:: best_fit numpy.ndarray result of model function, evaluated at provided independent variables and with best-fit parameters. .. attribute:: best_values Dictionary with parameter names as keys, and best-fit values as values. .. attribute:: bic Floating point best-fit Bayesian Information Criterion statistic (see :ref:`fit-results-label`). .. attribute:: chisqr Floating point best-fit chi-square statistic (see :ref:`fit-results-label`). .. attribute:: ci_out Confidence interval data (see :ref:`confidence_chapter`) or None if the confidence intervals have not been calculated. .. attribute:: covar numpy.ndarray (square) covariance matrix returned from fit. .. attribute:: data numpy.ndarray of data to compare to model. .. attribute:: errorbars Boolean for whether error bars were estimated by fit. .. attribute:: ier Integer returned code from :scipydoc:`optimize.leastsq`. .. attribute:: init_fit numpy.ndarray result of model function, evaluated at provided independent variables and with initial parameters. .. attribute:: init_params Initial parameters. .. attribute:: init_values Dictionary with parameter names as keys, and initial values as values. .. attribute:: iter_cb Optional callable function, to be called at each fit iteration. This must take take arguments of ``(params, iter, resid, *args, **kws)``, where `params` will have the current parameter values, `iter` the iteration, `resid` the current residual array, and `*args` and `**kws` as passed to the objective function. See :ref:`fit-itercb-label`. .. attribute:: jacfcn Optional callable function, to be called to calculate Jacobian array. .. attribute:: lmdif_message String message returned from :scipydoc:`optimize.leastsq`. .. attribute:: message String message returned from :func:`~lmfit.minimizer.minimize`. .. attribute:: method String naming fitting method for :func:`~lmfit.minimizer.minimize`. .. attribute:: model Instance of :class:`Model` used for model. .. attribute:: ndata Integer number of data points. .. attribute:: nfev Integer number of function evaluations used for fit. .. attribute:: nfree Integer number of free parameters in fit. .. attribute:: nvarys Integer number of independent, freely varying variables in fit. .. attribute:: params Parameters used in fit. Will have best-fit values. .. attribute:: redchi Floating point reduced chi-square statistic (see :ref:`fit-results-label`). .. attribute:: residual numpy.ndarray for residual. .. attribute:: scale_covar Boolean flag for whether to automatically scale covariance matrix. .. attribute:: success Boolean value of whether fit succeeded. .. attribute:: weights numpy.ndarray (or None) of weighting values to be used in fit. If not None, it will be used as a multiplicative factor of the residual array, so that ``weights*(data - fit)`` is minimized in the least-squares sense. Calculating uncertainties in the model function ------------------------------------------------- We return to the first example above and ask not only for the uncertainties in the fitted parameters but for the range of values that those uncertainties mean for the model function itself. We can use the :meth:`ModelResult.eval_uncertainty` method of the model result object to evaluate the uncertainty in the model with a specified level for :math:`sigma`. That is, adding:: dely = result.eval_uncertainty(sigma=3) plt.fill_between(x, result.best_fit-dely, result.best_fit+dely, color="#ABABAB") to the example fit to the Gaussian at the beginning of this chapter will give :math:`3-sigma` bands for the best-fit Gaussian, and produce the figure below. .. _figModel4: .. image:: _images/model_fit4.png :target: _images/model_fit4.png :width: 50% .. index:: Composite models .. _composite_models_section: Composite Models : adding (or multiplying) Models ============================================================== One of the more interesting features of the :class:`Model` class is that Models can be added together or combined with basic algebraic operations (add, subtract, multiply, and divide) to give a composite model. The composite model will have parameters from each of the component models, with all parameters being available to influence the whole model. This ability to combine models will become even more useful in the next chapter, when pre-built subclasses of :class:`Model` are discussed. For now, we'll consider a simple example, and build a model of a Gaussian plus a line, as to model a peak with a background. For such a simple problem, we could just build a model that included both components:: def gaussian_plus_line(x, amp, cen, wid, slope, intercept): "line + 1-d gaussian" gauss = (amp/(sqrt(2*pi)*wid)) * exp(-(x-cen)**2 /(2*wid**2)) line = slope * x + intercept return gauss + line and use that with:: mod = Model(gaussian_plus_line) But we already had a function for a gaussian function, and maybe we'll discover that a linear background isn't sufficient which would mean the model function would have to be changed. Instead, lmfit allows models to be combined into a :class:`CompositeModel`. As an alternative to including a linear background in our model function, we could define a linear function:: def line(x, slope, intercept): "a line" return slope * x + intercept and build a composite model with just:: mod = Model(gaussian) + Model(line) This model has parameters for both component models, and can be used as: .. literalinclude:: ../examples/doc_model2.py which prints out the results:: [[Model]] (Model(gaussian) + Model(line)) [[Fit Statistics]] # function evals = 44 # data points = 101 # variables = 5 chi-square = 2.579 reduced chi-square = 0.027 Akaike info crit = -360.457 Bayesian info crit = -347.381 [[Variables]] amp: 8.45931061 +/- 0.124145 (1.47%) (init= 5) cen: 5.65547872 +/- 0.009176 (0.16%) (init= 5) intercept: -0.96860201 +/- 0.033522 (3.46%) (init= 1) slope: 0.26484403 +/- 0.005748 (2.17%) (init= 0) wid: 0.67545523 +/- 0.009916 (1.47%) (init= 1) [[Correlations]] (unreported correlations are < 0.100) C(amp, wid) = 0.666 C(cen, intercept) = 0.129 and shows the plot on the left. .. _figModel2: .. image:: _images/model_fit2.png :target: _images/model_fit2.png :width: 48% .. image:: _images/model_fit2a.png :target: _images/model_fit2a.png :width: 48% On the left, data is shown in blue dots, the total fit is shown in solid red line, and the initial fit is shown as a black dashed line. In the figure on the right, the data is again shown in blue dots, and the Gaussian component shown as a black dashed line, and the linear component shown as a red dashed line. These components were generated after the fit using the Models :meth:`ModelResult.eval_components` method of the `result`:: comps = result.eval_components() which returns a dictionary of the components, using keys of the model name (or `prefix` if that is set). This will use the parameter values in `result.params` and the independent variables (`x`) used during the fit. Note that while the :class:`ModelResult` held in `result` does store the best parameters and the best estimate of the model in `result.best_fit`, the original model and parameters in `pars` are left unaltered. You can apply this composite model to other data sets, or evaluate the model at other values of `x`. You may want to do this to give a finer or coarser spacing of data point, or to extrapolate the model outside the fitting range. This can be done with:: xwide = np.linspace(-5, 25, 3001) predicted = mod.eval(x=xwide) In this example, the argument names for the model functions do not overlap. If they had, the `prefix` argument to :class:`Model` would have allowed us to identify which parameter went with which component model. As we will see in the next chapter, using composite models with the built-in models provides a simple way to build up complex models. .. autoclass:: CompositeModel(left, right, op[, **kws]) Note that when using builtin Python binary operators, a :class:`CompositeModel` will automatically be constructed for you. That is, doing:: mod = Model(fcn1) + Model(fcn2) * Model(fcn3) will create a :class:`CompositeModel`. Here, `left` will be `Model(fcn1)`, `op` will be :meth:`operator.add`, and `right` will be another CompositeModel that has a `left` attribute of `Model(fcn2)`, an `op` of :meth:`operator.mul`, and a `right` of `Model(fcn3)`. To use a binary operator other than '+', '-', '*', or '/' you can explicitly create a :class:`CompositeModel` with the appropriate binary operator. For example, to convolve two models, you could define a simple convolution function, perhaps as:: import numpy as np def convolve(dat, kernel): # simple convolution npts = min(len(dat), len(kernel)) pad = np.ones(npts) tmp = np.concatenate((pad*dat[0], dat, pad*dat[-1])) out = np.convolve(tmp, kernel, mode='valid') noff = int((len(out) - npts)/2) return (out[noff:])[:npts] which extends the data in both directions so that the convolving kernel function gives a valid result over the data range. Because this function takes two array arguments and returns an array, it can be used as the binary operator. A full script using this technique is here: .. literalinclude:: ../examples/doc_model3.py which prints out the results:: [[Model]] (Model(jump) Model(gaussian)) [[Fit Statistics]] # function evals = 27 # data points = 201 # variables = 3 chi-square = 22.091 reduced chi-square = 0.112 Akaike info crit = -437.837 Bayesian info crit = -427.927 [[Variables]] mid: 5 (fixed) sigma: 0.64118585 +/- 0.013233 (2.06%) (init= 1.5) center: 4.51633608 +/- 0.009567 (0.21%) (init= 3.5) amplitude: 0.62654849 +/- 0.001813 (0.29%) (init= 1) [[Correlations]] (unreported correlations are < 0.100) C(center, amplitude) = 0.344 C(sigma, amplitude) = 0.280 and shows the plots: .. _figModel3: .. image:: _images/model_fit3a.png :target: _images/model_fit3a.png :width: 48% .. image:: _images/model_fit3b.png :target: _images/model_fit3b.png :width: 48% Using composite models with built-in or custom operators allows you to build complex models from testable sub-components. lmfit-0.9.7/doc/parameters.rst0000644000076500000240000000734413066042256017230 0ustar Newvillestaff00000000000000.. _parameters_chapter: .. module:: lmfit.parameter ================================================ :class:`Parameter` and :class:`Parameters` ================================================ This chapter describes the :class:`Parameter` object, which is a key concept of lmfit. A :class:`Parameter` is the quantity to be optimized in all minimization problems, replacing the plain floating point number used in the optimization routines from :mod:`scipy.optimize`. A :class:`Parameter` has a value that can either be varied in the fit or held at a fixed value, and can have upper and/or lower bounds placed on the value. It can even have a value that is constrained by an algebraic expression of other Parameter values. Since :class:`Parameter` objects live outside the core optimization routines, they can be used in **all** optimization routines from :mod:`scipy.optimize`. By using :class:`Parameter` objects instead of plain variables, the objective function does not have to be modified to reflect every change of what is varied in the fit, or whether bounds can be applied. This simplifies the writing of models, allowing general models that describe the phenomenon and gives the user more flexibility in using and testing variations of that model. Whereas a :class:`Parameter` expands on an individual floating point variable, the optimization methods actually still need an ordered group of floating point variables. In the :mod:`scipy.optimize` routines this is required to be a one-dimensional :numpydoc:`ndarray`. In lmfit, this one-dimensional array is replaced by a :class:`Parameters` object, which works as an ordered dictionary of :class:`Parameter` objects with a few additional features and methods. That is, while the concept of a :class:`Parameter` is central to lmfit, one normally creates and interacts with a :class:`Parameters` instance that contains many :class:`Parameter` objects. For example, the objective functions you write for lmfit will take an instance of :class:`Parameters` as its first argument. A table of parameter values, bounds and other attributes can be printed using :meth:`Parameters.pretty_print`. The :class:`Parameter` class ======================================== .. autoclass:: Parameter See :ref:`bounds_chapter` for details on the math used to implement the bounds with :attr:`min` and :attr:`max`. The :attr:`expr` attribute can contain a mathematical expression that will be used to compute the value for the Parameter at each step in the fit. See :ref:`constraints_chapter` for more details and examples of this feature. .. index:: Removing a Constraint Expression .. automethod:: set The :class:`Parameters` class ======================================== .. autoclass:: Parameters .. automethod:: add .. automethod:: add_many .. automethod:: pretty_print .. automethod:: valuesdict .. automethod:: dumps .. automethod:: dump .. automethod:: loads .. automethod:: load Simple Example ================== A basic example making use of :class:`~lmfit.parameter.Parameters` and the :func:`~lmfit.minimizer.minimize` function (discussed in the next chapter) might look like this: .. literalinclude:: ../examples/doc_basic.py Here, the objective function explicitly unpacks each Parameter value. This can be simplified using the :class:`Parameters` :meth:`valuesdict` method, which would make the objective function ``fcn2min`` above look like:: def fcn2min(params, x, data): """ model decaying sine wave, subtract data""" v = params.valuesdict() model = v['amp'] * np.sin(x * v['omega'] + v['shift']) * np.exp(-x*x*v['decay']) return model - data The results are identical, and the difference is a stylistic choice. lmfit-0.9.7/doc/sphinx/0000755000076500000240000000000013114357470015635 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/sphinx/ext_mathjax.py0000644000076500000240000000044113066042256020521 0ustar Newvillestaff00000000000000# sphinx extensions for mathjax extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.intersphinx', 'sphinx.ext.extlinks', 'sphinx.ext.napoleon', 'sphinx.ext.mathjax'] lmfit-0.9.7/doc/sphinx/ext_pngmath.py0000644000076500000240000000044113066042256020523 0ustar Newvillestaff00000000000000# sphinx extensions for pngmath extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.intersphinx', 'sphinx.ext.extlinks', 'sphinx.ext.napoleon', 'sphinx.ext.pngmath'] lmfit-0.9.7/doc/sphinx/theme/0000755000076500000240000000000013114357470016737 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/sphinx/theme/lmfitdoc/0000755000076500000240000000000013114357470020540 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/sphinx/theme/lmfitdoc/layout.html0000644000076500000240000000421013066042256022737 0ustar Newvillestaff00000000000000{# sphinxdoc/layout.html ~~~~~~~~~~~~~~~~~~~~~ Sphinx layout template for the sphinxdoc theme. :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details. #} {%- extends "basic/layout.html" %} {%- block extrahead %} {% endblock %} {% block rootrellink %}

  • [intro|
  • parameters|
  • minimize|
  • model|
  • built-in models|
  • confidence intervals|
  • bounds|
  • constraints]
  • {% endblock %} {% block relbar1 %} {{ super() }} {% endblock %} {# put the sidebar before the body #} {% block sidebar1 %}{{ sidebar() }}{% endblock %} {% block sidebar2 %}{% endblock %} lmfit-0.9.7/doc/sphinx/theme/lmfitdoc/static/0000755000076500000240000000000013114357470022027 5ustar Newvillestaff00000000000000lmfit-0.9.7/doc/sphinx/theme/lmfitdoc/static/contents.png0000644000076500000240000000031213066042256024365 0ustar Newvillestaff00000000000000PNG  IHDR(?wsRGB pHYs  tIME 7C{tEXtCommentCreated with GIMPW7IDATץ9 Z^']x.$@Z[!8EȞ-oÝo\KIENDB`lmfit-0.9.7/doc/sphinx/theme/lmfitdoc/static/lmfitdoc.css_t0000644000076500000240000001446313066042256024674 0ustar Newvillestaff00000000000000/* * lmfitdoc.css_t * minor riff on sphinxdoc.css_t * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Sphinx stylesheet -- sphinxdoc theme. Originally created by * Armin Ronacher for Werkzeug. * * :copyright: Copyright 2007-2014 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("basic.css"); /* -- page layout ----------------------------------------------------------- */ body { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; font-size: 14px; letter-spacing: -0.01em; line-height: 150%; text-align: center; background-color: #D6DAC4; color: black; padding: 0; border: 0px solid #D0D0C0; margin: 15px 15px 15px 15px; min-width: 740px; } div.document { background-color: white; text-align: left; background-image: url(contents.png); background-repeat: repeat-x; } div.bodywrapper { margin: 0 {{ theme_sidebarwidth|toint + 10 }}px 0 0; border-right: 1px solid #ccc; } div.body { margin: 0; padding: 0.5em 20px 20px 20px; } div.related { font-size: 1em; background-color: #0D0; } div.related ul { height: 2em; border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; background-color: #F0EFE4; color: #157; } div.related ul li { margin: 0; padding: 0; height: 2em; float: left; background-color: #D0000; } div.related ul li.right { float: right; margin-right: 5px; } div.related ul li a { margin: 0; padding: 0 5px 0 5px; line-height: 1.75em; color: #EE9816; color: #157; } div.related ul li a:hover { color: #822; } div.sphinxsidebarwrapper { padding: 0; } div.sphinxsidebar { margin: 0; padding: 0.5em 15px 15px 0; width: {{ theme_sidebarwidth|toint - 20 }}px; float: right; font-size: 1em; text-align: left; } div.sphinxsidebar h3, div.sphinxsidebar h4 { margin: 1em 0 0.5em 0; font-size: 1em; padding: 0.1em 0 0.1em 0.5em; color: #157; border: 1px solid #A0A090; background-color: #D0D0C4; } div.sphinxsidebar h3 a { color: #157; background-color: #D0D0C4; } div.sphinxsidebar ul { padding-left: 1.5em; margin-top: 7px; padding: 0; line-height: 130%; } div.sphinxsidebar ul ul { margin-left: 20px; } div.footer { background-color: #E0E8D4; color: #86989B; padding: 3px 8px 3px 0; clear: both; font-size: 0.8em; text-align: right; } div.footer a { color: #86989B; text-decoration: underline; } /* -- body styles ----------------------------------------------------------- */ p { margin: 0.8em 0 0.5em 0; } a { color: #CA7900; text-decoration: none; } a:hover { color: #2491CF; } div.body a { text-decoration: underline; } h1 { padding: 0.2em 0 0.2em 0; margin: 0.7em 0 0.3em 0; font-size: 1.5em; color: #157; background-color: #F0EFE4; } h2 { padding: 0.2em 0 0.2em 0; margin: 1.3em 0 0.2em 0; font-size: 1.35em; padding: 0; background-color: #FAFAF0; } h3 { padding: 0.2em 0 0.2em 0; margin: 1em 0 -0.3em 0; font-size: 1.2em; background-color: #FBFBF3; } div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { color: black!important; } h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { display: none; margin: 0 0 0 0.3em; padding: 0 0.2em 0 0.2em; color: #aaa!important; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { display: inline; } h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, h5 a.anchor:hover, h6 a.anchor:hover { color: #777; background-color: #eee; } a.headerlink { color: #c60f0f!important; font-size: 1em; margin-left: 6px; padding: 0 4px 0 4px; text-decoration: none!important; } a.headerlink:hover { background-color: #ccc; color: white!important; } cite, code, tt { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; } tt { background-color: #f2f2f2; border-bottom: 1px solid #ddd; color: #333; } tt.descname, tt.descclassname, tt.xref { border: 0; } hr { border: 1px solid #abc; margin: 2em; } a tt { border: 0; color: #CA7900; } a tt:hover { color: #2491CF; } pre { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; line-height: 120%; padding: 0.5em; border: 1px solid #ccc; background-color: #f8f8f8; } pre a { color: inherit; text-decoration: underline; } td.linenos pre { padding: 0.5em 0; } div.quotebar { background-color: #f8f8f8; max-width: 250px; float: right; padding: 2px 7px; border: 1px solid #ccc; } div.topic { background-color: #f8f8f8; } table { border-collapse: collapse; margin: 0 -0.5em 0 -0.5em; } table td, table th { padding: 0.2em 0.5em 0.2em 0.5em; } div.admonition, div.warning { font-size: 0.9em; margin: 1em 0 1em 0; border: 1px solid #86989B; background-color: #f7f7f7; padding: 0; } div.admonition p, div.warning p { margin: 0.5em 1em 0.5em 1em; padding: 0; } div.admonition pre, div.warning pre { margin: 0.4em 1em 0.4em 1em; } div.admonition p.admonition-title, div.warning p.admonition-title { margin: 0; padding: 0.1em 0 0.1em 0.5em; color: white; border-bottom: 1px solid #86989B; font-weight: bold; background-color: #AFC1C4; } div.warning { border: 1px solid #940000; } div.warning p.admonition-title { background-color: #CF0000; border-bottom-color: #940000; } div.admonition ul, div.admonition ol, div.warning ul, div.warning ol { margin: 0.1em 0.5em 0.5em 3em; padding: 0; } div.versioninfo { margin: 1em 0 0 0; border: 1px solid #ccc; background-color: #DDEAF0; padding: 8px; line-height: 1.3em; font-size: 0.9em; } .viewcode-back { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; } div.viewcode-block:target { background-color: #f4debf; border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; } lmfit-0.9.7/doc/sphinx/theme/lmfitdoc/static/navigation.png0000644000076500000240000000033213066042256024671 0ustar Newvillestaff00000000000000PNG  IHDR<sRGB pHYs  tIME y݉tEXtCommentCreated with GIMPWGIDATӽ0 OBt~8qg*m, 0{,Bt6o.q\Y~t7"LIENDB`lmfit-0.9.7/doc/sphinx/theme/lmfitdoc/theme.conf0000644000076500000240000000011413066042256022504 0ustar Newvillestaff00000000000000[theme] inherit = basic stylesheet = lmfitdoc.css pygments_style = friendly lmfit-0.9.7/doc/support.rst0000644000076500000240000000277713066042256016606 0ustar Newvillestaff00000000000000.. _support_chapter: =========================== Getting Help =========================== .. _mailing list: https://groups.google.com/group/lmfit-py .. _github issues: https://github.com/lmfit/lmfit-py/issues If you have questions, comments, or suggestions for LMFIT, please use the `mailing list`_. This provides an on-line conversation that is and archived well and can be searched well with standard web searches. If you find a bug in the code or documentation, use `GitHub Issues`_ to submit a report. If you have an idea for how to solve the problem and are familiar with Python and GitHub, submitting a GitHub Pull Request would be greatly appreciated. If you are unsure whether to use the mailing list or the Issue tracker, please start a conversation on the `mailing list`_. That is, the problem you're having may or may not be due to a bug. If it is due to a bug, creating an Issue from the conversation is easy. If it is not a bug, the problem will be discussed and then the Issue will be closed. While one *can* search through closed Issues on github, these are not so easily searched, and the conversation is not easily useful to others later. Starting the conversation on the mailing list with "How do I do this?" or "Why didn't this work?" instead of "This should work and doesn't" is generally preferred, and will better help others with similar questions. Of course, there is not always an obvious way to decide if something is a Question or an Issue, and we will try our best to engage in all discussions. lmfit-0.9.7/doc/test_ci2_result.png0000644000076500000240000051645313066042256020161 0ustar Newvillestaff00000000000000PNG  IHDR$7sBIT|d pHYsaa?i IDATxy\, PV.fYfzŃl}̲J;vL˓IX1-$(+(k dV^ۍ5̼7ޛbXB!B!BB!B!IB!B&W!B!DH+B!"IB!B$ !B!i|B!B4 B!B!B_!B!!MB!B&W!B!DH+B!"IB!B$ !B!i|B!B4 B!B!B_!B!!MB!B&W!B!DH+B!"IB!B$ !B!i|B!B4 B!B!B_!B!!MB!B&W!B!DH+B!"IB!B$ !B!i|B!B ?8-[Do夤9wK)B!"M:t(֭#!!>ϟGaҥ޽X&MR !B!4FSݺu+wT;v,vӾǏ~EDFFVyyD߿>}РAF꣨n. . 8]&z"??x㄄>lFo1b(D@?>wa#QTWR Rު!|u:lPæ=zjV^Abs1K.SXRHaI!._ڽ&NlX/;ϨFѡq'f5~xMv#Yuk28|0N#L>g(1,)[iju1۫RƪQ2z>TgʕiӦNj\jj*OtuNqQ{j/?/]#3Pnmu+J}2^yߋY/]wQTR@1_MDܟ&иVcjHzԍKȺMͰu{,{~Y_y?P{C]&oU!'e}bL0XөSgfо}{Ν07pCxǫl/L8xD7n󲉲2y|S~=+ ݙ|dN'UKB!&Κ5'=ׯEz}CK I*/w%C9U#ʨ0ⲳIKK#++o¿¨7Un/娎, v.ٕra ^11.WqJKo c>P%1›}{>rw\}[ҷP/7͹ߏ"U   ^:5Ď;r딐B!BTWϚiꑫmmۓii.VZk) K.a`@IT@ jxEl. W74ـUzW^q)$k r74n+B!D5!7@ԍMj7a1[.RH= ?M`RI,ĄB!Eow}8c'd|;,ã>K_壄B!f$-zH#<wq^֡,Ytw&;KB!H?]v9|9ڒ18" !B!@oYOov} ?MdI5j8B!B?isw%Ÿ8{鬿t6~HIwqB!~$7@t:_.:͋^wqlbЦaIG!Bg|X|tO._*'"5;;u[ћ2{vԼ\Uk˖Lbbꫯhٲ%O=M4aĉ<Pz/Uo W\*|U$܏:rfebӉℜ86@||<+W=޿p}믿R\ՅbyyhEAiUw{_+n-X1B+sh `pz /[hȍ* B Cb>ʵ赏8!QF2o</^L\\]W.>}MNN3fp{駟2h \^MT{6'ҟ<`5V1xlQcU[5Eu!uwҮ]2[nb8=}v6cRNўKlUKZ|WAthn_k=_wq|nl=uàw(ƬY5j'O&::9s0abccIOON:̞=PRRB;w=f3sε]$`j)5W y.'1O~>.j< 1}OjW|9VΦN}޽2|~sӵk[JdpGsG\}UCoaA,ܾ7Ox,Ia ]5Ғذa'ׯsz|OxCC Q$P%sDVE&rz+zC` ՑEgzucȡ9+Vзo_:ĬY39q?4ʺ) Uݳg#GĉDGGgѦM&Nȗ_~I5']wJ= cΖ9l>Ԧ97lk#ͽ(BJ޲oEʮUohLx%R_iCx,릌+NX¯*NǧNk;2},\p #%fo7o:;n_QYA|Ex/^̨Qشi>6mbΜ9ܹ5k`ƍǯR{GhP /Vwʆ)$O_뻨B(+j8wݵ9^w7mP]g7W{ܹ:>sQEWR.W-^ϸq1nCI\ {q=%+4W]4<33P 7nv 4hSfMN:E\\_MF{×;oׅawqBFFvN>҈A轂벗& ,Bbܠzuf{}cʑB8)"h]/ Z#&zh5kիM4`ԨQN6#鹷| K2N'V8٤IAT -}>Nt|1BY}[p$] î!Nǩr%spmuz^(?u@+SƌYFQ 5tL#C;h<ى1[q ozgG¯tm."bŹsEn$:, uM8:6fE!|lm(B+ e޲q.r_S݅_]g5}af_())I&\tӧO?c;:ÞO ea"[^$W׬盒?t=3FyE¯ !@qO{跏ΏBs E֣wboE T{0G˱[bGX׶¦8~4_ڵkSF ;F^0O 2LǩpYv}+K p6lqq1[lnݺ̛7 .x{1Ê_4cԵX@TY[򈈨ԩSmaÆL2~ tWݶ,Juk\}ԳNof(y̠_l1h"A{B:{r[בI\fJuS<rE͛74h@׮])((gkgԩ 8}gݴUq~EuS:ƽcǎDGG=k2HHP}C^NNuMYu&7kԎ ZՎ>n:=mwQ28ޜG37*ji3m+ +Ba؏(.6qZjŴi';;$.^ȱcǸ馛2rYG-w+{R\\LXX3f0yd:I\{hïR`JjgՕvw`\*D c Ҿ5k5[|7E ⪋gqf_Unf`e׍MT/v!O?{nFARRvO>yqN6$/mUgQ\ZK.E)m=lvYf1n8^x~mjժhٳ鈰X[ƻuc_Ȭ!r\:o~wQ*bί2H9 i+Jfwv(,|}~ȑ#$%%QRRB~8x 0z_@9/M=l"m^3p@~mt:QQQ\|K[.VVpSZ>EY$7tlܑ:uXEYcH!.A"CoY.dlW[Ճ^oF0bD<Ŭ]˗+3]w 333fc˦]+ci׮/_lQ^Z}^$u5^ܹidwwu pZ^¯wcÁ &n[Ĩ!Θ1ccԨQN?GyK{nbcc4iz4rrrؾ};Ǐ7\+'v؁z?q"g[Z}F+Ŵ^-~ؑxbILL$==L22SPp{S)uNoXY1Qͭ+[}܊`(3s]Sم_a2RϪ !{|w\:.Jm9l~VPP@VV#F`РA8p\XwߑJR2mرc?$++'|Ҷƍ} + \ i9܅@)/I],Ѩ/7QN8}`ʔ6^-V<]Q}b( u̚5 b^yUbcrY ^g۶ :{J岎A&%/"Tm} ܺXQQUuxsh鏑CtgƇ~D-2`¬?eqk6x`]O-OGR|WQKoߍb8yO}wQ8i^bq ʕ+moOfѣ~;/_&//DqiӦ/2ױ * 4SY*Ejvv6ii_\I],z!Jn<~dt:iɖ-[1 Lݾ};+ZEK+.cpHS<83 MLy-^{m2z=@^H(tw^kf[?[S+WZ+C:9tNwQ<&o z]jQF2o</^L\\IO>dgg3l҈b۶mlڴ P.DUqzЫu׎8q{}bݺ*Pj{j[xͷ0L V:wba|s:] \ՌspX6KnF3S&f3~ '. B(wr:Wݞ˞J[@Yh5+k֒X@6-4hEfbԨQL 1x,_#S~JIIJ%%&b]o\7>{iî" !nd]5jǺyH#kpw.JJJbÆ N'Nh_~{qFz+#37CK[y ̰aCyLjfɒ%L<1h ӝJh0'^sxW(/_@n7p9x`,˖@ $ Irpd"?{YF8>o`<( M-vyN7kJ@oh +Qqߏ.G:N㦄]!c7-(ߟ:f3QF1{l>۷]v 2aW`QŴ㸸N֙ͼ[kW:W_l7+k+o9)&3^&~E8)]Wm曕f||OѣGG7GzPO;MtՊ!3~C a㻓s" .J)K/^!qo.hkQ p?pAs O?ҼysVX Ҍr 4X0a ,bp]J\j ]ɎЭ[*bSKx< 2W9a"s#J@1 ~{7Ǝ}&Mbg9~ 7b^3eӎʹ>>C{1*_ $nX%)ߚ5nК(B z ?Rzn6C>7:)2fb] $:pAN\<&o G(B2Bz t:.f-ZcۧQ#b{3pmիba͚5,[˼#lgݝUQ@CFe4Mkג_:ع3pQ,zKWy<_,< M6.?3ӹٳKY1hH |C\Vk=A9 a릋s^ P{lm6ﯬ}YV-t:˗/;g޽j NGSn݈޻_dO.hZ| bĈ 4k [j ê;lWkiX!I]!,w8kCoNLfUzF5kFSw6jvN.6ĉ< L(m~,{.]Df×z6Z/ZzA-u:nI&M@߾)NŐҦU]|7*+c~E0舭Ϊ=z\_(5[b"%c:8C HJapJ*P( :Z18ū7MhڴmsNG||<$&V;wҰaCNNN-Zޣe˖.wm>|8Çޗ;h"Lftz[|7[FQu222Ȱvi?FͲEn& [rѡקg.ԩS]0 |BOƿ5Wз=ZeR``@"nrI i"αU1 LfΞȑshQn?LAy|y7cbe;Ջs"E%ywrVߞ]:ǝJ,F^}5ǎyK,X`&{fh[~{k[~UK j&z_f͚СC\?m4RSS}\Jи/{*_\6]׿~^(! lu`q/dzz:f1cz3sf&'22¶DXb%O>"/4W˸qϲmNfϞ :Ҋpc#ݜ/!ʅtuCg-WuG' :{gOh…9vQ&g;rzGWM g vmb]0 E}U̻fd]LNI tt-[ < Œp.,cr5j.&h:qafe* B~~>K$$$ЩS'RRI#F ;;m:Rgvqoq]]!$ݥ4S5;^sg:jD1}v8o3K0 df%*6ӧLӦ4~mۉ'%%ԃJ@.6BuR"i|^%xl.} u= @v"n9z IIIlذiĉzl޼iC,ݵŰX,?ѩ]!| 38)w-^BP`n aaLd̐܈O>YŐ!׳hѓ$%o=>ǎR -M㪎% Z+ઽs %FQ ˜'NMzLN mo+c}66:E}5ͰsZ5 \0$DCЮ ~砮n:J/O&~/H2u`墳|EϓRpn]!|{6>VB6 ޖ-ϝa7W.tF=\QfpR d["-* v](Bc~]Y"oE/@Np}2Ly>t\ٯK3ݞ5۳[kmCB!LGq0k _poEԑ۳.9LX)jBj{v?D.:tFE)w6bz {k^%%0ChѢFO֭W%K6qUOP#La= Qoc>Sj"8OrzRW3WU %P&< Qjw34 EI+ UY]:@Px ޙ W!*~hx:(D|_~!33^- 7ˏR`XO퉎wQ17z@ iI|6cIfp?xBr+ޠc2{|U jmF&*uwPb[+Y9At@x2uy8 hZgTt{ḫd}2kDZQk,Te/u$ݞZ|}] ɓ'9vÆ W{$̒FI7gQ3n8Bi0bb8qy"8}Z\l hh' K`ؑ 7C4-I걓hOŠzC>GN<ߵ2T[UJ_7_~zn}%l#^*c;k,:u*ӦM#;;3gоQ{fcs"G p{K.$''ӹsgvr˗BRRܹsz=:tSNtԉăЫb0l nQuN~? p̶BodNNB3J}(.mݝ]H 7+O| K;_NNS,/ho^гREMewgwP0Cf"[lwW/yqd#6k> ԯ_^zDGK7W_jHYb~6PfΘ1ccԨQN?GyK{nbcc4i>֭cl޼]w'7ͲE޽َch}Y#6?nsSGe*szG`(4î+0ٕzh^F(هNգ+0mh2VfC~~m{1mn>'4H 7ھ Aoɰ"{~. շ-ٺu+zbԨQ]5kCѻwoohۨ-Nqc݁uEr bĈ 4kw}Gjj*III; }}\Mp)r IDATYp!afuJL0k[ !6 _ޛ*ں8w:>Vxpq!QΪhX`u6,["o (3ll$9S@l ,yFBBl6^۳gOf3r &MfMƏOLLݶÇ3|z>P .+(C/(5/1!Dpԭ [{U. ӧO{zЩډc~ !O9rA+3#=JZ @2v]Nv+&).z2N/i(h꫖Mvt(7"uR;.ko*=@ :Uhձscex=߿!_T-i޼9/^d̘1<_riHMMbX9wK^P^P.cpXz@+(3&8$\]fggV;UYC. (  bÆ ݼ.V4S}ٝsJ7 V$:չQ˧N6moɓ|0 nКv ’BirM; ݝlxJO=ﷻ޼ysj֬ɣ>ڵk} bCYAse\c=ncMQ&JvWM u]ub>^).k'EiOe yo_T.Vn+)#dƯ_YW%uRZ_ݝu(0ŕ(̩۳Y=ς̐!C8v 2O>W/6lR;657YFHMMe޼y,^8\}!;;f̘a{wi.^Tf3_~eߵvh97C(P'.[T#JpnJE6ju ݰ%*8+iz\Ǟg.VAl+ WOR%M YUU`¾.ZPꢧWgvW;%_HMxcdeeٺKՋѣG%.߽6׶JlXl3k,FɓfΜ9L0XөSgfо}{Ν ]HOOGQRRBZZ|? ֓Xcì?_ʅJ"(k8 k.UA«9fl]s_Qpxei"c~E_od}5vwӾ#Ǻx]9ݞ~qD_~Np l*zaLҫs >jٍ\}H}* \|\b{Wm]*.^K}< P#.:Lc~(-a (aEW1!zN*,^uUKcXO}J;_ѭ0+w_UpEـr}_Ή?NW&:bQ~˫QW_PꙄ_o 2X?"7oٯ(攨mUZm,Κ5q1ݛ>W/ZmI1;m>쓅'_+BD^PnN쳓ng9VӖ^m 2¯z(z+ ]-PUb/% _S؊oy2ï*=vzVU|rmc2xw/}q z)~jV|EЫxD9EBo *Pp&`y Njh5&Ji^z#(.g<%WSՇ_]UںYR:HYƌĉ@RLR ߎF|xBk ԄRn8 DEx''-ͷKzY`H(zAS BCp3]Uc]8B[ aa0Phd!ۓ,"B "kPoM/C8ȡ"'M* VLNfRF^#G*GG@k % &|ÝK.gPII,۾*;oc9 MEr B`yy)xchxsݰiA@3|.8^bocGaH U?b(RثCgU_g~/A[+xw&z A,P OiR=I&d99T_^E&#V5 |W2sLOnn.fbܸq2g#= 솗vi`6_JOO~,2iҵEO{vcMUl<&RCh%s\rHʹAݮl֖!x6**K` ̢V2-UME|z)fϞr|ٲQ#`Uy"|ױަ!D/TLP+Q4o3^px p'dк,#Պ^cOw! 8oNEؕ [D !1+v %< ̈́W|_ ~6UN{ƿt?:~^Zbe_4EAH_.cgsѸ{7K:Q` r 5ܑQZNf^&W^k둭^>E %z@ME=q&|O?'f(.3D ^m<8 BCi>D>glƾ>Z@¸V+\9-4`ȰpmK1-e "~z_Vv[: K4kX/!Qj}RH +w`*"~}A3L> R*3?Z5TKA Dᘛ=UiO[#9 JlUfs6ؐ 0OXkͩ韵r@*DۦȯM}סnbͮ8(jGY(-Ce}͛p9qJZ$)j(~A;ꗪ5 qů~Ѳuny*DN^0r7h^T]w/*@v;رclْz>}x=?--~B"##ҦARLy>y\ӹeAOI[4ھ]Fr8|4~R*-=-"$9.r09*=F}tѫt٧^B R6( g6txUHew]`0ZsM1WA /^BSfcMƈՐ`H{FM6ʯ8fC T)|uu11ukRwʔ){~,]4֯_e˖ѬYXTIN̏+;fS%EfgTo Bͩou|,zD_2矿Y볲 )ڄsqלWPon-q td"C͚V7LőKB{{--$**ĉ8qPZٵcIķXd K,q9VXXH DgfuvbL)BRRg^Y#.lOf hAj^:^}Mz^+4-#P);1u[CS lZ&I9p옍?.[K|+(f' ߶D5 h_rHNmՄ6EèЫڣ-OAC%3{`‚)/gq{BEWR39tt_w6+-"..#G:UE}Νʼ"62fderUϫ=5ĺO87ofРcL Dc"^fv 2n0d}GPJUZkW4Rsj&zABS[ H\+>Ӱw3ǣii9qM(.VQ<•ַ( (ӻ3aؾ %XvZQ`Qį: #U? Pv-_M[O(1Ayap5oeL(h W pg'Zspa>|ݎlF)Enn.qqq.]˗;%''矓,c1L^93/Z20^iwz+}y?^VYܾ9Pj13ދ[=\{mw2O? דF+mx"9T*z:C̘qЊ`P[JL&^I—u1cW_XqQv{_} @į`B"kp;Zʗ6oVi{͚Cs~>]ʪU(1hiWTuBRu=r9:6@111 8wyK[)w%77{w^~w^HIWᛑUtYBk.Nbb"l۶y˗/wٓ뮻J̜9^f{C]-ADa mQfg._ziWXxC,aOؚEDD֍&e-~'!pͯo]hkB 3?Νo| wqChVVg:W_\ok Κ_Ǧ{c~PPPrԩr&Laús,[g!v|(hlCg=Dx^ >t4)5pB.\Hbb"s7c…Uؕ(? .z,f̘AZZZsN:ɓٹs';vd._7ҥK1܉=10KwTb]MDBf<X,fڴi_ϥpl6caf3}gznaOIKߏZƮ*zGa n4}_<[14c*L{‚0ׁJv;;y{ڵ=۶#66v8@LLkƍbECJ۠<$'5 *"~,Eaa)ouQQ+|uPlSQ.BXzsDI(ᇵɤ:ٓuU:>k,l؝"):bk1{ ҭu/veg[6O~mW*Viyj&L`ڴidggdYXҳgONe]Ɯ9s8s ?K.eĈ |\kL6H3ja_'-Jf㏟fĈ53sW_K+>>e-#<ԩSܹO[*UX ^U ٗsV" */OIIy>}:ϻyRMp({UƱ]q=Jԥzsoׁ TtIO}c+oӧKׯw=}'%WM^ f޼yyX+ ~Acb}.~{ 5h,R/2Zpqo&FPnk&_gs LWE 'l6:!bK% N =<v4#"|q:Et"y$y\x_vVtZZJrJrss?Xuj׮ʺ{:Pƹ]QMEgG; lzj IDAT#6=rtf0[ݮinE)m+Eu<_8&@'C+w }>op4nb/W?/^ep}>ve{_nyChⷡv;?/65ࠡXw&~dcy睟 \}Ϲ23r Bx0bN8/_7w_w`9􃑺/=1L$EOLBm UX;ݷos6|l޼]=8W\kƕW^YK {fV"xk!zvDgfJɲ2&͎n''0k.r Z2ū75 [fu%p}QLuMƣu:@'G m0]wx] Zk}?qF9Enŋ?%0kIeKJ RڳٌoW#:ND+[错canq0gΔKqp!O?}&Ke O?@d9Y\BDK*~NYqx6>Z`윑ARtkZE}̘1l޼,mڂ wO?4pVXܹ3+VÍѫWkQ^U-"g I<שG&%%XKZDpunzĉnSZZ[o}_KDux^TT )xܬc,M/ +>sů:h!Kb_PhE~~ V?[<Yhɷ#ӣWwNn ^ec2v0XvvÆȞ=Z%+|0˭a1&Ŵ(z\ge.Ez6NDo]i:(T)z.kE>JчurJ{naQAڵ+rhmV+++WЭ[W~q9m۶`ᡇc܅ 2 >/T"NrMnNat-6] ݹ}XMQ`1xUHg`/ְm6nA:9c9T5 f͚_(cqms!n\ ~TDCo ?_$J%-Kݫv+;`~iOhx|>n8ƍWm{C+wkouX&HM=cǎ 6JVw_f=Wo?2v=QzDnT9+@)$}Q/lS16[:55-8aQTteMWgڟt_(//gs^ЖO|x^~// bFhW\=tÄ^ʽ"C$_73)С6;[1`&.VJݜW)Ob "+Gzn+oeǶ|kq Htؙ:ɘø ǑG7D 2&|wMٶ }e=ѫ6w22bGÆᣏަ}v[sW29!| ֭[ҜRhp?}zr)*^}"uL!+ӛ*D{xUÊ_@K8a r#aa!bwL~5ѣo !+ۃ$$te5QXZJ+O 7$cHw] l(qM7O\ &m\StܑwޙOr%vfpAĭ0N`_Zt *$Lu_ VF kyAךy0"zn}"?xe :+((d͚hn"O&x隿nTՙAwb\"q"w)FP6L hgO۷":3f/E 䪫2lH5x?38vcAN{wc;F GlؐI\tޙ;sY~ lڔAHH\RyNӼysBCBx ;¢"19_ 9^5 +Wy kKLxת5KmFK 8> RhF мys{x֭ {defҤ[iͽrm$de&7{PQ}#ÖD:"z~Kdq]fÈl- mg4RDŽkfJ9Y#5kF^^>~7x)zu IK/!}ٵbYe8*ǁ W,_ϔxkWj;w82jBl6V;wbX?>zYB(++֭[\X,lظݵǍnaXt+*;8 ̰c^oxD _^f~+VڬޯL&"44͛sHjLx F1MrV+k׮cРLz'%%y bK>JWSQAhhhXwV:5j|tԚfQw1c$,,?ro,aҤۜWk.u,V+{&qQ'ʘl\S*2ψsF^w 98f/E>ƫ/s-YfǡCZ;v"`N[r3D6[$2guœ݇.twk]0xů#8uZe⺇(x. uhؖԩ`Xᇵ\tkbju+0)pG%V&$;=kHN+\Ɠ2a{qҾ vSik`G-|(O3}Yc r_pa y;.ȦMo'drNeV+3f<:]Ee}5@*X?A Ya0`rF1lGeTvˠCmf͚œO>R FB׮X,9Ӈ8ڷo=r]RR??<Ìi&vdeZPÂo^o7<yz*ZU 421"IƽDh^ʓ~ů G Ղ lDEEرc/1Lhт3gA~رco|v#9?QT{D BN1Qv;ְ́vu:&HS9ɯbc;Wnd".>v!dd2L&%6K?+EVffD ARts;7.b֮]Kxx87x#}#Gdƍl6SO1zJcƌaΜ9 J>}())aʔ(+-<)))C;Czz:AAAL0nݺrJ6l@hh( *~E Nb(nzU6ˋs|}%+ԝ/ܹsiժ!~u]3bD6sęL)q`Wy9r:q~^ wkYY }m۞z1׾eV,*}:O>$?]tcƌ{aԨQٳv8=|xke;"o."zA1SMZ_W_OE_(u&mM?ΰa0LzlK?ղwu/x%M /T)Z5_l֮#f3l\ @) B{ 7|dv^SꫯaÆXGD NbchچLZݧ3z)..f׮]$&&2x` #m5['k(QQQsKKKyWXLDEy_Udwpo B@V_φ /rW6|[]'`۝ #&.;w:"Wpĵ#y#n%5,X'O{a6Yx1\r IIIL0kגl8`G3E/rI&~G(DyA [3Te_V7. %@)pj30w (,dȑ<3 2 {1vM*/ݑq/d֯dbvu N̙3K:t(-"++.u۶mn{h+ڜ>3O*: n`ҤI|8p)SƐ!CX|9.L2dŽмhDub]ֶw<ӌmxTi+7tknDkoaP x6\஺`BMEoщ ]O xB:ukDou>_(/2g%KR$+Mz~GY: ~ NعQ;;Zo`2ٷo)))y,g;U }8ǀ/}ޭV+ s<\glq.=J)X,l۶l"|k*|osiCIt/[UDD x<$4l M#MqpOov.Q_lFM"?|\~k9M5nѪUD .DGMf~&7pCĄѽ:R#ִ̠MA;:z˹ٗKk*U1Psџ|yq@d^+x32Hh@XpX=X%jV u NϯF_^+uӖJ:MzvZ#/U07 IRts?ޚ/&vILL$55m۶yͳ>6ab);oD|شiz+&L`dgֲ_bgOmSdL&(8qڵuE |uOAhX "CuEܦAo GYw6VfڴidggPQ{f3w5O=1Vv5uY_,߳ӡCfmnd2Gnn|ÇkGMFFZbڵU>9ĉ8qg IDATYCq+%K8:>_X/ ;SU׋/ ?kCv6FN>o3<]P*& ըUf^&6hPC1L՞j*R⋂P_TCH5n1cp5x=O:ԴsF~=yPzJ uPbcc]fRfXr}\&tL&'OӲ¹E` Ԅ/ Bmo2k| ൳(//禛nSN̝;M=+ie̼Lg􉉉a;,]Jcƌadee`>rs?CZG"pQ-id";XVnfڴi… ڦORt 6,ZS7#/6eBCpBxiٲ%o&3gΤcǎL2-ZZ׏ŋ)S`HLLt&B@|Q.MFo͇~ȧ~Jrr2 .ॗ^jLӛzecYo׿sN&_"g={dݺuϚ5q7n\͛>A8@|Q.MJr-r- iYsuWO   BCd KVthW޺{   44"|Z9#/^m{l nAAAj_+Vv$)F  Ğ=XK"#/ѲWAAD$Ύ;sa K %+  B"WJ>U;geRYAAE(:EtUf^&!A!tڀ   _J윑A>X̖JAAwD UR]e̼Le}   _J.LJ)ϔ   4"|*IIBٿ?:tlL&qqq撐nw^ `٘?>^{mrlĉL8=G> 40K,qzu }1z_ u WftJf~&"&:<_):u*mڴܹs2pjZl_ 4Hݼy3 EC!(CCIu33gSze @m*mBllsv 6@\\999s >}:? ٛ)[m?J '՞|1:MN?"|LS?Ιy5um:y0T􅘘;ҥKuI3f 7o&++  M>={l2j`"[m?4 D '՞|1:MN?MJֵP7r?;o=Yp! .$119so0sL.\@DD-bуCcO?1|rrr2d k#MGA S>Yt)iii_ڵkٳ'?gfΜ9dك)LjpvѳgO֭[WY\7qU:w P7!0_KP7z `le$  BSD|]B۷B6o|ֶT'Jl%ݾKUQmWMM^\\6'}}-gKM@Ol=F6_ NSSl5Q56nܨ]իW{Ԕ)SO>,l. <ǻ[oZq>!x/C/l2_c y\e +W:{*!ZŽw}.] A˘1cs EA !po4)T\54>̙SUQQݻwgڵ$&&2m4¤   9J;w$--cǎѲeK|M9s&;vdʔ)|<#XVŋhdAAAƠI _AAAA)Mf;#AAAA gݵkÇ'11Tm˗ӻwozu]GQQOfСѣٽ{݄"""ҥkU6oޜ]2` \mFfΜl/tٿRRR<-jfm4y|Pg;\dI,(([n!11}2eʔ:YUs֭ @.]lӦ.]ЫW/v'_} "$$/)..O> 0/~$''3`?nK| _~׏_|/nذÇε^sյ Oҽ{wwΣ>Z9r &L>}7o^2r!ƎKӧiiiέ?´i\|"44bKҿw!''om76u$''%\¡C-[/e_INNfذa j_ON0͜α_Hjx3==T8kVt3j(xbR|7jkgUmǫ^xϯUYδiTΝ79}t.]-[x<>ٹsڲezGՃ>_}j~i{YYJMMU~_駟ԑ#GRJ8qBu]unjj…j>Z]k֬QIII̙3TwyꫯQ:ӟc=ҶKIIQ6lU[F>׿U)fS_~Z`A5Pl޼YK>|X)ԩSԙ3gv PfSݺus?nk-ZP[nUJ)o>rmL?ڴimۦR*==c__)w}*#}m1KOOW=>m+))Q+Vp>?9rdoN5k,R6lP;wVe_|jtK.bRU UjjܹsB6Ν;W]wuYś{V_~RJ3cbbܾ&/|9"##cU՞={\裏رcϷmۦ:w\=ݮx uM7HuaVj߾ڽ{K5iVN[U۶mklӧUjjڿU-ZP6M9rDEDD83-jf]4LP)ڬvRnΪڬSXl/wcZr餺t~J6O>ӧO3zh&OѣG}jGaԩtJ۶m1߿;:3-jf]m z!ڷo_g;Y[;mFΝ8khݺu쬪ͺ=AKر35Onݺѿvw1),,dƌ+(?߿?ڵ/梋.k۶mf~o_߿xJ 4{|~I}ٱc۷]vӇy7뮻aȑ 8F?ù.߻"##o6ǏK.1ŋуcǎ?_PTTľ}6XՅm޼y?3ǎ.]Ժo͛ǕW^_ | AAAdjd\9y$G>cС :>Ȃ ?A||OOOy\T æ ";eZ[澥V֭[vouoY+s)ԛ&Z.iK(/. 3s~ 3g׋̙3|g9>sClll8KcǎԫW/OIII)ӦM7ޠnݺeZٳ޽+VY 0 иq2+Rrکp5k7o$,,QFѭ[7JUnrr2/2\psΑ@ddd}/v"==޽{{(JYYYV\K/Tk˛( 8>$Ox +<;*sjQ%O@&Mضmӧsi4&L|Nӓc08s 9/NSNeX===9s ߷hbccL F6l@9w7nܠI&9+W~(N///UƔ)Sزe FooYX%>4ietoذa_%27o^௿~c…|>\vmYwrYZQسg{W^!##k׮ѺukKUu2h K3czGy4he{YĜ_c46i$Ǩӧst}/^l}5+7::H4 nnn <{dܸqj(ޯl 3d޽L:a<.==7nиqcVX?ic2dLwHII)w:o~۷[:m9>}pKc;6Z#F] Q+q֫WZj :~2;o7(tQiٲ((2c e֯_jJi޼O*iii S`eȐ!JJJ\___MQx+qvYZ5e˖JPPﯼ-3M*֭| %$$DiٲҸqceƌ*qݻW VBBB6m(cƌQ8P8 +4gLLҾ}{%88Xi׮7ߔ,i0oooˢK%3wfݠ eJRRR/em튗ᡸ+^^^.\]U +w̙J@@+~aM͚51chтݻwK/FPP';w$00cD۶m9tʟJ$T4M_ڵYr%'111|U+_|:t[nGy}Bl8pCѥK}]4 iiimۖЫW/ @\\cǎe̙2=ʸq8rÇWW  $$'No߾k׎Νkyn޽<† "gc IDATxWh׮aaae„ y9ҰaC%&&|>vƺN}ɓӧO+FYn(T^]ٹs(G)C QEQFرCQEoVZy7o*ZRHB[;O !ٵkҬY3KZn>}ZYe#G(M6@EQLI__֪UKINNO JKv-Ǿ}UV<3֭ywefx ,WXzVVÆ ӓٳg'~yRW^XlԩS=zpyປ6mڰd^x*Ek|EuЁÇE{.xxxd˾'Otԉ'N{nF#ׯ_ƍ8::ҰaCE?^1i$y7oҫW/qxB؉rdzN:uJ\-'tX'No>e6@`` ]t9Yd dG$EV^=-ZēO>Ihh('Onݺ8::qF֬YCHH>>sM&Lu8~87ޫ(B!0ѩZ\֭[iڴ)j#DsOgϞԭ[tl޼pZl )Sxg_)X֤.FcM|nѣCU,[QF{9s&MXpyF#Zm&REUUu8.JcM|}}}ۺu|>}:gϮȰ{W\ѣ-8)>wY|_prpI焳3NN:Rͱ:ӿSͩfɍVRZ]ܜJA"彊NsQ'W_(V~LJ%zQscYR[VrUh߽=)1X&...nݚ|YfϕU3ԤImfy|i5jg:qf<4Y, Y5.L25%CA!;YwuwoZ~.e^"=3;餧A1@ 5w'w)3vݓ!m04`(:h 8y$CGg"&U9/ a;> J?LZZ}w-QoZqeU3UUiZټ'=|緬cͦE SOU=Olfԯ^(֕ymIl%f|]m78%ƲaK1j.гQ;vɓyk4bccݻ7>>>Z @y':ujcccf͚91bM' QQQQDEEؖʮ]*.I?V]E>-O*9ڨm7/=dex8{Re7_VE(*8/J;UQjw#{-y 3d޽fϞm m! ߉|"A##|sV9=Lxp^CH\~I'V///ڴiCXX^^^j%4 =ǧ~dS۹z* #i jWi\u>0uᢳ{rI΋BBҍj4>#>#CBuC=0f_>6D#Fjf^u 5CPIVI&E!lG!SF|–9:82t<.1#ǮS;,^-Gާ^zj#B$B A0{梁Su:/̞3{.0FLv8B!Q !JhwX?K{>a!ٝyЅC| j#B%Bk-J}xr|!ٍ7/֎x6YyS;!B0I|Be.:V^smcƉ(aټ|Q1#B!l\[Y!쑃ցFnx+-ajjeF=MjuG!6N_!7ɕ;Wxqˋ o7òIo󲠕B!D: !яۍ! M2K6nKhPCB!W!lNcpy!ٔ37ΰf&hB!F_!A]k~z'2eñ)sexpCB!W!lTm,=Nplh 2.A#qwvW;!B I|†͐!L8Qݖ[HNKgE!v%ӦM#,,vXBQ"}ʸu0*FCRUd\$ Ci۸ڡ!ŽT?'..8lقFaСj%%V۵6KX|gj;Ywrr #GhǮHA]d z~j"hGy FnjTOGsG~-ݱnX_x___BRPOxbƏvBQ&f<4EQڡbUVjbפSX uQew#;vɓyk4`׮]ӻwB˛>}:5ḵmĈ1BQQQDEEؖR4,ԭVlgU9VS; ( oO4RZx1f*t97΋REUF}w޽E/22qݷ4{l"4!lJ~'X"""TH;̼XiN9rgҧECIe),FQUyQEF;ߢHKKc̙Cbb" 6dܹ 6]vٳgn &GLfaB6ȀVm<>-:obcccBQQ%!|~=7ϟh4( gΜI&9_xGhд Ѹqسgzc޳=v(e䵓$\M{EcBTu2+쌚#5'<3DP](ʹ|/^Bֻ~{}VE`0h—cvwI;N! UkY/׏ L̕WXZPĶmd^QE=W !Əο=vѲeKUFB)Qj+lȈkt+bIzsEz*EOݘ|FT;Rx|#v(¦v_ea#2$Daz=Kj8p K.LJ-Zp)hҤ-gFՅfdHSs1~xRRRk׎vh"Y=NK2  W>V1w y_!䶓j\jSbFȦ:NPM+(-Qp8. QF?ҥK2e ˗/'99`Ο?Or9ڷXĒ LSt*]6mڰyfF#}a[Рz,?S;9å[ۢڡUYB<(({a98F# tܙKҮ];,Y+VO__Y ܝN!uQDK|===IJJBQ233}6j%47х{ i"pj{Y%`ZiI9j4yP悒`IEprpb|x>9vND6D-Ztv(B՘ uKcb`RN|z>9s>wF~"չfnmAK}v(%*=zaÆܹsQFѷoӧOTR#F0bĈ_|(oA#n"ѲCIt"b&pW5IMʱ-55\K؎`Dń jS"즫OWtJwRE՛ 2 `rOw }gQ4>~,] EQ8~8>h4!C͑#ItdLYs >W%cw;r<5 |?s-Odd$Ǐϧ4={6vG*Nh|ޔKȻӅ{]80}_(%"BNOMzek0؟7|SP*7sKCX's SB3e/.UQ4>t:?_ 7oxg,wknaUCqvݻ磣D.0奰Z^:5+M|'fdENq T"*ӟEٙv2qABN_'n::JQܙP`l9a~E77-{faթ l!ŪB9~:[ Uf&~FʊMBB9?>^^ mDk7ovs˜疣.)Jhwyf:t@VV[lsjUX3 9{ IxV=g=~Hf&٬'#]/yZ۪(P`۳&MˢEqMn40ptx]&Ѧ_Fx/ɯPUmf7W&ӵtޝܹs̚5e˖`t:{/ Vu1wl-O]13%| &M"88@Nx饗((oFxrVrO!NE2DW.$9:82PDAѪRKGp`]K Ui&TjDF3z0\]]ٽ{7o_S ƆwWƽ<جI:<%Thѣ?3dD d^sa(pr&ݫ@uQr ȫ%7fÆ jQa`.w›kLzrKIV>O߂12h$seW.jپ} /Nc͚5'$ii'3orK+2Gkޞ۷ÇrWjPz^כ-h5+úE%P_s{isyZKE'f%p/!7`f~ߢN{:zuiͦ,c$72npQ^ڡT*i&ԱcdeeѰaC?3g3fbbbx6&dr~ c}NLg' ')X/^U(>p*ھ72@~.wۯHQyI=&R/u_^E Jvz:GZ~֣i$|p_%h8?I((jv(Je %mY IDATL<<v(ƥVi&֭KRR~-`jT^G2btҥKr ~E|1nutvNJ4'5O&A7[ZwlJ,,II׮]qVKpFQ(X6h=H>ZE^GH[uI+6E[j>-$w^[JzSP| M~ɨ(;OZƄQ;~wڡJFlСqe͛7ߟ=z0x /_Ͽ qqqAѐ(\pGss4OyʱY5V%-jsp07++ݻs5puuw^dff[HS@l&ܫycVu"*bk^*}U\$=<1]e~Sa$JƧ=۳&N|%g;#ނ9}6ܹÏ?ȥKx睷9̟NGy٧`l Po9?#<_#9Ƌ^ur#Gpq._3;¥Fн{oOs*W.nVe"p8+Kaǎy\=ZF &2rPEQ\e̗^?/yuZ[Pqp2ujxBK/fժ4RRRعs'~~~|jԨAvmٸq NNGn>ඞŔ߭ N~oyd&ɯ6nKީ<b4{._}5ϒxzzsqBQ_?-6 Wuқr{8W{f'Ɠm7EœZ.]>NgZҿQFܾ}Ebr<7]HGxyON%i΢B0wzyu\Yh c&:0o<V^9mK{ uɥK8wZ4F#uB޵>mϓZV$WO!GaWX ZӬ͚^Nu{ {IBfk~46^Iz-r_Sfa&/r h/^p`<-.-8psq-[NHS*Jw'>}UppC4gQD։aeG ddA`yMӝ|o߾MΏpyz9|g{ut\h0AK]"ldo<݇r2׽O[b{Q|HOYt/۶mh45nJ1SEd>I+ Q7%^һngZk4L:ލѓ_`…xxr#:#...z֭[G۶mt5>HTN><\]ՑP;|zQO`@CvÇg&c:~4~o~/_Iju ޽+'X;233+ [wFK;y:A`Qܫ.}H UHOOg{ڵ}E˖d bJM~B*F_QI|D%2sYPE GZ-...̚51cPfM<'|„ p"]tݻdddD֭?rHE?}wb0%+ P9a_rO xn $:7xqVE7=Fa 677ӍS4ӄLGJu{W$In~ z^]{j8/رc'O<16={ODX?5knwS-|gaH[Tŋ 83g!١sMz@:pMVEnT^`Z-FksѬY344n'''-5}?vUQG|F .ĩJ[.uU;awr7s ^@|QdddGB\ܟ89PVl-eJ7[$KɯTo WS ҹs7wSt*zܒT\j(nWn:I~Jת~ СC,Y]$ NnekRtrbب<5)F~wdhYf<㤧Nhh\WWWjԨ^'33ڵks18'Ej Eγ]{Qe/'&O} n]F4 [য়vqUE7}w"+tW=TJ7m J+*T-ẃHgJfMw.\BRR ?DZ-ܹQN[66$*]{az @jڵ+K.U9*{QPK YUWi4\.k4h9p`7K|ɍ7pww~$'kpuEN5rthZƎ?@VpwwGѯ_?6l؀` --?3gi#4h(>''l ;Nui]7Q6*L\ ]@hx= ݻY(ĉO~Ř1;>&),;Hto"$d'$A寏}]~xܻ.ଁ訣]@=L^ 3+WΝoٴm7umN~Dʩ(""oslْ5fӧOf͚91#Fw6&9]SFzLmeb:feh4h4tzY%""ÇҾ}LHp60IIgpttiSܹٳ'Ǐ'&&sѸqcƍ;v,Zfڵ={rWҿ1 ( 3FEEc[jjjG.Nci0 rgv<j͚5+wsΖE*jZF#7ndƌ-Eԩd`KE6oܹߣ(@zg佽JQ8gfI愽H[o{$;wU>NCVudj`Æ_y~{Gy _Pck{n}m97U&v7۱cGի~0k,n޼IXXF[n88|Gٳg~?U/鵖k1|oҫ`Z<ՠ@OF زe9mۆhhēLڵwBjܸ;vd'8q},2rH.]Č3m۶Lc?eҤ1Z^VիG2dO?6lڵkѭ :={m6vލ]t֭[,Z@Zf32eZ'줹{SZIȯ: jmLV͛wpr?m)h{QmNewwMR vϵkpwwё8֭[NX&Fc:8[ (^}H6y~zCёܹy14mOcȐZMZhAÆ غu+JvΝ;Q.,͌#ggB^r%bbbؾ};dڴi$&&w⺟~ K P~ WܣxCDV;t+#w'w7V;ձcGNI HO0Ս` `4n_rLu믋89r5[̭JĴ3>Թ%y.ݿ?/:;4hvXvhI_>jw;b<=C!uMB2=kv=993fҥ ms=K@@kj׮mĉ89: ր?4#*ٳ4jMS›p̙ѣGW#F !!M2k,|}} ]w],8h$e?uҨp 9sfptq_ :A1vL ޴]Q4'_s좴*>V^zqqðST vjР3?m•L#5ࠥeKoMh4(ᇟfҤWޢvZ u6}`I`>hESr^RH~XMah}`z=;v~u,XC{&ٳm[6nK!+7V;Wij/4WfBGoѤ$h5s4.$_f޼ K"=z+Wnr,.M6WLm.gψOZ>I~UժE~I,7W=3|ݕs젥HЧZ~mFjxɯ$OK|Eq`:yWk${uML, ;ˏxS┖ŨQ%#8;;e !4dʔtږO>yc;622!nqze w7;pz{{syF#ZEQ8s M4ɱaaakF͔)S0 .8Wy{mGhC-bǪ*BxjM^mkU{&D]ȽUܗ8u FiZ=;PYYM[` Tz`j\8+}gUXL רDE! HCZj.#5.<i 0]\PrH׮I+00c"4MBzvfÑQip9{~48uXv;zu!%n)-sVɘAiׯOxx8K.eر^ooӜq[n?P*;ӲNKb2.t~7.̈́=Dao"2P`xe6CwҥhSAZuk9.-}k~NتW w$GggX_cp?`N!qb8F#!&o!o={0rs^[Ozu3X!o7iзoZܹPԮƵk7j5DG':z?@mFQ3rZlt_k 0n8}jԨa^wޡqL4jժ1|郢(ԬY+VoN܅8ÐE S@m[\d!HgS!-aapuGH ,WdW%Eӝ1Ǻ1 te `li wa޷y5|7a'?]hٖ pids( ¸Or*-Fc:s9fH+*YOw4K>p8`IHP;׀ޙGU33 K ѰD* D-[U_# Vр QYbE*@4EBq%d|'9n9O *Pj=F>KvlSSS ٰaþ;W =B)#i)t]?zt3p᏶vB[O'dUH(@3IyWjSbp gv+zV`H!?AayaPDZl/gv9QK|q3`P(?#cD5P ⩠!+x0RUe9 RxO}m\ -i^ᮻN')) ~cBbmus!ms 8K+/D.AsV+:O-Yݞ^p7_=@Ix} שc\z_~Xݍ<j+ kt ]m?O/#ZB'VuB>c) JnCSÙ8~\:[u7l/h4rw0qDfΜIvvn! L 9_`uPV]O^[o]+*c?lXgOW;@{4QC`JObl"w<]brൊ[}/i YEv1_cotlKhЋ_$iDyy2fQQh>lu} S#Z4W(oX3k61ŷ+>>u1qDnV_BbE.WG(8tVmx~tQܪP}^|}(tDx#з<^p qNw:ɣu^oaƍFFy{KB!݇ݿD)ʥWrGhi1p;p :p z~oPg·:` %%)S6fFV?:9'@9P-Ht1syI1KD^94I:WضH bǎtmKwIkaH!(p [PQ@ztLQ-{ֽOHbUPoMbk@ (^ )Y&M_`0Э[7rrr8P>q ynޫZ1xb{Q1/QGKџ ;6@~9x߾= ~̂!z{ޱ4"zެGQ^}UƌqSTҪ֮ugׯoB_P^@}~_D%O9_՞#}7q+~AdgI^b1!42>ߦI^=r <GGy6nHVV111̙3ec=F޽ݻ7}zMVj36ѻ]}Eo B?<dA x:tVf sNn&Nʶmd:B%,7tDo/l94opݢn,F+%.WWs} hXG99_˜PZ:kGyħ۷/+V`͚5TWW;OXj~-& .Çset ઊF[^ 5 ǰ/F=y"9P4I?$zA<<2dH! 2C!;/EQ0zK=EG]{#K_go/|?O!@NGăao]Yw+ umBy+̅fuy-ٽם=k$\2\Fv>}X~˾իWsM7+ӧO'''G _׫U 0I܂{>CKӅNW = w߱i& cǎeذa$ >#'p0=} ,$8^nPKo(ET_$-Y0UwWk#< [[\7$?//ѣGNzz:_|1yyy <8 l}dHKK={6W^y_NN܄UhE",*P) xBM|gϞ Oii)Gkeҥ$4 \)|ɓ'dn)@AMYNa׈*!y4&\cs.jwv./5|e ѷh!3Dx-zǨjw7p?t>)))`0ɞ=oAE}`4Hx1tP<|)@-Els]ÞҲw- v p^i;[i59H|5aVG"osg,X@aa!f7 |7[u]ǬY;1LX Cc1"ѫ7W b"ߊ/FQ.]j%m~I΀SVt,%%%w}NKKcժU 3{l~>\ǰّ_两UVVt MǶgۨ쟜_gZdR {4iSNe֬YLOh[neڴiTUU( k׮eɒ%? /'ҿxS45Y+5j9=a[۔'g! G|0%%%'cƌaɒ%A$Xd&eXLFf;SP^ԁSrB S-Y!bl*W׌km;\46 5,<_7ׂlFը݆&~gӛyW|.|#""{}}YFMIIseܹ~CX (k4"x=z[x'D*1Pt>?QwCUǷ@_XCb1o IUXT zQ-/?H{ ܋ߑ7E6F#2-/۞ 4>O袋JZ^NALUq\[1*zћϭEL W/S 믿ɓ'eŊL4) ՞*=KC}4Va6"T9K vWY =5k1Maov\ ⃻H &0n8ڷoOLhl0(* wcA7{>9J#Y!)NBi(NPն{zxe˖v !itoם1SμL5 x~>vC L.g-UPq.QgH[%ρb[@`!zdFfr&;ܫBVt:QnuY-,D"RJ+i]G)~υ_;ÕW^KK?ѿ,:azn)qnC5G. ~WV\``ȑ3C~]dt=$r{,@ aa7.Z L_s /PUUELL Ѣ`׷[F#Mq)ۨ_ Lz\BU@t|1 IV~}ׄk^J+i]OjU ]Dek>_5C7j*cj¹gò]1T}60!ʃ08+W+D+K.D 6Lf TΒ0 W.r]lUgE/d¿oR,S_gH+ k^_U@ZdEQcHsԩSڵ׷4H>'m6˜ ۡ$ W>wP]/O O?%ž9Ӊh$[ntĞ=\}~, ůFG4++kFߋ]0+U1fWVOV#Z{6 f :ǬUh70\r-1-[ϒ}}|Cx omu`}3 ұlU/sEQVXW\AU˶Fm@fr{j·wboG"/z}*n?.žOcA85VlkԆLdǡ~GAE%F|0;!8 OW]g$F&GWҺ, QfУTT FubsR ߨ(CYY6!zZXN2N0)\q= FW5R"?E<^@m;Y ĕ̤LV|LS <2YҺ M:V\.wyE;> m{2g|+<D]vƒPS&Yy}2 ``X81`j8fV5>OȠo;,|#qFaΜ9+N||D| 0uSRR6l-m^XJv (J DtU !|-zЀMms:^m G!//ok\hO<=҄R5+9/gNOPgI+ƃԢW=McW{po p֪2üESgL4ܦTI$!=8r> *Eo ߋ`0eNJuC8?^@i:JoSO"$@h$T+߬vՙ̓>0^w\@D'j_eDѾ|з+BR26kX; IS()){⹙`gϞ4BW^rV>@UEٿ) u)@zohQQ @UK5W ps<7tD<"-qu)b%_LO|zͶȗرא)_M2-L4N[Y.xzs 1&\/~{ j Z [86]% }@.j(~Amq~P}y,7QթKy@İ3Y)L&1^xa٤X55|'md&el2->\P^@\d=$ # ?:W-[cONJ)jނ$X`-W]ՑS1*t4ףj0 w$ÅZ+.Os'qی~,YE{ N^_5 UM&A 0'릊38~ȵ9С7xKq IDAT_^ogjy{^}QH/D2EeŠB[RP! [Iٺu+ӦM EQXv-K,a۷1cpIN:Ejj*=~{Fi@j{s1@NTYYS D[D_oR<_'mw~+~-8Nn{nW^x[ů뫯g N·5PS)D=@||KkK0Aj֡]֟W^$`d&eτdpC/~1G{ Q\|,~k!92$5 sϮ'!_W#]N  qv,(~coyQȷm+ wx:$dU/}aQf5kp:k{x ƤIrd˗oPIk$n yok{HۚPÜdkD~O`P^^w/0qn:"6ѫ1H/+;WU_d+##7 ,* p'wi 2!*s QߧCm^,uRJZ ȌBFu n,=7/%K𗿌aѢIǥ.dǧD6{EchhM&{ܣo}=܌h$::m1))1dRR.cQRJkW"z5O +EDh2|'| YY"iw sZ |s6rsY܁NL_C[_>hBs.3T#7LANgР{:W_![)1Y <*k_I@Zf~sǯ:Ec +Zݻڎtm f#)|[9bag۷瞧x80(+yk#W" &S·BVtHs_Q[k_!w`(y.&N|G1 .أäWvաq#sE-k!:_^;0i9믿NΩ^>&7M~[ˎ;xٳرöɓ'3yd74#"#0 z^~yاnK z3pu+z䐓㰭2HIX |vaRJ$]@MaSob{g&+:~),,a޼?1zSO-c=DX<ߴbu|HZ#Ub!e=&~Aئhb6Z֮'g!`0p#x9O@=/ !Ǹu(t,~uVDH ?l7 ޽".:t?dggӣG-Z!ChGܫ^ EmDf3z3VaE.w ª (ڵ,X8ZA=G4_VгCOb#]3^"iKx }v0T DZ_yٹs/_},;p9ʋ`dOp "eڿC"imhW0Jͩu w펢 =&!Cβ^/⫯#""cBB=pv=|43:_Q-bǎ9r+/0vXΝ˄ 0`< @I7L$;_̜y m4c !J­蕞^$י][Tٹ\2 $7n$++̙oժU <ӿ{ R< s.hd/MM7Df|}^}ƎnQ{tNYX\v.55!m崫1@&ӱ+5(p'A&qL6(vL|4v^CHz|EqSÌ=x?AixVlyQg6CS[YZG4(zH BF$ ! ?E܅>8Qof׮+ӳ"ZxE0H"y_ڢm_MbъVou,&o@aA>$ /Jyy%S+ʕ G-50RW*VS<غu+,\˗{y8t-b <Ah)g&_~HO?;'F&-D^^mW" 'ZȪX)(o>}0`""\i>d@~l}Ě-:Uˇnbq~gFE +mQ"MM`G8zU簋tD-sxwXt%K^ݓYX,hq^?kKzl5,=GKt(t8j42x  jmFH>z/H+.IՋԚknQc!7%=hEW<L&zرc7tФsR@~ mߋ(Dݛ^oر):P'wc4PzHW4~֪j|/n%MCڟiEVYϳm*@Ia뉌ek?K.Vڷg֬ 'g=jgi>"o]W?̇nKmLJ;ѫG6K$FfR& *;7GF#IرcGoJx mG+@J5phĪ((BdD&ӱi8:W-Jtz~ӱ4D ܘ#PZqe;`62 {N|(g2qL}C>RA4EwQG -_~5&#xױЋޑ1u+z/I8)ugo&[P^@^D4hfGx~Jhw3i$&vdٰaZAtm"mQ&~\AS3_w!D"Ÿg͚_iuСük6 ?ʆ|DVHwQŢ%`Qw;+Zb o9j%xg֮]OHLZ^L^mܼWQٺu+ӦM EQXv-K,a-ZʩSyj."eyZbbb:u wťi_iv%iXUj(bb4ȱ @jj =RQy谣ר i@:]sR- 8P9wPNdD( V"=.w%]D4ɦ|^AyWuF$,(q`6Y6ѫq睷2F-SJ&N+mQ8zJ@x7$8ڨހHK7[8TR\|ZYy#Gʈq:pߐ!~òQF-\nٓ_>@Q}222|Ҿh,nDXlH$D~OU,uXle$߷:83]EDDЯ_ՈED+[b&[OiůV=W18(۫a22o.?uuQ4lWz|CT_WZش%g~駳3x0j@xpj2)z%KfR&Vʾ} \=EG*V,=K԰{X}CmWMG{~|%-}s0r'{~(-V/f+oXAwnq  {n?kO2uTСoYfQZZJDDs/v .je=^ _H" 5.~{ZAV#8>ƈҩh( ?ñcU$zK딱=} ŴD2UvX~g C>@$lXl1ӧ(ڛ|(Ҩ O sb#lʥ[]]n_ԸڔH9s&~;7to6ӦM/t8&66_|> 7SO=?QKJǘh߃=*(/]T;ǑI$Mq'~ @;~(WaL6N].i2QaGF~Z9\:J$m w{[!}#vn(R#X*-*L&.d4r8ԩSX>zCi7,O\ h%<ЃGJ&wN)zG!//-[k3EEE3Nzm{o4:t({4B$d&5V`EpD;鐲ERj@±_PP,F#''Xw}C"dAVƍs;s@kHxJ&Y&.6`d܇9vӧO#227\#r իJǩz#Eo[ݻc4S@Ϟ=9xs /_ΓO>gv\p\X23y=!''a[eeeF#xy}Mq tGFݏ;>s0ƍːzKP[o_m|I[EϚVU9&v_I!"L& K#՞݅=W 0` \w &b y{9yY@xbV"o(zm՛׹Wo%'r%pUWy6KCa)E' 웼f3˖=d{LhYY9/H>oPOsX3ڸq#YYY0g}ׯg <~q}aQ@LTg (-[F||<_~ᣏ>bXV^mXjHۖIMM6RҳgOc8q"))),Z(C̤Lk9\}X2HBw[Y"XB%%>}@-3OOêF i΍NH28=!lU5Y;8s˗k3BEe©QXz|ˊ+Xf ƎW_ #Xv-_}0#Ü9Uc`$$}ڵcرuY,Z3NGToNʜ^ $''3d^uNoMjjKlfҤItܙ VR%j{aP7,a[l㢋~jiӇrR騕=9J$mĮ <ήtX` :vNH'խnhM߰Ӈ];SNQ[[K׮]9s ,2e SL=%#39+[P^@r|2c:6zD" =궄̏ڗ:;xp1yg:t(\r Ft= |S IDATtHMq!ED"QLʤh'O6x\Ay]24*D[܅Sai5Bza (t2鄗W:iq $HsKQrJSЊ^am.5 0GF曯oP?&߂kB:UBvCRz}*?~7ryzh~cժtօ?ɓhmm-q 1ҋ1g텇#)z%NfCQr mہķg86sc 6Jh-BڣuW|Nǡ d8e4`L< @FFYIEyTzv+~C[n%55 |rRSSyQL <#Fp嗷cǬуHguIII9Bw:{z-97^)z%ҽ);YFeMnw˾cǒݻO>aڵA$p$i>Şv \A8Jѐ( u&~o^*Q: `}j'^rN; .A<9rc!Gy1o޼(pdfF+{_֭c^}wپ}; yzSb+` RJ$RR,pUP^VFOe_~˾@<љX@Z0K"tq-G0p*)QXs_vG\~{m폺;NT@ЖL |߰m?=t3neժ}]LX8;ǣ!RJ$Afr&{4,| e9+ 2Mv@kڡxXkgxKk>" &mhTM)j܋ db,\۽s ~RH0Q ߰"oi)ݹ|T̝k-֝\٥&z݆8K+Hd&eWFAE=;$626jg?h} b۶J(Fb3wXXL_ķ\ہ>" }mWWYF5cZe4baѢ㮻$11w}?NLXlBR7,~5.}D ߰16~%lSQ 3[9EVY/z"ED"Ks;dI"\0g?c\G!+q'~յ&~uQӳfѵkW{]|-v`(B uGIxF&lͭ\ l<4?gLA'zzALR*|y ]G 0@~1 1Ebk̵F| zzx{CoH$#3ITv{z>paZ!A>}0n3g $዗wXUiv Pm21p@onKٺ HՋi[a-|Ms( >މߔ"XqqqL2F#VĘ-bAvx!QZ8"t:Y롭 U-{1@RcP;KX, _\};v_|O>*nk/׫^D"q}t{zv鶲sɱj-29Hn@_W]җq ZLƍ͛!22*, Hd+x6%~v_tVm ؼ^@("},I*v o&4i$ǚ]\\hԘSW3_8IV(!D2Bk%jcFgy[o̥KXoML2;wCfƌáC8p _}Ue҈dɒݻ!KPDEݡz_Yd ǎcܹWWW4i/o/‰R`@]vK+Duiܼ!*3Ymc0E 'ٳYj:9LK|֭KHHΖ7lݻ餬5jƍk׮L>t{9|IfϞÙ6mW$okr痀!-[,UTsdBe̛;Bl%f8zp?aAxxxkƅ صk.\`ܸq(V-͞ ˛J:N8Aݺui߾=J)FI*UC4k֌nQ|/III5_;O:t(*TZ^ի5B̗/-ZVW_\v-ZdƏo0Z` ,ZRREImyی\?zqa`F̻=ő`Y vzJG)mcݺuZ|?ׅ-?<};CB8~fM~j'hՐbqTО%}]%שYe^2SmP?ݻسgW=upB e c… sXpͯ!%ʲUܫB8$[~ReIAEKr?`С$[p$g_Q8%ƂUMT15o<C1o޼;ZddڴiS&Loz~ t:Gy#0u܆ rssSʕSαܦMTxxx둺((y8ΣcvŶŷ]v̛7J*eptN:Ev^V~i(Ʃ~SI]ōE!S5J9мBwE֭˵kj(Q۷oyɒ%̜9upaڵk!B! +ȗ*UРA~.]J͚5$`Zg= ԩSe!Ba+ȷcǎmh֬YSF ?ȑ# 889stFB!$B!BQˮǏiӦÇ-.zjׯݺu#55sѮ];իGhh(ݻw6)ƍ4i҄0BCCiݺʼn \s>ZdZ-!!!mVkݻ7oۤ7<<*U 5k+Æ LZZ[˗Jxx81^o.\Hxx83qD{n6mJ2exgSNԩ{%&&ҵkWBCC `Ν;ǓO>IHHDGG)hRK*Ŕ)SR5o] ߟ'xsΙ[laaaz3w\_~QF裏XPuZ-)))~{7djժ [v-t邿?aaamۖ'N+>kx"۷Ϗ`n1߿/hn5k_1Z7n܈U;s? UVv 8nJdd|X)֭[UPPbSJ]]x2/g|[nUgΜQ>>>y>EljݺuSLQ-[W|֖w/c*ڽ{TwqWZep.)u}0))IEFFΝ;I&)c4i֭Ǐ_iZW*U#GT"RSN7k5k֬I|U֠Anz>uTէO)/((Hܹ|Ȑ!VW^yEzuMռysp>L=3V/]LLW齔nݺRN:j˖-J)ߟykǷ{ne]nnnj޽6\-W|26 ={ݕ-[6K6l`L{%bK1G*::ڮQ===elݺ;wRJxUfM$Ůӧ^:Za5 ^^^$$$dY.!!///soooΟ?Ncʔ)tŦenݚիpBƏorGɠAZc 7͛6)xzz2p@6lHvطoM j׮MHH}.*5jӦMC`(;wBժUiժ-Zz`iΝn&Yӧ6=α?ϟRK./_ nĈ?TVU@NRYf/[Vw YrfN{G*U8{=?;x`y*Wl?pOf۶m,\Ъ9s.]0}tjԨaղaz߅_ruݻ7QQQ899xYgΜ7 $$ .p9=̙3]F[n%55:?222 ==?E1lذ|+omJ)v_|A||<wȑ#6~ 5kiZR9xyy~z󸸸,WpٳgYbÏX~ϭ^Mسgj ':t`ƌtlle.]44Mc׾}{n߾M|||ykNb׮],_h- bl߾ÇիW_~?Sʕ+ӭ[7os=r[޹shӦ G[n\ -'=SWVظ,d[YL0`AAA2emڴ3gh([,ݻwgӦMt)̙3vؓ{)Z}'55djԨ}(S ͚5aÆxzzo>x вeK6o E^:6 ob0a+V`Æ 6XCJpvv&11Um--Z>www{Ell,ϟ',, ˗/?se>#;GgPbEʖ-K>}Co{ݻw;TK.qq9UZhҤ ۷o~6صVR ?tRj֬#i׮{ѣW^ ‰'XlYDى\vʹEhҤ7ngΜԩS:u OOO֭[wϤNJJ2um,Z ܳ܂*;""777<@LL `8Zl]vm.,]E5kNb…AKe=z-555kܷ^=Lyϟ'୷* =z?pMnݺŬYy ?^ʝ;wػw/+WdРA삃Ynw_~!88*eҥKy饗V5o;wLܹ3%JN:\x'NN}G<8Zy_vEl'Nd…o 6G|7adg{1~blذ!_Y1Ǝ;ryHy"5{e:^]zBCCZ8yGشi`k.WTsQ裏*???ըQ#+3foL˭ZJիWOթSG=3*%%E)Զm۔FQ*,,L]ڤ옘BBBTHHѣ:{.?PN !rקO5jDhh(:u"118*T1cnݺl۶aÆNpp0` /LÆ ٿJ$h4WbE-ZġCeǎ̝;צ1Q*USrύ7I!D&Mݻٿ?͚5>@ѐBÆ ߦ}t҅{ /0vX:>Ltt4dԨQ5"883gqtʕ+G-hԨǏ7LJ(z 8s挍D<%D%&&J*#G(1ch4ĉ*""B?J)nܸݻՕ+WTժUնmLzRJK.^[`j߾RJ$UJRjĉ_~99V QȘשO?T 0@)FV\Rj̙L2jJ) գGR6mRFmܸQ)O?իׯz+VX{(T8)k֭vڦzrJT L#̙36x?$$$zK/kq->Ǎ78rc{Gߘ2e z^ @޽;3gdذa|7OYbIIIᩧbԨQ4hڛ.D0|͛Gzz:鸻=|:_~W9s ܾ}={Ү];~i[nϑB(W+VL>͛iٲ%K,Zjxxxp$y>%s+Vd޽9>vZJHH^㯿VZ8pt"0d:wLzpww'44^jj*۷gaСiBz۶m'+WfժU#'''\]];c(+@+#F)B؟$B!D!լY3<<<̺uhР~~~ 44MBQ\8;{|2+>>>*UaiiiѮ];*WlpL>Ɩu1!!///soooΟ?^Gz[(n(v},ﯿJ>}v1ou1?STI]ŕp֪vI|? /+W(_}G`>Z{ֺe_wQYohM^^^_<..իh텼R5א CepGwۺ۬Zv'۩|+K7/q%K9¿?*ףWsh)_1V*RJ5ߋ7.r%.߸}uv.M)RR.(T% JR¹7dpl|кh( qJ#?1Zب **J͙3G)Ԓ%KTFr,V=RjjĈwuEhTrrtn:)S-[XllTlllq>S߸R.l벳P-ťuk[ku>>>j߾}KIIQUTQRJ?Y5㺟{}3nSN_U}3sqOT \8P e4)]u]m:I{c'UJ< k^^q{Zqd}v:rVe2T}Zy>!N`'Fkl{Ebccٰa]ve?;'ҧ%C"S8k\Nc>wp :3^:/G&=7jA)\jȱQGӧOgbh"!!!J~㸗ɓ'ӥK\:t(*TZ^իW-X ȭIII;Z]1&&Ν;K}Ø>}ǎSO=SO=U eړFgc{6˶_7t+*OK{) !9~{tiTC3f l8Gk>;ﰪ*hF9OE5qK#7ƍɓ|.3i$4he h,CDDDcYcΝY'=B"+'zG`A9x{i1FZ^oL=5Pڥ4zѯA?hT !=6Ƿf͚+b`趔㈏7=`L0+Vn:\]](V{^M+emgَ^Xkݲ^[[Ӡz~;c[哭5')gRV^HYYIcOO7 "="s$rl|070)1 *wG˖-ٳRJ-^yC+F_uڵ\cB8#EKq Q9>qǶms5:u픽)֮]SlDwWڱZܒԎJ;4K#B]"V`')::qQ|yf͚8:vȁh4ƍ9s ÇvDEEΝ;0 !6K9P-Khd:)D~>cli;Qsh1^؄#(Pkv_bxp( cǎg05kX|=EyQ)|uQB*jN+Znƾ[*RooooP3:aK;6 !?]C!(<<%6$';"@¦i{.tIķٟߖ`W!DqW\ ^Ǖ+H[~d9Mg6|W"^)T4 !>I|{ Q>- >Ll;~Ϛc-tہ/nvK!raY:ϭuH ٧ӯA?i+?մH~7fl˱,꾈2%;$!HB~fO%QEBh4|Էܼs!;"c|K&Ęck>{&oaLdw f%ɯ(dB䝧'}?8;B/l */Ȑr1Aq/1$8CI$(ԕ_k!D_{Sh]~^=iIKp0߿r$+ ($,伦7|͞Q5c$ř+4xO~7(SCrXJ)?U&;!YJzsIx''<]$Y&RL^z%عs'h-:>`LzOf[Q,J [FF[Փ͞E#}?{Bg`O.kglKo}~S {#{%%]ssAeddcؽ{7uKDEE .qw'2&',P_Q;tƧB߹} K!kQ=EI⛋[) _?iSBLz'ɮyk)?1I|Ԅ j 4Ȕ&$$fnݺ?ζmfLzsb1 W8J*q5ׯKf…lڴ oA+f jg_y/X/ɯU<[+Y(f1[)|K{" ^fOx%6tz]\2N N_N#<<;w0df̘Vɉ[n̹P#)CƤ^|͛'N_8u֑BX|9...DGGӳgOVXcTp!s, +3e.Dqlೌ0UGW;q(.b0C{;!M/5l>18qW'a g\˸/;k׮lٲ\~ݦɯ$|zbccٱc}}_DQzG֤ @Ɲr/ /@FFƍ3%/_]vٳ`9y`cL-{} O܌7[[QyWgZ${ZGߴw8Bc /XNx͒]`W2,&&ipwHLL ކaÆ?һwo"##9p56"I|Txx@ϔ)SgܹmۖiӦ̙39q/w}8ΦG)!6w֨Mw$ɯׯtwhΜ9ßIZ۷/:hvɅ;h!_A2}fAή !=~$IITp`pËϯsI{#Xr7A)tWT zpssR9r)5zꫯػwomJHsOG׳i&>CFmz_M6|Oy$gOg>9gO@_ЪVJ\\?~5k0g ҥK4ooooV^+W(qn3[!ko'񙉰o~/! =x7X â]}7~}ɺBnd Y#ʞB2Ѓq (ܹsY~=3gΤQF#hܸM[{A_ְ'_݉WQR%F}WWW>Zh$x{,ɯpP AAA >_~ ~iӦqyʖ-ˆ T/W\P^WG3xՕ-u w< %DQA3f,:H_p% _˪ IDATޡ! \7eᩥiIS| ph=z4={D߳~7o#={ hF_  J(4p}6k*{l$ɯp@}vԩCӦMz*_5Z~ڵkF2eXb-[ĉ| Xtx 1 e8>+9Hhؓ+T*]GrǗzBjPLv/SIl=Cw>}ӣGUf?Ν;SoV>HW/GHHyo(U齴4,X@+n'x`B9_%{nw}NJ+prr//^DӦMOիWF4hЀ%Kղ%w젊Ng!ѻdI!`qQ8$D-C~ŠVr](<<@QX,ݔ{vSoR22Lg1b'N$((PV-6n… qrrbϞ=m#o!0~#70vX>St:cǎ믿ڵk9XJ~M];-M"'>Oaϗ[&QLn߾ӧYb<)5j xnVs^l/ͬ@!kBM˗/ٳ ȱرcYh%KՕ{UU+[-XthQM|WNVRʥ? ppٓ2&rm5Ov-%FI Z^OŊ>}:3f?lٲ||gt:\\\(S N\9Ν.C A96Nؿ?:=z|3m/]J_@C͝m(xh ɯpP0r(8'ٙ/4ʗ/o#*FhT=!u\<3>߳~&ߟзo_.]Jtt4111Ya֬Y>|ҥK3|̮]cz6Y̥p/nplV-:u;SGn֬y[)\2W^ݝoҥK3l0TBzpwwD6wZo1׆$-$# "~7̚5h,Y€qeʔa<=%k@k0h\@_4ͱ01E2صkZɓ'5Zl.NNu:֩CnKVKyz~hm+xs.lI~\xX6l0tڵ+ɓ¿rʀ Zҥv5kִK̎[ngXr^xԏ$>9TQPϛ9rmbV hhu:ʐ5T:/^Dr1ݙ>}:'O6-ĉwFy/ J$$O>TPTz=ΤjYS9k5O%ݿB Hr^ϋ/Ȕ)SP̞=o[9~YGOnr`~Z(fc d&Km2FeNMna+>}ի`F Y____*Udɒlٲ%:[¨W^: ˸ӪV+~:SJ|Jτx)sv/*,X`())NQA8 bSv{6sK-G#NNiD+T5kBy0 Q (pQɉ+d`F)=?eNN$-T"HNիGrr2Δ+W֭[s6oތٙk<53SNI~ J7xr!,G.YB0Nq!1W O8-͒%# (cVl_ŧu:x0%|f~2?"l?dɜa!68X1{-EYÒagcM>>>s| s77&9ٓ_K5kryz=Z xyyeYn˖-j4Dtt48;˩g?5Yzx) w861~xx6ᱚ;!Db9wJ9H6Rқ\qYKtuueƌoXgnC> <\tw_hCFhwq6m?>|rW~ѭ[7RSSMuZ-)))Y>7djժV'Kn}<NG%9s)ü~)J)2,-7'1lm|=*>I|HJgpt.Fd}*bpyNNNα6}b bkz _K21՟ pr믧XO~vƪ7ɭ 1 6֟w1$8ݗ?Ǐg֬YiӳgO"## ?=vh>qp{bu_ٿCq(<G0gި'r75ُ_} #P>}'Cn:4h`1UV[jYfxxxX|( h4Μ9R͛7ӰaC֮]KϞ=x"U!-(u1`QfQfS@' &#t|3nݞVKl%( R3w2_7&鯷}M73-)șرcG%&&@0ooMˍ=Co>mFxxBvx]uIĒKU{_^ʛ8{lE<5*3Wo[(vk8 CNkJz}əZy-}:e{TP ȕkFT|GzjH&Yz%Jڮ>˖.^+?loha3+:^huRC'}wQ˩ĉL[ (2dg'neT"i7ӸFiJel)|3]fo>jY}/eԝHF-|*Hk,=|[*Hоa8ڱp %5MH)fxvGPB)*gݖ^ P&#Wбcg LJXg?GZzY6 Y^y}{s3)#WO:w Jk֭wa͚I/3_}%K.1bm^7*ɯ++mycbw#s0̟!mӱ\S HrrǛ~ƍqm R22(OQ,N^/[2lԽ~w^]*Z)pzǃ?3'\wÇNSdA)=7[sՒwMU~n.Z"-Z)ETD(#g\Guџ28T 7PG,↖] @B'7IڦM.|N4'<}rţ8p99eD+ mT%Š,[%V+W8蚊;Y^ڐ+ʋwkp]|kZ2))]Ů]<5_/]qʮ(uD8gO^|ȧ\Kml4Dӓq}zwq2S*.=ԩPXx'XCE^·#Dny%ӖLcѶEL;{Zhd_͞=L;)CiP4siQV)JZȑ\-FTUie n#pAb+G7\iѣGn:rsEgW_}몀sn=uƉb۸dbZCyy9ףmԭ0\}=1ͩ3}zѫQ@֫~9p.5r p*>]=#'[? PB{#m u9/CiP4sX^A6|wfkyH/ek(7UO.7ҫWn39TM*P2gJwξ}x\qe(Ӈ#Fn6m]ve޽=Uxm<㨪 ={7n<}n(Zk`?Wۨislwhp#3RA"71U|^`]tD"/}5+wPp%d'\zM(i 68( sjYmbGZ赪bCu5Vm܏":aW4Oz=fƌ9.]/ DR|عk&\˳>j^fض-~_lQQeA |h:sgĞ_cѫ<_y@~FlJZa;/f%U+Ci4snw2we~D_ҫǭN9T:thjCDX[W޺u6%煆.Ѐ[I-!%{ZKtt۶m"9YG7K/~72ZK _ ] Y~wV.ti7 g!5CH$. һX!:{ kqVX05.x8kĥ\[om3 v7ߜGdUk!Ɵ SzAo#5)pQq88f㢉׹We˖w0}hT򇹘 jWM" 6FOS~W: gԨĴhAEevHs~챿WgI̘1wH|tI<<.] Dj}5|yEhע]SgNtR^B"H\WO p.Yyú(Y*o\N:<>øΩ Пu60kIǽ %DOmRx7<6J+)MT>iu_cf 2+ 8?oqD5eC6Wq@zƋG8?7lBzz_W4_~^OaJgh*FiphD9tOWZDoOʋ635kgԨjSUNiuM2ʯ~E==ӧ+?mZX,<ԋ33w?f[Xm6~#W\1#Goz/myNQ]ůrI$OcW,wtk 7=DK|Wf]zHnUC,EU_&))ѣbyO6|W;v4̨6Ni͒,GG^ر8vl6h*+,Z%p8ʯ~K_]HqR޽3uMtȲe_h|?~472l$V+e}ȰhgƽzE=WJ#$ IBIE n"sFSko[E0&w%bDR_&]^X, c[ߎhRRD}nݒ{QUnΝw>D gF]z]튒lWwU&I:8w@ddE\Ç0jlVvGPV- +>K7Őe{v&vJJ5 W]uv1P07RPp Cr;qǝdz?\V\H gebMF- ~[Ӈ!C"4Sr^pX,;>xz>[ioO, w0w0*1 U#ѣW1HŜjH"]ҫivb;(jrܽ-ó Xύ%P`3/"g8/Tq26@C3 ~zE!- TU.7qYgO]b9}8+9̍EsI" &Q(IdķQ⌔%㫲!]&нtvz&O+7_Պ 2#'l&; *'//Lq/l3 }ލ'$=K" 8QʩS׃>G-\΄ 迫vUfY#)e04gwW "X]!H!-Jcb%U;W2CH sj?믘 "*eߋa0jyO3/ĉRf_XyJp煦 #d7E""QZz~ȑТE}*Ar ҐU6o 2+ '/l㗹);k$(;U?f!**h|гj婧aw5ʲ0F~,eٸ+BF~%`3$iJwido e D #:u^ (XngAT>]EQXEr84 IM^WK5Gy6 !f hisIvLƍ C%"FDJ;5(}XzJ(c#N{f/tݻȯ4>` Nj(i^;k$i)%!Ɵn~ :o [;sMIE <3pE"i/:ׁo/"Y_'8T([,c$ѹU{R>|U(^}5CSYGHmowID .ȠWlܸ@g^ה*xV+ JzsYC"4C:t8 IDATOPXXD|gð~M(N,TUl*-=|5O1sBgYȹ$ԍ6m۩/k 4~v,Qθ^= +*pՀR̹N(_~ȑ|:n_Grx f}ҥߊԥw*vEAoS!}S(w>wFzaŊ,.P|5M#+k!,G}uO1|S[)ė: @~#nwyjkTRrA͂%Ɣ?_@މ|JUU)ƂξnKIFof(“/Vy8Fq 6~x%ä/"qvTC$ڽ{'EW DfXTSIׅɬxwujڷhOZ|Z"41.*"[nSkX؆WKIY&@|ϑIlg D10E}D"ǐ!)XaԘU ,\I$|HmW[#-tKO̹a&}A8+VlZJ6LZ&#c0)>+>4* "(@Ce֬!={Y\~hZ;tV͘1).M-߁k,e̸ՋZK$_ MG~DiE)-#oiO<\"4|] ץ7"^y-PW]B.p\b3hK~d9XĪ6ZL8))f-(q2Tx zX,*y/1"k|]0~dc_=t6%aW j&ѓdd[nJމ̞ V+ƺhޕ'8*X\q^ϓ`®YkoCe޵;<,CH9Қ9[aS?>%mF1(Ə1~N`tڡ%Ӝ|R|D 1h ZPͱ W_Ƀ\OϏe_ٵ QAS~,P]~%aƟ+Wxb?mJLCʜWR<]vyڋ/TÁ  H ^|W篦uTktV"4bbAXw:>v<3w aWZ@Jo͐dg6 uʯ>`}O]+z=(\uU?f< > bYpzzsp@W-,<Ԯ5WU+ԘHk$=;dspZVbH\:H3潼 ߚJ/BWJUQCz/1^y)MSD :;񞐇^|:TB@5kL}[YʯjO~->O?s;k̙눲)D؃3k.,D7/6ltTybDHfby\zo0bD͛(5j&dk3$(j=8o4HBSIF/<:Zh ڪ0zB^yeqϵ.eiazqlUճ YE݈_ ;v0x`RSS9sغu0fzI>}xWyM}R-DANVdrD8Io6&kNǀsEK0+f+8SrGeMRzk6j蓱"38@-Um ̜_L^?xoK(.to…׸ʜ3=}[O 2+?U6 Vp"!ҦqbԩJP@ 3F \䅐#ޏk/_ iӦqmq7`nf֮]qM7n?~<S$ӷS_gOdծUhI{(I##p!>ؖt J5SEQ5J ަBxQcs+ Vs~DX#=Qw-">0s+hGӥ`DQgP}KN4glIC}J,?R| T'H< ( ҮR[`S54DJ X,q;{A0o>;{ʉ/ 5kwF 8aaVp8 ="8U%;J:2ؽ{7;wbŠDAAnݺ;2qDrss9׿gyON6'NĉCfIc\p `M@Ҡ?>8vر0Fk\u)F2CbujrQ@KI$ p^D7q_tNO9Ecb9fM/1ZBJo X|wΔ)SظԴ’%Kի=z`8quW_Mbb"bk,5}_11 "1y'^΂(~{ބC`Ν`z_ f$vGGR~k&4( sf?| ̹?;tcV̧߆EVVYYY[o㏓@LL g.#==Yfs؍}T+~d{_Ͱd\[乱Oz_j@&б X-Vܝb q-,^0 ު(XK\,,;vw\{ 2>#z!77|o>%%%L<ŋ}vxꩧ\qlذt b.Y-= g)n?'&bW;%^9CAWA/SbpE\6zOnn.k׮O>߿ѣGWتZ/1HNNv7} ”tj! W9TQ `clL}.m{bDP|Djb.N}Q+:n;_}IH\ K|Wb`@b"b=F<767LқOU[6U|mx<7Ou5Jo N^Im iXhW_}5}?U-2(J 5IkOU8wG}D2ϊ]gDL.q;`s>5~kq5+2&. dA ?wYW Vc=G-rs~s= aXu8|y26%oӞ_P\ܴiK.b0rH;OF};ӭ{.4Mcujn/ǡFS+.";XGY4UwQu1 `3pX|wiݺm_ui녤$/wvqϯӴ{:q@{AJwt:m,{tˬ V4ZW~}Dou \: u_+w 欅6-@|+vc!D("e cR~3a4Mc„ } H%7/3FRS~d;Kuy!`\;Q#VM b"࣍).«0c"DW;`G|J/@BBBiѣGn:rssxWh3o>8?<$dTLګp(\$\oށ@1tv=Q)sڳWF_9suFV9jD< Ak5xiϮr^iϲQmxy饗9s&֭c$ƋW5#_Ur~=F<76e磚,Hr^I-Ĺ>1|gU3ppws=lذ2P?GVV7|3?iݺG년MFll,s+nӷo_͛z.M6( }G|7U>ř մ!Lu_bB%PQ)ZD#PgXk) s>1F~!>wu*mhD `; 8Lȯy^V1]v~/,K&:ªX|ps(&:53D1#ύMg(+D$Pձ,kg^f= &MF3wʔ)~0|^yk^0Oz=fƌ9.]7k⒅kg|<:ɯ1ց帝>!CM7v3< ŜӼr./n}|qx4M&33I Ѷh *;kƪU\p#ύM³ͮçv /H oqq1&Lgᬳ"++s9Gy$5 *Q~}_L8 _}![_ǑdV)Ϊ_~o( =\G% 4n 0ul{0,yX"4PHo-қKzSLQ~sehX|#"DmXN;49Ivδl]B.CD׫)zW3K~+;dP 8!*K.k9iӘpUPP4$CH95 vlԽ֯K;y \Ç뮻8쳉`„ Θ&N>F BY Zӂ=is߯/dڳ'z8hTU()5a˖-,[ EQ5j $ơ(,-$e|Ʊ*gu:-چm IC?έVz_8V P~^s*3f?!CpqIE5 I$Abώ&x)$ y ׊*b>'˯_#ʔ)S<*I ŧkğ>]˺_חH5 kCUDI XeRf~ 2mےѣGYt)]&l.Uo7\hs.N,N8锊rXG5_|E$ _I 85Ŝa!ݜsIȑ#xG1bFFv݈Fp 19yy 2(,/4lܸw֭yG6xo>OKu(} ("Q_F~Q I*j'ݨ} !qjSC~S[~m[wZjǎQ`7Fr(|6@6PeŻ5q^D{~W7dOUU[Ұ!o2:U[2g=~}!WR /k6 KUxKo?<JJYfEii)7pGaʔ)XGby"BS9}O'P58*Z!`6iBF~%1+c籸dnؓ;G#Qf_}ט={oEQp8qOR(" \YlDŏZzu"]KzM[xoI X|_u~G?|zӻcolQI mS0HޮHJo"`񍊊"&&*6nBW^-/gB~(@T+}m?>ɯl" y,ym=ɯHP=3ߦρxPC!IjIZ|o~iΒfʝ5JoVjz2Ko&έ4a7>>\ $''WIXLg@_USҫvn)/jUO:J6f55/@vWNT>hZi}!כ'2b4M{?'N $ ->2{yG޾~V:*|p3NדHklGpRU J,jriCzSLmNE#K/ĉͥK.űdɒPMRȯ^)MOe`~ Nvk$zcc_IO~ !_ 8n =N_wU+UoӟOcƌ`׮]=Zo#Xٹwm;YF|%͉I1 tl S>k%+j_/5uI/ᅦ~jX| S^^iDEEaϒu _-:Y d= Ӡmxts n V~>)HUQ]R/"=RO #}/S6~~:-[$tjى-ڳp z^/'ꥷ8tuxgcpM?7JU}JޣKzJfdd("v"#EՊ :t@aaahF(D!9Om .˳a9з,M-w֝G}0#qDxI1B/+/s h%+tCLd~5pRBz~?!C,":#1وjd;nGl(''UUImŧ{$ GE_K46 +:K89DzO^.O\`3- k&N4Jm;77KBMU \Lח*~p'hl%4VUI^=K`߽ytNjPO_[~BS^K…~gʯKE;yoҟ y J$ 4쪝G8ˏK4q?p,*s/BVE.pYp504w:5^#Rx#s=ǐ!C1b#F $?uޖa%:񀪉ylǿ5yLVϤkgT^FI_BlCY!kjd$j_zVE>~.&ItvIMMsa֭UobKK}Q9l8@:K89VJo"`;v,[ne{o;6cjzigul@>pΡx_Qwo~A@$og)PSq**+7l(ہDro;7gGr6mv<|~pB"##]*%m$&֋n:19UuM$Ɗ;x>0 `ɓmtE; 8WXֈB)͏ >>c2f:v1IŽ?๘v~9Էv::D+G 8vŊ#^--G=U Y9jQ(f{_"]ʯ$&)M~vE6L?DTRʣTF8V*x}tڴiqlĉL818o¤ŧhۢ\NSb̟?رc4oB6يr-QHO^-C,I!y7֭c]00Iq e4̝kgd?ނָS.%iޛ^/є+]vAasujl3ԇZvEA(pҥ#+WPZlOfٳ 3f͚5(4Z_߰knh WR;qռ 5Ȝ K9?`޼ULv;kz|ƨ_vQUłiq+Wzj,Y:֯_?/^L~MOr8HOCCÿqv!yI4!|1z)}m4zWyq 6нv`BGm[2R|%5,c H~-G8w4CY2/~ jgʷ0~ Y!_fμsW?gaYQsl'rL1 `qb]qAJl2$UOSx.s6^ ;w5Jdg&""mP9d'瑱G]*++,RSSyy뭷xY9lIJ۔\3۝ILw7qQʇ{}XaV'wMCqE! נ:8vDdNFJDi%KЫW/z9q붟~~ȑ#ٷo/ү_? ĦMBʱ[97!QƆ `Zҥk}DVlݺs_b|)/v:"d|'>Z bSF/V6sWf6Nnw0kxccW9r֮]%\[u]ӍVNoу\֮]K>"O2m4q82b $ӜC<77ƵAz'V.3's:73fFV7 6q+0oM0yd/^IHH੧@UUz^~erssK>}:GeҤI;lܸ^x믿>^5:N #p|TT̚!F]ԩ7xDDrbJ#6,l6JpAҵֵXsK~g/bSGomT:+}~*]e_boiBBG֬YOQQ1+VǸqѮ]w?!Cвe !;}_I#-4Me+P!ύ]K ݨ`;x*:W_=OC)#.5;l2222ѣwq}NN 6 m>s***عs'۷W^ 26lP_o/Mi741ս*@JC>9*+nٲQy=(kn "*[&̙/p+)Z9f`GGB]%g9~WzC_5U}_.KJN~UW]DBȸ~o/RRrb^.&gENw4<:^:>Xz'ˈopbχ+3~z#E!%"fAoU}+S&''W-668G9r?}'N`׮]s ?iIJnkAqE42=#F0iC z=x'JXG^{e{-L EG] ،aQ_sEz-\ln_V~O? CҶp8袛8~dzcGvaV3RN'bq>z\HHiizנ?惛dE!ύa8V &Lfg{r]|?աwҥKvnJϞHa0F.\j%**=Sٱwu$弲dNHp*=ϟ?uYرc?O}E1\9;'fbdֽB1J--dѢ#|<°aCxr (z_})7L梤!Ɩ- I\ w\c}~6>}m.FGcРT<3ygeeS^|݆}h.X[ӾIII,_]\Ww_?qǏ'!Aʅ^ʕ+(//sxfΜIFFFes__J:Q~8TSe{ΥϜ3Zz\ ٻߤ-m FJ7,Zdd\pAGQPQvpͲle,ei- ]Ҥy<49 9. >Ӽy #Fx7h&~g3XdOz,Øh(~z]_O=z4 |3yp:ټlQujx`e8;CP/{!<<'2Ѭ+Wn<$x^YV'6RgyRѣ;v 55iӦY8 ,+ӧӧOի@zz'r+_ؒeE%zՕՁ` l&GN|CNNNuY兏} ?IPPse׮] ˲WN/5j/{X2H_ɂm7=YCpQ9s0ui77WxIh4ƌ{y&Өy34{=5jThA믿o߾z"##oj̛7Dlذ^O.]9s#Y_8V3k\r8gR##C9 m69c:ܷo~a!.\`䄇~!#33QFn:3<6mg}*ފźKo\/2(EAqى_4oތɓ-4r3gfp`^WKEݠOPJldsxÓ6)OLd<õnŵg׮ f-gMiZJ0KLz!I(!y&LPy޽ݻwetܙݻKuƌRT9х>cZu[lڙ^gzɜwK{tK4\!:Fx \Onn[l%..ŋh,^{w<~ilB^h߾=67$ ?T7ߢ+d%뺒ӇbZG'1p^o`Ѣ喝.]ղܐ! ,X#xxxpiqzN D ypyh(ϧC ʨ*ɶ^n{dcىm9x87_k+0S$?n+I(AJTLIbZE'qsr[(&jA&z=9z=_|%z~q!ҥK̘1Hhhew};wi&Ky'd') ͚D^ټҟpc˄Ӈb3 lv~S"K8| ٵk;cP IDATprr믿fذa{nJjj*ݠgt%GvNLY⛜aFFt|?ٙA|w5 D~=hWpT`.NL $<$U;ny&UG3z%ի[4ڶm Hi4 _5~{6EJϸƒYݧo2k)SA&M۷/;w._}ӧOgҥ)23/Ӿ xxJD"DŵnO\.и74'$f:;|||HOOҥK̜9# }j 3)-=$vd}$z#Ml5hIIȲݭ_G3=nw6ƕ k\7(9kؼyf~~~e_wvv*}!^ڡXljEFh]@R[ײ1cݻwg͚5$%%j %11Fh"V\I\.gcGvޓ҉oJf Z[&Lz|c ƀԩ_9|?ƵkY|<QZ.˛(I|M;Q/<>_֞=<HJL]v(:!f I^}|MׯI|Ch4W699#YFt5LRGDDP~},YBBB .h4R ׀)>N_IzEI+2$O5L u~\"+V yğh K@f/>kয়3p@Zedh-ϵQBJio7ݛdYy:'CYxgg&7}ՕPoV:olTJ)R2Rsǘ/,D5w^; 4$--' XrcYIz-I+_{ =ol}לdث=j:\pcQ[],6Vϭ 3KMO ;?ՙ>z{H-2R.&`*kdYwa[n(\ك[kt:잃ިY[ݮgpLe$j0Ӷ#8Xѣ??˻^^^[ggg~[otFђʓWT3B3$S?'bϥ=Q{R4ᵾ32 %q̛ghnnqʓ#> %fevn[2:?@߾ٸ1qOF7xl=(W)IoaV'H[_Lzqc'(F`ݺnn&996mڐ@FIII˫GΒp둝+dAMlvz'i27믿jQJShp WTs%(k~nx47GZyY6߿kf}âեͷNxW.sUTpœߢ}V}:I6X$cر#7~)J)Rw_~7G*^À*#%3j6N! ̜!m~Bݸ$II|E a>t37.z[s\Rk,gyJ̜P_Kꇖ#E38A&N|q 8۳ >%#8=Z3ƞZH^a[V)tJt)5SSH+ҦA~Z~XK꥽w{4sEV [Ѽ~M8~$?ϖ-7 6`xhp {WrKI-CYڮJ%IC1|p.\@F={6IIIaԨQ;wgggqsssPuKcy'sO?,g{Evrw WWwVXAϞ=9{,|wgȄR>-I_Ua -V Q={[rfJLL#55qƑPlwwwMٽ{7yyyL4a:oHH{Ee0チddc͚5 ggg:u*Çw?gx%%g|Es{ 1:䅸)$))5kпFѣG 9&<3f>,~-vSh OOY䌯YVG)DuW>!}ɓj ִ9h4Vg9s&}WDz{=̟1+:H Zh{ԯ__3Y ǐ3B{[֑ge'}_?N=xGK]_qƅ^/Zvvٮ^JjbccYz5/^iӦ[`t ax Qn.ZnMzz:FVR4-[PP?/SNeSN%66®½ѠaO2'))k7gJ:xcd^^O<>><Ӵmĉ:8Z!L$B!jӧ3}tBCC(B_!B;0lVR2RhX!8*!*/yUӃtnJAA ӓ8$=t]t!44xWr+W$<< @NN彭[Ehh(?gΜxb!229sTy/ !4 Y\|3yjɶ|^.]:pO%r411{TƍGBBBerss1b˖-0q СCOIMM_7|p͛Ν;Yr%ٳB~9#YhߔAd(Dd733$ @9y$G-ܪU%$$#GZ&OJJŅ{g}+VpuZ--[$++ K.Ѽys\]]D!jBa:om/u.0~d(DeQOЬYbO:ʆ+DS҆qǎŕ{E(j'[EQ;u\zgiѪe3LɈ՗ Q96R֭[[iG9q-GåKa߾}4hЀ]бcGصkZ'D!}Q!wsd"[DhBZ !BؙW/x7%SFtB"B!XpU`(` !DW!  d`+!" !B8Kǡ瓒 g|8;:ꯥBXHB:oFedG&K(]-̟?_庫^l)˖rk{~?ձؓ iu&5{ qJQbj2$oݩ:[eKKmMZ'ٓ2QUe ڤ|o5!N6S !B8[ǦHFG!j-I|BСCt҅Pٷo_˭\pBBB0`999vTDccFY!$B!D s=Gjj*ƍ#!!21e˖qA|||8qt8k kh:Rfǎ ]lͿWڥ*?VRUeKU_vm)V}133$֬Y@=z4G%88زܪU%$$#G2yBehK\U׺;A:7g=UZWeƺjv,?S5!N6cGUG͛7OG|̛7]򨫏?Cz->>^[k|JLLǎG鏢w_h4eZNkd(DQQRURB!Tff&ڵ#++ VR 6mTR 2sLVZ}ѣ'OtTB!]VB!D Mll,s`ѢEnݺP G;v 55iӦ1x`+B8B!j hԨf͢}?Xb*zH[<<<Ba !B!Rg!B!ZL|:D.] %>>}ʕ+ '$$3gѣaaaDEE1p@Ο?oܹ3DEEѽ{w>\Z?~g}fM-ZD,'Nجl3[nJTT9sŋ&&&ڵkgkÆ ٓ"##ٰaCթS'-WVEKN"::*k׭H/Z˗/{0oC+Ӯev3 Z-+V(u*s.{)-Gqݖןz)BCCk׮"ƒm׮]*Ʒ~>EhRZ6l >>޲5eX%$UsݺuS~RJ N:[&''GhB*=zzWRJeddM6Y}WTBB]6*77ײz*l֭VAAAjeiMh4ҥKeuW}ᇖgϞ[FƌSkݻw7xC%. /gyFؤܜׯ_Wj6){ӦM*##C)ԥKT۶m+]SԶmU߾}_UՕ+WԵkTǎO?T͆ |Mih} eW/RJ)z IDAT쩦MVr={V[*kǎ*,,L+UW\I*1 M6| dyaÆ*%%E)ԝwީ\\\TnnZpj޼0aRJ۷+???U%uyxxe˖٤]/^T͚5SSJ)|}}-ߡ-u._TfffI߃NSAAAnWeu6lؠN:UN m.뺊{eOSO U˗/#rJqvvW}QSNuP8uT5`YUZjŊJ)z[߿չ7##CyzzZ:hT-[TG)?P(ܷo+Q{vh4~ISɓ%nFo[>tjݺ2vիWU&M|6xKL|W^֯_mV٥KTTTT򔭔Rz٢Yf;U#GT&M<6m6lXtj͖cƌwyG=3h4+W۲A_f :T}W6+$Xl۶MY޻|rssS׮]SJ)նm[o հaC hTFm۶xoVI]S_~Mڵ}vR;P;wynWWyehf{0ݢE uȑ 2uٲ]Zn6lX7ovY+-]tiS6lX(Wk֬qDhoS7oLm^ycupB-F |2,]Ν;ӹsg~GUiӦ@XX^ߨT_X5RR#GҬY3ص5k֐СCy'իW-2]رc;ΝW^Kzm۶1x`ƎK^0 U^3gt'ܑN=9}-?;zh^u7onr͟ONNɓlܸfe:u}2}t|||lVnimLe۷?$77JnprrTN+:tٳ9sTfΜieÆ {(Kڵ7_|[[nn. bٲe\֭[3l0Ka.\@6m;w.u]իu5jԈ k1l0򈈈]]lWETU]]s%55Pꖴ͛73f8:BΞ=˻ԩSv+Kףg˖-,Xcǖy {QJѿL‰'ػw/:{,k֭[[iZRŎ:zjǏ:O>ҥK^7Vb#F`ҤIU^uرcAAAi'fƌ<#UfY[楬vk9׳gO_Ή'v;v[dɒ۶&ؼys?i&6m/L~~>/^$<bXRKrrr駟nۯZvzz:?*|uƭ2WtI4hsʕ+\vYfY6VuE عs'˖-cȑ,22UVPPP_"##+]..[hO?M32d?3J)z=?eVl+((`L>>}P^=ڶmKff&r)44EѬY39}4cǎy]?#-[kѢElْT.0SwؤIڶmKppu*.3s_ֿoooZnM+ܮevYsrr",,oޖ*=@FF幹]Jzc4h_~%p;w:~7|5k֔fGٳ}2~jZ/^ȶmۈrThI&[0DغuͶ IMMUwy Q:uR{QJ)[o|a*,,LmVO]|Y)ƍFQ*::ZEGGۥm۶աCաC5h u*ne7oެ:t蠢T՟geR*))IqC*>>^ov`0֭[Whj͚52苟_[\:ߪ &XsoG6lhYWDGGٳgW(???մiS_|QrR V_/wamժU]v*<<\qjÆ .ӧU^TddP#F TYӧO/`e4/ÕNS#GQVm1sCBBTnԩS,-]TĨhڵkg_U>jڴ񱬷l]W\\j߾T-ZPaaa*99Ru=3WWYJzᇕjWu֭Cdd廬h*RWUgU~~~E5kLUYjѢj׮R42{ǎUddRݻw^J-##C=]vJ9t]\\m U'|LJ… O>J)NW{ǹqFuw(>cħQ].B!BPY!B!D"B!BZM_!B!$B!B!j5I|B!BjJi޼9iiivoڵqoNǸq*5lRRR '22#??a Q{;)(ݰaԩQQQՋ ?Nƍy뭷]vlܸcCdd${`t:Ndd$;vdn(+I|Eh4״iS,X޽{IJJgΜ9vAݝiӦ~vM^^&MrtXBT{N !J7uToݻڵ+o6˗/ӱcGxٳ'}eΝ > &Xطo 0n8x H$\/_NDDQQQ꫖:D^'**?͛뮻&**+V/OLL s> 11l&::@\]]ĉvh_Un۶-:VKǎ9~*Dt}:u"223gZqnnn8<<<{ԩHn4hgϞԩSvn%Deddf͚+1ch4ȑ#*..N8p@)T^^T۷oW.\P-ZP7nsERΝ6|ճgOR[]tI)G}FQ,tղeKT5 S?s=?4ZlRJ3g +2e4hRJu)F֮]R~PaaaUaaajҥU$!j궝BܴaզMKZlVǏW7, }N)LɠB6iD:u-[[lCO /p5WR|͛ʕ+Yx1QQQt:yiܸ1K,oQQQO۷xbbbb !={Jhh(w}7111>U#:t`ҤI# ,`ɒ%$%%Yl QXuN !UP(%iѴjՊE:a;1Տl'䌯vΜ9Cxx8v{x#9-D I!(?9+B!V3B!B!j5I|B!Bj !BQ cƌ!((V[hꛢV\Ixx8!!! 0;F)D&B!cqFJ]&77#Fl2<'NcBmΎQΟ??L`` Gz*ǏG4oXHuE![Ů]vUVKHH#GdŖ(ꢪ6fذaC7oCutE]%}Q}1-- 1h/”(겪u6 L_lxxx˼L:՞ab]6l_]{ܪ/[bUr亷,s|[YgϾXy?!9(\%_UUo]pkkynMlX Mۖ9ޒmLm(h|%='t_9O\ ȻG\y7_+-"}f2&WuƖLƍK}źbU_]{ܪ/[bUr亷,s|[ŕ=?W*Apj ABx9-R} }5ѡ]U#'^ڵkj,^$̙QJqw;:L!Լyvc͌1!C|r~m1c3f AAAhZ-oذxbbb`ʔ)R 6 nرcҥ >,۷oyΊ_iéR,=/xrɓ7緄n9:ZGjjԩhZ^^V_W:w̹s&Uĉqr*8((qig ׬Y3F|qoོ~뼵-6pjYGy`[ЏV:b+KX]wbUH>^,z$;G%Dq=ƍkS$&&2ydzEVVaaaݛ2}UbYv-&Lʕ+4_x Ν;nj3n/Ҹqc@>K/?ׯѣի/ɉ4RRReIb:ә|ƙ_k҇D1м IDAT?>/ZvvWJѿLO~\B;ׯK,!66=z/db3ٌh$y-VN08Û`ܴiSm^w^ @ll,]ta͚5>ǣ( -Y} 8-IHHuaر|Gtڕm۶n:L&#|Ih^kxӧi֬;wd̙_Fu gf٠7-붤{L<]oS*,U/ϲ˄!|+85߬]FѺukåK8z(?f @-y Y35k2e FHv{ǐ!C֭]vk!s[,7!~NJJ deeѷo_7o``ټ oߞ={Or7m (a1+ʇcPnr 5kw^$I"));JN:+TWOFwMZf۔ DZsǸ[8q+GcCE7"Թ_!2˗/fܸq 4g駟_̓>JJJJ .ĉۗ0ofϞSO=E~~>EEE| ij<Ł$ &РARSS9r$f:P~},'N΀*Z`%n.PůXL Sz=ޭ[7֭[W*ň^oW$ ٱc.*Ivl㖦k!b ͩ0>{_R%V=um!|+<̞=xqn 6 RTTDPP^f *164_{noBB۷o{壏>"<<̙3I;@DxW:,O|^ Nѻ)zD uޝ\|MnVVx̙31AU}| ^*f9reOddV=Zqz$#B+8zl6}r`0 /pyVXAymlD)l_6lȌ3hM&Gf1h6ʺku>de;k~5?M >(F!jLEf[Iݱcٱc:t`ҤI|$''3fCw5GsQ[)cl7>.]`ňBV0ԬYx0L4irJBX &X?F#o&0x`N[lA2dڿgvO"~!į@ \/WE׫ w@=mҦMy΢E0 ̙D&WQ9 ;ҡA/p\&ii|7;b[( o?Nll,Fm۶9^Ν;ӡCyttHNNf֭>}=>>t !yđ#GWuX!~UoW`@ PH{1+ƢV2&Mh4?~^~e,X@9{,q$E *C[e%X 6E7_ĕywwСĸ+yf֬YϞ={tt5j~5;EފHhP-wlo)WdYf삱f7 ~W xVO?w޼K0m4ի;$''zA}{>k̻Հ< I2Jjj1w׌ dcb vi6s7 69ij2fN >jgP6^jgw,ƕ@ ,87=Pk%#zAYx=r ֭jy$uB8fI,ڷ$Gosʕo}½ e/ԭZWosPWe{ǰa8p={$!!V{e᯿rW[S"ٿHjė[H5ۜr蹣< ks[ e(ᛓ޽{6lt҅5k lrNKعϟgFn:50={{ź̢)m L`T ZmE$i"FCۜ2GeBL!LI9A[AZX|9'O䯿M6zwn*/^lGhێl۾5k`) cįFeQWڜ_m@hԕ ώ\8\r{i?*ÆCقsXPliE\zG l?[ҽU n$>L<[ooEvu#W~?_2~Rj)))DGGE߾}i޼9ٳg /о}{zɓO>ɍ7ިƬYY?^Dj,7n8޵kW>4'$Vk*ժ[G /(f_+~Q5 2LDFFq>~`BwWE_@xgu^-a@c s[!~IR$_UmJ"2ozfI n5oT6yԩ^w֍u֕5_mx6m @VVw}7ǎ];ebX\`wV'vM73Auaɒ}䔝mۨj R9cWh~Ř/ы3Y\>{IDv2*$ZExVd%WYwd{,;ۙwަPg$VZ^СCL&fc<7EUw u?Ec1(@LdOѾ};Ǧх 5j $9;[\pPůvG PE\ME/6+%Mq sىUxMmu㷡Ε b9B||<{AT^qEHHFLBYSXń. ~|_pцqZ4< xbjJRB59M #قshǕ[S@ +|"ݫ7+p9.r#5EmJ~+Ovyңvb#_ѣJ0rrr7n'ϧ{HrՐg bz ~E1Ů^M`cđߖ<Dh 4|_G+QJ *N+pP=U]Ta^C'&&N?)e”PZ}Oł u$>zKOpY~'.;ǠAXp!ꨮا,ZDسŃPOeLeKݻ~b)W﫵=Y-@Pѯ7`,Ӽu4oތի֐j40gY)mMo`%~)]N]x 9["Ǥs=ȑ#=Y~=3gdƍl޼q1nܸ7Ijo~&6԰I6>KGD\BVxw;LH̚5k8w̩S;w.oUqDW,FjUUgM&kќbMvv֠ گ~sx"bl6 &w 7( A=^zz:Ç`>|LupyΜ9Cttt[$5KԥS .-3Cg)D)۷7yq`IܼG~=>LÆ 1`q:t8;;..~&MPNBBBXj^f]ufHM[LzS*|sk 7m*_͚u2J:u裏xʲ}I> 785T#]_١TVc ~pᆎѫ%9y$S9:*k=~A Oګw)睯b& dbʔZ.fsBy'L 3j'0YnSL!33ÇOr=~q._ha6Il0m/d3/c;-JTǗ=/Vwv2t?"=/OBF,YO?f#\,Ɵ@ (/LTp^s^`>̞=|־(@X "z7oΟq|ĉ._~e^~2KW%֯d ?M?9Mk5gz"F/R:)tj=L<2akΝ;Iv!&!cㅶ #S[G Wql:uԽ*f.PC"dLFoӊ;o1qIP3աD`҆?@g@P֨^B=΅ՠs.^EX9Ypy6ˉ 'ؙSoS\~#:[.p"<~U ~HqStҍ]98;wl4R:5mXp!Z5bkr  EȷIi}Sܸ*nSӶ;ZsrŋW9@PxS)g뢃S~=s$qűtH1W<݈nM6zsŤnOV#6EP 'VlL˥0rL&΢/s2łYνȕB Wh'iG>8ѪUs0\i)&؏?Ջ^j(uDyg2Y8t(QJ@zpuZmI1ϦoN)R@l$^ш-(F嗟3OT&&gA{ŕxf1uȚ<>fb`yEZp]9g!~Aε^PMV+-&1ӯ\'O>Ç?Bx qA+,$D&F͸b6ĦcqަJ 4 V,[L]<:Ĺӧ SÝɉඇV;vgEس8VzVY"|Ce7^4obYyI>|:E dYnv }{Ջ^ aDyVɲe0LlC ,N ;)d ۜ3c "kD,IoSƟf3%^<ģ>-dI€25Ez<|U+į PЊ߄0 7,׷Πiܸݻ*g2a$ZLnǏ@$;ƛץ.ǟwJш+ J!&#$$6dH5 Ym䣴8jn'*Z2@9;iLbE-:lr)PF@vދi$ VϪ!hkÞxljh4m6s-Zm۶[' }T=}a!PfiܳZ@Dطo v/$+kgOA掙8KޯuAu!B  IDATǣzkrFnu#ؿ?|\4gc5-JC&| [Yhߠ=F35gaަJ(PGXikeÆt&F\ĥ,vϯ!Csѽk[)Scv܉l&;;[' KJ<VDZ̼yYJ.S]Gq95݉@4Jv{7g< Jk@X*T^ |r${dsfӱ+,6C<9%b{+q'B=l6X 2`@?]v#fs!⒃XאgAe}|rf1S^=鋶VJ*~]vpސHD5iӦmر1%.ׅ|Pk%.B |QPE+[61yg2lXMEC\EoP\C=HN~{j/&TM2B]Q&;Gnl۶6s@U$-.O Ŷ lj'矙={6׿:tΖՉ_pEZ$Iu[fre:uV 1'\p: DPƢs5q񄇇KNN&99LmŋyIIu ^_MxgW0TRS]Lnn.T6&)l ۜbsՃsg;6EP`e_% 낅 6իWKD,__XVV+[B׮]iٲ%m۶>}BWc%ͻIO$22MvsKޝl̞Q$7ڲ 75Pոjg7+rW3'OLǎFAi[!&ntҖޚΉ'_YYDM$XmW q`xO6mDBx5";Qh+dgN:4젷92k,6H*z"(e @(&Y60#BPP_D$]WLԮ]ի3|pbbb֭6l(VVtu_&nKpmc?㏩tlf KܹV_xi.޶Li2%dEEՎG?rm-رcM%1qSL[:sqyg?6'U`.^AeF-p -|öۘxDMsSK2l6zYwr-7!I|W>ڳ0+D{2AY/ZӧO~zڵQEƱʢ-՞:״8w:M&#B& SPw__@i%exGjg4i ]*ww< kE" YwQe˦!{ (z7Ŵi?ܯqg^!+#UO=WGW{!|鏧.J+od|t=qsb4ٶm˹^{-Zжm[z}Q@/;իC͚ʥKya\W S892#B684 C=qwN 4i_?@ ਢw2Uk3 Q~[y?=: MbΜ4{]NŋTh["ms+FB"vdGB¸mz"(#;tP{9SLaǎܹLvvN f< ԑe9rFBF~ӧs AQQɈ&Q\:qKnExJvTTC"Vl=ǝw>C`6"+lFXy,H֮ϖ[d#&9v#y~Wh铡DzK=V|1@F#z,C¾)  l`য়BF_s WJ0l:Ȋw!œvޝ(>.fիWަ?' +WeȐՙ}z{@N}Nw< ,#꤬.4^_bWq8=M뀺6@P~!UCy-kw1thg&ML \tWu)|[:1M!ΙN[d*1lXwj׮oR^pVB5Q@-,oOUi:KoS<ؙ]9ws_oq ~gfϞ /GO2BdMđ;$lL\_M|4nܛS`*FS24Ѫ >T#Ix8}z#lY y,:wIhen:X] ci=-.m/-<A`Ew²2b%d4`#xO9KJJ?W¬Y>}U {|}Gij+ /ZP56EPZXVYn]ҲeK zM(a߱^FY`T>H 1.jH:ujrYd08&>/8-ATbWk0خ;4P4BX /^OI2^?\ھ"5hMEHb< }VWn}aB$O>^Ķ2{L#l"XnSQ9 GͶo6ÃtkܭB~ڵkSzu@LL ݺucÆ :[Mq[ [32 `oew|sԯ_(Nn#%YY  {yM/P {:j_ 2Yv׻,Z MxrگZs("Q  %up:vxy{yTQlk?@J|DuefqJ5ȀU1M4?SRҪ]~{WZg6sG";*ibD z/^Ym38E1e$~ûGkY8v< ɘ|Xն-qb^ExM"o73& &{<I1 H2qQ{`(A` |Ӫn+C:[fgX7%%h۷/͛7waŴiӆ={өS'-+~v+q7EB$#26ģu^&M"DfevqU2Qv]hu$ yk^XnE6:Æ}ọGe8th4S_bǎʹb]-dUn+#ѫ pSnK.y=Y>PO G^AӲnK Ҳ**t T P[ԩS]6+gkʤED=qO6YQ#ծc0x_ijh.p=O gc_fMbS!Y̛lDI ndr.3[ot Ufc=ڏM >Q GKjVKʀ{1+|.+(-WIx '|Fw%|~z|*-W8POu^?_`|͛W=y}Z {= %(VV 7lDh>䭷F#ʂJDc^ŧ Cy4֍WPGXtAUueC+L-A"<2] joF]^2`6R%:g pd$-G6e6v;{ϯ-Y= aР"zJJ4"V ܽ5Ÿ^ś[ eE {7ǎطenKjI@Q1wF5gkG/_;GQ7{7k%)a:#+E#į@P!z9j:'h Yԋ`pW޽{ڵ+-Zs=СC 8-[Һuk>rT_ԖFzJ${+"9І<_LFjɃU2gCN<}7e!F8gkBϠ^DTxVm&i6 {jd(;&gx%tfrP?]ž A,H1W۾^m@ 5*+B].[vY 7+T}]K:~ax̙ȑ#Y~5,3h ^|En0W7j$FyOlL!|+p\Um#Ftheb{oe1=9R[ϯZ@$h>FY$6(GX ( Qo8m*4|F)`SR<<ˁ(`tćպt^ 4 pzÊJ(mgcNJxlaBM·x;IOOg <ÇZ'44!zb2]$LF]tCP~o@z~:-^AQYdd._\g)2_ag(+AZLx=WE@ 2,~?BB>pB%bovAI,q#z PϦ8E/@bصnKӘdAU%%jl2/ZjԩS:t(6lzɓرc9[YۊOB`SPl9[co86m"!"ԹдUm2+V#%U'w:w|ΩvRC) :K T x<+B,8eFH6u4p[KiEV\vw2鸅=t{ʖbzܫ>q.zAIuz%6&(5j٠W#z刎رcH!2q.СCZR < >M6a<>3&{j.XtOM/ `Dr|(Pb:fL_G+ d$\= `\7) 7ϯ[HVD+A`cO[7$+W!&|$|2Vo3@%e痹>AmCIPE{N*LFXsx \ OoR^=:v7|È#3g.a~;>,G%22 T|-@#>"]9h]uG$Y]}Q2!A5$P I.=D%Iֈl6$ziI<`uZ!~2nwc9.ۈc=3K z~,U@_j%zQDZ^yukzC{s$և+[g@UYbT4_,66Xȑ# . LZZo}79obu8P s`&ؒ:r1}9Fa6Т5 [⒟U!~1 ҈^ȺȗṖNѫrs=^60 u[+\vZ0ztEoZq\\9jԸJgpVBtkguVZjE6mhӦ l%EPz['ܧ;!`2Iy>vSˡvKBŢ,bw剽Q`xMbԓ!96SXZL9NHPȸ˛'KR G5i3ו^ r IDAT믿fذa>} |YM\-e;{\2E+ʇn߇z_!C0{lFZxbEvz,W Uz~%Xa@xC8O;ً"x;8G*:;6-{X,oJkd}|t56E^i~7<4,1p߬Mw~/WŌ2eCڮl%gΜ9lٲ:u+p7SOlY 3߶UG 힂n߂ p&(7ϯ)T̃JQ " A׮/ gAѹ+}9UL[. jɐ /.?ɵ:kqfx~#m(C)nUEVZ(\ zߘv/;cp.4~\X|Ǚ?>-[жke˖ȇ~OoXRMZ`W%ؗC:p^Ut.ȥˢ)8{j/u,:{ݻ{;{,/ (U7 p^U8(٢{)J'lceZƣz.zӊ oD [ԪuaVPM)y*~3>/T񘚚Jjj˱\זxc: aBY]Bƾ*z՞Bzh0 ""B՗M›92$K}m+*.\={eB%jUfݑ:FsP,oI(xqz-VX(1e!'OE(b8ʬ$hoqӦM$$x{xc)UQ.P6|E!zbtt4&L %%YϹ:m,F*Dֈ,·-,{ *& ߻ロ$jԨAh`0YQʷT"1,],ŵׯ^žv}EJBYt;FJ8ɓ'?>'O7(D@\W_ &@RKSr ='-1=X,k+8_uOѫ9 {UL0iӦ96|?WK'wЪn2b}裏HHHBQ Wvr'<*㟤 Kl)k@D #2 Aq7PAv(" **ҖBKZZZx4I=yмysMxOs<5C,8Y7X#CrY6"##:uj 6J#~]Zٰz¦nO[,<MD/hQfu*z#|KJ/˗Wv7j%#˽شX| 5 *I _y.${KN|mcx6f[㽅u($(ꋓ&M#%%ϑ#GSz&pmhfVz}-zu,ݻPk162ro'&-&x%nm҄СC믹K~^)l%T ,VEqP]pJGAdুVŰQ`_nj$_ }.eyŋKevs ZR?Z-j#nůB)?/V$eסm (O߾}yyG_?Y 5 Ea 0Bֵ,y7ĦZN { |}}}L.\(ݒf̕6+_(Ͱk@Ms !]֯cHe~Q;VI|Q#~JM>^+nТ'~Ӊ-gDVv&h(bX`:W_}~La6 y l%ڼkmmo+7Bէ҄<&4+%s% O^뺒 SV|Kr+[˩4̙39x W^ڦd, nogů³Ȗmº- {P(x {.H7 ǪLނp?!INN_~Aѯ_?$ REТ~ | 96-N$sm,LL0`RSSyhժwyglfLLL$11ѣG3c %*~#a"0 Z|a!cܢpIDT5MhhZX#e$ie3.ORsڠAR݄{;G ƺ y6 ;ůIC`Q16/zuQP\AoI>S[ůcUpѻX\kAs1潻wG~§h, j?… t̚5KU#٦l^>Kشya_?V6޵hInc@ɂ[;͒"rFD (2*nBw3 S!~oS&Rv&X(PX7[߂~~`Emh/I D UEgkOփKYkroZEށ{P W'\L栛=j;&5@PyYꂛ,(0۳2ZtpoH1,mbY^pH% Sey=d}5ld %Zd{.kI2N3ymB^p e{HB= Owڵm^en(< g\LDq"zk ӇPzÇ =z>L:uiQEdvMYf4[!BM@V|b`[U G=eW\|lQXkX1 'Nw[!MM t݌C+_Wwm߯P(hܳ@dE(|}up|$i|^f&j3uF ,h57['=&=AoD/ծx=`Ɨ u}`{ZKh|qD[4i=_Yz5Ǐgn]f \gk1# 1i1tj&{BȟusHm%x)Xr ^أ;V{ x^m# ЬA 4;hI$xMUį,pUoj͎c 99YѢ?99&._!dR'$ Xw@5ӳ`ѻzV !.#م0mZNݹCFg#prW7Ν;Ǿ}uGɔ)SHHHhtIII7`֭|JrYIw+T?D ݪu%QsO%KB=(n9=23n'z J&t`PZ#NjoMx'iH3f cƌ\!B1Gڴ( Gሇ=jW(;˖-cٲeN˵MB)(DZmUhHA|:a- j:v>[}C7Hby[X*P۲ca|dV^TZ%۲ߨc&(EFo??[:qe>G^ziMf;|TM@$'x )Y9:8c`q} zoO$j엜9KhD[MI,jp+z'PWDomO?%((뎹s֚l#3Os5*~u +V|'۔- &p_E %v!C[,+E >"]l@V:Htt ,{Qm-$}h!i 6aFPWEal+_ gGW(1Ezyyb&k/]]3?\`&!kn%;;5z- }U_p4qp#p BTTkG@ڷk™cithON /YDoytޝ%K0n8V^M```0K:=:t||=&|cRc[. =bOވJI٧٧ &2>o>/Mg| ;̟֪Q:|s;/ЮmLmel nVAPuq]-7ZاIIǟac||NK^;̜9 XH9h6D !}0X,{q4g706:r{3~xfϞMÆ Yx13f̠UVL4){$sۣ b$N* "|2*~$2BK#~p oχ7vL{BR3wsq_3иV7Oعsg㯽Z1٥j^'QGoL2+G ΫFiį/ZRet_ ,_4{ieM^B{%4ظ- //=lXa*m0ώE U !b7fGp.m E)NՎկ6l]^@:thx)ٰ1 ֑\}qBI/z߈f -Z4[tlل 0}0~ ذ!MXN+/=#uhnEQFi n7c_$v~u]uM+ϒSҬ7)9hwa|z ^Lf6^$33ݪ>E[}߯c}M@~h׷cp`o p:e,IZӧSW/-C+Wzŋ?}'Ox,/J1଺͹L [AK߬ᄗdЦuǟp횉)SS:MzlVDiviDJ B-iGlfryY<}Quk`\߲EhoXuRmEkZܱck^M7p,ڷ"'~)S^\ 6?V8+TUk0-5G9iiǝ(Xr&q0~:'r'Wfs5ZjKg8x3v;]E#49|g1aV-4}]Ղ+%>G)U϶RH!W0:d|_?פ0,85UfݺhhҚzʺJjde]ḗY5ICe`.T\'_u&O9iA"0m6|*1gΟOd2q=w"*j9t҉ENvv6 ~ԩ. ﷷ 2%WEt/z3a||K⦛1hsL|7Dp)ygYY %O0 'm ^A(#YY^Iye^{wBuGP+b=2>7vYي-ұY'f< ^cȐv o1˭_3 m'> j-uģ+`vvk@ UG"~EhU[>&#V@%ަiγo~O |֭,_G^_'77VT \\y2VX! `W%(H:vlGLQVC2dH>x=s,@ӱI)M"|En;c@^A()F,|cb11xkB @PN NTo%]Sn)99ל^׿>#05W/[Ksնm K~C3^bဗf[=e F6 Ѕm *یP֫\oֳ>ri?gп-v иq+233 2&M~z\¢9`CGYX7KKPBBFN>CGn J(8]m^g_D .&pcd+&-NMe_)(Qؗ/mPmuu:(-uƍ;HN>CPPK.zm9™3hԤ O<8:믻hN^b! ܘ:%p]!BUZNP8֌WE |09pw~}ɓ'ȠyOt~$>=aa+䡉ޘ/ayCuV0vGHH0KFpjqXJRl8^Ħ #V ugD BIiݦ˽@_(,-2_Gh+{ mÌ4ꀆJ.+Rpc޼1-xyy{̙`0ؿWJTXb5'OwL&Acp|U,$$q-"ta"$Uo%/Mrm$$$b4Ю]f3o]2uTz=;w AI,[Mڶ/_N]ø:^^L&f̘>+Wfƌ8mqO|W|t5[xxkhH^0yטc>,$M^ɽBRz N*w׊gSh|품_gfN0hD.]S14]?c))) 4\իDŽ 矇_H6gq==>7@V*àߺ ڊp`2@'71ՎݡfN  >5m; A=,^wy(>S}6o>J6/O&OcZn:h n o_s7CѼyS7Dg}- ٶ "zD-#珠PRHp]uA('z<@,Uk ̺aDxfڃu{0O421[ =z9y4\rNB?!\|Mv͋/hO1/BÇ Y,@$?6TĀZ}u|Aa&iasL۷}} Ƒ3k;$@^H^A(WBYƤRHpFP8pCaHn *~</)h+F@#Xr=7вe;߂;w ;#,6o˙={6>>>̜9hڶmZڃ_(~G9-ɏom"x?.h"?2x |M, [ld21qD.\ȏ?;ϡC_>͚5#%%ƍx9 ʅ y1b7&{ FhҤ1=;r}L,38b6ڵz". WcNp| |,-균o#LHPEpH‚m{ ʥ kxfqmai|,ϦR0?ѣ;"7Xf-۷'77˖-cĈ9s˗/ /йsgv;,dϧ2 %$$!CFS;JPpKLgKnM[lgLDGG3d:w 7-⮻O>bPN,X>``׮]DEE󷿍%0ք?n'@֭yw?xD UAaPbfB'%؜Koa{Yl߾N:ѤI^z%f3m۶e̜9+Wo>xiժ3f *p6bfeFx-[رcYp!~~~ 8@^zUאv_&++%KR oenY J]!W [-߄ i n 5B`g y (ΊS`}_lQڵvݻvS-t_E/hW_}}{n 7Lj%F~AϥK_[=}?O߾}F… |{$&&VbOSĔ-sv6](s=M^nnbq=駞E8p@{])Ǝ]tk׮>|8FP[|1"b biӦ1`M=z? pwӽ{/yd_̑G}{&TwD Ub_2m2,Yױ& @,o+B׳w^RRR&++]:٘={6=zݻ{n6lȑ#tc֬Yյ*B߾gU.7x#NbKzk'[Wզ%laѐ bMF3Tq lO||4f_6bVϏH8@ǎ6l/2QFb mo^l6cbs0#%py]Ocn\j{<89)e$ U)@nuiùEfv}=)%8 d[ J>7#GX,74nܘ]v1zh]͛y㏱X,L&֭[G~^#77z;ӧO` :ЁO>IFΉ(ƌØ1cʻ{Bْ9 knB泶I*7bԃo[ع ?ѣ,^_~٩{%&&]+wײeXlӱJMmvb~qdffsN~ikRR=z 88Wb6l[dp1w+[j(LH@3;ǤIFg=V֖p. |[ގ"q0툻Oj` fi&ZnM֭裏"<<.%%%믿.zyGy7xTҥKYr%۶m+sҽ{ ]vۄ;!lquu:/W|3'3gR~}&NHݺu8q"[WywqQ~]}bOF8s >(SN>E̙3DRvBn u[HfLUEpFSƦR߻>mxWBu %8#>KvV"i ZrnlC{|8}bƍ 6!Cp 70`[zѠ AJꏯPJ9-p4-sI'|-9K('nl!Ѯuq#\^>Dk;a;9W|;wi[.׮]=z흳XNObJ䪲BRWX+–-[hFf^k'Crjŝxc07j|s&aÆl 56W(54i̕+ڄu֥L>^ztR~'fґC"+c .f__2 Ǝ{8P T N!%t tTn ;O]Ϧc6+ #F`ʕty3aB>gTdHפIHIIashٲ%w}-[иqnbBu]賋:*rWVMŴiB7|NϞChԨo&<qqqLiS_~%׊ Tel%/&H*MeXa5S#oM U6&a 0jŷ}x{ySLP6 H%WEvMu/ 8c 0:fuCf,G Kno[T  c$L}$KLj cƖsτ_AGiXAAO(2s2$m-.s"$ D   ƱQqo\Z2 D_AAN||<}!44^zq|r-tԉnݺ1a{-jF;_ D  B4i=qqq<?>9~~~̛7IF31cxUcS~/ֹ1i1 h;{$xe˖l2cڦ_AAA@]{ ߲"%TSd   :s|_{5cǎeر٭jMͨW^+i1tlNWA=#+  BCi% /i$ WAA*IH@H|R_A(    TIBgɐ_HD  P%162r<8eqzLdt_AAA$#8y11ס]v3!WAA*QAαcRF(   TI6j ,|cR%P2q'j+|+AGPiݦS#)nmn*SKyo[,S'}+=UEySW羗7"| !Lu)-vkU޿: _^ވAA2O>} W^>|yׯSNtЁQFY=ډ_AAA(#&M#..;L8h9BV5KBE WAAsطoQQQ9'~YIDATNtކ ޽;:t`:tT6svv6111+K+m~ i^˶-5nu2{CU8Sx Zl^)t:HNNh4KNN&((<883g`X`:tRCtvA'Q[GxݫBCCKmݺ;C&Mdl_<7tRڶm_ewG*l"|AAA3AAAj4RӧOBCCիv{ԩ:t`ԨQdffpiLǎ gѤUHYYYݛ4hG-v1czCUgIdd$;v쨰/^رc k׮nmۖ&M̷~K=婧r{իWܹ3vZÉsL6 _}t֍nݺ#vC>}W#F(͢oߞ/ȶ#)))9p:w̻[j[>};0:w?”)S|Ϗ>=Xz5aaak!))c+OڵpBCC8p Of"""_T}p sM7詾=֭[(ԩS )Ѹ" %""/;vD+ gϞMǎ"::~ag۷/{m۽Glذ}wwxyySPhJcϜ9P¸<޽{ݭ[7z=Gm6ze3e={p7nZ*n)\U?\)ԪU 7ܐLuuש8RSLQӦMSJ)va?wڴijҶbQ/_Gqޮ]v;S#{mN.]T<;c~ kۑ)SS̑#G/|IPTddGfffvիZ|GlرC(tj߾駟lɓjjjkQvgեKuz쩾ٷW^yE)숈P{)-GgyF)lVC Q+]GΞ=weecǎ̙3J)._\Uޙfծ];o_R{])Ǖӽ2wդIuaR۶mS]v)Ԗ-[Թs+c2m6uIնmb+*ojÆ |߿W vޭTUttRJׯWm۶t߿jРX,okW^Vs-;/ܹsըQTnnRJ^SYj N:oF)5o\xľbQ[V[lQJi㕠 uwG)))EhB;v+V8 Ç6mڸrbzmŢfΜYTYYYW^ĉžAymNZo<U*]vUԩS=2y믫ob+W[n~o1b;V}'WݻUǎedd(___R}_~QJ)uAզMgաC'[~9*ފkHIoEM)S*QXR #f>ÇWhۃ e˖|WET='OM6E~ ""gy+WTHۇM6gϞ <T-̯]vvM&==>|+aaa\wuvmzpa~W q۞ĉ۟nK=/QJiӦK-ܹ3Æ +]G/^̄ ?cvVZ`t:m<@bbGlfddºuݻ7{fŊʉ'_y1}tر#gϦyݴiSZlʕ+-9..c[j-.q'OI&<͛9s cǎ塇*v7mDrr2ƍ(3'''~vIjj*ӦMM&wf̘1ݻzaÆa6˽mG.\AxerM7ѬY|͛sԩB;eONӦM=jCq oW_}1'Od̟?VZynA,vE;pe"##;v, ˫LvO3.7n{J)FoMRR'ӧO'&&#Yhݻwޣo߾=ܯr5!00>ӧQJ  bӦMǏwYmSSXn] ڏĉy뭷ʽݭ[~BBBmw`Zٶ\n]k uտ!Cp50ٵkk׮-3Wl"aǎرg}l.\@N)]G6mʨQرc<@ Z2oW^yQFُ{ue4zqxbߏ=]v-=Eݺu+ .DQ~}F֭[*pBƏ_sQ5j>>>9_mTU<[xeffr%ZjŁW}gϞiӆ0pJhIp~'@KԲeK:w\!}_Y_bݺul޼___~˙5k[lYf'>>ݻ޾}8s 7ߐƬYlpp|ygx"e۸qcׯo_ ofϞ=SJg{fjj*QHH{fǎt#m9%Bܹ3]tZۼyswΒ%K-f```>3x`O\\-3ԩS9vk֬),'NIIŋs/_N޽˽ٳgsIILLM6lذP멶˗Gm~wv h7nƢE9r$E~暄[W_}EΝKf}… ޽RvZk^&5kF@@=rZZv*=رgϞ'P~} P& :M7ݤ:tn(zWl?믿V;vT۷W#FPJ)o߮t:ܹPjȑݻUdd Saaa{UN*v])I믿0t׿/VHJ)o>u70իW/{hl6o^c88W%`ZT (.fWn*ĤA,F>4(1ŔbĚB j xK4 $*K5(rQ RLu\X9$3Ϟgn_(&M___1o|qѹsVm6xoe9ggg˻ᆱ+f 9nccF'h9W_}%.7oоx?,%IIIrAzݻw%55UTUh_4T7J~~DEE(nݺ~i,psY$%%Ee'O"fYTU2/''G_>W\ŋh4ʸq$$$DRRR3zj1%SNΝ;b0d̙{Μ9w~h4ʴiÇ.%|S:O>s犢(bX$99(UYYY~ӛwuuI||*… n,VIKKEQDQ~/ om6$%%i-KʬY$""B.]t*o'""""""r#oݭDDDDDDvaKDDDDDD/y4DDDDDDXGcKDDDDDD/ I`` n߾=b۫DRRbbb( \Aw"[}}=UUj*twwvZDnoI"ۧ~hTp[nE\\"""`ِUUqe@UUEAff&TUE||c,]t$Gܩ$"g?zzzpAq8G}'N 88!!!.Ζ _>/^|m~鍱n߾\ n둖HA4}ǏaZ/M#l6݋j/|,oǏk0cŠ+ݻwSK.w'uVGdB@@.\}tLL JJJ~zx{{l'3ośnիW遷7&Mׯ_G[[>C455fz{{ֆxyy!88"}9md2!<<k֬Ann>ɓ'ZXh6o<&#\= i$@@@cy:w'&LG o`( n޼Oϛ7v)NII v;jjj84~ Bqq1a6qu gϞEyy94M(Aww7PQQ7B4… PUAbb"OZvv6^xe˖كbb`#+܎jddBrr2,~L f$;66;vG; l9s~ϫwAcGP=}xe˖NPUU7ގID$Q/{!** .]3D##DcI"_""""""hKDDDDDD/y4DDDDDDXGcKDDDDDD/y4DDDDDDXGcKDDDDDD/y4DDDDDDXGcKDDDDDD/y]ZiLIENDB`lmfit-0.9.7/doc/whatsnew.rst0000644000076500000240000001436313066042256016724 0ustar Newvillestaff00000000000000.. _whatsnew_chapter: ===================== Release Notes ===================== .. _lmfit github repository: http://github.com/lmfit/lmfit-py This section discusses changes between versions, especially changes significant to the use and behavior of the library. This is not meant to be a comprehensive list of changes. For such a complete record, consult the `lmfit github repository`_. .. _whatsnew_096_label: Version 0.9.6 Release Notes ========================================== Support for SciPy 0.14 has been dropped: SciPy 0.15 is now required. This is especially important for lmfit maintenance, as it means we can now rely on SciPy having code for differential evolution and do not need to keep a local copy. A brute force method was added, which can be used either with :meth:`Minimizer.brute` or using the `method='brute'` option to :meth:`Minimizer.minimize`. This method requires finite bounds on all varying parameters, or that parameters have a finite `brute_step` attribute set to specify the step size. Custom cost functions can now be used for the scalar minimizers using the `reduce_fcn` option. Many improvements to documentation and docstrings in the code were made. As part of that effort, all API documentation in this main Sphinx documentation now derives from the docstrings. Uncertainties in the resulting best-fit for a model can now be calculated from the uncertainties in the model parameters. Parameters have two new attributes: `brute_step`, to specify the step size when using the `brute` method, and `user_data`, which is unused but can be used to hold additional information the user may desire. This will be preserved on copy and pickling. Several bug fixes and cleanups. Versioneer was updated to 0.18. Tests can now be run either with nose or pytest. .. _whatsnew_095_label: Version 0.9.5 Release Notes ========================================== Support for Python 2.6 and SciPy 0.13 has been dropped. .. _whatsnew_094_label: Version 0.9.4 Release Notes ========================================== Some support for the new `least_squares` routine from SciPy 0.17 has been added. Parameters can now be used directly in floating point or array expressions, so that the Parameter value does not need `sigma = params['sigma'].value`. The older, explicit usage still works, but the docs, samples, and tests have been updated to use the simpler usage. Support for Python 2.6 and SciPy 0.13 is now explicitly deprecated and wil be dropped in version 0.9.5. .. _whatsnew_093_label: Version 0.9.3 Release Notes ========================================== Models involving complex numbers have been improved. The `emcee` module can now be used for uncertainty estimation. Many bug fixes, and an important fix for performance slowdown on getting parameter values. ASV benchmarking code added. .. _whatsnew_090_label: Version 0.9.0 Release Notes ========================================== This upgrade makes an important, non-backward-compatible change to the way many fitting scripts and programs will work. Scripts that work with version 0.8.3 will not work with version 0.9.0 and vice versa. The change was not made lightly or without ample discussion, and is really an improvement. Modifying scripts that did work with 0.8.3 to work with 0.9.0 is easy, but needs to be done. Summary ~~~~~~~~~~~~ The upgrade from 0.8.3 to 0.9.0 introduced the :class:`MinimizerResult` class (see :ref:`fit-results-label`) which is now used to hold the return value from :func:`minimize` and :meth:`Minimizer.minimize`. This returned object contains many goodness of fit statistics, and holds the optimized parameters from the fit. Importantly, the parameters passed into :func:`minimize` and :meth:`Minimizer.minimize` are no longer modified by the fit. Instead, a copy of the passed-in parameters is made which is changed and returns as the :attr:`params` attribute of the returned :class:`MinimizerResult`. Impact ~~~~~~~~~~~~~ This upgrade means that a script that does:: my_pars = Parameters() my_pars.add('amp', value=300.0, min=0) my_pars.add('center', value= 5.0, min=0, max=10) my_pars.add('decay', value= 1.0, vary=False) result = minimize(objfunc, my_pars) will still work, but that ``my_pars`` will **NOT** be changed by the fit. Instead, ``my_pars`` is copied to an internal set of parameters that is changed in the fit, and this copy is then put in ``result.params``. To look at fit results, use ``result.params``, not ``my_pars``. This has the effect that ``my_pars`` will still hold the starting parameter values, while all of the results from the fit are held in the ``result`` object returned by :func:`minimize`. If you want to do an initial fit, then refine that fit to, for example, do a pre-fit, then refine that result different fitting method, such as:: result1 = minimize(objfunc, my_pars, method='nelder') result1.params['decay'].vary = True result2 = minimize(objfunc, result1.params, method='leastsq') and have access to all of the starting parameters ``my_pars``, the result of the first fit ``result1``, and the result of the final fit ``result2``. Discussion ~~~~~~~~~~~~~~ The main goal for making this change were to 1. give a better return value to :func:`minimize` and :meth:`Minimizer.minimize` that can hold all of the information about a fit. By having the return value be an instance of the :class:`MinimizerResult` class, it can hold an arbitrary amount of information that is easily accessed by attribute name, and even be given methods. Using objects is good! 2. To limit or even eliminate the amount of "state information" a :class:`Minimizer` holds. By state information, we mean how much of the previous fit is remembered after a fit is done. Keeping (and especially using) such information about a previous fit means that a :class:`Minimizer` might give different results even for the same problem if run a second time. While it's desirable to be able to adjust a set of :class:`Parameters` re-run a fit to get an improved result, doing this by changing an internal attribute (:attr:`Minimizer.params`) has the undesirable side-effect of not being able to "go back", and makes it somewhat cumbersome to keep track of changes made while adjusting parameters and re-running fits. lmfit-0.9.7/INSTALL0000644000076500000240000000076513066042256014617 0ustar Newvillestaff00000000000000Installation instructions for LMFIT-py ======================================== To install the lmfit python module, use:: python setup.py build python setup.py install For lmfit 0.9.4, the following versions are required: Python: 2.6, 2.7, 3.3, 3.4, or 3.5 Numpy: 1.5 or higher Scipy: 0.13 or higher Note that Python 2.6 and scipy 0.13 are deprecated, and support and testing with them will be dropped in 0.9.5. Matt Newville Last Update: 2016-July-1 lmfit-0.9.7/LICENSE0000644000076500000240000000632513066042256014571 0ustar Newvillestaff00000000000000Copyright, Licensing, and Re-distribution ----------------------------------------- The LMFIT-py code is distribution under the following license: Copyright (c) 2014 Matthew Newville, The University of Chicago Till Stensitzki, Freie Universitat Berlin Daniel B. Allen, Johns Hopkins University Michal Rawlik, Eidgenossische Technische Hochschule, Zurich Antonino Ingargiola, University of California, Los Angeles A. R. J. Nelson, Australian Nuclear Science and Technology Organisation Permission to use and redistribute the source code or binary forms of this software and its documentation, with or without modification is hereby granted provided that the above notice of copyright, these terms of use, and the disclaimer of warranty below appear in the source code and documentation, and that none of the names of above institutions or authors appear in advertising or endorsement of works derived from this software without specific prior written permission from all parties. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THIS SOFTWARE. ----------------------------------------- Some code sections have been taken from the scipy library whose licence is below. Copyright (c) 2001, 2002 Enthought, Inc. All rights reserved. Copyright (c) 2003-2016 SciPy Developers. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. c. Neither the name of Enthought nor the names of the SciPy Developers may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.lmfit-0.9.7/lmfit/0000755000076500000240000000000013114357470014672 5ustar Newvillestaff00000000000000lmfit-0.9.7/lmfit/__init__.py0000644000076500000240000000427313066042256017010 0ustar Newvillestaff00000000000000"""Lmfit provides a high-level interface to non-linear optimization and curve-fitting problems for Python. Lmfit builds on the Levenberg-Marquardt algorithm of scipy.optimize.leastsq(), but also supports most of the optimization methods from scipy.optimize. It has a number of useful enhancements, including: * Using Parameter objects instead of plain floats as variables. A Parameter has a value that can be varied in the fit, fixed, have upper and/or lower bounds. It can even have a value that is constrained by an algebraic expression of other Parameter values. * Ease of changing fitting algorithms. Once a fitting model is set up, one can change the fitting algorithm without changing the objective function. * Improved estimation of confidence intervals. While scipy.optimize.leastsq() will automatically calculate uncertainties and correlations from the covariance matrix, lmfit also has functions to explicitly explore parameter space to determine confidence levels even for the most difficult cases. * Improved curve-fitting with the Model class. This which extends the capabilities of scipy.optimize.curve_fit(), allowing you to turn a function that models for your data into a python class that helps you parametrize and fit data with that model. * Many pre-built models for common lineshapes are included and ready to use. version: 0.9.5 last update: 2016-Jul-26 License: BSD Authors: Matthew Newville, The University of Chicago Till Stensitzki, Freie Universitat Berlin Daniel B. Allen, Johns Hopkins University Antonino Ingargiola, University of California, Los Angeles """ import sys from .confidence import conf_interval, conf_interval2d from .minimizer import Minimizer, MinimizerException, minimize from .parameter import Parameter, Parameters from .printfuncs import (fit_report, ci_report, report_fit, report_ci, report_errors) from .model import Model, CompositeModel from . import models from . import uncertainties from .uncertainties import ufloat, correlated_values # versioneer code from ._version import get_versions __version__ = get_versions()['version'] del get_versions lmfit-0.9.7/lmfit/_version.py0000644000076500000240000000076113114357470017074 0ustar Newvillestaff00000000000000 # This file was generated by 'versioneer.py' (0.18) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. import json version_json = ''' { "date": "2017-05-31T14:11:22-0500", "dirty": false, "error": null, "full-revisionid": "c2b7ea15507baf2032f497441de917e505c6b784", "version": "0.9.7" } ''' # END VERSION_JSON def get_versions(): return json.loads(version_json) lmfit-0.9.7/lmfit/asteval.py0000644000076500000240000007250613111710636016707 0ustar Newvillestaff00000000000000"""Safe(ish) evaluator of python expressions, using ast module. The emphasis here is on mathematical expressions, and so numpy functions are imported if available and used. Symbols are held in the Interpreter symtable -- a simple dictionary supporting a simple, flat namespace. Expressions can be compiled into ast node and then evaluated later, using the current values in the ???. """ from __future__ import division, print_function import ast import math from sys import exc_info, stdout, version_info from .astutils import (FROM_MATH, FROM_NUMPY, FROM_PY, LOCALFUNCS, NUMPY_RENAMES, UNSAFE_ATTRS, ExceptionHolder, ReturnedNone, op2func, valid_symbol_name) HAS_NUMPY = False try: import numpy HAS_NUMPY = True except ImportError: print("Warning: numpy not available... functionality will be limited.") class Interpreter: """Mathematical expression compiler and interpreter. This module compiles expressions and statements to AST representation, using python's ast module, and then executes the AST representation using a dictionary of named object (variable, functions). The result is a restricted, simplified version of Python meant for numerical caclulations that is somewhat safer than 'eval' because some operations (such as 'import' and 'eval') are simply not allowed. The resulting language uses a flat namespace that works on Python objects, but does not allow new classes to be defined. Many parts of Python syntax are supported, including: for loops, while loops, if-then-elif-else conditionals try-except (including 'finally') function definitions with def advanced slicing: a[::-1], array[-3:, :, ::2] if-expressions: out = one_thing if TEST else other list comprehension out = [sqrt(i) for i in values] The following Python syntax elements are not supported: Import, Exec, Lambda, Class, Global, Generators, Yield, Decorators In addition, while many builtin functions are supported, several builtin functions are missing ('eval', 'exec', and 'getattr' for example) that can be considered unsafe. If numpy is installed, many numpy functions are also imported. """ supported_nodes = ('arg', 'assert', 'assign', 'attribute', 'augassign', 'binop', 'boolop', 'break', 'call', 'compare', 'continue', 'delete', 'dict', 'ellipsis', 'excepthandler', 'expr', 'expression', 'extslice', 'for', 'functiondef', 'if', 'ifexp', 'index', 'interrupt', 'list', 'listcomp', 'module', 'name', 'nameconstant', 'num', 'pass', 'print', 'raise', 'repr', 'return', 'slice', 'str', 'subscript', 'try', 'tuple', 'unaryop', 'while') def __init__(self, symtable=None, writer=None, use_numpy=True): """TODO: docstring in public method.""" self.writer = writer or stdout if symtable is None: symtable = {} self.symtable = symtable self._interrupt = None self.error = [] self.error_msg = None self.expr = None self.retval = None self.lineno = 0 self.use_numpy = HAS_NUMPY and use_numpy symtable['print'] = self._printer # add python symbols py_symtable = dict((sym, __builtins__[sym]) for sym in FROM_PY if sym in __builtins__) symtable.update(py_symtable) # add local symbols local_symtable = dict((sym, obj) for (sym, obj) in LOCALFUNCS.items()) symtable.update(local_symtable) # add math symbols math_symtable = dict((sym, getattr(math, sym)) for sym in FROM_MATH if hasattr(math, sym)) symtable.update(math_symtable) # add numpy symbols if self.use_numpy: numpy_symtable = dict((sym, getattr(numpy, sym)) for sym in FROM_NUMPY if hasattr(numpy, sym)) symtable.update(numpy_symtable) npy_rename_symtable = dict((name, getattr(numpy, sym)) for name, sym in NUMPY_RENAMES.items() if hasattr(numpy, sym)) symtable.update(npy_rename_symtable) self.node_handlers = dict(((node, getattr(self, "on_%s" % node)) for node in self.supported_nodes)) # to rationalize try/except try/finally for Python2.6 through Python3.3 self.node_handlers['tryexcept'] = self.node_handlers['try'] self.node_handlers['tryfinally'] = self.node_handlers['try'] self.no_deepcopy = [key for key, val in symtable.items() if (callable(val) or 'numpy.lib.index_tricks' in repr(val))] def user_defined_symbols(self): """Return a set of symbols that have been added to symtable after construction. I.e., the symbols from self.symtable that are not in self.no_deepcopy. Returns ------- unique_symbols : set symbols in symtable that are not in self.no_deepcopy """ sym_in_current = set(self.symtable.keys()) sym_from_construction = set(self.no_deepcopy) unique_symbols = sym_in_current.difference(sym_from_construction) return unique_symbols def unimplemented(self, node): """Unimplemented nodes.""" self.raise_exception(node, exc=NotImplementedError, msg="'%s' not supported" % (node.__class__.__name__)) def raise_exception(self, node, exc=None, msg='', expr=None, lineno=None): """Add an exception.""" if self.error is None: self.error = [] if expr is None: expr = self.expr if len(self.error) > 0 and not isinstance(node, ast.Module): msg = '%s' % msg err = ExceptionHolder(node, exc=exc, msg=msg, expr=expr, lineno=lineno) self._interrupt = ast.Break() self.error.append(err) if self.error_msg is None: self.error_msg = "%s in expr='%s'" % (msg, self.expr) elif len(msg) > 0: self.error_msg = "%s\n %s" % (self.error_msg, msg) if exc is None: try: exc = self.error[0].exc except: exc = RuntimeError raise exc(self.error_msg) # main entry point for Ast node evaluation # parse: text of statements -> ast # run: ast -> result # eval: string statement -> result = run(parse(statement)) def parse(self, text): """Parse statement/expression to Ast representation.""" self.expr = text try: return ast.parse(text) except SyntaxError: self.raise_exception(None, msg='Syntax Error', expr=text) except: self.raise_exception(None, msg='Runtime Error', expr=text) def run(self, node, expr=None, lineno=None, with_raise=True): """Execute parsed Ast representation for an expression.""" # Note: keep the 'node is None' test: internal code here may run # run(None) and expect a None in return. if len(self.error) > 0: return if node is None: return None if isinstance(node, str): node = self.parse(node) if lineno is not None: self.lineno = lineno if expr is not None: self.expr = expr # get handler for this node: # on_xxx with handle nodes of type 'xxx', etc try: handler = self.node_handlers[node.__class__.__name__.lower()] except KeyError: print(" lmfit asteval node handler error ", node) return self.unimplemented(node) # run the handler: this will likely generate # recursive calls into this run method. try: ret = handler(node) if isinstance(ret, enumerate): ret = list(ret) return ret except: if with_raise: self.raise_exception(node, expr=expr) def __call__(self, expr, **kw): """TODO: docstring in public method.""" return self.eval(expr, **kw) def eval(self, expr, lineno=0, show_errors=True): """Evaluate a single statement.""" self.lineno = lineno self.error = [] try: node = self.parse(expr) except: errmsg = exc_info()[1] if len(self.error) > 0: errmsg = "\n".join(self.error[0].get_error()) if not show_errors: try: exc = self.error[0].exc except: exc = RuntimeError raise exc(errmsg) print(errmsg, file=self.writer) return try: return self.run(node, expr=expr, lineno=lineno) except: errmsg = exc_info()[1] if len(self.error) > 0: errmsg = "\n".join(self.error[0].get_error()) if not show_errors: try: exc = self.error[0].exc except: exc = RuntimeError raise exc(errmsg) print(errmsg, file=self.writer) return def dump(self, node, **kw): """Simple ast dumper.""" return ast.dump(node, **kw) # handlers for ast components def on_expr(self, node): """Expression.""" return self.run(node.value) # ('value',) def on_index(self, node): """Index.""" return self.run(node.value) # ('value',) def on_return(self, node): # ('value',) """Return statement: look for None, return special sentinal.""" self.retval = self.run(node.value) if self.retval is None: self.retval = ReturnedNone return def on_repr(self, node): """Repr.""" return repr(self.run(node.value)) # ('value',) def on_module(self, node): # ():('body',) """Module def.""" out = None for tnode in node.body: out = self.run(tnode) return out def on_expression(self, node): "basic expression" return self.on_module(node) # ():('body',) def on_pass(self, node): """Pass statement.""" return None # () def on_ellipsis(self, node): """Ellipses.""" return Ellipsis # for break and continue: set the instance variable _interrupt def on_interrupt(self, node): # () """Interrupt handler.""" self._interrupt = node return node def on_break(self, node): """Break.""" return self.on_interrupt(node) def on_continue(self, node): """Continue.""" return self.on_interrupt(node) def on_assert(self, node): # ('test', 'msg') """Assert statement.""" if not self.run(node.test): self.raise_exception(node, exc=AssertionError, msg=node.msg) return True def on_list(self, node): # ('elt', 'ctx') """List.""" return [self.run(e) for e in node.elts] def on_tuple(self, node): # ('elts', 'ctx') """Tuple.""" return tuple(self.on_list(node)) def on_dict(self, node): # ('keys', 'values') """Dictionary.""" return dict([(self.run(k), self.run(v)) for k, v in zip(node.keys, node.values)]) def on_num(self, node): # ('n',) """Return number.""" return node.n def on_str(self, node): # ('s',) """Return string.""" return node.s def on_nameconstant(self, node): # ('value',) """named constant""" return node.value def on_name(self, node): # ('id', 'ctx') """Name node.""" ctx = node.ctx.__class__ if ctx in (ast.Param, ast.Del): return str(node.id) else: if node.id in self.symtable: return self.symtable[node.id] else: msg = "name '%s' is not defined" % node.id self.raise_exception(node, exc=NameError, msg=msg) def node_assign(self, node, val): """Assign a value (not the node.value object) to a node. This is used by on_assign, but also by for, list comprehension, etc. """ if node.__class__ == ast.Name: if not valid_symbol_name(node.id): errmsg = "invalid symbol name (reserved word?) %s" % node.id self.raise_exception(node, exc=NameError, msg=errmsg) sym = self.symtable[node.id] = val if node.id in self.no_deepcopy: self.no_deepcopy.pop(node.id) elif node.__class__ == ast.Attribute: if node.ctx.__class__ == ast.Load: msg = "cannot assign to attribute %s" % node.attr self.raise_exception(node, exc=AttributeError, msg=msg) setattr(self.run(node.value), node.attr, val) elif node.__class__ == ast.Subscript: sym = self.run(node.value) xslice = self.run(node.slice) if isinstance(node.slice, ast.Index): sym[xslice] = val elif isinstance(node.slice, ast.Slice): sym[slice(xslice.start, xslice.stop)] = val elif isinstance(node.slice, ast.ExtSlice): sym[(xslice)] = val elif node.__class__ in (ast.Tuple, ast.List): if len(val) == len(node.elts): for telem, tval in zip(node.elts, val): self.node_assign(telem, tval) else: raise ValueError('too many values to unpack') def on_attribute(self, node): # ('value', 'attr', 'ctx') """Extract attribute.""" ctx = node.ctx.__class__ if ctx == ast.Store: msg = "attribute for storage: shouldn't be here!" self.raise_exception(node, exc=RuntimeError, msg=msg) sym = self.run(node.value) if ctx == ast.Del: return delattr(sym, node.attr) # ctx is ast.Load fmt = "cannnot access attribute '%s' for %s" if node.attr not in UNSAFE_ATTRS: fmt = "no attribute '%s' for %s" try: return getattr(sym, node.attr) except AttributeError: pass # AttributeError or accessed unsafe attribute obj = self.run(node.value) msg = fmt % (node.attr, obj) self.raise_exception(node, exc=AttributeError, msg=msg) def on_assign(self, node): # ('targets', 'value') """Simple assignment.""" val = self.run(node.value) for tnode in node.targets: self.node_assign(tnode, val) return def on_augassign(self, node): # ('target', 'op', 'value') """Augmented assign.""" return self.on_assign(ast.Assign(targets=[node.target], value=ast.BinOp(left=node.target, op=node.op, right=node.value))) def on_slice(self, node): # ():('lower', 'upper', 'step') """Simple slice.""" return slice(self.run(node.lower), self.run(node.upper), self.run(node.step)) def on_extslice(self, node): # ():('dims',) """Extended slice.""" return tuple([self.run(tnode) for tnode in node.dims]) def on_subscript(self, node): # ('value', 'slice', 'ctx') """Subscript handling -- one of the tricky parts.""" val = self.run(node.value) nslice = self.run(node.slice) ctx = node.ctx.__class__ if ctx in (ast.Load, ast.Store): if isinstance(node.slice, (ast.Index, ast.Slice, ast.Ellipsis)): return val.__getitem__(nslice) elif isinstance(node.slice, ast.ExtSlice): return val[(nslice)] else: msg = "subscript with unknown context" self.raise_exception(node, msg=msg) def on_delete(self, node): # ('targets',) """Delete statement.""" for tnode in node.targets: if tnode.ctx.__class__ != ast.Del: break children = [] while tnode.__class__ == ast.Attribute: children.append(tnode.attr) tnode = tnode.value if tnode.__class__ == ast.Name: children.append(tnode.id) children.reverse() self.symtable.pop('.'.join(children)) else: msg = "could not delete symbol" self.raise_exception(node, msg=msg) def on_unaryop(self, node): # ('op', 'operand') """Unary operator.""" return op2func(node.op)(self.run(node.operand)) def on_binop(self, node): # ('left', 'op', 'right') """Binary operator.""" return op2func(node.op)(self.run(node.left), self.run(node.right)) def on_boolop(self, node): # ('op', 'values') """Boolean operator.""" val = self.run(node.values[0]) is_and = ast.And == node.op.__class__ if (is_and and val) or (not is_and and not val): for n in node.values: val = op2func(node.op)(val, self.run(n)) if (is_and and not val) or (not is_and and val): break return val def on_compare(self, node): # ('left', 'ops', 'comparators') """Comparison operators.""" lval = self.run(node.left) out = True for op, rnode in zip(node.ops, node.comparators): rval = self.run(rnode) out = op2func(op)(lval, rval) lval = rval if self.use_numpy and isinstance(out, numpy.ndarray) and out.any(): break elif not out: break return out def on_print(self, node): # ('dest', 'values', 'nl') """Note: implements Python2 style print statement, not print() function. May need improvement.... """ dest = self.run(node.dest) or self.writer end = '' if node.nl: end = '\n' out = [self.run(tnode) for tnode in node.values] if out and len(self.error) == 0: self._printer(*out, file=dest, end=end) def _printer(self, *out, **kws): """Generic print function.""" flush = kws.pop('flush', True) fileh = kws.pop('file', self.writer) sep = kws.pop('sep', ' ') end = kws.pop('sep', '\n') print(*out, file=fileh, sep=sep, end=end) if flush: fileh.flush() def on_if(self, node): # ('test', 'body', 'orelse') """Regular if-then-else statement.""" block = node.body if not self.run(node.test): block = node.orelse for tnode in block: self.run(tnode) def on_ifexp(self, node): # ('test', 'body', 'orelse') """If expressions.""" expr = node.orelse if self.run(node.test): expr = node.body return self.run(expr) def on_while(self, node): # ('test', 'body', 'orelse') """While blocks.""" while self.run(node.test): self._interrupt = None for tnode in node.body: self.run(tnode) if self._interrupt is not None: break if isinstance(self._interrupt, ast.Break): break else: for tnode in node.orelse: self.run(tnode) self._interrupt = None def on_for(self, node): # ('target', 'iter', 'body', 'orelse') """For blocks.""" for val in self.run(node.iter): self.node_assign(node.target, val) self._interrupt = None for tnode in node.body: self.run(tnode) if self._interrupt is not None: break if isinstance(self._interrupt, ast.Break): break else: for tnode in node.orelse: self.run(tnode) self._interrupt = None def on_listcomp(self, node): # ('elt', 'generators') """List comprehension.""" out = [] for tnode in node.generators: if tnode.__class__ == ast.comprehension: for val in self.run(tnode.iter): self.node_assign(tnode.target, val) add = True for cond in tnode.ifs: add = add and self.run(cond) if add: out.append(self.run(node.elt)) return out def on_excepthandler(self, node): # ('type', 'name', 'body') """Exception handler...""" return (self.run(node.type), node.name, node.body) def on_try(self, node): # ('body', 'handlers', 'orelse', 'finalbody') """Try/except/else/finally blocks.""" no_errors = True for tnode in node.body: self.run(tnode, with_raise=False) no_errors = no_errors and len(self.error) == 0 if len(self.error) > 0: e_type, e_value, e_tback = self.error[-1].exc_info for hnd in node.handlers: htype = None if hnd.type is not None: htype = __builtins__.get(hnd.type.id, None) if htype is None or isinstance(e_type(), htype): self.error = [] if hnd.name is not None: self.node_assign(hnd.name, e_value) for tline in hnd.body: self.run(tline) break if no_errors and hasattr(node, 'orelse'): for tnode in node.orelse: self.run(tnode) if hasattr(node, 'finalbody'): for tnode in node.finalbody: self.run(tnode) def on_raise(self, node): # ('type', 'inst', 'tback') """Raise statement: note difference for python 2 and 3.""" if version_info[0] == 3: excnode = node.exc msgnode = node.cause else: excnode = node.type msgnode = node.inst out = self.run(excnode) msg = ' '.join(out.args) msg2 = self.run(msgnode) if msg2 not in (None, 'None'): msg = "%s: %s" % (msg, msg2) self.raise_exception(None, exc=out.__class__, msg=msg, expr='') def on_call(self, node): """Function execution.""" # ('func', 'args', 'keywords'. Py<3.5 has 'starargs' and 'kwargs' too) func = self.run(node.func) if not hasattr(func, '__call__') and not isinstance(func, type): msg = "'%s' is not callable!!" % (func) self.raise_exception(node, exc=TypeError, msg=msg) args = [self.run(targ) for targ in node.args] starargs = getattr(node, 'starargs', None) if starargs is not None: args = args + self.run(starargs) keywords = {} for key in node.keywords: if not isinstance(key, ast.keyword): msg = "keyword error in function call '%s'" % (func) self.raise_exception(node, msg=msg) keywords[key.arg] = self.run(key.value) kwargs = getattr(node, 'kwargs', None) if kwargs is not None: keywords.update(self.run(kwargs)) try: return func(*args, **keywords) except: self.raise_exception(node, msg="Error running %s" % (func)) def on_arg(self, node): # ('test', 'msg') """Arg for function definitions.""" # print(" ON ARG ! ", node, node.arg) return node.arg def on_functiondef(self, node): """Define procedures.""" # ('name', 'args', 'body', 'decorator_list') if node.decorator_list != []: raise Warning("decorated procedures not supported!") kwargs = [] offset = len(node.args.args) - len(node.args.defaults) for idef, defnode in enumerate(node.args.defaults): defval = self.run(defnode) keyval = self.run(node.args.args[idef+offset]) kwargs.append((keyval, defval)) if version_info[0] == 3: args = [tnode.arg for tnode in node.args.args[:offset]] else: args = [tnode.id for tnode in node.args.args[:offset]] doc = None nb0 = node.body[0] if isinstance(nb0, ast.Expr) and isinstance(nb0.value, ast.Str): doc = nb0.value.s self.symtable[node.name] = Procedure(node.name, self, doc=doc, lineno=self.lineno, body=node.body, args=args, kwargs=kwargs, vararg=node.args.vararg, varkws=node.args.kwarg) if node.name in self.no_deepcopy: self.no_deepcopy.pop(node.name) class Procedure(object): """Procedure: user-defined function for asteval. This stores the parsed ast nodes as from the 'functiondef' ast node for later evaluation. """ def __init__(self, name, interp, doc=None, lineno=0, body=None, args=None, kwargs=None, vararg=None, varkws=None): """TODO: docstring in public method.""" self.name = name self.__asteval__ = interp self.raise_exc = self.__asteval__.raise_exception self.__doc__ = doc self.body = body self.argnames = args self.kwargs = kwargs self.vararg = vararg self.varkws = varkws self.lineno = lineno def __repr__(self): """TODO: docstring in magic method.""" sig = "" if len(self.argnames) > 0: sig = "%s%s" % (sig, ', '.join(self.argnames)) if self.vararg is not None: sig = "%s, *%s" % (sig, self.vararg) if len(self.kwargs) > 0: if len(sig) > 0: sig = "%s, " % sig _kw = ["%s=%s" % (k, v) for k, v in self.kwargs] sig = "%s%s" % (sig, ', '.join(_kw)) if self.varkws is not None: sig = "%s, **%s" % (sig, self.varkws) sig = "" % (self.name, sig) if self.__doc__ is not None: sig = "%s\n %s" % (sig, self.__doc__) return sig def __call__(self, *args, **kwargs): """TODO: docstring in public method.""" symlocals = {} args = list(args) n_args = len(args) n_names = len(self.argnames) n_kws = len(kwargs) # may need to move kwargs to args if names align! if (n_args < n_names) and n_kws > 0: for name in self.argnames[n_args:]: if name in kwargs: args.append(kwargs.pop(name)) n_args = len(args) n_names = len(self.argnames) n_kws = len(kwargs) if len(self.argnames) > 0 and kwargs is not None: msg = "multiple values for keyword argument '%s' in Procedure %s" for targ in self.argnames: if targ in kwargs: self.raise_exc(None, exc=TypeError, msg=msg % (targ, self.name), lineno=self.lineno) if n_args != n_names: msg = None if n_args < n_names: msg = 'not enough arguments for Procedure %s()' % self.name msg = '%s (expected %i, got %i)' % (msg, n_names, n_args) self.raise_exc(None, exc=TypeError, msg=msg) for argname in self.argnames: symlocals[argname] = args.pop(0) try: if self.vararg is not None: symlocals[self.vararg] = tuple(args) for key, val in self.kwargs: if key in kwargs: val = kwargs.pop(key) symlocals[key] = val if self.varkws is not None: symlocals[self.varkws] = kwargs elif len(kwargs) > 0: msg = 'extra keyword arguments for Procedure %s (%s)' msg = msg % (self.name, ','.join(list(kwargs.keys()))) self.raise_exc(None, msg=msg, exc=TypeError, lineno=self.lineno) except (ValueError, LookupError, TypeError, NameError, AttributeError): msg = 'incorrect arguments for Procedure %s' % self.name self.raise_exc(None, msg=msg, lineno=self.lineno) save_symtable = self.__asteval__.symtable.copy() self.__asteval__.symtable.update(symlocals) self.__asteval__.retval = None retval = None # evaluate script of function for node in self.body: self.__asteval__.run(node, expr='<>', lineno=self.lineno) if len(self.__asteval__.error) > 0: break if self.__asteval__.retval is not None: retval = self.__asteval__.retval if retval is ReturnedNone: retval = None break self.__asteval__.symtable = save_symtable symlocals = None return retval lmfit-0.9.7/lmfit/astutils.py0000644000076500000240000003021713066042256017116 0ustar Newvillestaff00000000000000"""Utility functions for asteval. Matthew Newville , The University of Chicago """ from __future__ import division, print_function import ast import re from sys import exc_info RESERVED_WORDS = ('and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'True', 'False', 'None', 'eval', 'execfile', '__import__', '__package__') NAME_MATCH = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*$").match UNSAFE_ATTRS = ('__subclasses__', '__bases__', '__globals__', '__code__', '__closure__', '__func__', '__self__', '__module__', '__dict__', '__class__', '__call__', '__get__', '__getattribute__', '__subclasshook__', '__new__', '__init__', 'func_globals', 'func_code', 'func_closure', 'im_class', 'im_func', 'im_self', 'gi_code', 'gi_frame', '__asteval__') # inherit these from python's __builtins__ FROM_PY = ('ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'EnvironmentError', 'Exception', 'False', 'FloatingPointError', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplementedError', 'OSError', 'OverflowError', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'ValueError', 'Warning', 'ZeroDivisionError', 'abs', 'all', 'any', 'bin', 'bool', 'bytearray', 'bytes', 'chr', 'complex', 'dict', 'dir', 'divmod', 'enumerate', 'filter', 'float', 'format', 'frozenset', 'hash', 'hex', 'id', 'int', 'isinstance', 'len', 'list', 'map', 'max', 'min', 'oct', 'ord', 'pow', 'range', 'repr', 'reversed', 'round', 'set', 'slice', 'sorted', 'str', 'sum', 'tuple', 'type', 'zip') # inherit these from python's math FROM_MATH = ('acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'exp', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'hypot', 'isinf', 'isnan', 'ldexp', 'log', 'log10', 'log1p', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'trunc') FROM_NUMPY = ('Inf', 'NAN', 'abs', 'add', 'alen', 'all', 'amax', 'amin', 'angle', 'any', 'append', 'arange', 'arccos', 'arccosh', 'arcsin', 'arcsinh', 'arctan', 'arctan2', 'arctanh', 'argmax', 'argmin', 'argsort', 'argwhere', 'around', 'array', 'array2string', 'asanyarray', 'asarray', 'asarray_chkfinite', 'ascontiguousarray', 'asfarray', 'asfortranarray', 'asmatrix', 'asscalar', 'atleast_1d', 'atleast_2d', 'atleast_3d', 'average', 'bartlett', 'base_repr', 'bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'blackman', 'bool', 'broadcast', 'broadcast_arrays', 'byte', 'c_', 'cdouble', 'ceil', 'cfloat', 'chararray', 'choose', 'clip', 'clongdouble', 'clongfloat', 'column_stack', 'common_type', 'complex', 'complex128', 'complex64', 'complex_', 'complexfloating', 'compress', 'concatenate', 'conjugate', 'convolve', 'copy', 'copysign', 'corrcoef', 'correlate', 'cos', 'cosh', 'cov', 'cross', 'csingle', 'cumprod', 'cumsum', 'datetime_data', 'deg2rad', 'degrees', 'delete', 'diag', 'diag_indices', 'diag_indices_from', 'diagflat', 'diagonal', 'diff', 'digitize', 'divide', 'dot', 'double', 'dsplit', 'dstack', 'dtype', 'e', 'ediff1d', 'empty', 'empty_like', 'equal', 'exp', 'exp2', 'expand_dims', 'expm1', 'extract', 'eye', 'fabs', 'fill_diagonal', 'finfo', 'fix', 'flatiter', 'flatnonzero', 'fliplr', 'flipud', 'float', 'float32', 'float64', 'float_', 'floating', 'floor', 'floor_divide', 'fmax', 'fmin', 'fmod', 'format_parser', 'frexp', 'frombuffer', 'fromfile', 'fromfunction', 'fromiter', 'frompyfunc', 'fromregex', 'fromstring', 'fv', 'genfromtxt', 'getbufsize', 'geterr', 'gradient', 'greater', 'greater_equal', 'hamming', 'hanning', 'histogram', 'histogram2d', 'histogramdd', 'hsplit', 'hstack', 'hypot', 'i0', 'identity', 'iinfo', 'imag', 'in1d', 'index_exp', 'indices', 'inexact', 'inf', 'info', 'infty', 'inner', 'insert', 'int', 'int0', 'int16', 'int32', 'int64', 'int8', 'int_', 'int_asbuffer', 'intc', 'integer', 'interp', 'intersect1d', 'intp', 'invert', 'ipmt', 'irr', 'iscomplex', 'iscomplexobj', 'isfinite', 'isfortran', 'isinf', 'isnan', 'isneginf', 'isposinf', 'isreal', 'isrealobj', 'isscalar', 'issctype', 'iterable', 'ix_', 'kaiser', 'kron', 'ldexp', 'left_shift', 'less', 'less_equal', 'linspace', 'little_endian', 'load', 'loads', 'loadtxt', 'log', 'log10', 'log1p', 'log2', 'logaddexp', 'logaddexp2', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'logspace', 'long', 'longcomplex', 'longdouble', 'longfloat', 'longlong', 'mafromtxt', 'mask_indices', 'mat', 'matrix', 'maximum', 'maximum_sctype', 'may_share_memory', 'mean', 'median', 'memmap', 'meshgrid', 'mgrid', 'minimum', 'mintypecode', 'mirr', 'mod', 'modf', 'msort', 'multiply', 'nan', 'nan_to_num', 'nanargmax', 'nanargmin', 'nanmax', 'nanmin', 'nansum', 'ndarray', 'ndenumerate', 'ndfromtxt', 'ndim', 'ndindex', 'negative', 'newaxis', 'nextafter', 'nonzero', 'not_equal', 'nper', 'npv', 'number', 'obj2sctype', 'ogrid', 'ones', 'ones_like', 'outer', 'packbits', 'percentile', 'pi', 'piecewise', 'place', 'pmt', 'poly', 'poly1d', 'polyadd', 'polyder', 'polydiv', 'polyfit', 'polyint', 'polymul', 'polysub', 'polyval', 'power', 'ppmt', 'prod', 'product', 'ptp', 'put', 'putmask', 'pv', 'r_', 'rad2deg', 'radians', 'rank', 'rate', 'ravel', 'real', 'real_if_close', 'reciprocal', 'record', 'remainder', 'repeat', 'reshape', 'resize', 'restoredot', 'right_shift', 'rint', 'roll', 'rollaxis', 'roots', 'rot90', 'round', 'round_', 'row_stack', 's_', 'sctype2char', 'searchsorted', 'select', 'setbufsize', 'setdiff1d', 'seterr', 'setxor1d', 'shape', 'short', 'sign', 'signbit', 'signedinteger', 'sin', 'sinc', 'single', 'singlecomplex', 'sinh', 'size', 'sometrue', 'sort', 'sort_complex', 'spacing', 'split', 'sqrt', 'square', 'squeeze', 'std', 'str', 'str_', 'subtract', 'sum', 'swapaxes', 'take', 'tan', 'tanh', 'tensordot', 'tile', 'trace', 'transpose', 'trapz', 'tri', 'tril', 'tril_indices', 'tril_indices_from', 'trim_zeros', 'triu', 'triu_indices', 'triu_indices_from', 'true_divide', 'trunc', 'ubyte', 'uint', 'uint0', 'uint16', 'uint32', 'uint64', 'uint8', 'uintc', 'uintp', 'ulonglong', 'union1d', 'unique', 'unravel_index', 'unsignedinteger', 'unwrap', 'ushort', 'vander', 'var', 'vdot', 'vectorize', 'vsplit', 'vstack', 'where', 'who', 'zeros', 'zeros_like') NUMPY_RENAMES = {'ln': 'log', 'asin': 'arcsin', 'acos': 'arccos', 'atan': 'arctan', 'atan2': 'arctan2', 'atanh': 'arctanh', 'acosh': 'arccosh', 'asinh': 'arcsinh'} def _open(filename, mode='r', buffering=0): """Read-only version of open().""" umode = 'r' if mode == 'rb': umode = 'rb' return open(filename, umode, buffering) LOCALFUNCS = {'open': _open} OPERATORS = {ast.Is: lambda a, b: a is b, ast.IsNot: lambda a, b: a is not b, ast.In: lambda a, b: a in b, ast.NotIn: lambda a, b: a not in b, ast.Add: lambda a, b: a + b, ast.BitAnd: lambda a, b: a & b, ast.BitOr: lambda a, b: a | b, ast.BitXor: lambda a, b: a ^ b, ast.Div: lambda a, b: a / b, ast.FloorDiv: lambda a, b: a // b, ast.LShift: lambda a, b: a << b, ast.RShift: lambda a, b: a >> b, ast.Mult: lambda a, b: a * b, ast.Pow: lambda a, b: a ** b, ast.Sub: lambda a, b: a - b, ast.Mod: lambda a, b: a % b, ast.And: lambda a, b: a and b, ast.Or: lambda a, b: a or b, ast.Eq: lambda a, b: a == b, ast.Gt: lambda a, b: a > b, ast.GtE: lambda a, b: a >= b, ast.Lt: lambda a, b: a < b, ast.LtE: lambda a, b: a <= b, ast.NotEq: lambda a, b: a != b, ast.Invert: lambda a: ~a, ast.Not: lambda a: not a, ast.UAdd: lambda a: +a, ast.USub: lambda a: -a} def valid_symbol_name(name): """Determine whether the input symbol name is a valid name. This checks for reserved words, and that the name matches the regular expression ``[a-zA-Z_][a-zA-Z0-9_]`` """ if name in RESERVED_WORDS: return False return NAME_MATCH(name) is not None def op2func(op): """Return function for operator nodes.""" return OPERATORS[op.__class__] class Empty: """Empty class.""" def __init__(self): """TODO: docstring in public method.""" pass def __nonzero__(self): """TODO: docstring in magic method.""" return False ReturnedNone = Empty() class ExceptionHolder(object): """Basic exception handler.""" def __init__(self, node, exc=None, msg='', expr=None, lineno=None): """TODO: docstring in public method.""" self.node = node self.expr = expr self.msg = msg self.exc = exc self.lineno = lineno self.exc_info = exc_info() if self.exc is None and self.exc_info[0] is not None: self.exc = self.exc_info[0] if self.msg is '' and self.exc_info[1] is not None: self.msg = self.exc_info[1] def get_error(self): """Retrieve error data.""" col_offset = -1 if self.node is not None: try: col_offset = self.node.col_offset except AttributeError: pass try: exc_name = self.exc.__name__ except AttributeError: exc_name = str(self.exc) if exc_name in (None, 'None'): exc_name = 'UnknownError' out = [" %s" % self.expr] if col_offset > 0: out.append(" %s^^^" % ((col_offset)*' ')) out.append(str(self.msg)) return (exc_name, '\n'.join(out)) class NameFinder(ast.NodeVisitor): """Find all symbol names used by a parsed node.""" def __init__(self): """TODO: docstring in public method.""" self.names = [] ast.NodeVisitor.__init__(self) def generic_visit(self, node): """TODO: docstring in public method.""" if node.__class__.__name__ == 'Name': if node.ctx.__class__ == ast.Load and node.id not in self.names: self.names.append(node.id) ast.NodeVisitor.generic_visit(self, node) def get_ast_names(astnode): """Return symbol Names from an AST node.""" finder = NameFinder() finder.generic_visit(astnode) return finder.names lmfit-0.9.7/lmfit/confidence.py0000644000076500000240000003361713066042256017352 0ustar Newvillestaff00000000000000"""Contains functions to calculate confidence intervals.""" from __future__ import print_function from collections import OrderedDict from warnings import warn import numpy as np from scipy.optimize import brentq from scipy.special import erf from scipy.stats import f from .minimizer import MinimizerException CONF_ERR_GEN = 'Cannot determine Confidence Intervals' CONF_ERR_STDERR = '%s without sensible uncertainty estimates' % CONF_ERR_GEN CONF_ERR_NVARS = '%s with < 2 variables' % CONF_ERR_GEN def f_compare(ndata, nparas, new_chi, best_chi, nfix=1.): """Return the probalitiy for two given parameter sets. nfix is the number of fixed parameters. """ nparas = nparas + nfix nfree = ndata - nparas nfix = 1.0*nfix dchi = new_chi / best_chi - 1.0 return f.cdf(dchi * nfree / nfix, nfix, nfree) def copy_vals(params): """Save the values and stderrs of params in temporary dict.""" tmp_params = {} for para_key in params: tmp_params[para_key] = (params[para_key].value, params[para_key].stderr) return tmp_params def restore_vals(tmp_params, params): """Restore values and stderrs of params from a temporary dict.""" for para_key in params: params[para_key].value, params[para_key].stderr = tmp_params[para_key] def conf_interval(minimizer, result, p_names=None, sigmas=(1, 2, 3), trace=False, maxiter=200, verbose=False, prob_func=None): """Calculate the confidence interval for parameters. The parameter for which the ci is calculated will be varied, while the remaining parameters are re-optimized for minimizing chi-square. The resulting chi-square is used to calculate the probability with a given statistic (e.g., F-test). This function uses a 1d-rootfinder from SciPy to find the values resulting in the searched confidence region. Parameters ---------- minimizer : Minimizer The minimizer to use, holding objective function. result : MinimizerResult The result of running minimize(). p_names : list, optional Names of the parameters for which the ci is calculated. If None, the ci is calculated for every parameter. sigmas : list, optional The sigma-levels to find. Default is [1, 2, 3]. See Note below. trace : bool, optional Defaults to False, if True, each result of a probability calculation is saved along with the parameter. This can be used to plot so-called "profile traces". maxiter : int, optional Maximum of iteration to find an upper limit. Default is 200. verbose: bool, optional Print extra debuging information. Default is False. prob_func : None or callable, optional Function to calculate the probability from the optimized chi-square. Default is None and uses built-in f_compare (F-test). Returns ------- output : dict A dictionary that contains a list of (sigma, vals)-tuples for each name. trace_dict : dict, optional Only if trace is True. Is a dict, the key is the parameter which was fixed. The values are again a dict with the names as keys, but with an additional key 'prob'. Each contains an array of the corresponding values. Note ----- The values for `sigma` are taken as the number of standard deviations for a normal distribution and converted to probabilities. That is, the default ``sigma=(1, 2, 3)`` will use probabilities of 0.6827, 0.9545, and 0.9973. If any of the sigma values is less than 1, that will be interpreted as a probability. That is, a value of 1 and 0.6827 will give the same results, within precision. See also -------- conf_interval2d Examples -------- >>> from lmfit.printfuncs import * >>> mini = minimize(some_func, params) >>> mini.leastsq() True >>> report_errors(params) ... #report >>> ci = conf_interval(mini) >>> report_ci(ci) ... #report Now with quantiles for the sigmas and using the trace. >>> ci, trace = conf_interval(mini, sigmas=(0.5, 1, 2, 3), trace=True) >>> fixed = trace['para1']['para1'] >>> free = trace['para1']['not_para1'] >>> prob = trace['para1']['prob'] This makes it possible to plot the dependence between free and fixed parameters. """ ci = ConfidenceInterval(minimizer, result, p_names, prob_func, sigmas, trace, verbose, maxiter) output = ci.calc_all_ci() if trace: return output, ci.trace_dict return output def map_trace_to_names(trace, params): """Map trace to parameter names.""" out = {} allnames = list(params.keys()) + ['prob'] for name in trace.keys(): tmp_dict = {} tmp = np.array(trace[name]) for para_name, values in zip(allnames, tmp.T): tmp_dict[para_name] = values out[name] = tmp_dict return out class ConfidenceInterval(object): """Class used to calculate the confidence interval.""" def __init__(self, minimizer, result, p_names=None, prob_func=None, sigmas=(1, 2, 3), trace=False, verbose=False, maxiter=50): """TODO: docstring in public method.""" self.verbose = verbose self.minimizer = minimizer self.result = result self.params = result.params self.org = copy_vals(self.params) self.best_chi = result.chisqr if p_names is None: p_names = [i for i in self.params if self.params[i].vary] self.p_names = p_names self.fit_params = [self.params[p] for p in self.p_names] # check that there are at least 2 true variables! # check that all stderrs are sensible (including not None or NaN) nvars = 0 for par in self.fit_params: if par.vary: nvars += 1 try: if not (par.vary and par.stderr > 0.0): raise MinimizerException(CONF_ERR_STDERR) except TypeError: raise MinimizerException(CONF_ERR_STDERR) if nvars < 2: raise MinimizerException(CONF_ERR_NVARS) if prob_func is None or not hasattr(prob_func, '__call__'): self.prob_func = f_compare if trace: self.trace_dict = dict([(i, []) for i in self.p_names]) self.trace = trace self.maxiter = maxiter self.min_rel_change = 1e-5 self.sigmas = list(sigmas) self.sigmas.sort() self.probs = [] for sigma in self.sigmas: if sigma < 1: prob = sigma else: prob = erf(sigma/np.sqrt(2)) self.probs.append(prob) def calc_all_ci(self): """Calculate all confidence intervals.""" out = OrderedDict() for p in self.p_names: out[p] = (self.calc_ci(p, -1)[::-1] + [(0., self.params[p].value)] + self.calc_ci(p, 1)) if self.trace: self.trace_dict = map_trace_to_names(self.trace_dict, self.params) return out def calc_ci(self, para, direction): """Calculate the ci for a single parameter for a single direction. Direction is either positive or negative 1. """ if isinstance(para, str): para = self.params[para] # function used to calculate the pro calc_prob = lambda val, prob: self.calc_prob(para, val, prob) if self.trace: x = [i.value for i in self.params.values()] self.trace_dict[para.name].append(x + [0]) para.vary = False limit, max_prob = self.find_limit(para, direction) start_val = a_limit = float(para.value) ret = [] orig_warn_settings = np.geterr() np.seterr(all='ignore') for prob in self.probs: if prob > max_prob: ret.append((prob, direction*np.inf)) continue try: val = brentq(calc_prob, a_limit, limit, rtol=.5e-4, args=prob) except ValueError: self.reset_vals() try: val = brentq(calc_prob, start_val, limit, rtol=.5e-4, args=prob) except ValueError: val = np.nan a_limit = val ret.append((prob, val)) para.vary = True self.reset_vals() np.seterr(**orig_warn_settings) return ret def reset_vals(self): """TODO: add method docstring.""" restore_vals(self.org, self.params) def find_limit(self, para, direction): """For given para, search a value so that prob(val) > sigmas.""" if self.verbose: print('Calculating CI for ' + para.name) self.reset_vals() # starting steps: if para.stderr > 0 and para.stderr < abs(para.value): step = para.stderr else: step = max(abs(para.value) * 0.2, 0.001) para.vary = False start_val = para.value old_prob = 0 limit = start_val i = 0 while old_prob < max(self.probs): i = i + 1 limit += step * direction new_prob = self.calc_prob(para, limit) rel_change = (new_prob - old_prob) / max(new_prob, old_prob, 1.e-12) old_prob = new_prob # Check convergence. if i > self.maxiter: errmsg = "Warning, maxiter={0} reached".format(self.maxiter) errmsg += ("and prob({0}={1}) = {2} < " "max(sigmas).".format(para.name, limit, new_prob)) warn(errmsg) break if rel_change < self.min_rel_change: errmsg = "Warning, rel_change={0} < 0.01 ".format(rel_change) errmsg += (" at iteration {3} and prob({0}={1}) = {2} < max" "(sigmas).".format(para.name, limit, new_prob, i)) warn(errmsg) break self.reset_vals() return limit, new_prob def calc_prob(self, para, val, offset=0., restore=False): """Calculate the probability for given value.""" if restore: restore_vals(self.org, self.params) para.value = val save_para = self.params[para.name] self.params[para.name] = para self.minimizer.prepare_fit(self.params) out = self.minimizer.leastsq() prob = self.prob_func(out.ndata, out.ndata - out.nfree, out.chisqr, self.best_chi) if self.trace: x = [i.value for i in out.params.values()] self.trace_dict[para.name].append(x + [prob]) self.params[para.name] = save_para return prob - offset def conf_interval2d(minimizer, result, x_name, y_name, nx=10, ny=10, limits=None, prob_func=None): r"""Calculate confidence regions for two fixed parameters. The method itself is explained in *conf_interval*: here we are fixing two parameters. Parameters ---------- minimizer : Minimizer The minimizer to use, holding objective function. result : MinimizerResult The result of running minimize(). x_name : str The name of the parameter which will be the x direction. y_name : str The name of the parameter which will be the y direction. nx : int, optional Number of points in the x direction. ny : int, optional Number of points in the y direction. limits : tuple, optional Should have the form ((x_upper, x_lower),(y_upper, y_lower)). If not given, the default is 5 std-errs in each direction. prob_func : None or callable, optional Function to calculate the probability from the optimized chi-square. Default is None and uses built-in f_compare (F-test). Returns ------- x : numpy.ndarray X-coordinates (same shape as nx). y : numpy.ndarray Y-coordinates (same shape as ny). grid : numpy.ndarray Grid containing the calculated probabilities (with shape (nx, ny)). Examples -------- >>> mini = Minimizer(some_func, params) >>> result = mini.leastsq() >>> x, y, gr = conf_interval2d(mini, result, 'para1','para2') >>> plt.contour(x,y,gr) """ # used to detect that .leastsq() has run! params = result.params best_chi = result.chisqr org = copy_vals(result.params) if prob_func is None or not hasattr(prob_func, '__call__'): prob_func = f_compare x = params[x_name] y = params[y_name] if limits is None: (x_upper, x_lower) = (x.value + 5 * x.stderr, x.value - 5 * x.stderr) (y_upper, y_lower) = (y.value + 5 * y.stderr, y.value - 5 * y.stderr) elif len(limits) == 2: (x_upper, x_lower) = limits[0] (y_upper, y_lower) = limits[1] x_points = np.linspace(x_lower, x_upper, nx) y_points = np.linspace(y_lower, y_upper, ny) grid = np.dstack(np.meshgrid(x_points, y_points)) x.vary = False y.vary = False def calc_prob(vals, restore=False): """Calculate the probability.""" if restore: restore_vals(org, result.params) x.value = vals[0] y.value = vals[1] save_x = result.params[x.name] save_y = result.params[y.name] result.params[x.name] = x result.params[y.name] = y minimizer.prepare_fit(params=result.params) out = minimizer.leastsq() prob = prob_func(out.ndata, out.ndata - out.nfree, out.chisqr, best_chi, nfix=2.) result.params[x.name] = save_x result.params[y.name] = save_y return prob out = x_points, y_points, np.apply_along_axis(calc_prob, -1, grid) x.vary, y.vary = True, True restore_vals(org, result.params) result.chisqr = best_chi return out lmfit-0.9.7/lmfit/lineshapes.py0000644000076500000240000002631613066042256017406 0ustar Newvillestaff00000000000000"""Basic model line shapes and distribution functions.""" from __future__ import division from numpy import arctan, cos, exp, log, pi, sqrt, where from numpy.testing import assert_allclose from scipy.special import erf, erfc, gammaln, wofz from scipy.special import gamma as gamfcn log2 = log(2) s2pi = sqrt(2*pi) spi = sqrt(pi) s2 = sqrt(2.0) functions = ('gaussian', 'lorentzian', 'voigt', 'pvoigt', 'moffat', 'pearson7', 'breit_wigner', 'damped_oscillator', 'dho', 'logistic', 'lognormal', 'students_t', 'expgaussian', 'donaich', 'skewed_gaussian', 'skewed_voigt', 'step', 'rectangle', 'erf', 'erfc', 'wofz', 'gamma', 'gammaln', 'exponential', 'powerlaw', 'linear', 'parabolic') def gaussian(x, amplitude=1.0, center=0.0, sigma=1.0): """Return a 1-dimensional Gaussian function. gaussian(x, amplitude, center, sigma) = (amplitude/(s2pi*sigma)) * exp(-(1.0*x-center)**2 / (2*sigma**2)) """ return (amplitude/(s2pi*sigma)) * exp(-(1.0*x-center)**2 / (2*sigma**2)) def lorentzian(x, amplitude=1.0, center=0.0, sigma=1.0): """Return a 1-dimensional Lorentzian function. lorentzian(x, amplitude, center, sigma) = (amplitude/(1 + ((1.0*x-center)/sigma)**2)) / (pi*sigma) """ return (amplitude/(1 + ((1.0*x-center)/sigma)**2)) / (pi*sigma) def voigt(x, amplitude=1.0, center=0.0, sigma=1.0, gamma=None): """Return a 1-dimensional Voigt function. voigt(x, amplitude, center, sigma, gamma) = amplitude*wofz(z).real / (sigma*s2pi) see http://en.wikipedia.org/wiki/Voigt_profile """ if gamma is None: gamma = sigma z = (x-center + 1j*gamma) / (sigma*s2) return amplitude*wofz(z).real / (sigma*s2pi) def pvoigt(x, amplitude=1.0, center=0.0, sigma=1.0, fraction=0.5): """Return a 1-dimensional pseudo-Voigt function. pvoigt(x, amplitude, center, sigma, fraction) = amplitude*(1-fraction)*gaussion(x, center, sigma_g) + amplitude*fraction*lorentzian(x, center, sigma) where sigma_g (the sigma for the Gaussian component) is sigma_g = sigma / sqrt(2*log(2)) ~= sigma / 1.17741 so that the Gaussian and Lorentzian components have the same FWHM of 2*sigma. """ sigma_g = sigma / sqrt(2*log2) return ((1-fraction)*gaussian(x, amplitude, center, sigma_g) + fraction*lorentzian(x, amplitude, center, sigma)) def moffat(x, amplitude=1, center=0., sigma=1, beta=1.): """Return a 1-dimensional Moffat function. moffat(x, amplitude, center, sigma, beta) = amplitude / (((x - center)/sigma)**2 + 1)**beta """ return amplitude / (((x - center)/sigma)**2 + 1)**beta def pearson7(x, amplitude=1.0, center=0.0, sigma=1.0, expon=1.0): """Return a Pearson7 lineshape. Using the wikipedia definition: pearson7(x, center, sigma, expon) = amplitude*(1+arg**2)**(-expon)/(sigma*beta(expon-0.5, 0.5)) where arg = (x-center)/sigma and beta() is the beta function. """ arg = (x-center)/sigma scale = amplitude * gamfcn(expon)/(gamfcn(0.5)*gamfcn(expon-0.5)) return scale*(1+arg**2)**(-expon)/sigma def breit_wigner(x, amplitude=1.0, center=0.0, sigma=1.0, q=1.0): """Return a Breit-Wigner-Fano lineshape. breit_wigner(x, amplitude, center, sigma, q) = amplitude*(q*sigma/2 + x - center)**2 / ( (sigma/2)**2 + (x - center)**2 ) """ gam = sigma/2.0 return amplitude*(q*gam + x - center)**2 / (gam*gam + (x-center)**2) def damped_oscillator(x, amplitude=1.0, center=1., sigma=0.1): """Return the amplitude for a damped harmonic oscillator. damped_oscillator(x, amplitude, center, sigma) = amplitude/sqrt( (1.0 - (x/center)**2)**2 + (2*sigma*x/center)**2)) """ center = max(1.e-9, abs(center)) return amplitude/sqrt((1.0 - (x/center)**2)**2 + (2*sigma*x/center)**2) def dho(x, amplitude=1., center=0., sigma=1., gamma=1.0): """Return a Damped Harmonic Oscillator. Similar to version from PAN dho(x, amplitude, center, sigma, gamma) = (amplitude*sigma*(bose/pi)* (lm - lp) where bose(x, gamma) = 1.0/ (1.0 - exp(-x/gamma)) lm(x, center, sigma) = 1.0 / ((x-center)**2 + sigma**2) lp(x, center, sigma) = 1.0 / ((x+center)**2 + sigma**2) """ bose = 1.0/(1.0 - exp(-x/gamma)) lm = 1.0/((x-center)**2 + sigma**2) lp = 1.0/((x+center)**2 + sigma**2) return amplitude*sigma*pi*bose*(lm - lp) def logistic(x, amplitude=1., center=0., sigma=1.): """Return a Logistic lineshape (yet another sigmoidal curve). logistic(x, amplitude, center, sigma) = = amplitude*(1. - 1. / (1 + exp((x-center)/sigma))) """ return amplitude*(1. - 1./(1. + exp((x-center)/sigma))) def lognormal(x, amplitude=1.0, center=0., sigma=1): """Return a log-normal function. lognormal(x, amplitude, center, sigma) = (amplitude/x) * exp(-(ln(x) - center)/ (2* sigma**2)) """ x[where(x <= 1.e-19)] = 1.e-19 return (amplitude/(x*sigma*s2pi)) * exp(-(log(x)-center)**2 / (2*sigma**2)) def students_t(x, amplitude=1.0, center=0.0, sigma=1.0): """Return Student's t distribution. students_t(x, amplitude, center, sigma) = gamma((sigma+1)/2) (1 + (x-center)**2/sigma)^(-(sigma+1)/2) ------------------------- sqrt(sigma*pi)gamma(sigma/2) """ s1 = (sigma+1)/2.0 denom = (sqrt(sigma*pi)*gamfcn(sigma/2)) return amplitude*(1 + (x-center)**2/sigma)**(-s1) * gamfcn(s1) / denom def expgaussian(x, amplitude=1, center=0, sigma=1.0, gamma=1.0): """Return a exponentially modified Gaussian. expgaussian(x, amplitude, center, sigma, gamma=) = (gamma/2) exp[center*gamma + (gamma*sigma)**2/2 - gamma*x] * erfc[(center + gamma*sigma**2 - x)/(sqrt(2)*sigma)] http://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution """ gss = gamma*sigma*sigma arg1 = gamma*(center + gss/2.0 - x) arg2 = (center + gss - x)/(s2*sigma) return amplitude*(gamma/2) * exp(arg1) * erfc(arg2) def donaich(x, amplitude=1.0, center=0, sigma=1.0, gamma=0.0): """Return a Doniach Sunjic asymmetric lineshape, used for photo-emission. donaich(x, amplitude, center, sigma, gamma) = amplitude* cos(pi*gamma/2 + (1-gamma) arctan((x-center)/sigma) / (sigma**2 + (x-center)**2)**[(1-gamma)/2] see http://www.casaxps.com/help_manual/line_shapes.htm """ arg = (x-center)/sigma gm1 = (1.0 - gamma) scale = amplitude/(sigma**gm1) return scale*cos(pi*gamma/2 + gm1*arctan(arg))/(1 + arg**2)**(gm1/2) def skewed_gaussian(x, amplitude=1.0, center=0.0, sigma=1.0, gamma=0.0): """Return a Gaussian lineshape, skewed with error function. Equal to: gaussian(x, center, sigma)*(1+erf(beta*(x-center))) with beta = gamma/(sigma*sqrt(2)) with gamma < 0: tail to low value of centroid gamma > 0: tail to high value of centroid see http://en.wikipedia.org/wiki/Skew_normal_distribution """ asym = 1 + erf(gamma*(x-center)/(s2*sigma)) return asym * gaussian(x, amplitude, center, sigma) def skewed_voigt(x, amplitude=1.0, center=0.0, sigma=1.0, gamma=None, skew=0.0): """Return a Voigt lineshape, skewed with error function. useful for ad-hoc Compton scatter profile with beta = skew/(sigma*sqrt(2)) = voigt(x, center, sigma, gamma)*(1+erf(beta*(x-center))) skew < 0: tail to low value of centroid skew > 0: tail to high value of centroid see http://en.wikipedia.org/wiki/Skew_normal_distribution """ beta = skew/(s2*sigma) asym = 1 + erf(beta*(x-center)) return asym * voigt(x, amplitude, center, sigma, gamma=gamma) def step(x, amplitude=1.0, center=0.0, sigma=1.0, form='linear'): """Return a step function. starts at 0.0, ends at amplitude, with half-max at center, and rising with form: 'linear' (default) = amplitude * min(1, max(0, arg)) 'atan', 'arctan' = amplitude * (0.5 + atan(arg)/pi) 'erf' = amplitude * (1 + erf(arg))/2.0 'logistic' = amplitude * [1 - 1/(1 + exp(arg))] where arg = (x - center)/sigma """ if abs(sigma) < 1.e-13: sigma = 1.e-13 out = (x - center)/sigma if form == 'erf': out = 0.5*(1 + erf(out)) elif form.startswith('logi'): out = (1. - 1./(1. + exp(out))) elif form in ('atan', 'arctan'): out = 0.5 + arctan(out)/pi else: out[where(out < 0)] = 0.0 out[where(out > 1)] = 1.0 return amplitude*out def rectangle(x, amplitude=1.0, center1=0.0, sigma1=1.0, center2=1.0, sigma2=1.0, form='linear'): """Return a rectangle function: step up, step down. (see step function) starts at 0.0, rises to amplitude (at center1 with width sigma1) then drops to 0.0 (at center2 with width sigma2) with form: 'linear' (default) = ramp_up + ramp_down 'atan', 'arctan' = amplitude*(atan(arg1) + atan(arg2))/pi 'erf' = amplitude*(erf(arg1) + erf(arg2))/2. 'logisitic' = amplitude*[1 - 1/(1 + exp(arg1)) - 1/(1+exp(arg2))] where arg1 = (x - center1)/sigma1 and arg2 = -(x - center2)/sigma2 """ if abs(sigma1) < 1.e-13: sigma1 = 1.e-13 if abs(sigma2) < 1.e-13: sigma2 = 1.e-13 arg1 = (x - center1)/sigma1 arg2 = (center2 - x)/sigma2 if form == 'erf': out = 0.5*(erf(arg1) + erf(arg2)) elif form.startswith('logi'): out = (1. - 1./(1. + exp(arg1)) - 1./(1. + exp(arg2))) elif form in ('atan', 'arctan'): out = (arctan(arg1) + arctan(arg2))/pi else: arg1[where(arg1 < 0)] = 0.0 arg1[where(arg1 > 1)] = 1.0 arg2[where(arg2 > 0)] = 0.0 arg2[where(arg2 < -1)] = -1.0 out = arg1 + arg2 return amplitude*out def _erf(x): """Return the error function. erf = 2/sqrt(pi)*integral(exp(-t**2), t=[0, z]) """ return erf(x) def _erfc(x): """Return the complementary error function. erfc = 1 - erf(x) """ return erfc(x) def _wofz(x): """Return the fadeeva function for complex argument. wofz = exp(-x**2)*erfc(-i*x) """ return wofz(x) def _gamma(x): """Return the gamma function.""" return gamfcn(x) def _gammaln(x): """Return the log of absolute value of gamma function.""" return gammaln(x) def exponential(x, amplitude=1, decay=1): """Return an exponential function. x -> amplitude * exp(-x/decay) """ return amplitude * exp(-x/decay) def powerlaw(x, amplitude=1, exponent=1.0): """Return the powerlaw function. x -> amplitude * x**exponent """ return amplitude * x**exponent def linear(x, slope=1.0, intercept=0.0): """Return a linear function. x -> slope * x + intercept """ return slope * x + intercept def parabolic(x, a=0.0, b=0.0, c=0.0): """Return a parabolic function. x -> a * x**2 + b * x + c """ return a * x**2 + b * x + c def assert_results_close(actual, desired, rtol=1e-03, atol=1e-03, err_msg='', verbose=True): """Check whether all actual and desired parameter values are close.""" for param_name, value in desired.items(): assert_allclose(actual[param_name], value, rtol, atol, err_msg, verbose) lmfit-0.9.7/lmfit/minimizer.py0000644000076500000240000023431013113614263017245 0ustar Newvillestaff00000000000000"""Simple minimizer is a wrapper around scipy.leastsq, allowing a user to build a fitting model as a function of general purpose Fit Parameters that can be fixed or varied, bounded, and written as a simple expression of other Fit Parameters. The user sets up a model in terms of instance of Parameters and writes a function-to-be-minimized (residual function) in terms of these Parameters. Original copyright: Copyright (c) 2011 Matthew Newville, The University of Chicago See LICENSE for more complete authorship information and license. """ from collections import namedtuple from copy import deepcopy import multiprocessing import numbers import warnings import numpy as np from numpy import dot, eye, ndarray, ones_like, sqrt, take, transpose, triu from numpy.dual import inv from numpy.linalg import LinAlgError from scipy.optimize import brute as scipy_brute from scipy.optimize import leastsq as scipy_leastsq from scipy.optimize import minimize as scipy_minimize from scipy.optimize import differential_evolution from scipy.stats import cauchy as cauchy_dist from scipy.stats import norm as norm_dist import six # use locally modified version of uncertainties package from . import uncertainties from .parameter import Parameter, Parameters # scipy version notes: # currently scipy 0.15 is required. # feature scipy version added # minimize 0.11 # OptimizeResult 0.13 # diff_evolution 0.15 # least_squares 0.17 # check for scipy.opitimize.least_squares HAS_LEAST_SQUARES = False try: from scipy.optimize import least_squares HAS_LEAST_SQUARES = True except ImportError: pass # check for EMCEE HAS_EMCEE = False try: import emcee as emcee HAS_EMCEE = True except ImportError: pass # check for pandas HAS_PANDAS = False try: import pandas as pd HAS_PANDAS = True except ImportError: pass # define the namedtuple here so pickle will work with the MinimizerResult Candidate = namedtuple('Candidate', ['params', 'score']) def asteval_with_uncertainties(*vals, **kwargs): """Calculate object value, given values for variables. This is used by the uncertainties package to calculate the uncertainty in an object even with a complicated expression. """ _obj = kwargs.get('_obj', None) _pars = kwargs.get('_pars', None) _names = kwargs.get('_names', None) _asteval = _pars._asteval if (_obj is None or _pars is None or _names is None or _asteval is None or _obj._expr_ast is None): return 0 for val, name in zip(vals, _names): _asteval.symtable[name] = val return _asteval.eval(_obj._expr_ast) wrap_ueval = uncertainties.wrap(asteval_with_uncertainties) def eval_stderr(obj, uvars, _names, _pars): """Evaluate uncertainty and set .stderr for a parameter `obj`. Given the uncertain values `uvars` (a list of uncertainties.ufloats), a list of parameter names that matches uvars, and a dict of param objects, keyed by name. This uses the uncertainties package wrapped function to evaluate the uncertainty for an arbitrary expression (in obj._expr_ast) of parameters. """ if not isinstance(obj, Parameter) or getattr(obj, '_expr_ast', None) is None: return uval = wrap_ueval(*uvars, _obj=obj, _names=_names, _pars=_pars) try: obj.stderr = uval.std_dev() except: obj.stderr = 0 class MinimizerException(Exception): """General Purpose Exception.""" def __init__(self, msg): Exception.__init__(self) self.msg = msg def __str__(self): return "\n%s" % self.msg SCALAR_METHODS = {'nelder': 'Nelder-Mead', 'powell': 'Powell', 'cg': 'CG', 'bfgs': 'BFGS', 'newton': 'Newton-CG', 'lbfgsb': 'L-BFGS-B', 'l-bfgsb': 'L-BFGS-B', 'tnc': 'TNC', 'cobyla': 'COBYLA', 'slsqp': 'SLSQP', 'dogleg': 'dogleg', 'trust-ncg': 'trust-ncg', 'differential_evolution': 'differential_evolution'} def reduce_chisquare(r): """Reduce residual array to scalar (chi-square). Calculate the chi-square value from the residual array `r`: (r*r).sum() Parameters ---------- r : numpy.ndarray Residual array. Returns ------- float Chi-square calculated from the residual array """ return (r*r).sum() def reduce_negentropy(r): """Reduce residual array to scalar (negentropy). Reduce residual array `r` to scalar using negative entropy and the normal (Gaussian) probability distribution of `r` as pdf: (norm.pdf(r)*norm.logpdf(r)).sum() since pdf(r) = exp(-r*r/2)/sqrt(2*pi), this is ((r*r/2 - log(sqrt(2*pi))) * exp(-r*r/2)).sum() Parameters ---------- r : numpy.ndarray Residual array. Returns ------- float Negative entropy value calculated from the residual array """ return (norm_dist.pdf(r)*norm_dist.logpdf(r)).sum() def reduce_cauchylogpdf(r): """Reduce residual array to scalar (cauchylogpdf). Reduce residual array `r` to scalar using negative log-likelihood and a Cauchy (Lorentzian) distribution of `r`: -scipy.stats.cauchy.logpdf(r) (where the Cauchy pdf = 1/(pi*(1+r*r))). This gives greater suppression of outliers compared to normal sum-of-squares. Parameters ---------- r : numpy.ndarray Residual array. Returns ------- float Negative entropy value calculated from the residual array """ return -cauchy_dist.logpdf(r).sum() class MinimizerResult(object): r""" The results of a minimization. Minimization results include data such as status and error messages, fit statistics, and the updated (i.e., best-fit) parameters themselves in the :attr:`params` attribute. The list of (possible) `MinimizerResult` attributes is given below: Attributes ---------- params : :class:`~lmfit.parameter.Parameters` The best-fit parameters resulting from the fit. status : int Termination status of the optimizer. Its value depends on the underlying solver. Refer to `message` for details. var_names : list Ordered list of variable parameter names used in optimization, and useful for understanding the values in :attr:`init_vals` and :attr:`covar`. covar : numpy.ndarray Covariance matrix from minimization (`leastsq` only), with rows and columns corresponding to :attr:`var_names`. init_vals : list List of initial values for variable parameters using :attr:`var_names`. init_values : dict Dictionary of initial values for variable parameters. nfev : int Number of function evaluations. success : bool True if the fit succeeded, otherwise False. errorbars : bool True if uncertainties were estimated, otherwise False. message : str Message about fit success. ier : int Integer error value from :scipydoc:`optimize.leastsq` (`leastsq` only). lmdif_message : str Message from :scipydoc:`optimize.leastsq` (`leastsq` only). nvarys : int Number of variables in fit: :math:`N_{\rm varys}`. ndata : int Number of data points: :math:`N`. nfree : int Degrees of freedom in fit: :math:`N - N_{\rm varys}`. residual : numpy.ndarray Residual array :math:`{\rm Resid_i}`. Return value of the objective function when using the best-fit values of the parameters. chisqr : float Chi-square: :math:`\chi^2 = \sum_i^N [{\rm Resid}_i]^2`. redchi : float Reduced chi-square: :math:`\chi^2_{\nu}= {\chi^2} / {(N - N_{\rm varys})}`. aic : float Akaike Information Criterion statistic: :math:`N \ln(\chi^2/N) + 2 N_{\rm varys}`. bic : float Bayesian Information Criterion statistic: :math:`N \ln(\chi^2/N) + \ln(N) N_{\rm varys}`. flatchain : pandas.DataFrame A flatchain view of the sampling chain from the `emcee` method. Methods ------- show_candidates Pretty_print() representation of candidates from the `brute` method. """ def __init__(self, **kws): for key, val in kws.items(): setattr(self, key, val) @property def flatchain(self): """A flatchain view of the sampling chain from the `emcee` method.""" if hasattr(self, 'chain'): if HAS_PANDAS: if len(self.chain.shape) == 4: return pd.DataFrame(self.chain[0, ...].reshape((-1, self.nvarys)), columns=self.var_names) elif len(self.chain.shape) == 3: return pd.DataFrame(self.chain.reshape((-1, self.nvarys)), columns=self.var_names) else: raise NotImplementedError('Please install Pandas to see the ' 'flattened chain') else: return None def show_candidates(self, candidate_nmb='all'): """A pretty_print() representation of the candidates. Showing candidates (default is 'all') or the specified candidate-# from the `brute` method. Parameters ---------- candidate_nmb : int or 'all' The candidate-number to show using the :meth:`pretty_print` method. """ if hasattr(self, 'candidates'): try: candidate = self.candidates[candidate_nmb] print("\nCandidate #{}, chisqr = " "{:.3f}".format(candidate_nmb, candidate.score)) candidate.params.pretty_print() except: for i, candidate in enumerate(self.candidates): print("\nCandidate #{}, chisqr = " "{:.3f}".format(i, candidate.score)) candidate.params.pretty_print() class Minimizer(object): """A general minimizer for curve fitting and optimization.""" _err_nonparam = ("params must be a minimizer.Parameters() instance or list " "of Parameters()") _err_maxfev = ("Too many function calls (max set to %i)! Use:" " minimize(func, params, ..., maxfev=NNN)" "or set leastsq_kws['maxfev'] to increase this maximum.") def __init__(self, userfcn, params, fcn_args=None, fcn_kws=None, iter_cb=None, scale_covar=True, nan_policy='raise', reduce_fcn=None, **kws): """ Parameters ---------- userfcn : callable Objective function that returns the residual (difference between model and data) to be minimized in a least-squares sense. This function must have the signature:: userfcn(params, *fcn_args, **fcn_kws) params : :class:`~lmfit.parameter.Parameters` Contains the Parameters for the model. fcn_args : tuple, optional Positional arguments to pass to `userfcn`. fcn_kws : dict, optional Keyword arguments to pass to `userfcn`. iter_cb : callable, optional Function to be called at each fit iteration. This function should have the signature:: iter_cb(params, iter, resid, *fcn_args, **fcn_kws) where `params` will have the current parameter values, `iter` the iteration, `resid` the current residual array, and `*fcn_args` and `**fcn_kws` are passed to the objective function. scale_covar : bool, optional Whether to automatically scale the covariance matrix (`leastsq` only). nan_policy : str, optional Specifies action if `userfcn` (or a Jacobian) returns NaN values. One of: - 'raise' : a `ValueError` is raised - 'propagate' : the values returned from `userfcn` are un-altered - 'omit' : non-finite values are filtered reduce_fcn : str or callable, optional Function to convert a residual array to a scalar value for the scalar minimizers. Optional values are (where `r` is the residual array): - None : sum of squares of residual [default] = (r*r).sum() - 'negentropy' : neg entropy, using normal distribution = rho*log(rho).sum()`, where rho = exp(-r*r/2)/(sqrt(2*pi)) - 'neglogcauchy': neg log likelihood, using Cauchy distribution = -log(1/(pi*(1+r*r))).sum() - callable : must take one argument (`r`) and return a float. **kws : dict, optional Options to pass to the minimizer being used. Notes ----- The objective function should return the value to be minimized. For the Levenberg-Marquardt algorithm from :meth:`leastsq` or :meth:`least_squares`, this returned value must be an array, with a length greater than or equal to the number of fitting variables in the model. For the other methods, the return value can either be a scalar or an array. If an array is returned, the sum of squares of the array will be sent to the underlying fitting method, effectively doing a least-squares optimization of the return values. If the objective function returns non-finite values then a `ValueError` will be raised because the underlying solvers cannot deal with them. A common use for the `fcn_args` and `fcn_kws` would be to pass in other data needed to calculate the residual, including such things as the data array, dependent variable, uncertainties in the data, and other data structures for the model calculation. """ self.userfcn = userfcn self.userargs = fcn_args if self.userargs is None: self.userargs = [] self.userkws = fcn_kws if self.userkws is None: self.userkws = {} self.kws = kws self.iter_cb = iter_cb self.scale_covar = scale_covar self.nfev = 0 self.nfree = 0 self.ndata = 0 self.ier = 0 self._abort = False self.success = True self.errorbars = False self.message = None self.lmdif_message = None self.chisqr = None self.redchi = None self.covar = None self.residual = None self.reduce_fcn = reduce_fcn self.params = params self.jacfcn = None self.nan_policy = nan_policy @property def values(self): """Return Parameter values in a simple dictionary.""" return {name: p.value for name, p in self.result.params.items()} def __residual(self, fvars, apply_bounds_transformation=True): """Residual function used for least-squares fit. With the new, candidate values of `fvars` (the fitting variables), this evaluates all parameters, including setting bounds and evaluating constraints, and then passes those to the user-supplied function to calculate the residual. Parameters ---------- fvars : numpy.ndarray Array of new parameter values suggested by the minimizer. apply_bounds_transformation : bool, optional Whether to apply lmfits parameter transformation to constrain parameters (default is True). This is needed for solvers without inbuilt support for bounds. Returns ------- residual : numpy.ndarray The evaluated function values for given `fvars`. """ # set parameter values if self._abort: return None params = self.result.params if fvars.shape == (): fvars = fvars.reshape((1,)) if apply_bounds_transformation: for name, val in zip(self.result.var_names, fvars): params[name].value = params[name].from_internal(val) else: for name, val in zip(self.result.var_names, fvars): params[name].value = val params.update_constraints() self.result.nfev += 1 out = self.userfcn(params, *self.userargs, **self.userkws) out = _nan_policy(out, nan_policy=self.nan_policy) if callable(self.iter_cb): abort = self.iter_cb(params, self.result.nfev, out, *self.userargs, **self.userkws) self._abort = self._abort or abort self._abort = self._abort and self.result.nfev > len(fvars) if not self._abort: return np.asarray(out).ravel() def __jacobian(self, fvars): """Reuturn analytical jacobian to be used with Levenberg-Marquardt. modified 02-01-2012 by Glenn Jones, Aberystwyth University modified 06-29-2015 M Newville to apply gradient scaling for bounded variables (thanks to JJ Helmus, N Mayorov) """ pars = self.result.params grad_scale = ones_like(fvars) for ivar, name in enumerate(self.result.var_names): val = fvars[ivar] pars[name].value = pars[name].from_internal(val) grad_scale[ivar] = pars[name].scale_gradient(val) self.result.nfev += 1 pars.update_constraints() # compute the jacobian for "internal" unbounded variables, # then rescale for bounded "external" variables. jac = self.jacfcn(pars, *self.userargs, **self.userkws) jac = _nan_policy(jac, nan_policy=self.nan_policy) if self.col_deriv: jac = (jac.transpose()*grad_scale).transpose() else: jac *= grad_scale return jac def penalty(self, fvars): """Penalty function for scalar minimizers. Parameters ---------- fvars : numpy.ndarray Array of values for the variable parameters. Returns ------- r : float The evaluated user-supplied objective function. If the objective function is an array of size greater than 1, use the scalar returned by `self.reduce_fcn`. This defaults to sum-of-squares, but can be replaced by other options. """ r = self.__residual(fvars) if isinstance(r, ndarray) and r.size > 1: r = self.reduce_fcn(r) if isinstance(r, ndarray) and r.size > 1: r = r.sum() return r def penalty_brute(self, fvars): """Penalty function for brute force method. Parameters ---------- fvars : numpy.ndarray Array of values for the variable parameters Returns ------- r : float The evaluated user-supplied objective function. If the objective function is an array of size greater than 1, use the scalar returned by `self.reduce_fcn`. This defaults to sum-of-squares, but can be replaced by other options. """ r = self.__residual(fvars, apply_bounds_transformation=False) if isinstance(r, ndarray) and r.size > 1: r = (r*r).sum() return r def prepare_fit(self, params=None): """Prepare parameters for fitting. Prepares and initializes model and Parameters for subsequent fitting. This routine prepares the conversion of :class:`Parameters` into fit variables, organizes parameter bounds, and parses, "compiles" and checks constrain expressions. The method also creates and returns a new instance of a :class:`MinimizerResult` object that contains the copy of the Parameters that will actually be varied in the fit. Parameters ---------- params : :class:`~lmfit.parameter.Parameters`, optional Contains the Parameters for the model; if None, then the Parameters used to initialize the Minimizer object are used. Returns ------- :class:`MinimizerResult` Notes ----- This method is called directly by the fitting methods, and it is generally not necessary to call this function explicitly. .. versionchanged:: 0.9.0 Return value changed to :class:`MinimizerResult`. """ # determine which parameters are actually variables # and which are defined expressions. self.result = MinimizerResult() result = self.result if params is not None: self.params = params if isinstance(self.params, Parameters): result.params = deepcopy(self.params) elif isinstance(self.params, (list, tuple)): result.params = Parameters() for par in self.params: if not isinstance(par, Parameter): raise MinimizerException(self._err_nonparam) else: result.params[par.name] = par elif self.params is None: raise MinimizerException(self._err_nonparam) # determine which parameters are actually variables # and which are defined expressions. result.var_names = [] # note that this *does* belong to self... result.init_vals = [] result.params.update_constraints() result.nfev = 0 result.errorbars = False result.aborted = False for name, par in self.result.params.items(): par.stderr = None par.correl = None if par.expr is not None: par.vary = False if par.vary: result.var_names.append(name) result.init_vals.append(par.setup_bounds()) par.init_value = par.value if par.name is None: par.name = name result.nvarys = len(result.var_names) result.init_values = {n: v for n, v in zip(result.var_names, result.init_vals)} # set up reduce function for scalar minimizers # 1. user supplied callable # 2. string starting with 'neglogc' or 'negent' # 3. sum of squares if not callable(self.reduce_fcn): if isinstance(self.reduce_fcn, six.string_types): if self.reduce_fcn.lower().startswith('neglogc'): self.reduce_fcn = reduce_cauchylogpdf elif self.reduce_fcn.lower().startswith('negent'): self.reduce_fcn = reduce_negentropy if self.reduce_fcn is None: self.reduce_fcn = reduce_chisquare return result def unprepare_fit(self): """Clean fit state, so that subsequent fits need to call prepare_fit(). removes AST compilations of constraint expressions. """ pass def scalar_minimize(self, method='Nelder-Mead', params=None, **kws): """Scalar minimization using :scipydoc:`optimize.minimize`. Perform fit with any of the scalar minimization algorithms supported by :scipydoc:`optimize.minimize`. Default argument values are: +-------------------------+-----------------+-----------------------------------------------------+ | :meth:`scalar_minimize` | Default Value | Description | | arg | | | +=========================+=================+=====================================================+ | method | ``Nelder-Mead`` | fitting method | +-------------------------+-----------------+-----------------------------------------------------+ | tol | 1.e-7 | fitting and parameter tolerance | +-------------------------+-----------------+-----------------------------------------------------+ | hess | None | Hessian of objective function | +-------------------------+-----------------+-----------------------------------------------------+ Parameters ---------- method : str, optional Name of the fitting method to use. One of: - 'Nelder-Mead' (default) - 'L-BFGS-B' - 'Powell' - 'CG' - 'Newton-CG' - 'COBYLA' - 'TNC' - 'trust-ncg' - 'dogleg' - 'SLSQP' - 'differential_evolution' params : :class:`~lmfit.parameter.Parameters`, optional Parameters to use as starting point. **kws : dict, optional Minimizer options pass to :scipydoc:`optimize.minimize`. Returns ------- :class:`MinimizerResult` Object containing the optimized parameter and several goodness-of-fit statistics. .. versionchanged:: 0.9.0 Return value changed to :class:`MinimizerResult`. Notes ----- If the objective function returns a NumPy array instead of the expected scalar, the sum of squares of the array will be used. Note that bounds and constraints can be set on Parameters for any of these methods, so are not supported separately for those designed to use bounds. However, if you use the differential_evolution method you must specify finite (min, max) for each varying Parameter. """ result = self.prepare_fit(params=params) result.method = method vars = result.init_vals params = result.params fmin_kws = dict(method=method, options={'maxiter': 1000 * (len(vars) + 1)}) fmin_kws.update(self.kws) fmin_kws.update(kws) # hess supported only in some methods if 'hess' in fmin_kws and method not in ('Newton-CG', 'dogleg', 'trust-ncg'): fmin_kws.pop('hess') # jac supported only in some methods (and Dfun could be used...) if 'jac' not in fmin_kws and fmin_kws.get('Dfun', None) is not None: self.jacfcn = fmin_kws.pop('jac') fmin_kws['jac'] = self.__jacobian if 'jac' in fmin_kws and method not in ('CG', 'BFGS', 'Newton-CG', 'dogleg', 'trust-ncg'): self.jacfcn = None fmin_kws.pop('jac') if method == 'differential_evolution': for par in params.values(): if (par.vary and not (np.isfinite(par.min) and np.isfinite(par.max))): raise ValueError('differential_evolution requires finite ' 'bound for all varying parameters') _bounds = [(-np.pi / 2., np.pi / 2.)] * len(vars) kwargs = dict(args=(), strategy='best1bin', maxiter=None, popsize=15, tol=0.01, mutation=(0.5, 1), recombination=0.7, seed=None, callback=None, disp=False, polish=True, init='latinhypercube') for k, v in fmin_kws.items(): if k in kwargs: kwargs[k] = v ret = differential_evolution(self.penalty, _bounds, **kwargs) else: ret = scipy_minimize(self.penalty, vars, **fmin_kws) result.aborted = self._abort self._abort = False if isinstance(ret, dict): for attr, value in ret.items(): setattr(result, attr, value) else: for attr in dir(ret): if not attr.startswith('_'): setattr(result, attr, getattr(ret, attr)) result.x = np.atleast_1d(result.x) result.chisqr = result.residual = self.__residual(result.x) result.nvarys = len(vars) result.ndata = 1 result.nfree = 1 if isinstance(result.residual, ndarray): result.chisqr = (result.chisqr**2).sum() result.ndata = len(result.residual) result.nfree = result.ndata - result.nvarys result.redchi = result.chisqr / max(1, result.nfree) # this is -2*loglikelihood _neg2_log_likel = result.ndata * np.log(result.chisqr / result.ndata) result.aic = _neg2_log_likel + 2 * result.nvarys result.bic = _neg2_log_likel + np.log(result.ndata) * result.nvarys return result def emcee(self, params=None, steps=1000, nwalkers=100, burn=0, thin=1, ntemps=1, pos=None, reuse_sampler=False, workers=1, float_behavior='posterior', is_weighted=True, seed=None): r""" Bayesian sampling of the posterior distribution using `emcee`. Bayesian sampling of the posterior distribution for the parameters using the `emcee` Markov Chain Monte Carlo package. The method assumes that the prior is Uniform. You need to have `emcee` installed to use this method. Parameters ---------- params : :class:`~lmfit.parameter.Parameters`, optional Parameters to use as starting point. If this is not specified then the Parameters used to initialize the Minimizer object are used. steps : int, optional How many samples you would like to draw from the posterior distribution for each of the walkers? nwalkers : int, optional Should be set so :math:`nwalkers >> nvarys`, where `nvarys` are the number of parameters being varied during the fit. "Walkers are the members of the ensemble. They are almost like separate Metropolis-Hastings chains but, of course, the proposal distribution for a given walker depends on the positions of all the other walkers in the ensemble." - from the `emcee` webpage. burn : int, optional Discard this many samples from the start of the sampling regime. thin : int, optional Only accept 1 in every `thin` samples. ntemps : int, optional If `ntemps > 1` perform a Parallel Tempering. pos : numpy.ndarray, optional Specify the initial positions for the sampler. If `ntemps == 1` then `pos.shape` should be `(nwalkers, nvarys)`. Otherwise, `(ntemps, nwalkers, nvarys)`. You can also initialise using a previous chain that had the same `ntemps`, `nwalkers` and `nvarys`. Note that `nvarys` may be one larger than you expect it to be if your `userfcn` returns an array and `is_weighted is False`. reuse_sampler : bool, optional If you have already run `emcee` on a given `Minimizer` object then it possesses an internal ``sampler`` attribute. You can continue to draw from the same sampler (retaining the chain history) if you set this option to True. Otherwise a new sampler is created. The `nwalkers`, `ntemps`, `pos`, and `params` keywords are ignored with this option. **Important**: the Parameters used to create the sampler must not change in-between calls to `emcee`. Alteration of Parameters would include changed ``min``, ``max``, ``vary`` and ``expr`` attributes. This may happen, for example, if you use an altered Parameters object and call the `minimize` method in-between calls to `emcee`. workers : Pool-like or int, optional For parallelization of sampling. It can be any Pool-like object with a map method that follows the same calling sequence as the built-in `map` function. If int is given as the argument, then a multiprocessing-based pool is spawned internally with the corresponding number of parallel processes. 'mpi4py'-based parallelization and 'joblib'-based parallelization pools can also be used here. **Note**: because of multiprocessing overhead it may only be worth parallelising if the objective function is expensive to calculate, or if there are a large number of objective evaluations per step (`ntemps * nwalkers * nvarys`). float_behavior : str, optional Specifies meaning of the objective function output if it returns a float. One of: - 'posterior' - objective function returns a log-posterior probability - 'chi2' - objective function returns :math:`\chi^2` See Notes for further details. is_weighted : bool, optional Has your objective function been weighted by measurement uncertainties? If `is_weighted is True` then your objective function is assumed to return residuals that have been divided by the true measurement uncertainty `(data - model) / sigma`. If `is_weighted is False` then the objective function is assumed to return unweighted residuals, `data - model`. In this case `emcee` will employ a positive measurement uncertainty during the sampling. This measurement uncertainty will be present in the output params and output chain with the name `__lnsigma`. A side effect of this is that you cannot use this parameter name yourself. **Important** this parameter only has any effect if your objective function returns an array. If your objective function returns a float, then this parameter is ignored. See Notes for more details. seed : int or `numpy.random.RandomState`, optional If `seed` is an int, a new `numpy.random.RandomState` instance is used, seeded with `seed`. If `seed` is already a `numpy.random.RandomState` instance, then that `numpy.random.RandomState` instance is used. Specify `seed` for repeatable minimizations. Returns ------- :class:`MinimizerResult` MinimizerResult object containing updated params, statistics, etc. The updated params represent the median (50th percentile) of all the samples, whilst the parameter uncertainties are half of the difference between the 15.87 and 84.13 percentiles. The `MinimizerResult` also contains the ``chain``, ``flatchain`` and ``lnprob`` attributes. The ``chain`` and ``flatchain`` attributes contain the samples and have the shape `(nwalkers, (steps - burn) // thin, nvarys)` or `(ntemps, nwalkers, (steps - burn) // thin, nvarys)`, depending on whether Parallel tempering was used or not. `nvarys` is the number of parameters that are allowed to vary. The ``flatchain`` attribute is a `pandas.DataFrame` of the flattened chain, `chain.reshape(-1, nvarys)`. To access flattened chain values for a particular parameter use `result.flatchain[parname]`. The ``lnprob`` attribute contains the log probability for each sample in ``chain``. The sample with the highest probability corresponds to the maximum likelihood estimate. Notes ----- This method samples the posterior distribution of the parameters using Markov Chain Monte Carlo. To do so it needs to calculate the log-posterior probability of the model parameters, `F`, given the data, `D`, :math:`\ln p(F_{true} | D)`. This 'posterior probability' is calculated as: .. math:: \ln p(F_{true} | D) \propto \ln p(D | F_{true}) + \ln p(F_{true}) where :math:`\ln p(D | F_{true})` is the 'log-likelihood' and :math:`\ln p(F_{true})` is the 'log-prior'. The default log-prior encodes prior information already known about the model. This method assumes that the log-prior probability is `-numpy.inf` (impossible) if the one of the parameters is outside its limits. The log-prior probability term is zero if all the parameters are inside their bounds (known as a uniform prior). The log-likelihood function is given by [1]_: .. math:: \ln p(D|F_{true}) = -\frac{1}{2}\sum_n \left[\frac{(g_n(F_{true}) - D_n)^2}{s_n^2}+\ln (2\pi s_n^2)\right] The first summand in the square brackets represents the residual for a given datapoint (:math:`g` being the generative model, :math:`D_n` the data and :math:`s_n` the standard deviation, or measurement uncertainty, of the datapoint). This term represents :math:`\chi^2` when summed over all data points. Ideally the objective function used to create `lmfit.Minimizer` should return the log-posterior probability, :math:`\ln p(F_{true} | D)`. However, since the in-built log-prior term is zero, the objective function can also just return the log-likelihood, unless you wish to create a non-uniform prior. If a float value is returned by the objective function then this value is assumed by default to be the log-posterior probability, i.e. `float_behavior is 'posterior'`. If your objective function returns :math:`\chi^2`, then you should use a value of `'chi2'` for `float_behavior`. `emcee` will then multiply your :math:`\chi^2` value by -0.5 to obtain the posterior probability. However, the default behaviour of many objective functions is to return a vector of (possibly weighted) residuals. Therefore, if your objective function returns a vector, `res`, then the vector is assumed to contain the residuals. If `is_weighted is True` then your residuals are assumed to be correctly weighted by the standard deviation (measurement uncertainty) of the data points (`res = (data - model) / sigma`) and the log-likelihood (and log-posterior probability) is calculated as: `-0.5 * numpy.sum(res**2)`. This ignores the second summand in the square brackets. Consequently, in order to calculate a fully correct log-posterior probability value your objective function should return a single value. If `is_weighted is False` then the data uncertainty, `s_n`, will be treated as a nuisance parameter and will be marginalized out. This is achieved by employing a strictly positive uncertainty (homoscedasticity) for each data point, :math:`s_n = \exp(\_\_lnsigma)`. `__lnsigma` will be present in `MinimizerResult.params`, as well as `Minimizer.chain`, `nvarys` will also be increased by one. References ---------- .. [1] http://dan.iel.fm/emcee/current/user/line/ """ if not HAS_EMCEE: raise NotImplementedError('You must have emcee to use' ' the emcee method') tparams = params # if you're reusing the sampler then ntemps, nwalkers have to be # determined from the previous sampling if reuse_sampler: if not hasattr(self, 'sampler') or not hasattr(self, '_lastpos'): raise ValueError("You wanted to use an existing sampler, but" "it hasn't been created yet") if len(self._lastpos.shape) == 2: ntemps = 1 nwalkers = self._lastpos.shape[0] elif len(self._lastpos.shape) == 3: ntemps = self._lastpos.shape[0] nwalkers = self._lastpos.shape[1] tparams = None result = self.prepare_fit(params=tparams) result.method = 'emcee' params = result.params # check if the userfcn returns a vector of residuals out = self.userfcn(params, *self.userargs, **self.userkws) out = np.asarray(out).ravel() if out.size > 1 and is_weighted is False: # we need to marginalise over a constant data uncertainty if '__lnsigma' not in params: # __lnsigma should already be in params if is_weighted was # previously set to True. params.add('__lnsigma', value=0.01, min=-np.inf, max=np.inf, vary=True) # have to re-prepare the fit result = self.prepare_fit(params) params = result.params # Removing internal parameter scaling. We could possibly keep it, # but I don't know how this affects the emcee sampling. bounds = [] var_arr = np.zeros(len(result.var_names)) i = 0 for par in params: param = params[par] if param.expr is not None: param.vary = False if param.vary: var_arr[i] = param.value i += 1 else: # don't want to append bounds if they're not being varied. continue param.from_internal = lambda val: val lb, ub = param.min, param.max if lb is None or lb is np.nan: lb = -np.inf if ub is None or ub is np.nan: ub = np.inf bounds.append((lb, ub)) bounds = np.array(bounds) self.nvarys = len(result.var_names) # set up multiprocessing options for the samplers auto_pool = None sampler_kwargs = {} if isinstance(workers, int) and workers > 1: auto_pool = multiprocessing.Pool(workers) sampler_kwargs['pool'] = auto_pool elif hasattr(workers, 'map'): sampler_kwargs['pool'] = workers # function arguments for the log-probability functions # these values are sent to the log-probability functions by the sampler. lnprob_args = (self.userfcn, params, result.var_names, bounds) lnprob_kwargs = {'is_weighted': is_weighted, 'float_behavior': float_behavior, 'userargs': self.userargs, 'userkws': self.userkws, 'nan_policy': self.nan_policy} if ntemps > 1: # the prior and likelihood function args and kwargs are the same sampler_kwargs['loglargs'] = lnprob_args sampler_kwargs['loglkwargs'] = lnprob_kwargs sampler_kwargs['logpargs'] = (bounds,) else: sampler_kwargs['args'] = lnprob_args sampler_kwargs['kwargs'] = lnprob_kwargs # set up the random number generator rng = _make_random_gen(seed) # now initialise the samplers if reuse_sampler: if auto_pool is not None: self.sampler.pool = auto_pool p0 = self._lastpos if p0.shape[-1] != self.nvarys: raise ValueError("You cannot reuse the sampler if the number" "of varying parameters has changed") elif ntemps > 1: # Parallel Tempering # jitter the starting position by scaled Gaussian noise p0 = 1 + rng.randn(ntemps, nwalkers, self.nvarys) * 1.e-4 p0 *= var_arr self.sampler = emcee.PTSampler(ntemps, nwalkers, self.nvarys, _lnpost, _lnprior, **sampler_kwargs) else: p0 = 1 + rng.randn(nwalkers, self.nvarys) * 1.e-4 p0 *= var_arr self.sampler = emcee.EnsembleSampler(nwalkers, self.nvarys, _lnpost, **sampler_kwargs) # user supplies an initialisation position for the chain # If you try to run the sampler with p0 of a wrong size then you'll get # a ValueError. Note, you can't initialise with a position if you are # reusing the sampler. if pos is not None and not reuse_sampler: tpos = np.asfarray(pos) if p0.shape == tpos.shape: pass # trying to initialise with a previous chain elif tpos.shape[0::2] == (nwalkers, self.nvarys): tpos = tpos[:, -1, :] # initialising with a PTsampler chain. elif ntemps > 1 and tpos.ndim == 4: tpos_shape = list(tpos.shape) tpos_shape.pop(2) if tpos_shape == (ntemps, nwalkers, self.nvarys): tpos = tpos[..., -1, :] else: raise ValueError('pos should have shape (nwalkers, nvarys)' 'or (ntemps, nwalkers, nvarys) if ntemps > 1') p0 = tpos # if you specified a seed then you also need to seed the sampler if seed is not None: self.sampler.random_state = rng.get_state() # now do a production run, sampling all the time output = self.sampler.run_mcmc(p0, steps) self._lastpos = output[0] # discard the burn samples and thin chain = self.sampler.chain[..., burn::thin, :] lnprobability = self.sampler.lnprobability[..., burn::thin] # take the zero'th PTsampler temperature for the parameter estimators if ntemps > 1: flatchain = chain[0, ...].reshape((-1, self.nvarys)) else: flatchain = chain.reshape((-1, self.nvarys)) quantiles = np.percentile(flatchain, [15.87, 50, 84.13], axis=0) for i, var_name in enumerate(result.var_names): std_l, median, std_u = quantiles[:, i] params[var_name].value = median params[var_name].stderr = 0.5 * (std_u - std_l) params[var_name].correl = {} params.update_constraints() # work out correlation coefficients corrcoefs = np.corrcoef(flatchain.T) for i, var_name in enumerate(result.var_names): for j, var_name2 in enumerate(result.var_names): if i != j: result.params[var_name].correl[var_name2] = corrcoefs[i, j] result.chain = np.copy(chain) result.lnprob = np.copy(lnprobability) result.errorbars = True result.nvarys = len(result.var_names) if auto_pool is not None: auto_pool.terminate() return result def least_squares(self, params=None, **kws): """Use the `least_squares` (new in scipy 0.17) to perform a fit. It assumes that the input Parameters have been initialized, and a function to minimize has been properly set up. When possible, this calculates the estimated uncertainties and variable correlations from the covariance matrix. This method wraps :scipydoc:`optimize.least_squares`, which has inbuilt support for bounds and robust loss functions. Parameters ---------- params : :class:`~lmfit.parameter.Parameters`, optional Parameters to use as starting point. **kws : dict, optional Minimizer options to pass to :scipydoc:`optimize.least_squares`. Returns ------- :class:`MinimizerResult` Object containing the optimized parameter and several goodness-of-fit statistics. .. versionchanged:: 0.9.0 Return value changed to :class:`MinimizerResult`. """ if not HAS_LEAST_SQUARES: raise NotImplementedError("SciPy with a version higher than 0.17 " "is needed for this method.") result = self.prepare_fit(params) result.method = 'least_squares' replace_none = lambda x, sign: sign*np.inf if x is None else x start_vals, lower_bounds, upper_bounds = [], [], [] for vname in result.var_names: par = self.params[vname] start_vals.append(par.value) lower_bounds.append(replace_none(par.min, -1)) upper_bounds.append(replace_none(par.max, -1)) ret = least_squares(self.__residual, start_vals, bounds=(lower_bounds, upper_bounds), kwargs=dict(apply_bounds_transformation=False), **kws) for attr in ret: setattr(result, attr, ret[attr]) result.x = np.atleast_1d(result.x) result.chisqr = result.residual = self.__residual(result.x, False) result.nvarys = len(result.var_names) result.ndata = 1 result.nfree = 1 if isinstance(result.residual, ndarray): result.chisqr = (result.chisqr**2).sum() result.ndata = len(result.residual) result.nfree = result.ndata - result.nvarys result.redchi = result.chisqr / result.nfree # this is -2*loglikelihood _neg2_log_likel = result.ndata * np.log(result.chisqr / result.ndata) result.aic = _neg2_log_likel + 2 * result.nvarys result.bic = _neg2_log_likel + np.log(result.ndata) * result.nvarys return result def leastsq(self, params=None, **kws): """Use Levenberg-Marquardt minimization to perform a fit. It assumes that the input Parameters have been initialized, and a function to minimize has been properly set up. When possible, this calculates the estimated uncertainties and variable correlations from the covariance matrix. This method calls :scipydoc:`optimize.leastsq`. By default, numerical derivatives are used, and the following arguments are set: +------------------+----------------+------------------------------------------------------------+ | :meth:`leastsq` | Default Value | Description | | arg | | | +==================+================+============================================================+ | xtol | 1.e-7 | Relative error in the approximate solution | +------------------+----------------+------------------------------------------------------------+ | ftol | 1.e-7 | Relative error in the desired sum of squares | +------------------+----------------+------------------------------------------------------------+ | maxfev | 2000*(nvar+1) | Maximum number of function calls (nvar= # of variables) | +------------------+----------------+------------------------------------------------------------+ | Dfun | None | Function to call for Jacobian calculation | +------------------+----------------+------------------------------------------------------------+ Parameters ---------- params : :class:`~lmfit.parameter.Parameters`, optional Parameters to use as starting point. **kws : dict, optional Minimizer options to pass to :scipydoc:`optimize.leastsq`. Returns ------- :class:`MinimizerResult` Object containing the optimized parameter and several goodness-of-fit statistics. .. versionchanged:: 0.9.0 Return value changed to :class:`MinimizerResult`. """ result = self.prepare_fit(params=params) result.method = 'leastsq' vars = result.init_vals nvars = len(vars) lskws = dict(full_output=1, xtol=1.e-7, ftol=1.e-7, col_deriv=False, gtol=1.e-7, maxfev=2000*(nvars+1), Dfun=None) lskws.update(self.kws) lskws.update(kws) self.col_deriv = False if lskws['Dfun'] is not None: self.jacfcn = lskws['Dfun'] self.col_deriv = lskws['col_deriv'] lskws['Dfun'] = self.__jacobian # suppress runtime warnings during fit and error analysis orig_warn_settings = np.geterr() np.seterr(all='ignore') lsout = scipy_leastsq(self.__residual, vars, **lskws) _best, _cov, infodict, errmsg, ier = lsout result.aborted = self._abort self._abort = False result.residual = resid = infodict['fvec'] result.ier = ier result.lmdif_message = errmsg result.success = ier in [1, 2, 3, 4] if result.aborted: result.message = 'Fit aborted by user callback.' result.success = False elif ier in {1, 2, 3}: result.message = 'Fit succeeded.' elif ier == 0: result.message = ('Invalid Input Parameters. I.e. more variables ' 'than data points given, tolerance < 0.0, or ' 'no data provided.') elif ier == 4: result.message = 'One or more variable did not affect the fit.' elif ier == 5: result.message = self._err_maxfev % lskws['maxfev'] else: result.message = 'Tolerance seems to be too small.' result.ndata = len(resid) result.chisqr = (resid**2).sum() result.nfree = (result.ndata - nvars) result.redchi = result.chisqr / result.nfree result.nvarys = nvars # this is -2*loglikelihood _neg2_log_likel = result.ndata * np.log(result.chisqr / result.ndata) result.aic = _neg2_log_likel + 2 * result.nvarys result.bic = _neg2_log_likel + np.log(result.ndata) * result.nvarys params = result.params # need to map _best values to params, then calculate the # grad for the variable parameters grad = ones_like(_best) vbest = ones_like(_best) # ensure that _best, vbest, and grad are not # broken 1-element ndarrays. if len(np.shape(_best)) == 0: _best = np.array([_best]) if len(np.shape(vbest)) == 0: vbest = np.array([vbest]) if len(np.shape(grad)) == 0: grad = np.array([grad]) for ivar, name in enumerate(result.var_names): grad[ivar] = params[name].scale_gradient(_best[ivar]) vbest[ivar] = params[name].value # modified from JJ Helmus' leastsqbound.py infodict['fjac'] = transpose(transpose(infodict['fjac']) / take(grad, infodict['ipvt'] - 1)) rvec = dot(triu(transpose(infodict['fjac'])[:nvars, :]), take(eye(nvars), infodict['ipvt'] - 1, 0)) try: result.covar = inv(dot(transpose(rvec), rvec)) except (LinAlgError, ValueError): result.covar = None result.fjac = infodict['fjac'] has_expr = False for par in params.values(): par.stderr, par.correl = 0, None has_expr = has_expr or par.expr is not None # self.errorbars = error bars were successfully estimated result.errorbars = (result.covar is not None) if result.aborted: result.errorbars = False if result.errorbars: if self.scale_covar: result.covar *= result.redchi for ivar, name in enumerate(result.var_names): par = params[name] par.stderr = sqrt(result.covar[ivar, ivar]) par.correl = {} try: result.errorbars = result.errorbars and (par.stderr > 0.0) for jvar, varn2 in enumerate(result.var_names): if jvar != ivar: par.correl[varn2] = ( result.covar[ivar, jvar] / (par.stderr * sqrt(result.covar[jvar, jvar]))) except: result.errorbars = False if has_expr: # uncertainties on constrained parameters: # get values with uncertainties (including correlations), # temporarily set Parameter values to these, # re-evaluate contrained parameters to extract stderr # and then set Parameters back to best-fit value try: uvars = uncertainties.correlated_values(vbest, result.covar) except (LinAlgError, ValueError): uvars = None if uvars is not None: for par in params.values(): eval_stderr(par, uvars, result.var_names, params) # restore nominal values for v, nam in zip(uvars, result.var_names): params[nam].value = v.nominal_value if not result.errorbars: result.message = '%s Could not estimate error-bars.' % result.message np.seterr(**orig_warn_settings) return result def brute(self, params=None, Ns=20, keep=50): """Use the `brute` method to find the global minimum of a function. The following parameters are passed to :scipydoc:`optimize.brute` and cannot be changed: +-------------------+-------+----------------------------------------+ | :meth:`brute` arg | Value | Description | +===================+=======+========================================+ | full_output | 1 | Return the evaluation grid and | | | | the objective function's values on it. | +-------------------+-------+----------------------------------------+ | finish | None | No "polishing" function is to be used | | | | after the grid search. | +-------------------+-------+----------------------------------------+ | disp | False | Do not print convergence messages | | | | (when finish is not None). | +-------------------+-------+----------------------------------------+ It assumes that the input Parameters have been initialized, and a function to minimize has been properly set up. Parameters ---------- params : :class:`~lmfit.parameter.Parameters` object, optional Contains the Parameters for the model. If None, then the Parameters used to initialize the Minimizer object are used. Ns : int, optional Number of grid points along the axes, if not otherwise specified (see Notes). keep : int, optional Number of best candidates from the brute force method that are stored in the :attr:`candidates` attribute. If 'all', then all grid points from :scipydoc:`optimize.brute` are stored as candidates. Returns ------- :class:`MinimizerResult` Object containing the parameters from the brute force method. The return values (`x0`, `fval`, `grid`, `Jout`) from :scipydoc:`optimize.brute` are stored as `brute_` attributes. The `MinimizerResult` also contains the `candidates` attribute and `show_candidates()` method. The `candidates` attribute contains the parameters and chisqr from the brute force method as a namedtuple, ('Candidate', ['params', 'score']), sorted on the (lowest) chisqr value. To access the values for a particular candidate one can use `result.candidate[#].params` or `result.candidate[#].score`, where a lower # represents a better candidate. The `show_candidates(#)` uses the :meth:`pretty_print` method to show a specific candidate-# or all candidates when no number is specified. .. versionadded:: 0.9.6 Notes ----- The :meth:`brute` method evalutes the function at each point of a multidimensional grid of points. The grid points are generated from the parameter ranges using `Ns` and (optional) `brute_step`. The implementation in :scipydoc:`optimize.brute` requires finite bounds and the `range` is specified as a two-tuple `(min, max)` or slice-object `(min, max, brute_step)`. A slice-object is used directly, whereas a two-tuple is converted to a slice object that interpolates `Ns` points from `min` to `max`, inclusive. In addition, the :meth:`brute` method in lmfit, handles three other scenarios given below with their respective slice-object: - lower bound (:attr:`min`) and :attr:`brute_step` are specified: range = (`min`, `min` + `Ns` * `brute_step`, `brute_step`). - upper bound (:attr:`max`) and :attr:`brute_step` are specified: range = (`max` - `Ns` * `brute_step`, `max`, `brute_step`). - numerical value (:attr:`value`) and :attr:`brute_step` are specified: range = (`value` - (`Ns`//2) * `brute_step`, `value` + (`Ns`//2) * `brute_step`, `brute_step`). """ result = self.prepare_fit(params=params) result.method = 'brute' brute_kws = dict(full_output=1, finish=None, disp=False) varying = np.asarray([par.vary for par in self.params.values()]) replace_none = lambda x, sign: sign*np.inf if x is None else x lower_bounds = np.asarray([replace_none(i.min, -1) for i in self.params.values()])[varying] upper_bounds = np.asarray([replace_none(i.max, 1) for i in self.params.values()])[varying] value = np.asarray([i.value for i in self.params.values()])[varying] stepsize = np.asarray([i.brute_step for i in self.params.values()])[varying] ranges = [] for i, step in enumerate(stepsize): if np.all(np.isfinite([lower_bounds[i], upper_bounds[i]])): # lower AND upper bounds are specified (brute_step optional) par_range = ((lower_bounds[i], upper_bounds[i], step) if step else (lower_bounds[i], upper_bounds[i])) elif np.isfinite(lower_bounds[i]) and step: # lower bound AND brute_step are specified par_range = (lower_bounds[i], lower_bounds[i] + Ns*step, step) elif np.isfinite(upper_bounds[i]) and step: # upper bound AND brute_step are specified par_range = (upper_bounds[i] - Ns*step, upper_bounds[i], step) elif np.isfinite(value[i]) and step: # no bounds, but an initial value is specified par_range = (value[i] - (Ns//2)*step, value[i] + (Ns//2)*step, step) else: raise ValueError('Not enough information provided for the brute ' 'force method. Please specify bounds or at ' 'least an initial value and brute_step for ' 'parameter "{}".'.format(result.var_names[i])) ranges.append(par_range) ret = scipy_brute(self.penalty_brute, tuple(ranges), Ns=Ns, **brute_kws) result.brute_x0 = ret[0] result.brute_fval = ret[1] result.brute_grid = ret[2] result.brute_Jout = ret[3] # sort the results of brute and populate .candidates attribute grid_score = ret[3].ravel() # chisqr grid_points = [par.ravel() for par in ret[2]] if len(result.var_names) == 1: grid_result = np.array([res for res in zip(zip(grid_points), grid_score)], dtype=[('par', 'O'), ('score', 'float64')]) else: grid_result = np.array([res for res in zip(zip(*grid_points), grid_score)], dtype=[('par', 'O'), ('score', 'float64')]) grid_result_sorted = grid_result[grid_result.argsort(order='score')] result.candidates = [] if keep == 'all': keep_candidates = len(grid_result_sorted) else: keep_candidates = min(len(grid_result_sorted), keep) for data in grid_result_sorted[:keep_candidates]: pars = deepcopy(self.params) for i, par in enumerate(result.var_names): pars[par].value = data[0][i] result.candidates.append(Candidate(params=pars, score=data[1])) result.params = result.candidates[0].params result.chisqr = ret[1] result.nvarys = len(result.var_names) result.residual = self.__residual(result.brute_x0, apply_bounds_transformation=False) result.ndata = len(result.residual) result.nfree = result.ndata - result.nvarys result.redchi = result.chisqr / result.nfree # this is -2*loglikelihood _neg2_log_likel = result.ndata * np.log(result.chisqr / result.ndata) result.aic = _neg2_log_likel + 2 * result.nvarys result.bic = _neg2_log_likel + np.log(result.ndata) * result.nvarys return result def minimize(self, method='leastsq', params=None, **kws): """Perform the minimization. Parameters ---------- method : str, optional Name of the fitting method to use. Valid values are: - `'leastsq'`: Levenberg-Marquardt (default) - `'least_squares'`: Least-Squares minimization, using Trust Region Reflective method by default - `'differential_evolution'`: differential evolution - `'brute'`: brute force method - '`nelder`': Nelder-Mead - `'lbfgsb'`: L-BFGS-B - `'powell'`: Powell - `'cg'`: Conjugate-Gradient - `'newton'`: Newton-CG - `'cobyla'`: Cobyla - `'tnc'`: Truncate Newton - `'trust-ncg'`: Trust Newton-CGn - `'dogleg'`: Dogleg - `'slsqp'`: Sequential Linear Squares Programming In most cases, these methods wrap and use the method with the same name from `scipy.optimize`, or use `scipy.optimize.minimize` with the same `method` argument. Thus '`leastsq`' will use `scipy.optimize.leastsq`, while '`powell`' will use `scipy.optimize.minimizer(...., method='powell')` For more details on the fitting methods please refer to the `SciPy docs `__. params : :class:`~lmfit.parameter.Parameters`, optional Parameters of the model to use as starting values. **kws : optional Additional arguments are passed to the underlying minimization method. Returns ------- :class:`MinimizerResult` Object containing the optimized parameter and several goodness-of-fit statistics. .. versionchanged:: 0.9.0 Return value changed to :class:`MinimizerResult`. """ function = self.leastsq kwargs = {'params': params} kwargs.update(self.kws) kwargs.update(kws) user_method = method.lower() if user_method.startswith('leasts'): function = self.leastsq elif user_method.startswith('least_s'): function = self.least_squares elif user_method.startswith('brute'): function = self.brute else: function = self.scalar_minimize for key, val in SCALAR_METHODS.items(): if (key.lower().startswith(user_method) or val.lower().startswith(user_method)): kwargs['method'] = val return function(**kwargs) def _lnprior(theta, bounds): """Calculate an improper uniform log-prior probability. Parameters ---------- theta : sequence Float parameter values (only those being varied). bounds : np.ndarray Lower and upper bounds of parameters that are varying. Has shape (nvarys, 2). Returns ------- lnprob : float Log prior probability. """ if np.any(theta > bounds[:, 1]) or np.any(theta < bounds[:, 0]): return -np.inf else: return 0 def _lnpost(theta, userfcn, params, var_names, bounds, userargs=(), userkws=None, float_behavior='posterior', is_weighted=True, nan_policy='raise'): """Calculate the log-posterior probability. See the `Minimizer.emcee` method for more details. Parameters ---------- theta : sequence Float parameter values (only those being varied). userfcn : callable User objective function. params : :class:`~lmfit.parameters.Parameters` The entire set of Parameters. var_names : list The names of the parameters that are varying. bounds : numpy.ndarray Lower and upper bounds of parameters. Has shape (nvarys, 2). userargs : tuple, optional Extra positional arguments required for user objective function. userkws : dict, optional Extra keyword arguments required for user objective function. float_behavior : str, optional Specifies meaning of objective when it returns a float. One of: 'posterior' - objective function returnins a log-posterior probability 'chi2' - objective function returns a chi2 value is_weighted : bool If `userfcn` returns a vector of residuals then `is_weighted` specifies if the residuals have been weighted by data uncertainties. nan_policy : str, optional Specifies action if `userfcn` returns NaN values. One of: 'raise' - a `ValueError` is raised 'propagate' - the values returned from `userfcn` are un-altered 'omit' - the non-finite values are filtered Returns ------- lnprob : float Log posterior probability. """ # the comparison has to be done on theta and bounds. DO NOT inject theta # values into Parameters, then compare Parameters values to the bounds. # Parameters values are clipped to stay within bounds. if np.any(theta > bounds[:, 1]) or np.any(theta < bounds[:, 0]): return -np.inf for name, val in zip(var_names, theta): params[name].value = val userkwargs = {} if userkws is not None: userkwargs = userkws # update the constraints params.update_constraints() # now calculate the log-likelihood out = userfcn(params, *userargs, **userkwargs) out = _nan_policy(out, nan_policy=nan_policy, handle_inf=False) lnprob = np.asarray(out).ravel() if lnprob.size > 1: # objective function returns a vector of residuals if '__lnsigma' in params and not is_weighted: # marginalise over a constant data uncertainty __lnsigma = params['__lnsigma'].value c = np.log(2 * np.pi) + 2 * __lnsigma lnprob = -0.5 * np.sum((lnprob / np.exp(__lnsigma)) ** 2 + c) else: lnprob = -0.5 * (lnprob * lnprob).sum() else: # objective function returns a single value. # use float_behaviour to figure out if the value is posterior or chi2 if float_behavior == 'posterior': pass elif float_behavior == 'chi2': lnprob *= -0.5 else: raise ValueError("float_behaviour must be either 'posterior' or" " 'chi2' " + float_behavior) return lnprob def _make_random_gen(seed): """Turn seed into a numpy.random.RandomState instance. If seed is None, return the RandomState singleton used by numpy.random. If seed is an int, return a new RandomState instance seeded with seed. If seed is already a RandomState instance, return it. Otherwise raise ValueError. """ if seed is None or seed is np.random: return np.random.mtrand._rand if isinstance(seed, (numbers.Integral, np.integer)): return np.random.RandomState(seed) if isinstance(seed, np.random.RandomState): return seed raise ValueError('%r cannot be used to seed a numpy.random.RandomState' ' instance' % seed) def _nan_policy(a, nan_policy='raise', handle_inf=True): """Specify behaviour when an array contains numpy.nan or numpy.inf. Parameters ---------- a : array_like Input array to consider. nan_policy : str, optional One of: 'raise' - raise a `ValueError` if `a` contains NaN 'propagate' - propagate NaN 'omit' - filter NaN from input array handle_inf : bool, optional As well as NaN consider +/- inf. Returns ------- filtered_array : array_like Note ---- This function is copied, then modified, from scipy/stats/stats.py/_contains_nan """ policies = ['propagate', 'raise', 'omit'] if handle_inf: handler_func = lambda a: ~np.isfinite(a) else: handler_func = np.isnan if nan_policy == 'propagate': # nan values are ignored. return a elif nan_policy == 'raise': try: # Calling np.sum to avoid creating a huge array into memory # e.g. np.isnan(a).any() with np.errstate(invalid='ignore'): contains_nan = handler_func(np.sum(a)) except TypeError: # If the check cannot be properly performed we fallback to omiting # nan values and raising a warning. This can happen when attempting to # sum things that are not numbers (e.g. as in the function `mode`). contains_nan = False warnings.warn("The input array could not be properly checked for nan " "values. nan values will be ignored.", RuntimeWarning) if contains_nan: raise ValueError("The input contains nan values") return a elif nan_policy == 'omit': # nans are filtered mask = handler_func(a) return a[~mask] else: raise ValueError("nan_policy must be one of {%s}" % ', '.join("'%s'" % s for s in policies)) def minimize(fcn, params, method='leastsq', args=None, kws=None, scale_covar=True, iter_cb=None, reduce_fcn=None, **fit_kws): """Perform a fit of a set of parameters by minimizing an objective (or cost) function using one one of the several available methods. The minimize function takes a objective function to be minimized, a dictionary (:class:`~lmfit.parameter.Parameters`) containing the model parameters, and several optional arguments. Parameters ---------- fcn : callable Objective function to be minimized. When method is `leastsq` or `least_squares`, the objective function should return an array of residuals (difference between model and data) to be minimized in a least-squares sense. With the scalar methods the objective function can either return the residuals array or a single scalar value. The function must have the signature: `fcn(params, *args, **kws)` params : :class:`~lmfit.parameter.Parameters` Contains the Parameters for the model. method : str, optional Name of the fitting method to use. Valid values are: - `'leastsq'`: Levenberg-Marquardt (default) - `'least_squares'`: Least-Squares minimization, using Trust Region Reflective method by default - `'differential_evolution'`: differential evolution - `'brute'`: brute force method - '`nelder`': Nelder-Mead - `'lbfgsb'`: L-BFGS-B - `'powell'`: Powell - `'cg'`: Conjugate-Gradient - `'newton'`: Newton-Congugate-Gradient - `'cobyla'`: Cobyla - `'tnc'`: Truncate Newton - `'trust-ncg'`: Trust Newton-Congugate-Gradient - `'dogleg'`: Dogleg - `'slsqp'`: Sequential Linear Squares Programming In most cases, these methods wrap and use the method of the same name from `scipy.optimize`, or use `scipy.optimize.minimize` with the same `method` argument. Thus '`leastsq`' will use `scipy.optimize.leastsq`, while '`powell`' will use `scipy.optimize.minimizer(...., method='powell')` For more details on the fitting methods please refer to the `SciPy docs `__. args : tuple, optional Positional arguments to pass to `fcn`. kws : dict, optional Keyword arguments to pass to `fcn`. iter_cb : callable, optional Function to be called at each fit iteration. This function should have the signature `iter_cb(params, iter, resid, *args, **kws)`, where where `params` will have the current parameter values, `iter` the iteration, `resid` the current residual array, and `*args` and `**kws` as passed to the objective function. scale_covar : bool, optional Whether to automatically scale the covariance matrix (`leastsq` only). reduce_fcn : str or callable, optional Function to convert a residual array to a scalar value for the scalar minimizers. See notes in `Minimizer`. **fit_kws : dict, optional Options to pass to the minimizer being used. Returns ------- :class:`MinimizerResult` Object containing the optimized parameter and several goodness-of-fit statistics. .. versionchanged:: 0.9.0 Return value changed to :class:`MinimizerResult`. Notes ----- The objective function should return the value to be minimized. For the Levenberg-Marquardt algorithm from leastsq(), this returned value must be an array, with a length greater than or equal to the number of fitting variables in the model. For the other methods, the return value can either be a scalar or an array. If an array is returned, the sum of squares of the array will be sent to the underlying fitting method, effectively doing a least-squares optimization of the return values. A common use for `args` and `kws` would be to pass in other data needed to calculate the residual, including such things as the data array, dependent variable, uncertainties in the data, and other data structures for the model calculation. On output, `params` will be unchanged. The best-fit values, and where appropriate, estimated uncertainties and correlations, will all be contained in the returned :class:`MinimizerResult`. See :ref:`fit-results-label` for further details. This function is simply a wrapper around :class:`Minimizer` and is equivalent to:: fitter = Minimizer(fcn, params, fcn_args=args, fcn_kws=kws, iter_cb=iter_cb, scale_covar=scale_covar, **fit_kws) fitter.minimize(method=method) """ fitter = Minimizer(fcn, params, fcn_args=args, fcn_kws=kws, iter_cb=iter_cb, scale_covar=scale_covar, reduce_fcn=reduce_fcn, **fit_kws) return fitter.minimize(method=method) lmfit-0.9.7/lmfit/model.py0000644000076500000240000015122713102476603016351 0ustar Newvillestaff00000000000000"""Concise nonlinear curve fitting.""" from __future__ import print_function from collections import OrderedDict from copy import deepcopy from functools import wraps import inspect import operator import warnings import numpy as np from scipy.special import erf from scipy.stats import t from . import Minimizer, Parameter, Parameters from .confidence import conf_interval from .printfuncs import ci_report, fit_report # Use pandas.isnull for aligning missing data if pandas is available. # otherwise use numpy.isnan try: from pandas import isnull, Series except ImportError: isnull = np.isnan Series = type(NotImplemented) def _align(var, mask, data): """Align missing data, if pandas is available.""" if isinstance(data, Series) and isinstance(var, Series): return var.reindex_like(data).dropna() elif mask is not None: return var[mask] return var try: from matplotlib import pyplot as plt _HAS_MATPLOTLIB = True except ImportError: _HAS_MATPLOTLIB = False def _ensureMatplotlib(function): if _HAS_MATPLOTLIB: @wraps(function) def wrapper(*args, **kws): return function(*args, **kws) return wrapper else: def no_op(*args, **kwargs): print('matplotlib module is required for plotting the results') return no_op class Model(object): """Create a model from a user-supplied model function. The model function will normally take an independent variable (generally, the first argument) and a series of arguments that are meant to be parameters for the model. It will return an array of data to model some data as for a curve-fitting problem. """ _forbidden_args = ('data', 'weights', 'params') _invalid_ivar = "Invalid independent variable name ('%s') for function %s" _invalid_par = "Invalid parameter name ('%s') for function %s" _invalid_missing = "missing must be None, 'none', 'drop', or 'raise'." _valid_missing = (None, 'none', 'drop', 'raise') _invalid_hint = "unknown parameter hint '%s' for param '%s'" _hint_names = ('value', 'vary', 'min', 'max', 'expr') def __init__(self, func, independent_vars=None, param_names=None, missing='none', prefix='', name=None, **kws): """ Parameters ---------- func : callable Function to be wrapped. independent_vars : list of str, optional Arguments to func that are independent variables (default is None). param_names : list of str, optional Names of arguments to func that are to be made into parameters (default is None). missing : str, optional How to handle NaN and missing values in data. One of: - 'none' or None : Do not check for null or missing values (default). - 'drop' : Drop null or missing observations in data. If pandas is installed, `pandas.isnull` is used, otherwise `numpy.isnan` is used. - 'raise' : Raise a (more helpful) exception when data contains null or missing values. prefix : str, optional Prefix used for the model. name : str, optional Name for the model. When None (default) the name is the same as the model function (`func`). **kws : dict, optional Additional keyword arguments to pass to model function. Notes ----- 1. Parameter names are inferred from the function arguments, and a residual function is automatically constructed. 2. The model function must return an array that will be the same size as the data being modeled. Examples -------- The model function will normally take an independent variable (generally, the first argument) and a series of arguments that are meant to be parameters for the model. Thus, a simple peak using a Gaussian defined as: >>> import numpy as np >>> def gaussian(x, amp, cen, wid): ... return amp * np.exp(-(x-cen)**2 / wid) can be turned into a Model with: >>> gmodel = Model(gaussian) this will automatically discover the names of the independent variables and parameters: >>> print(gmodel.param_names, gmodel.independent_vars) ['amp', 'cen', 'wid'], ['x'] """ self.func = func self._prefix = prefix self._param_root_names = param_names # will not include prefixes self.independent_vars = independent_vars self._func_allargs = [] self._func_haskeywords = False if missing not in self._valid_missing: raise ValueError(self._invalid_missing) self.missing = missing self.opts = kws self.param_hints = OrderedDict() # the following has been changed from OrderedSet for the time being self._param_names = [] self._parse_params() if self.independent_vars is None: self.independent_vars = [] if name is None and hasattr(self.func, '__name__'): name = self.func.__name__ self._name = name def _reprstring(self, long=False): out = self._name opts = [] if len(self._prefix) > 0: opts.append("prefix='%s'" % (self._prefix)) if long: for k, v in self.opts.items(): opts.append("%s='%s'" % (k, v)) if len(opts) > 0: out = "%s, %s" % (out, ', '.join(opts)) return "Model(%s)" % out @property def name(self): """Return Model name.""" return self._reprstring(long=False) @name.setter def name(self, value): self._name = value @property def prefix(self): """Return Model prefix.""" return self._prefix @property def param_names(self): """Return the parameters of the Model.""" return self._param_names def __repr__(self): """ Return representation of Model.""" return "" % (self.name) def copy(self, **kwargs): """DOES NOT WORK.""" raise NotImplementedError("Model.copy does not work. Make a new Model") def _parse_params(self): """Build parameters from function arguments.""" if self.func is None: return if hasattr(self.func, 'argnames') and hasattr(self.func, 'kwargs'): pos_args = self.func.argnames[:] kw_args = {} for name, defval in self.func.kwargs: kw_args[name] = defval keywords_ = list(kw_args.keys()) else: try: # PY3 argspec = inspect.getfullargspec(self.func) keywords_ = argspec.varkw except AttributeError: # PY2 argspec = inspect.getargspec(self.func) keywords_ = argspec.keywords pos_args = argspec.args kw_args = {} if argspec.defaults is not None: for val in reversed(argspec.defaults): kw_args[pos_args.pop()] = val self._func_haskeywords = keywords_ is not None self._func_allargs = pos_args + list(kw_args.keys()) allargs = self._func_allargs if len(allargs) == 0 and keywords_ is not None: return # default independent_var = 1st argument if self.independent_vars is None: self.independent_vars = [pos_args[0]] # default param names: all positional args # except independent variables self.def_vals = {} might_be_param = [] if self._param_root_names is None: self._param_root_names = pos_args[:] for key, val in kw_args.items(): if (not isinstance(val, bool) and isinstance(val, (float, int))): self._param_root_names.append(key) self.def_vals[key] = val elif val is None: might_be_param.append(key) for p in self.independent_vars: if p in self._param_root_names: self._param_root_names.remove(p) new_opts = {} for opt, val in self.opts.items(): if (opt in self._param_root_names or opt in might_be_param and isinstance(val, Parameter)): self.set_param_hint(opt, value=val.value, min=val.min, max=val.max, expr=val.expr) elif opt in self._func_allargs: new_opts[opt] = val self.opts = new_opts names = [] if self._prefix is None: self._prefix = '' for pname in self._param_root_names: names.append("%s%s" % (self._prefix, pname)) # check variables names for validity # The implicit magic in fit() requires us to disallow some fname = self.func.__name__ for arg in self.independent_vars: if arg not in allargs or arg in self._forbidden_args: raise ValueError(self._invalid_ivar % (arg, fname)) for arg in names: if (self._strip_prefix(arg) not in allargs or arg in self._forbidden_args): raise ValueError(self._invalid_par % (arg, fname)) # the following as been changed from OrderedSet for the time being. self._param_names = names[:] def set_param_hint(self, name, **kwargs): """Set *hints* to use when creating parameters with `make_params()` for the named parameter. This is especially convenient for setting initial values. The `name` can include the models `prefix` or not. The hint given can also include optional bounds and constraints ``(value, vary, min, max, expr)``, which will be used by make_params() when building default parameters. Parameters ---------- name : string Parameter name. **kwargs : optional Arbitrary keyword arguments, needs to be a Parameter attribute. Can be any of the following: - value : float, optional Numerical Parameter value. - vary : bool, optional Whether the Parameter is varied during a fit (default is True). - min : float, optional Lower bound for value (default is `-numpy.inf`, no lower bound). - max : float, optional Upper bound for value (default is `numpy.inf`, no upper bound). - expr : str, optional Mathematical expression used to constrain the value during the fit. Example -------- >>> model = GaussianModel() >>> model.set_param_hint('sigma', min=0) """ npref = len(self._prefix) if npref > 0 and name.startswith(self._prefix): name = name[npref:] if name not in self.param_hints: self.param_hints[name] = OrderedDict() for key, val in kwargs.items(): if key in self._hint_names: self.param_hints[name][key] = val else: warnings.warn(self._invalid_hint % (key, name)) def print_param_hints(self, colwidth=8): """Print a nicely aligned text-table of parameter hints. Parameters ---------- colwidth : int, optional Width of each column, except for first and last columns. """ name_len = max(len(s) for s in self.param_hints) print('{:{name_len}} {:>{n}} {:>{n}} {:>{n}} {:>{n}} {:{n}}' .format('Name', 'Value', 'Min', 'Max', 'Vary', 'Expr', name_len=name_len, n=colwidth)) line = ('{name:<{name_len}} {value:{n}g} {min:{n}g} {max:{n}g} ' '{vary!s:>{n}} {expr}') for name, values in sorted(self.param_hints.items()): pvalues = dict(name=name, value=np.nan, min=-np.inf, max=np.inf, vary=True, expr='') pvalues.update(**values) print(line.format(name_len=name_len, n=colwidth, **pvalues)) def make_params(self, verbose=False, **kwargs): """Create a Parameters object for a Model. Parameters ---------- verbose : bool, optional Whether to print out messages (default is False). **kwargs : optional Parameter names and initial values. Returns --------- params : Parameters Notes ----- 1. The parameters may or may not have decent initial values for each parameter. 2. This applies any default values or parameter hints that may have been set. """ params = Parameters() # make sure that all named parameters are in params for name in self.param_names: if name in params: par = params[name] else: par = Parameter(name=name) par._delay_asteval = True basename = name[len(self._prefix):] # apply defaults from model function definition if basename in self.def_vals: par.value = self.def_vals[basename] if par.value in (None, -np.inf, np.inf, np.nan): for key, val in self.def_vals.items(): if key in name.lower(): par.value = val # apply defaults from parameter hints if basename in self.param_hints: hint = self.param_hints[basename] for item in self._hint_names: if item in hint: setattr(par, item, hint[item]) # apply values passed in through kw args if basename in kwargs: # kw parameter names with no prefix par.value = kwargs[basename] if name in kwargs: # kw parameter names with prefix par.value = kwargs[name] params.add(par) if verbose: print(' - Adding parameter "%s"' % name) # next build parameters defined in param_hints # note that composites may define their own additional # convenience parameters here for basename, hint in self.param_hints.items(): name = "%s%s" % (self._prefix, basename) if name in params: par = params[name] else: par = Parameter(name=name) params.add(par) if verbose: print(' - Adding parameter for hint "%s"' % name) par._delay_asteval = True for item in self._hint_names: if item in hint: setattr(par, item, hint[item]) if basename in kwargs: par.value = kwargs[basename] # Add the new parameter to self._param_names if name not in self._param_names: self._param_names.append(name) for p in params.values(): p._delay_asteval = False return params def guess(self, data, **kws): """Guess starting values for the parameters of a model. This is not implemented for all models, but is available for many of the built-in models. Parameters ---------- data : array_like Array of data to use to guess parameter values. **kws : optional Additional keyword arguments, passed to model function. Returns ------- params : Parameters Notes ----- Should be implemented for each model subclass to run self.make_params(), update starting values and return a Parameters object. Raises ------ NotImplementedError """ cname = self.__class__.__name__ msg = 'guess() not implemented for %s' % cname raise NotImplementedError(msg) def _residual(self, params, data, weights, **kwargs): """Return the residual. Default residual: (data-model)*weights. If the model returns complex values, the residual is computed by treating the real and imaginary parts separately. In this case, if the weights provided are real, they are assumed to apply equally to the real and imaginary parts. If the weights are complex, the real part of the weights are applied to the real part of the residual and the imaginary part is treated correspondingly. Since the underlying scipy.optimize routines expect numpy.float arrays, the only complex type supported is np.complex. The "ravels" throughout are necessary to support pandas.Series. """ diff = self.eval(params, **kwargs) - data if diff.dtype == np.complex: # data/model are complex diff = diff.ravel().view(np.float) if weights is not None: if weights.dtype == np.complex: # weights are complex weights = weights.ravel().view(np.float) else: # real weights but complex data weights = (weights + 1j * weights).ravel().view(np.float) if weights is not None: diff *= weights return np.asarray(diff).ravel() # for compatibility with pandas.Series def _handle_missing(self, data): """Handle missing data.""" if self.missing == 'raise': if np.any(isnull(data)): raise ValueError("Data contains a null value.") elif self.missing == 'drop': mask = ~isnull(data) if np.all(mask): return None # short-circuit this -- no missing values mask = np.asarray(mask) # for compatibility with pandas.Series return mask def _strip_prefix(self, name): npref = len(self._prefix) if npref > 0 and name.startswith(self._prefix): name = name[npref:] return name def make_funcargs(self, params=None, kwargs=None, strip=True): """Convert parameter values and keywords to function arguments.""" if params is None: params = {} if kwargs is None: kwargs = {} out = {} out.update(self.opts) for name, par in params.items(): if strip: name = self._strip_prefix(name) if name in self._func_allargs or self._func_haskeywords: out[name] = par.value # kwargs handled slightly differently -- may set param value too! for name, val in kwargs.items(): if strip: name = self._strip_prefix(name) if name in self._func_allargs or self._func_haskeywords: out[name] = val if name in params: params[name].value = val return out def _make_all_args(self, params=None, **kwargs): """Generate **all** function args for all functions.""" args = {} for key, val in self.make_funcargs(params, kwargs).items(): args["%s%s" % (self._prefix, key)] = val return args def eval(self, params=None, **kwargs): """Evaluate the model with supplied parameters and keyword arguments. Parameters ----------- params : Parameters, optional Parameters to use in Model. **kwargs : optional Additional keyword arguments to pass to model function. Returns ------- numpy.ndarray Value of model given the parameters and other arguments. Notes ----- 1. if `params` is None, the values for all parameters are expected to be provided as keyword arguments. If `params` is given, and a keyword argument for a parameter value is also given, the keyword argument will be used. 2. all non-parameter arguments for the model function, **including all the independent variables** will need to be passed in using keyword arguments. """ return self.func(**self.make_funcargs(params, kwargs)) @property def components(self): """Return components for composite model.""" return [self] def eval_components(self, params=None, **kwargs): """Evaluate the model with the supplied parameters. Parameters ----------- params : Parameters, optional Parameters to use in Model. **kwargs : optional Additional keyword arguments to pass to model function. Returns ------- OrderedDict Keys are prefixes for component model, values are value of each component. """ key = self._prefix if len(key) < 1: key = self._name return {key: self.eval(params=params, **kwargs)} def fit(self, data, params=None, weights=None, method='leastsq', iter_cb=None, scale_covar=True, verbose=False, fit_kws=None, **kwargs): """Fit the model to the data using the supplied Parameters. Parameters ---------- data : array_like Array of data to be fit. params : Parameters, optional Parameters to use in fit (default is None). weights : array_like of same size as `data`, optional Weights to use for the calculation of the fit residual (default is None). method : str, optional Name of fitting method to use (default is `'leastsq'`). iter_cb : callable, optional Callback function to call at each iteration (default is None). scale_covar : bool, optional Whether to automatically scale the covariance matrix when calculating uncertainties (default is True, `leastsq` method only). verbose: bool, optional Whether to print a message when a new parameter is added because of a hint (default is True). fit_kws: dict, optional Options to pass to the minimizer being used. **kwargs: optional Arguments to pass to the model function, possibly overriding params. Returns ------- ModelResult Examples -------- Take `t` to be the independent variable and data to be the curve we will fit. Use keyword arguments to set initial guesses: >>> result = my_model.fit(data, tau=5, N=3, t=t) Or, for more control, pass a Parameters object. >>> result = my_model.fit(data, params, t=t) Keyword arguments override Parameters. >>> result = my_model.fit(data, params, tau=5, t=t) Notes ----- 1. if `params` is None, the values for all parameters are expected to be provided as keyword arguments. If `params` is given, and a keyword argument for a parameter value is also given, the keyword argument will be used. 2. all non-parameter arguments for the model function, **including all the independent variables** will need to be passed in using keyword arguments. 3. Parameters (however passed in), are copied on input, so the original Parameter objects are unchanged, and the updated values are in the returned `ModelResult`. """ if params is None: params = self.make_params(verbose=verbose) else: params = deepcopy(params) # If any kwargs match parameter names, override params. param_kwargs = set(kwargs.keys()) & set(self.param_names) for name in param_kwargs: p = kwargs[name] if isinstance(p, Parameter): p.name = name # allows N=Parameter(value=5) with implicit name params[name] = deepcopy(p) else: params[name].set(value=p) del kwargs[name] # All remaining kwargs should correspond to independent variables. for name in kwargs: if name not in self.independent_vars: warnings.warn("The keyword argument %s does not" % name + "match any arguments of the model function." + "It will be ignored.", UserWarning) # If any parameter is not initialized raise a more helpful error. missing_param = any([p not in params.keys() for p in self.param_names]) blank_param = any([(p.value is None and p.expr is None) for p in params.values()]) if missing_param or blank_param: msg = ('Assign each parameter an initial value by passing ' 'Parameters or keyword arguments to fit.\n') missing = [p for p in self.param_names if p not in params.keys()] blank = [name for name, p in params.items() if p.value is None and p.expr is None] msg += 'Missing parameters: %s\n' % str(missing) msg += 'Non initialized parameters: %s' % str(blank) raise ValueError(msg) # Do not alter anything that implements the array interface (np.array, pd.Series) # but convert other iterables (e.g., Python lists) to numpy arrays. if not hasattr(data, '__array__'): data = np.asfarray(data) for var in self.independent_vars: var_data = kwargs[var] if (not hasattr(var_data, '__array__')) and (not np.isscalar(var_data)): kwargs[var] = np.asfarray(var_data) # Handle null/missing values. mask = None if self.missing not in (None, 'none'): mask = self._handle_missing(data) # This can raise. if mask is not None: data = data[mask] if weights is not None: weights = _align(weights, mask, data) # If independent_vars and data are alignable (pandas), align them, # and apply the mask from above if there is one. for var in self.independent_vars: if not np.isscalar(kwargs[var]): kwargs[var] = _align(kwargs[var], mask, data) if fit_kws is None: fit_kws = {} output = ModelResult(self, params, method=method, iter_cb=iter_cb, scale_covar=scale_covar, fcn_kws=kwargs, **fit_kws) output.fit(data=data, weights=weights) output.components = self.components return output def __add__(self, other): """+""" return CompositeModel(self, other, operator.add) def __sub__(self, other): """-""" return CompositeModel(self, other, operator.sub) def __mul__(self, other): """*""" return CompositeModel(self, other, operator.mul) def __div__(self, other): """/""" return CompositeModel(self, other, operator.truediv) def __truediv__(self, other): """/""" return CompositeModel(self, other, operator.truediv) class CompositeModel(Model): """Combine two models (`left` and `right`) with a binary operator (`op`) into a CompositeModel. Normally, one does not have to explicitly create a `CompositeModel`, but can use normal Python operators `+`, '-', `*`, and `/` to combine components as in:: >>> mod = Model(fcn1) + Model(fcn2) * Model(fcn3) """ _names_collide = ("\nTwo models have parameters named '{clash}'. " "Use distinct names.") _bad_arg = "CompositeModel: argument {arg} is not a Model" _bad_op = "CompositeModel: operator {op} is not callable" _known_ops = {operator.add: '+', operator.sub: '-', operator.mul: '*', operator.truediv: '/'} def __init__(self, left, right, op, **kws): """ Parameters ---------- left : Model Left-hand model. right : Model Right-hand model. op : callable binary operator Operator to combine `left` and `right` models. **kws : optional Additional keywords are passed to `Model` when creating this new model. Notes ----- 1. The two models must use the same independent variable. """ if not isinstance(left, Model): raise ValueError(self._bad_arg.format(arg=left)) if not isinstance(right, Model): raise ValueError(self._bad_arg.format(arg=right)) if not callable(op): raise ValueError(self._bad_op.format(op=op)) self.left = left self.right = right self.op = op name_collisions = set(left.param_names) & set(right.param_names) if len(name_collisions) > 0: msg = '' for collision in name_collisions: msg += self._names_collide.format(clash=collision) raise NameError(msg) # we assume that all the sub-models have the same independent vars if 'independent_vars' not in kws: kws['independent_vars'] = self.left.independent_vars if 'missing' not in kws: kws['missing'] = self.left.missing def _tmp(self, *args, **kws): pass Model.__init__(self, _tmp, **kws) for side in (left, right): prefix = side.prefix for basename, hint in side.param_hints.items(): self.param_hints["%s%s" % (prefix, basename)] = hint def _parse_params(self): self._func_haskeywords = (self.left._func_haskeywords or self.right._func_haskeywords) self._func_allargs = (self.left._func_allargs + self.right._func_allargs) self.def_vals = deepcopy(self.right.def_vals) self.def_vals.update(self.left.def_vals) self.opts = deepcopy(self.right.opts) self.opts.update(self.left.opts) def _reprstring(self, long=False): return "(%s %s %s)" % (self.left._reprstring(long=long), self._known_ops.get(self.op, self.op), self.right._reprstring(long=long)) def eval(self, params=None, **kwargs): """TODO: docstring in public method.""" return self.op(self.left.eval(params=params, **kwargs), self.right.eval(params=params, **kwargs)) def eval_components(self, **kwargs): """Return OrderedDict of name, results for each component.""" out = OrderedDict(self.left.eval_components(**kwargs)) out.update(self.right.eval_components(**kwargs)) return out @property def param_names(self): """Return parameter names for composite model.""" return self.left.param_names + self.right.param_names @property def components(self): """Return components for composite model.""" return self.left.components + self.right.components def _make_all_args(self, params=None, **kwargs): """Generate **all** function arguments for all functions.""" out = self.right._make_all_args(params=params, **kwargs) out.update(self.left._make_all_args(params=params, **kwargs)) return out class ModelResult(Minimizer): """Result from the Model fit. This has many attributes and methods for viewing and working with the results of a fit using Model. It inherits from Minimizer, so that it can be used to modify and re-run the fit for the Model. """ def __init__(self, model, params, data=None, weights=None, method='leastsq', fcn_args=None, fcn_kws=None, iter_cb=None, scale_covar=True, **fit_kws): """ Parameters ---------- model : Model Model to use. params : Parameters Parameters with initial values for model. data : array_like, optional Data to be modeled. weights : array_like, optional Weights to multiply (data-model) for fit residual. method : str, optional Name of minimization method to use (default is `'leastsq'`). fcn_args : sequence, optional Positional arguments to send to model function. fcn_dict : dict, optional Keyword arguments to send to model function. iter_cb : callable, optional Function to call on each iteration of fit. scale_covar : bool, optional Whether to scale covariance matrix for uncertainty evaluation. **fit_kws : optional Keyword arguments to send to minimization routine. """ self.model = model self.data = data self.weights = weights self.method = method self.ci_out = None self.init_params = deepcopy(params) Minimizer.__init__(self, model._residual, params, fcn_args=fcn_args, fcn_kws=fcn_kws, iter_cb=iter_cb, scale_covar=scale_covar, **fit_kws) def fit(self, data=None, params=None, weights=None, method=None, **kwargs): """Re-perform fit for a Model, given data and params. Parameters ---------- data : array_like, optional Data to be modeled. params : Parameters, optional Parameters with initial values for model. weights : array_like, optional Weights to multiply (data-model) for fit residual. method : str, optional Name of minimization method to use (default is `'leastsq'`). **kwargs : optional Keyword arguments to send to minimization routine. """ if data is not None: self.data = data if params is not None: self.init_params = params if weights is not None: self.weights = weights if method is not None: self.method = method self.ci_out = None self.userargs = (self.data, self.weights) self.userkws.update(kwargs) self.init_fit = self.model.eval(params=self.params, **self.userkws) _ret = self.minimize(method=self.method) for attr in dir(_ret): if not attr.startswith('_'): try: setattr(self, attr, getattr(_ret, attr)) except AttributeError: pass self.init_values = self.model._make_all_args(self.init_params) self.best_values = self.model._make_all_args(_ret.params) self.best_fit = self.model.eval(params=_ret.params, **self.userkws) def eval(self, params=None, **kwargs): """Evaluate model function. Parameters ---------- params : Parameters, optional Parameters to use. **kwargs : optional Options to send to Model.eval() Returns ------- out : numpy.ndarray Array for evaluated model. """ self.userkws.update(kwargs) if params is None: params = self.params return self.model.eval(params=params, **self.userkws) def eval_components(self, params=None, **kwargs): """Evaluate each component of a composite model function. Parameters ---------- params : Parameters, optional Parameters, defaults to ModelResult.params **kwargs : optional Leyword arguments to pass to model function. Returns ------- OrderedDict Keys are prefixes of component models, and values are the estimated model value for each component of the model. """ self.userkws.update(kwargs) if params is None: params = self.params return self.model.eval_components(params=params, **self.userkws) def eval_uncertainty(self, params=None, sigma=1, **kwargs): """Evaluate the uncertainty of the *model function* from the uncertainties for the best-fit parameters. This can be used to give confidence bands for the model. Parameters ---------- params : Parameters, optional Parameters, defaults to ModelResult.params. sigma : float, optional Confidence level, i.e. how many sigma (default is 1). **kwargs : optional Values of options, independent variables, etcetera. Returns ------- numpy.ndarray Uncertainty at each value of the model. Example ------- >>> out = model.fit(data, params, x=x) >>> dely = out.eval_confidence_band(x=x) >>> plt.plot(x, data) >>> plt.plot(x, out.best_fit) >>> plt.fill_between(x, out.best_fit-dely, ... out.best_fit+dely, color='#888888') Notes ----- 1. This is based on the excellent and clear example from https://www.astro.rug.nl/software/kapteyn/kmpfittutorial.html#confidence-and-prediction-intervals, which references the original work of: J. Wolberg,Data Analysis Using the Method of Least Squares, 2006, Springer 2. The value of sigma is number of `sigma` values, and is converted to a probability. Values or 1, 2, or 3 give probalities of 0.6827, 0.9545, and 0.9973, respectively. If the sigma value is < 1, it is interpreted as the probability itself. That is, `sigma=1` and `sigma=0.6827` will give the same results, within precision errors. """ self.userkws.update(kwargs) if params is None: params = self.params nvarys = self.nvarys ndata = self.ndata covar = self.covar / self.redchi fjac = np.zeros(ndata*nvarys).reshape((nvarys, ndata)) df2 = np.zeros(ndata) # find derivative by hand! for i in range(nvarys): pname = self.var_names[i] pars = self.params val0 = pars[pname].value dval = pars[pname].stderr/3.0 pars[pname].value = val0 + dval res1 = self.model.eval(pars, **self.userkws) pars[pname].value = val0 - dval res2 = self.model.eval(pars, **self.userkws) pars[pname].value = val0 fjac[i] = (res1 - res2) / (2*dval) for i in range(nvarys): for j in range(nvarys): df2 += fjac[i]*fjac[j]*covar[i, j] if sigma < 1.0: prob = sigma else: prob = erf(sigma/np.sqrt(2)) return np.sqrt(df2*self.redchi) * t.ppf((prob+1)/2.0, ndata-nvarys) def conf_interval(self, **kwargs): """Calculate the confidence intervals for the variable parameters. Confidence intervals are calculated using the :func:`confidence.conf_interval()` function and keyword arguments (`**kwargs`) are passed to that function. The result is stored in the :attr:`ci_out` attribute so that it can be accessed without recalculating them. """ if self.ci_out is None: self.ci_out = conf_interval(self, self, **kwargs) return self.ci_out def ci_report(self, with_offset=True, ndigits=5, **kwargs): """Return a nicely formatted text report of the confidence intervals. Parameters ---------- with_offset : bool, optional Whether to subtract best value from all other values (default is True). ndigits : int, optional Number of significant digits to show (default is 5). **kwargs: optional Keyword arguments that are passed to the `conf_interval` function. Returns ------- str Text of formatted report on confidence intervals. """ return ci_report(self.conf_interval(**kwargs), with_offset=with_offset, ndigits=ndigits) def fit_report(self, modelpars=None, show_correl=True, min_correl=0.1, sort_pars=False): """Return a printable fit report. The report contains fit statistics and best-fit values with uncertainties and correlations. Parameters ---------- modelpars : Parameters, optional Known Model Parameters. show_correl : bool, optional Whether to show list of sorted correlations (default is True). min_correl : float, optional Smallest correlation in absolute value to show (default is 0.1). sort_pars : callable, optional Whether to show parameter names sorted in alphanumerical order (default is False). If False, then the parameters will be listed in the order as they were added to the Parameters dictionary. If callable, then this (one argument) function is used to extract a comparison key from each list element. Returns ------- text : str Multi-line text of fit report. See Also -------- :func:`fit_report()` """ report = fit_report(self, modelpars=modelpars, show_correl=show_correl, min_correl=min_correl, sort_pars=sort_pars) modname = self.model._reprstring(long=True) return '[[Model]]\n %s\n%s\n' % (modname, report) @_ensureMatplotlib def plot_fit(self, ax=None, datafmt='o', fitfmt='-', initfmt='--', xlabel=None, ylabel=None, yerr=None, numpoints=None, data_kws=None, fit_kws=None, init_kws=None, ax_kws=None): """Plot the fit results using matplotlib, if available. The plot will include the data points, the initial fit curve, and the best-fit curve. If the fit model included weights or if `yerr` is specified, errorbars will also be plotted. Parameters ---------- ax : matplotlib.axes.Axes, optional The axes to plot on. The default in None, which means use the current pyplot axis or create one if there is none. datafmt : str, optional Matplotlib format string for data points. fitfmt : str, optional Matplotlib format string for fitted curve. initfmt : str, optional Matplotlib format string for initial conditions for the fit. xlabel : str, optional Matplotlib format string for labeling the x-axis. ylabel : str, optional Matplotlib format string for labeling the y-axis. yerr : numpy.ndarray, optional Array of uncertainties for data array. numpoints : int, optional If provided, the final and initial fit curves are evaluated not only at data points, but refined to contain `numpoints` points in total. data_kws : dict, optional Keyword arguments passed on to the plot function for data points. fit_kws : dict, optional Keyword arguments passed on to the plot function for fitted curve. init_kws : dict, optional Keyword arguments passed on to the plot function for the initial conditions of the fit. ax_kws : dict, optional Keyword arguments for a new axis, if there is one being created. Returns ------- matplotlib.axes.Axes Notes ----- For details about plot format strings and keyword arguments see documentation of matplotlib.axes.Axes.plot. If `yerr` is specified or if the fit model included weights, then matplotlib.axes.Axes.errorbar is used to plot the data. If `yerr` is not specified and the fit includes weights, `yerr` set to 1/self.weights If `ax` is None then `matplotlib.pyplot.gca(**ax_kws)` is called. See Also -------- ModelResult.plot_residuals : Plot the fit residuals using matplotlib. ModelResult.plot : Plot the fit results and residuals using matplotlib. """ if data_kws is None: data_kws = {} if fit_kws is None: fit_kws = {} if init_kws is None: init_kws = {} if ax_kws is None: ax_kws = {} if len(self.model.independent_vars) == 1: independent_var = self.model.independent_vars[0] else: print('Fit can only be plotted if the model function has one ' 'independent variable.') return False if not isinstance(ax, plt.Axes): ax = plt.gca(**ax_kws) x_array = self.userkws[independent_var] # make a dense array for x-axis if data is not dense if numpoints is not None and len(self.data) < numpoints: x_array_dense = np.linspace(min(x_array), max(x_array), numpoints) else: x_array_dense = x_array ax.plot( x_array_dense, self.model.eval(self.init_params, **{independent_var: x_array_dense}), initfmt, label='init', **init_kws) ax.plot( x_array_dense, self.model.eval(self.params, **{independent_var: x_array_dense}), fitfmt, label='best-fit', **fit_kws) if yerr is None and self.weights is not None: yerr = 1.0/self.weights if yerr is not None: ax.errorbar(x_array, self.data, yerr=yerr, fmt=datafmt, label='data', **data_kws) else: ax.plot(x_array, self.data, datafmt, label='data', **data_kws) ax.set_title(self.model.name) if xlabel is None: ax.set_xlabel(independent_var) else: ax.set_xlabel(xlabel) if ylabel is None: ax.set_ylabel('y') else: ax.set_ylabel(ylabel) ax.legend(loc='best') return ax @_ensureMatplotlib def plot_residuals(self, ax=None, datafmt='o', yerr=None, data_kws=None, fit_kws=None, ax_kws=None): """Plot the fit residuals using matplotlib, if available. If `yerr` is supplied or if the model included weights, errorbars will also be plotted. Parameters ---------- ax : matplotlib.axes.Axes, optional The axes to plot on. The default in None, which means use the current pyplot axis or create one if there is none. datafmt : str, optional Matplotlib format string for data points. yerr : numpy.ndarray, optional Array of uncertainties for data array. data_kws : dict, optional Keyword arguments passed on to the plot function for data points. fit_kws : dict, optional Keyword arguments passed on to the plot function for fitted curve. ax_kws : dict, optional Keyword arguments for a new axis, if there is one being created. Returns ------- matplotlib.axes.Axes Notes ----- For details about plot format strings and keyword arguments see documentation of matplotlib.axes.Axes.plot. If `yerr` is specified or if the fit model included weights, then matplotlib.axes.Axes.errorbar is used to plot the data. If `yerr` is not specified and the fit includes weights, `yerr` set to 1/self.weights If `ax` is None then `matplotlib.pyplot.gca(**ax_kws)` is called. See Also -------- ModelResult.plot_fit : Plot the fit results using matplotlib. ModelResult.plot : Plot the fit results and residuals using matplotlib. """ if data_kws is None: data_kws = {} if fit_kws is None: fit_kws = {} if ax_kws is None: ax_kws = {} if len(self.model.independent_vars) == 1: independent_var = self.model.independent_vars[0] else: print('Fit can only be plotted if the model function has one ' 'independent variable.') return False if not isinstance(ax, plt.Axes): ax = plt.gca(**ax_kws) x_array = self.userkws[independent_var] ax.axhline(0, **fit_kws) if yerr is None and self.weights is not None: yerr = 1.0/self.weights if yerr is not None: ax.errorbar(x_array, self.eval() - self.data, yerr=yerr, fmt=datafmt, label='residuals', **data_kws) else: ax.plot(x_array, self.eval() - self.data, datafmt, label='residuals', **data_kws) ax.set_title(self.model.name) ax.set_ylabel('residuals') ax.legend(loc='best') return ax @_ensureMatplotlib def plot(self, datafmt='o', fitfmt='-', initfmt='--', xlabel=None, ylabel=None, yerr=None, numpoints=None, fig=None, data_kws=None, fit_kws=None, init_kws=None, ax_res_kws=None, ax_fit_kws=None, fig_kws=None): """Plot the fit results and residuals using matplotlib, if available. The method will produce a matplotlib figure with both results of the fit and the residuals plotted. If the fit model included weights, errorbars will also be plotted. Parameters ---------- datafmt : str, optional Matplotlib format string for data points. fitfmt : str, optional Matplotlib format string for fitted curve. initfmt : str, optional Matplotlib format string for initial conditions for the fit. xlabel : str, optional Matplotlib format string for labeling the x-axis. ylabel : str, optional Matplotlib format string for labeling the y-axis. yerr : numpy.ndarray, optional Array of uncertainties for data array. numpoints : int, optional If provided, the final and initial fit curves are evaluated not only at data points, but refined to contain `numpoints` points in total. fig : matplotlib.figure.Figure, optional The figure to plot on. The default is None, which means use the current pyplot figure or create one if there is none. data_kws : dict, optional Keyword arguments passed on to the plot function for data points. fit_kws : dict, optional Keyword arguments passed on to the plot function for fitted curve. init_kws : dict, optional Keyword arguments passed on to the plot function for the initial conditions of the fit. ax_res_kws : dict, optional Keyword arguments for the axes for the residuals plot. ax_fit_kws : dict, optional Keyword arguments for the axes for the fit plot. fig_kws : dict, optional Keyword arguments for a new figure, if there is one being created. Returns ------- A tuple with matplotlib's Figure and GridSpec objects. Notes ----- The method combines ModelResult.plot_fit and ModelResult.plot_residuals. If `yerr` is specified or if the fit model included weights, then matplotlib.axes.Axes.errorbar is used to plot the data. If `yerr` is not specified and the fit includes weights, `yerr` set to 1/self.weights If `fig` is None then `matplotlib.pyplot.figure(**fig_kws)` is called, otherwise `fig_kws` is ignored. See Also -------- ModelResult.plot_fit : Plot the fit results using matplotlib. ModelResult.plot_residuals : Plot the fit residuals using matplotlib. """ if data_kws is None: data_kws = {} if fit_kws is None: fit_kws = {} if init_kws is None: init_kws = {} if ax_res_kws is None: ax_res_kws = {} if ax_fit_kws is None: ax_fit_kws = {} # make a square figure with side equal to the default figure's x-size figxsize = plt.rcParams['figure.figsize'][0] fig_kws_ = dict(figsize=(figxsize, figxsize)) if fig_kws is not None: fig_kws_.update(fig_kws) if len(self.model.independent_vars) != 1: print('Fit can only be plotted if the model function has one ' 'independent variable.') return False if not isinstance(fig, plt.Figure): fig = plt.figure(**fig_kws_) gs = plt.GridSpec(nrows=2, ncols=1, height_ratios=[1, 4]) ax_res = fig.add_subplot(gs[0], **ax_res_kws) ax_fit = fig.add_subplot(gs[1], sharex=ax_res, **ax_fit_kws) self.plot_fit(ax=ax_fit, datafmt=datafmt, fitfmt=fitfmt, yerr=yerr, initfmt=initfmt, xlabel=xlabel, ylabel=ylabel, numpoints=numpoints, data_kws=data_kws, fit_kws=fit_kws, init_kws=init_kws, ax_kws=ax_fit_kws) self.plot_residuals(ax=ax_res, datafmt=datafmt, yerr=yerr, data_kws=data_kws, fit_kws=fit_kws, ax_kws=ax_res_kws) plt.setp(ax_res.get_xticklabels(), visible=False) ax_fit.set_title('') return fig, gs lmfit-0.9.7/lmfit/models.py0000644000076500000240000011352513110357266016535 0ustar Newvillestaff00000000000000"""TODO: module docstring.""" import numpy as np from . import lineshapes from .asteval import Interpreter from .astutils import get_ast_names from .lineshapes import (breit_wigner, damped_oscillator, dho, donaich, expgaussian, exponential, gaussian, linear, logistic, lognormal, lorentzian, moffat, parabolic, pearson7, powerlaw, pvoigt, rectangle, skewed_gaussian, skewed_voigt, step, students_t, voigt) from .model import Model class DimensionalError(Exception): """TODO: class docstring.""" pass def _validate_1d(independent_vars): if len(independent_vars) != 1: raise DimensionalError( "This model requires exactly one independent variable.") def index_of(arr, val): """Return index of array nearest to a value.""" if val < min(arr): return 0 return np.abs(arr-val).argmin() def fwhm_expr(model): """Return constraint expression for fwhm.""" fmt = "{factor:.7f}*{prefix:s}sigma" return fmt.format(factor=model.fwhm_factor, prefix=model.prefix) def height_expr(model): """Return constraint expression for maximum peak height.""" fmt = "{factor:.7f}*{prefix:s}amplitude/max(1.e-15, {prefix:s}sigma)" return fmt.format(factor=model.height_factor, prefix=model.prefix) def guess_from_peak(model, y, x, negative, ampscale=1.0, sigscale=1.0): """Estimate amp, cen, sigma for a peak, create params.""" if x is None: return 1.0, 0.0, 1.0 maxy, miny = max(y), min(y) maxx, minx = max(x), min(x) imaxy = index_of(y, maxy) cen = x[imaxy] amp = (maxy - miny)*3.0 sig = (maxx-minx)/6.0 halfmax_vals = np.where(y > (maxy+miny)/2.0)[0] if negative: imaxy = index_of(y, miny) amp = -(maxy - miny)*3.0 halfmax_vals = np.where(y < (maxy+miny)/2.0)[0] if len(halfmax_vals) > 2: sig = (x[halfmax_vals[-1]] - x[halfmax_vals[0]])/2.0 cen = x[halfmax_vals].mean() amp = amp*sig*ampscale sig = sig*sigscale pars = model.make_params(amplitude=amp, center=cen, sigma=sig) pars['%ssigma' % model.prefix].set(min=0.0) return pars def update_param_vals(pars, prefix, **kwargs): """Update parameter values with keyword arguments.""" for key, val in kwargs.items(): pname = "%s%s" % (prefix, key) if pname in pars: pars[pname].value = val return pars COMMON_INIT_DOC = """ Parameters ---------- independent_vars: ['x'] Arguments to func that are independent variables. prefix: string, optional String to prepend to parameter names, needed to add two Models that have parameter names in common. missing: str or None, optional How to handle NaN and missing values in data. One of: - 'none' or None: Do not check for null or missing values (default). - 'drop': Drop null or missing observations in data. if pandas is installed, `pandas.isnull` is used, otherwise `numpy.isnan` is used. - 'raise': Raise a (more helpful) exception when data contains null or missing values. **kwargs : optional Keyword arguments to pass to :class:`Model`. """ COMMON_GUESS_DOC = """Guess starting values for the parameters of a model. Parameters ---------- data : array_like Array of data to use to guess parameter values. **kws : optional Additional keyword arguments, passed to model function. Returns ------- params : Parameters """ COMMON_DOC = COMMON_INIT_DOC class ConstantModel(Model): """Constant model, with a single Parameter: ``c``. Note that this is 'constant' in the sense of having no dependence on the independent variable ``x``, not in the sense of being non- varying. To be clear, ``c`` will be a Parameter that will be varied in the fit (by default, of course). """ def __init__(self, independent_vars=['x'], prefix='', missing=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) def constant(x, c=0.0): return c super(ConstantModel, self).__init__(constant, **kwargs) def guess(self, data, **kwargs): pars = self.make_params() pars['%sc' % self.prefix].set(value=data.mean()) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class ComplexConstantModel(Model): """Complex constant model, with wo Parameters: ``re``, and ``im``. Note that ``re`` and ``im`` are 'constant' in the sense of having no dependence on the independent variable ``x``, not in the sense of being non-varying. To be clear, ``re`` and ``im`` will be Parameters that will be varied in the fit (by default, of course). """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) def constant(x, re=0., im=0.): return re + 1j*im super(ComplexConstantModel, self).__init__(constant, **kwargs) def guess(self, data, **kwargs): pars = self.make_params() pars['%sre' % self.prefix].set(value=data.real.mean()) pars['%sim' % self.prefix].set(value=data.imag.mean()) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class LinearModel(Model): """Linear model, with two Parameters ``intercept`` and ``slope``. Defined as: .. math:: f(x; m, b) = m x + b with ``slope`` for :math:`m` and ``intercept`` for :math:`b`. """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(LinearModel, self).__init__(linear, **kwargs) def guess(self, data, x=None, **kwargs): sval, oval = 0., 0. if x is not None: sval, oval = np.polyfit(x, data, 1) pars = self.make_params(intercept=oval, slope=sval) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class QuadraticModel(Model): """A quadratic model, with three Parameters ``a``, ``b``, and ``c``. Defined as: .. math:: f(x; a, b, c) = a x^2 + b x + c """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(QuadraticModel, self).__init__(parabolic, **kwargs) def guess(self, data, x=None, **kwargs): a, b, c = 0., 0., 0. if x is not None: a, b, c = np.polyfit(x, data, 2) pars = self.make_params(a=a, b=b, c=c) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC ParabolicModel = QuadraticModel class PolynomialModel(Model): r"""A polynomial model with up to 7 Parameters, specfied by ``degree``. .. math:: f(x; c_0, c_1, \ldots, c_7) = \sum_{i=0, 7} c_i x^i with parameters ``c0``, ``c1``, ..., ``c7``. The supplied ``degree`` will specify how many of these are actual variable parameters. This uses :numpydoc:`polyval` for its calculation of the polynomial. """ MAX_DEGREE = 7 DEGREE_ERR = "degree must be an integer less than %d." def __init__(self, degree, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) if not isinstance(degree, int) or degree > self.MAX_DEGREE: raise TypeError(self.DEGREE_ERR % self.MAX_DEGREE) self.poly_degree = degree pnames = ['c%i' % (i) for i in range(degree + 1)] kwargs['param_names'] = pnames def polynomial(x, c0=0, c1=0, c2=0, c3=0, c4=0, c5=0, c6=0, c7=0): return np.polyval([c7, c6, c5, c4, c3, c2, c1, c0], x) super(PolynomialModel, self).__init__(polynomial, **kwargs) def guess(self, data, x=None, **kwargs): pars = self.make_params() if x is not None: out = np.polyfit(x, data, self.poly_degree) for i, coef in enumerate(out[::-1]): pars['%sc%i' % (self.prefix, i)].set(value=coef) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class GaussianModel(Model): r"""A model based on a Gaussian or normal distribution lineshape. (see http://en.wikipedia.org/wiki/Normal_distribution), with three Parameters: ``amplitude``, ``center``, and ``sigma``. In addition, parameters ``fwhm`` and ``height`` are included as constraints to report full width at half maximum and maximum peak height, respectively. .. math:: f(x; A, \mu, \sigma) = \frac{A}{\sigma\sqrt{2\pi}} e^{[{-{(x-\mu)^2}/{{2\sigma}^2}}]} where the parameter ``amplitude`` corresponds to :math:`A`, ``center`` to :math:`\mu`, and ``sigma`` to :math:`\sigma`. The full width at half maximum is :math:`2\sigma\sqrt{2\ln{2}}`, approximately :math:`2.3548\sigma`. """ fwhm_factor = 2.354820 height_factor = 1./np.sqrt(2*np.pi) def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(GaussianModel, self).__init__(gaussian, **kwargs) self.set_param_hint('sigma', min=0) self.set_param_hint('fwhm', expr=fwhm_expr(self)) self.set_param_hint('height', expr=height_expr(self)) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class LorentzianModel(Model): r"""A model based on a Lorentzian or Cauchy-Lorentz distribution function (see http://en.wikipedia.org/wiki/Cauchy_distribution), with three Parameters: ``amplitude``, ``center``, and ``sigma``. In addition, parameters ``fwhm`` and ``height`` are included as constraints to report full width at half maximum and maximum peak height, respectively. .. math:: f(x; A, \mu, \sigma) = \frac{A}{\pi} \big[\frac{\sigma}{(x - \mu)^2 + \sigma^2}\big] where the parameter ``amplitude`` corresponds to :math:`A`, ``center`` to :math:`\mu`, and ``sigma`` to :math:`\sigma`. The full width at half maximum is :math:`2\sigma`. """ fwhm_factor = 2.0 height_factor = 1./np.pi def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(LorentzianModel, self).__init__(lorentzian, **kwargs) self.set_param_hint('sigma', min=0) self.set_param_hint('fwhm', expr=fwhm_expr(self)) self.set_param_hint('height', expr=height_expr(self)) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative, ampscale=1.25) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class VoigtModel(Model): r"""A model based on a Voigt distribution function (see http://en.wikipedia.org/wiki/Voigt_profile>), with four Parameters: ``amplitude``, ``center``, ``sigma``, and ``gamma``. By default, ``gamma`` is constrained to have value equal to ``sigma``, though it can be varied independently. In addition, parameters ``fwhm`` and ``height`` are included as constraints to report full width at half maximum and maximum peak height, respectively. The definition for the Voigt function used here is .. math:: f(x; A, \mu, \sigma, \gamma) = \frac{A \textrm{Re}[w(z)]}{\sigma\sqrt{2 \pi}} where .. math:: :nowrap: \begin{eqnarray*} z &=& \frac{x-\mu +i\gamma}{\sigma\sqrt{2}} \\ w(z) &=& e^{-z^2}{\operatorname{erfc}}(-iz) \end{eqnarray*} and :func:`erfc` is the complimentary error function. As above, ``amplitude`` corresponds to :math:`A`, ``center`` to :math:`\mu`, and ``sigma`` to :math:`\sigma`. The parameter ``gamma`` corresponds to :math:`\gamma`. If ``gamma`` is kept at the default value (constrained to ``sigma``), the full width at half maximum is approximately :math:`3.6013\sigma`. """ fwhm_factor = 3.60131 height_factor = 1./np.sqrt(2*np.pi) def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(VoigtModel, self).__init__(voigt, **kwargs) self.set_param_hint('sigma', min=0) self.set_param_hint('gamma', expr='%ssigma' % self.prefix) self.set_param_hint('fwhm', expr=fwhm_expr(self)) self.set_param_hint('height', expr=height_expr(self)) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative, ampscale=1.5, sigscale=0.65) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class PseudoVoigtModel(Model): r"""A model based on a pseudo-Voigt distribution function (see http://en.wikipedia.org/wiki/Voigt_profile#Pseudo-Voigt_Approximation), which is a weighted sum of a Gaussian and Lorentzian distribution functions that share values for ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`) and full width at half maximum (and so have constrained values of ``sigma`` (:math:`\sigma`). A parameter ``fraction`` (:math:`\alpha`) controls the relative weight of the Gaussian and Lorentzian components, giving the full definition of .. math:: f(x; A, \mu, \sigma, \alpha) = \frac{(1-\alpha)A}{\sigma_g\sqrt{2\pi}} e^{[{-{(x-\mu)^2}/{{2\sigma_g}^2}}]} + \frac{\alpha A}{\pi} \big[\frac{\sigma}{(x - \mu)^2 + \sigma^2}\big] where :math:`\sigma_g = {\sigma}/{\sqrt{2\ln{2}}}` so that the full width at half maximum of each component and of the sum is :math:`2\sigma`. The :meth:`guess` function always sets the starting value for ``fraction`` at 0.5. """ fwhm_factor = 2.0 def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(PseudoVoigtModel, self).__init__(pvoigt, **kwargs) self.set_param_hint('sigma', min=0) self.set_param_hint('fraction', value=0.5) self.set_param_hint('fwhm', expr=fwhm_expr(self)) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative, ampscale=1.25) pars['%sfraction' % self.prefix].set(value=0.5) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class MoffatModel(Model): r"""A model based on the Moffat distribution function (see https://en.wikipedia.org/wiki/Moffat_distribution), with four Parameters: ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`), a width parameter ``sigma`` (:math:`\sigma`) and an exponent ``beta`` (:math:`\beta`). .. math:: f(x; A, \mu, \sigma, \beta) = A \big[(\frac{x-\mu}{\sigma})^2+1\big]^{-\beta} the full width have maximum is :math:`2\sigma\sqrt{2^{1/\beta}-1}`. The :meth:`guess` function always sets the starting value for ``beta`` to 1. Note that for (:math:`\beta=1`) the Moffat has a Lorentzian shape. """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(MoffatModel, self).__init__(moffat, **kwargs) self.set_param_hint('sigma', min=0) self.set_param_hint('beta') self.set_param_hint('fwhm', expr="2*%ssigma*sqrt(2**(1.0/%sbeta)-1)" % (self.prefix, self.prefix)) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative, ampscale=0.5, sigscale=1.) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class Pearson7Model(Model): r"""A model based on a Pearson VII distribution (see http://en.wikipedia.org/wiki/Pearson_distribution#The_Pearson_type_VII_distribution), with four parameers: ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`), ``sigma`` (:math:`\sigma`), and ``exponent`` (:math:`m`) in .. math:: f(x; A, \mu, \sigma, m) = \frac{A}{\sigma{\beta(m-\frac{1}{2}, \frac{1}{2})}} \bigl[1 + \frac{(x-\mu)^2}{\sigma^2} \bigr]^{-m} where :math:`\beta` is the beta function (see :scipydoc:`special.beta` in :mod:`scipy.special`). The :meth:`guess` function always gives a starting value for ``exponent`` of 1.5. """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(Pearson7Model, self).__init__(pearson7, **kwargs) self.set_param_hint('expon', value=1.5) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative) pars['%sexpon' % self.prefix].set(value=1.5) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class StudentsTModel(Model): r"""A model based on a Student's t distribution function (see http://en.wikipedia.org/wiki/Student%27s_t-distribution), with three Parameters: ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`) and ``sigma`` (:math:`\sigma`) in .. math:: f(x; A, \mu, \sigma) = \frac{A \Gamma(\frac{\sigma+1}{2})} {\sqrt{\sigma\pi}\,\Gamma(\frac{\sigma}{2})} \Bigl[1+\frac{(x-\mu)^2}{\sigma}\Bigr]^{-\frac{\sigma+1}{2}} where :math:`\Gamma(x)` is the gamma function. """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(StudentsTModel, self).__init__(students_t, **kwargs) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class BreitWignerModel(Model): r"""A model based on a Breit-Wigner-Fano function (see http://en.wikipedia.org/wiki/Fano_resonance>), with four Parameters: ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`), ``sigma`` (:math:`\sigma`), and ``q`` (:math:`q`) in .. math:: f(x; A, \mu, \sigma, q) = \frac{A (q\sigma/2 + x - \mu)^2}{(\sigma/2)^2 + (x - \mu)^2} """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(BreitWignerModel, self).__init__(breit_wigner, **kwargs) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative) pars['%sq' % self.prefix].set(value=1.0) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class LognormalModel(Model): r"""A model based on the Log-normal distribution function (see http://en.wikipedia.org/wiki/Lognormal), with three Parameters ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`) and ``sigma`` (:math:`\sigma`) in .. math:: f(x; A, \mu, \sigma) = \frac{A e^{-(\ln(x) - \mu)/ 2\sigma^2}}{x} """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(LognormalModel, self).__init__(lognormal, **kwargs) def guess(self, data, x=None, negative=False, **kwargs): pars = self.make_params(amplitude=1.0, center=0.0, sigma=0.25) pars['%ssigma' % self.prefix].set(min=0.0) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class DampedOscillatorModel(Model): r"""A model based on the Damped Harmonic Oscillator Amplitude (see http://en.wikipedia.org/wiki/Harmonic_oscillator#Amplitude_part), with three Parameters: ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`) and ``sigma`` (:math:`\sigma`) in .. math:: f(x; A, \mu, \sigma) = \frac{A}{\sqrt{ [1 - (x/\mu)^2]^2 + (2\sigma x/\mu)^2}} """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(DampedOscillatorModel, self).__init__(damped_oscillator, **kwargs) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative, ampscale=0.1, sigscale=0.1) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class DampedHarmonicOscillatorModel(Model): r"""A model based on a variation of the Damped Harmonic Oscillator (see http://en.wikipedia.org/wiki/Harmonic_oscillator), following the definition given in DAVE/PAN (see https://www.ncnr.nist.gov/dave/) with four Parameters: ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`), ``sigma`` (:math:`\sigma`), and ``gamma`` (:math:`\gamma`) in .. math:: f(x; A, \mu, \sigma, \gamma) = \frac{A\sigma}{\pi [1 - \exp(-x/\gamma)]} \Big[ \frac{1}{(x-\mu)^2 + \sigma^2} - \frac{1}{(x+\mu)^2 + \sigma^2} \Big] """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(DampedHarmonicOscillatorModel, self).__init__(dho, **kwargs) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative, ampscale=0.1, sigscale=0.1) pars['%sgamma' % self.prefix].set(value=1.0, min=0.0) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class ExponentialGaussianModel(Model): r"""A model of an Exponentially modified Gaussian distribution (see http://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution) with four Parameters ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`), ``sigma`` (:math:`\sigma`), and ``gamma`` (:math:`\gamma`) in .. math:: f(x; A, \mu, \sigma, \gamma) = \frac{A\gamma}{2} \exp\bigl[\gamma({\mu - x + \gamma\sigma^2/2})\bigr] {\operatorname{erfc}}\Bigl(\frac{\mu + \gamma\sigma^2 - x}{\sqrt{2}\sigma}\Bigr) where :func:`erfc` is the complimentary error function. """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(ExponentialGaussianModel, self).__init__(expgaussian, **kwargs) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class SkewedGaussianModel(Model): r"""A variation of the Exponential Gaussian, this uses a skewed normal distribution (see http://en.wikipedia.org/wiki/Skew_normal_distribution), with Parameters ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`), ``sigma`` (:math:`\sigma`), and ``gamma`` (:math:`\gamma`) in .. math:: f(x; A, \mu, \sigma, \gamma) = \frac{A}{\sigma\sqrt{2\pi}} e^{[{-{(x-\mu)^2}/{{2\sigma}^2}}]} \Bigl\{ 1 + {\operatorname{erf}}\bigl[ \frac{\gamma(x-\mu)}{\sigma\sqrt{2}} \bigr] \Bigr\} where :func:`erf` is the error function. """ fwhm_factor = 2.354820 def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(SkewedGaussianModel, self).__init__(skewed_gaussian, **kwargs) self.set_param_hint('sigma', min=0) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class DonaichModel(Model): r"""A model of an Doniach Sunjic asymmetric lineshape (see http://www.casaxps.com/help_manual/line_shapes.htm), used in photo-emission, with four Parameters ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`), ``sigma`` (:math:`\sigma`), and ``gamma`` (:math:`\gamma`) in .. math:: f(x; A, \mu, \sigma, \gamma) = A\frac{\cos\bigl[\pi\gamma/2 + (1-\gamma) \arctan{(x - \mu)}/\sigma\bigr]} {\bigr[1 + (x-\mu)/\sigma\bigl]^{(1-\gamma)/2}} """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(DonaichModel, self).__init__(donaich, **kwargs) def guess(self, data, x=None, negative=False, **kwargs): pars = guess_from_peak(self, data, x, negative, ampscale=0.5) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class PowerLawModel(Model): r"""A model based on a Power Law (see http://en.wikipedia.org/wiki/Power_law>), with two Parameters: ``amplitude`` (:math:`A`), and ``exponent`` (:math:`k`), in: .. math:: f(x; A, k) = A x^k """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(PowerLawModel, self).__init__(powerlaw, **kwargs) def guess(self, data, x=None, **kwargs): try: expon, amp = np.polyfit(np.log(x+1.e-14), np.log(data+1.e-14), 1) except: expon, amp = 1, np.log(abs(max(data)+1.e-9)) pars = self.make_params(amplitude=np.exp(amp), exponent=expon) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class ExponentialModel(Model): r"""A model based on an exponential decay function (see http://en.wikipedia.org/wiki/Exponential_decay) with two Parameters: ``amplitude`` (:math:`A`), and ``decay`` (:math:`\tau`), in: .. math:: f(x; A, \tau) = A e^{-x/\tau} """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(ExponentialModel, self).__init__(exponential, **kwargs) def guess(self, data, x=None, **kwargs): try: sval, oval = np.polyfit(x, np.log(abs(data)+1.e-15), 1) except: sval, oval = 1., np.log(abs(max(data)+1.e-9)) pars = self.make_params(amplitude=np.exp(oval), decay=-1.0/sval) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class StepModel(Model): r"""A model based on a Step function, with three Parameters: ``amplitude`` (:math:`A`), ``center`` (:math:`\mu`) and ``sigma`` (:math:`\sigma`) and four choices for functional form: - ``linear`` (the default) - ``atan`` or ``arctan`` for an arc-tangent function - ``erf`` for an error function - ``logistic`` for a logistic function (see http://en.wikipedia.org/wiki/Logistic_function). The step function starts with a value 0, and ends with a value of :math:`A` rising to :math:`A/2` at :math:`\mu`, with :math:`\sigma` setting the characteristic width. The forms are .. math:: :nowrap: \begin{eqnarray*} & f(x; A, \mu, \sigma, {\mathrm{form={}'linear{}'}}) & = A \min{[1, \max{(0, \alpha)}]} \\ & f(x; A, \mu, \sigma, {\mathrm{form={}'arctan{}'}}) & = A [1/2 + \arctan{(\alpha)}/{\pi}] \\ & f(x; A, \mu, \sigma, {\mathrm{form={}'erf{}'}}) & = A [1 + {\operatorname{erf}}(\alpha)]/2 \\ & f(x; A, \mu, \sigma, {\mathrm{form={}'logistic{}'}})& = A [1 - \frac{1}{1 + e^{\alpha}} ] \end{eqnarray*} where :math:`\alpha = (x - \mu)/{\sigma}`. """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(StepModel, self).__init__(step, **kwargs) def guess(self, data, x=None, **kwargs): if x is None: return ymin, ymax = min(data), max(data) xmin, xmax = min(x), max(x) pars = self.make_params(amplitude=(ymax-ymin), center=(xmax+xmin)/2.0) pars['%ssigma' % self.prefix].set(value=(xmax-xmin)/7.0, min=0.0) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class RectangleModel(Model): r"""A model based on a Step-up and Step-down function, with five Parameters: ``amplitude`` (:math:`A`), ``center1`` (:math:`\mu_1`), ``center2`` (:math:`\mu_2`), `sigma1`` (:math:`\sigma_1`) and ``sigma2`` (:math:`\sigma_2`) and four choices for functional form (which is used for both the Step up and the Step down: - ``linear`` (the default) - ``atan`` or ``arctan`` for an arc-tangent function - ``erf`` for an error function - ``logistic`` for a logistic function (see http://en.wikipedia.org/wiki/Logistic_function). The function starts with a value 0, transitions to a value of :math:`A`, taking the value :math:`A/2` at :math:`\mu_1`, with :math:`\sigma_1` setting the characteristic width. The function then transitions again to the value :math:`A/2` at :math:`\mu_2`, with :math:`\sigma_2` setting the characteristic width. The forms are .. math:: :nowrap: \begin{eqnarray*} &f(x; A, \mu, \sigma, {\mathrm{form={}'linear{}'}}) &= A \{ \min{[1, \max{(0, \alpha_1)}]} + \min{[-1, \max{(0, \alpha_2)}]} \} \\ &f(x; A, \mu, \sigma, {\mathrm{form={}'arctan{}'}}) &= A [\arctan{(\alpha_1)} + \arctan{(\alpha_2)}]/{\pi} \\ &f(x; A, \mu, \sigma, {\mathrm{form={}'erf{}'}}) &= A [{\operatorname{erf}}(\alpha_1) + {\operatorname{erf}}(\alpha_2)]/2 \\ &f(x; A, \mu, \sigma, {\mathrm{form={}'logistic{}'}}) &= A [1 - \frac{1}{1 + e^{\alpha_1}} - \frac{1}{1 + e^{\alpha_2}} ] \end{eqnarray*} where :math:`\alpha_1 = (x - \mu_1)/{\sigma_1}` and :math:`\alpha_2 = -(x - \mu_2)/{\sigma_2}`. """ def __init__(self, independent_vars=['x'], prefix='', missing=None, name=None, **kwargs): kwargs.update({'prefix': prefix, 'missing': missing, 'independent_vars': independent_vars}) super(RectangleModel, self).__init__(rectangle, **kwargs) self.set_param_hint('center1') self.set_param_hint('center2') self.set_param_hint('midpoint', expr='(%scenter1+%scenter2)/2.0' % (self.prefix, self.prefix)) def guess(self, data, x=None, **kwargs): if x is None: return ymin, ymax = min(data), max(data) xmin, xmax = min(x), max(x) pars = self.make_params(amplitude=(ymax-ymin), center1=(xmax+xmin)/4.0, center2=3*(xmax+xmin)/4.0) pars['%ssigma1' % self.prefix].set(value=(xmax-xmin)/7.0, min=0.0) pars['%ssigma2' % self.prefix].set(value=(xmax-xmin)/7.0, min=0.0) return update_param_vals(pars, self.prefix, **kwargs) __init__.__doc__ = COMMON_INIT_DOC guess.__doc__ = COMMON_GUESS_DOC class ExpressionModel(Model): idvar_missing = "No independent variable found in\n %s" idvar_notfound = "Cannot find independent variables '%s' in\n %s" no_prefix = "ExpressionModel does not support `prefix` argument" def __init__(self, expr, independent_vars=None, init_script=None, missing=None, **kws): """Model from User-supplied expression. Parameters ---------- expr : str Mathematical expression for model. independent_vars : list of strings or None, optional Variable names to use as independent variables. init_script : string or None, optional Initial script to run in asteval interpreter. missing : str or None, optional How to handle NaN and missing values in data. One of: - 'none' or None: Do not check for null or missing values (default). - 'drop': Drop null or missing observations in data. if pandas is installed, `pandas.isnull` is used, otherwise `numpy.isnan` is used. - 'raise': Raise a (more helpful) exception when data contains null or missing values. **kws : optional Keyword arguments to pass to :class:`Model`. Notes ----- 1. each instance of ExpressionModel will create and using its own version of an asteval interpreter. 2. prefix is **not supported** for ExpressionModel """ # create ast evaluator, load custom functions self.asteval = Interpreter() for name in lineshapes.functions: self.asteval.symtable[name] = getattr(lineshapes, name, None) if init_script is not None: self.asteval.eval(init_script) # save expr as text, parse to ast, save for later use self.expr = expr.strip() self.astcode = self.asteval.parse(self.expr) # find all symbol names found in expression sym_names = get_ast_names(self.astcode) if independent_vars is None and 'x' in sym_names: independent_vars = ['x'] if independent_vars is None: raise ValueError(self.idvar_missing % (self.expr)) # determine which named symbols are parameter names, # try to find all independent variables idvar_found = [False]*len(independent_vars) param_names = [] for name in sym_names: if name in independent_vars: idvar_found[independent_vars.index(name)] = True elif name not in param_names and name not in self.asteval.symtable: param_names.append(name) # make sure we have all independent parameters if not all(idvar_found): lost = [] for ix, found in enumerate(idvar_found): if not found: lost.append(independent_vars[ix]) lost = ', '.join(lost) raise ValueError(self.idvar_notfound % (lost, self.expr)) kws['independent_vars'] = independent_vars if 'prefix' in kws: raise Warning(self.no_prefix) def _eval(**kwargs): for name, val in kwargs.items(): self.asteval.symtable[name] = val return self.asteval.run(self.astcode) kws["missing"] = missing super(ExpressionModel, self).__init__(_eval, **kws) # set param names here, and other things normally # set in _parse_params(), which will be short-circuited. self.independent_vars = independent_vars self._func_allargs = independent_vars + param_names self._param_names = param_names self._func_haskeywords = True self.def_vals = {} def __repr__(self): """TODO: docstring in magic method.""" return "" % (self.expr) def _parse_params(self): """Over-write ExpressionModel._parse_params with `pass`. This prevents normal parsing of function for parameter names. """ pass lmfit-0.9.7/lmfit/parameter.py0000644000076500000240000007764013111710636017234 0ustar Newvillestaff00000000000000"""Parameter class.""" from __future__ import division from collections import OrderedDict from copy import deepcopy import json from numpy import arcsin, array, cos, inf, isfinite, nan, sin, sqrt from . import uncertainties from .asteval import Interpreter from .astutils import get_ast_names, valid_symbol_name def check_ast_errors(expr_eval): """Check for errors derived from asteval.""" if len(expr_eval.error) > 0: expr_eval.raise_exception(None) def isclose(x, y, rtol=1e-5, atol=1e-8): """Check whether two numbers are the same within a tolerance. abs(`x` - `y`) <= (`atol` + `rtol` * abs(`y`)) Parameters ---------- x, y : float Input values. rtol : float, optional The relative tolerance parameter. atol : float, optional The absolute tolerance parameter. Returns ------- bool True if `x` and `y` are the same within tolerance, otherwise False. """ def within_tol(x, y, atol, rtol): return abs(x - y) <= atol + rtol * abs(y) xfin = isfinite(x) yfin = isfinite(y) # both are finite if xfin and yfin: return within_tol(x, y, atol, rtol) elif x == y: return True else: return False class Parameters(OrderedDict): """An ordered dictionary of all the Parameter objects required to specify a fit model. All minimization and Model fitting routines in lmfit will use exactly one Parameters object, typically given as the first argument to the objective function. All keys of a Parameters() instance must be strings and valid Python symbol names, so that the name must match ``[a-z_][a-z0-9_]*`` and cannot be a Python reserved word. All values of a Parameters() instance must be Parameter objects. A Parameters() instance includes an asteval interpreter used for evaluation of constrained Parameters. Parameters() support copying and pickling, and have methods to convert to and from serializations using json strings. """ def __init__(self, asteval=None, *args, **kwds): """ Arguments --------- asteval : :class:`asteval.Interpreter`, optional Instance of the asteval Interpreter to use for constraint expressions. If None, a new interpreter will be created. *args : optional Arguments. **kwds : optional Keyword arguments. """ super(Parameters, self).__init__(self) self._asteval = asteval if asteval is None: self._asteval = Interpreter() self.update(*args, **kwds) def copy(self): """Parameters.copy() should always be a deepcopy.""" return self.__deepcopy__(None) def __copy__(self): """Parameters.copy() should always be a deepcopy.""" return self.__deepcopy__(None) def __deepcopy__(self, memo): """Parameters.deepcopy() needs to make sure that asteval is available and that all individual Parameter objects are copied.""" _pars = Parameters(asteval=None) # find the symbols that were added by users, not during construction unique_symbols = {key: self._asteval.symtable[key] for key in self._asteval.user_defined_symbols()} _pars._asteval.symtable.update(unique_symbols) # we're just about to add a lot of Parameter objects to the newly parameter_list = [] for key, par in self.items(): if isinstance(par, Parameter): param = Parameter(name=par.name, value=par.value, min=par.min, max=par.max) param.vary = par.vary param.brute_step = par.brute_step param.stderr = par.stderr param.correl = par.correl param.init_value = par.init_value param.expr = par.expr param.user_data = par.user_data parameter_list.append(param) _pars.add_many(*parameter_list) return _pars def __setitem__(self, key, par): """TODO: add magic method docstring.""" if key not in self: if not valid_symbol_name(key): raise KeyError("'%s' is not a valid Parameters name" % key) if par is not None and not isinstance(par, Parameter): raise ValueError("'%s' is not a Parameter" % par) OrderedDict.__setitem__(self, key, par) par.name = key par._expr_eval = self._asteval self._asteval.symtable[key] = par.value def __add__(self, other): """Add Parameters objects.""" if not isinstance(other, Parameters): raise ValueError("'%s' is not a Parameters object" % other) out = deepcopy(self) params = other.values() out.add_many(*params) return out def __iadd__(self, other): """Add/assign Parameters objects.""" if not isinstance(other, Parameters): raise ValueError("'%s' is not a Parameters object" % other) params = other.values() self.add_many(*params) return self def __array__(self): """Convert Parameters to array.""" return array([float(k) for k in self.values()]) def __reduce__(self): """Reduce Parameters instance such that it can be pickled.""" # make a list of all the parameters params = [self[k] for k in self] # find the symbols from _asteval.symtable, that need to be remembered. sym_unique = self._asteval.user_defined_symbols() unique_symbols = {key: deepcopy(self._asteval.symtable[key]) for key in sym_unique} return self.__class__, (), {'unique_symbols': unique_symbols, 'params': params} def __setstate__(self, state): """Unpickle a Parameters instance. Parameters ---------- state : dict state['unique_symbols'] is a dictionary containing symbols that need to be injected into _asteval.symtable state['params'] is a list of Parameter instances to be added """ # first update the Interpreter symbol table. This needs to be done # first because Parameter's early in the list may depend on later # Parameter's. This leads to problems because add_many eventually leads # to a Parameter value being retrieved with _getval, which, if the # dependent value hasn't already been added to the symtable, leads to # an Error. Another way of doing this would be to remove all the expr # from the Parameter instances before they get added, then to restore # them. self._asteval.symtable.update(state['unique_symbols']) # then add all the parameters self.add_many(*state['params']) def update_constraints(self): """Update all constrained parameters, checking that dependencies are evaluated as needed.""" requires_update = set(name for name, par in self.items() if par._expr is not None) updated_tracker = set(requires_update) def _update_param(name): """Update a parameter value, including setting bounds. For a constrained parameter (one with an `expr` defined), this first updates (recursively) all parameters on which the parameter depends (using the 'deps' field). """ par = self.__getitem__(name) if par._expr_eval is None: par._expr_eval = self._asteval for dep in par._expr_deps: if dep in updated_tracker: _update_param(dep) self._asteval.symtable[name] = par.value updated_tracker.discard(name) for name in requires_update: _update_param(name) def pretty_repr(self, oneline=False): """Return a pretty representation of a Parameters class. Parameters ---------- oneline : bool, optional If True prints a one-line parameters representation (default is False). Returns ------- s: str Parameters representation. """ if oneline: return super(Parameters, self).__repr__() s = "Parameters({\n" for key in self.keys(): s += " '%s': %s, \n" % (key, self[key]) s += " })\n" return s def pretty_print(self, oneline=False, colwidth=8, precision=4, fmt='g', columns=['value', 'min', 'max', 'stderr', 'vary', 'expr', 'brute_step']): """Pretty-print of parameters data. Parameters ---------- oneline : bool, optional If True prints a one-line parameters representation (default is False). colwidth : int, optional Column width for all columns specified in :attr:`columns`. precision : int, optional Number of digits to be printed after floating point. fmt : {'g', 'e', 'f'}, optional Single-character numeric formatter. Valid values are: 'f' floating point, 'g' floating point and exponential, or 'e' exponential. columns : :obj:`list` of :obj:`str`, optional List of :class:`Parameter` attribute names to print. """ if oneline: print(self.pretty_repr(oneline=oneline)) return name_len = max(len(s) for s in self) allcols = ['name'] + columns title = '{:{name_len}} ' + len(columns) * ' {:>{n}}' print(title.format(*allcols, name_len=name_len, n=colwidth).title()) numstyle = '{%s:>{n}.{p}{f}}' # format for numeric columns otherstyles = dict(name='{name:<{name_len}} ', stderr='{stderr!s:>{n}}', vary='{vary!s:>{n}}', expr='{expr!s:>{n}}', brute_step='{brute_step!s:>{n}}') line = ' '.join([otherstyles.get(k, numstyle % k) for k in allcols]) for name, values in sorted(self.items()): pvalues = {k: getattr(values, k) for k in columns} pvalues['name'] = name # stderr is a special case: it is either numeric or None (i.e. str) if 'stderr' in columns and pvalues['stderr'] is not None: pvalues['stderr'] = (numstyle % '').format( pvalues['stderr'], n=colwidth, p=precision, f=fmt) elif 'brute_step' in columns and pvalues['brute_step'] is not None: pvalues['brute_step'] = (numstyle % '').format( pvalues['brute_step'], n=colwidth, p=precision, f=fmt) print(line.format(name_len=name_len, n=colwidth, p=precision, f=fmt, **pvalues)) def add(self, name, value=None, vary=True, min=-inf, max=inf, expr=None, brute_step=None): """Add a Parameter. Parameters ---------- name : str Name of parameter. Must match ``[a-z_][a-z0-9_]*`` and cannot be a Python reserved word. value : float, optional Numerical Parameter value, typically the *initial value*. vary : bool, optional Whether the Parameter is varied during a fit (default is True). min : float, optional Lower bound for value (default is `-numpy.inf`, no lower bound). max : float, optional Upper bound for value (default is `numpy.inf`, no upper bound). expr : str, optional Mathematical expression used to constrain the value during the fit. brute_step : float, optional Step size for grid points in the `brute` method. Examples -------- >>> params = Parameters() >>> params.add('xvar', value=0.50, min=0, max=1) >>> params.add('yvar', expr='1.0 - xvar') which is equivalent to: >>> params = Parameters() >>> params['xvar'] = Parameter(name='xvar', value=0.50, min=0, max=1) >>> params['yvar'] = Parameter(name='yvar', expr='1.0 - xvar') """ if isinstance(name, Parameter): self.__setitem__(name.name, name) else: self.__setitem__(name, Parameter(value=value, name=name, vary=vary, min=min, max=max, expr=expr, brute_step=brute_step)) def add_many(self, *parlist): """Add many parameters, using a sequence of tuples. Parameters ---------- parlist : :obj:`sequence` of :obj:`tuple` or :class:`Parameter` A sequence of tuples, or a sequence of `Parameter` instances. If it is a sequence of tuples, then each tuple must contain at least the name. The order in each tuple must be `(name, value, vary, min, max, expr, brute_step)`. Examples -------- >>> params = Parameters() # add with tuples: (NAME VALUE VARY MIN MAX EXPR BRUTE_STEP) >>> params.add_many(('amp', 10, True, None, None, None, None), ... ('cen', 4, True, 0.0, None, None, None), ... ('wid', 1, False, None, None, None, None), ... ('frac', 0.5)) # add a sequence of Parameters >>> f = Parameter('par_f', 100) >>> g = Parameter('par_g', 2.) >>> params.add_many(f, g) """ for para in parlist: if isinstance(para, Parameter): self.__setitem__(para.name, para) else: param = Parameter(*para) self.__setitem__(param.name, param) def valuesdict(self): """Return an ordered dictionary of parameter values. Returns ------- OrderedDict An ordered dictionary of :attr:`name`::attr:`value` pairs for each Parameter. """ return OrderedDict(((p.name, p.value) for p in self.values())) def dumps(self, **kws): """Represent Parameters as a JSON string. Parameters ---------- **kws : optional Keyword arguments that are passed to `json.dumps()`. Returns ------- str JSON string representation of Parameters. See Also -------- dump(), loads(), load(), json.dumps() """ params = [p.__getstate__() for p in self.values()] sym_unique = self._asteval.user_defined_symbols() unique_symbols = {key: deepcopy(self._asteval.symtable[key]) for key in sym_unique} return json.dumps({'unique_symbols': unique_symbols, 'params': params}, **kws) def loads(self, s, **kws): """Load Parameters from a JSON string. Parameters ---------- **kws : optional Keyword arguments that are passed to `json.loads()`. Returns ------- :class:`Parameters` Updated Parameters from the JSON string. Notes ----- Current Parameters will be cleared before loading the data from the JSON string. See Also -------- dump(), dumps(), load(), json.loads() """ self.clear() tmp = json.loads(s, **kws) state = {'unique_symbols': tmp['unique_symbols'], 'params': []} for parstate in tmp['params']: _par = Parameter() _par.__setstate__(parstate) state['params'].append(_par) self.__setstate__(state) return self def dump(self, fp, **kws): """Write JSON representation of Parameters to a file-like object. Parameters ---------- fp : file-like object An open and ``.write()``-supporting file-like object. **kws : optional Keyword arguments that are passed to `dumps()`. Returns ------- None or int Return value from `fp.write()`. None for Python 2.7 and the number of characters written in Python 3. See Also -------- dump(), load(), json.dump() """ return fp.write(self.dumps(**kws)) def load(self, fp, **kws): """Load JSON representation of Parameters from a file-like object. Parameters ---------- fp : file-like object An open and ``.read()``-supporting file-like object. **kws : optional Keyword arguments that are passed to `loads()`. Returns ------- :class:`Parameters` Updated Parameters loaded from `fp`. See Also -------- dump(), loads(), json.load() """ return self.loads(fp.read(), **kws) class Parameter(object): """A Parameter is an object that can be varied in a fit, or one of the controlling variables in a model. It is a central component of lmfit, and all minimization and modeling methods use Parameter objects. A Parameter has a `name` attribute, and a scalar floating point `value`. It also has a `vary` attribute that describes whether the value should be varied during the minimization. Finite bounds can be placed on the Parameter's value by setting its `min` and/or `max` attributes. A Parameter can also have its value determined by a mathematical expression of other Parameter values held in the `expr` attrribute. Additional attributes include `brute_step` used as the step size in a brute-force minimization, and `user_data` reserved exclusively for user's need. After a minimization, a Parameter may also gain other attributes, including `stderr` holding the estimated standard error in the Parameter's value, and `correl`, a dictionary of correlation values with other Parameters used in the minimization. """ def __init__(self, name=None, value=None, vary=True, min=-inf, max=inf, expr=None, brute_step=None, user_data=None): """ Parameters ---------- name : str, optional Name of the Parameter. value : float, optional Numerical Parameter value. vary : bool, optional Whether the Parameter is varied during a fit (default is True). min : float, optional Lower bound for value (default is `-numpy.inf`, no lower bound). max : float, optional Upper bound for value (default is `numpy.inf`, no upper bound). expr : str, optional Mathematical expression used to constrain the value during the fit. brute_step : float, optional Step size for grid points in the `brute` method. user_data : optional User-definable extra attribute used for a Parameter. Attributes ---------- stderr : float The estimated standard error for the best-fit value. correl : dict A dictionary of the correlation with the other fitted Parameters of the form:: `{'decay': 0.404, 'phase': -0.020, 'frequency': 0.102}` """ self.name = name self._val = value self.user_data = user_data self.init_value = value self.min = min self.max = max self.brute_step = brute_step self.vary = vary self._expr = expr self._expr_ast = None self._expr_eval = None self._expr_deps = [] self._delay_asteval = False self.stderr = None self.correl = None self.from_internal = lambda val: val self._init_bounds() def set(self, value=None, vary=None, min=None, max=None, expr=None, brute_step=None): """Set or update Parameter attributes. Parameters ---------- value : float, optional Numerical Parameter value. vary : bool, optional Whether the Parameter is varied during a fit. min : float, optional Lower bound for value. To remove a lower bound you must use `-numpy.inf`. max : float, optional Upper bound for value. To remove an upper bound you must use `numpy.inf`. expr : str, optional Mathematical expression used to constrain the value during the fit. To remove a constraint you must supply an empty string. brute_step : float, optional Step size for grid points in the `brute` method. To remove the step size you must use ``0``. Notes ----- Each argument to `set()` has a default value of `None`, which will leave the current value for the attribute unchanged. Thus, to lift a lower or upper bound, passing in `None` will not work. Instead, you must set these to `-numpy.inf` or `numpy.inf`, as with:: par.set(min=None) # leaves lower bound unchanged par.set(min=-numpy.inf) # removes lower bound Similarly, to clear an expression, pass a blank string, (not ``None``!) as with:: par.set(expr=None) # leaves expression unchanged par.set(expr='') # removes expression Explicitly setting a value or setting `vary=True` will also clear the expression. Finally, to clear the brute_step size, pass ``0``, not ``None``:: par.set(brute_step=None) # leaves brute_step unchanged par.set(brute_step=0) # removes brute_step """ if value is not None: self.value = value self.__set_expression('') if vary is not None: self.vary = vary if vary: self.__set_expression('') if min is not None: self.min = min if max is not None: self.max = max if expr is not None: self.__set_expression(expr) if brute_step is not None: if brute_step == 0.0: self.brute_step = None else: self.brute_step = brute_step def _init_bounds(self): """Make sure initial bounds are self-consistent.""" # _val is None means - infinity. if self.max is None: self.max = inf if self.min is None: self.min = -inf if self._val is not None: if self.min > self.max: self.min, self.max = self.max, self.min if isclose(self.min, self.max, atol=1e-13, rtol=1e-13): raise ValueError("Parameter '%s' has min == max" % self.name) if self._val > self.max: self._val = self.max if self._val < self.min: self._val = self.min elif self._expr is None: self._val = self.min self.setup_bounds() def __getstate__(self): """Get state for pickle.""" return (self.name, self.value, self.vary, self.expr, self.min, self.max, self.brute_step, self.stderr, self.correl, self.init_value, self.user_data) def __setstate__(self, state): """Set state for pickle.""" (self.name, self.value, self.vary, self.expr, self.min, self.max, self.brute_step, self.stderr, self.correl, self.init_value, self.user_data) = state self._expr_ast = None self._expr_eval = None self._expr_deps = [] self._delay_asteval = False self._init_bounds() def __repr__(self): """Returns printable representation of a Parameter object.""" s = [] if self.name is not None: s.append("'%s'" % self.name) sval = repr(self._getval()) if not self.vary and self._expr is None: sval = "value=%s (fixed)" % sval elif self.stderr is not None: sval = "value=%s +/- %.3g" % (sval, self.stderr) s.append(sval) s.append("bounds=[%s:%s]" % (repr(self.min), repr(self.max))) if self._expr is not None: s.append("expr='%s'" % self.expr) if self.brute_step is not None: s.append("brute_step=%s" % (self.brute_step)) return "" % ', '.join(s) def setup_bounds(self): """Set up Minuit-style internal/external parameter transformation of min/max bounds. As a side-effect, this also defines the self.from_internal method used to re-calculate self.value from the internal value, applying the inverse Minuit-style transformation. This method should be called prior to passing a Parameter to the user-defined objective function. This code borrows heavily from JJ Helmus' leastsqbound.py Returns ------- _val : float The internal value for parameter from self.value (which holds the external, user-expected value). This internal value should actually be used in a fit. """ if self.min is None: self.min = -inf if self.max is None: self.max = inf if self.min == -inf and self.max == inf: self.from_internal = lambda val: val _val = self._val elif self.max == inf: self.from_internal = lambda val: self.min - 1.0 + sqrt(val*val + 1) _val = sqrt((self._val - self.min + 1.0)**2 - 1) elif self.min == -inf: self.from_internal = lambda val: self.max + 1 - sqrt(val*val + 1) _val = sqrt((self.max - self._val + 1.0)**2 - 1) else: self.from_internal = lambda val: self.min + (sin(val) + 1) * \ (self.max - self.min) / 2.0 _val = arcsin(2*(self._val - self.min)/(self.max - self.min) - 1) return _val def scale_gradient(self, val): """Return scaling factor for gradient. Parameters ---------- val: float Numerical Parameter value. Returns ------- float Scaling factor for gradient the according to Minuit-style transformation. """ if self.min == -inf and self.max == inf: return 1.0 elif self.max == inf: return val / sqrt(val*val + 1) elif self.min == -inf: return -val / sqrt(val*val + 1) else: return cos(val) * (self.max - self.min) / 2.0 def _getval(self): """Get value, with bounds applied.""" # Note assignment to self._val has been changed to self.value # The self.value property setter makes sure that the # _expr_eval.symtable is kept updated. # If you just assign to self._val then # _expr_eval.symtable[self.name] # becomes stale if parameter.expr is not None. if (isinstance(self._val, uncertainties.Variable) and self._val is not nan): try: self.value = self._val.nominal_value except AttributeError: pass if not self.vary and self._expr is None: return self._val if self._expr is not None: if self._expr_ast is None: self.__set_expression(self._expr) if self._expr_eval is not None: if not self._delay_asteval: self.value = self._expr_eval(self._expr_ast) check_ast_errors(self._expr_eval) if self._val is not None: if self._val > self.max: self._val = self.max elif self._val < self.min: self._val = self.min if self._expr_eval is not None: self._expr_eval.symtable[self.name] = self._val return self._val def set_expr_eval(self, evaluator): """Set expression evaluator instance.""" self._expr_eval = evaluator @property def value(self): """Return the numerical value of the Parameter, with bounds applied.""" return self._getval() @value.setter def value(self, val): """Set the numerical Parameter value.""" self._val = val if not hasattr(self, '_expr_eval'): self._expr_eval = None if self._expr_eval is not None: self._expr_eval.symtable[self.name] = val @property def expr(self): """Return the mathematical expression used to constrain the value during the fit.""" return self._expr @expr.setter def expr(self, val): """Set the mathematical expression used to constrain the value during the fit. To remove a constraint you must supply an empty string. """ self.__set_expression(val) def __set_expression(self, val): if val == '': val = None self._expr = val if val is not None: self.vary = False if not hasattr(self, '_expr_eval'): self._expr_eval = None if val is None: self._expr_ast = None if val is not None and self._expr_eval is not None: self._expr_ast = self._expr_eval.parse(val) check_ast_errors(self._expr_eval) self._expr_deps = get_ast_names(self._expr_ast) def __array__(self): """array""" return array(float(self._getval())) def __str__(self): """string""" return self.__repr__() def __abs__(self): """abs""" return abs(self._getval()) def __neg__(self): """neg""" return -self._getval() def __pos__(self): """positive""" return +self._getval() def __nonzero__(self): """not zero""" return self._getval() != 0 def __int__(self): """int""" return int(self._getval()) def __float__(self): """float""" return float(self._getval()) def __trunc__(self): """trunc""" return self._getval().__trunc__() def __add__(self, other): """+""" return self._getval() + other def __sub__(self, other): """-""" return self._getval() - other def __div__(self, other): """/""" return self._getval() / other __truediv__ = __div__ def __floordiv__(self, other): """//""" return self._getval() // other def __divmod__(self, other): """divmod.""" return divmod(self._getval(), other) def __mod__(self, other): """%""" return self._getval() % other def __mul__(self, other): """*""" return self._getval() * other def __pow__(self, other): """**""" return self._getval() ** other def __gt__(self, other): """>""" return self._getval() > other def __ge__(self, other): """>=""" return self._getval() >= other def __le__(self, other): """<=""" return self._getval() <= other def __lt__(self, other): """<""" return self._getval() < other def __eq__(self, other): """==""" return self._getval() == other def __ne__(self, other): """!=""" return self._getval() != other def __radd__(self, other): """+ (right)""" return other + self._getval() def __rdiv__(self, other): """/ (right)""" return other / self._getval() __rtruediv__ = __rdiv__ def __rdivmod__(self, other): """divmod (right)""" return divmod(other, self._getval()) def __rfloordiv__(self, other): """// (right)""" return other // self._getval() def __rmod__(self, other): """% (right)""" return other % self._getval() def __rmul__(self, other): """* (right)""" return other * self._getval() def __rpow__(self, other): """** (right)""" return other ** self._getval() def __rsub__(self, other): """- (right)""" return other - self._getval() def isParameter(x): """Test for Parameter-ness.""" return (isinstance(x, Parameter) or x.__class__.__name__ == 'Parameter') lmfit-0.9.7/lmfit/printfuncs.py0000644000076500000240000001712213107321632017433 0ustar Newvillestaff00000000000000"""Functions to display fitting results and confidence intervals.""" from __future__ import print_function import re from .parameter import Parameters def alphanumeric_sort(s, _nsre=re.compile('([0-9]+)')): """Sort alphanumeric string.""" return [int(text) if text.isdigit() else text.lower() for text in re.split(_nsre, s)] def getfloat_attr(obj, attr, fmt='%.3f'): """Format an attribute of an object for printing.""" val = getattr(obj, attr, None) if val is None: return 'unknown' if isinstance(val, int): return '%d' % val if isinstance(val, float): return fmt % val else: return repr(val) def gformat(val, length=11): """Format a number with '%g'-like format. The return will be length ``length`` (default is 12) and have at least length-6 significant digits. """ length = max(length, 7) fmt = '{0: .%ig}' % (length-6) if isinstance(val, int): out = ('{0: .%ig}' % (length-2)).format(val) if len(out) > length: out = fmt.format(val) else: out = fmt.format(val) if len(out) < length: if 'e' in out: ie = out.find('e') if '.' not in out[:ie]: out = out[:ie] + '.' + out[ie:] out = out.replace('e', '0'*(length-len(out))+'e') else: fmt = '{0: .%ig}' % (length-1) out = fmt.format(val)[:length] if len(out) < length: pad = '0' if '.' in out else ' ' out += pad*(length-len(out)) return out CORREL_HEAD = '[[Correlations]] (unreported correlations are < % .3f)' def fit_report(inpars, modelpars=None, show_correl=True, min_correl=0.1, sort_pars=False): """Generate a report of the fitting results. The report contains the best-fit values for the parameters and their uncertainties and correlations. Parameters ---------- inpars : Parameters Input Parameters from fit or MinimizerResult returned from a fit. modelpars : Parameters, optional Known Model Parameters. show_correl : bool, optional Whether to show list of sorted correlations (default is True). min_correl : float, optional Smallest correlation in absolute value to show (default is 0.1). sort_pars : bool or callable, optional Whether to show parameter names sorted in alphanumerical order. If False (default), then the parameters will be listed in the order they were added to the Parameters dictionary. If callable, then this (one argument) function is used to extract a comparison key from each list element. Returns ------- string Multi-line text of fit report. """ if isinstance(inpars, Parameters): result, params = None, inpars if hasattr(inpars, 'params'): result = inpars params = inpars.params if sort_pars: if callable(sort_pars): key = sort_pars else: key = alphanumeric_sort parnames = sorted(params, key=key) else: # dict.keys() returns a KeysView in py3, and they're indexed # further down parnames = list(params.keys()) buff = [] add = buff.append if result is not None: add("[[Fit Statistics]]") add(" # function evals = %s" % getfloat_attr(result, 'nfev')) add(" # data points = %s" % getfloat_attr(result, 'ndata')) add(" # variables = %s" % getfloat_attr(result, 'nvarys')) add(" chi-square = %s" % getfloat_attr(result, 'chisqr')) add(" reduced chi-square = %s" % getfloat_attr(result, 'redchi')) add(" Akaike info crit = %s" % getfloat_attr(result, 'aic')) add(" Bayesian info crit = %s" % getfloat_attr(result, 'bic')) namelen = max([len(n) for n in parnames]) add("[[Variables]]") for name in parnames: par = params[name] space = ' '*(namelen+1-len(name)) nout = "%s:%s" % (name, space) inval = '(init= ?)' if par.init_value is not None: inval = '(init=% .7g)' % par.init_value if modelpars is not None and name in modelpars: inval = '%s, model_value =% .7g' % (inval, modelpars[name].value) try: sval = gformat(par.value) except (TypeError, ValueError): sval = 'Non Numeric Value?' if par.stderr is not None: serr = gformat(par.stderr, length=9) try: spercent = '({0:.2%})'.format(abs(par.stderr/par.value)) except ZeroDivisionError: spercent = '' sval = '%s +/-%s %s' % (sval, serr, spercent) if par.vary: add(" %s %s %s" % (nout, sval, inval)) elif par.expr is not None: add(" %s %s == '%s'" % (nout, sval, par.expr)) else: add(" %s % .7g (fixed)" % (nout, par.value)) if show_correl: correls = {} for i, name in enumerate(parnames): par = params[name] if not par.vary: continue if hasattr(par, 'correl') and par.correl is not None: for name2 in parnames[i+1:]: if (name != name2 and name2 in par.correl and abs(par.correl[name2]) > min_correl): correls["%s, %s" % (name, name2)] = par.correl[name2] sort_correl = sorted(correls.items(), key=lambda it: abs(it[1])) sort_correl.reverse() if len(sort_correl) > 0: add(CORREL_HEAD % min_correl) for name, val in sort_correl: lspace = max(1, 25 - len(name)) add(' C(%s)%s = % .3f ' % (name, (' '*30)[:lspace], val)) return '\n'.join(buff) def report_errors(params, **kws): """Print a report for fitted params: see error_report().""" print(fit_report(params, **kws)) def report_fit(params, **kws): """Print a report for fitted params: see error_report().""" print(fit_report(params, **kws)) def ci_report(ci, with_offset=True, ndigits=5): """Return text of a report for confidence intervals. Parameters ---------- with_offset : bool, optional Whether to subtract best value from all other values (default is True). ndigits : int, optional Number of significant digits to show (default is 5). Returns ------- str Text of formatted report on confidence intervals. """ maxlen = max([len(i) for i in ci]) buff = [] add = buff.append def convp(x): """TODO: function docstring.""" if abs(x[0]) < 1.e-2: return "_BEST_" return "%.2f%%" % (x[0]*100) title_shown = False fmt_best = fmt_diff = "{0:.%if}" % ndigits if with_offset: fmt_diff = "{0:+.%if}" % ndigits for name, row in ci.items(): if not title_shown: add("".join([''.rjust(maxlen+1)] + [i.rjust(ndigits+5) for i in map(convp, row)])) title_shown = True thisrow = [" %s:" % name.ljust(maxlen)] offset = 0.0 if with_offset: for cval, val in row: if abs(cval) < 1.e-2: offset = val for cval, val in row: if cval < 1.e-2: sval = fmt_best.format(val) else: sval = fmt_diff.format(val-offset) thisrow.append(sval.rjust(ndigits+5)) add("".join(thisrow)) return '\n'.join(buff) def report_ci(ci): """Print a report for confidence intervals.""" print(ci_report(ci)) lmfit-0.9.7/lmfit/ui/0000755000076500000240000000000013114357470015307 5ustar Newvillestaff00000000000000lmfit-0.9.7/lmfit/ui/__init__.py0000644000076500000240000000305313066042256017420 0ustar Newvillestaff00000000000000# These variables are used at the end of the module to decide # which BaseFitter subclass the Fitter will point to. import warnings has_ipython, has_matplotlib = False, False try: import matplotlib except ImportError: pass else: has_matplotlib = True try: import IPython except ImportError: warnings.warn("lmfit.Fitter will use basic mode, not IPython: need matplotlib") else: _ipy_msg1 = "lmfit.Fitter will use basic mode, not IPython: need IPython2." _ipy_msg2 = "lmfit.Fitter will use basic mode, not IPython: could not get IPython version" _ipy_msg3 = "lmfit.Fitter will use basic mode, not IPython: need ipywidgets." try: major_version = IPython.release.version_info[0] if major_version < 2: warnings.warn(_ipy_msg1) elif major_version > 3: # After IPython 3, widgets were moved to a separate package. # There is a shim to allow the old import, but the package has to be # installed for that to work. try: import ipywidgets except ImportError: warnings.warn(_ipy_msg3) else: # has_ipython = iPython installed and we are in an IPython session. has_ipython = IPython.get_ipython() is not None except Exception as e: warnings.warn(_ipy_msg2) from .basefitter import BaseFitter Fitter = BaseFitter if has_matplotlib: from .basefitter import MPLFitter Fitter = MPLFitter if has_ipython: from .ipy_fitter import NotebookFitter Fitter = NotebookFitter lmfit-0.9.7/lmfit/ui/basefitter.py0000644000076500000240000003003513066042256020011 0ustar Newvillestaff00000000000000import warnings import numpy as np from ..asteval import Interpreter from ..astutils import NameFinder from ..model import Model from ..models import ExponentialModel # arbitrary default from ..parameter import check_ast_errors _COMMON_DOC = """ This an interactive container for fitting models to particular data. It maintains the attributes `current_params` and `current_result`. When its fit() method is called, the best fit becomes the new `current_params`. The most basic usage is iteratively fitting data, taking advantage of this stateful memory that keep the parameters between each fit. """ _COMMON_EXAMPLES_DOC = """ Examples -------- >>> fitter = Fitter(data, model=SomeModel, x=x) >>> fitter.model # This property can be changed, to try different models on the same # data with the same independent vars. # (This is especially handy in the notebook.) >>> fitter.current_params # This copy of the model's Parameters is updated after each fit. >>> fitter.fit() # Perform a fit using fitter.current_params as a guess. # Optionally, pass a params argument or individual keyword arguments # to override current_params. >>> fitter.current_result # This is the result of the latest fit. It contain the usual # copies of the Parameters, in the attributes params and init_params. >>> fitter.data = new_data # If this property is updated, the `current_params` are retained an used # as an initial guess if fit() is called again. """ class BaseFitter(object): __doc__ = _COMMON_DOC + """ Parameters ---------- data : array-like model : lmfit.Model optional initial Model to use, maybe be set or changed later """ + _COMMON_EXAMPLES_DOC def __init__(self, data, model=None, **kwargs): self._data = data self.kwargs = kwargs # GUI-based subclasses need a default value for the menu of models, # and so an arbitrary default is applied here, for uniformity # among the subclasses. if model is None: model = ExponentialModel self.model = model def _on_model_value_change(self, name, value): self.model = value def _on_fit_button_click(self, b): self.fit() def _on_guess_button_click(self, b): self.guess() @property def data(self): return self._data @data.setter def data(self, value): self._data = value @property def model(self): return self._model @model.setter def model(self, value): if callable(value): model = value() else: model = value self._model = model self.current_result = None self._current_params = model.make_params() # Use these to evaluate any Parameters that use expressions. self.asteval = Interpreter() self.namefinder = NameFinder() self._finalize_model(value) self.guess() def _finalize_model(self, value): # subclasses optionally override to update display here pass @property def current_params(self): """Each time fit() is called, these will be updated to reflect the latest best params. They will be used as the initial guess for the next fit, unless overridden by arguments to fit().""" return self._current_params @current_params.setter def current_params(self, new_params): # Copy contents, but retain original params objects. for name, par in new_params.items(): self._current_params[name].value = par.value self._current_params[name].expr = par.expr self._current_params[name].vary = par.vary self._current_params[name].min = par.min self._current_params[name].max = par.max # Compute values for expression-based Parameters. self.__assign_deps(self._current_params) for _, par in self._current_params.items(): if par.value is None: self.__update_paramval(self._current_params, par.name) self._finalize_params() def _finalize_params(self): # subclasses can override this to pass params to display pass def guess(self): count_indep_vars = len(self.model.independent_vars) guessing_successful = True try: if count_indep_vars == 0: guess = self.model.guess(self._data) elif count_indep_vars == 1: key = self.model.independent_vars[0] val = self.kwargs[key] d = {key: val} guess = self.model.guess(self._data, **d) self.current_params = guess except NotImplementedError: guessing_successful = False return guessing_successful def __assign_deps(self, params): # N.B. This does not use self.current_params but rather # new Parameters that are being built by self.guess(). for name, par in params.items(): if par.expr is not None: par.ast = self.asteval.parse(par.expr) check_ast_errors(self.asteval.error) par.deps = [] self.namefinder.names = [] self.namefinder.generic_visit(par.ast) for symname in self.namefinder.names: if (symname in self.current_params and symname not in par.deps): par.deps.append(symname) self.asteval.symtable[name] = par.value if par.name is None: par.name = name def __update_paramval(self, params, name): # N.B. This does not use self.current_params but rather # new Parameters that are being built by self.guess(). par = params[name] if getattr(par, 'expr', None) is not None: if getattr(par, 'ast', None) is None: par.ast = self.asteval.parse(par.expr) if par.deps is not None: for dep in par.deps: self.__update_paramval(params, dep) par.value = self.asteval.run(par.ast) out = check_ast_errors(self.asteval.error) if out is not None: self.asteval.raise_exception(None) self.asteval.symtable[name] = par.value def fit(self, *args, **kwargs): "Use current_params unless overridden by arguments passed here." guess = dict(self.current_params) guess.update(self.kwargs) # from __init__, e.g. x=x guess.update(kwargs) self.current_result = self.model.fit(self._data, *args, **guess) self.current_params = self.current_result.params class MPLFitter(BaseFitter): # This is a small elaboration on BaseModel; it adds a plot() # method that depends on matplotlib. It adds several plot- # styling arguments to the signature. __doc__ = _COMMON_DOC + """ Parameters ---------- data : array-like model : lmfit.Model optional initial Model to use, maybe be set or changed later Additional Parameters --------------------- axes_style : dictionary representing style keyword arguments to be passed through to `Axes.set(...)` data_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the data points init_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the initial fit line best_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the best fit line **kwargs : independent variables or extra arguments, passed like `x=x` """ + _COMMON_EXAMPLES_DOC def __init__(self, data, model=None, axes_style={}, data_style={}, init_style={}, best_style={}, **kwargs): self.axes_style = axes_style self.data_style = data_style self.init_style = init_style self.best_style = best_style super(MPLFitter, self).__init__(data, model, **kwargs) def plot(self, axes_style={}, data_style={}, init_style={}, best_style={}, ax=None): """Plot data, initial guess fit, and best fit. Optional style arguments pass keyword dictionaries through to their respective components of the matplotlib plot. Precedence is: 1. arguments passed to this function, plot() 2. arguments passed to the Fitter when it was first declared 3. hard-coded defaults Parameters --------------------- axes_style : dictionary representing style keyword arguments to be passed through to `Axes.set(...)` data_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the data points init_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the initial fit line best_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the best fit line ax : matplotlib.Axes optional `Axes` object. Axes will be generated if not provided. """ try: import matplotlib.pyplot as plt except ImportError: raise ImportError("Matplotlib is required to use this Fitter. " "Use BaseFitter or a subclass thereof " "that does not depend on matplotlib.") # Configure style _axes_style= dict() # none, but this is here for possible future use _axes_style.update(self.axes_style) _axes_style.update(axes_style) _data_style= dict(color='blue', marker='o', linestyle='none') _data_style.update(**_normalize_kwargs(self.data_style, 'line2d')) _data_style.update(**_normalize_kwargs(data_style, 'line2d')) _init_style = dict(color='gray') _init_style.update(**_normalize_kwargs(self.init_style, 'line2d')) _init_style.update(**_normalize_kwargs(init_style, 'line2d')) _best_style= dict(color='red') _best_style.update(**_normalize_kwargs(self.best_style, 'line2d')) _best_style.update(**_normalize_kwargs(best_style, 'line2d')) if ax is None: fig, ax = plt.subplots() count_indep_vars = len(self.model.independent_vars) if count_indep_vars == 0: ax.plot(self._data, **_data_style) elif count_indep_vars == 1: indep_var = self.kwargs[self.model.independent_vars[0]] ax.plot(indep_var, self._data, **_data_style) else: raise NotImplementedError("Cannot plot models with more than one " "indepedent variable.") result = self.current_result # alias for brevity if not result: ax.set(**_axes_style) return # short-circuit the rest of the plotting if count_indep_vars == 0: ax.plot(result.init_fit, **_init_style) ax.plot(result.best_fit, **_best_style) elif count_indep_vars == 1: ax.plot(indep_var, result.init_fit, **_init_style) ax.plot(indep_var, result.best_fit, **_best_style) ax.set(**_axes_style) def _normalize_kwargs(kwargs, kind='patch'): """Convert matplotlib keywords from short to long form.""" # Source: # github.com/tritemio/FRETBursts/blob/fit_experim/fretbursts/burst_plot.py if kind == 'line2d': long_names = dict(c='color', ls='linestyle', lw='linewidth', mec='markeredgecolor', mew='markeredgewidth', mfc='markerfacecolor', ms='markersize',) elif kind == 'patch': long_names = dict(c='color', ls='linestyle', lw='linewidth', ec='edgecolor', fc='facecolor',) for short_name in long_names: if short_name in kwargs: kwargs[long_names[short_name]] = kwargs.pop(short_name) return kwargs lmfit-0.9.7/lmfit/ui/ipy_fitter.py0000644000076500000240000002455313066042256020047 0ustar Newvillestaff00000000000000import warnings import IPython from IPython.display import clear_output, display import numpy as np from ..model import Model from .basefitter import _COMMON_DOC, _COMMON_EXAMPLES_DOC, MPLFitter # Note: If IPython is not available of the version is < 2, # this module will not be imported, and a different Fitter. # Widgets were only experimental in IPython 2.x, but this does work there. # Handle the change in naming from 2.x to 3.x. IPY2 = IPython.release.version_info[0] == 2 IPY3 = IPython.release.version_info[0] == 3 if IPY2: from IPython.html.widgets import DropdownWidget as Dropdown from IPython.html.widgets import ButtonWidget as Button from IPython.html.widgets import ContainerWidget from IPython.html.widgets import FloatTextWidget as FloatText from IPython.html.widgets import CheckboxWidget as Checkbox class HBox(ContainerWidget): def __init__(self, *args, **kwargs): self.add_class('hbox') super(self, ContainerWidget).__init__(*args, **kwargs) elif IPY3: # as of IPython 3.x: from IPython.html.widgets import Dropdown from IPython.html.widgets import Button from IPython.html.widgets import HBox from IPython.html.widgets import FloatText from IPython.html.widgets import Checkbox else: # as of IPython 4.x+: from ipywidgets import Dropdown from ipywidgets import Button from ipywidgets import HBox from ipywidgets import FloatText from ipywidgets import Checkbox class ParameterWidgetGroup(object): """Construct several widgets that together represent a Parameter. This will only be used if IPython is available.""" def __init__(self, par): self.par = par # Define widgets. self.value_text = FloatText(description=par.name, min=self.par.min, max=self.par.max) self.value_text.width = 100 self.min_text = FloatText(description='min', max=self.par.max) self.min_text.width = 100 self.max_text = FloatText(description='max', min=self.par.min) self.max_text.width = 100 self.min_checkbox = Checkbox(description='min') self.max_checkbox = Checkbox(description='max') self.vary_checkbox = Checkbox(description='vary') # Set widget values and visibility. if par.value is not None: self.value_text.value = self.par.value min_unset = self.par.min is None or self.par.min == -np.inf max_unset = self.par.max is None or self.par.max == np.inf self.min_checkbox.value = not min_unset self.min_text.visible = not min_unset self.min_text.value = self.par.min self.max_checkbox.value = not max_unset self.max_text.visible = not max_unset self.max_text.value = self.par.max self.vary_checkbox.value = self.par.vary # Configure widgets to sync with par attributes. self.value_text.on_trait_change(self._on_value_change, 'value') self.min_text.on_trait_change(self._on_min_value_change, 'value') self.max_text.on_trait_change(self._on_max_value_change, 'value') self.min_checkbox.on_trait_change(self._on_min_checkbox_change, 'value') self.max_checkbox.on_trait_change(self._on_max_checkbox_change, 'value') self.vary_checkbox.on_trait_change(self._on_vary_change, 'value') def _on_value_change(self, name, value): self.par.value = value def _on_min_checkbox_change(self, name, value): self.min_text.visible = value if value: # -np.inf does not play well with a numerical text field, # so set min to -1 if activated (and back to -inf if deactivated). self.min_text.value = -1 self.par.min = self.min_text.value self.value_text.min = self.min_text.value else: self.par.min = None def _on_max_checkbox_change(self, name, value): self.max_text.visible = value if value: # np.inf does not play well with a numerical text field, # so set max to 1 if activated (and back to inf if deactivated). self.max_text.value = 1 self.par.max = self.max_text.value self.value_text.max = self.max_text.value else: self.par.max = None def _on_min_value_change(self, name, value): self.par.min = value self.value_text.min = value self.max_text.min = value def _on_max_value_change(self, name, value): self.par.max = value self.value_text.max = value self.min_text.max = value def _on_vary_change(self, name, value): self.par.vary = value # self.value_text.disabled = not value def close(self): # one convenience method to close (i.e., hide and disconnect) all # widgets in this group self.value_text.close() self.min_text.close() self.max_text.close() self.vary_checkbox.close() self.min_checkbox.close() self.max_checkbox.close() def _repr_html_(self): box = HBox() box.children = [self.value_text, self.vary_checkbox, self.min_checkbox, self.min_text, self.max_checkbox, self.max_text] display(box) # Make it easy to set the widget attributes directly. @property def value(self): return self.value_text.value @value.setter def value(self, value): self.value_text.value = value @property def vary(self): return self.vary_checkbox.value @vary.setter def vary(self, value): self.vary_checkbox.value = value @property def min(self): return self.min_text.value @min.setter def min(self, value): self.min_text.value = value @property def max(self): return self.max_text.value @max.setter def max(self, value): self.max_text.value = value @property def name(self): return self.par.name class NotebookFitter(MPLFitter): __doc__ = _COMMON_DOC + """ If IPython is available, it uses the IPython notebook's rich display to fit data interactively in a web-based GUI. The Parameters are represented in a web-based form that is kept in sync with `current_params`. All subclasses to Model, including user-defined ones, are shown in a drop-down menu. Clicking the "Fit" button updates a plot, as above, and updates the Parameters in the form to reflect the best fit. Parameters ---------- data : array-like model : lmfit.Model optional initial Model to use, maybe be set or changed later all_models : list optional list of Models to populate drop-down menu, by default all built-in and user-defined subclasses of Model are used Additional Parameters --------------------- axes_style : dictionary representing style keyword arguments to be passed through to `Axes.set(...)` data_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the data points init_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the initial fit line best_style : dictionary representing style keyword arguments to be passed through to the matplotlib `plot()` command the plots the best fit line **kwargs : independent variables or extra arguments, passed like `x=x` """ + _COMMON_EXAMPLES_DOC def __init__(self, data, model=None, all_models=None, axes_style={}, data_style={}, init_style={}, best_style={}, **kwargs): # Dropdown menu of all subclasses of Model, incl. user-defined. self.models_menu = Dropdown() # Dropbox API is very different between IPy 2.x and 3.x. if IPY2: if all_models is None: all_models = dict([(m.__name__, m) for m in Model.__subclasses__()]) self.models_menu.values = all_models else: if all_models is None: all_models = [(m.__name__, m) for m in Model.__subclasses__()] self.models_menu.options = all_models self.models_menu.on_trait_change(self._on_model_value_change, 'value') # Button to trigger fitting. self.fit_button = Button(description='Fit') self.fit_button.on_click(self._on_fit_button_click) # Button to trigger guessing. self.guess_button = Button(description='Auto-Guess') self.guess_button.on_click(self._on_guess_button_click) # Parameter widgets are not built here. They are (re-)built when # the model is (re-)set. super(NotebookFitter, self).__init__(data, model, axes_style, data_style, init_style, best_style, **kwargs) def _repr_html_(self): display(self.models_menu) button_box = HBox() button_box.children = [self.fit_button, self.guess_button] display(button_box) for pw in self.param_widgets: display(pw) self.plot() def guess(self): guessing_successful = super(NotebookFitter, self).guess() self.guess_button.disabled = not guessing_successful def _finalize_model(self, value): first_run = not hasattr(self, 'param_widgets') if not first_run: # Remove all Parameter widgets, and replace them with widgets # for the new model. for pw in self.param_widgets: pw.close() self.models_menu.value = value self.param_widgets = [ParameterWidgetGroup(p) for _, p in self._current_params.items()] if not first_run: for pw in self.param_widgets: display(pw) def _finalize_params(self): for pw in self.param_widgets: pw.value = self._current_params[pw.name].value pw.min = self._current_params[pw.name].min pw.max = self._current_params[pw.name].max pw.vary = self._current_params[pw.name].vary def plot(self): clear_output(wait=True) super(NotebookFitter, self).plot() def fit(self): super(NotebookFitter, self).fit() self.plot() lmfit-0.9.7/lmfit/uncertainties/0000755000076500000240000000000013114357470017547 5ustar Newvillestaff00000000000000lmfit-0.9.7/lmfit/uncertainties/__init__.py0000644000076500000240000017240113111710636021657 0ustar Newvillestaff00000000000000#!! Whenever the documentation below is updated, setup.py should be # checked for consistency. ''' Calculations with full error propagation for quantities with uncertainties. Derivatives can also be calculated. Web user guide: http://packages.python.org/uncertainties/. Example of possible calculation: (0.2 +/- 0.01)**2 = 0.04 +/- 0.004. Correlations between expressions are correctly taken into account (for instance, with x = 0.2+/-0.01, 2*x-x-x is exactly zero, as is y-x-x with y = 2*x). Examples: import uncertainties from uncertainties import ufloat from uncertainties.umath import * # sin(), etc. # Mathematical operations: x = ufloat((0.20, 0.01)) # x = 0.20+/-0.01 x = ufloat("0.20+/-0.01") # Other representation x = ufloat("0.20(1)") # Other representation x = ufloat("0.20") # Implicit uncertainty of +/-1 on the last digit print x**2 # Square: prints "0.04+/-0.004" print sin(x**2) # Prints "0.0399...+/-0.00399..." print x.std_score(0.17) # Prints "-3.0": deviation of -3 sigmas # Access to the nominal value, and to the uncertainty: square = x**2 # Square print square # Prints "0.04+/-0.004" print square.nominal_value # Prints "0.04" print square.std_dev() # Prints "0.004..." print square.derivatives[x] # Partial derivative: 0.4 (= 2*0.20) # Correlations: u = ufloat((1, 0.05), "u variable") # Tag v = ufloat((10, 0.1), "v variable") sum_value = u+v u.set_std_dev(0.1) # Standard deviations can be updated on the fly print sum_value - u - v # Prints "0.0" (exact result) # List of all sources of error: print sum_value # Prints "11+/-0.1414..." for (var, error) in sum_value.error_components().items(): print "%s: %f" % (var.tag, error) # Individual error components # Covariance matrices: cov_matrix = uncertainties.covariance_matrix([u, v, sum_value]) print cov_matrix # 3x3 matrix # Correlated variables can be constructed from a covariance matrix, if # NumPy is available: (u2, v2, sum2) = uncertainties.correlated_values([1, 10, 11], cov_matrix) print u2 # Value and uncertainty of u: correctly recovered (1+/-0.1) print uncertainties.covariance_matrix([u2, v2, sum2]) # == cov_matrix - The main function provided by this module is ufloat, which creates numbers with uncertainties (Variable objects). Variable objects can be used as if they were regular Python numbers. The main attributes and methods of Variable objects are defined in the documentation of the Variable class. - Valid operations on numbers with uncertainties include basic mathematical functions (addition, etc.). Most operations from the standard math module (sin, etc.) can be applied on numbers with uncertainties by using their generalization from the uncertainties.umath module: from uncertainties.umath import sin print sin(ufloat("1+/-0.01")) # 0.841...+/-0.005... print sin(1) # umath.sin() also works on floats, exactly like math.sin() Logical operations (>, ==, etc.) are also supported. Basic operations on NumPy arrays or matrices of numbers with uncertainties can be performed: 2*numpy.array([ufloat((1, 0.01)), ufloat((2, 0.1))]) More complex operations on NumPy arrays can be performed through the dedicated uncertainties.unumpy sub-module (see its documentation). Calculations that are performed through non-Python code (Fortran, C, etc.) can handle numbers with uncertainties instead of floats through the provided wrap() wrapper: import uncertainties # wrapped_f is a version of f that can take arguments with # uncertainties, even if f only takes floats: wrapped_f = uncertainties.wrap(f) If some derivatives of the wrapped function f are known (analytically, or numerically), they can be given to wrap()--see the documentation for wrap(). - Utility functions are also provided: the covariance matrix between random variables can be calculated with covariance_matrix(), or used as input for the definition of correlated quantities (correlated_values() function--defined only if the NumPy module is available). - Mathematical expressions involving numbers with uncertainties generally return AffineScalarFunc objects, which also print as a value with uncertainty. Their most useful attributes and methods are described in the documentation for AffineScalarFunc. Note that Variable objects are also AffineScalarFunc objects. UFloat is an alias for AffineScalarFunc, provided as a convenience: testing whether a value carries an uncertainty handled by this module should be done with insinstance(my_value, UFloat). - Mathematically, numbers with uncertainties are, in this package, probability distributions. These probabilities are reduced to two numbers: a nominal value and an uncertainty. Thus, both variables (Variable objects) and the result of mathematical operations (AffineScalarFunc objects) contain these two values (respectively in their nominal_value attribute and through their std_dev() method). The uncertainty of a number with uncertainty is simply defined in this package as the standard deviation of the underlying probability distribution. The numbers with uncertainties manipulated by this package are assumed to have a probability distribution mostly contained around their nominal value, in an interval of about the size of their standard deviation. This should cover most practical cases. A good choice of nominal value for a number with uncertainty is thus the median of its probability distribution, the location of highest probability, or the average value. - When manipulating ensembles of numbers, some of which contain uncertainties, it can be useful to access the nominal value and uncertainty of all numbers in a uniform manner: x = ufloat("3+/-0.1") print nominal_value(x) # Prints 3 print std_dev(x) # Prints 0.1 print nominal_value(3) # Prints 3: nominal_value works on floats print std_dev(3) # Prints 0: std_dev works on floats - Probability distributions (random variables and calculation results) are printed as: nominal value +/- standard deviation but this does not imply any property on the nominal value (beyond the fact that the nominal value is normally inside the region of high probability density), or that the probability distribution of the result is symmetrical (this is rarely strictly the case). - Linear approximations of functions (around the nominal values) are used for the calculation of the standard deviation of mathematical expressions with this package. The calculated standard deviations and nominal values are thus meaningful approximations as long as the functions involved have precise linear expansions in the region where the probability distribution of their variables is the largest. It is therefore important that uncertainties be small. Mathematically, this means that the linear term of functions around the nominal values of their variables should be much larger than the remaining higher-order terms over the region of significant probability. For instance, sin(0+/-0.01) yields a meaningful standard deviation since it is quite linear over 0+/-0.01. However, cos(0+/-0.01) yields an approximate standard deviation of 0 (because the cosine is not well approximated by a line around 0), which might not be precise enough for all applications. - Comparison operations (>, ==, etc.) on numbers with uncertainties have a pragmatic semantics, in this package: numbers with uncertainties can be used wherever Python numbers are used, most of the time with a result identical to the one that would be obtained with their nominal value only. However, since the objects defined in this module represent probability distributions and not pure numbers, comparison operator are interpreted in a specific way. The result of a comparison operation ("==", ">", etc.) is defined so as to be essentially consistent with the requirement that uncertainties be small: the value of a comparison operation is True only if the operation yields True for all infinitesimal variations of its random variables, except, possibly, for an infinitely small number of cases. Example: "x = 3.14; y = 3.14" is such that x == y but x = ufloat((3.14, 0.01)) y = ufloat((3.14, 0.01)) is not such that x == y, since x and y are independent random variables that almost never give the same value. However, x == x still holds. The boolean value (bool(x), "if x...") of a number with uncertainty x is the result of x != 0. - The uncertainties package is for Python 2.5 and above. - This package contains tests. They can be run either manually or automatically with the nose unit testing framework (nosetests). (c) 2009-2013 by Eric O. LEBIGOT (EOL) . Please send feature requests, bug reports, or feedback to this address. Please support future development by donating $5 or more through PayPal! This software is released under a dual license. (1) The BSD license. (2) Any other license, as long as it is obtained from the original author.''' # The idea behind this module is to replace the result of mathematical # operations by a local approximation of the defining function. For # example, sin(0.2+/-0.01) becomes the affine function # (AffineScalarFunc object) whose nominal value is sin(0.2) and # whose variations are given by sin(0.2+delta) = 0.98...*delta. # Uncertainties can then be calculated by using this local linear # approximation of the original function. from __future__ import division # Many analytical derivatives depend on this import re import math from math import sqrt, log # Optimization: no attribute look-up import copy import warnings import six # Numerical version: __version_info__ = (1, 9) __version__ = '.'.join(map(str, __version_info__)) __author__ = 'Eric O. LEBIGOT (EOL) ' # Attributes that are always exported (some other attributes are # exported only if the NumPy module is available...): __all__ = [ # All sub-modules and packages are not imported by default, # in particular because NumPy might be unavailable. 'ufloat', # Main function: returns a number with uncertainty # Uniform access to nominal values and standard deviations: 'nominal_value', 'std_dev', # Utility functions (more are exported if NumPy is present): 'covariance_matrix', # Class for testing whether an object is a number with # uncertainty. Not usually created by users (except through the # Variable subclass), but possibly manipulated by external code # ['derivatives()' method, etc.]. 'UFloat', # Wrapper for allowing non-pure-Python function to handle # quantities with uncertainties: 'wrap', # The documentation for wrap() indicates that numerical # derivatives are calculated through partial_derivative(). The # user might also want to change the size of the numerical # differentiation step. 'partial_derivative' ] ############################################################################### def set_doc(doc_string): """ Decorator function that sets the docstring to the given text. It is useful for functions whose docstring is calculated (including string substitutions). """ def set_doc_string(func): func.__doc__ = doc_string return func return set_doc_string # Some types known to not depend on Variable objects are put in # CONSTANT_TYPES. The most common types can be put in front, as this # may slightly improve the execution speed. CONSTANT_TYPES = (float, int, complex) # , long) ############################################################################### # Utility for issuing deprecation warnings def deprecation(message): ''' Warns the user with the given message, by issuing a DeprecationWarning. ''' warnings.warn(message, DeprecationWarning, stacklevel=2) ############################################################################### ## Definitions that depend on the availability of NumPy: try: import numpy except ImportError: pass else: # NumPy numbers do not depend on Variable objects: CONSTANT_TYPES += (numpy.number,) # Entering variables as a block of correlated values. Only available # if NumPy is installed. #! It would be possible to dispense with NumPy, but a routine should be # written for obtaining the eigenvectors of a symmetric matrix. See # for instance Numerical Recipes: (1) reduction to tri-diagonal # [Givens or Householder]; (2) QR / QL decomposition. def correlated_values(nom_values, covariance_mat, tags=None): """ Returns numbers with uncertainties (AffineScalarFunc objects) that correctly reproduce the given covariance matrix, and have the given (float) values as their nominal value. The correlated_values_norm() function returns the same result, but takes a correlation matrix instead of a covariance matrix. The list of values and the covariance matrix must have the same length, and the matrix must be a square (symmetric) one. The numbers with uncertainties returned depend on newly created, independent variables (Variable objects). If 'tags' is not None, it must list the tag of each new independent variable. nom_values -- sequence with the nominal (real) values of the numbers with uncertainties to be returned. covariance_mat -- full covariance matrix of the returned numbers with uncertainties (not the statistical correlation matrix, i.e., not the normalized covariance matrix). For example, the first element of this matrix is the variance of the first returned number with uncertainty. """ # If no tags were given, we prepare tags for the newly created # variables: if tags is None: tags = (None,) * len(nom_values) # The covariance matrix is diagonalized in order to define # the independent variables that model the given values: (variances, transform) = numpy.linalg.eigh(covariance_mat) # Numerical errors might make some variances negative: we set # them to zero: variances[variances < 0] = 0. # Creation of new, independent variables: # We use the fact that the eigenvectors in 'transform' are # special: 'transform' is unitary: its inverse is its transpose: variables = tuple( # The variables represent "pure" uncertainties: Variable(0, sqrt(variance), tag) for (variance, tag) in zip(variances, tags)) # Representation of the initial correlated values: values_funcs = tuple( AffineScalarFunc(value, dict(zip(variables, coords))) for (coords, value) in zip(transform, nom_values)) return values_funcs __all__.append('correlated_values') def correlated_values_norm(values_with_std_dev, correlation_mat, tags=None): ''' Returns correlated values like correlated_values(), but takes instead as input: - nominal (float) values along with their standard deviation, and - a correlation matrix (i.e. a normalized covariance matrix normalized with individual standard deviations). values_with_std_dev -- sequence of (nominal value, standard deviation) pairs. The returned, correlated values have these nominal values and standard deviations. correlation_mat -- correlation matrix (i.e. the normalized covariance matrix, a matrix with ones on its diagonal). ''' (nominal_values, std_devs) = numpy.transpose(values_with_std_dev) return correlated_values( nominal_values, correlation_mat*std_devs*std_devs[numpy.newaxis].T, tags) __all__.append('correlated_values_norm') ############################################################################### # Mathematical operations with local approximations (affine scalar # functions) class NotUpcast(Exception): 'Raised when an object cannot be converted to a number with uncertainty' def to_affine_scalar(x): """ Transforms x into a constant affine scalar function (AffineScalarFunc), unless it is already an AffineScalarFunc (in which case x is returned unchanged). Raises an exception unless 'x' belongs to some specific classes of objects that are known not to depend on AffineScalarFunc objects (which then cannot be considered as constants). """ if isinstance(x, AffineScalarFunc): return x #! In Python 2.6+, numbers.Number could be used instead, here: if isinstance(x, CONSTANT_TYPES): # No variable => no derivative to define: return AffineScalarFunc(x, {}) # Case of lists, etc. raise NotUpcast("%s cannot be converted to a number with" " uncertainty" % type(x)) def partial_derivative(f, param_num): """ Returns a function that numerically calculates the partial derivative of function f with respect to its argument number param_num. The step parameter represents the shift of the parameter used in the numerical approximation. """ def partial_derivative_of_f(*args, **kws): """ Partial derivative, calculated with the (-epsilon, +epsilon) method, which is more precise than the (0, +epsilon) method. """ # f_nominal_value = f(*args) param_kw = None if '__param__kw__' in kws: param_kw = kws.pop('__param__kw__') shifted_args = list(args) # Copy, and conversion to a mutable shifted_kws = {} for k, v in kws.items(): shifted_kws[k] = v step = 1.e-8 if param_kw in shifted_kws: step = step*abs(shifted_kws[param_kw]) elif param_num < len(shifted_args): # The step is relative to the parameter being varied, so that # shsifting it does not suffer from finite precision: step = step*abs(shifted_args[param_num]) if param_kw in shifted_kws: shifted_kws[param_kw] += step elif param_num < len(shifted_args): shifted_args[param_num] += step shifted_f_plus = f(*shifted_args, **shifted_kws) if param_kw in shifted_kws: shifted_kws[param_kw] -= 2*step elif param_num < len(shifted_args): shifted_args[param_num] -= 2*step shifted_f_minus = f(*shifted_args, **shifted_kws) return (shifted_f_plus - shifted_f_minus)/2/step return partial_derivative_of_f class NumericalDerivatives(object): """ Convenient access to the partial derivatives of a function, calculated numerically. """ # This is not a list because the number of arguments of the # function is not known in advance, in general. def __init__(self, function): """ 'function' is the function whose derivatives can be computed. """ self._function = function def __getitem__(self, n): """ Returns the n-th numerical derivative of the function. """ return partial_derivative(self._function, n) def wrap(f, derivatives_iter=None): """ Wraps a function f into a function that also accepts numbers with uncertainties (UFloat objects) and returns a number with uncertainties. Doing so may be necessary when function f cannot be expressed analytically (with uncertainties-compatible operators and functions like +, *, umath.sin(), etc.). f must return a scalar (not a list, etc.). In the wrapped function, the standard Python scalar arguments of f (float, int, etc.) can be replaced by numbers with uncertainties. The result will contain the appropriate uncertainty. If no argument to the wrapped function has an uncertainty, f simply returns its usual, scalar result. If supplied, derivatives_iter can be an iterable that generally contains functions; each successive function is the partial derivative of f with respect to the corresponding variable (one function for each argument of f, which takes as many arguments as f). If instead of a function, an element of derivatives_iter contains None, then it is automatically replaced by the relevant numerical derivative; this can be used for non-scalar arguments of f (like string arguments). If derivatives_iter is None, or if derivatives_iter contains a fixed (and finite) number of elements, then any missing derivative is calculated numerically. An infinite number of derivatives can be specified by having derivatives_iter be an infinite iterator; this can for instance be used for specifying the derivatives of functions with a undefined number of argument (like sum(), whose partial derivatives all return 1). Example (for illustration purposes only, as uncertainties.umath.sin() runs faster than the examples that follow): wrap(math.sin) is a sine function that can be applied to numbers with uncertainties. Its derivative will be calculated numerically. wrap(math.sin, [None]) would have produced the same result. wrap(math.sin, [math.cos]) is the same function, but with an analytically defined derivative. """ if derivatives_iter is None: derivatives_iter = NumericalDerivatives(f) else: # Derivatives that are not defined are calculated numerically, # if there is a finite number of them (the function lambda # *args: fsum(args) has a non-defined number of arguments, as # it just performs a sum): try: # Is the number of derivatives fixed? len(derivatives_iter) except TypeError: pass else: derivatives_iter = [ partial_derivative(f, k) if derivative is None else derivative for (k, derivative) in enumerate(derivatives_iter)] #! Setting the doc string after "def f_with...()" does not # seem to work. We define it explicitly: @set_doc("""\ Version of %s(...) that returns an affine approximation (AffineScalarFunc object), if its result depends on variables (Variable objects). Otherwise, returns a simple constant (when applied to constant arguments). Warning: arguments of the function that are not AffineScalarFunc objects must not depend on uncertainties.Variable objects in any way. Otherwise, the dependence of the result in uncertainties.Variable objects will be incorrect. Original documentation: %s""" % (f.__name__, f.__doc__)) def f_with_affine_output(*args, **kwargs): # Can this function perform the calculation of an # AffineScalarFunc (or maybe float) result? try: old_funcs = map(to_affine_scalar, args) aff_funcs = [to_affine_scalar(a) for a in args] aff_kws = kwargs aff_varkws = [] for key, val in kwargs.items(): if isinstance(val, Variable): aff_kws[key] = to_affine_scalar(val) aff_varkws.append(key) except NotUpcast: # This function does not know how to itself perform # calculations with non-float-like arguments (as they # might for instance be objects whose value really changes # if some Variable objects had different values): # Is it clear that we can't delegate the calculation? if any(isinstance(arg, AffineScalarFunc) for arg in args): # This situation arises for instance when calculating # AffineScalarFunc(...)*numpy.array(...). In this # case, we must let NumPy handle the multiplication # (which is then performed element by element): return NotImplemented else: # If none of the arguments is an AffineScalarFunc, we # can delegate the calculation to the original # function. This can be useful when it is called with # only one argument (as in # numpy.log10(numpy.ndarray(...)): return f(*args, **kwargs) ######################################## # Nominal value of the constructed AffineScalarFunc: args_values = [e.nominal_value for e in aff_funcs] kw_values = {} for key, val in aff_kws.items(): kw_values[key] = val if key in aff_varkws: kw_values[key] = val.nominal_value f_nominal_value = f(*args_values, **kw_values) ######################################## # List of involved variables (Variable objects): variables = set() for expr in aff_funcs: variables |= set(expr.derivatives) for vname in aff_varkws: variables |= set(aff_kws[vname].derivatives) ## It is sometimes useful to only return a regular constant: # (1) Optimization / convenience behavior: when 'f' is called # on purely constant values (e.g., sin(2)), there is no need # for returning a more complex AffineScalarFunc object. # (2) Functions that do not return a "float-like" value might # not have a relevant representation as an AffineScalarFunc. # This includes boolean functions, since their derivatives are # either 0 or are undefined: they are better represented as # Python constants than as constant AffineScalarFunc functions. if not variables or isinstance(f_nominal_value, bool): return f_nominal_value # The result of 'f' does depend on 'variables'... ######################################## # Calculation of the derivatives with respect to the arguments # of f (aff_funcs): # The chain rule is applied. This is because, in the case of # numerical derivatives, it allows for a better-controlled # numerical stability than numerically calculating the partial # derivatives through '[f(x + dx, y + dy, ...) - # f(x,y,...)]/da' where dx, dy,... are calculated by varying # 'a'. In fact, it is numerically better to control how big # (dx, dy,...) are: 'f' is a simple mathematical function and # it is possible to know how precise the df/dx are (which is # not possible with the numerical df/da calculation above). # We use numerical derivatives, if we don't already have a # list of derivatives: #! Note that this test could be avoided by requiring the # caller to always provide derivatives. When changing the # functions of the math module, this would force this module # to know about all the math functions. Another possibility # would be to force derivatives_iter to contain, say, the # first 3 derivatives of f. But any of these two ideas has a # chance to break, one day... (if new functions are added to # the math module, or if some function has more than 3 # arguments). derivatives_wrt_args = [] for (arg, derivative) in zip(aff_funcs, derivatives_iter): derivatives_wrt_args.append(derivative(*args_values, **aff_kws) if arg.derivatives else 0) kws_values = [] for vname in aff_varkws: kws_values.append( aff_kws[vname].nominal_value) for (vname, derivative) in zip(aff_varkws, derivatives_iter): derivatives_wrt_args.append(derivative(__param__kw__=vname, **kw_values) if aff_kws[vname].derivatives else 0) ######################################## # Calculation of the derivative of f with respect to all the # variables (Variable) involved. # Initial value (is updated below): derivatives_wrt_vars = dict((var, 0.) for var in variables) # The chain rule is used (we already have # derivatives_wrt_args): for (func, f_derivative) in zip(aff_funcs, derivatives_wrt_args): for (var, func_derivative) in func.derivatives.items(): derivatives_wrt_vars[var] += f_derivative * func_derivative for (vname, f_derivative) in zip(aff_varkws, derivatives_wrt_args): func = aff_kws[vname] for (var, func_derivative) in func.derivatives.items(): derivatives_wrt_vars[var] += f_derivative * func_derivative # The function now returns an AffineScalarFunc object: return AffineScalarFunc(f_nominal_value, derivatives_wrt_vars) # It is easier to work with f_with_affine_output, which represents # a wrapped version of 'f', when it bears the same name as 'f': f_with_affine_output.__name__ = f.__name__ return f_with_affine_output def _force_aff_func_args(func): """ Takes an operator op(x, y) and wraps it. The constructed operator returns func(x, to_affine_scalar(y)) if y can be upcast with to_affine_scalar(); otherwise, it returns NotImplemented. Thus, func() is only called on two AffineScalarFunc objects, if its first argument is an AffineScalarFunc. """ def op_on_upcast_args(x, y): """ Returns %s(self, to_affine_scalar(y)) if y can be upcast through to_affine_scalar. Otherwise returns NotImplemented. """ % func.__name__ try: y_with_uncert = to_affine_scalar(y) except NotUpcast: # This module does not know how to handle the comparison: # (example: y is a NumPy array, in which case the NumPy # array will decide that func() should be applied # element-wise between x and all the elements of y): return NotImplemented else: return func(x, y_with_uncert) return op_on_upcast_args ######################################## # Definition of boolean operators, that assume that self and # y_with_uncert are AffineScalarFunc. # The fact that uncertainties must be smalled is used, here: the # comparison functions are supposed to be constant for most values of # the random variables. # Even though uncertainties are supposed to be small, comparisons # between 3+/-0.1 and 3.0 are handled (even though x == 3.0 is not a # constant function in the 3+/-0.1 interval). The comparison between # x and x is handled too, when x has an uncertainty. In fact, as # explained in the main documentation, it is possible to give a useful # meaning to the comparison operators, in these cases. def _eq_on_aff_funcs(self, y_with_uncert): """ __eq__ operator, assuming that both self and y_with_uncert are AffineScalarFunc objects. """ difference = self - y_with_uncert # Only an exact zero difference means that self and y are # equal numerically: return not(difference._nominal_value or difference.std_dev()) def _ne_on_aff_funcs(self, y_with_uncert): """ __ne__ operator, assuming that both self and y_with_uncert are AffineScalarFunc objects. """ return not _eq_on_aff_funcs(self, y_with_uncert) def _gt_on_aff_funcs(self, y_with_uncert): """ __gt__ operator, assuming that both self and y_with_uncert are AffineScalarFunc objects. """ return self._nominal_value > y_with_uncert._nominal_value def _ge_on_aff_funcs(self, y_with_uncert): """ __ge__ operator, assuming that both self and y_with_uncert are AffineScalarFunc objects. """ return (_gt_on_aff_funcs(self, y_with_uncert) or _eq_on_aff_funcs(self, y_with_uncert)) def _lt_on_aff_funcs(self, y_with_uncert): """ __lt__ operator, assuming that both self and y_with_uncert are AffineScalarFunc objects. """ return self._nominal_value < y_with_uncert._nominal_value def _le_on_aff_funcs(self, y_with_uncert): """ __le__ operator, assuming that both self and y_with_uncert are AffineScalarFunc objects. """ return (_lt_on_aff_funcs(self, y_with_uncert) or _eq_on_aff_funcs(self, y_with_uncert)) ######################################## class AffineScalarFunc(object): """ Affine functions that support basic mathematical operations (addition, etc.). Such functions can for instance be used for representing the local (linear) behavior of any function. This class is mostly meant to be used internally. This class can also be used to represent constants. The variables of affine scalar functions are Variable objects. AffineScalarFunc objects include facilities for calculating the 'error' on the function, from the uncertainties on its variables. Main attributes and methods: - nominal_value, std_dev(): value at the origin / nominal value, and standard deviation. - error_components(): error_components()[x] is the error due to Variable x. - derivatives: derivatives[x] is the (value of the) derivative with respect to Variable x. This attribute is a dictionary whose keys are the Variable objects on which the function depends. All the Variable objects on which the function depends are in 'derivatives'. - std_score(x): position of number x with respect to the nominal value, in units of the standard deviation. """ # To save memory in large arrays: __slots__ = ('_nominal_value', 'derivatives') #! The code could be modify in order to accommodate for non-float # nominal values. This could for instance be done through # the operator module: instead of delegating operations to # float.__*__ operations, they could be delegated to # operator.__*__ functions (while taking care of properly handling # reverse operations: __radd__, etc.). def __init__(self, nominal_value, derivatives): """ nominal_value -- value of the function at the origin. nominal_value must not depend in any way of the Variable objects in 'derivatives' (the value at the origin of the function being defined is a constant). derivatives -- maps each Variable object on which the function being defined depends to the value of the derivative with respect to that variable, taken at the nominal value of all variables. Warning: the above constraint is not checked, and the user is responsible for complying with it. """ # Defines the value at the origin: # Only float-like values are handled. One reason is that it # does not make sense for a scalar function to be affine to # not yield float values. Another reason is that it would not # make sense to have a complex nominal value, here (it would # not be handled correctly at all): converting to float should # be possible. self._nominal_value = float(nominal_value) self.derivatives = derivatives # The following prevents the 'nominal_value' attribute from being # modified by the user: @property def nominal_value(self): "Nominal value of the random number." return self._nominal_value ############################################################ ### Operators: operators applied to AffineScalarFunc and/or ### float-like objects only are supported. This is why methods ### from float are used for implementing these operators. # Operators with no reflection: ######################################## # __nonzero__() is supposed to return a boolean value (it is used # by bool()). It is for instance used for converting the result # of comparison operators to a boolean, in sorted(). If we want # to be able to sort AffineScalarFunc objects, __nonzero__ cannot # return a AffineScalarFunc object. Since boolean results (such # as the result of bool()) don't have a very meaningful # uncertainty unless it is zero, this behavior is fine. def __nonzero__(self): """ Equivalent to self != 0. """ #! This might not be relevant for AffineScalarFunc objects # that contain values in a linear space which does not convert # the float 0 into the null vector (see the __eq__ function: # __nonzero__ works fine if subtracting the 0 float from a # vector of the linear space works as if 0 were the null # vector of that space): return self != 0. # Uses the AffineScalarFunc.__ne__ function ######################################## ## Logical operators: warning: the resulting value cannot always ## be differentiated. # The boolean operations are not differentiable everywhere, but # almost... # (1) I can rely on the assumption that the user only has "small" # errors on variables, as this is used in the calculation of the # standard deviation (which performs linear approximations): # (2) However, this assumption is not relevant for some # operations, and does not have to hold, in some cases. This # comes from the fact that logical operations (e.g. __eq__(x,y)) # are not differentiable for many usual cases. For instance, it # is desirable to have x == x for x = n+/-e, whatever the size of e. # Furthermore, n+/-e != n+/-e', if e != e', whatever the size of e or # e'. # (3) The result of logical operators does not have to be a # function with derivatives, as these derivatives are either 0 or # don't exist (i.e., the user should probably not rely on # derivatives for his code). # __eq__ is used in "if data in [None, ()]", for instance. It is # therefore important to be able to handle this case too, which is # taken care of when _force_aff_func_args(_eq_on_aff_funcs) # returns NotImplemented. __eq__ = _force_aff_func_args(_eq_on_aff_funcs) __ne__ = _force_aff_func_args(_ne_on_aff_funcs) __gt__ = _force_aff_func_args(_gt_on_aff_funcs) # __ge__ is not the opposite of __lt__ because these operators do # not always yield a boolean (for instance, 0 <= numpy.arange(10) # yields an array). __ge__ = _force_aff_func_args(_ge_on_aff_funcs) __lt__ = _force_aff_func_args(_lt_on_aff_funcs) __le__ = _force_aff_func_args(_le_on_aff_funcs) ######################################## # Uncertainties handling: def error_components(self): """ Individual components of the standard deviation of the affine function (in absolute value), returned as a dictionary with Variable objects as keys. This method assumes that the derivatives contained in the object take scalar values (and are not a tuple, like what math.frexp() returns, for instance). """ # Calculation of the variance: error_components = {} for (variable, derivative) in self.derivatives.items(): # Individual standard error due to variable: error_components[variable] = abs(derivative*variable._std_dev) return error_components def std_dev(self): """ Standard deviation of the affine function. This method assumes that the function returns scalar results. This returned standard deviation depends on the current standard deviations [std_dev()] of the variables (Variable objects) involved. """ #! It would be possible to not allow the user to update the #std dev of Variable objects, in which case AffineScalarFunc #objects could have a pre-calculated or, better, cached #std_dev value (in fact, many intermediate AffineScalarFunc do #not need to have their std_dev calculated: only the final #AffineScalarFunc returned to the user does). return sqrt(sum( delta**2 for delta in self.error_components().values())) def _general_representation(self, to_string): """ Uses the to_string() conversion function on both the nominal value and the standard deviation, and returns a string that describes them. to_string() is typically repr() or str(). """ (nominal_value, std_dev) = (self._nominal_value, self.std_dev()) # String representation: # Not putting spaces around "+/-" helps with arrays of # Variable, as each value with an uncertainty is a # block of signs (otherwise, the standard deviation can be # mistaken for another element of the array). return ("%s+/-%s" % (to_string(nominal_value), to_string(std_dev)) if std_dev else to_string(nominal_value)) def __repr__(self): return self._general_representation(repr) def __str__(self): return self._general_representation(str) def std_score(self, value): """ Returns 'value' - nominal value, in units of the standard deviation. Raises a ValueError exception if the standard deviation is zero. """ try: # The ._nominal_value is a float: there is no integer division, # here: return (value - self._nominal_value) / self.std_dev() except ZeroDivisionError: raise ValueError("The standard deviation is zero:" " undefined result.") def __deepcopy__(self, memo): """ Hook for the standard copy module. The returned AffineScalarFunc is a completely fresh copy, which is fully independent of any variable defined so far. New variables are specially created for the returned AffineScalarFunc object. """ return AffineScalarFunc( self._nominal_value, dict((copy.deepcopy(var), deriv) for (var, deriv) in self.derivatives.items())) def __getstate__(self): """ Hook for the pickle module. """ obj_slot_values = dict((k, getattr(self, k)) for k in # self.__slots__ would not work when # self is an instance of a subclass: AffineScalarFunc.__slots__) return obj_slot_values def __setstate__(self, data_dict): """ Hook for the pickle module. """ for (name, value) in data_dict.items(): setattr(self, name, value) # Nicer name, for users: isinstance(ufloat(...), UFloat) is True: UFloat = AffineScalarFunc def get_ops_with_reflection(): """ Returns operators with a reflection, along with their derivatives (for float operands). """ # Operators with a reflection: # We do not include divmod(). This operator could be included, by # allowing its result (a tuple) to be differentiated, in # derivative_value(). However, a similar result can be achieved # by the user by calculating separately the division and the # result. # {operator(x, y): (derivative wrt x, derivative wrt y)}: # Note that unknown partial derivatives can be numerically # calculated by expressing them as something like # "partial_derivative(float.__...__, 1)(x, y)": # String expressions are used, so that reversed operators are easy # to code, and execute relatively efficiently: derivatives_list = { 'add': ("1.", "1."), # 'div' is the '/' operator when __future__.division is not in # effect. Since '/' is applied to # AffineScalarFunc._nominal_value numbers, it is applied on # floats, and is therefore the "usual" mathematical division. 'div': ("1/y", "-x/y**2"), 'floordiv': ("0.", "0."), # Non exact: there is a discontinuities # The derivative wrt the 2nd arguments is something like (..., x//y), # but it is calculated numerically, for convenience: 'mod': ("1.", "partial_derivative(float.__mod__, 1)(x, y)"), 'mul': ("y", "x"), 'pow': ("y*x**(y-1)", "log(x)*x**y"), 'sub': ("1.", "-1."), 'truediv': ("1/y", "-x/y**2") } # Conversion to Python functions: ops_with_reflection = {} for (op, derivatives) in derivatives_list.items(): ops_with_reflection[op] = [ eval("lambda x, y: %s" % expr) for expr in derivatives ] ops_with_reflection["r"+op] = [ eval("lambda y, x: %s" % expr) for expr in reversed(derivatives)] return ops_with_reflection # Operators that have a reflection, along with their derivatives: _ops_with_reflection = get_ops_with_reflection() # Some effectively modified operators (for the automated tests): _modified_operators = [] _modified_ops_with_reflection = [] def add_operators_to_AffineScalarFunc(): """ Adds many operators (__add__, etc.) to the AffineScalarFunc class. """ ######################################## #! Derivatives are set to return floats. For one thing, # uncertainties generally involve floats, as they are based on # small variations of the parameters. It is also better to # protect the user from unexpected integer result that behave # badly with the division. ## Operators that return a numerical value: # Single-argument operators that should be adapted from floats to # AffineScalarFunc objects, associated to their derivative: simple_numerical_operators_derivatives = { 'abs': lambda x: 1. if x>=0 else -1., 'neg': lambda x: -1., 'pos': lambda x: 1., 'trunc': lambda x: 0. } for (op, derivative) in ( simple_numerical_operators_derivatives.items()): attribute_name = "__%s__" % op # float objects don't exactly have the same attributes between # different versions of Python (for instance, __trunc__ was # introduced with Python 2.6): try: setattr(AffineScalarFunc, attribute_name, wrap(getattr(float, attribute_name), [derivative])) except AttributeError: pass else: _modified_operators.append(op) ######################################## # Reversed versions (useful for float*AffineScalarFunc, for instance): for (op, derivatives) in _ops_with_reflection.items(): attribute_name = '__%s__' % op # float objects don't exactly have the same attributes between # different versions of Python (for instance, __div__ and # __rdiv__ were removed, in Python 3): try: setattr(AffineScalarFunc, attribute_name, wrap(getattr(float, attribute_name), derivatives)) except AttributeError: pass else: _modified_ops_with_reflection.append(op) ######################################## # Conversions to pure numbers are meaningless. Note that the # behavior of float(1j) is similar. for coercion_type in ('complex', 'int', 'long', 'float'): def raise_error(self): raise TypeError("can't convert an affine function (%s)" ' to %s; use x.nominal_value' # In case AffineScalarFunc is sub-classed: % (self.__class__, coercion_type)) setattr(AffineScalarFunc, '__%s__' % coercion_type, raise_error) add_operators_to_AffineScalarFunc() # Actual addition of class attributes class Variable(AffineScalarFunc): """ Representation of a float-like scalar random variable, along with its uncertainty. Objects are meant to represent variables that are independent from each other (correlations are handled through the AffineScalarFunc class). """ # To save memory in large arrays: __slots__ = ('_std_dev', 'tag') def __init__(self, value, std_dev, tag=None): """ The nominal value and the standard deviation of the variable are set. These values must be scalars. 'tag' is a tag that the user can associate to the variable. This is useful for tracing variables. The meaning of the nominal value is described in the main module documentation. """ #! The value, std_dev, and tag are assumed by __copy__() not to # be copied. Either this should be guaranteed here, or __copy__ # should be updated. # Only float-like values are handled. One reason is that the # division operator on integers would not produce a # differentiable functions: for instance, Variable(3, 0.1)/2 # has a nominal value of 3/2 = 1, but a "shifted" value # of 3.1/2 = 1.55. value = float(value) # If the variable changes by dx, then the value of the affine # function that gives its value changes by 1*dx: # ! Memory cycles are created. However, they are garbage # collected, if possible. Using a weakref.WeakKeyDictionary # takes much more memory. Thus, this implementation chooses # more cycles and a smaller memory footprint instead of no # cycles and a larger memory footprint. # ! Using AffineScalarFunc instead of super() results only in # a 3 % speed loss (Python 2.6, Mac OS X): super(Variable, self).__init__(value, {self: 1.}) # We force the error to be float-like. Since it is considered # as a Gaussian standard deviation, it is semantically # positive (even though there would be no problem defining it # as a sigma, where sigma can be negative and still define a # Gaussian): assert std_dev >= 0, "the error must be a positive number" # Since AffineScalarFunc.std_dev is a property, we cannot do # "self.std_dev = ...": self._std_dev = std_dev self.tag = tag # Standard deviations can be modified (this is a feature). # AffineScalarFunc objects that depend on the Variable have their # std_dev() automatically modified (recalculated with the new # std_dev of their Variables): def set_std_dev(self, value): """ Updates the standard deviation of the variable to a new value. """ # A zero variance is accepted. Thus, it is possible to # conveniently use infinitely precise variables, for instance # to study special cases. self._std_dev = value # The following method is overridden so that we can represent the tag: def _general_representation(self, to_string): """ Uses the to_string() conversion function on both the nominal value and standard deviation and returns a string that describes the number. to_string() is typically repr() or str(). """ num_repr = super(Variable, self)._general_representation(to_string) # Optional tag: only full representations (to_string == repr) # contain the tag, as the tag is required in order to recreate # the variable. Outputting the tag for regular string ("print # x") would be too heavy and produce an unusual representation # of a number with uncertainty. return (num_repr if ((self.tag is None) or (to_string != repr)) else "< %s = %s >" % (self.tag, num_repr)) def __hash__(self): # All Variable objects are by definition independent # variables, so they never compare equal; therefore, their # id() are therefore allowed to differ # (http://docs.python.org/reference/datamodel.html#object.__hash__): return id(self) def __copy__(self): """ Hook for the standard copy module. """ # This copy implicitly takes care of the reference of the # variable to itself (in self.derivatives): the new Variable # object points to itself, not to the original Variable. # Reference: http://www.doughellmann.com/PyMOTW/copy/index.html #! The following assumes that the arguments to Variable are # *not* copied upon construction, since __copy__ is not supposed # to copy "inside" information: return Variable(self.nominal_value, self.std_dev(), self.tag) def __deepcopy__(self, memo): """ Hook for the standard copy module. A new variable is created. """ # This deep copy implicitly takes care of the reference of the # variable to itself (in self.derivatives): the new Variable # object points to itself, not to the original Variable. # Reference: http://www.doughellmann.com/PyMOTW/copy/index.html return self.__copy__() def __getstate__(self): """ Hook for the standard pickle module. """ obj_slot_values = dict((k, getattr(self, k)) for k in self.__slots__) obj_slot_values.update(AffineScalarFunc.__getstate__(self)) # Conversion to a usual dictionary: return obj_slot_values def __setstate__(self, data_dict): """ Hook for the standard pickle module. """ for (name, value) in data_dict.items(): setattr(self, name, value) ############################################################################### # Utilities def nominal_value(x): """ Returns the nominal value of x if it is a quantity with uncertainty (i.e., an AffineScalarFunc object); otherwise, returns x unchanged. This utility function is useful for transforming a series of numbers, when only some of them generally carry an uncertainty. """ return x.nominal_value if isinstance(x, AffineScalarFunc) else x def std_dev(x): """ Returns the standard deviation of x if it is a quantity with uncertainty (i.e., an AffineScalarFunc object); otherwise, returns the float 0. This utility function is useful for transforming a series of numbers, when only some of them generally carry an uncertainty. """ return x.std_dev() if isinstance(x, AffineScalarFunc) else 0. def covariance_matrix(nums_with_uncert): """ Returns a matrix that contains the covariances between the given sequence of numbers with uncertainties (AffineScalarFunc objects). The resulting matrix implicitly depends on their ordering in 'nums_with_uncert'. The covariances are floats (never int objects). The returned covariance matrix is the exact linear approximation result, if the nominal values of the numbers with uncertainties and of their variables are their mean. Otherwise, the returned covariance matrix should be close to its linear approximation value. The returned matrix is a list of lists. """ # See PSI.411 in EOL's notes. covariance_matrix = [] for (i1, expr1) in enumerate(nums_with_uncert): derivatives1 = expr1.derivatives # Optimization vars1 = set(derivatives1) coefs_expr1 = [] for (i2, expr2) in enumerate(nums_with_uncert[:i1+1]): derivatives2 = expr2.derivatives # Optimization coef = 0. for var in vars1.intersection(derivatives2): # var is a variable common to both numbers with # uncertainties: coef += (derivatives1[var]*derivatives2[var]*var._std_dev**2) coefs_expr1.append(coef) covariance_matrix.append(coefs_expr1) # We symmetrize the matrix: for (i, covariance_coefs) in enumerate(covariance_matrix): covariance_coefs.extend(covariance_matrix[j][i] for j in range(i+1, len(covariance_matrix))) return covariance_matrix try: import numpy except ImportError: pass else: def correlation_matrix(nums_with_uncert): ''' Returns the correlation matrix of the given sequence of numbers with uncertainties, as a NumPy array of floats. ''' cov_mat = numpy.array(covariance_matrix(nums_with_uncert)) std_devs = numpy.sqrt(cov_mat.diagonal()) return cov_mat/std_devs/std_devs[numpy.newaxis].T __all__.append('correlation_matrix') ############################################################################### # Parsing of values with uncertainties: POSITIVE_DECIMAL_UNSIGNED = r'(\d+)(\.\d*)?' # Regexp for a number with uncertainty (e.g., "-1.234(2)e-6"), where the # uncertainty is optional (in which case the uncertainty is implicit): NUMBER_WITH_UNCERT_RE_STR = ''' ([+-])? # Sign %s # Main number (?:\(%s\))? # Optional uncertainty ([eE][+-]?\d+)? # Optional exponent ''' % (POSITIVE_DECIMAL_UNSIGNED, POSITIVE_DECIMAL_UNSIGNED) NUMBER_WITH_UNCERT_RE = re.compile( "^%s$" % NUMBER_WITH_UNCERT_RE_STR, re.VERBOSE) def parse_error_in_parentheses(representation): """ Returns (value, error) from a string representing a number with uncertainty like 12.34(5), 12.34(142), 12.5(3.4) or 12.3(4.2)e3. If no parenthesis is given, an uncertainty of one on the last digit is assumed. Raises ValueError if the string cannot be parsed. """ match = NUMBER_WITH_UNCERT_RE.search(representation) if match: # The 'main' part is the nominal value, with 'int'eger part, and # 'dec'imal part. The 'uncert'ainty is similarly broken into its # integer and decimal parts. (sign, main_int, main_dec, uncert_int, uncert_dec, exponent) = match.groups() else: raise ValueError("Unparsable number representation: '%s'." " Was expecting a string of the form 1.23(4)" " or 1.234" % representation) # The value of the number is its nominal value: value = float(''.join((sign or '', main_int, main_dec or '.0', exponent or ''))) if uncert_int is None: # No uncertainty was found: an uncertainty of 1 on the last # digit is assumed: uncert_int = '1' # Do we have a fully explicit uncertainty? if uncert_dec is not None: uncert = float("%s%s" % (uncert_int, uncert_dec or '')) else: # uncert_int represents an uncertainty on the last digits: # The number of digits after the period defines the power of # 10 than must be applied to the provided uncertainty: num_digits_after_period = (0 if main_dec is None else len(main_dec)-1) uncert = int(uncert_int)/10**num_digits_after_period # We apply the exponent to the uncertainty as well: uncert *= float("1%s" % (exponent or '')) return (value, uncert) # The following function is not exposed because it can in effect be # obtained by doing x = ufloat(representation) and # x.nominal_value and x.std_dev(): def str_to_number_with_uncert(representation): """ Given a string that represents a number with uncertainty, returns the nominal value and the uncertainty. The string can be of the form: - 124.5+/-0.15 - 124.50(15) - 124.50(123) - 124.5 When no numerical error is given, an uncertainty of 1 on the last digit is implied. Raises ValueError if the string cannot be parsed. """ try: # Simple form 1234.45+/-1.2: (value, uncert) = representation.split('+/-') except ValueError: # Form with parentheses or no uncertainty: parsed_value = parse_error_in_parentheses(representation) else: try: parsed_value = (float(value), float(uncert)) except ValueError: raise ValueError('Cannot parse %s: was expecting a number' ' like 1.23+/-0.1' % representation) return parsed_value def ufloat(representation, tag=None): """ Returns a random variable (Variable object). Converts the representation of a number into a number with uncertainty (a random variable, defined by a nominal value and a standard deviation). The representation can be a (value, standard deviation) sequence, or a string. Strings of the form '12.345+/-0.015', '12.345(15)', or '12.3' are recognized (see full list below). In the last case, an uncertainty of +/-1 is assigned to the last digit. 'tag' is an optional string tag for the variable. Variables don't have to have distinct tags. Tags are useful for tracing what values (and errors) enter in a given result (through the error_components() method). Examples of valid string representations: -1.23(3.4) -1.34(5) 1(6) 3(4.2) -9(2) 1234567(1.2) 12.345(15) -12.3456(78)e-6 12.3(0.4)e-5 0.29 31. -31. 31 -3.1e10 169.0(7) 169.1(15) """ # This function is somewhat optimized so as to help with the # creation of lots of Variable objects (through unumpy.uarray, for # instance). # representations is "normalized" so as to be a valid sequence of # 2 arguments for Variable(). #! Accepting strings and any kind of sequence slows down the code # by about 5 %. On the other hand, massive initializations of # numbers with uncertainties are likely to be performed with # unumpy.uarray, which does not support parsing from strings and # thus does not have any overhead. #! Different, in Python 3: if isinstance(representation, six.string_types): representation = str_to_number_with_uncert(representation) #! The tag is forced to be a string, so that the user does not # create a Variable(2.5, 0.5) in order to represent 2.5 +/- 0.5. # Forcing 'tag' to be a string prevents numerical uncertainties # from being considered as tags, here: if tag is not None: #! 'unicode' is removed in Python3: assert isinstance(tag, six.string_types), "The tag can only be a string." #! The special ** syntax is for Python 2.5 and before (Python 2.6+ # understands tag=tag): return Variable(*representation, **{'tag': tag}) lmfit-0.9.7/lmfit/uncertainties/umath.py0000644000076500000240000003002513066042256021236 0ustar Newvillestaff00000000000000''' Mathematical operations that generalize many operations from the standard math module so that they also work on numbers with uncertainties. Examples: from umath import sin # Manipulation of numbers with uncertainties: x = uncertainties.ufloat((3, 0.1)) print sin(x) # prints 0.141120008...+/-0.098999... # The umath functions also work on regular Python floats: print sin(3) # prints 0.141120008... This is a Python float. Importing all the functions from this module into the global namespace is possible. This is encouraged when using a Python shell as a calculator. Example: import uncertainties from uncertainties.umath import * # Imports tan(), etc. x = uncertainties.ufloat((3, 0.1)) print tan(x) # tan() is the uncertainties.umath.tan function The numbers with uncertainties handled by this module are objects from the uncertainties module, from either the Variable or the AffineScalarFunc class. (c) 2009-2013 by Eric O. LEBIGOT (EOL) . Please send feature requests, bug reports, or feedback to this address. This software is released under a dual license. (1) The BSD license. (2) Any other license, as long as it is obtained from the original author.''' from __future__ import division # Many analytical derivatives depend on this # Standard modules import functools import itertools import math import sys # Local modules from __init__ import (AffineScalarFunc, __author__, set_doc, to_affine_scalar, wrap) ############################################################################### # We wrap the functions from the math module so that they keep track of # uncertainties by returning a AffineScalarFunc object. # Some functions from the math module cannot be adapted in a standard # way so to work with AffineScalarFunc objects (either as their result # or as their arguments): # (1) Some functions return a result of a type whose value and # variations (uncertainties) cannot be represented by AffineScalarFunc # (e.g., math.frexp, which returns a tuple). The exception raised # when not wrapping them with wrap() is more obvious than the # one obtained when wrapping them (in fact, the wrapped functions # attempts operations that are not supported, such as calculation a # subtraction on a result of type tuple). # (2) Some functions don't take continuous scalar arguments (which can # be varied during differentiation): math.fsum, math.factorial... # Such functions can either be: # - wrapped in a special way. # - excluded from standard wrapping by adding their name to # no_std_wrapping # Math functions that have a standard interface: they take # one or more float arguments, and return a scalar: many_scalars_to_scalar_funcs = [] # Some functions require a specific treatment and must therefore be # excluded from standard wrapping. Functions # no_std_wrapping = ['modf', 'frexp', 'ldexp', 'fsum', 'factorial'] # Functions with numerical derivatives: num_deriv_funcs = ['fmod', 'gamma', 'isinf', 'isnan', 'lgamma', 'trunc'] # Functions that do not belong in many_scalars_to_scalar_funcs, but # that have a version that handles uncertainties: non_std_wrapped_funcs = [] # Function that copies the relevant attributes from generalized # functions from the math module: wraps = functools.partial(functools.update_wrapper, assigned=('__doc__', '__name__')) ######################################## # Wrapping of math functions: # Fixed formulas for the derivatives of some functions from the math # module (some functions might not be present in all version of # Python). Singular points are not taken into account. The user # should never give "large" uncertainties: problems could only appear # if this assumption does not hold. # Functions not mentioned in _fixed_derivatives have their derivatives # calculated numerically. # Functions that have singularities (possibly at infinity) benefit # from analytical calculations (instead of the default numerical # calculation) because their derivatives generally change very fast. # Even slowly varying functions (e.g., abs()) yield more precise # results when differentiated analytically, because of the loss of # precision in numerical calculations. #def log_1arg_der(x): # """ # Derivative of log(x) (1-argument form). # """ # return 1/x def log_der0(*args): """ Derivative of math.log() with respect to its first argument. Works whether 1 or 2 arguments are given. """ if len(args) == 1: return 1/args[0] else: return 1/args[0]/math.log(args[1]) # 2-argument form # The following version goes about as fast: ## A 'try' is used for the most common case because it is fast when no ## exception is raised: #try: # return log_1arg_der(*args) # Argument number check #except TypeError: # return 1/args[0]/math.log(args[1]) # 2-argument form _erf_coef = 2/math.sqrt(math.pi) # Optimization for erf() fixed_derivatives = { # In alphabetical order, here: 'acos': [lambda x: -1/math.sqrt(1-x**2)], 'acosh': [lambda x: 1/math.sqrt(x**2-1)], 'asin': [lambda x: 1/math.sqrt(1-x**2)], 'asinh': [lambda x: 1/math.sqrt(1+x**2)], 'atan': [lambda x: 1/(1+x**2)], 'atan2': [lambda y, x: x/(x**2+y**2), # Correct for x == 0 lambda y, x: -y/(x**2+y**2)], # Correct for x == 0 'atanh': [lambda x: 1/(1-x**2)], 'ceil': [lambda x: 0], 'copysign': [lambda x, y: (1 if x >= 0 else -1) * math.copysign(1, y), lambda x, y: 0], 'cos': [lambda x: -math.sin(x)], 'cosh': [math.sinh], 'degrees': [lambda x: math.degrees(1)], 'erf': [lambda x: math.exp(-x**2)*_erf_coef], 'erfc': [lambda x: -math.exp(-x**2)*_erf_coef], 'exp': [math.exp], 'expm1': [math.exp], 'fabs': [lambda x: 1 if x >= 0 else -1], 'floor': [lambda x: 0], 'hypot': [lambda x, y: x/math.hypot(x, y), lambda x, y: y/math.hypot(x, y)], 'log': [log_der0, lambda x, y: -math.log(x, y)/y/math.log(y)], 'log10': [lambda x: 1/x/math.log(10)], 'log1p': [lambda x: 1/(1+x)], 'pow': [lambda x, y: y*math.pow(x, y-1), lambda x, y: math.log(x) * math.pow(x, y)], 'radians': [lambda x: math.radians(1)], 'sin': [math.cos], 'sinh': [math.cosh], 'sqrt': [lambda x: 0.5/math.sqrt(x)], 'tan': [lambda x: 1+math.tan(x)**2], 'tanh': [lambda x: 1-math.tanh(x)**2] } # Many built-in functions in the math module are wrapped with a # version which is uncertainty aware: this_module = sys.modules[__name__] # for (name, attr) in vars(math).items(): for name in dir(math): if name in fixed_derivatives: # Priority to functions in fixed_derivatives derivatives = fixed_derivatives[name] elif name in num_deriv_funcs: # Functions whose derivatives are calculated numerically by # this module fall here (isinf, fmod,...): derivatives = None # Means: numerical calculation required else: continue # 'name' not wrapped by this module (__doc__, e, etc.) func = getattr(math, name) setattr(this_module, name, wraps(wrap(func, derivatives), func)) many_scalars_to_scalar_funcs.append(name) ############################################################################### ######################################## # Special cases: some of the functions from no_std_wrapping: ########## # The math.factorial function is not converted to an uncertainty-aware # function, because it does not handle non-integer arguments: it does # not make sense to give it an argument with a numerical error # (whereas this would be relevant for the gamma function). ########## # fsum takes a single argument, which cannot be differentiated. # However, each of the arguments inside this single list can # be a variable. We handle this in a specific way: if sys.version_info[:2] >= (2, 6): # For drop-in compatibility with the math module: factorial = math.factorial non_std_wrapped_funcs.append('factorial') # We wrap math.fsum original_func = math.fsum # For optimization purposes # The function below exists so that temporary variables do not # pollute the module namespace: def wrapped_fsum(): """ Returns an uncertainty-aware version of math.fsum, which must be contained in _original_func. """ # The fsum function is flattened, in order to use the # wrap() wrapper: flat_fsum = lambda *args: original_func(args) flat_fsum_wrap = wrap( flat_fsum, itertools.repeat(lambda *args: 1)) return wraps(lambda arg_list: flat_fsum_wrap(*arg_list), original_func) fsum = wrapped_fsum() non_std_wrapped_funcs.append('fsum') @set_doc(math.modf.__doc__) def modf(x): """ Version of modf that works for numbers with uncertainty, and also for regular numbers. """ # The code below is inspired by wrap(). It is # simpler because only 1 argument is given, and there is no # delegation to other functions involved (as for __mul__, etc.). aff_func = to_affine_scalar(x) (frac_part, int_part) = math.modf(aff_func.nominal_value) if aff_func.derivatives: # The derivative of the fractional part is simply 1: the # derivatives of modf(x)[0] are the derivatives of x: return (AffineScalarFunc(frac_part, aff_func.derivatives), int_part) else: # This function was not called with an AffineScalarFunc # argument: there is no need to return numbers with uncertainties: return (frac_part, int_part) many_scalars_to_scalar_funcs.append('modf') @set_doc(math.ldexp.__doc__) def ldexp(x, y): # The code below is inspired by wrap(). It is # simpler because only 1 argument is given, and there is no # delegation to other functions involved (as for __mul__, etc.). # Another approach would be to add an additional argument to # wrap() so that some arguments are automatically # considered as constants. aff_func = to_affine_scalar(x) # y must be an integer, for math.ldexp if aff_func.derivatives: factor = 2**y return AffineScalarFunc( math.ldexp(aff_func.nominal_value, y), # Chain rule: dict((var, factor*deriv) for (var, deriv) in aff_func.derivatives.iteritems())) else: # This function was not called with an AffineScalarFunc # argument: there is no need to return numbers with uncertainties: # aff_func.nominal_value is not passed instead of x, because # we do not have to care about the type of the return value of # math.ldexp, this way (aff_func.nominal_value might be the # value of x coerced to a difference type [int->float, for # instance]): return math.ldexp(x, y) many_scalars_to_scalar_funcs.append('ldexp') @set_doc(math.frexp.__doc__) def frexp(x): """ Version of frexp that works for numbers with uncertainty, and also for regular numbers. """ # The code below is inspired by wrap(). It is # simpler because only 1 argument is given, and there is no # delegation to other functions involved (as for __mul__, etc.). aff_func = to_affine_scalar(x) if aff_func.derivatives: result = math.frexp(aff_func.nominal_value) # With frexp(x) = (m, e), dm/dx = 1/(2**e): factor = 1/(2**result[1]) return ( AffineScalarFunc( result[0], # Chain rule: dict((var, factor*deriv) for (var, deriv) in aff_func.derivatives.iteritems())), # The exponent is an integer and is supposed to be # continuous (small errors): result[1]) else: # This function was not called with an AffineScalarFunc # argument: there is no need to return numbers with uncertainties: return math.frexp(x) non_std_wrapped_funcs.append('frexp') ############################################################################### # Exported functions: __all__ = many_scalars_to_scalar_funcs + non_std_wrapped_funcs lmfit-0.9.7/lmfit.egg-info/0000755000076500000240000000000013114357470016364 5ustar Newvillestaff00000000000000lmfit-0.9.7/lmfit.egg-info/dependency_links.txt0000644000076500000240000000000113114357464022435 0ustar Newvillestaff00000000000000 lmfit-0.9.7/lmfit.egg-info/PKG-INFO0000644000076500000240000000327113114357464017467 0ustar Newvillestaff00000000000000Metadata-Version: 1.1 Name: lmfit Version: 0.9.7 Summary: Least-Squares Minimization with Bounds and Constraints Home-page: http://lmfit.github.io/lmfit-py/ Author: LMFit Development Team Author-email: matt.newville@gmail.com License: BSD Download-URL: http://lmfit.github.io//lmfit-py/ Description: A library for least-squares minimization and data fitting in Python. Built on top of scipy.optimize, lmfit provides a Parameter object which can be set as fixed or free, can have upper and/or lower bounds, or can be written in terms of algebraic constraints of other Parameters. The user writes a function to be minimized as a function of these Parameters, and the scipy.optimize methods are used to find the optimal values for the Parameters. The Levenberg-Marquardt (leastsq) is the default minimization algorithm, and provides estimated standard errors and correlations between varied Parameters. Other minimization methods, including Nelder-Mead's downhill simplex, Powell's method, BFGS, Sequential Least Squares, and others are also supported. Bounds and contraints can be placed on Parameters for all of these methods. In addition, methods for explicitly calculating confidence intervals are provided for exploring minmization problems where the approximation of estimating Parameter uncertainties from the covariance matrix is questionable. Platform: Windows Platform: Linux Platform: Mac OS X Classifier: Intended Audience :: Science/Research Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering lmfit-0.9.7/lmfit.egg-info/requires.txt0000644000076500000240000000002013114357464020757 0ustar Newvillestaff00000000000000numpy scipy six lmfit-0.9.7/lmfit.egg-info/SOURCES.txt0000644000076500000240000000701413114357470020252 0ustar Newvillestaff00000000000000INSTALL LICENSE MANIFEST.in README.rst THANKS.txt publish_docs.sh requirements.txt setup.cfg setup.py versioneer.py NIST_STRD/Bennett5.dat NIST_STRD/BoxBOD.dat NIST_STRD/Chwirut1.dat NIST_STRD/Chwirut2.dat NIST_STRD/DanWood.dat NIST_STRD/ENSO.dat NIST_STRD/Eckerle4.dat NIST_STRD/Gauss1.dat NIST_STRD/Gauss2.dat NIST_STRD/Gauss3.dat NIST_STRD/Hahn1.dat NIST_STRD/Kirby2.dat NIST_STRD/Lanczos1.dat NIST_STRD/Lanczos2.dat NIST_STRD/Lanczos3.dat NIST_STRD/MGH09.dat NIST_STRD/MGH10.dat NIST_STRD/MGH17.dat NIST_STRD/Misra1a.dat NIST_STRD/Misra1b.dat NIST_STRD/Misra1c.dat NIST_STRD/Misra1d.dat NIST_STRD/Nelson.dat NIST_STRD/Rat42.dat NIST_STRD/Rat43.dat NIST_STRD/Roszman1.dat NIST_STRD/Thurber.dat doc/.DS_Store doc/Makefile doc/bounds.rst doc/builtin_models.rst doc/conf.py doc/confidence.rst doc/constraints.rst doc/contents.rst doc/extensions.py doc/extensions.pyc doc/faq.rst doc/fitting.rst doc/index.rst doc/installation.rst doc/intro.rst doc/model.rst doc/parameters.rst doc/support.rst doc/test_ci2_result.png doc/whatsnew.rst doc/__pycache__/extensions.cpython-35.pyc doc/__pycache__/extensions.cpython-36.pyc doc/_images/conf_interval1.png doc/_images/conf_interval1a.png doc/_images/conf_interval2.png doc/_images/emcee_dbl_exp.png doc/_images/emcee_dbl_exp2.png doc/_images/emcee_triangle.png doc/_images/model_eval.png doc/_images/model_fit1.png doc/_images/model_fit2.png doc/_images/model_fit2a.png doc/_images/model_fit3a.png doc/_images/model_fit3b.png doc/_images/model_fit4.png doc/_images/models_doc1.png doc/_images/models_doc2.png doc/_images/models_nistgauss.png doc/_images/models_nistgauss2.png doc/_images/models_peak1.png doc/_images/models_peak2.png doc/_images/models_peak3.png doc/_images/models_peak4.png doc/_images/models_stepfit.png doc/_static/empty doc/_templates/indexsidebar.html doc/sphinx/apigen.py doc/sphinx/ext_mathjax.py doc/sphinx/ext_pngmath.py doc/sphinx/github.py doc/sphinx/numpydoc/__init__.py doc/sphinx/numpydoc/comment_eater.py doc/sphinx/numpydoc/compiler_unparse.py doc/sphinx/numpydoc/docscrape.py doc/sphinx/numpydoc/docscrape_sphinx.py doc/sphinx/numpydoc/numpydoc.py doc/sphinx/numpydoc/phantom_import.py doc/sphinx/numpydoc/plot_directive.py doc/sphinx/numpydoc/traitsdoc.py doc/sphinx/theme/lmfitdoc/layout.html doc/sphinx/theme/lmfitdoc/theme.conf doc/sphinx/theme/lmfitdoc/static/contents.png doc/sphinx/theme/lmfitdoc/static/lmfitdoc.css_t doc/sphinx/theme/lmfitdoc/static/navigation.png lmfit/__init__.py lmfit/_version.py lmfit/asteval.py lmfit/astutils.py lmfit/confidence.py lmfit/lineshapes.py lmfit/minimizer.py lmfit/model.py lmfit/models.py lmfit/parameter.py lmfit/printfuncs.py lmfit.egg-info/PKG-INFO lmfit.egg-info/SOURCES.txt lmfit.egg-info/dependency_links.txt lmfit.egg-info/requires.txt lmfit.egg-info/top_level.txt lmfit/ui/__init__.py lmfit/ui/basefitter.py lmfit/ui/ipy_fitter.py lmfit/uncertainties/__init__.py lmfit/uncertainties/umath.py tests/NISTModels.py tests/_test_ci.py tests/_test_make_paras_and_func.py tests/lmfit_testutils.py tests/test_1variable.py tests/test_NIST_Strd.py tests/test_algebraic_constraint.py tests/test_algebraic_constraint2.py tests/test_basicfit.py tests/test_bounded_jacobian.py tests/test_bounds.py tests/test_brute_method.py tests/test_confidence.py tests/test_copy_params.py tests/test_default_kws.py tests/test_itercb.py tests/test_least_squares.py tests/test_manypeaks_speed.py tests/test_minimizer.py tests/test_model.py tests/test_model_uncertainties.py tests/test_multidatasets.py tests/test_nose.py tests/test_parameters.py tests/test_params_set.py tests/test_stepmodel.pylmfit-0.9.7/lmfit.egg-info/top_level.txt0000644000076500000240000000000613114357464021115 0ustar Newvillestaff00000000000000lmfit lmfit-0.9.7/MANIFEST.in0000644000076500000240000000060013066042256015310 0ustar Newvillestaff00000000000000include README.txt INSTALL LICENSE MANIFEST.in PKG-INFO THANKS.txt include setup.py publish_docs.sh include requirements.txt exclude *.pyc core.* *~ *.pdf recursive-include lmfit *.py recursive-include tests *.py *.dat recursive-include NIST_STRD *.dat recursive-include doc * recursive-exclude doc/_build * recursive-exclude doc *.pdf include versioneer.py include lmfit/_version.py lmfit-0.9.7/NIST_STRD/0000755000076500000240000000000013114357470015170 5ustar Newvillestaff00000000000000lmfit-0.9.7/NIST_STRD/Bennett5.dat0000644000076500000240000001533213066042256017351 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Bennett5 (Bennett5.dat) File Format: ASCII Starting Values (lines 41 to 43) Certified Values (lines 41 to 48) Data (lines 61 to 214) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving superconductivity magnetization modeling. The response variable is magnetism, and the predictor variable is the log of time in minutes. Reference: Bennett, L., L. Swartzendruber, and H. Brown, NIST (1994). Superconductivity Magnetization Modeling. Data: 1 Response Variable (y = magnetism) 1 Predictor Variable (x = log[time]) 154 Observations Higher Level of Difficulty Observed Data Model: Miscellaneous Class 3 Parameters (b1 to b3) y = b1 * (b2+x)**(-1/b3) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = -2000 -1500 -2.5235058043E+03 2.9715175411E+02 b2 = 50 45 4.6736564644E+01 1.2448871856E+00 b3 = 0.8 0.85 9.3218483193E-01 2.0272299378E-02 Residual Sum of Squares: 5.2404744073E-04 Residual Standard Deviation: 1.8629312528E-03 Degrees of Freedom: 151 Number of Observations: 154 Data: y x -34.834702E0 7.447168E0 -34.393200E0 8.102586E0 -34.152901E0 8.452547E0 -33.979099E0 8.711278E0 -33.845901E0 8.916774E0 -33.732899E0 9.087155E0 -33.640301E0 9.232590E0 -33.559200E0 9.359535E0 -33.486801E0 9.472166E0 -33.423100E0 9.573384E0 -33.365101E0 9.665293E0 -33.313000E0 9.749461E0 -33.260899E0 9.827092E0 -33.217400E0 9.899128E0 -33.176899E0 9.966321E0 -33.139198E0 10.029280E0 -33.101601E0 10.088510E0 -33.066799E0 10.144430E0 -33.035000E0 10.197380E0 -33.003101E0 10.247670E0 -32.971298E0 10.295560E0 -32.942299E0 10.341250E0 -32.916302E0 10.384950E0 -32.890202E0 10.426820E0 -32.864101E0 10.467000E0 -32.841000E0 10.505640E0 -32.817799E0 10.542830E0 -32.797501E0 10.578690E0 -32.774300E0 10.613310E0 -32.757000E0 10.646780E0 -32.733799E0 10.679150E0 -32.716400E0 10.710520E0 -32.699100E0 10.740920E0 -32.678799E0 10.770440E0 -32.661400E0 10.799100E0 -32.644001E0 10.826970E0 -32.626701E0 10.854080E0 -32.612202E0 10.880470E0 -32.597698E0 10.906190E0 -32.583199E0 10.931260E0 -32.568699E0 10.955720E0 -32.554298E0 10.979590E0 -32.539799E0 11.002910E0 -32.525299E0 11.025700E0 -32.510799E0 11.047980E0 -32.499199E0 11.069770E0 -32.487598E0 11.091100E0 -32.473202E0 11.111980E0 -32.461601E0 11.132440E0 -32.435501E0 11.152480E0 -32.435501E0 11.172130E0 -32.426800E0 11.191410E0 -32.412300E0 11.210310E0 -32.400799E0 11.228870E0 -32.392101E0 11.247090E0 -32.380501E0 11.264980E0 -32.366001E0 11.282560E0 -32.357300E0 11.299840E0 -32.348598E0 11.316820E0 -32.339901E0 11.333520E0 -32.328400E0 11.349940E0 -32.319698E0 11.366100E0 -32.311001E0 11.382000E0 -32.299400E0 11.397660E0 -32.290699E0 11.413070E0 -32.282001E0 11.428240E0 -32.273300E0 11.443200E0 -32.264599E0 11.457930E0 -32.256001E0 11.472440E0 -32.247299E0 11.486750E0 -32.238602E0 11.500860E0 -32.229900E0 11.514770E0 -32.224098E0 11.528490E0 -32.215401E0 11.542020E0 -32.203800E0 11.555380E0 -32.198002E0 11.568550E0 -32.189400E0 11.581560E0 -32.183601E0 11.594420E0 -32.174900E0 11.607121E0 -32.169102E0 11.619640E0 -32.163300E0 11.632000E0 -32.154598E0 11.644210E0 -32.145901E0 11.656280E0 -32.140099E0 11.668200E0 -32.131401E0 11.679980E0 -32.125599E0 11.691620E0 -32.119801E0 11.703130E0 -32.111198E0 11.714510E0 -32.105400E0 11.725760E0 -32.096699E0 11.736880E0 -32.090900E0 11.747890E0 -32.088001E0 11.758780E0 -32.079300E0 11.769550E0 -32.073502E0 11.780200E0 -32.067699E0 11.790730E0 -32.061901E0 11.801160E0 -32.056099E0 11.811480E0 -32.050301E0 11.821700E0 -32.044498E0 11.831810E0 -32.038799E0 11.841820E0 -32.033001E0 11.851730E0 -32.027199E0 11.861550E0 -32.024300E0 11.871270E0 -32.018501E0 11.880890E0 -32.012699E0 11.890420E0 -32.004002E0 11.899870E0 -32.001099E0 11.909220E0 -31.995300E0 11.918490E0 -31.989500E0 11.927680E0 -31.983700E0 11.936780E0 -31.977900E0 11.945790E0 -31.972099E0 11.954730E0 -31.969299E0 11.963590E0 -31.963501E0 11.972370E0 -31.957701E0 11.981070E0 -31.951900E0 11.989700E0 -31.946100E0 11.998260E0 -31.940300E0 12.006740E0 -31.937401E0 12.015150E0 -31.931601E0 12.023490E0 -31.925800E0 12.031760E0 -31.922899E0 12.039970E0 -31.917101E0 12.048100E0 -31.911301E0 12.056170E0 -31.908400E0 12.064180E0 -31.902599E0 12.072120E0 -31.896900E0 12.080010E0 -31.893999E0 12.087820E0 -31.888201E0 12.095580E0 -31.885300E0 12.103280E0 -31.882401E0 12.110920E0 -31.876600E0 12.118500E0 -31.873699E0 12.126030E0 -31.867901E0 12.133500E0 -31.862101E0 12.140910E0 -31.859200E0 12.148270E0 -31.856300E0 12.155570E0 -31.850500E0 12.162830E0 -31.844700E0 12.170030E0 -31.841801E0 12.177170E0 -31.838900E0 12.184270E0 -31.833099E0 12.191320E0 -31.830200E0 12.198320E0 -31.827299E0 12.205270E0 -31.821600E0 12.212170E0 -31.818701E0 12.219030E0 -31.812901E0 12.225840E0 -31.809999E0 12.232600E0 -31.807100E0 12.239320E0 -31.801300E0 12.245990E0 -31.798401E0 12.252620E0 -31.795500E0 12.259200E0 -31.789700E0 12.265750E0 -31.786800E0 12.272240E0 lmfit-0.9.7/NIST_STRD/BoxBOD.dat0000644000076500000240000000326613066042256016745 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: BoxBOD (BoxBOD.dat) File Format: ASCII Starting Values (lines 41 to 42) Certified Values (lines 41 to 47) Data (lines 61 to 66) Procedure: Nonlinear Least Squares Regression Description: These data are described in detail in Box, Hunter and Hunter (1978). The response variable is biochemical oxygen demand (BOD) in mg/l, and the predictor variable is incubation time in days. Reference: Box, G. P., W. G. Hunter, and J. S. Hunter (1978). Statistics for Experimenters. New York, NY: Wiley, pp. 483-487. Data: 1 Response (y = biochemical oxygen demand) 1 Predictor (x = incubation time) 6 Observations Higher Level of Difficulty Observed Data Model: Exponential Class 2 Parameters (b1 and b2) y = b1*(1-exp[-b2*x]) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 1 100 2.1380940889E+02 1.2354515176E+01 b2 = 1 0.75 5.4723748542E-01 1.0455993237E-01 Residual Sum of Squares: 1.1680088766E+03 Residual Standard Deviation: 1.7088072423E+01 Degrees of Freedom: 4 Number of Observations: 6 Data: y x 109 1 149 2 149 3 191 5 213 7 224 10 lmfit-0.9.7/NIST_STRD/Chwirut1.dat0000644000076500000240000001661113066042256017374 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Chwirut1 (Chwirut1.dat) File Format: ASCII Starting Values (lines 41 to 43) Certified Values (lines 41 to 48) Data (lines 61 to 274) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving ultrasonic calibration. The response variable is ultrasonic response, and the predictor variable is metal distance. Reference: Chwirut, D., NIST (197?). Ultrasonic Reference Block Study. Data: 1 Response Variable (y = ultrasonic response) 1 Predictor Variable (x = metal distance) 214 Observations Lower Level of Difficulty Observed Data Model: Exponential Class 3 Parameters (b1 to b3) y = exp[-b1*x]/(b2+b3*x) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 0.1 0.15 1.9027818370E-01 2.1938557035E-02 b2 = 0.01 0.008 6.1314004477E-03 3.4500025051E-04 b3 = 0.02 0.010 1.0530908399E-02 7.9281847748E-04 Residual Sum of Squares: 2.3844771393E+03 Residual Standard Deviation: 3.3616721320E+00 Degrees of Freedom: 211 Number of Observations: 214 Data: y x 92.9000E0 0.5000E0 78.7000E0 0.6250E0 64.2000E0 0.7500E0 64.9000E0 0.8750E0 57.1000E0 1.0000E0 43.3000E0 1.2500E0 31.1000E0 1.7500E0 23.6000E0 2.2500E0 31.0500E0 1.7500E0 23.7750E0 2.2500E0 17.7375E0 2.7500E0 13.8000E0 3.2500E0 11.5875E0 3.7500E0 9.4125E0 4.2500E0 7.7250E0 4.7500E0 7.3500E0 5.2500E0 8.0250E0 5.7500E0 90.6000E0 0.5000E0 76.9000E0 0.6250E0 71.6000E0 0.7500E0 63.6000E0 0.8750E0 54.0000E0 1.0000E0 39.2000E0 1.2500E0 29.3000E0 1.7500E0 21.4000E0 2.2500E0 29.1750E0 1.7500E0 22.1250E0 2.2500E0 17.5125E0 2.7500E0 14.2500E0 3.2500E0 9.4500E0 3.7500E0 9.1500E0 4.2500E0 7.9125E0 4.7500E0 8.4750E0 5.2500E0 6.1125E0 5.7500E0 80.0000E0 0.5000E0 79.0000E0 0.6250E0 63.8000E0 0.7500E0 57.2000E0 0.8750E0 53.2000E0 1.0000E0 42.5000E0 1.2500E0 26.8000E0 1.7500E0 20.4000E0 2.2500E0 26.8500E0 1.7500E0 21.0000E0 2.2500E0 16.4625E0 2.7500E0 12.5250E0 3.2500E0 10.5375E0 3.7500E0 8.5875E0 4.2500E0 7.1250E0 4.7500E0 6.1125E0 5.2500E0 5.9625E0 5.7500E0 74.1000E0 0.5000E0 67.3000E0 0.6250E0 60.8000E0 0.7500E0 55.5000E0 0.8750E0 50.3000E0 1.0000E0 41.0000E0 1.2500E0 29.4000E0 1.7500E0 20.4000E0 2.2500E0 29.3625E0 1.7500E0 21.1500E0 2.2500E0 16.7625E0 2.7500E0 13.2000E0 3.2500E0 10.8750E0 3.7500E0 8.1750E0 4.2500E0 7.3500E0 4.7500E0 5.9625E0 5.2500E0 5.6250E0 5.7500E0 81.5000E0 .5000E0 62.4000E0 .7500E0 32.5000E0 1.5000E0 12.4100E0 3.0000E0 13.1200E0 3.0000E0 15.5600E0 3.0000E0 5.6300E0 6.0000E0 78.0000E0 .5000E0 59.9000E0 .7500E0 33.2000E0 1.5000E0 13.8400E0 3.0000E0 12.7500E0 3.0000E0 14.6200E0 3.0000E0 3.9400E0 6.0000E0 76.8000E0 .5000E0 61.0000E0 .7500E0 32.9000E0 1.5000E0 13.8700E0 3.0000E0 11.8100E0 3.0000E0 13.3100E0 3.0000E0 5.4400E0 6.0000E0 78.0000E0 .5000E0 63.5000E0 .7500E0 33.8000E0 1.5000E0 12.5600E0 3.0000E0 5.6300E0 6.0000E0 12.7500E0 3.0000E0 13.1200E0 3.0000E0 5.4400E0 6.0000E0 76.8000E0 .5000E0 60.0000E0 .7500E0 47.8000E0 1.0000E0 32.0000E0 1.5000E0 22.2000E0 2.0000E0 22.5700E0 2.0000E0 18.8200E0 2.5000E0 13.9500E0 3.0000E0 11.2500E0 4.0000E0 9.0000E0 5.0000E0 6.6700E0 6.0000E0 75.8000E0 .5000E0 62.0000E0 .7500E0 48.8000E0 1.0000E0 35.2000E0 1.5000E0 20.0000E0 2.0000E0 20.3200E0 2.0000E0 19.3100E0 2.5000E0 12.7500E0 3.0000E0 10.4200E0 4.0000E0 7.3100E0 5.0000E0 7.4200E0 6.0000E0 70.5000E0 .5000E0 59.5000E0 .7500E0 48.5000E0 1.0000E0 35.8000E0 1.5000E0 21.0000E0 2.0000E0 21.6700E0 2.0000E0 21.0000E0 2.5000E0 15.6400E0 3.0000E0 8.1700E0 4.0000E0 8.5500E0 5.0000E0 10.1200E0 6.0000E0 78.0000E0 .5000E0 66.0000E0 .6250E0 62.0000E0 .7500E0 58.0000E0 .8750E0 47.7000E0 1.0000E0 37.8000E0 1.2500E0 20.2000E0 2.2500E0 21.0700E0 2.2500E0 13.8700E0 2.7500E0 9.6700E0 3.2500E0 7.7600E0 3.7500E0 5.4400E0 4.2500E0 4.8700E0 4.7500E0 4.0100E0 5.2500E0 3.7500E0 5.7500E0 24.1900E0 3.0000E0 25.7600E0 3.0000E0 18.0700E0 3.0000E0 11.8100E0 3.0000E0 12.0700E0 3.0000E0 16.1200E0 3.0000E0 70.8000E0 .5000E0 54.7000E0 .7500E0 48.0000E0 1.0000E0 39.8000E0 1.5000E0 29.8000E0 2.0000E0 23.7000E0 2.5000E0 29.6200E0 2.0000E0 23.8100E0 2.5000E0 17.7000E0 3.0000E0 11.5500E0 4.0000E0 12.0700E0 5.0000E0 8.7400E0 6.0000E0 80.7000E0 .5000E0 61.3000E0 .7500E0 47.5000E0 1.0000E0 29.0000E0 1.5000E0 24.0000E0 2.0000E0 17.7000E0 2.5000E0 24.5600E0 2.0000E0 18.6700E0 2.5000E0 16.2400E0 3.0000E0 8.7400E0 4.0000E0 7.8700E0 5.0000E0 8.5100E0 6.0000E0 66.7000E0 .5000E0 59.2000E0 .7500E0 40.8000E0 1.0000E0 30.7000E0 1.5000E0 25.7000E0 2.0000E0 16.3000E0 2.5000E0 25.9900E0 2.0000E0 16.9500E0 2.5000E0 13.3500E0 3.0000E0 8.6200E0 4.0000E0 7.2000E0 5.0000E0 6.6400E0 6.0000E0 13.6900E0 3.0000E0 81.0000E0 .5000E0 64.5000E0 .7500E0 35.5000E0 1.5000E0 13.3100E0 3.0000E0 4.8700E0 6.0000E0 12.9400E0 3.0000E0 5.0600E0 6.0000E0 15.1900E0 3.0000E0 14.6200E0 3.0000E0 15.6400E0 3.0000E0 25.5000E0 1.7500E0 25.9500E0 1.7500E0 81.7000E0 .5000E0 61.6000E0 .7500E0 29.8000E0 1.7500E0 29.8100E0 1.7500E0 17.1700E0 2.7500E0 10.3900E0 3.7500E0 28.4000E0 1.7500E0 28.6900E0 1.7500E0 81.3000E0 .5000E0 60.9000E0 .7500E0 16.6500E0 2.7500E0 10.0500E0 3.7500E0 28.9000E0 1.7500E0 28.9500E0 1.7500E0 lmfit-0.9.7/NIST_STRD/Chwirut2.dat0000644000076500000240000000577013066042256017401 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Chwirut2 (Chwirut2.dat) File Format: ASCII Starting Values (lines 41 to 43) Certified Values (lines 41 to 48) Data (lines 61 to 114) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving ultrasonic calibration. The response variable is ultrasonic response, and the predictor variable is metal distance. Reference: Chwirut, D., NIST (197?). Ultrasonic Reference Block Study. Data: 1 Response (y = ultrasonic response) 1 Predictor (x = metal distance) 54 Observations Lower Level of Difficulty Observed Data Model: Exponential Class 3 Parameters (b1 to b3) y = exp(-b1*x)/(b2+b3*x) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 0.1 0.15 1.6657666537E-01 3.8303286810E-02 b2 = 0.01 0.008 5.1653291286E-03 6.6621605126E-04 b3 = 0.02 0.010 1.2150007096E-02 1.5304234767E-03 Residual Sum of Squares: 5.1304802941E+02 Residual Standard Deviation: 3.1717133040E+00 Degrees of Freedom: 51 Number of Observations: 54 Data: y x 92.9000E0 0.500E0 57.1000E0 1.000E0 31.0500E0 1.750E0 11.5875E0 3.750E0 8.0250E0 5.750E0 63.6000E0 0.875E0 21.4000E0 2.250E0 14.2500E0 3.250E0 8.4750E0 5.250E0 63.8000E0 0.750E0 26.8000E0 1.750E0 16.4625E0 2.750E0 7.1250E0 4.750E0 67.3000E0 0.625E0 41.0000E0 1.250E0 21.1500E0 2.250E0 8.1750E0 4.250E0 81.5000E0 .500E0 13.1200E0 3.000E0 59.9000E0 .750E0 14.6200E0 3.000E0 32.9000E0 1.500E0 5.4400E0 6.000E0 12.5600E0 3.000E0 5.4400E0 6.000E0 32.0000E0 1.500E0 13.9500E0 3.000E0 75.8000E0 .500E0 20.0000E0 2.000E0 10.4200E0 4.000E0 59.5000E0 .750E0 21.6700E0 2.000E0 8.5500E0 5.000E0 62.0000E0 .750E0 20.2000E0 2.250E0 7.7600E0 3.750E0 3.7500E0 5.750E0 11.8100E0 3.000E0 54.7000E0 .750E0 23.7000E0 2.500E0 11.5500E0 4.000E0 61.3000E0 .750E0 17.7000E0 2.500E0 8.7400E0 4.000E0 59.2000E0 .750E0 16.3000E0 2.500E0 8.6200E0 4.000E0 81.0000E0 .500E0 4.8700E0 6.000E0 14.6200E0 3.000E0 81.7000E0 .500E0 17.1700E0 2.750E0 81.3000E0 .500E0 28.9000E0 1.750E0 lmfit-0.9.7/NIST_STRD/DanWood.dat0000644000076500000240000000372713066042256017225 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: DanWood (DanWood.dat) File Format: ASCII Starting Values (lines 41 to 42) Certified Values (lines 41 to 47) Data (lines 61 to 66) Procedure: Nonlinear Least Squares Regression Description: These data and model are described in Daniel and Wood (1980), and originally published in E.S.Keeping, "Introduction to Statistical Inference," Van Nostrand Company, Princeton, NJ, 1962, p. 354. The response variable is energy radieted from a carbon filament lamp per cm**2 per second, and the predictor variable is the absolute temperature of the filament in 1000 degrees Kelvin. Reference: Daniel, C. and F. S. Wood (1980). Fitting Equations to Data, Second Edition. New York, NY: John Wiley and Sons, pp. 428-431. Data: 1 Response Variable (y = energy) 1 Predictor Variable (x = temperature) 6 Observations Lower Level of Difficulty Observed Data Model: Miscellaneous Class 2 Parameters (b1 and b2) y = b1*x**b2 + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 1 0.7 7.6886226176E-01 1.8281973860E-02 b2 = 5 4 3.8604055871E+00 5.1726610913E-02 Residual Sum of Squares: 4.3173084083E-03 Residual Standard Deviation: 3.2853114039E-02 Degrees of Freedom: 4 Number of Observations: 6 Data: y x 2.138E0 1.309E0 3.421E0 1.471E0 3.597E0 1.490E0 4.340E0 1.565E0 4.882E0 1.611E0 5.660E0 1.680E0 lmfit-0.9.7/NIST_STRD/Eckerle4.dat0000644000076500000240000000533013066042256017320 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Eckerle4 (Eckerle4.dat) File Format: ASCII Starting Values (lines 41 to 43) Certified Values (lines 41 to 48) Data (lines 61 to 95) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving circular interference transmittance. The response variable is transmittance, and the predictor variable is wavelength. Reference: Eckerle, K., NIST (197?). Circular Interference Transmittance Study. Data: 1 Response Variable (y = transmittance) 1 Predictor Variable (x = wavelength) 35 Observations Higher Level of Difficulty Observed Data Model: Exponential Class 3 Parameters (b1 to b3) y = (b1/b2) * exp[-0.5*((x-b3)/b2)**2] + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 1 1.5 1.5543827178E+00 1.5408051163E-02 b2 = 10 5 4.0888321754E+00 4.6803020753E-02 b3 = 500 450 4.5154121844E+02 4.6800518816E-02 Residual Sum of Squares: 1.4635887487E-03 Residual Standard Deviation: 6.7629245447E-03 Degrees of Freedom: 32 Number of Observations: 35 Data: y x 0.0001575E0 400.000000E0 0.0001699E0 405.000000E0 0.0002350E0 410.000000E0 0.0003102E0 415.000000E0 0.0004917E0 420.000000E0 0.0008710E0 425.000000E0 0.0017418E0 430.000000E0 0.0046400E0 435.000000E0 0.0065895E0 436.500000E0 0.0097302E0 438.000000E0 0.0149002E0 439.500000E0 0.0237310E0 441.000000E0 0.0401683E0 442.500000E0 0.0712559E0 444.000000E0 0.1264458E0 445.500000E0 0.2073413E0 447.000000E0 0.2902366E0 448.500000E0 0.3445623E0 450.000000E0 0.3698049E0 451.500000E0 0.3668534E0 453.000000E0 0.3106727E0 454.500000E0 0.2078154E0 456.000000E0 0.1164354E0 457.500000E0 0.0616764E0 459.000000E0 0.0337200E0 460.500000E0 0.0194023E0 462.000000E0 0.0117831E0 463.500000E0 0.0074357E0 465.000000E0 0.0022732E0 470.000000E0 0.0008800E0 475.000000E0 0.0004579E0 480.000000E0 0.0002345E0 485.000000E0 0.0001586E0 490.000000E0 0.0001143E0 495.000000E0 0.0000710E0 500.000000E0 lmfit-0.9.7/NIST_STRD/ENSO.dat0000644000076500000240000001516213066042256016432 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: ENSO (ENSO.dat) File Format: ASCII Starting Values (lines 41 to 49) Certified Values (lines 41 to 54) Data (lines 61 to 228) Procedure: Nonlinear Least Squares Regression Description: The data are monthly averaged atmospheric pressure differences between Easter Island and Darwin, Australia. This difference drives the trade winds in the southern hemisphere. Fourier analysis of the data reveals 3 significant cycles. The annual cycle is the strongest, but cycles with periods of approximately 44 and 26 months are also present. These cycles correspond to the El Nino and the Southern Oscillation. Arguments to the SIN and COS functions are in radians. Reference: Kahaner, D., C. Moler, and S. Nash, (1989). Numerical Methods and Software. Englewood Cliffs, NJ: Prentice Hall, pp. 441-445. Data: 1 Response (y = atmospheric pressure) 1 Predictor (x = time) 168 Observations Average Level of Difficulty Observed Data Model: Miscellaneous Class 9 Parameters (b1 to b9) y = b1 + b2*cos( 2*pi*x/12 ) + b3*sin( 2*pi*x/12 ) + b5*cos( 2*pi*x/b4 ) + b6*sin( 2*pi*x/b4 ) + b8*cos( 2*pi*x/b7 ) + b9*sin( 2*pi*x/b7 ) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 11.0 10.0 1.0510749193E+01 1.7488832467E-01 b2 = 3.0 3.0 3.0762128085E+00 2.4310052139E-01 b3 = 0.5 0.5 5.3280138227E-01 2.4354686618E-01 b4 = 40.0 44.0 4.4311088700E+01 9.4408025976E-01 b5 = -0.7 -1.5 -1.6231428586E+00 2.8078369611E-01 b6 = -1.3 0.5 5.2554493756E-01 4.8073701119E-01 b7 = 25.0 26.0 2.6887614440E+01 4.1612939130E-01 b8 = -0.3 -0.1 2.1232288488E-01 5.1460022911E-01 b9 = 1.4 1.5 1.4966870418E+00 2.5434468893E-01 Residual Sum of Squares: 7.8853978668E+02 Residual Standard Deviation: 2.2269642403E+00 Degrees of Freedom: 159 Number of Observations: 168 Data: y x 12.90000 1.000000 11.30000 2.000000 10.60000 3.000000 11.20000 4.000000 10.90000 5.000000 7.500000 6.000000 7.700000 7.000000 11.70000 8.000000 12.90000 9.000000 14.30000 10.000000 10.90000 11.00000 13.70000 12.00000 17.10000 13.00000 14.00000 14.00000 15.30000 15.00000 8.500000 16.00000 5.700000 17.00000 5.500000 18.00000 7.600000 19.00000 8.600000 20.00000 7.300000 21.00000 7.600000 22.00000 12.70000 23.00000 11.00000 24.00000 12.70000 25.00000 12.90000 26.00000 13.00000 27.00000 10.90000 28.00000 10.400000 29.00000 10.200000 30.00000 8.000000 31.00000 10.90000 32.00000 13.60000 33.00000 10.500000 34.00000 9.200000 35.00000 12.40000 36.00000 12.70000 37.00000 13.30000 38.00000 10.100000 39.00000 7.800000 40.00000 4.800000 41.00000 3.000000 42.00000 2.500000 43.00000 6.300000 44.00000 9.700000 45.00000 11.60000 46.00000 8.600000 47.00000 12.40000 48.00000 10.500000 49.00000 13.30000 50.00000 10.400000 51.00000 8.100000 52.00000 3.700000 53.00000 10.70000 54.00000 5.100000 55.00000 10.400000 56.00000 10.90000 57.00000 11.70000 58.00000 11.40000 59.00000 13.70000 60.00000 14.10000 61.00000 14.00000 62.00000 12.50000 63.00000 6.300000 64.00000 9.600000 65.00000 11.70000 66.00000 5.000000 67.00000 10.80000 68.00000 12.70000 69.00000 10.80000 70.00000 11.80000 71.00000 12.60000 72.00000 15.70000 73.00000 12.60000 74.00000 14.80000 75.00000 7.800000 76.00000 7.100000 77.00000 11.20000 78.00000 8.100000 79.00000 6.400000 80.00000 5.200000 81.00000 12.00000 82.00000 10.200000 83.00000 12.70000 84.00000 10.200000 85.00000 14.70000 86.00000 12.20000 87.00000 7.100000 88.00000 5.700000 89.00000 6.700000 90.00000 3.900000 91.00000 8.500000 92.00000 8.300000 93.00000 10.80000 94.00000 16.70000 95.00000 12.60000 96.00000 12.50000 97.00000 12.50000 98.00000 9.800000 99.00000 7.200000 100.00000 4.100000 101.00000 10.60000 102.00000 10.100000 103.00000 10.100000 104.00000 11.90000 105.00000 13.60000 106.0000 16.30000 107.0000 17.60000 108.0000 15.50000 109.0000 16.00000 110.0000 15.20000 111.0000 11.20000 112.0000 14.30000 113.0000 14.50000 114.0000 8.500000 115.0000 12.00000 116.0000 12.70000 117.0000 11.30000 118.0000 14.50000 119.0000 15.10000 120.0000 10.400000 121.0000 11.50000 122.0000 13.40000 123.0000 7.500000 124.0000 0.6000000 125.0000 0.3000000 126.0000 5.500000 127.0000 5.000000 128.0000 4.600000 129.0000 8.200000 130.0000 9.900000 131.0000 9.200000 132.0000 12.50000 133.0000 10.90000 134.0000 9.900000 135.0000 8.900000 136.0000 7.600000 137.0000 9.500000 138.0000 8.400000 139.0000 10.70000 140.0000 13.60000 141.0000 13.70000 142.0000 13.70000 143.0000 16.50000 144.0000 16.80000 145.0000 17.10000 146.0000 15.40000 147.0000 9.500000 148.0000 6.100000 149.0000 10.100000 150.0000 9.300000 151.0000 5.300000 152.0000 11.20000 153.0000 16.60000 154.0000 15.60000 155.0000 12.00000 156.0000 11.50000 157.0000 8.600000 158.0000 13.80000 159.0000 8.700000 160.0000 8.600000 161.0000 8.600000 162.0000 8.700000 163.0000 12.80000 164.0000 13.20000 165.0000 14.00000 166.0000 13.40000 167.0000 14.80000 168.0000 lmfit-0.9.7/NIST_STRD/Gauss1.dat0000644000076500000240000001765313066042256017040 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Gauss1 (Gauss1.dat) File Format: ASCII Starting Values (lines 41 to 48) Certified Values (lines 41 to 53) Data (lines 61 to 310) Procedure: Nonlinear Least Squares Regression Description: The data are two well-separated Gaussians on a decaying exponential baseline plus normally distributed zero-mean noise with variance = 6.25. Reference: Rust, B., NIST (1996). Data: 1 Response (y) 1 Predictor (x) 250 Observations Lower Level of Difficulty Generated Data Model: Exponential Class 8 Parameters (b1 to b8) y = b1*exp( -b2*x ) + b3*exp( -(x-b4)**2 / b5**2 ) + b6*exp( -(x-b7)**2 / b8**2 ) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 97.0 94.0 9.8778210871E+01 5.7527312730E-01 b2 = 0.009 0.0105 1.0497276517E-02 1.1406289017E-04 b3 = 100.0 99.0 1.0048990633E+02 5.8831775752E-01 b4 = 65.0 63.0 6.7481111276E+01 1.0460593412E-01 b5 = 20.0 25.0 2.3129773360E+01 1.7439951146E-01 b6 = 70.0 71.0 7.1994503004E+01 6.2622793913E-01 b7 = 178.0 180.0 1.7899805021E+02 1.2436988217E-01 b8 = 16.5 20.0 1.8389389025E+01 2.0134312832E-01 Residual Sum of Squares: 1.3158222432E+03 Residual Standard Deviation: 2.3317980180E+00 Degrees of Freedom: 242 Number of Observations: 250 Data: y x 97.62227 1.000000 97.80724 2.000000 96.62247 3.000000 92.59022 4.000000 91.23869 5.000000 95.32704 6.000000 90.35040 7.000000 89.46235 8.000000 91.72520 9.000000 89.86916 10.000000 86.88076 11.00000 85.94360 12.00000 87.60686 13.00000 86.25839 14.00000 80.74976 15.00000 83.03551 16.00000 88.25837 17.00000 82.01316 18.00000 82.74098 19.00000 83.30034 20.00000 81.27850 21.00000 81.85506 22.00000 80.75195 23.00000 80.09573 24.00000 81.07633 25.00000 78.81542 26.00000 78.38596 27.00000 79.93386 28.00000 79.48474 29.00000 79.95942 30.00000 76.10691 31.00000 78.39830 32.00000 81.43060 33.00000 82.48867 34.00000 81.65462 35.00000 80.84323 36.00000 88.68663 37.00000 84.74438 38.00000 86.83934 39.00000 85.97739 40.00000 91.28509 41.00000 97.22411 42.00000 93.51733 43.00000 94.10159 44.00000 101.91760 45.00000 98.43134 46.00000 110.4214 47.00000 107.6628 48.00000 111.7288 49.00000 116.5115 50.00000 120.7609 51.00000 123.9553 52.00000 124.2437 53.00000 130.7996 54.00000 133.2960 55.00000 130.7788 56.00000 132.0565 57.00000 138.6584 58.00000 142.9252 59.00000 142.7215 60.00000 144.1249 61.00000 147.4377 62.00000 148.2647 63.00000 152.0519 64.00000 147.3863 65.00000 149.2074 66.00000 148.9537 67.00000 144.5876 68.00000 148.1226 69.00000 148.0144 70.00000 143.8893 71.00000 140.9088 72.00000 143.4434 73.00000 139.3938 74.00000 135.9878 75.00000 136.3927 76.00000 126.7262 77.00000 124.4487 78.00000 122.8647 79.00000 113.8557 80.00000 113.7037 81.00000 106.8407 82.00000 107.0034 83.00000 102.46290 84.00000 96.09296 85.00000 94.57555 86.00000 86.98824 87.00000 84.90154 88.00000 81.18023 89.00000 76.40117 90.00000 67.09200 91.00000 72.67155 92.00000 68.10848 93.00000 67.99088 94.00000 63.34094 95.00000 60.55253 96.00000 56.18687 97.00000 53.64482 98.00000 53.70307 99.00000 48.07893 100.00000 42.21258 101.00000 45.65181 102.00000 41.69728 103.00000 41.24946 104.00000 39.21349 105.00000 37.71696 106.0000 36.68395 107.0000 37.30393 108.0000 37.43277 109.0000 37.45012 110.0000 32.64648 111.0000 31.84347 112.0000 31.39951 113.0000 26.68912 114.0000 32.25323 115.0000 27.61008 116.0000 33.58649 117.0000 28.10714 118.0000 30.26428 119.0000 28.01648 120.0000 29.11021 121.0000 23.02099 122.0000 25.65091 123.0000 28.50295 124.0000 25.23701 125.0000 26.13828 126.0000 33.53260 127.0000 29.25195 128.0000 27.09847 129.0000 26.52999 130.0000 25.52401 131.0000 26.69218 132.0000 24.55269 133.0000 27.71763 134.0000 25.20297 135.0000 25.61483 136.0000 25.06893 137.0000 27.63930 138.0000 24.94851 139.0000 25.86806 140.0000 22.48183 141.0000 26.90045 142.0000 25.39919 143.0000 17.90614 144.0000 23.76039 145.0000 25.89689 146.0000 27.64231 147.0000 22.86101 148.0000 26.47003 149.0000 23.72888 150.0000 27.54334 151.0000 30.52683 152.0000 28.07261 153.0000 34.92815 154.0000 28.29194 155.0000 34.19161 156.0000 35.41207 157.0000 37.09336 158.0000 40.98330 159.0000 39.53923 160.0000 47.80123 161.0000 47.46305 162.0000 51.04166 163.0000 54.58065 164.0000 57.53001 165.0000 61.42089 166.0000 62.79032 167.0000 68.51455 168.0000 70.23053 169.0000 74.42776 170.0000 76.59911 171.0000 81.62053 172.0000 83.42208 173.0000 79.17451 174.0000 88.56985 175.0000 85.66525 176.0000 86.55502 177.0000 90.65907 178.0000 84.27290 179.0000 85.72220 180.0000 83.10702 181.0000 82.16884 182.0000 80.42568 183.0000 78.15692 184.0000 79.79691 185.0000 77.84378 186.0000 74.50327 187.0000 71.57289 188.0000 65.88031 189.0000 65.01385 190.0000 60.19582 191.0000 59.66726 192.0000 52.95478 193.0000 53.87792 194.0000 44.91274 195.0000 41.09909 196.0000 41.68018 197.0000 34.53379 198.0000 34.86419 199.0000 33.14787 200.0000 29.58864 201.0000 27.29462 202.0000 21.91439 203.0000 19.08159 204.0000 24.90290 205.0000 19.82341 206.0000 16.75551 207.0000 18.24558 208.0000 17.23549 209.0000 16.34934 210.0000 13.71285 211.0000 14.75676 212.0000 13.97169 213.0000 12.42867 214.0000 14.35519 215.0000 7.703309 216.0000 10.234410 217.0000 11.78315 218.0000 13.87768 219.0000 4.535700 220.0000 10.059280 221.0000 8.424824 222.0000 10.533120 223.0000 9.602255 224.0000 7.877514 225.0000 6.258121 226.0000 8.899865 227.0000 7.877754 228.0000 12.51191 229.0000 10.66205 230.0000 6.035400 231.0000 6.790655 232.0000 8.783535 233.0000 4.600288 234.0000 8.400915 235.0000 7.216561 236.0000 10.017410 237.0000 7.331278 238.0000 6.527863 239.0000 2.842001 240.0000 10.325070 241.0000 4.790995 242.0000 8.377101 243.0000 6.264445 244.0000 2.706213 245.0000 8.362329 246.0000 8.983658 247.0000 3.362571 248.0000 1.182746 249.0000 4.875359 250.0000 lmfit-0.9.7/NIST_STRD/Gauss2.dat0000644000076500000240000001765213066042256017040 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Gauss2 (Gauss2.dat) File Format: ASCII Starting Values (lines 41 to 48) Certified Values (lines 41 to 53) Data (lines 61 to 310) Procedure: Nonlinear Least Squares Regression Description: The data are two slightly-blended Gaussians on a decaying exponential baseline plus normally distributed zero-mean noise with variance = 6.25. Reference: Rust, B., NIST (1996). Data: 1 Response (y) 1 Predictor (x) 250 Observations Lower Level of Difficulty Generated Data Model: Exponential Class 8 Parameters (b1 to b8) y = b1*exp( -b2*x ) + b3*exp( -(x-b4)**2 / b5**2 ) + b6*exp( -(x-b7)**2 / b8**2 ) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 96.0 98.0 9.9018328406E+01 5.3748766879E-01 b2 = 0.009 0.0105 1.0994945399E-02 1.3335306766E-04 b3 = 103.0 103.0 1.0188022528E+02 5.9217315772E-01 b4 = 106.0 105.0 1.0703095519E+02 1.5006798316E-01 b5 = 18.0 20.0 2.3578584029E+01 2.2695595067E-01 b6 = 72.0 73.0 7.2045589471E+01 6.1721965884E-01 b7 = 151.0 150.0 1.5327010194E+02 1.9466674341E-01 b8 = 18.0 20.0 1.9525972636E+01 2.6416549393E-01 Residual Sum of Squares: 1.2475282092E+03 Residual Standard Deviation: 2.2704790782E+00 Degrees of Freedom: 242 Number of Observations: 250 Data: y x 97.58776 1.000000 97.76344 2.000000 96.56705 3.000000 92.52037 4.000000 91.15097 5.000000 95.21728 6.000000 90.21355 7.000000 89.29235 8.000000 91.51479 9.000000 89.60966 10.000000 86.56187 11.00000 85.55316 12.00000 87.13054 13.00000 85.67940 14.00000 80.04851 15.00000 82.18925 16.00000 87.24081 17.00000 80.79407 18.00000 81.28570 19.00000 81.56940 20.00000 79.22715 21.00000 79.43275 22.00000 77.90195 23.00000 76.75468 24.00000 77.17377 25.00000 74.27348 26.00000 73.11900 27.00000 73.84826 28.00000 72.47870 29.00000 71.92292 30.00000 66.92176 31.00000 67.93835 32.00000 69.56207 33.00000 69.07066 34.00000 66.53983 35.00000 63.87883 36.00000 69.71537 37.00000 63.60588 38.00000 63.37154 39.00000 60.01835 40.00000 62.67481 41.00000 65.80666 42.00000 59.14304 43.00000 56.62951 44.00000 61.21785 45.00000 54.38790 46.00000 62.93443 47.00000 56.65144 48.00000 57.13362 49.00000 58.29689 50.00000 58.91744 51.00000 58.50172 52.00000 55.22885 53.00000 58.30375 54.00000 57.43237 55.00000 51.69407 56.00000 49.93132 57.00000 53.70760 58.00000 55.39712 59.00000 52.89709 60.00000 52.31649 61.00000 53.98720 62.00000 53.54158 63.00000 56.45046 64.00000 51.32276 65.00000 53.11676 66.00000 53.28631 67.00000 49.80555 68.00000 54.69564 69.00000 56.41627 70.00000 54.59362 71.00000 54.38520 72.00000 60.15354 73.00000 59.78773 74.00000 60.49995 75.00000 65.43885 76.00000 60.70001 77.00000 63.71865 78.00000 67.77139 79.00000 64.70934 80.00000 70.78193 81.00000 70.38651 82.00000 77.22359 83.00000 79.52665 84.00000 80.13077 85.00000 85.67823 86.00000 85.20647 87.00000 90.24548 88.00000 93.61953 89.00000 95.86509 90.00000 93.46992 91.00000 105.8137 92.00000 107.8269 93.00000 114.0607 94.00000 115.5019 95.00000 118.5110 96.00000 119.6177 97.00000 122.1940 98.00000 126.9903 99.00000 125.7005 100.00000 123.7447 101.00000 130.6543 102.00000 129.7168 103.00000 131.8240 104.00000 131.8759 105.00000 131.9994 106.0000 132.1221 107.0000 133.4414 108.0000 133.8252 109.0000 133.6695 110.0000 128.2851 111.0000 126.5182 112.0000 124.7550 113.0000 118.4016 114.0000 122.0334 115.0000 115.2059 116.0000 118.7856 117.0000 110.7387 118.0000 110.2003 119.0000 105.17290 120.0000 103.44720 121.0000 94.54280 122.0000 94.40526 123.0000 94.57964 124.0000 88.76605 125.0000 87.28747 126.0000 92.50443 127.0000 86.27997 128.0000 82.44307 129.0000 80.47367 130.0000 78.36608 131.0000 78.74307 132.0000 76.12786 133.0000 79.13108 134.0000 76.76062 135.0000 77.60769 136.0000 77.76633 137.0000 81.28220 138.0000 79.74307 139.0000 81.97964 140.0000 80.02952 141.0000 85.95232 142.0000 85.96838 143.0000 79.94789 144.0000 87.17023 145.0000 90.50992 146.0000 93.23373 147.0000 89.14803 148.0000 93.11492 149.0000 90.34337 150.0000 93.69421 151.0000 95.74256 152.0000 91.85105 153.0000 96.74503 154.0000 87.60996 155.0000 90.47012 156.0000 88.11690 157.0000 85.70673 158.0000 85.01361 159.0000 78.53040 160.0000 81.34148 161.0000 75.19295 162.0000 72.66115 163.0000 69.85504 164.0000 66.29476 165.0000 63.58502 166.0000 58.33847 167.0000 57.50766 168.0000 52.80498 169.0000 50.79319 170.0000 47.03490 171.0000 46.47090 172.0000 43.09016 173.0000 34.11531 174.0000 39.28235 175.0000 32.68386 176.0000 30.44056 177.0000 31.98932 178.0000 23.63330 179.0000 23.69643 180.0000 20.26812 181.0000 19.07074 182.0000 17.59544 183.0000 16.08785 184.0000 18.94267 185.0000 18.61354 186.0000 17.25800 187.0000 16.62285 188.0000 13.48367 189.0000 15.37647 190.0000 13.47208 191.0000 15.96188 192.0000 12.32547 193.0000 16.33880 194.0000 10.438330 195.0000 9.628715 196.0000 13.12268 197.0000 8.772417 198.0000 11.76143 199.0000 12.55020 200.0000 11.33108 201.0000 11.20493 202.0000 7.816916 203.0000 6.800675 204.0000 14.26581 205.0000 10.66285 206.0000 8.911574 207.0000 11.56733 208.0000 11.58207 209.0000 11.59071 210.0000 9.730134 211.0000 11.44237 212.0000 11.22912 213.0000 10.172130 214.0000 12.50905 215.0000 6.201493 216.0000 9.019605 217.0000 10.80607 218.0000 13.09625 219.0000 3.914271 220.0000 9.567886 221.0000 8.038448 222.0000 10.231040 223.0000 9.367410 224.0000 7.695971 225.0000 6.118575 226.0000 8.793207 227.0000 7.796692 228.0000 12.45065 229.0000 10.61601 230.0000 6.001003 231.0000 6.765098 232.0000 8.764653 233.0000 4.586418 234.0000 8.390783 235.0000 7.209202 236.0000 10.012090 237.0000 7.327461 238.0000 6.525136 239.0000 2.840065 240.0000 10.323710 241.0000 4.790035 242.0000 8.376431 243.0000 6.263980 244.0000 2.705892 245.0000 8.362109 246.0000 8.983507 247.0000 3.362469 248.0000 1.182678 249.0000 4.875312 250.0000 lmfit-0.9.7/NIST_STRD/Gauss3.dat0000644000076500000240000001765413066042256017043 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Gauss3 (Gauss3.dat) File Format: ASCII Starting Values (lines 41 to 48) Certified Values (lines 41 to 53) Data (lines 61 to 310) Procedure: Nonlinear Least Squares Regression Description: The data are two strongly-blended Gaussians on a decaying exponential baseline plus normally distributed zero-mean noise with variance = 6.25. Reference: Rust, B., NIST (1996). Data: 1 Response (y) 1 Predictor (x) 250 Observations Average Level of Difficulty Generated Data Model: Exponential Class 8 Parameters (b1 to b8) y = b1*exp( -b2*x ) + b3*exp( -(x-b4)**2 / b5**2 ) + b6*exp( -(x-b7)**2 / b8**2 ) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 94.9 96.0 9.8940368970E+01 5.3005192833E-01 b2 = 0.009 0.0096 1.0945879335E-02 1.2554058911E-04 b3 = 90.1 80.0 1.0069553078E+02 8.1256587317E-01 b4 = 113.0 110.0 1.1163619459E+02 3.5317859757E-01 b5 = 20.0 25.0 2.3300500029E+01 3.6584783023E-01 b6 = 73.8 74.0 7.3705031418E+01 1.2091239082E+00 b7 = 140.0 139.0 1.4776164251E+02 4.0488183351E-01 b8 = 20.0 25.0 1.9668221230E+01 3.7806634336E-01 Residual Sum of Squares: 1.2444846360E+03 Residual Standard Deviation: 2.2677077625E+00 Degrees of Freedom: 242 Number of Observations: 250 Data: y x 97.58776 1.000000 97.76344 2.000000 96.56705 3.000000 92.52037 4.000000 91.15097 5.000000 95.21728 6.000000 90.21355 7.000000 89.29235 8.000000 91.51479 9.000000 89.60965 10.000000 86.56187 11.00000 85.55315 12.00000 87.13053 13.00000 85.67938 14.00000 80.04849 15.00000 82.18922 16.00000 87.24078 17.00000 80.79401 18.00000 81.28564 19.00000 81.56932 20.00000 79.22703 21.00000 79.43259 22.00000 77.90174 23.00000 76.75438 24.00000 77.17338 25.00000 74.27296 26.00000 73.11830 27.00000 73.84732 28.00000 72.47746 29.00000 71.92128 30.00000 66.91962 31.00000 67.93554 32.00000 69.55841 33.00000 69.06592 34.00000 66.53371 35.00000 63.87094 36.00000 69.70526 37.00000 63.59295 38.00000 63.35509 39.00000 59.99747 40.00000 62.64843 41.00000 65.77345 42.00000 59.10141 43.00000 56.57750 44.00000 61.15313 45.00000 54.30767 46.00000 62.83535 47.00000 56.52957 48.00000 56.98427 49.00000 58.11459 50.00000 58.69576 51.00000 58.23322 52.00000 54.90490 53.00000 57.91442 54.00000 56.96629 55.00000 51.13831 56.00000 49.27123 57.00000 52.92668 58.00000 54.47693 59.00000 51.81710 60.00000 51.05401 61.00000 52.51731 62.00000 51.83710 63.00000 54.48196 64.00000 49.05859 65.00000 50.52315 66.00000 50.32755 67.00000 46.44419 68.00000 50.89281 69.00000 52.13203 70.00000 49.78741 71.00000 49.01637 72.00000 54.18198 73.00000 53.17456 74.00000 53.20827 75.00000 57.43459 76.00000 51.95282 77.00000 54.20282 78.00000 57.46687 79.00000 53.60268 80.00000 58.86728 81.00000 57.66652 82.00000 63.71034 83.00000 65.24244 84.00000 65.10878 85.00000 69.96313 86.00000 68.85475 87.00000 73.32574 88.00000 76.21241 89.00000 78.06311 90.00000 75.37701 91.00000 87.54449 92.00000 89.50588 93.00000 95.82098 94.00000 97.48390 95.00000 100.86070 96.00000 102.48510 97.00000 105.7311 98.00000 111.3489 99.00000 111.0305 100.00000 110.1920 101.00000 118.3581 102.00000 118.8086 103.00000 122.4249 104.00000 124.0953 105.00000 125.9337 106.0000 127.8533 107.0000 131.0361 108.0000 133.3343 109.0000 135.1278 110.0000 131.7113 111.0000 131.9151 112.0000 132.1107 113.0000 127.6898 114.0000 133.2148 115.0000 128.2296 116.0000 133.5902 117.0000 127.2539 118.0000 128.3482 119.0000 124.8694 120.0000 124.6031 121.0000 117.0648 122.0000 118.1966 123.0000 119.5408 124.0000 114.7946 125.0000 114.2780 126.0000 120.3484 127.0000 114.8647 128.0000 111.6514 129.0000 110.1826 130.0000 108.4461 131.0000 109.0571 132.0000 106.5308 133.0000 109.4691 134.0000 106.8709 135.0000 107.3192 136.0000 106.9000 137.0000 109.6526 138.0000 107.1602 139.0000 108.2509 140.0000 104.96310 141.0000 109.3601 142.0000 107.6696 143.0000 99.77286 144.0000 104.96440 145.0000 106.1376 146.0000 106.5816 147.0000 100.12860 148.0000 101.66910 149.0000 96.44254 150.0000 97.34169 151.0000 96.97412 152.0000 90.73460 153.0000 93.37949 154.0000 82.12331 155.0000 83.01657 156.0000 78.87360 157.0000 74.86971 158.0000 72.79341 159.0000 65.14744 160.0000 67.02127 161.0000 60.16136 162.0000 57.13996 163.0000 54.05769 164.0000 50.42265 165.0000 47.82430 166.0000 42.85748 167.0000 42.45495 168.0000 38.30808 169.0000 36.95794 170.0000 33.94543 171.0000 34.19017 172.0000 31.66097 173.0000 23.56172 174.0000 29.61143 175.0000 23.88765 176.0000 22.49812 177.0000 24.86901 178.0000 17.29481 179.0000 18.09291 180.0000 15.34813 181.0000 14.77997 182.0000 13.87832 183.0000 12.88891 184.0000 16.20763 185.0000 16.29024 186.0000 15.29712 187.0000 14.97839 188.0000 12.11330 189.0000 14.24168 190.0000 12.53824 191.0000 15.19818 192.0000 11.70478 193.0000 15.83745 194.0000 10.035850 195.0000 9.307574 196.0000 12.86800 197.0000 8.571671 198.0000 11.60415 199.0000 12.42772 200.0000 11.23627 201.0000 11.13198 202.0000 7.761117 203.0000 6.758250 204.0000 14.23375 205.0000 10.63876 206.0000 8.893581 207.0000 11.55398 208.0000 11.57221 209.0000 11.58347 210.0000 9.724857 211.0000 11.43854 212.0000 11.22636 213.0000 10.170150 214.0000 12.50765 215.0000 6.200494 216.0000 9.018902 217.0000 10.80557 218.0000 13.09591 219.0000 3.914033 220.0000 9.567723 221.0000 8.038338 222.0000 10.230960 223.0000 9.367358 224.0000 7.695937 225.0000 6.118552 226.0000 8.793192 227.0000 7.796682 228.0000 12.45064 229.0000 10.61601 230.0000 6.001000 231.0000 6.765096 232.0000 8.764652 233.0000 4.586417 234.0000 8.390782 235.0000 7.209201 236.0000 10.012090 237.0000 7.327461 238.0000 6.525136 239.0000 2.840065 240.0000 10.323710 241.0000 4.790035 242.0000 8.376431 243.0000 6.263980 244.0000 2.705892 245.0000 8.362109 246.0000 8.983507 247.0000 3.362469 248.0000 1.182678 249.0000 4.875312 250.0000 lmfit-0.9.7/NIST_STRD/Hahn1.dat0000644000076500000240000002303513066042256016623 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Hahn1 (Hahn1.dat) File Format: ASCII Starting Values (lines 41 to 47) Certified Values (lines 41 to 52) Data (lines 61 to 296) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving the thermal expansion of copper. The response variable is the coefficient of thermal expansion, and the predictor variable is temperature in degrees kelvin. Reference: Hahn, T., NIST (197?). Copper Thermal Expansion Study. Data: 1 Response (y = coefficient of thermal expansion) 1 Predictor (x = temperature, degrees kelvin) 236 Observations Average Level of Difficulty Observed Data Model: Rational Class (cubic/cubic) 7 Parameters (b1 to b7) y = (b1+b2*x+b3*x**2+b4*x**3) / (1+b5*x+b6*x**2+b7*x**3) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 10 1 1.0776351733E+00 1.7070154742E-01 b2 = -1 -0.1 -1.2269296921E-01 1.2000289189E-02 b3 = 0.05 0.005 4.0863750610E-03 2.2508314937E-04 b4 = -0.00001 -0.000001 -1.4262662514E-06 2.7578037666E-07 b5 = -0.05 -0.005 -5.7609940901E-03 2.4712888219E-04 b6 = 0.001 0.0001 2.4053735503E-04 1.0449373768E-05 b7 = -0.000001 -0.0000001 -1.2314450199E-07 1.3027335327E-08 Residual Sum of Squares: 1.5324382854E+00 Residual Standard Deviation: 8.1803852243E-02 Degrees of Freedom: 229 Number of Observations: 236 Data: y x .591E0 24.41E0 1.547E0 34.82E0 2.902E0 44.09E0 2.894E0 45.07E0 4.703E0 54.98E0 6.307E0 65.51E0 7.03E0 70.53E0 7.898E0 75.70E0 9.470E0 89.57E0 9.484E0 91.14E0 10.072E0 96.40E0 10.163E0 97.19E0 11.615E0 114.26E0 12.005E0 120.25E0 12.478E0 127.08E0 12.982E0 133.55E0 12.970E0 133.61E0 13.926E0 158.67E0 14.452E0 172.74E0 14.404E0 171.31E0 15.190E0 202.14E0 15.550E0 220.55E0 15.528E0 221.05E0 15.499E0 221.39E0 16.131E0 250.99E0 16.438E0 268.99E0 16.387E0 271.80E0 16.549E0 271.97E0 16.872E0 321.31E0 16.830E0 321.69E0 16.926E0 330.14E0 16.907E0 333.03E0 16.966E0 333.47E0 17.060E0 340.77E0 17.122E0 345.65E0 17.311E0 373.11E0 17.355E0 373.79E0 17.668E0 411.82E0 17.767E0 419.51E0 17.803E0 421.59E0 17.765E0 422.02E0 17.768E0 422.47E0 17.736E0 422.61E0 17.858E0 441.75E0 17.877E0 447.41E0 17.912E0 448.7E0 18.046E0 472.89E0 18.085E0 476.69E0 18.291E0 522.47E0 18.357E0 522.62E0 18.426E0 524.43E0 18.584E0 546.75E0 18.610E0 549.53E0 18.870E0 575.29E0 18.795E0 576.00E0 19.111E0 625.55E0 .367E0 20.15E0 .796E0 28.78E0 0.892E0 29.57E0 1.903E0 37.41E0 2.150E0 39.12E0 3.697E0 50.24E0 5.870E0 61.38E0 6.421E0 66.25E0 7.422E0 73.42E0 9.944E0 95.52E0 11.023E0 107.32E0 11.87E0 122.04E0 12.786E0 134.03E0 14.067E0 163.19E0 13.974E0 163.48E0 14.462E0 175.70E0 14.464E0 179.86E0 15.381E0 211.27E0 15.483E0 217.78E0 15.59E0 219.14E0 16.075E0 262.52E0 16.347E0 268.01E0 16.181E0 268.62E0 16.915E0 336.25E0 17.003E0 337.23E0 16.978E0 339.33E0 17.756E0 427.38E0 17.808E0 428.58E0 17.868E0 432.68E0 18.481E0 528.99E0 18.486E0 531.08E0 19.090E0 628.34E0 16.062E0 253.24E0 16.337E0 273.13E0 16.345E0 273.66E0 16.388E0 282.10E0 17.159E0 346.62E0 17.116E0 347.19E0 17.164E0 348.78E0 17.123E0 351.18E0 17.979E0 450.10E0 17.974E0 450.35E0 18.007E0 451.92E0 17.993E0 455.56E0 18.523E0 552.22E0 18.669E0 553.56E0 18.617E0 555.74E0 19.371E0 652.59E0 19.330E0 656.20E0 0.080E0 14.13E0 0.248E0 20.41E0 1.089E0 31.30E0 1.418E0 33.84E0 2.278E0 39.70E0 3.624E0 48.83E0 4.574E0 54.50E0 5.556E0 60.41E0 7.267E0 72.77E0 7.695E0 75.25E0 9.136E0 86.84E0 9.959E0 94.88E0 9.957E0 96.40E0 11.600E0 117.37E0 13.138E0 139.08E0 13.564E0 147.73E0 13.871E0 158.63E0 13.994E0 161.84E0 14.947E0 192.11E0 15.473E0 206.76E0 15.379E0 209.07E0 15.455E0 213.32E0 15.908E0 226.44E0 16.114E0 237.12E0 17.071E0 330.90E0 17.135E0 358.72E0 17.282E0 370.77E0 17.368E0 372.72E0 17.483E0 396.24E0 17.764E0 416.59E0 18.185E0 484.02E0 18.271E0 495.47E0 18.236E0 514.78E0 18.237E0 515.65E0 18.523E0 519.47E0 18.627E0 544.47E0 18.665E0 560.11E0 19.086E0 620.77E0 0.214E0 18.97E0 0.943E0 28.93E0 1.429E0 33.91E0 2.241E0 40.03E0 2.951E0 44.66E0 3.782E0 49.87E0 4.757E0 55.16E0 5.602E0 60.90E0 7.169E0 72.08E0 8.920E0 85.15E0 10.055E0 97.06E0 12.035E0 119.63E0 12.861E0 133.27E0 13.436E0 143.84E0 14.167E0 161.91E0 14.755E0 180.67E0 15.168E0 198.44E0 15.651E0 226.86E0 15.746E0 229.65E0 16.216E0 258.27E0 16.445E0 273.77E0 16.965E0 339.15E0 17.121E0 350.13E0 17.206E0 362.75E0 17.250E0 371.03E0 17.339E0 393.32E0 17.793E0 448.53E0 18.123E0 473.78E0 18.49E0 511.12E0 18.566E0 524.70E0 18.645E0 548.75E0 18.706E0 551.64E0 18.924E0 574.02E0 19.1E0 623.86E0 0.375E0 21.46E0 0.471E0 24.33E0 1.504E0 33.43E0 2.204E0 39.22E0 2.813E0 44.18E0 4.765E0 55.02E0 9.835E0 94.33E0 10.040E0 96.44E0 11.946E0 118.82E0 12.596E0 128.48E0 13.303E0 141.94E0 13.922E0 156.92E0 14.440E0 171.65E0 14.951E0 190.00E0 15.627E0 223.26E0 15.639E0 223.88E0 15.814E0 231.50E0 16.315E0 265.05E0 16.334E0 269.44E0 16.430E0 271.78E0 16.423E0 273.46E0 17.024E0 334.61E0 17.009E0 339.79E0 17.165E0 349.52E0 17.134E0 358.18E0 17.349E0 377.98E0 17.576E0 394.77E0 17.848E0 429.66E0 18.090E0 468.22E0 18.276E0 487.27E0 18.404E0 519.54E0 18.519E0 523.03E0 19.133E0 612.99E0 19.074E0 638.59E0 19.239E0 641.36E0 19.280E0 622.05E0 19.101E0 631.50E0 19.398E0 663.97E0 19.252E0 646.9E0 19.89E0 748.29E0 20.007E0 749.21E0 19.929E0 750.14E0 19.268E0 647.04E0 19.324E0 646.89E0 20.049E0 746.9E0 20.107E0 748.43E0 20.062E0 747.35E0 20.065E0 749.27E0 19.286E0 647.61E0 19.972E0 747.78E0 20.088E0 750.51E0 20.743E0 851.37E0 20.83E0 845.97E0 20.935E0 847.54E0 21.035E0 849.93E0 20.93E0 851.61E0 21.074E0 849.75E0 21.085E0 850.98E0 20.935E0 848.23E0 lmfit-0.9.7/NIST_STRD/Kirby2.dat0000644000076500000240000001334613066042256017032 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Kirby2 (Kirby2.dat) File Format: ASCII Starting Values (lines 41 to 45) Certified Values (lines 41 to 50) Data (lines 61 to 211) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving scanning electron microscope line with standards. Reference: Kirby, R., NIST (197?). Scanning electron microscope line width standards. Data: 1 Response (y) 1 Predictor (x) 151 Observations Average Level of Difficulty Observed Data Model: Rational Class (quadratic/quadratic) 5 Parameters (b1 to b5) y = (b1 + b2*x + b3*x**2) / (1 + b4*x + b5*x**2) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 2 1.5 1.6745063063E+00 8.7989634338E-02 b2 = -0.1 -0.15 -1.3927397867E-01 4.1182041386E-03 b3 = 0.003 0.0025 2.5961181191E-03 4.1856520458E-05 b4 = -0.001 -0.0015 -1.7241811870E-03 5.8931897355E-05 b5 = 0.00001 0.00002 2.1664802578E-05 2.0129761919E-07 Residual Sum of Squares: 3.9050739624E+00 Residual Standard Deviation: 1.6354535131E-01 Degrees of Freedom: 146 Number of Observations: 151 Data: y x 0.0082E0 9.65E0 0.0112E0 10.74E0 0.0149E0 11.81E0 0.0198E0 12.88E0 0.0248E0 14.06E0 0.0324E0 15.28E0 0.0420E0 16.63E0 0.0549E0 18.19E0 0.0719E0 19.88E0 0.0963E0 21.84E0 0.1291E0 24.00E0 0.1710E0 26.25E0 0.2314E0 28.86E0 0.3227E0 31.85E0 0.4809E0 35.79E0 0.7084E0 40.18E0 1.0220E0 44.74E0 1.4580E0 49.53E0 1.9520E0 53.94E0 2.5410E0 58.29E0 3.2230E0 62.63E0 3.9990E0 67.03E0 4.8520E0 71.25E0 5.7320E0 75.22E0 6.7270E0 79.33E0 7.8350E0 83.56E0 9.0250E0 87.75E0 10.2670E0 91.93E0 11.5780E0 96.10E0 12.9440E0 100.28E0 14.3770E0 104.46E0 15.8560E0 108.66E0 17.3310E0 112.71E0 18.8850E0 116.88E0 20.5750E0 121.33E0 22.3200E0 125.79E0 22.3030E0 125.79E0 23.4600E0 128.74E0 24.0600E0 130.27E0 25.2720E0 133.33E0 25.8530E0 134.79E0 27.1100E0 137.93E0 27.6580E0 139.33E0 28.9240E0 142.46E0 29.5110E0 143.90E0 30.7100E0 146.91E0 31.3500E0 148.51E0 32.5200E0 151.41E0 33.2300E0 153.17E0 34.3300E0 155.97E0 35.0600E0 157.76E0 36.1700E0 160.56E0 36.8400E0 162.30E0 38.0100E0 165.21E0 38.6700E0 166.90E0 39.8700E0 169.92E0 40.0300E0 170.32E0 40.5000E0 171.54E0 41.3700E0 173.79E0 41.6700E0 174.57E0 42.3100E0 176.25E0 42.7300E0 177.34E0 43.4600E0 179.19E0 44.1400E0 181.02E0 44.5500E0 182.08E0 45.2200E0 183.88E0 45.9200E0 185.75E0 46.3000E0 186.80E0 47.0000E0 188.63E0 47.6800E0 190.45E0 48.0600E0 191.48E0 48.7400E0 193.35E0 49.4100E0 195.22E0 49.7600E0 196.23E0 50.4300E0 198.05E0 51.1100E0 199.97E0 51.5000E0 201.06E0 52.1200E0 202.83E0 52.7600E0 204.69E0 53.1800E0 205.86E0 53.7800E0 207.58E0 54.4600E0 209.50E0 54.8300E0 210.65E0 55.4000E0 212.33E0 56.4300E0 215.43E0 57.0300E0 217.16E0 58.0000E0 220.21E0 58.6100E0 221.98E0 59.5800E0 225.06E0 60.1100E0 226.79E0 61.1000E0 229.92E0 61.6500E0 231.69E0 62.5900E0 234.77E0 63.1200E0 236.60E0 64.0300E0 239.63E0 64.6200E0 241.50E0 65.4900E0 244.48E0 66.0300E0 246.40E0 66.8900E0 249.35E0 67.4200E0 251.32E0 68.2300E0 254.22E0 68.7700E0 256.24E0 69.5900E0 259.11E0 70.1100E0 261.18E0 70.8600E0 264.02E0 71.4300E0 266.13E0 72.1600E0 268.94E0 72.7000E0 271.09E0 73.4000E0 273.87E0 73.9300E0 276.08E0 74.6000E0 278.83E0 75.1600E0 281.08E0 75.8200E0 283.81E0 76.3400E0 286.11E0 76.9800E0 288.81E0 77.4800E0 291.08E0 78.0800E0 293.75E0 78.6000E0 295.99E0 79.1700E0 298.64E0 79.6200E0 300.84E0 79.8800E0 302.02E0 80.1900E0 303.48E0 80.6600E0 305.65E0 81.2200E0 308.27E0 81.6600E0 310.41E0 82.1600E0 313.01E0 82.5900E0 315.12E0 83.1400E0 317.71E0 83.5000E0 319.79E0 84.0000E0 322.36E0 84.4000E0 324.42E0 84.8900E0 326.98E0 85.2600E0 329.01E0 85.7400E0 331.56E0 86.0700E0 333.56E0 86.5400E0 336.10E0 86.8900E0 338.08E0 87.3200E0 340.60E0 87.6500E0 342.57E0 88.1000E0 345.08E0 88.4300E0 347.02E0 88.8300E0 349.52E0 89.1200E0 351.44E0 89.5400E0 353.93E0 89.8500E0 355.83E0 90.2500E0 358.32E0 90.5500E0 360.20E0 90.9300E0 362.67E0 91.2000E0 364.53E0 91.5500E0 367.00E0 92.2000E0 371.30E0 lmfit-0.9.7/NIST_STRD/Lanczos1.dat0000644000076500000240000000560413066042256017360 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Lanczos1 (Lanczos1.dat) File Format: ASCII Starting Values (lines 41 to 46) Certified Values (lines 41 to 51) Data (lines 61 to 84) Procedure: Nonlinear Least Squares Regression Description: These data are taken from an example discussed in Lanczos (1956). The data were generated to 14-digits of accuracy using f(x) = 0.0951*exp(-x) + 0.8607*exp(-3*x) + 1.5576*exp(-5*x). Reference: Lanczos, C. (1956). Applied Analysis. Englewood Cliffs, NJ: Prentice Hall, pp. 272-280. Data: 1 Response (y) 1 Predictor (x) 24 Observations Average Level of Difficulty Generated Data Model: Exponential Class 6 Parameters (b1 to b6) y = b1*exp(-b2*x) + b3*exp(-b4*x) + b5*exp(-b6*x) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 1.2 0.5 9.5100000027E-02 5.3347304234E-11 b2 = 0.3 0.7 1.0000000001E+00 2.7473038179E-10 b3 = 5.6 3.6 8.6070000013E-01 1.3576062225E-10 b4 = 5.5 4.2 3.0000000002E+00 3.3308253069E-10 b5 = 6.5 4 1.5575999998E+00 1.8815731448E-10 b6 = 7.6 6.3 5.0000000001E+00 1.1057500538E-10 Residual Sum of Squares: 1.4307867721E-25 Residual Standard Deviation: 8.9156129349E-14 Degrees of Freedom: 18 Number of Observations: 24 Data: y x 2.513400000000E+00 0.000000000000E+00 2.044333373291E+00 5.000000000000E-02 1.668404436564E+00 1.000000000000E-01 1.366418021208E+00 1.500000000000E-01 1.123232487372E+00 2.000000000000E-01 9.268897180037E-01 2.500000000000E-01 7.679338563728E-01 3.000000000000E-01 6.388775523106E-01 3.500000000000E-01 5.337835317402E-01 4.000000000000E-01 4.479363617347E-01 4.500000000000E-01 3.775847884350E-01 5.000000000000E-01 3.197393199326E-01 5.500000000000E-01 2.720130773746E-01 6.000000000000E-01 2.324965529032E-01 6.500000000000E-01 1.996589546065E-01 7.000000000000E-01 1.722704126914E-01 7.500000000000E-01 1.493405660168E-01 8.000000000000E-01 1.300700206922E-01 8.500000000000E-01 1.138119324644E-01 9.000000000000E-01 1.000415587559E-01 9.500000000000E-01 8.833209084540E-02 1.000000000000E+00 7.833544019350E-02 1.050000000000E+00 6.976693743449E-02 1.100000000000E+00 6.239312536719E-02 1.150000000000E+00 lmfit-0.9.7/NIST_STRD/Lanczos2.dat0000644000076500000240000000505513066042256017361 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Lanczos2 (Lanczos2.dat) File Format: ASCII Starting Values (lines 41 to 46) Certified Values (lines 41 to 51) Data (lines 61 to 84) Procedure: Nonlinear Least Squares Regression Description: These data are taken from an example discussed in Lanczos (1956). The data were generated to 6-digits of accuracy using f(x) = 0.0951*exp(-x) + 0.8607*exp(-3*x) + 1.5576*exp(-5*x). Reference: Lanczos, C. (1956). Applied Analysis. Englewood Cliffs, NJ: Prentice Hall, pp. 272-280. Data: 1 Response (y) 1 Predictor (x) 24 Observations Average Level of Difficulty Generated Data Model: Exponential Class 6 Parameters (b1 to b6) y = b1*exp(-b2*x) + b3*exp(-b4*x) + b5*exp(-b6*x) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 1.2 0.5 9.6251029939E-02 6.6770575477E-04 b2 = 0.3 0.7 1.0057332849E+00 3.3989646176E-03 b3 = 5.6 3.6 8.6424689056E-01 1.7185846685E-03 b4 = 5.5 4.2 3.0078283915E+00 4.1707005856E-03 b5 = 6.5 4 1.5529016879E+00 2.3744381417E-03 b6 = 7.6 6.3 5.0028798100E+00 1.3958787284E-03 Residual Sum of Squares: 2.2299428125E-11 Residual Standard Deviation: 1.1130395851E-06 Degrees of Freedom: 18 Number of Observations: 24 Data: y x 2.51340E+00 0.00000E+00 2.04433E+00 5.00000E-02 1.66840E+00 1.00000E-01 1.36642E+00 1.50000E-01 1.12323E+00 2.00000E-01 9.26890E-01 2.50000E-01 7.67934E-01 3.00000E-01 6.38878E-01 3.50000E-01 5.33784E-01 4.00000E-01 4.47936E-01 4.50000E-01 3.77585E-01 5.00000E-01 3.19739E-01 5.50000E-01 2.72013E-01 6.00000E-01 2.32497E-01 6.50000E-01 1.99659E-01 7.00000E-01 1.72270E-01 7.50000E-01 1.49341E-01 8.00000E-01 1.30070E-01 8.50000E-01 1.13812E-01 9.00000E-01 1.00042E-01 9.50000E-01 8.83321E-02 1.00000E+00 7.83354E-02 1.05000E+00 6.97669E-02 1.10000E+00 6.23931E-02 1.15000E+00 lmfit-0.9.7/NIST_STRD/Lanczos3.dat0000644000076500000240000000502113066042256017353 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Lanczos3 (Lanczos3.dat) File Format: ASCII Starting Values (lines 41 to 46) Certified Values (lines 41 to 51) Data (lines 61 to 84) Procedure: Nonlinear Least Squares Regression Description: These data are taken from an example discussed in Lanczos (1956). The data were generated to 5-digits of accuracy using f(x) = 0.0951*exp(-x) + 0.8607*exp(-3*x) + 1.5576*exp(-5*x). Reference: Lanczos, C. (1956). Applied Analysis. Englewood Cliffs, NJ: Prentice Hall, pp. 272-280. Data: 1 Response (y) 1 Predictor (x) 24 Observations Lower Level of Difficulty Generated Data Model: Exponential Class 6 Parameters (b1 to b6) y = b1*exp(-b2*x) + b3*exp(-b4*x) + b5*exp(-b6*x) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 1.2 0.5 8.6816414977E-02 1.7197908859E-02 b2 = 0.3 0.7 9.5498101505E-01 9.7041624475E-02 b3 = 5.6 3.6 8.4400777463E-01 4.1488663282E-02 b4 = 5.5 4.2 2.9515951832E+00 1.0766312506E-01 b5 = 6.5 4 1.5825685901E+00 5.8371576281E-02 b6 = 7.6 6.3 4.9863565084E+00 3.4436403035E-02 Residual Sum of Squares: 1.6117193594E-08 Residual Standard Deviation: 2.9923229172E-05 Degrees of Freedom: 18 Number of Observations: 24 Data: y x 2.5134E+00 0.00000E+00 2.0443E+00 5.00000E-02 1.6684E+00 1.00000E-01 1.3664E+00 1.50000E-01 1.1232E+00 2.00000E-01 0.9269E+00 2.50000E-01 0.7679E+00 3.00000E-01 0.6389E+00 3.50000E-01 0.5338E+00 4.00000E-01 0.4479E+00 4.50000E-01 0.3776E+00 5.00000E-01 0.3197E+00 5.50000E-01 0.2720E+00 6.00000E-01 0.2325E+00 6.50000E-01 0.1997E+00 7.00000E-01 0.1723E+00 7.50000E-01 0.1493E+00 8.00000E-01 0.1301E+00 8.50000E-01 0.1138E+00 9.00000E-01 0.1000E+00 9.50000E-01 0.0883E+00 1.00000E+00 0.0783E+00 1.05000E+00 0.0698E+00 1.10000E+00 0.0624E+00 1.15000E+00 lmfit-0.9.7/NIST_STRD/MGH09.dat0000644000076500000240000000442213066042256016447 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: MGH09 (MGH09.dat) File Format: ASCII Starting Values (lines 41 to 44) Certified Values (lines 41 to 49) Data (lines 61 to 71) Procedure: Nonlinear Least Squares Regression Description: This problem was found to be difficult for some very good algorithms. There is a local minimum at (+inf, -14.07..., -inf, -inf) with final sum of squares 0.00102734.... See More, J. J., Garbow, B. S., and Hillstrom, K. E. (1981). Testing unconstrained optimization software. ACM Transactions on Mathematical Software. 7(1): pp. 17-41. Reference: Kowalik, J.S., and M. R. Osborne, (1978). Methods for Unconstrained Optimization Problems. New York, NY: Elsevier North-Holland. Data: 1 Response (y) 1 Predictor (x) 11 Observations Higher Level of Difficulty Generated Data Model: Rational Class (linear/quadratic) 4 Parameters (b1 to b4) y = b1*(x**2+x*b2) / (x**2+x*b3+b4) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 25 0.25 1.9280693458E-01 1.1435312227E-02 b2 = 39 0.39 1.9128232873E-01 1.9633220911E-01 b3 = 41.5 0.415 1.2305650693E-01 8.0842031232E-02 b4 = 39 0.39 1.3606233068E-01 9.0025542308E-02 Residual Sum of Squares: 3.0750560385E-04 Residual Standard Deviation: 6.6279236551E-03 Degrees of Freedom: 7 Number of Observations: 11 Data: y x 1.957000E-01 4.000000E+00 1.947000E-01 2.000000E+00 1.735000E-01 1.000000E+00 1.600000E-01 5.000000E-01 8.440000E-02 2.500000E-01 6.270000E-02 1.670000E-01 4.560000E-02 1.250000E-01 3.420000E-02 1.000000E-01 3.230000E-02 8.330000E-02 2.350000E-02 7.140000E-02 2.460000E-02 6.250000E-02 lmfit-0.9.7/NIST_STRD/MGH10.dat0000644000076500000240000000445113066042256016441 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: MGH10 (MGH10.dat) File Format: ASCII Starting Values (lines 41 to 43) Certified Values (lines 41 to 48) Data (lines 61 to 76) Procedure: Nonlinear Least Squares Regression Description: This problem was found to be difficult for some very good algorithms. See More, J. J., Garbow, B. S., and Hillstrom, K. E. (1981). Testing unconstrained optimization software. ACM Transactions on Mathematical Software. 7(1): pp. 17-41. Reference: Meyer, R. R. (1970). Theoretical and computational aspects of nonlinear regression. In Nonlinear Programming, Rosen, Mangasarian and Ritter (Eds). New York, NY: Academic Press, pp. 465-486. Data: 1 Response (y) 1 Predictor (x) 16 Observations Higher Level of Difficulty Generated Data Model: Exponential Class 3 Parameters (b1 to b3) y = b1 * exp[b2/(x+b3)] + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 2 0.02 5.6096364710E-03 1.5687892471E-04 b2 = 400000 4000 6.1813463463E+03 2.3309021107E+01 b3 = 25000 250 3.4522363462E+02 7.8486103508E-01 Residual Sum of Squares: 8.7945855171E+01 Residual Standard Deviation: 2.6009740065E+00 Degrees of Freedom: 13 Number of Observations: 16 Data: y x 3.478000E+04 5.000000E+01 2.861000E+04 5.500000E+01 2.365000E+04 6.000000E+01 1.963000E+04 6.500000E+01 1.637000E+04 7.000000E+01 1.372000E+04 7.500000E+01 1.154000E+04 8.000000E+01 9.744000E+03 8.500000E+01 8.261000E+03 9.000000E+01 7.030000E+03 9.500000E+01 6.005000E+03 1.000000E+02 5.147000E+03 1.050000E+02 4.427000E+03 1.100000E+02 3.820000E+03 1.150000E+02 3.307000E+03 1.200000E+02 2.872000E+03 1.250000E+02 lmfit-0.9.7/NIST_STRD/MGH17.dat0000644000076500000240000000601513066042256016446 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: MGH17 (MGH17.dat) File Format: ASCII Starting Values (lines 41 to 45) Certified Values (lines 41 to 50) Data (lines 61 to 93) Procedure: Nonlinear Least Squares Regression Description: This problem was found to be difficult for some very good algorithms. See More, J. J., Garbow, B. S., and Hillstrom, K. E. (1981). Testing unconstrained optimization software. ACM Transactions on Mathematical Software. 7(1): pp. 17-41. Reference: Osborne, M. R. (1972). Some aspects of nonlinear least squares calculations. In Numerical Methods for Nonlinear Optimization, Lootsma (Ed). New York, NY: Academic Press, pp. 171-189. Data: 1 Response (y) 1 Predictor (x) 33 Observations Average Level of Difficulty Generated Data Model: Exponential Class 5 Parameters (b1 to b5) y = b1 + b2*exp[-x*b4] + b3*exp[-x*b5] + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 50 0.5 3.7541005211E-01 2.0723153551E-03 b2 = 150 1.5 1.9358469127E+00 2.2031669222E-01 b3 = -100 -1 -1.4646871366E+00 2.2175707739E-01 b4 = 1 0.01 1.2867534640E-02 4.4861358114E-04 b5 = 2 0.02 2.2122699662E-02 8.9471996575E-04 Residual Sum of Squares: 5.4648946975E-05 Residual Standard Deviation: 1.3970497866E-03 Degrees of Freedom: 28 Number of Observations: 33 Data: y x 8.440000E-01 0.000000E+00 9.080000E-01 1.000000E+01 9.320000E-01 2.000000E+01 9.360000E-01 3.000000E+01 9.250000E-01 4.000000E+01 9.080000E-01 5.000000E+01 8.810000E-01 6.000000E+01 8.500000E-01 7.000000E+01 8.180000E-01 8.000000E+01 7.840000E-01 9.000000E+01 7.510000E-01 1.000000E+02 7.180000E-01 1.100000E+02 6.850000E-01 1.200000E+02 6.580000E-01 1.300000E+02 6.280000E-01 1.400000E+02 6.030000E-01 1.500000E+02 5.800000E-01 1.600000E+02 5.580000E-01 1.700000E+02 5.380000E-01 1.800000E+02 5.220000E-01 1.900000E+02 5.060000E-01 2.000000E+02 4.900000E-01 2.100000E+02 4.780000E-01 2.200000E+02 4.670000E-01 2.300000E+02 4.570000E-01 2.400000E+02 4.480000E-01 2.500000E+02 4.380000E-01 2.600000E+02 4.310000E-01 2.700000E+02 4.240000E-01 2.800000E+02 4.200000E-01 2.900000E+02 4.140000E-01 3.000000E+02 4.110000E-01 3.100000E+02 4.060000E-01 3.200000E+02 lmfit-0.9.7/NIST_STRD/Misra1a.dat0000644000076500000240000000350213066042256017156 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Misra1a (Misra1a.dat) File Format: ASCII Starting Values (lines 41 to 42) Certified Values (lines 41 to 47) Data (lines 61 to 74) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study regarding dental research in monomolecular adsorption. The response variable is volume, and the predictor variable is pressure. Reference: Misra, D., NIST (1978). Dental Research Monomolecular Adsorption Study. Data: 1 Response Variable (y = volume) 1 Predictor Variable (x = pressure) 14 Observations Lower Level of Difficulty Observed Data Model: Exponential Class 2 Parameters (b1 and b2) y = b1*(1-exp[-b2*x]) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 500 250 2.3894212918E+02 2.7070075241E+00 b2 = 0.0001 0.0005 5.5015643181E-04 7.2668688436E-06 Residual Sum of Squares: 1.2455138894E-01 Residual Standard Deviation: 1.0187876330E-01 Degrees of Freedom: 12 Number of Observations: 14 Data: y x 10.07E0 77.6E0 14.73E0 114.9E0 17.94E0 141.1E0 23.93E0 190.8E0 29.61E0 239.9E0 35.18E0 289.0E0 40.02E0 332.8E0 44.82E0 378.4E0 50.76E0 434.8E0 55.05E0 477.3E0 61.01E0 536.8E0 66.40E0 593.1E0 75.47E0 689.1E0 81.78E0 760.0E0 lmfit-0.9.7/NIST_STRD/Misra1b.dat0000644000076500000240000000347213066042256017165 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Misra1b (Misra1b.dat) File Format: ASCII Starting Values (lines 41 to 42) Certified Values (lines 41 to 47) Data (lines 61 to 74) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study regarding dental research in monomolecular adsorption. The response variable is volume, and the predictor variable is pressure. Reference: Misra, D., NIST (1978). Dental Research Monomolecular Adsorption Study. Data: 1 Response (y = volume) 1 Predictor (x = pressure) 14 Observations Lower Level of Difficulty Observed Data Model: Miscellaneous Class 2 Parameters (b1 and b2) y = b1 * (1-(1+b2*x/2)**(-2)) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 500 300 3.3799746163E+02 3.1643950207E+00 b2 = 0.0001 0.0002 3.9039091287E-04 4.2547321834E-06 Residual Sum of Squares: 7.5464681533E-02 Residual Standard Deviation: 7.9301471998E-02 Degrees of Freedom: 12 Number of Observations: 14 Data: y x 10.07E0 77.6E0 14.73E0 114.9E0 17.94E0 141.1E0 23.93E0 190.8E0 29.61E0 239.9E0 35.18E0 289.0E0 40.02E0 332.8E0 44.82E0 378.4E0 50.76E0 434.8E0 55.05E0 477.3E0 61.01E0 536.8E0 66.40E0 593.1E0 75.47E0 689.1E0 81.78E0 760.0E0 lmfit-0.9.7/NIST_STRD/Misra1c.dat0000644000076500000240000000350213066042256017160 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Misra1c (Misra1c.dat) File Format: ASCII Starting Values (lines 41 to 42) Certified Values (lines 41 to 47) Data (lines 61 to 74) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study regarding dental research in monomolecular adsorption. The response variable is volume, and the predictor variable is pressure. Reference: Misra, D., NIST (1978). Dental Research Monomolecular Adsorption. Data: 1 Response (y = volume) 1 Predictor (x = pressure) 14 Observations Average Level of Difficulty Observed Data Model: Miscellaneous Class 2 Parameters (b1 and b2) y = b1 * (1-(1+2*b2*x)**(-.5)) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 500 600 6.3642725809E+02 4.6638326572E+00 b2 = 0.0001 0.0002 2.0813627256E-04 1.7728423155E-06 Residual Sum of Squares: 4.0966836971E-02 Residual Standard Deviation: 5.8428615257E-02 Degrees of Freedom: 12 Number of Observations: 14 Data: y x 10.07E0 77.6E0 14.73E0 114.9E0 17.94E0 141.1E0 23.93E0 190.8E0 29.61E0 239.9E0 35.18E0 289.0E0 40.02E0 332.8E0 44.82E0 378.4E0 50.76E0 434.8E0 55.05E0 477.3E0 61.01E0 536.8E0 66.40E0 593.1E0 75.47E0 689.1E0 81.78E0 760.0E0 lmfit-0.9.7/NIST_STRD/Misra1d.dat0000644000076500000240000000346513066042256017171 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Misra1d (Misra1d.dat) File Format: ASCII Starting Values (lines 41 to 42) Certified Values (lines 41 to 47) Data (lines 61 to 74) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study regarding dental research in monomolecular adsorption. The response variable is volume, and the predictor variable is pressure. Reference: Misra, D., NIST (1978). Dental Research Monomolecular Adsorption Study. Data: 1 Response (y = volume) 1 Predictor (x = pressure) 14 Observations Average Level of Difficulty Observed Data Model: Miscellaneous Class 2 Parameters (b1 and b2) y = b1*b2*x*((1+b2*x)**(-1)) + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 500 450 4.3736970754E+02 3.6489174345E+00 b2 = 0.0001 0.0003 3.0227324449E-04 2.9334354479E-06 Residual Sum of Squares: 5.6419295283E-02 Residual Standard Deviation: 6.8568272111E-02 Degrees of Freedom: 12 Number of Observations: 14 Data: y x 10.07E0 77.6E0 14.73E0 114.9E0 17.94E0 141.1E0 23.93E0 190.8E0 29.61E0 239.9E0 35.18E0 289.0E0 40.02E0 332.8E0 44.82E0 378.4E0 50.76E0 434.8E0 55.05E0 477.3E0 61.01E0 536.8E0 66.40E0 593.1E0 75.47E0 689.1E0 81.78E0 760.0E0 lmfit-0.9.7/NIST_STRD/Nelson.dat0000644000076500000240000001553613066042256017131 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Nelson (Nelson.dat) File Format: ASCII Starting Values (lines 41 to 43) Certified Values (lines 41 to 48) Data (lines 61 to 188) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a study involving the analysis of performance degradation data from accelerated tests, published in IEEE Transactions on Reliability. The response variable is dialectric breakdown strength in kilo-volts, and the predictor variables are time in weeks and temperature in degrees Celcius. Reference: Nelson, W. (1981). Analysis of Performance-Degradation Data. IEEE Transactions on Reliability. Vol. 2, R-30, No. 2, pp. 149-155. Data: 1 Response ( y = dialectric breakdown strength) 2 Predictors (x1 = time; x2 = temperature) 128 Observations Average Level of Difficulty Observed Data Model: Exponential Class 3 Parameters (b1 to b3) log[y] = b1 - b2*x1 * exp[-b3*x2] + e Starting values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 2 2.5 2.5906836021E+00 1.9149996413E-02 b2 = 0.0001 0.000000005 5.6177717026E-09 6.1124096540E-09 b3 = -0.01 -0.05 -5.7701013174E-02 3.9572366543E-03 Residual Sum of Squares: 3.7976833176E+00 Residual Standard Deviation: 1.7430280130E-01 Degrees of Freedom: 125 Number of Observations: 128 Data: y x1 x2 15.00E0 1E0 180E0 17.00E0 1E0 180E0 15.50E0 1E0 180E0 16.50E0 1E0 180E0 15.50E0 1E0 225E0 15.00E0 1E0 225E0 16.00E0 1E0 225E0 14.50E0 1E0 225E0 15.00E0 1E0 250E0 14.50E0 1E0 250E0 12.50E0 1E0 250E0 11.00E0 1E0 250E0 14.00E0 1E0 275E0 13.00E0 1E0 275E0 14.00E0 1E0 275E0 11.50E0 1E0 275E0 14.00E0 2E0 180E0 16.00E0 2E0 180E0 13.00E0 2E0 180E0 13.50E0 2E0 180E0 13.00E0 2E0 225E0 13.50E0 2E0 225E0 12.50E0 2E0 225E0 12.50E0 2E0 225E0 12.50E0 2E0 250E0 12.00E0 2E0 250E0 11.50E0 2E0 250E0 12.00E0 2E0 250E0 13.00E0 2E0 275E0 11.50E0 2E0 275E0 13.00E0 2E0 275E0 12.50E0 2E0 275E0 13.50E0 4E0 180E0 17.50E0 4E0 180E0 17.50E0 4E0 180E0 13.50E0 4E0 180E0 12.50E0 4E0 225E0 12.50E0 4E0 225E0 15.00E0 4E0 225E0 13.00E0 4E0 225E0 12.00E0 4E0 250E0 13.00E0 4E0 250E0 12.00E0 4E0 250E0 13.50E0 4E0 250E0 10.00E0 4E0 275E0 11.50E0 4E0 275E0 11.00E0 4E0 275E0 9.50E0 4E0 275E0 15.00E0 8E0 180E0 15.00E0 8E0 180E0 15.50E0 8E0 180E0 16.00E0 8E0 180E0 13.00E0 8E0 225E0 10.50E0 8E0 225E0 13.50E0 8E0 225E0 14.00E0 8E0 225E0 12.50E0 8E0 250E0 12.00E0 8E0 250E0 11.50E0 8E0 250E0 11.50E0 8E0 250E0 6.50E0 8E0 275E0 5.50E0 8E0 275E0 6.00E0 8E0 275E0 6.00E0 8E0 275E0 18.50E0 16E0 180E0 17.00E0 16E0 180E0 15.30E0 16E0 180E0 16.00E0 16E0 180E0 13.00E0 16E0 225E0 14.00E0 16E0 225E0 12.50E0 16E0 225E0 11.00E0 16E0 225E0 12.00E0 16E0 250E0 12.00E0 16E0 250E0 11.50E0 16E0 250E0 12.00E0 16E0 250E0 6.00E0 16E0 275E0 6.00E0 16E0 275E0 5.00E0 16E0 275E0 5.50E0 16E0 275E0 12.50E0 32E0 180E0 13.00E0 32E0 180E0 16.00E0 32E0 180E0 12.00E0 32E0 180E0 11.00E0 32E0 225E0 9.50E0 32E0 225E0 11.00E0 32E0 225E0 11.00E0 32E0 225E0 11.00E0 32E0 250E0 10.00E0 32E0 250E0 10.50E0 32E0 250E0 10.50E0 32E0 250E0 2.70E0 32E0 275E0 2.70E0 32E0 275E0 2.50E0 32E0 275E0 2.40E0 32E0 275E0 13.00E0 48E0 180E0 13.50E0 48E0 180E0 16.50E0 48E0 180E0 13.60E0 48E0 180E0 11.50E0 48E0 225E0 10.50E0 48E0 225E0 13.50E0 48E0 225E0 12.00E0 48E0 225E0 7.00E0 48E0 250E0 6.90E0 48E0 250E0 8.80E0 48E0 250E0 7.90E0 48E0 250E0 1.20E0 48E0 275E0 1.50E0 48E0 275E0 1.00E0 48E0 275E0 1.50E0 48E0 275E0 13.00E0 64E0 180E0 12.50E0 64E0 180E0 16.50E0 64E0 180E0 16.00E0 64E0 180E0 11.00E0 64E0 225E0 11.50E0 64E0 225E0 10.50E0 64E0 225E0 10.00E0 64E0 225E0 7.27E0 64E0 250E0 7.50E0 64E0 250E0 6.70E0 64E0 250E0 7.60E0 64E0 250E0 1.50E0 64E0 275E0 1.00E0 64E0 275E0 1.20E0 64E0 275E0 1.20E0 64E0 275E0 lmfit-0.9.7/NIST_STRD/Rat42.dat0000644000076500000240000000352413066042256016561 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Rat42 (Rat42.dat) File Format: ASCII Starting Values (lines 41 to 43) Certified Values (lines 41 to 48) Data (lines 61 to 69) Procedure: Nonlinear Least Squares Regression Description: This model and data are an example of fitting sigmoidal growth curves taken from Ratkowsky (1983). The response variable is pasture yield, and the predictor variable is growing time. Reference: Ratkowsky, D.A. (1983). Nonlinear Regression Modeling. New York, NY: Marcel Dekker, pp. 61 and 88. Data: 1 Response (y = pasture yield) 1 Predictor (x = growing time) 9 Observations Higher Level of Difficulty Observed Data Model: Exponential Class 3 Parameters (b1 to b3) y = b1 / (1+exp[b2-b3*x]) + e Starting Values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 100 75 7.2462237576E+01 1.7340283401E+00 b2 = 1 2.5 2.6180768402E+00 8.8295217536E-02 b3 = 0.1 0.07 6.7359200066E-02 3.4465663377E-03 Residual Sum of Squares: 8.0565229338E+00 Residual Standard Deviation: 1.1587725499E+00 Degrees of Freedom: 6 Number of Observations: 9 Data: y x 8.930E0 9.000E0 10.800E0 14.000E0 18.590E0 21.000E0 22.330E0 28.000E0 39.350E0 42.000E0 56.110E0 57.000E0 61.730E0 63.000E0 64.620E0 70.000E0 67.080E0 79.000E0 lmfit-0.9.7/NIST_STRD/Rat43.dat0000644000076500000240000000405513066042256016562 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Rat43 (Rat43.dat) File Format: ASCII Starting Values (lines 41 to 44) Certified Values (lines 41 to 49) Data (lines 61 to 75) Procedure: Nonlinear Least Squares Regression Description: This model and data are an example of fitting sigmoidal growth curves taken from Ratkowsky (1983). The response variable is the dry weight of onion bulbs and tops, and the predictor variable is growing time. Reference: Ratkowsky, D.A. (1983). Nonlinear Regression Modeling. New York, NY: Marcel Dekker, pp. 62 and 88. Data: 1 Response (y = onion bulb dry weight) 1 Predictor (x = growing time) 15 Observations Higher Level of Difficulty Observed Data Model: Exponential Class 4 Parameters (b1 to b4) y = b1 / ((1+exp[b2-b3*x])**(1/b4)) + e Starting Values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 100 700 6.9964151270E+02 1.6302297817E+01 b2 = 10 5 5.2771253025E+00 2.0828735829E+00 b3 = 1 0.75 7.5962938329E-01 1.9566123451E-01 b4 = 1 1.3 1.2792483859E+00 6.8761936385E-01 Residual Sum of Squares: 8.7864049080E+03 Residual Standard Deviation: 2.8262414662E+01 Degrees of Freedom: 9 Number of Observations: 15 Data: y x 16.08E0 1.0E0 33.83E0 2.0E0 65.80E0 3.0E0 97.20E0 4.0E0 191.55E0 5.0E0 326.20E0 6.0E0 386.87E0 7.0E0 520.53E0 8.0E0 590.03E0 9.0E0 651.92E0 10.0E0 724.93E0 11.0E0 699.56E0 12.0E0 689.96E0 13.0E0 637.56E0 14.0E0 717.41E0 15.0E0 lmfit-0.9.7/NIST_STRD/Roszman1.dat0000644000076500000240000000467013066042256017402 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Roszman1 (Roszman1.dat) File Format: ASCII Starting Values (lines 41 to 44) Certified Values (lines 41 to 49) Data (lines 61 to 85) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving quantum defects in iodine atoms. The response variable is the number of quantum defects, and the predictor variable is the excited energy state. The argument to the ARCTAN function is in radians. Reference: Roszman, L., NIST (19??). Quantum Defects for Sulfur I Atom. Data: 1 Response (y = quantum defect) 1 Predictor (x = excited state energy) 25 Observations Average Level of Difficulty Observed Data Model: Miscellaneous Class 4 Parameters (b1 to b4) pi = 3.141592653589793238462643383279E0 y = b1 - b2*x - arctan[b3/(x-b4)]/pi + e Starting Values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 0.1 0.2 2.0196866396E-01 1.9172666023E-02 b2 = -0.00001 -0.000005 -6.1953516256E-06 3.2058931691E-06 b3 = 1000 1200 1.2044556708E+03 7.4050983057E+01 b4 = -100 -150 -1.8134269537E+02 4.9573513849E+01 Residual Sum of Squares: 4.9484847331E-04 Residual Standard Deviation: 4.8542984060E-03 Degrees of Freedom: 21 Number of Observations: 25 Data: y x 0.252429 -4868.68 0.252141 -4868.09 0.251809 -4867.41 0.297989 -3375.19 0.296257 -3373.14 0.295319 -3372.03 0.339603 -2473.74 0.337731 -2472.35 0.333820 -2469.45 0.389510 -1894.65 0.386998 -1893.40 0.438864 -1497.24 0.434887 -1495.85 0.427893 -1493.41 0.471568 -1208.68 0.461699 -1206.18 0.461144 -1206.04 0.513532 -997.92 0.506641 -996.61 0.505062 -996.31 0.535648 -834.94 0.533726 -834.66 0.568064 -710.03 0.612886 -530.16 0.624169 -464.17 lmfit-0.9.7/NIST_STRD/Thurber.dat0000644000076500000240000000572713066042256017307 0ustar Newvillestaff00000000000000NIST/ITL StRD Dataset Name: Thurber (Thurber.dat) File Format: ASCII Starting Values (lines 41 to 47) Certified Values (lines 41 to 52) Data (lines 61 to 97) Procedure: Nonlinear Least Squares Regression Description: These data are the result of a NIST study involving semiconductor electron mobility. The response variable is a measure of electron mobility, and the predictor variable is the natural log of the density. Reference: Thurber, R., NIST (197?). Semiconductor electron mobility modeling. Data: 1 Response Variable (y = electron mobility) 1 Predictor Variable (x = log[density]) 37 Observations Higher Level of Difficulty Observed Data Model: Rational Class (cubic/cubic) 7 Parameters (b1 to b7) y = (b1 + b2*x + b3*x**2 + b4*x**3) / (1 + b5*x + b6*x**2 + b7*x**3) + e Starting Values Certified Values Start 1 Start 2 Parameter Standard Deviation b1 = 1000 1300 1.2881396800E+03 4.6647963344E+00 b2 = 1000 1500 1.4910792535E+03 3.9571156086E+01 b3 = 400 500 5.8323836877E+02 2.8698696102E+01 b4 = 40 75 7.5416644291E+01 5.5675370270E+00 b5 = 0.7 1 9.6629502864E-01 3.1333340687E-02 b6 = 0.3 0.4 3.9797285797E-01 1.4984928198E-02 b7 = 0.03 0.05 4.9727297349E-02 6.5842344623E-03 Residual Sum of Squares: 5.6427082397E+03 Residual Standard Deviation: 1.3714600784E+01 Degrees of Freedom: 30 Number of Observations: 37 Data: y x 80.574E0 -3.067E0 84.248E0 -2.981E0 87.264E0 -2.921E0 87.195E0 -2.912E0 89.076E0 -2.840E0 89.608E0 -2.797E0 89.868E0 -2.702E0 90.101E0 -2.699E0 92.405E0 -2.633E0 95.854E0 -2.481E0 100.696E0 -2.363E0 101.060E0 -2.322E0 401.672E0 -1.501E0 390.724E0 -1.460E0 567.534E0 -1.274E0 635.316E0 -1.212E0 733.054E0 -1.100E0 759.087E0 -1.046E0 894.206E0 -0.915E0 990.785E0 -0.714E0 1090.109E0 -0.566E0 1080.914E0 -0.545E0 1122.643E0 -0.400E0 1178.351E0 -0.309E0 1260.531E0 -0.109E0 1273.514E0 -0.103E0 1288.339E0 0.010E0 1327.543E0 0.119E0 1353.863E0 0.377E0 1414.509E0 0.790E0 1425.208E0 0.963E0 1421.384E0 1.006E0 1442.962E0 1.115E0 1464.350E0 1.572E0 1468.705E0 1.841E0 1447.894E0 2.047E0 1457.628E0 2.200E0 lmfit-0.9.7/PKG-INFO0000644000076500000240000000327113114357470014657 0ustar Newvillestaff00000000000000Metadata-Version: 1.1 Name: lmfit Version: 0.9.7 Summary: Least-Squares Minimization with Bounds and Constraints Home-page: http://lmfit.github.io/lmfit-py/ Author: LMFit Development Team Author-email: matt.newville@gmail.com License: BSD Download-URL: http://lmfit.github.io//lmfit-py/ Description: A library for least-squares minimization and data fitting in Python. Built on top of scipy.optimize, lmfit provides a Parameter object which can be set as fixed or free, can have upper and/or lower bounds, or can be written in terms of algebraic constraints of other Parameters. The user writes a function to be minimized as a function of these Parameters, and the scipy.optimize methods are used to find the optimal values for the Parameters. The Levenberg-Marquardt (leastsq) is the default minimization algorithm, and provides estimated standard errors and correlations between varied Parameters. Other minimization methods, including Nelder-Mead's downhill simplex, Powell's method, BFGS, Sequential Least Squares, and others are also supported. Bounds and contraints can be placed on Parameters for all of these methods. In addition, methods for explicitly calculating confidence intervals are provided for exploring minmization problems where the approximation of estimating Parameter uncertainties from the covariance matrix is questionable. Platform: Windows Platform: Linux Platform: Mac OS X Classifier: Intended Audience :: Science/Research Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Scientific/Engineering lmfit-0.9.7/publish_docs.sh0000644000076500000240000000170213066042256016570 0ustar Newvillestaff00000000000000installdir='/www/apache/htdocs/software/python/lmfit' docbuild='doc/_build' cd doc echo '# Making docs' make all cd ../ echo '# Building tarball of docs' mkdir _tmpdoc cp -pr doc/lmfit.pdf _tmpdoc/lmfit.pdf cp -pr doc/_build/html/* _tmpdoc/. cd _tmpdoc tar czf ../../lmfit_docs.tar.gz . cd .. rm -rf _tmpdoc # echo "# Switching to gh-pages branch" git checkout gh-pages if [ $? -ne 0 ] ; then echo ' failed.' exit fi tar xzf ../lmfit_docs.tar.gz . echo "# commit changes to gh-pages branch" git commit -am "changed docs" if [ $? -ne 0 ] ; then echo ' failed.' exit fi echo "# Pushing docs to github" git push echo "# switch back to master branch" git checkout master if [ $? -ne 0 ] ; then echo ' failed.' exit fi # install locally echo "# Installing docs to CARS web pages" cp ../lmfit_docs.tar.gz $installdir/.. cd $installdir if [ $? -ne 0 ] ; then echo ' failed.' exit fi tar xvzf ../lmfit_docs.tar.gz lmfit-0.9.7/README.rst0000644000076500000240000000702313066042256015247 0ustar Newvillestaff00000000000000LMfit-py ======== .. image:: https://travis-ci.org/lmfit/lmfit-py.png :target: https://travis-ci.org/lmfit/lmfit-py .. image:: https://zenodo.org/badge/4185/lmfit/lmfit-py.svg :target: https://zenodo.org/badge/latestdoi/4185/lmfit/lmfit-py Overview --------- LMfit-py provides a Least-Squares Minimization routine and class with a simple, flexible approach to parameterizing a model for fitting to data. LMfit is a pure python package, and so easy to install from source or with ``pip install lmfit``. For questions, comments, and suggestions, please use the LMfit mailing list, https://groups.google.com/group/lmfit-py. Using the bug tracking software in GitHub Issues is encouraged for known problems and bug reports. Please read `Contributing.md <.github/CONTRIBUTING.md>`_ before creating an Issue. Parameters and Fitting ------------------------- LMfit-py provides a Least-Squares Minimization routine and class with a simple, flexible approach to parameterizing a model for fitting to data. Named Parameters can be held fixed or freely adjusted in the fit, or held between lower and upper bounds. In addition, parameters can be constrained as a simple mathematical expression of other Parameters. To do this, the programmer defines a Parameters object, an enhanced dictionary, containing named parameters:: fit_params = Parameters() fit_params['amp'] = Parameter(value=1.2, min=0.1, max=1000) fit_params['cen'] = Parameter(value=40.0, vary=False) fit_params['wid'] = Parameter(value=4, min=0) or using the equivalent:: fit_params = Parameters() fit_params.add('amp', value=1.2, min=0.1, max=1000) fit_params.add('cen', value=40.0, vary=False) fit_params.add('wid', value=4, min=0) The programmer will also write a function to be minimized (in the least-squares sense) with its first argument being this Parameters object, and additional positional and keyword arguments as desired:: def myfunc(params, x, data, someflag=True): amp = params['amp'].value cen = params['cen'].value wid = params['wid'].value ... return residual_array For each call of this function, the values for the params may have changed, subject to the bounds and constraint settings for each Parameter. The function should return the residual (ie, data-model) array to be minimized. The advantage here is that the function to be minimized does not have to be changed if different bounds or constraints are placed on the fitting Parameters. The fitting model (as described in myfunc) is instead written in terms of physical parameters of the system, and remains remains independent of what is actually varied in the fit. In addition, which parameters are adjusted and which are fixed happens at run-time, so that changing what is varied and what constraints are placed on the parameters can easily be modified by the consumer in real-time data analysis. To perform the fit, the user calls:: result = minimize(myfunc, fit_params, args=(x, data), kws={'someflag':True}, ....) After the fit, each real variable in the ``fit_params`` dictionary is updated to have best-fit values, estimated standard deviations, and correlations with other variables in the fit, while the results dictionary holds fit statistics and information. By default, the underlying fit algorithm is the Levenberg-Marquart algorithm with numerically-calculated derivatives from MINPACK's lmdif function, as used by ``scipy.optimize.leastsq``. Other solvers (Nelder-Mead, etc) are also available, though slightly less well-tested and supported. lmfit-0.9.7/requirements.txt0000644000076500000240000000004413113304521017025 0ustar Newvillestaff00000000000000six>1.10 numpy>=1.9.1 scipy>=0.15.1 lmfit-0.9.7/setup.cfg0000644000076500000240000000032713114357470015402 0ustar Newvillestaff00000000000000[versioneer] vcs = git style = pep440 versionfile_source = lmfit/_version.py versionfile_build = lmfit/_version.py tag_prefix = parentdir_prefix = lmfit- [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 lmfit-0.9.7/setup.py0000644000076500000240000000472113113304637015271 0ustar Newvillestaff00000000000000#!/usr/bin/env python # from distutils.core import setup from __future__ import print_function import sys from setuptools import setup import versioneer # Minimal Python version sanity check # taken from the Jupyter Notebook setup.py -- Modified BSD License v = sys.version_info if v[:2] < (2, 7) or (v[0] >= 3 and v[:2] < (3, 3)): error = "ERROR: lmfit requires Python version 2.7 or 3.3 or above." print(error, file=sys.stderr) sys.exit(1) long_desc = """A library for least-squares minimization and data fitting in Python. Built on top of scipy.optimize, lmfit provides a Parameter object which can be set as fixed or free, can have upper and/or lower bounds, or can be written in terms of algebraic constraints of other Parameters. The user writes a function to be minimized as a function of these Parameters, and the scipy.optimize methods are used to find the optimal values for the Parameters. The Levenberg-Marquardt (leastsq) is the default minimization algorithm, and provides estimated standard errors and correlations between varied Parameters. Other minimization methods, including Nelder-Mead's downhill simplex, Powell's method, BFGS, Sequential Least Squares, and others are also supported. Bounds and contraints can be placed on Parameters for all of these methods. In addition, methods for explicitly calculating confidence intervals are provided for exploring minmization problems where the approximation of estimating Parameter uncertainties from the covariance matrix is questionable. """ setup(name = 'lmfit', version = versioneer.get_version(), cmdclass = versioneer.get_cmdclass(), author = 'LMFit Development Team', author_email = 'matt.newville@gmail.com', url = 'http://lmfit.github.io/lmfit-py/', download_url = 'http://lmfit.github.io//lmfit-py/', install_requires = ['numpy', 'scipy', 'six'], license = 'BSD', description = "Least-Squares Minimization with Bounds and Constraints", long_description = long_desc, platforms = ['Windows', 'Linux', 'Mac OS X'], classifiers=['Intended Audience :: Science/Research', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Scientific/Engineering', ], # test_suite='nose.collector', # test_requires=['Nose'], package_dir = {'lmfit': 'lmfit'}, packages = ['lmfit', 'lmfit.ui', 'lmfit.uncertainties'], ) lmfit-0.9.7/tests/0000755000076500000240000000000013114357470014721 5ustar Newvillestaff00000000000000lmfit-0.9.7/tests/_test_ci.py0000644000076500000240000000320313066042256017061 0ustar Newvillestaff00000000000000from __future__ import print_function from lmfit import minimize, Parameters, conf_interval, report_ci, report_errors import numpy as np pi = np.pi import nose def test_ci(): np.random.seed(1) p_true = Parameters() p_true.add('amp', value=14.0) p_true.add('period', value=5.33) p_true.add('shift', value=0.123) p_true.add('decay', value=0.010) def residual(pars, x, data=None): amp = pars['amp'] per = pars['period'] shift = pars['shift'] decay = pars['decay'] if abs(shift) > pi / 2: shift = shift - np.sign(shift) * pi model = amp * np.sin(shift + x / per) * np.exp(-x * x * decay * decay) if data is None: return model return model - data n = 2500 xmin = 0. xmax = 250.0 noise = np.random.normal(scale=0.7215, size=n) x = np.linspace(xmin, xmax, n) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=13.0) fit_params.add('period', value=4) fit_params.add('shift', value=0.1) fit_params.add('decay', value=0.02) out = minimize(residual, fit_params, args=(x,), kws={'data': data}) fit = residual(fit_params, x) print( ' N fev = ', out.nfev) print( out.chisqr, out.redchi, out.nfree) report_errors(fit_params) ci, tr = conf_interval(out, sigmas=[0.674], trace=True) report_ci(ci) for p in out.params: diff1 = ci[p][1][1] - ci[p][0][1] diff2 = ci[p][2][1] - ci[p][1][1] stderr = out.params[p].stderr assert(abs(diff1 - stderr) / stderr < 0.05) assert(abs(diff2 - stderr) / stderr < 0.05) lmfit-0.9.7/tests/_test_make_paras_and_func.py0000644000076500000240000000131713066042256022432 0ustar Newvillestaff00000000000000# -*- coding: utf-8 -*- import lmfit def test_wrap_function(): get_names = lambda p: [p_key for p_key in p ] def func(A, b, c, d=5, e=10): return A + b + c + d x0 = [1, 2, 3] para, f = lmfit.make_paras_and_func(func, x0) assert(get_names(para) == ['A', 'b', 'c']) y1 = f(para) y2 = func(*x0) assert(y1==y2) x0 = [1, 2, 3, 4] para, f = lmfit.make_paras_and_func(func, x0) assert(get_names(para) == ['A', 'b', 'c', 'd']) y1 = f(para) y2 = func(*x0) assert(y1==y2) x0 = [1, 2, 3] para, f = lmfit.make_paras_and_func(func, x0, {'e': 3}) assert(get_names(para) == ['A', 'b', 'c', 'e']) y1 = f(para) y2 = func(*x0) assert(y1==y2) lmfit-0.9.7/tests/lmfit_testutils.py0000644000076500000240000000107313066042256020526 0ustar Newvillestaff00000000000000from lmfit import Parameter from numpy.testing import assert_allclose def assert_paramval(param, val, tol=1.e-3): """assert that a named parameter's value is close to expected value""" assert(isinstance(param, Parameter)) pval = param.value assert_allclose([pval], [val], rtol=tol, atol=tol, err_msg='',verbose=True) def assert_paramattr(param, attr, val): """assert that a named parameter's value is a value""" assert(isinstance(param, Parameter)) assert(hasattr(param, attr)) assert(getattr(param, attr) == val) lmfit-0.9.7/tests/NISTModels.py0000644000076500000240000001353613066042256017223 0ustar Newvillestaff00000000000000import os import sys from numpy import exp, log, log10, sin, cos, arctan, array from lmfit import Parameters thisdir, thisfile = os.path.split(__file__) NIST_DIR = os.path.join(thisdir, '..', 'NIST_STRD') def read_params(params): if isinstance(params, Parameters): return [par.value for par in params.values()] else: return params def Bennet5(b, x, y=0): b = read_params(b) return y - b[0] * (b[1]+x)**(-1/b[2]) def BoxBOD(b, x, y=0): b = read_params(b) return y - b[0]*(1-exp(-b[1]*x)) def Chwirut(b, x, y=0): b = read_params(b) return y - exp(-b[0]*x)/(b[1]+b[2]*x) def DanWood(b, x, y=0): b = read_params(b) return y - b[0]*x**b[1] def ENSO(b, x, y=0): b = read_params(b) pi = 3.141592653589793238462643383279 return y - b[0] + (b[1]*cos( 2*pi*x/12 ) + b[2]*sin( 2*pi*x/12 ) + b[4]*cos( 2*pi*x/b[3] ) + b[5]*sin( 2*pi*x/b[3] ) + b[7]*cos( 2*pi*x/b[6] ) + b[8]*sin( 2*pi*x/b[6] ) ) def Eckerle4(b, x, y=0): b = read_params(b) return y - (b[0]/b[1]) * exp(-0.5*((x-b[2])/b[1])**2) def Gauss(b, x, y=0): b = read_params(b) return y - b[0]*exp( -b[1]*x ) + (b[2]*exp( -(x-b[3])**2 / b[4]**2 ) + b[5]*exp( -(x-b[6])**2 / b[7]**2 ) ) def Hahn1(b, x, y=0): b = read_params(b) return y - ((b[0]+b[1]*x+b[2]*x**2+b[3]*x**3) / (1+b[4]*x+b[5]*x**2+b[6]*x**3) ) def Kirby(b, x, y=0): b = read_params(b) return y - (b[0] + b[1]*x + b[2]*x**2) / (1 + b[3]*x + b[4]*x**2) def Lanczos(b, x, y=0): b = read_params(b) return y - b[0]*exp(-b[1]*x) + b[2]*exp(-b[3]*x) + b[4]*exp(-b[5]*x) def MGH09(b, x, y=0): b = read_params(b) return y - b[0]*(x**2+x*b[1]) / (x**2+x*b[2]+b[3]) def MGH10(b, x, y=0): b = read_params(b) return y - b[0] * exp( b[1]/(x+b[2]) ) def MGH17(b, x, y=0): b = read_params(b) return y - b[0] + b[1]*exp(-x*b[3]) + b[2]*exp(-x*b[4]) def Misra1a(b, x, y=0): b = read_params(b) return y - b[0]*(1-exp(-b[1]*x)) def Misra1b(b, x, y=0): b = read_params(b) return y - b[0] * (1-(1+b[1]*x/2)**(-2)) def Misra1c(b, x, y=0): b = read_params(b) return y - b[0] * (1-(1+2*b[1]*x)**(-.5)) def Misra1d(b, x, y=0): b = read_params(b) return y - b[0]*b[1]*x*((1+b[1]*x)**(-1)) def Nelson(b, x, y=None): b = read_params(b) x1 = x[:,0] x2 = x[:,1] if y is None: return - exp(b[0] - b[1]*x1 * exp(-b[2]*x2)) return log(y) - (b[0] - b[1]*x1 * exp(-b[2]*x2) ) def Rat42(b, x, y=0): b = read_params(b) return y - b[0] / (1+exp(b[1]-b[2]*x)) def Rat43(b, x, y=0): b = read_params(b) return y - b[0] / ((1+exp(b[1]-b[2]*x))**(1/b[3])) def Roszman1(b, x, y=0): b = read_params(b) pi = 3.141592653589793238462643383279 return y - b[0] - b[1]*x - arctan(b[2]/(x-b[3]))/pi def Thurber(b, x, y=0): b = read_params(b) return y - ( (b[0] + b[1]*x + b[2]*x**2 + b[3]*x**3) / (1 + b[4]*x + b[5]*x**2 + b[6]*x**3) ) # Model name fcn, #fitting params, dim of x Models = {'Bennett5': (Bennet5, 3, 1), 'BoxBOD': (BoxBOD, 2, 1), 'Chwirut1': (Chwirut, 3, 1), 'Chwirut2': (Chwirut, 3, 1), 'DanWood': (DanWood, 2, 1), 'ENSO': (ENSO, 9, 1), 'Eckerle4': (Eckerle4, 3, 1), 'Gauss1': (Gauss, 8, 1), 'Gauss2': (Gauss, 8, 1), 'Gauss3': (Gauss, 8, 1), 'Hahn1': (Hahn1, 7, 1), 'Kirby2': (Kirby, 5, 1), 'Lanczos1': (Lanczos, 6, 1), 'Lanczos2': (Lanczos, 6, 1), 'Lanczos3': (Lanczos, 6, 1), 'MGH09': (MGH09, 4, 1), 'MGH10': (MGH10, 3, 1), 'MGH17': (MGH17, 5, 1), 'Misra1a': (Misra1a, 2, 1), 'Misra1b' : (Misra1b, 2, 1), 'Misra1c' : (Misra1c, 2, 1), 'Misra1d' : (Misra1d, 2, 1), 'Nelson': (Nelson, 3, 2), 'Rat42': (Rat42, 3, 1), 'Rat43': (Rat43, 4, 1), 'Roszman1': (Roszman1, 4, 1), 'Thurber': (Thurber, 7, 1) } def ReadNistData(dataset): """NIST STRD data is in a simple, fixed format with line numbers being significant! """ finp = open(os.path.join(NIST_DIR, "%s.dat" % dataset), 'r') lines = [l[:-1] for l in finp.readlines()] finp.close() ModelLines = lines[30:39] ParamLines = lines[40:58] DataLines = lines[60:] words = ModelLines[1].strip().split() nparams = int(words[0]) start1 = [0]*nparams start2 = [0]*nparams certval = [0]*nparams certerr = [0]*nparams for i, text in enumerate(ParamLines[:nparams]): [s1, s2, val, err] = [float(x) for x in text.split('=')[1].split()] start1[i] = s1 start2[i] = s2 certval[i] = val certerr[i] = err # for t in ParamLines[nparams:]: t = t.strip() if ':' not in t: continue val = float(t.split(':')[1]) if t.startswith('Residual Sum of Squares'): sum_squares = val elif t.startswith('Residual Standard Deviation'): std_dev = val elif t.startswith('Degrees of Freedom'): nfree = int(val) elif t.startswith('Number of Observations'): ndata = int(val) y, x = [], [] for d in DataLines: vals = [float(i) for i in d.strip().split()] y.append(vals[0]) if len(vals) > 2: x.append(vals[1:]) else: x.append(vals[1]) y = array(y) x = array(x) out = {'y': y, 'x': x, 'nparams': nparams, 'ndata': ndata, 'nfree': nfree, 'start1': start1, 'start2': start2, 'sum_squares': sum_squares, 'std_dev': std_dev, 'cert': certval, 'cert_values': certval, 'cert_stderr': certerr } return out lmfit-0.9.7/tests/test_1variable.py0000644000076500000240000000272313066042256020203 0ustar Newvillestaff00000000000000# test of fitting one variable # From Nick Schurch import lmfit, numpy from numpy.testing import assert_allclose def linear_chisq(params, x, data, errs=None): ''' Calcs chi-squared residuals linear model (weighted by errors if given) ''' if type(params) is not lmfit.parameter.Parameters: msg = "Params argument is not a lmfit parameter set" raise TypeError(msg) if "m" not in params.keys(): msg = "No slope parameter (m) defined in the model" raise KeyError(msg) if "c" not in params.keys(): msg = "No intercept parameter (c) defined in the model" raise KeyError(msg) model = params["m"]*x + params["c"] residuals = (data-model) if errs is not None: residuals = residuals/errs return(residuals) def test_1var(): rands = [-0.21698284, 0.41900591, 0.02349374, -0.218552, -0.3513699, 0.33418304, 0.04226855, 0.213303, 0.45948731, 0.33587736] x = numpy.arange(10)+1 y = numpy.arange(10)+1+rands y_errs = numpy.sqrt(y)/2 params = lmfit.Parameters() params.add(name="m", value=1.0, vary=True) params.add(name="c", value=0.0, vary=False) out = lmfit.minimize(linear_chisq, params, args=(x, y)) lmfit.report_fit(out) assert_allclose(params['m'].value, 1.025, rtol=0.02, atol=0.02) assert(len(params)==2) assert(out.nvarys == 1) assert(out.chisqr > 0.01) assert(out.chisqr < 5.00) if __name__ == '__main__': test_1var() lmfit-0.9.7/tests/test_algebraic_constraint.py0000644000076500000240000001124613066042256022512 0ustar Newvillestaff00000000000000from numpy import linspace, zeros, sin, exp, random, sqrt, pi, sign from lmfit import Parameters, Parameter, Minimizer, Model from lmfit.lineshapes import gaussian, lorentzian, pvoigt from lmfit.printfuncs import report_fit def test_constraints1(): def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params) pfit= result.params fit = residual(result.params, x) assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value) def test_constraints2(): """add a user-defined function to symbol table""" def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data)/sigma n = 601 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) def width_func(wpar): """ """ return 2*wpar myfit.params._asteval.symtable['wfun'] = width_func try: myfit.params.add(name='wid_l', expr='wfun(wid_g)') except: assert(False) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params) pfit= result.params fit = residual(result.params, x) assert(pfit['cen_l'].value == 1.5 + pfit['cen_g'].value) assert(pfit['amp_l'].value == pfit['amp_tot'].value - pfit['amp_g'].value) assert(pfit['wid_l'].value == 2 * pfit['wid_g'].value) def test_constraints3(): """test a constraint with simple function call""" x = [1723, 1773, 1823, 1523, 1773, 1033.03078, 1042.98077, 1047.90937, 1053.95899, 1057.94906, 1063.13788, 1075.74218, 1086.03102] y = [0.79934, -0.31876, -0.46852, 0.05, -0.21, 11.1708, 10.31844, 9.73069, 9.21319, 9.12457, 9.05243, 8.66407, 8.29664] def VFT(T, ninf=-3, A=5e3, T0=800): return ninf + A/(T-T0) vftModel = Model(VFT) vftModel.set_param_hint('D', vary=False, expr=r'A*log(10)/T0') result = vftModel.fit(y, T=x) assert(result.params['A'].value > 2600.0) assert(result.params['A'].value < 2650.0) assert(result.params['D'].value > 7.0) assert(result.params['D'].value < 7.5) if __name__ == '__main__': test_constraints1() test_constraints2() test_constraints3() lmfit-0.9.7/tests/test_algebraic_constraint2.py0000644000076500000240000000572713066042256022603 0ustar Newvillestaff00000000000000from numpy import linspace, zeros, sin, exp, random, sqrt, pi, sign from lmfit import Parameters, Parameter, Minimizer from lmfit.lineshapes import gaussian, lorentzian, pvoigt from lmfit.printfuncs import report_fit import sys # Turn off plotting if run by nosetests. WITHPLOT = True for arg in sys.argv: if 'nose' in arg or 'pytest' in arg: WITHPLOT = False if WITHPLOT: try: import matplotlib import pylab except ImportError: WITHPLOT = False def test_constraints(with_plot=True): with_plot = with_plot and WITHPLOT def residual(pars, x, sigma=None, data=None): yg = gaussian(x, pars['amp_g'], pars['cen_g'], pars['wid_g']) yl = lorentzian(x, pars['amp_l'], pars['cen_l'], pars['wid_l']) model = yg + yl + pars['line_off'] + x * pars['line_slope'] if data is None: return model if sigma is None: return (model - data) return (model - data) / sigma n = 201 xmin = 0. xmax = 20.0 x = linspace(xmin, xmax, n) data = (gaussian(x, 21, 8.1, 1.2) + lorentzian(x, 10, 9.6, 2.4) + random.normal(scale=0.23, size=n) + x*0.5) if with_plot: pylab.plot(x, data, 'r+') pfit = Parameters() pfit.add(name='amp_g', value=10) pfit.add(name='cen_g', value=9) pfit.add(name='wid_g', value=1) pfit.add(name='amp_tot', value=20) pfit.add(name='amp_l', expr='amp_tot - amp_g') pfit.add(name='cen_l', expr='1.5+cen_g') pfit.add(name='wid_l', expr='2*wid_g') pfit.add(name='line_slope', value=0.0) pfit.add(name='line_off', value=0.0) sigma = 0.021 # estimate of data error (for all data points) myfit = Minimizer(residual, pfit, fcn_args=(x,), fcn_kws={'sigma':sigma, 'data':data}, scale_covar=True) myfit.prepare_fit() init = residual(myfit.params, x) result = myfit.leastsq() print(' Nfev = ', result.nfev) print( result.chisqr, result.redchi, result.nfree) report_fit(result.params, min_correl=0.3) fit = residual(result.params, x) if with_plot: pylab.plot(x, fit, 'b-') assert(result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert(result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert(result.params['wid_l'].value == 2 * result.params['wid_g'].value) # now, change fit slightly and re-run myfit.params['wid_l'].expr = '1.25*wid_g' result = myfit.leastsq() report_fit(result.params, min_correl=0.4) fit2 = residual(result.params, x) if with_plot: pylab.plot(x, fit2, 'k') pylab.show() assert(result.params['cen_l'].value == 1.5 + result.params['cen_g'].value) assert(result.params['amp_l'].value == result.params['amp_tot'].value - result.params['amp_g'].value) assert(result.params['wid_l'].value == 1.25 * result.params['wid_g'].value) test_constraints() lmfit-0.9.7/tests/test_basicfit.py0000644000076500000240000000262713066042256020124 0ustar Newvillestaff00000000000000import numpy as np from lmfit import minimize, Parameters, Parameter, report_fit from lmfit_testutils import assert_paramval, assert_paramattr def test_basic(): # create data to be fitted x = np.linspace(0, 15, 301) data = (5. * np.sin(2 * x - 0.1) * np.exp(-x*x*0.025) + np.random.normal(size=len(x), scale=0.2) ) # define objective function: returns the array to be minimized def fcn2min(params, x, data): """ model decaying sine wave, subtract data""" amp = params['amp'] shift = params['shift'] omega = params['omega'] decay = params['decay'] model = amp * np.sin(x * omega + shift) * np.exp(-x*x*decay) return model - data # create a set of Parameters params = Parameters() params.add('amp', value= 10, min=0) params.add('decay', value= 0.1) params.add('shift', value= 0.0, min=-np.pi/2., max=np.pi/2) params.add('omega', value= 3.0) # do fit, here with leastsq model result = minimize(fcn2min, params, args=(x, data)) # calculate final result final = data + result.residual # report_fit(result) assert(result.nfev > 5) assert(result.nfev < 500) assert(result.chisqr > 1) assert(result.nvarys == 4) assert_paramval(result.params['amp'], 5.03, tol=0.05) assert_paramval(result.params['omega'], 2.0, tol=0.05) if __name__ == '__main__': test_basic() lmfit-0.9.7/tests/test_bounded_jacobian.py0000644000076500000240000000202613066042256021577 0ustar Newvillestaff00000000000000from lmfit import Parameters, minimize, fit_report from lmfit_testutils import assert_paramval, assert_paramattr import numpy as np def test_bounded_jacobian(): pars = Parameters() pars.add('x0', value=2.0) pars.add('x1', value=2.0, min=1.5) global jac_count jac_count = 0 def resid(params): x0 = params['x0'] x1 = params['x1'] return np.array([10 * (x1 - x0*x0), 1-x0]) def jac(params): global jac_count jac_count += 1 x0 = params['x0'] return np.array([[-20*x0, 10], [-1, 0]]) out0 = minimize(resid, pars, Dfun=None) assert_paramval(out0.params['x0'], 1.2243, tol=0.02) assert_paramval(out0.params['x1'], 1.5000, tol=0.02) assert(jac_count == 0) out1 = minimize(resid, pars, Dfun=jac) assert_paramval(out1.params['x0'], 1.2243, tol=0.02) assert_paramval(out1.params['x1'], 1.5000, tol=0.02) assert(jac_count > 5) print(fit_report(out1, show_correl=True)) if __name__ == '__main__': test_bounded_jacobian() lmfit-0.9.7/tests/test_bounds.py0000644000076500000240000000310313066042256017620 0ustar Newvillestaff00000000000000from lmfit import Parameters, minimize, fit_report from lmfit_testutils import assert_paramval, assert_paramattr from numpy import linspace, zeros, sin, exp, random, pi, sign def test_bounds(): p_true = Parameters() p_true.add('amp', value=14.0) p_true.add('period', value=5.4321) p_true.add('shift', value=0.12345) p_true.add('decay', value=0.01000) def residual(pars, x, data=None): amp = pars['amp'] per = pars['period'] shift = pars['shift'] decay = pars['decay'] if abs(shift) > pi/2: shift = shift - sign(shift)*pi model = amp*sin(shift + x/per) * exp(-x*x*decay*decay) if data is None: return model return (model - data) n = 1500 xmin = 0. xmax = 250.0 random.seed(0) noise = random.normal(scale=2.80, size=n) x = linspace(xmin, xmax, n) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=13.0, max=20, min=0.0) fit_params.add('period', value=2, max=10) fit_params.add('shift', value=0.0, max=pi/2., min=-pi/2.) fit_params.add('decay', value=0.02, max=0.10, min=0.00) out = minimize(residual, fit_params, args=(x,), kws={'data':data}) fit = residual(out.params, x) assert(out.nfev > 10) assert(out.nfree > 50) assert(out.chisqr > 1.0) print(fit_report(out, show_correl=True, modelpars=p_true)) assert_paramval(out.params['decay'], 0.01, tol=1.e-2) assert_paramval(out.params['shift'], 0.123, tol=1.e-2) if __name__ == '__main__': test_bounds() lmfit-0.9.7/tests/test_brute_method.py0000644000076500000240000002677613107321636021032 0ustar Newvillestaff00000000000000from __future__ import print_function import pickle import numpy as np from numpy.testing import (assert_, decorators, assert_raises, assert_almost_equal, assert_equal, assert_allclose) from scipy import optimize import lmfit # use example problem described int he scipy documentation: # https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.brute.html # setup for scipy-brute optimization # params = (2, 3, 7, 8, 9, 10, 44, -1, 2, 26, 1, -2, 0.5) def f1(z, *params): x, y = z a, b, c, d, e, f, g, h, i, j, k, l, scale = params return (a * x**2 + b * x * y + c * y**2 + d*x + e*y + f) def f2(z, *params): x, y = z a, b, c, d, e, f, g, h, i, j, k, l, scale = params return (-g*np.exp(-((x-h)**2 + (y-i)**2) / scale)) def f3(z, *params): x, y = z a, b, c, d, e, f, g, h, i, j, k, l, scale = params return (-j*np.exp(-((x-k)**2 + (y-l)**2) / scale)) def f(z, *params): return f1(z, *params) + f2(z, *params) + f3(z, *params) # setup for scipy-brute optimization # # setup for lmfit-brute optimization # params_lmfit = lmfit.Parameters() params_lmfit.add_many( ('a', 2, False, None, None, None), ('b', 3, False, None, None, None), ('c', 7, False, None, None, None), ('d', 8, False, None, None, None), ('e', 9, False, None, None, None), ('f', 10, False, None, None, None), ('g', 44, False, None, None, None), ('h', -1, False, None, None, None), ('i', 2, False, None, None, None), ('j', 26, False, None, None, None), ('k', 1, False, None, None, None), ('l', -2, False, None, None, None), ('scale', 0.5, False, None, None, None), ('x', -4.0, True, -4.0, 4.0, None, None), ('y', -2.0, True, -2.0, 2.0, None, None), ) def f1_lmfit(p): par = p.valuesdict() return (par['a'] * par['x']**2 + par['b'] * par['x'] * par['y'] + par['c'] * par['y']**2 + par['d']*par['x'] + par['e']*par['y'] + par['f']) def f2_lmfit(p): par = p.valuesdict() return (-1.0*par['g']*np.exp(-((par['x']-par['h'])**2 + (par['y']-par['i'])**2) / par['scale'])) def f3_lmfit(p): par = p.valuesdict() return (-1.0*par['j']*np.exp(-((par['x']-par['k'])**2 + (par['y']-par['l'])**2) / par['scale'])) def f_lmfit(params_lmfit): return f1_lmfit(params_lmfit) + f2_lmfit(params_lmfit) + f3_lmfit(params_lmfit) # setup for lmfit-brute optimization ### def test_brute_lmfit_vs_scipy(): # The tests below are to make sure that the implementation of the brute # method in lmfit gives identical results to scipy.optimize.brute, when # using finite bounds for all varying parameters. # TEST 1: using bounds, with (default) Ns=20 and no stepsize specified assert(not params_lmfit['x'].brute_step) # brute_step for x == None assert(not params_lmfit['y'].brute_step) # brute_step for y == None rranges = ((-4, 4), (-2, 2)) resbrute = optimize.brute(f, rranges, args=params, full_output=True, Ns=20, finish=None) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute', Ns=20) assert_equal(resbrute[2], resbrute_lmfit.brute_grid, verbose=True) # grid identical assert_equal(resbrute[3], resbrute_lmfit.brute_Jout, verbose=True) # function values on grid identical assert_equal(resbrute[0][0], resbrute_lmfit.brute_x0[0], verbose=True) # best fit x value identical assert_equal(resbrute[0][0], resbrute_lmfit.params['x'].value, verbose=True) # best fit x value stored correctly assert_equal(resbrute[0][1], resbrute_lmfit.brute_x0[1], verbose=True) # best fit y value identical assert_equal(resbrute[0][1], resbrute_lmfit.params['y'].value, verbose=True) # best fit y value stored correctly assert_equal(resbrute[1], resbrute_lmfit.brute_fval, verbose=True) # best fit function value identical assert_equal(resbrute[1], resbrute_lmfit.chisqr, verbose=True) # best fit function value stored correctly # TEST 2: using bounds, setting Ns=40 and no stepsize specified assert(not params_lmfit['x'].brute_step) # brute_step for x == None assert(not params_lmfit['y'].brute_step) # brute_step for y == None rranges = ((-4, 4), (-2, 2)) resbrute = optimize.brute(f, rranges, args=params, full_output=True, Ns=40, finish=None) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute', Ns=40) assert_equal(resbrute[2], resbrute_lmfit.brute_grid, verbose=True) # grid identical assert_equal(resbrute[3], resbrute_lmfit.brute_Jout, verbose=True) # function values on grid identical assert_equal(resbrute[0][0], resbrute_lmfit.params['x'].value, verbose=True) # best fit x value identical assert_equal(resbrute[0][1], resbrute_lmfit.params['y'].value, verbose=True) # best fit y value identical assert_equal(resbrute[1], resbrute_lmfit.chisqr, verbose=True) # best fit function value identical # TEST 3: using bounds and specifing stepsize for both parameters params_lmfit['x'].set(brute_step=0.25) params_lmfit['y'].set(brute_step=0.25) assert_equal(params_lmfit['x'].brute_step, 0.25 ,verbose=True) assert_equal(params_lmfit['y'].brute_step, 0.25 ,verbose=True) rranges = (slice(-4, 4, 0.25), slice(-2, 2, 0.25)) resbrute = optimize.brute(f, rranges, args=params, full_output=True, Ns=20, finish=None) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute') assert_equal(resbrute[2], resbrute_lmfit.brute_grid, verbose=True) # grid identical assert_equal(resbrute[3], resbrute_lmfit.brute_Jout, verbose=True) # function values on grid identical assert_equal(resbrute[0][0], resbrute_lmfit.params['x'].value, verbose=True) # best fit x value identical assert_equal(resbrute[0][1], resbrute_lmfit.params['y'].value, verbose=True) # best fit y value identical assert_equal(resbrute[1], resbrute_lmfit.chisqr, verbose=True) # best fit function value identical # TEST 4: using bounds, Ns=10, adn specifing stepsize for parameter 'x' params_lmfit['x'].set(brute_step=0.15) params_lmfit['y'].set(brute_step=0) # brute_step for y == None assert_equal(params_lmfit['x'].brute_step, 0.15 ,verbose=True) assert(not params_lmfit['y'].brute_step) rranges = (slice(-4, 4, 0.15), (-2, 2)) resbrute = optimize.brute(f, rranges, args=params, full_output=True, Ns=10, finish=None) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute', Ns=10, keep='all') assert_equal(resbrute[2], resbrute_lmfit.brute_grid, verbose=True) # grid identical assert_equal(resbrute[3], resbrute_lmfit.brute_Jout, verbose=True) # function values on grid identical assert_equal(resbrute[0][0], resbrute_lmfit.params['x'].value, verbose=True) # best fit x value identical assert_equal(resbrute[0][1], resbrute_lmfit.params['y'].value, verbose=True) # best fit y value identical assert_equal(resbrute[1], resbrute_lmfit.chisqr, verbose=True) # best fit function value identical def test_brute(): # The tests below are to make sure that the implementation of the brute # method in lmfit works as intended. # restore original settings for paramers 'x' and 'y' params_lmfit.add_many( ('x', -4.0, True, -4.0, 4.0, None, None), ('y', -2.0, True, -2.0, 2.0, None, None)) # TEST 1: only upper bound and brute_step specified, using default Ns=20 Ns = 20 params_lmfit['x'].set(min=-np.inf) params_lmfit['x'].set(brute_step=0.25) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute') grid_x_expected = np.linspace(params_lmfit['x'].max - Ns*params_lmfit['x'].brute_step, params_lmfit['x'].max, Ns, False) grid_x = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][0]) assert_almost_equal(grid_x_expected, grid_x, verbose=True) grid_y = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][1]) grid_y_expected = np.linspace(params_lmfit['y'].min, params_lmfit['y'].max, Ns) assert_almost_equal(grid_y_expected, grid_y, verbose=True) # TEST 2: only lower bound and brute_step specified, using Ns=15 Ns = 15 params_lmfit['y'].set(max=np.inf) params_lmfit['y'].set(brute_step=0.1) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute', Ns=15) grid_x_expected = np.linspace(params_lmfit['x'].max - Ns*params_lmfit['x'].brute_step, params_lmfit['x'].max, Ns, False) grid_x = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][0]) assert_almost_equal(grid_x_expected, grid_x, verbose=True) grid_y = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][1]) grid_y_expected = np.linspace(params_lmfit['y'].min, params_lmfit['y'].min + Ns*params_lmfit['y'].brute_step, Ns, False) assert_almost_equal(grid_y_expected, grid_y, verbose=True) # TEST 3: only value and brute_step specified, using Ns=15 Ns = 15 params_lmfit['x'].set(max=np.inf) params_lmfit['x'].set(min=-np.inf) params_lmfit['x'].set(brute_step=0.1) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute', Ns=15) grid_x_expected = np.linspace(params_lmfit['x'].value - (Ns//2)*params_lmfit['x'].brute_step, params_lmfit['x'].value + (Ns//2)*params_lmfit['x'].brute_step, Ns) grid_x = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][0]) assert_almost_equal(grid_x_expected, grid_x, verbose=True) grid_y = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][1]) grid_y_expected = np.linspace(params_lmfit['y'].min, params_lmfit['y'].min + Ns*params_lmfit['y'].brute_step, Ns, False) assert_almost_equal(grid_y_expected, grid_y, verbose=True) # TEST 3: only value and brute_step specified, using Ns=15 fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute', Ns=15) grid_x_expected = np.linspace(params_lmfit['x'].value - (Ns//2)*params_lmfit['x'].brute_step, params_lmfit['x'].value + (Ns//2)*params_lmfit['x'].brute_step, Ns) grid_x = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][0]) assert_almost_equal(grid_x_expected, grid_x, verbose=True) grid_y = np.unique([par.ravel() for par in resbrute_lmfit.brute_grid][1]) grid_y_expected = np.linspace(params_lmfit['y'].min, params_lmfit['y'].min + Ns*params_lmfit['y'].brute_step, Ns, False) assert_almost_equal(grid_y_expected, grid_y, verbose=True) # TEST 4: check for correct functioning of keep argument and candidates attribute params_lmfit.add_many( # restore original settings for paramers 'x' and 'y' ('x', -4.0, True, -4.0, 4.0, None, None), ('y', -2.0, True, -2.0, 2.0, None, None)) fitter = lmfit.Minimizer(f_lmfit, params_lmfit) resbrute_lmfit = fitter.minimize(method='brute') assert(len(resbrute_lmfit.candidates) == 50) # default number of stored candidates resbrute_lmfit = fitter.minimize(method='brute', keep=10) assert(len(resbrute_lmfit.candidates) == 10) assert(isinstance(resbrute_lmfit.candidates[0].params, lmfit.Parameters)) # TEST 5: make sure the MinimizerResult can be pickle'd pkl = pickle.dumps(resbrute_lmfit) test_brute_lmfit_vs_scipy() test_brute() lmfit-0.9.7/tests/test_confidence.py0000644000076500000240000000465113066042256020434 0ustar Newvillestaff00000000000000import numpy as np from numpy.testing import assert_allclose import lmfit from lmfit_testutils import assert_paramval def residual(params, x, data): return data - 1.0/(params['a']*x)+ params['b'] def residual2(params, x, data): return data - params['c']/(params['a']*x)+params['b'] def test_confidence1(): x = np.linspace(0.3,10,100) np.random.seed(0) y = 1/(0.1*x)+2+0.1*np.random.randn(x.size) pars = lmfit.Parameters() pars.add_many(('a', 0.1), ('b', 1)) minimizer = lmfit.Minimizer(residual, pars, fcn_args=(x, y) ) out = minimizer.leastsq() # lmfit.report_fit(out) assert(out.nfev > 5) assert(out.nfev < 500) assert(out.chisqr < 3.0) assert(out.nvarys == 2) assert_paramval(out.params['a'], 0.1, tol=0.1) assert_paramval(out.params['b'], -2.0, tol=0.1) ci = lmfit.conf_interval(minimizer, out) assert_allclose(ci['b'][0][0], 0.997, rtol=0.01) assert_allclose(ci['b'][0][1], -2.022, rtol=0.01) assert_allclose(ci['b'][2][0], 0.683, rtol=0.01) assert_allclose(ci['b'][2][1], -1.997, rtol=0.01) assert_allclose(ci['b'][5][0], 0.95, rtol=0.01) assert_allclose(ci['b'][5][1], -1.96, rtol=0.01) # lmfit.printfuncs.report_ci(ci) def test_confidence2(): x = np.linspace(0.3,10,100) np.random.seed(0) y = 1/(0.1*x)+2+0.1*np.random.randn(x.size) pars = lmfit.Parameters() pars.add_many(('a', 0.1), ('b', 1), ('c', 1.0)) pars['a'].max = 0.25 pars['a'].min = 0.00 pars['a'].value = 0.2 pars['c'].vary = False minimizer = lmfit.Minimizer(residual2, pars, fcn_args=(x, y) ) out = minimizer.minimize(method='nelder') out = minimizer.minimize(method='leastsq', params=out.params) # lmfit.report_fit(out) assert(out.nfev > 5) assert(out.nfev < 500) assert(out.chisqr < 3.0) assert(out.nvarys == 2) assert_paramval(out.params['a'], 0.1, tol=0.1) assert_paramval(out.params['b'], -2.0, tol=0.1) ci = lmfit.conf_interval(minimizer, out) assert_allclose(ci['b'][0][0], 0.997, rtol=0.01) assert_allclose(ci['b'][0][1], -2.022, rtol=0.01) assert_allclose(ci['b'][2][0], 0.683, rtol=0.01) assert_allclose(ci['b'][2][1], -1.997, rtol=0.01) assert_allclose(ci['b'][5][0], 0.95, rtol=0.01) assert_allclose(ci['b'][5][1], -1.96, rtol=0.01) lmfit.printfuncs.report_ci(ci) if __name__ == '__main__': test_confidence1() test_confidence2() lmfit-0.9.7/tests/test_copy_params.py0000644000076500000240000000160513066042256020650 0ustar Newvillestaff00000000000000import numpy as np from lmfit import Parameters, minimize, report_fit def get_data(): x = np.arange(0, 1, 0.01) y1 = 1.5*np.exp(0.9*x) + np.random.normal(scale=0.001, size=len(x)) y2 = 2.0 + x + 1/2.*x**2 +1/3.*x**3 y2 = y2 + np.random.normal(scale=0.001, size=len(x)) return x, y1, y2 def residual(params, x, data): model = params['a']*np.exp(params['b']*x) return (data-model) def test_copy_params(): x, y1, y2 = get_data() params = Parameters() params.add('a', value = 2.0) params.add('b', value = 2.0) # fit to first data set out1 = minimize(residual, params, args=(x, y1)) # fit to second data set out2 = minimize(residual, params, args=(x, y2)) adiff = out1.params['a'].value - out2.params['a'].value bdiff = out1.params['b'].value - out2.params['b'].value assert(abs(adiff) > 1.e-2) assert(abs(bdiff) > 1.e-2) lmfit-0.9.7/tests/test_default_kws.py0000644000076500000240000000116013066042256020637 0ustar Newvillestaff00000000000000import numpy as np from nose.tools import assert_true from lmfit.lineshapes import gaussian from lmfit.models import GaussianModel def test_default_inputs_gauss(): area = 1 cen = 0 std = 0.2 x = np.arange(-3, 3, 0.01) y = gaussian(x, area, cen, std) g = GaussianModel() fit_option1 = {'maxfev': 5000, 'xtol': 1e-2} result1 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option1) fit_option2 = {'maxfev': 5000, 'xtol': 1e-6} result2 = g.fit(y, x=x, amplitude=1, center=0, sigma=0.5, fit_kws=fit_option2) assert_true(result1.values!=result2.values) return lmfit-0.9.7/tests/test_itercb.py0000644000076500000240000000200413066042256017575 0ustar Newvillestaff00000000000000import numpy as np from lmfit import Parameters, minimize, report_fit from lmfit.models import LinearModel, GaussianModel from lmfit.lineshapes import gaussian def per_iteration(pars, iter, resid, *args, **kws): """iteration callback, will abort at iteration 23 """ # print( iter, ', '.join(["%s=%.4f" % (p.name, p.value) for p in pars.values()])) return iter == 23 def test_itercb(): x = np.linspace(0, 20, 401) y = gaussian(x, amplitude=24.56, center=7.6543, sigma=1.23) y = y - .20*x + 3.333 + np.random.normal(scale=0.23, size=len(x)) mod = GaussianModel(prefix='peak_') + LinearModel(prefix='bkg_') pars = mod.make_params(peak_amplitude=21.0, peak_center=7.0, peak_sigma=2.0, bkg_intercept=2, bkg_slope=0.0) out = mod.fit(y, pars, x=x, iter_cb=per_iteration) assert(out.nfev == 23) assert(out.aborted) assert(not out.errorbars) assert(not out.success) lmfit-0.9.7/tests/test_least_squares.py0000644000076500000240000000325313066042256021207 0ustar Newvillestaff00000000000000from lmfit import Parameters, minimize, fit_report, Minimizer from lmfit.minimizer import HAS_LEAST_SQUARES from lmfit_testutils import assert_paramval, assert_paramattr from numpy import linspace, zeros, sin, exp, random, pi, sign import nose def test_bounds(): if not HAS_LEAST_SQUARES: raise nose.SkipTest p_true = Parameters() p_true.add('amp', value=14.0) p_true.add('period', value=5.4321) p_true.add('shift', value=0.12345) p_true.add('decay', value=0.01000) def residual(pars, x, data=None): amp = pars['amp'] per = pars['period'] shift = pars['shift'] decay = pars['decay'] if abs(shift) > pi/2: shift = shift - sign(shift)*pi model = amp*sin(shift + x/per) * exp(-x*x*decay*decay) if data is None: return model return (model - data) n = 1500 xmin = 0. xmax = 250.0 random.seed(0) noise = random.normal(scale=2.80, size=n) x = linspace(xmin, xmax, n) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=13.0, max=20, min=0.0) fit_params.add('period', value=2, max=10) fit_params.add('shift', value=0.0, max=pi/2., min=-pi/2.) fit_params.add('decay', value=0.02, max=0.10, min=0.00) min = Minimizer(residual, fit_params, (x, data)) out = min.least_squares() assert(out.nfev > 10) assert(out.nfree > 50) assert(out.chisqr > 1.0) print(fit_report(out, show_correl=True, modelpars=p_true)) assert_paramval(out.params['decay'], 0.01, tol=1.e-2) assert_paramval(out.params['shift'], 0.123, tol=1.e-2) if __name__ == '__main__': test_bounds() lmfit-0.9.7/tests/test_manypeaks_speed.py0000644000076500000240000000145613066042256021507 0ustar Newvillestaff00000000000000# # test speed of building complex model # import time import sys import numpy as np from lmfit import Model from lmfit.lineshapes import gaussian from copy import deepcopy sys.setrecursionlimit(2000) def test_manypeaks_speed(): x = np.linspace( -5, 5, 251) model = None t0 = time.time() for i in np.arange(500): g = Model(gaussian, prefix='g%i_' % i) if model is None: model = g else: model += g t1 = time.time() pars = model.make_params() t2 = time.time() cpars = deepcopy(pars) t3 = time.time() # these are very conservative tests that # should be satisfied on nearly any machine assert((t3-t2) < 0.5) assert((t2-t1) < 0.5) assert((t1-t0) < 5.0) if __name__ == '__main__': test_manypeaks_speed() lmfit-0.9.7/tests/test_minimizer.py0000644000076500000240000000107613066042256020340 0ustar Newvillestaff00000000000000from lmfit import Parameters, Minimizer def test_scalar_minimize_neg_value(): x0 = 3.14 fmin = -1.1 xtol = 0.001 ftol = 2.0 * xtol def objective(pars): return (pars['x'] - x0) ** 2.0 + fmin params = Parameters() params.add('x', value=2*x0) minr = Minimizer(objective, params) result = minr.scalar_minimize(method='Nelder-Mead', options={'xtol': xtol, 'ftol': ftol}) assert abs(result.params['x'].value - x0) < xtol assert abs(result.fun - fmin) < ftol lmfit-0.9.7/tests/test_model.py0000644000076500000240000006160513110357266017441 0ustar Newvillestaff00000000000000import unittest import warnings import nose from numpy.testing import assert_allclose, assert_raises from numpy.testing.decorators import knownfailureif import numpy as np from lmfit import Model, Parameter, models from lmfit.lineshapes import gaussian from lmfit.models import PseudoVoigtModel def assert_results_close(actual, desired, rtol=1e-03, atol=1e-03, err_msg='', verbose=True): for param_name, value in desired.items(): assert_allclose(actual[param_name], value, rtol, atol, err_msg, verbose) def _skip_if_no_pandas(): try: import pandas except ImportError: raise nose.SkipTest("Skipping tests that require pandas.") class CommonTests(object): # to be subclassed for testing predefined models def setUp(self): np.random.seed(1) self.noise = 0.0001*np.random.randn(*self.x.shape) # Some Models need args (e.g., polynomial order), and others don't. try: args = self.args except AttributeError: self.model = self.model_constructor() self.model_drop = self.model_constructor(missing='drop') self.model_raise = self.model_constructor(missing='raise') self.model_explicit_var = self.model_constructor(['x']) func = self.model.func else: self.model = self.model_constructor(*args) self.model_drop = self.model_constructor(*args, missing='drop') self.model_raise = self.model_constructor(*args, missing='raise') self.model_explicit_var = self.model_constructor( *args, independent_vars=['x']) func = self.model.func self.data = func(x=self.x, **self.true_values()) + self.noise @property def x(self): return np.linspace(1, 10, num=1000) def test_fit(self): model = self.model # Pass Parameters object. params = model.make_params(**self.guess()) result = model.fit(self.data, params, x=self.x) assert_results_close(result.values, self.true_values()) # Pass inidividual Parameter objects as kwargs. kwargs = dict((name, p) for name, p in params.items()) result = self.model.fit(self.data, x=self.x, **kwargs) assert_results_close(result.values, self.true_values()) # Pass guess values (not Parameter objects) as kwargs. kwargs = dict((name, p.value) for name, p in params.items()) result = self.model.fit(self.data, x=self.x, **kwargs) assert_results_close(result.values, self.true_values()) def test_explicit_independent_vars(self): self.check_skip_independent_vars() model = self.model_explicit_var pars = model.make_params(**self.guess()) result = model.fit(self.data, pars, x=self.x) assert_results_close(result.values, self.true_values()) def test_fit_with_weights(self): model = self.model # fit without weights params = model.make_params(**self.guess()) out1 = model.fit(self.data, params, x=self.x) # fit with weights weights = 1.0/(0.5 + self.x**2) out2 = model.fit(self.data, params, weights=weights, x=self.x) max_diff = 0.0 for parname, val1 in out1.values.items(): val2 = out2.values[parname] if max_diff < abs(val1-val2): max_diff = abs(val1-val2) assert(max_diff > 1.e-8) def test_result_attributes(self): pars = self.model.make_params(**self.guess()) result = self.model.fit(self.data, pars, x=self.x) # result.init_values assert_results_close(result.values, self.true_values()) self.assertEqual(result.init_values, self.guess()) # result.init_params params = self.model.make_params() for param_name, value in self.guess().items(): params[param_name].value = value self.assertEqual(result.init_params, params) # result.best_fit assert_allclose(result.best_fit, self.data, atol=self.noise.max()) # result.init_fit init_fit = self.model.func(x=self.x, **self.guess()) assert_allclose(result.init_fit, init_fit) # result.model self.assertTrue(result.model is self.model) def test_result_eval(self): # Check eval() output against init_fit and best_fit. pars = self.model.make_params(**self.guess()) result = self.model.fit(self.data, pars, x=self.x) assert_allclose(result.eval(x=self.x, **result.values), result.best_fit) assert_allclose(result.eval(x=self.x, **result.init_values), result.init_fit) def test_result_eval_custom_x(self): self.check_skip_independent_vars() pars = self.model.make_params(**self.guess()) result = self.model.fit(self.data, pars, x=self.x) # Check that the independent variable is respected. short_eval = result.eval(x=np.array([0, 1, 2]), **result.values) if hasattr(short_eval, '__len__'): self.assertEqual(len(short_eval), 3) def test_result_report(self): pars = self.model.make_params(**self.guess()) result = self.model.fit(self.data, pars, x=self.x) report = result.fit_report() assert("[[Model]]" in report) assert("[[Variables]]" in report) assert("[[Fit Statistics]]" in report) assert(" # function evals =" in report) assert(" Akaike " in report) assert(" chi-square " in report) def test_data_alignment(self): _skip_if_no_pandas() from pandas import Series # Align data and indep var of different lengths using pandas index. data = Series(self.data.copy()).iloc[10:-10] x = Series(self.x.copy()) model = self.model params = model.make_params(**self.guess()) result = model.fit(data, params, x=x) result = model.fit(data, params, x=x) assert_results_close(result.values, self.true_values()) # Skip over missing (NaN) values, aligning via pandas index. data.iloc[500:510] = np.nan result = self.model_drop.fit(data, params, x=x) assert_results_close(result.values, self.true_values()) # Raise if any NaN values are present. raises = lambda: self.model_raise.fit(data, params, x=x) self.assertRaises(ValueError, raises) def check_skip_independent_vars(self): # to be overridden for models that do not accept indep vars pass def test_aic(self): model = self.model # Pass Parameters object. params = model.make_params(**self.guess()) result = model.fit(self.data, params, x=self.x) aic = result.aic self.assertTrue(aic < 0) # aic must be negative # Pass extra unused Parameter. params.add("unused_param", value=1.0, vary=True) result = model.fit(self.data, params, x=self.x) aic_extra = result.aic self.assertTrue(aic_extra < 0) # aic must be negative self.assertTrue(aic < aic_extra) # the extra param should lower the aic def test_bic(self): model = self.model # Pass Parameters object. params = model.make_params(**self.guess()) result = model.fit(self.data, params, x=self.x) bic = result.bic self.assertTrue(bic < 0) # aic must be negative # Compare to AIC aic = result.aic self.assertTrue(aic < bic) # aic should be lower than bic # Pass extra unused Parameter. params.add("unused_param", value=1.0, vary=True) result = model.fit(self.data, params, x=self.x) bic_extra = result.bic self.assertTrue(bic_extra < 0) # bic must be negative self.assertTrue(bic < bic_extra) # the extra param should lower the bic class TestUserDefiniedModel(CommonTests, unittest.TestCase): # mainly aimed at checking that the API does what it says it does # and raises the right exceptions or warnings when things are not right def setUp(self): self.true_values = lambda: dict(amplitude=7.1, center=1.1, sigma=2.40) self.guess = lambda: dict(amplitude=5, center=2, sigma=4) # return a fresh copy self.model_constructor = ( lambda *args, **kwargs: Model(gaussian, *args, **kwargs)) super(TestUserDefiniedModel, self).setUp() @property def x(self): return np.linspace(-10, 10, num=1000) def test_lists_become_arrays(self): # smoke test self.model.fit([1, 2, 3], x=[1, 2, 3], **self.guess()) assert_raises(ValueError, self.model.fit, [1, 2, None, 3], x=[1, 2, 3, 4], **self.guess()) def test_missing_param_raises_error(self): # using keyword argument parameters guess_missing_sigma = self.guess() del guess_missing_sigma['sigma'] # f = lambda: self.model.fit(self.data, x=self.x, **guess_missing_sigma) # self.assertRaises(ValueError, f) # using Parameters params = self.model.make_params() for param_name, value in guess_missing_sigma.items(): params[param_name].value = value f = lambda: self.model.fit(self.data, params, x=self.x) def test_extra_param_issues_warning(self): # The function accepts extra params, Model will warn but not raise. def flexible_func(x, amplitude, center, sigma, **kwargs): return gaussian(x, amplitude, center, sigma) flexible_model = Model(flexible_func) pars = flexible_model.make_params(**self.guess()) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") flexible_model.fit(self.data, pars, x=self.x, extra=5) self.assertTrue(len(w) == 1) self.assertTrue(issubclass(w[-1].category, UserWarning)) def test_missing_independent_variable_raises_error(self): pars = self.model.make_params(**self.guess()) f = lambda: self.model.fit(self.data, pars) self.assertRaises(KeyError, f) def test_bounding(self): true_values = self.true_values() true_values['center'] = 1.3 # as close as it's allowed to get pars = self.model.make_params(**self.guess()) pars['center'].set(value=2, min=1.3) result = self.model.fit(self.data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.05) def test_vary_false(self): true_values = self.true_values() true_values['center'] = 1.3 pars = self.model.make_params(**self.guess()) pars['center'].set(value=1.3, vary=False) result = self.model.fit(self.data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.05) # testing model addition... def test_user_defined_gaussian_plus_constant(self): data = self.data + 5.0 model = self.model + models.ConstantModel() guess = self.guess() pars = model.make_params(c= 10.1, **guess) true_values = self.true_values() true_values['c'] = 5.0 result = model.fit(data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01) def test_model_with_prefix(self): # model with prefix of 'a' and 'b' mod = models.GaussianModel(prefix='a') vals = {'center': 2.45, 'sigma':0.8, 'amplitude':3.15} data = gaussian(x=self.x, **vals) + self.noise/3.0 pars = mod.guess(data, x=self.x) self.assertTrue('aamplitude' in pars) self.assertTrue('asigma' in pars) out = mod.fit(data, pars, x=self.x) self.assertTrue(out.params['aamplitude'].value > 2.0) self.assertTrue(out.params['acenter'].value > 2.0) self.assertTrue(out.params['acenter'].value < 3.0) mod = models.GaussianModel(prefix='b') data = gaussian(x=self.x, **vals) + self.noise/3.0 pars = mod.guess(data, x=self.x) self.assertTrue('bamplitude' in pars) self.assertTrue('bsigma' in pars) def test_change_prefix(self): "should fail" mod = models.GaussianModel(prefix='b') set_prefix_failed = None try: mod.prefix = 'c' set_prefix_failed = False except AttributeError: set_prefix_failed = True except: set_prefix_failed = None self.assertTrue(set_prefix_failed) def test_sum_of_two_gaussians(self): # two user-defined gaussians model1 = self.model f2 = lambda x, amp, cen, sig: gaussian(x, amplitude=amp, center=cen, sigma=sig) model2 = Model(f2) values1 = self.true_values() values2 = {'cen': 2.45, 'sig':0.8, 'amp':3.15} data = gaussian(x=self.x, **values1) + f2(x=self.x, **values2) + self.noise/3.0 model = self.model + model2 pars = model.make_params() pars['sigma'].set(value=2, min=0) pars['center'].set(value=1, min=0.2, max=1.8) pars['amplitude'].set(value=3, min=0) pars['sig'].set(value=1, min=0) pars['cen'].set(value=2.4, min=2, max=3.5) pars['amp'].set(value=1, min=0) true_values = dict(list(values1.items()) + list(values2.items())) result = model.fit(data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01) # user-defined models with common parameter names # cannot be added, and should raise f = lambda: model1 + model1 self.assertRaises(NameError, f) # two predefined_gaussians, using suffix to differentiate model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') model = model1 + model2 true_values = {'g1_center': values1['center'], 'g1_amplitude': values1['amplitude'], 'g1_sigma': values1['sigma'], 'g2_center': values2['cen'], 'g2_amplitude': values2['amp'], 'g2_sigma': values2['sig']} pars = model.make_params() pars['g1_sigma'].set(2) pars['g1_center'].set(1) pars['g1_amplitude'].set(3) pars['g2_sigma'].set(1) pars['g2_center'].set(2.4) pars['g2_amplitude'].set(1) result = model.fit(data, pars, x=self.x) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01) # without suffix, the names collide and Model should raise model1 = models.GaussianModel() model2 = models.GaussianModel() f = lambda: model1 + model2 self.assertRaises(NameError, f) def test_sum_composite_models(self): # test components of composite model created adding composite model model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') model3 = models.GaussianModel(prefix='g3_') model4 = models.GaussianModel(prefix='g4_') model_total1 = (model1 + model2) + model3 for mod in [model1, model2, model3]: self.assertTrue(mod in model_total1.components) model_total2 = model1 + (model2 + model3) for mod in [model1, model2, model3]: self.assertTrue(mod in model_total2.components) model_total3 = (model1 + model2) + (model3 + model4) for mod in [model1, model2, model3, model4]: self.assertTrue(mod in model_total3.components) def test_eval_components(self): model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') model3 = models.ConstantModel(prefix='bkg_') mod = model1 + model2 + model3 pars = mod.make_params() values1 = dict(amplitude=7.10, center=1.1, sigma=2.40) values2 = dict(amplitude=12.2, center=2.5, sigma=0.5) data = (1.01 + gaussian(x=self.x, **values1) + gaussian(x=self.x, **values2) + 0.05*self.noise) pars['g1_sigma'].set(2) pars['g1_center'].set(1, max=1.5) pars['g1_amplitude'].set(3) pars['g2_sigma'].set(1) pars['g2_center'].set(2.6, min=2.0) pars['g2_amplitude'].set(1) pars['bkg_c'].set(1.88) result = mod.fit(data, params=pars, x=self.x) self.assertTrue(abs(result.params['g1_amplitude'].value - 7.1) < 1.5) self.assertTrue(abs(result.params['g2_amplitude'].value - 12.2) < 1.5) self.assertTrue(abs(result.params['g1_center'].value - 1.1) < 0.2) self.assertTrue(abs(result.params['g2_center'].value - 2.5) < 0.2) self.assertTrue(abs(result.params['bkg_c'].value - 1.0) < 0.25) comps = mod.eval_components(x=self.x) assert('bkg_' in comps) def test_composite_has_bestvalues(self): # test that a composite model has non-empty best_values model1 = models.GaussianModel(prefix='g1_') model2 = models.GaussianModel(prefix='g2_') mod = model1 + model2 pars = mod.make_params() values1 = dict(amplitude=7.10, center=1.1, sigma=2.40) values2 = dict(amplitude=12.2, center=2.5, sigma=0.5) data = gaussian(x=self.x, **values1) + gaussian(x=self.x, **values2) + 0.1*self.noise pars['g1_sigma'].set(2) pars['g1_center'].set(1, max=1.5) pars['g1_amplitude'].set(3) pars['g2_sigma'].set(1) pars['g2_center'].set(2.6, min=2.0) pars['g2_amplitude'].set(1) result = mod.fit(data, params=pars, x=self.x) self.assertTrue(len(result.best_values) == 6) self.assertTrue(abs(result.params['g1_amplitude'].value - 7.1) < 0.5) self.assertTrue(abs(result.params['g2_amplitude'].value - 12.2) < 0.5) self.assertTrue(abs(result.params['g1_center'].value - 1.1) < 0.2) self.assertTrue(abs(result.params['g2_center'].value - 2.5) < 0.2) def test_hints_in_composite_models(self): # test propagation of hints from base models to composite model def func(x, amplitude): pass m1 = Model(func, prefix='p1_') m2 = Model(func, prefix='p2_') m1.set_param_hint('amplitude', value=1) m2.set_param_hint('amplitude', value=2) mx = (m1 + m2) params = mx.make_params() param_values = dict((name, p.value) for name, p in params.items()) self.assertEqual(param_values['p1_amplitude'], 1) self.assertEqual(param_values['p2_amplitude'], 2) def test_hints_for_peakmodels(self): # test that height/fwhm do not cause asteval errors. x = np.linspace(-10, 10, 101) y = np.sin(x / 3) + x /100. m1 = models.LinearModel(prefix='m1_') params = m1.guess(y, x=x) m2 = models.GaussianModel(prefix='m2_') params.update(m2.make_params()) m = m1 + m2 param_values = dict((name, p.value) for name, p in params.items()) self.assertTrue(param_values['m1_intercept'] < -0.0) self.assertEqual(param_values['m2_amplitude'], 1) def test_weird_param_hints(self): # tests Github Issue 312, a very weird way to access param_hints def func(x, amp): return amp*x m = Model(func) models = {} for i in range(2): m.set_param_hint('amp', value=1) m.set_param_hint('amp', value=25) models[i] = Model(func, prefix='mod%i_' % i) models[i].param_hints['amp'] = m.param_hints['amp'] self.assertEqual(models[0].param_hints['amp'], models[1].param_hints['amp']) def test_param_hint_explicit_value(self): # tests Github Issue 384 pmod = PseudoVoigtModel() params = pmod.make_params(sigma=2, fraction=0.77) assert_allclose(params['fraction'].value, 0.77, rtol=0.01) def test_composite_model_with_expr_constrains(self): """Smoke test for composite model fitting with expr constraints. """ y = [ 0, 0, 4, 2, 1, 8, 21, 21, 23, 35, 50, 54, 46, 70, 77, 87, 98, 113, 148, 136, 185, 195, 194, 168, 170, 139, 155, 115, 132, 109, 102, 85, 69, 81, 82, 80, 71, 64, 79, 88, 111, 97, 97, 73, 72, 62, 41, 30, 13, 3, 9, 7, 0, 0, 0] x = np.arange(-0.2, 1.2, 0.025)[:-1] + 0.5*0.025 def gauss(x, sigma, mu, A): return A*np.exp(-(x-mu)**2/(2*sigma**2)) # Initial values p1_mu = 0.2 p1_sigma = 0.1 #p2_mu = 0.8 p2_sigma = 0.1 peak1 = Model(gauss, prefix='p1_') peak2 = Model(gauss, prefix='p2_') model = peak1 + peak2 model.set_param_hint('p1_mu', value=p1_mu, min=-1, max=2) #model.set_param_hint('p2_mu', value=p2_mu, min=-1, max=2) model.set_param_hint('p1_sigma', value=p1_sigma, min=0.01, max=0.2) model.set_param_hint('p2_sigma', value=p2_sigma, min=0.01, max=0.2) model.set_param_hint('p1_A', value=100, min=0.01) model.set_param_hint('p2_A', value=50, min=0.01) # Constrains the distance between peaks to be > 0 model.set_param_hint('pos_delta', value=0.3, min=0) model.set_param_hint('p2_mu', min=-1, expr='p1_mu + pos_delta') # Test fitting result = model.fit(y, x=x) self.assertTrue(result.params['pos_delta'].value > 0) class TestLinear(CommonTests, unittest.TestCase): def setUp(self): self.true_values = lambda: dict(slope=5, intercept=2) self.guess = lambda: dict(slope=10, intercept=6) self.model_constructor = models.LinearModel super(TestLinear, self).setUp() class TestParabolic(CommonTests, unittest.TestCase): def setUp(self): self.true_values = lambda: dict(a=5, b=2, c=8) self.guess = lambda: dict(a=1, b=6, c=3) self.model_constructor = models.ParabolicModel super(TestParabolic, self).setUp() class TestPolynomialOrder2(CommonTests, unittest.TestCase): # class Polynomial constructed with order=2 def setUp(self): self.true_values = lambda: dict(c2=5, c1=2, c0=8) self.guess = lambda: dict(c1=1, c2=6, c0=3) self.model_constructor = models.PolynomialModel self.args = (2,) super(TestPolynomialOrder2, self).setUp() class TestPolynomialOrder3(CommonTests, unittest.TestCase): # class Polynomial constructed with order=3 def setUp(self): self.true_values = lambda: dict(c3=2, c2=5, c1=2, c0=8) self.guess = lambda: dict(c3=1, c1=1, c2=6, c0=3) self.model_constructor = models.PolynomialModel self.args = (3,) super(TestPolynomialOrder3, self).setUp() class TestConstant(CommonTests, unittest.TestCase): def setUp(self): self.true_values = lambda: dict(c=5) self.guess = lambda: dict(c=2) self.model_constructor = models.ConstantModel super(TestConstant, self).setUp() def check_skip_independent_vars(self): raise nose.SkipTest("ConstantModel has not independent_vars.") class TestPowerlaw(CommonTests, unittest.TestCase): def setUp(self): self.true_values = lambda: dict(amplitude=5, exponent=3) self.guess = lambda: dict(amplitude=2, exponent=8) self.model_constructor = models.PowerLawModel super(TestPowerlaw, self).setUp() class TestExponential(CommonTests, unittest.TestCase): def setUp(self): self.true_values = lambda: dict(amplitude=5, decay=3) self.guess = lambda: dict(amplitude=2, decay=8) self.model_constructor = models.ExponentialModel super(TestExponential, self).setUp() class TestComplexConstant(CommonTests, unittest.TestCase): def setUp(self): self.true_values = lambda: dict(re=5,im=5) self.guess = lambda: dict(re=2,im=2) self.model_constructor = models.ComplexConstantModel super(TestComplexConstant, self).setUp() class TestExpression(CommonTests, unittest.TestCase): def setUp(self): self.true_values = lambda: dict(off_c=0.25, amp_c=1.0, x0=2.0) self.guess = lambda: dict(off_c=0.20, amp_c=1.5, x0=2.5) self.expression = "off_c + amp_c * exp(-x/x0)" self.model_constructor = ( lambda *args, **kwargs: models.ExpressionModel(self.expression, *args, **kwargs)) super(TestExpression, self).setUp() def test_composite_with_expression(self): expression_model = models.ExpressionModel("exp(-x/x0)", name='exp') amp_model = models.ConstantModel(prefix='amp_') off_model = models.ConstantModel(prefix='off_', name="off") comp_model = off_model + amp_model * expression_model x = self.x true_values = self.true_values() data = comp_model.eval(x=x, **true_values) + self.noise # data = 0.25 + 1 * np.exp(-x / 2.) params = comp_model.make_params(**self.guess()) result = comp_model.fit(data, x=x, params=params) assert_results_close(result.values, true_values, rtol=0.01, atol=0.01) data_components = comp_model.eval_components(x=x) self.assertIn('exp', data_components) # lmfit-0.9.7/tests/test_model_uncertainties.py0000644000076500000240000000625513066042256022376 0ustar Newvillestaff00000000000000""" tests of ModelResult.eval_uncertainty() """ import numpy as np from numpy.testing import assert_allclose from lmfit.lineshapes import gaussian from lmfit.models import LinearModel, GaussianModel def get_linearmodel(slope=0.8, intercept=0.5, noise=1.5): # create data to be fitted np.random.seed(88) x = np.linspace(0, 10, 101) y = intercept + x*slope y = y + np.random.normal(size=len(x), scale=noise) model = LinearModel() params = model.make_params(intercept=intercept, slope=slope) return x, y, model, params def get_gaussianmodel(amplitude=1.0, center=5.0, sigma=1.0, noise=0.1): # create data to be fitted np.random.seed(7392) x = np.linspace(-20, 20, 201) y = gaussian(x, amplitude, center=center, sigma=sigma) y = y + np.random.normal(size=len(x), scale=noise) model = GaussianModel() params = model.make_params(amplitude=amplitude/5.0, center=center-1.0, sigma=sigma*2.0) return x, y, model, params def test_linear_constant_intercept(): x, y, model, params = get_linearmodel(slope=4, intercept=-10) params['intercept'].vary = False ret = model.fit(y, params, x=x) dely = ret.eval_uncertainty(sigma=1) slope_stderr = ret.params['slope'].stderr assert_allclose(dely.min(), 0, rtol=1.e-2) assert_allclose(dely.max(), slope_stderr*x.max(), rtol=1.e-2) assert_allclose(dely.mean(),slope_stderr*x.mean(), rtol=1.e-2) def test_linear_constant_slope(): x, y, model, params = get_linearmodel(slope=-4, intercept=2.3) params['slope'].vary = False ret = model.fit(y, params, x=x) dely = ret.eval_uncertainty(sigma=1) intercept_stderr = ret.params['intercept'].stderr assert_allclose(dely.min(), intercept_stderr, rtol=1.e-2) assert_allclose(dely.max(), intercept_stderr, rtol=1.e-2) def test_gauss_sigmalevel(): """ test that dely increases as sigma increases""" x, y, model, params = get_gaussianmodel(amplitude=50.0, center=4.5, sigma=0.78, noise=0.1) ret = model.fit(y, params, x=x) dely_sigma1 = ret.eval_uncertainty(sigma=1) dely_sigma2 = ret.eval_uncertainty(sigma=2) dely_sigma3 = ret.eval_uncertainty(sigma=3) assert(dely_sigma3.mean() > 1.5*dely_sigma2.mean()) assert(dely_sigma2.mean() > 1.5*dely_sigma1.mean()) def test_gauss_noiselevel(): """ test that dely increases as expected with changing noise level""" lonoise = 0.05 hinoise = 10*lonoise x, y, model, params = get_gaussianmodel(amplitude=20.0, center=2.1, sigma=1.0, noise=lonoise) ret1 = model.fit(y, params, x=x) dely_lonoise = ret1.eval_uncertainty(sigma=1) x, y, model, params = get_gaussianmodel(amplitude=20.0, center=2.1, sigma=1.0, noise=hinoise) ret2 = model.fit(y, params, x=x) dely_hinoise = ret2.eval_uncertainty(sigma=1) assert_allclose(dely_hinoise.mean(), 10*dely_lonoise.mean(), rtol=1.e-2) if __name__ == '__main__': test_linear_constant_intercept() test_linear_constant_slope() test_gauss_sigmalevel() test_gauss_noiselevel() lmfit-0.9.7/tests/test_multidatasets.py0000644000076500000240000000461513066042256021222 0ustar Newvillestaff00000000000000# # example fitting to multiple (simulated) data sets # import numpy as np from lmfit import minimize, Parameters, fit_report from lmfit.lineshapes import gaussian def gauss_dataset(params, i, x): """calc gaussian from params for data set i using simple, hardwired naming convention""" amp = params['amp_%i' % (i+1)] cen = params['cen_%i' % (i+1)] sig = params['sig_%i' % (i+1)] return gaussian(x, amp, cen, sig) def objective(params, x, data): """ calculate total residual for fits to several data sets held in a 2-D array, and modeled by Gaussian functions""" ndata, nx = data.shape resid = 0.0*data[:] # make residual per data set for i in range(ndata): resid[i, :] = data[i, :] - gauss_dataset(params, i, x) # now flatten this to a 1D array, as minimize() needs return resid.flatten() def test_multidatasets(): # create 5 datasets x = np.linspace( -1, 2, 151) data = [] for i in np.arange(5): amp = 2.60 + 1.50*np.random.rand() cen = -0.20 + 1.50*np.random.rand() sig = 0.25 + 0.03*np.random.rand() dat = gaussian(x, amp, cen, sig) + \ np.random.normal(size=len(x), scale=0.1) data.append(dat) # data has shape (5, 151) data = np.array(data) assert(data.shape) == (5, 151) # create 5 sets of parameters, one per data set pars = Parameters() for iy, y in enumerate(data): pars.add( 'amp_%i' % (iy+1), value=0.5, min=0.0, max=200) pars.add( 'cen_%i' % (iy+1), value=0.4, min=-2.0, max=2.0) pars.add( 'sig_%i' % (iy+1), value=0.3, min=0.01, max=3.0) # but now constrain all values of sigma to have the same value # by assigning sig_2, sig_3, .. sig_5 to be equal to sig_1 for iy in (2, 3, 4, 5): pars['sig_%i' % iy].expr='sig_1' # run the global fit to all the data sets out = minimize(objective, pars, args=(x, data)) assert(len(pars) == 15) assert(out.nvarys == 11) assert(out.nfev > 15) assert(out.chisqr > 1.0) assert(pars['amp_1'].value > 0.1) assert(pars['sig_1'].value > 0.1) assert(pars['sig_2'].value == pars['sig_1'].value) ## plot the data sets and fits # plt.figure() # for i in range(5): # y_fit = gauss_dataset(pars, i, x) # plt.plot(x, data[i, :], 'o', x, y_fit, '-') # plt.show() if __name__ == '__main__': test_multidatasets() lmfit-0.9.7/tests/test_NIST_Strd.py0000644000076500000240000001624013066042256020105 0ustar Newvillestaff00000000000000from __future__ import print_function import sys import math from optparse import OptionParser from lmfit import Parameters, minimize from NISTModels import Models, ReadNistData HASPYLAB = False for arg in sys.argv: if 'nose' in arg or 'pytest' in arg: HASPYLAB = False if HASPYLAB: try: import matplotlib import pylab HASPYLAB = True except ImportError: HASPYLAB = False def ndig(a, b): "precision for NIST values" return round(-math.log10((abs(abs(a)-abs(b)) +1.e-15)/ abs(b))) ABAR = ' |----------------+----------------+------------------+-------------------|' def Compare_NIST_Results(DataSet, myfit, params, NISTdata): buff = [' ======================================', ' %s: ' % DataSet, ' | Parameter Name | Value Found | Certified Value | # Matching Digits |'] buff.append(ABAR) val_dig_min = 200 err_dig_min = 200 fmt = ' | %s | % -.7e | % -.7e | %2i |' for i in range(NISTdata['nparams']): parname = 'b%i' % (i+1) par = params[parname] thisval = par.value certval = NISTdata['cert_values'][i] vdig = ndig(thisval, certval) pname = (parname + ' value ' + ' '*14)[:14] buff.append(fmt % (pname, thisval, certval, vdig)) val_dig_min = min(val_dig_min, vdig) thiserr = par.stderr certerr = NISTdata['cert_stderr'][i] if thiserr is not None and myfit.errorbars: edig = ndig(thiserr, certerr) ename = (parname + ' stderr' + ' '*14)[:14] buff.append(fmt % (ename, thiserr, certerr, edig)) err_dig_min = min(err_dig_min, edig) buff.append(ABAR) sumsq = NISTdata['sum_squares'] try: chi2 = myfit.chisqr buff.append(' | Sum of Squares | %.7e | %.7e | %2i |' % (chi2, sumsq, ndig(chi2, sumsq))) except: pass buff.append(ABAR) if not myfit.errorbars: buff.append(' | * * * * COULD NOT ESTIMATE UNCERTAINTIES * * * * |') err_dig_min = 0 if err_dig_min < 199: buff.append(' Worst agreement: %i digits for value, %i digits for error ' % (val_dig_min, err_dig_min)) else: buff.append(' Worst agreement: %i digits' % (val_dig_min)) return val_dig_min, '\n'.join(buff) def NIST_Dataset(DataSet, method='leastsq', start='start2', plot=True, verbose=False): NISTdata = ReadNistData(DataSet) resid, npar, dimx = Models[DataSet] y = NISTdata['y'] x = NISTdata['x'] params = Parameters() for i in range(npar): pname = 'b%i' % (i+1) cval = NISTdata['cert_values'][i] cerr = NISTdata['cert_stderr'][i] pval1 = NISTdata[start][i] params.add(pname, value=pval1) myfit = minimize(resid, params, method=method, args=(x,), kws={'y':y}) digs, buff = Compare_NIST_Results(DataSet, myfit, myfit.params, NISTdata) if verbose: print(buff) if plot and HASPYLAB: fit = -resid(myfit.params, x, ) pylab.plot(x, y, 'ro') pylab.plot(x, fit, 'k+-') pylab.show() return digs > 1 def build_usage(): modelnames = [] ms = '' for d in sorted(Models.keys()): ms = ms + ' %s ' % d if len(ms) > 55: modelnames.append(ms) ms = ' ' modelnames.append(ms) modelnames = '\n'.join(modelnames) usage = """ === Test Fit to NIST StRD Models === usage: ------ python fit_NIST.py [options] Model Start where Start is one of 'start1','start2' or 'cert', for different starting values, and Model is one of %s if Model = 'all', all models and starting values will be run. options: -------- -m name of fitting method. One of: leastsq, nelder, powell, lbfgsb, bfgs, tnc, cobyla, slsqp, cg, newto-cg leastsq (Levenberg-Marquardt) is the default """ % modelnames return usage ############################ def run_interactive(): usage = build_usage() parser = OptionParser(usage=usage, prog="fit-NIST.py") parser.add_option("-m", "--method", dest="method", metavar='METH', default='leastsq', help="set method name, default = 'leastsq'") (opts, args) = parser.parse_args() dset = '' start = 'start2' if len(args) > 0: dset = args[0] if len(args) > 1: start = args[1] if dset.lower() == 'all': tpass = 0 tfail = 0 failures = [] dsets = sorted(Models.keys()) for dset in dsets: for start in ('start1', 'start2', 'cert'): if NIST_Dataset(dset, method=opts.method, start=start, plot=False, verbose=True): tpass += 1 else: tfail += 1 failures.append(" %s (starting at '%s')" % (dset, start)) print('--------------------------------------') print(' Fit Method: %s ' % opts.method) print(' Final Results: %i pass, %i fail.' % (tpass, tfail)) print(' Tests Failed for:\n %s' % '\n '.join(failures)) print('--------------------------------------') elif dset not in Models: print(usage) else: return NIST_Dataset(dset, method=opts.method, start=start, plot=True, verbose=True) def RunNIST_Model(model): out1 = NIST_Dataset(model, start='start1', plot=False, verbose=False) out2 = NIST_Dataset(model, start='start2', plot=False, verbose=False) print("NIST Test" , model, out1, out2) assert(out1 or out2) return out1 or out2 def test_Bennett5(): return RunNIST_Model('Bennett5') def test_BoxBOD(): return RunNIST_Model('BoxBOD') def test_Chwirut1(): return RunNIST_Model('Chwirut1') def test_Chwirut2(): return RunNIST_Model('Chwirut2') def test_DanWood(): return RunNIST_Model('DanWood') def test_ENSO(): return RunNIST_Model('ENSO') def test_Eckerle4(): return RunNIST_Model('Eckerle4') def test_Gauss1(): return RunNIST_Model('Gauss1') def test_Gauss2(): return RunNIST_Model('Gauss2') def test_Gauss3(): return RunNIST_Model('Gauss3') def test_Hahn1(): return RunNIST_Model('Hahn1') def test_Kirby2(): return RunNIST_Model('Kirby2') def test_Lanczos1(): return RunNIST_Model('Lanczos1') def test_Lanczos2(): return RunNIST_Model('Lanczos2') def test_Lanczos3(): return RunNIST_Model('Lanczos3') def test_MGH09(): return RunNIST_Model('MGH09') def test_MGH10(): return RunNIST_Model('MGH10') def test_MGH17(): return RunNIST_Model('MGH17') def test_Misra1a(): return RunNIST_Model('Misra1a') def test_Misra1b(): return RunNIST_Model('Misra1b') def test_Misra1c(): return RunNIST_Model('Misra1c') def test_Misra1d(): return RunNIST_Model('Misra1d') def test_Nelson(): return RunNIST_Model('Nelson') def test_Rat42(): return RunNIST_Model('Rat42') def test_Rat43(): return RunNIST_Model('Rat43') def test_Roszman1(): return RunNIST_Model('Roszman1') def test_Thurber(): return RunNIST_Model('Thurber') if __name__ == '__main__': run_interactive() lmfit-0.9.7/tests/test_nose.py0000644000076500000240000006102113111710636017270 0ustar Newvillestaff00000000000000# -*- coding: utf-8 -*- from __future__ import print_function from lmfit import minimize, Parameters, Parameter, report_fit, Minimizer from lmfit.minimizer import (SCALAR_METHODS, HAS_EMCEE, MinimizerResult, _lnpost, _nan_policy) from lmfit.lineshapes import gaussian from lmfit import ufloat import numpy as np from numpy import pi from numpy.testing import (assert_, decorators, assert_raises, assert_almost_equal, assert_equal, assert_allclose) import unittest import nose from nose import SkipTest def check(para, real_val, sig=3): err = abs(para.value - real_val) print('Check Param w/ stderr: ', para.name, para.value, real_val, para.stderr) assert(err < sig * para.stderr) def check_wo_stderr(para, real_val, sig=0.1): err = abs(para.value - real_val) print('Check Param w/o stderr: ', para.name, para.value, real_val, sig) assert(err < sig) def check_paras(para_fit, para_real, sig=3): for i in para_fit: check(para_fit[i], para_real[i].value, sig=sig) def test_simple(): # create data to be fitted np.random.seed(1) x = np.linspace(0, 15, 301) data = (5. * np.sin(2 * x - 0.1) * np.exp(-x*x*0.025) + np.random.normal(size=len(x), scale=0.2)) # define objective function: returns the array to be minimized def fcn2min(params, x, data): """ model decaying sine wave, subtract data""" amp = params['amp'] shift = params['shift'] omega = params['omega'] decay = params['decay'] model = amp * np.sin(x * omega + shift) * np.exp(-x*x*decay) return model - data # create a set of Parameters params = Parameters() params.add('amp', value= 10, min=0) params.add('decay', value= 0.1) params.add('shift', value= 0.0, min=-pi / 2., max=pi / 2) params.add('omega', value= 3.0) # do fit, here with leastsq model result = minimize(fcn2min, params, args=(x, data)) # calculate final result final = data + result.residual # write error report print(" --> SIMPLE --> ") print(result.params) report_fit(result.params) #assert that the real parameters are found for para, val in zip(result.params.values(), [5, 0.025, -.1, 2]): check(para, val) def test_lbfgsb(): p_true = Parameters() p_true.add('amp', value=14.0) p_true.add('period', value=5.33) p_true.add('shift', value=0.123) p_true.add('decay', value=0.010) def residual(pars, x, data=None): amp = pars['amp'] per = pars['period'] shift = pars['shift'] decay = pars['decay'] if abs(shift) > pi/2: shift = shift - np.sign(shift) * pi model = amp * np.sin(shift + x / per) * np.exp(-x * x * decay * decay) if data is None: return model return (model - data) n = 2500 xmin = 0. xmax = 250.0 noise = np.random.normal(scale=0.7215, size=n) x = np.linspace(xmin, xmax, n) data = residual(p_true, x) + noise fit_params = Parameters() fit_params.add('amp', value=11.0, min=5, max=20) fit_params.add('period', value=5., min=1., max=7) fit_params.add('shift', value=.10, min=0.0, max=0.2) fit_params.add('decay', value=6.e-3, min=0, max=0.1) init = residual(fit_params, x) out = minimize(residual, fit_params, method='lbfgsb', args=(x,), kws={'data':data}) fit = residual(fit_params, x) for name, par in out.params.items(): nout = "%s:%s" % (name, ' '*(20-len(name))) print("%s: %s (%s) " % (nout, par.value, p_true[name].value)) for para, true_para in zip(out.params.values(), p_true.values()): check_wo_stderr(para, true_para.value) def test_derive(): def func(pars, x, data=None): model= pars['a'] * np.exp(-pars['b'] * x) + pars['c'] if data is None: return model return model - data def dfunc(pars, x, data=None): v = np.exp(-pars['b']*x) return np.array([v, -pars['a']*x*v, np.ones(len(x))]) def f(var, x): return var[0]* np.exp(-var[1] * x)+var[2] params1 = Parameters() params1.add('a', value=10) params1.add('b', value=10) params1.add('c', value=10) params2 = Parameters() params2.add('a', value=10) params2.add('b', value=10) params2.add('c', value=10) a, b, c = 2.5, 1.3, 0.8 x = np.linspace(0,4,50) y = f([a, b, c], x) data = y + 0.15*np.random.normal(size=len(x)) # fit without analytic derivative min1 = Minimizer(func, params1, fcn_args=(x,), fcn_kws={'data':data}) out1 = min1.leastsq() fit1 = func(out1.params, x) # fit with analytic derivative min2 = Minimizer(func, params2, fcn_args=(x,), fcn_kws={'data':data}) out2 = min2.leastsq(Dfun=dfunc, col_deriv=1) fit2 = func(out2.params, x) print ('''Comparison of fit to exponential decay with and without analytic derivatives, to model = a*exp(-b*x) + c for a = %.2f, b = %.2f, c = %.2f ============================================== Statistic/Parameter| Without | With | ---------------------------------------------- N Function Calls | %3i | %3i | Chi-square | %.4f | %.4f | a | %.4f | %.4f | b | %.4f | %.4f | c | %.4f | %.4f | ---------------------------------------------- ''' % (a, b, c, out1.nfev, out2.nfev, out1.chisqr, out2.chisqr, out1.params['a'].value, out2.params['a'].value, out1.params['b'].value, out2.params['b'].value, out1.params['c'].value, out2.params['c'].value )) check_wo_stderr(out1.params['a'], out2.params['a'].value, 0.00005) check_wo_stderr(out1.params['b'], out2.params['b'].value, 0.00005) check_wo_stderr(out1.params['c'], out2.params['c'].value, 0.00005) def test_peakfit(): def residual(pars, x, data=None): g1 = gaussian(x, pars['a1'], pars['c1'], pars['w1']) g2 = gaussian(x, pars['a2'], pars['c2'], pars['w2']) model = g1 + g2 if data is None: return model return (model - data) n = 601 xmin = 0. xmax = 15.0 noise = np.random.normal(scale=.65, size=n) x = np.linspace(xmin, xmax, n) org_params = Parameters() org_params.add_many(('a1', 12.0, True, None, None, None), ('c1', 5.3, True, None, None, None), ('w1', 1.0, True, None, None, None), ('a2', 9.1, True, None, None, None), ('c2', 8.1, True, None, None, None), ('w2', 2.5, True, None, None, None)) data = residual(org_params, x) + noise fit_params = Parameters() fit_params.add_many(('a1', 8.0, True, None, 14., None), ('c1', 5.0, True, None, None, None), ('w1', 0.7, True, None, None, None), ('a2', 3.1, True, None, None, None), ('c2', 8.8, True, None, None, None)) fit_params.add('w2', expr='2.5*w1') myfit = Minimizer(residual, fit_params, fcn_args=(x,), fcn_kws={'data': data}) myfit.prepare_fit() init = residual(fit_params, x) out = myfit.leastsq() # print(' N fev = ', myfit.nfev) # print(myfit.chisqr, myfit.redchi, myfit.nfree) report_fit(out.params) fit = residual(out.params, x) check_paras(out.params, org_params) def test_scalar_minimize_has_no_uncertainties(): # scalar_minimize doesn't calculate uncertainties. # when a scalar_minimize is run the stderr and correl for each parameter # should be None. (stderr and correl are set to None when a Parameter is # initialised). # This requires a reset after a leastsq fit has been done. # Only when scalar_minimize calculates stderr and correl can this test # be removed. np.random.seed(1) x = np.linspace(0, 15, 301) data = (5. * np.sin(2 * x - 0.1) * np.exp(-x*x*0.025) + np.random.normal(size=len(x), scale=0.2) ) # define objective function: returns the array to be minimized def fcn2min(params, x, data): """ model decaying sine wave, subtract data""" amp = params['amp'] shift = params['shift'] omega = params['omega'] decay = params['decay'] model = amp * np.sin(x * omega + shift) * np.exp(-x*x*decay) return model - data # create a set of Parameters params = Parameters() params.add('amp', value= 10, min=0) params.add('decay', value= 0.1) params.add('shift', value= 0.0, min=-pi / 2., max=pi / 2) params.add('omega', value= 3.0) mini = Minimizer(fcn2min, params, fcn_args=(x, data)) out = mini.minimize() assert_(np.isfinite(out.params['amp'].stderr)) print(out.errorbars) assert_(out.errorbars == True) out2 = mini.minimize(method='nelder-mead') assert_(out2.params['amp'].stderr is None) assert_(out2.params['decay'].stderr is None) assert_(out2.params['shift'].stderr is None) assert_(out2.params['omega'].stderr is None) assert_(out2.params['amp'].correl is None) assert_(out2.params['decay'].correl is None) assert_(out2.params['shift'].correl is None) assert_(out2.params['omega'].correl is None) assert_(out2.errorbars == False) def test_scalar_minimize_reduce_fcn(): # test that the reduce_fcn option for scalar_minimize # gives different and improved results with outliers np.random.seed(2) x = np.linspace(0, 10, 101) yo = 1.0 + 2.0*np.sin(4*x) * np.exp(-x / 5) y = yo + np.random.normal(size=len(yo), scale=0.250) outliers = np.random.random_integers(int(len(x)/3.0), len(x)-1, int(len(x)/12)) y[outliers] += 5*np.random.random(len(outliers)) # define objective function: returns the array to be minimized def objfunc(pars, x, data): decay = pars['decay'] offset= pars['offset'] omega = pars['omega'] amp = pars['amp'] model = offset + amp * np.sin(x*omega) * np.exp(-x/decay) return model - data # create a set of Parameters params = Parameters() params.add('offset', 2.0) params.add('omega', 3.3) params.add('amp', 2.5) params.add('decay', 1.0) method='L-BFGS-B' out1 = minimize(objfunc, params, args=(x, y), method=method) out2 = minimize(objfunc, params, args=(x, y), method=method, reduce_fcn='neglogcauchy') #print assert all assert_allclose(out1.params['omega'].value, 4.0, rtol=0.01) assert_allclose(out1.params['decay'].value, 7.6, rtol=0.01) assert_allclose(out2.params['omega'].value, 4.0, rtol=0.01) assert_allclose(out2.params['decay'].value, 5.8, rtol=0.01) def test_multidimensional_fit_GH205(): # test that you don't need to flatten the output from the objective # function. Tests regression for GH205. pos = np.linspace(0, 99, 100) xv, yv = np.meshgrid(pos, pos) f = lambda xv, yv, lambda1, lambda2: (np.sin(xv * lambda1) + np.cos(yv * lambda2)) data = f(xv, yv, 0.3, 3) assert_(data.ndim, 2) def fcn2min(params, xv, yv, data): """ model decaying sine wave, subtract data""" model = f(xv, yv, params['lambda1'], params['lambda2']) return model - data # create a set of Parameters params = Parameters() params.add('lambda1', value=0.4) params.add('lambda2', value=3.2) mini = Minimizer(fcn2min, params, fcn_args=(xv, yv, data)) res = mini.minimize() def test_ufloat(): """ test of ufloat from uncertainties """ x = ufloat((1, 0.1)) assert_allclose(x.nominal_value, 1.0, rtol=1.e-7) assert_allclose(x.std_dev(), 0.1, rtol=1.e-7) y = x*x assert_allclose(y.nominal_value, 1.0, rtol=1.e-7) assert_allclose(y.std_dev(), 0.2, rtol=1.e-7) y = x - x assert_allclose(y.nominal_value, 0.0, rtol=1.e-7) assert_allclose(y.std_dev(), 0.0, rtol=1.e-7) class CommonMinimizerTest(unittest.TestCase): def setUp(self): """ test scale minimizers except newton-cg (needs jacobian) and anneal (doesn't work out of the box). """ p_true = Parameters() p_true.add('amp', value=14.0) p_true.add('period', value=5.33) p_true.add('shift', value=0.123) p_true.add('decay', value=0.010) self.p_true = p_true n = 2500 xmin = 0. xmax = 250.0 noise = np.random.normal(scale=0.7215, size=n) self.x = np.linspace(xmin, xmax, n) self.data = self.residual(p_true, self.x) + noise fit_params = Parameters() fit_params.add('amp', value=11.0, min=5, max=20) fit_params.add('period', value=5., min=1., max=7) fit_params.add('shift', value=.10, min=0.0, max=0.2) fit_params.add('decay', value=6.e-3, min=0, max=0.1) self.fit_params = fit_params self.mini = Minimizer(self.residual, fit_params, [self.x, self.data]) def residual(self, pars, x, data=None): amp = pars['amp'] per = pars['period'] shift = pars['shift'] decay = pars['decay'] if abs(shift) > pi/2: shift = shift - np.sign(shift) * pi model = amp*np.sin(shift + x/per) * np.exp(-x*x*decay*decay) if data is None: return model return model - data def test_diffev_bounds_check(self): # You need finite (min, max) for each parameter if you're using # differential_evolution. self.fit_params['decay'].min = -np.inf self.fit_params['decay'].vary = True self.minimizer = 'differential_evolution' np.testing.assert_raises(ValueError, self.scalar_minimizer) # but only if a parameter is not fixed self.fit_params['decay'].vary = False self.mini.scalar_minimize(method='differential_evolution', maxiter=1) def test_scalar_minimizers(self): # test all the scalar minimizers for method in SCALAR_METHODS: if method in ['newton', 'dogleg', 'trust-ncg', 'cg']: continue self.minimizer = SCALAR_METHODS[method] if method == 'Nelder-Mead': sig = 0.2 else: sig = 0.15 self.scalar_minimizer(sig=sig) def scalar_minimizer(self, sig=0.15): try: from scipy.optimize import minimize as scipy_minimize except ImportError: raise SkipTest print(self.minimizer) out = self.mini.scalar_minimize(method=self.minimizer) self.residual(out.params, self.x) for name, par in out.params.items(): nout = "%s:%s" % (name, ' '*(20-len(name))) print("%s: %s (%s) " % (nout, par.value, self.p_true[name].value)) for para, true_para in zip(out.params.values(), self.p_true.values()): check_wo_stderr(para, true_para.value, sig=sig) def test_nan_policy(self): # check that an error is raised if there are nan in # the data returned by userfcn self.data[0] = np.nan for method in SCALAR_METHODS: assert_raises(ValueError, self.mini.scalar_minimize, SCALAR_METHODS[method]) assert_raises(ValueError, self.mini.minimize) # now check that the fit proceeds if nan_policy is 'omit' self.mini.nan_policy = 'omit' res = self.mini.minimize() assert_equal(res.ndata, np.size(self.data, 0) - 1) for para, true_para in zip(res.params.values(), self.p_true.values()): check_wo_stderr(para, true_para.value, sig=0.15) def test_nan_policy_function(self): a = np.array([0, 1, 2, 3, np.nan]) assert_raises(ValueError, _nan_policy, a) assert_(np.isnan(_nan_policy(a, nan_policy='propagate')[-1])) assert_equal(_nan_policy(a, nan_policy='omit'), [0, 1, 2, 3]) a[-1] = np.inf assert_raises(ValueError, _nan_policy, a) assert_(np.isposinf(_nan_policy(a, nan_policy='propagate')[-1])) assert_equal(_nan_policy(a, nan_policy='omit'), [0, 1, 2, 3]) assert_equal(_nan_policy(a, handle_inf=False), a) @decorators.slow def test_emcee(self): # test emcee if not HAS_EMCEE: return True np.random.seed(123456) out = self.mini.emcee(nwalkers=100, steps=200, burn=50, thin=10) check_paras(out.params, self.p_true, sig=3) @decorators.slow def test_emcee_PT(self): # test emcee with parallel tempering if not HAS_EMCEE: return True np.random.seed(123456) self.mini.userfcn = residual_for_multiprocessing out = self.mini.emcee(ntemps=4, nwalkers=50, steps=200, burn=100, thin=10, workers=2) check_paras(out.params, self.p_true, sig=3) @decorators.slow def test_emcee_multiprocessing(self): # test multiprocessing runs if not HAS_EMCEE: return True np.random.seed(123456) self.mini.userfcn = residual_for_multiprocessing out = self.mini.emcee(steps=10, workers=4) def test_emcee_bounds_length(self): # the log-probability functions check if the parameters are # inside the bounds. Check that the bounds and parameters # are the right lengths for comparison. This can be done # if nvarys != nparams if not HAS_EMCEE: return True self.mini.params['amp'].vary=False self.mini.params['period'].vary=False self.mini.params['shift'].vary=False out = self.mini.emcee(steps=10) @decorators.slow def test_emcee_partial_bounds(self): # mcmc with partial bounds if not HAS_EMCEE: return True np.random.seed(123456) # test mcmc output vs lm, some parameters not bounded self.fit_params['amp'].max = np.inf # self.fit_params['amp'].min = -np.inf out = self.mini.emcee(nwalkers=100, steps=300, burn=100, thin=10) check_paras(out.params, self.p_true, sig=3) def test_emcee_init_with_chain(self): # can you initialise with a previous chain if not HAS_EMCEE: return True out = self.mini.emcee(nwalkers=100, steps=5) # can initialise with a chain out2 = self.mini.emcee(nwalkers=100, steps=1, pos=out.chain) # can initialise with a correct subset of a chain out3 = self.mini.emcee(nwalkers=100, steps=1, pos=out.chain[..., -1, :]) # but you can't initialise if the shape is wrong. assert_raises(ValueError, self.mini.emcee, nwalkers=100, steps=1, pos=out.chain[..., -1, :-1]) def test_emcee_reuse_sampler(self): if not HAS_EMCEE: return True self.mini.emcee(nwalkers=100, steps=5) # if you've run the sampler the Minimizer object should have a _lastpos # attribute assert_(hasattr(self.mini, '_lastpos')) # now try and re-use sampler out2 = self.mini.emcee(steps=10, reuse_sampler=True) assert_(out2.chain.shape[1] == 15) # you shouldn't be able to reuse the sampler if nvarys has changed. self.mini.params['amp'].vary = False assert_raises(ValueError, self.mini.emcee, reuse_sampler=True) def test_emcee_lnpost(self): # check ln likelihood is calculated correctly. It should be # -0.5 * chi**2. result = self.mini.minimize() # obtain the numeric values # note - in this example all the parameters are varied fvars = np.array([par.value for par in result.params.values()]) # calculate the cost function with scaled values (parameters all have # lower and upper bounds. scaled_fvars = [] for par, fvar in zip(result.params.values(), fvars): par.value = fvar scaled_fvars.append(par.setup_bounds()) val = self.mini.penalty(np.array(scaled_fvars)) # calculate the log-likelihood value bounds = np.array([(par.min, par.max) for par in result.params.values()]) val2 = _lnpost(fvars, self.residual, result.params, result.var_names, bounds, userargs=(self.x, self.data)) assert_almost_equal(-0.5 * val, val2) def test_emcee_output(self): # test mcmc output if not HAS_EMCEE: return True try: from pandas import DataFrame except ImportError: return True out = self.mini.emcee(nwalkers=10, steps=20, burn=5, thin=2) assert_(isinstance(out, MinimizerResult)) assert_(isinstance(out.flatchain, DataFrame)) # check that we can access the chains via parameter name assert_(out.flatchain['amp'].shape[0] == 80) assert_(out.errorbars is True) assert_(np.isfinite(out.params['amp'].correl['period'])) # the lnprob array should be the same as the chain size assert_(np.size(out.chain)//out.nvarys == np.size(out.lnprob)) # test chain output shapes assert_(out.lnprob.shape == (10, (20-5+1)/2) ) assert_(out.chain.shape == (10, (20-5+1)/2, out.nvarys) ) assert_(out.flatchain.shape == (10*(20-5+1)/2, out.nvarys)) def test_emcee_PT_output(self): # test mcmc output when using parallel tempering if not HAS_EMCEE: return True try: from pandas import DataFrame except ImportError: return True out = self.mini.emcee(ntemps=6, nwalkers=10, steps=20, burn=5, thin=2) assert_(isinstance(out, MinimizerResult)) assert_(isinstance(out.flatchain, DataFrame)) # check that we can access the chains via parameter name assert_(out.flatchain['amp'].shape[0] == 80) assert_(out.errorbars is True) assert_(np.isfinite(out.params['amp'].correl['period'])) # the lnprob array should be the same as the chain size assert_(np.size(out.chain)//out.nvarys == np.size(out.lnprob)) # test chain output shapes assert_(out.lnprob.shape == (6, 10, (20-5+1)/2) ) assert_(out.chain.shape == (6, 10, (20-5+1)/2, out.nvarys) ) # Only the 0th temperature is returned assert_(out.flatchain.shape == (10*(20-5+1)/2, out.nvarys)) @decorators.slow def test_emcee_float(self): # test that it works if the residuals returns a float, not a vector if not HAS_EMCEE: return True def resid(pars, x, data=None): return -0.5 * np.sum(self.residual(pars, x, data=data)**2) # just return chi2 def resid2(pars, x, data=None): return np.sum(self.residual(pars, x, data=data)**2) self.mini.userfcn = resid np.random.seed(123456) out = self.mini.emcee(nwalkers=100, steps=200, burn=50, thin=10) check_paras(out.params, self.p_true, sig=3) self.mini.userfcn = resid2 np.random.seed(123456) out = self.mini.emcee(nwalkers=100, steps=200, burn=50, thin=10, float_behavior='chi2') check_paras(out.params, self.p_true, sig=3) @decorators.slow def test_emcee_seed(self): # test emcee seeding can reproduce a sampling run if not HAS_EMCEE: return True out = self.mini.emcee(params=self.fit_params, nwalkers=100, steps=1, seed=1) out2 = self.mini.emcee(params=self.fit_params, nwalkers=100, steps=1, seed=1) assert_almost_equal(out.chain, out2.chain) def residual_for_multiprocessing(pars, x, data=None): # a residual function defined in the top level is needed for # multiprocessing. bound methods don't work. amp = pars['amp'] per = pars['period'] shift = pars['shift'] decay = pars['decay'] if abs(shift) > pi/2: shift = shift - np.sign(shift) * pi model = amp*np.sin(shift + x/per) * np.exp(-x*x*decay*decay) if data is None: return model return (model - data) if __name__ == '__main__': nose.main() lmfit-0.9.7/tests/test_parameters.py0000644000076500000240000001511213107321643020470 0ustar Newvillestaff00000000000000from __future__ import print_function from lmfit import Parameters, Parameter from lmfit.parameter import isclose from numpy.testing import assert_, assert_almost_equal, assert_equal import unittest from copy import deepcopy, copy import numpy as np import pickle class TestParameters(unittest.TestCase): def setUp(self): self.params = Parameters() self.params.add_many(('a', 1., True, None, None, None), ('b', 2., True, None, None, None), ('c', 3., True, None, None, '2. * a')) def test_expr_was_evaluated(self): self.params.update_constraints() assert_almost_equal(self.params['c'].value, 2 * self.params['a'].value) def test_copy(self): # check simple Parameters.copy() does not fail # on non-trivial Parameters p1 = Parameters() p1.add('t', 2.0, min=0.0, max=5.0) p1.add('x', 10.0) p1.add('y', expr='x*t + sqrt(t)/3.0') p2 = p1.copy() assert(isinstance(p2, Parameters)) assert('t' in p2) assert('y' in p2) assert(p2['t'].max < 6.0) assert(np.isinf(p2['x'].max) and p2['x'].max > 0) assert(np.isinf(p2['x'].min) and p2['x'].min < 0) assert('sqrt(t)' in p2['y'].expr ) assert(p2._asteval is not None) assert(p2._asteval.symtable is not None) assert((p2['y'].value > 20) and (p2['y'].value < 21)) def test_copy_function(self): # check copy(Parameters) does not fail p1 = Parameters() p1.add('t', 2.0, min=0.0, max=5.0) p1.add('x', 10.0) p1.add('y', expr='x*t + sqrt(t)/3.0') p2 = copy(p1) assert(isinstance(p2, Parameters)) # change the 'x' value in the original p1['x'].value = 4.0 assert(p2['x'].value > 9.8) assert(p2['x'].value < 10.2) assert(np.isinf(p2['x'].max) and p2['x'].max > 0) assert('t' in p2) assert('y' in p2) assert(p2['t'].max < 6.0) assert(np.isinf(p2['x'].min) and p2['x'].min < 0) assert('sqrt(t)' in p2['y'].expr ) assert(p2._asteval is not None) assert(p2._asteval.symtable is not None) assert((p2['y'].value > 20) and (p2['y'].value < 21)) assert(p1['y'].value < 10) def test_deepcopy(self): # check that a simple copy works b = deepcopy(self.params) assert_(self.params == b) # check that we can add a symbol to the interpreter self.params['b'].expr = 'sin(1)' self.params['b'].value = 10 assert_almost_equal(self.params['b'].value, np.sin(1)) assert_almost_equal(self.params._asteval.symtable['b'], np.sin(1)) # check that the symbols in the interpreter are still the same after # deepcopying b = deepcopy(self.params) unique_symbols_params = self.params._asteval.user_defined_symbols() unique_symbols_b = self.params._asteval.user_defined_symbols() assert_(unique_symbols_b == unique_symbols_params) for unique_symbol in unique_symbols_b: if self.params._asteval.symtable[unique_symbol] is np.nan: continue assert_(self.params._asteval.symtable[unique_symbol] == b._asteval.symtable[unique_symbol]) def test_add_many_params(self): # test that we can add many parameters, but only parameters are added. a = Parameter('a', 1) b = Parameter('b', 2) p = Parameters() p.add_many(a, b) assert_(list(p.keys()) == ['a', 'b']) def test_expr_and_constraints_GH265(self): # test that parameters are reevaluated if they have bounds and expr # see GH265 p = Parameters() p['a'] = Parameter('a', 10, True) p['b'] = Parameter('b', 10, True, 0, 20) assert_equal(p['b'].min, 0) assert_equal(p['b'].max, 20) p['a'].expr = '2 * b' assert_almost_equal(p['a'].value, 20) p['b'].value = 15 assert_almost_equal(p['b'].value, 15) assert_almost_equal(p['a'].value, 30) p['b'].value = 30 assert_almost_equal(p['b'].value, 20) assert_almost_equal(p['a'].value, 40) def test_pickle_parameter(self): # test that we can pickle a Parameter p = Parameter('a', 10, True, 0, 1) pkl = pickle.dumps(p) q = pickle.loads(pkl) assert_(p == q) def test_pickle_parameters(self): # test that we can pickle a Parameters object p = Parameters() p.add('a', 10, True, 0, 100) p.add('b', 10, True, 0, 100, 'a * sin(1)') p.update_constraints() p._asteval.symtable['abc'] = '2 * 3.142' pkl = pickle.dumps(p, -1) q = pickle.loads(pkl) q.update_constraints() assert_(p == q) assert_(not p is q) # now test if the asteval machinery survived assert_(q._asteval.symtable['abc'] == '2 * 3.142') # check that unpickling of Parameters is not affected by expr that # refer to Parameter that are added later on. In the following # example var_0.expr refers to var_1, which is a Parameter later # on in the Parameters OrderedDict. p = Parameters() p.add('var_0', value=1) p.add('var_1', value=2) p['var_0'].expr = 'var_1' pkl = pickle.dumps(p) q = pickle.loads(pkl) def test_set_symtable(self): # test that we use Parameter.set(value=XXX) and have # that new value be used in constraint expressions pars = Parameters() pars.add('x', value=1.0) pars.add('y', expr='x + 1') assert_(isclose(pars['y'].value, 2.0)) pars['x'].set(value=3.0) assert_(isclose(pars['y'].value, 4.0)) def test_dumps_loads_parameters(self): # test that we can dumps() and then loads() a Parameters pars = Parameters() pars.add('x', value=1.0) pars.add('y', value=2.0) pars['x'].expr = 'y / 2.0' dumps = pars.dumps() newpars = Parameters().loads(dumps) newpars['y'].value = 100.0 assert_(isclose(newpars['x'].value, 50.0)) def test_isclose(self): assert_(isclose(1., 1+1e-5, atol=1e-4, rtol=0)) assert_(not isclose(1., 1+1e-5, atol=1e-6, rtol=0)) assert_(isclose(1e10, 1.00001e10, rtol=1e-5, atol=1e-8)) assert_(not isclose(0, np.inf)) assert_(not isclose(-np.inf, np.inf)) assert_(isclose(np.inf, np.inf)) assert_(not isclose(np.nan, np.nan)) if __name__ == '__main__': unittest.main() lmfit-0.9.7/tests/test_params_set.py0000644000076500000240000002106313066042256020471 0ustar Newvillestaff00000000000000import numpy as np from numpy.testing import assert_allclose from lmfit import Parameters, minimize, report_fit from lmfit.lineshapes import gaussian from lmfit.models import VoigtModel def test_param_set(): np.random.seed(2015) x = np.arange(0, 20, 0.05) y = gaussian(x, amplitude=15.43, center=4.5, sigma=2.13) y = y + 0.05 - 0.01*x + np.random.normal(scale=0.03, size=len(x)) model = VoigtModel() params = model.guess(y, x=x) # test #1: gamma is constrained to equal sigma assert(params['gamma'].expr == 'sigma') params.update_constraints() sigval = params['sigma'].value assert_allclose(params['gamma'].value, sigval, 1e-4, 1e-4, '', True) # test #2: explicitly setting a param value should work, even when # it had been an expression. The value will be left as fixed gamval = 0.87543 params['gamma'].set(value=gamval) assert(params['gamma'].expr is None) assert(not params['gamma'].vary) assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True) # test #3: explicitly setting an expression should work # Note, the only way to ensure that **ALL** constraints are up to date # is to call params.update_constraints(). This is because the constraint # may have multiple dependencies. params['gamma'].set(expr='sigma/2.0') assert(params['gamma'].expr is not None) assert(not params['gamma'].vary) params.update_constraints() assert_allclose(params['gamma'].value, sigval/2.0, 1e-4, 1e-4, '', True) # test #4: explicitly setting a param value WITH vary=True # will set it to be variable gamval = 0.7777 params['gamma'].set(value=gamval, vary=True) assert(params['gamma'].expr is None) assert(params['gamma'].vary) assert_allclose(params['gamma'].value, gamval, 1e-4, 1e-4, '', True) # test 5: make sure issue #389 is fixed: set boundaries and make sure # they are kept when changing the value amplitude_vary = params['amplitude'].vary amplitude_expr = params['amplitude'].expr params['amplitude'].set(min=0.0, max=100.0) params.update_constraints() assert_allclose(params['amplitude'].min, 0.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True) params['amplitude'].set(value=40.0) params.update_constraints() assert_allclose(params['amplitude'].value, 40.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].min, 0.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True) assert(params['amplitude'].expr == amplitude_expr) assert(params['amplitude'].vary == amplitude_vary) assert(not params['amplitude'].brute_step) # test for possible regressions of this fix (without 'expr'): # the set function should only change the requested attribute(s) params['amplitude'].set(value=35.0) params.update_constraints() assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].min, 0.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True) assert(params['amplitude'].vary == amplitude_vary) assert(params['amplitude'].expr == amplitude_expr) assert(not params['amplitude'].brute_step) # set minimum params['amplitude'].set(min=10.0) params.update_constraints() assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].max, 100.0, 1e-4, 1e-4, '', True) assert(params['amplitude'].vary == amplitude_vary) assert(params['amplitude'].expr == amplitude_expr) assert(not params['amplitude'].brute_step) # set maximum params['amplitude'].set(max=110.0) params.update_constraints() assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].max, 110.0, 1e-4, 1e-4, '', True) assert(params['amplitude'].vary == amplitude_vary) assert(params['amplitude'].expr == amplitude_expr) assert(not params['amplitude'].brute_step) # set vary params['amplitude'].set(vary=False) params.update_constraints() assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].max, 110.0, 1e-4, 1e-4, '', True) assert(params['amplitude'].vary == False) assert(params['amplitude'].expr == amplitude_expr) assert(not params['amplitude'].brute_step) # set brute_step params['amplitude'].set(brute_step=0.1) params.update_constraints() assert_allclose(params['amplitude'].value, 35.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].min, 10.0, 1e-4, 1e-4, '', True) assert_allclose(params['amplitude'].max, 110.0, 1e-4, 1e-4, '', True) assert(params['amplitude'].vary == False) assert(params['amplitude'].expr == amplitude_expr) assert_allclose(params['amplitude'].brute_step, 0.1, 1e-4, 1e-4, '', True) # test for possible regressions of this fix for variables WITH 'expr': height_value = params['height'].value height_min = params['height'].min height_max = params['height'].max height_vary = params['height'].vary height_expr = params['height'].expr height_brute_step = params['height'].brute_step # set vary=True should remove expression params['height'].set(vary=True) params.update_constraints() assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True) assert_allclose(params['height'].min, height_min, 1e-4, 1e-4, '', True) assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True) assert(params['height'].vary == True) assert(params['height'].expr == None) assert(params['height'].brute_step == height_brute_step) # setting an expression should set vary=False params['height'].set(expr=height_expr) params.update_constraints() assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True) assert_allclose(params['height'].min, height_min, 1e-4, 1e-4, '', True) assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True) assert(params['height'].vary == False) assert(params['height'].expr == height_expr) assert(params['height'].brute_step == height_brute_step) # changing min/max should not remove expression params['height'].set(min=0) params.update_constraints() assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True) assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True) assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True) assert(params['height'].vary == height_vary) assert(params['height'].expr == height_expr) assert(params['height'].brute_step == height_brute_step) # changing brute_step should not remove expression params['height'].set(brute_step=0.1) params.update_constraints() assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True) assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True) assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True) assert(params['height'].vary == height_vary) assert(params['height'].expr == height_expr) assert_allclose(params['amplitude'].brute_step, 0.1, 1e-4, 1e-4, '', True) # changing the value should remove expression and keep vary=False params['height'].set(brute_step=0) params['height'].set(value=10.0) params.update_constraints() assert_allclose(params['height'].value, 10.0, 1e-4, 1e-4, '', True) assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True) assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True) assert(params['height'].vary == False) assert(params['height'].expr == None) assert(params['height'].brute_step == height_brute_step) # passing expr='' should only remove the expression params['height'].set(expr=height_expr) # first restore the original expr params.update_constraints() params['height'].set(expr='') params.update_constraints() assert_allclose(params['height'].value, height_value, 1e-4, 1e-4, '', True) assert_allclose(params['height'].min, 0.0, 1e-4, 1e-4, '', True) assert_allclose(params['height'].max, height_max, 1e-4, 1e-4, '', True) assert(params['height'].vary == False) assert(params['height'].expr == None) assert(params['height'].brute_step == height_brute_step) test_param_set() lmfit-0.9.7/tests/test_stepmodel.py0000644000076500000240000000320513102246416020320 0ustar Newvillestaff00000000000000import numpy as np from lmfit import fit_report from lmfit.models import StepModel, ConstantModel from lmfit_testutils import assert_paramval, assert_paramattr def get_data(): x = np.linspace(0, 10, 201) dat = np.ones_like(x) dat[:48] = 0.0 dat[48:77] = np.arange(77-48)/(77.0-48) dat = dat + 5e-2*np.random.randn(len(x)) dat = 110.2 * dat + 12.0 return x, dat def test_stepmodel_linear(): x, y = get_data() stepmod = StepModel(form='linear') const = ConstantModel() pars = stepmod.guess(y, x) pars = pars + const.make_params(c=3*y.min()) mod = stepmod + const out = mod.fit(y, pars, x=x) assert(out.nfev > 5) assert(out.nvarys == 4) assert(out.chisqr > 1) assert(out.params['c'].value > 3) assert(out.params['center'].value > 1) assert(out.params['center'].value < 4) assert(out.params['sigma'].value > 0.5) assert(out.params['sigma'].value < 3.5) assert(out.params['amplitude'].value > 50) def test_stepmodel_erf(): x, y = get_data() stepmod = StepModel(form='linear') const = ConstantModel() pars = stepmod.guess(y, x) pars = pars + const.make_params(c=3*y.min()) mod = stepmod + const out = mod.fit(y, pars, x=x) assert(out.nfev > 5) assert(out.nvarys == 4) assert(out.chisqr > 1) assert(out.params['c'].value > 3) assert(out.params['center'].value > 1) assert(out.params['center'].value < 4) assert(out.params['amplitude'].value > 50) assert(out.params['sigma'].value > 0.2) assert(out.params['sigma'].value < 1.5) if __name__ == '__main__': # test_stepmodel_linear() test_stepmodel_erf() lmfit-0.9.7/THANKS.txt0000644000076500000240000000343413066042256015313 0ustar Newvillestaff00000000000000Many people have contributed to lmfit. The attribution of credit in a project such as this is very difficult to get perfect, and there are no doubt important contributions missing or under-represented here. Please consider this file as part of the documentation that may have bugs that need fixing. Some of the largest and most important contributions (approximately in order of contribution in size to the existing code) are from: Matthew Newville wrote the original version and maintains the project. Till Stensitzki wrote the improved estimates of confidence intervals, and contributed many tests, bug fixes, and documentation. A. R. J. Nelson added differential_evolution, emcee, and greatly improved the code, docstrings, and overall project. Daniel B. Allan wrote much of the high level Model code, and many improvements to the testing and documentation. Antonino Ingargiola wrote much of the high level Model code and has provided many bug fixes and improvements. Renee Otten wrote the brute force method, and has improved the code and documentation in many places. Michal Rawlik added plotting capabilities for Models. J. J. Helmus wrote the MINUT bounds for leastsq, originally in leastsqbounds.py, and ported to lmfit. E. O. Le Bigot wrote the uncertainties package, a version of which is used by lmfit. Additional patches, bug fixes, and suggestions have come from Christoph Deil, Francois Boulogne, Thomas Caswell, Colin Brosseau, nmearl, Gustavo Pasquevich, Clemens Prescher, LiCode, Ben Gamari, Yoav Roam, Alexander Stark, Alexandre Beelen, and many others. The lmfit code obviously depends on, and owes a very large debt to the code in scipy.optimize. Several discussions on the scipy-user and lmfit mailing lists have also led to improvements in this code. lmfit-0.9.7/versioneer.py0000644000076500000240000020600313066042256016312 0ustar Newvillestaff00000000000000 # Version: 0.18 """The Versioneer - like a rocketeer, but for versions. The Versioneer ============== * like a rocketeer, but for versions! * https://github.com/warner/python-versioneer * Brian Warner * License: Public Domain * Compatible With: python2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, and pypy * [![Latest Version] (https://pypip.in/version/versioneer/badge.svg?style=flat) ](https://pypi.python.org/pypi/versioneer/) * [![Build Status] (https://travis-ci.org/warner/python-versioneer.png?branch=master) ](https://travis-ci.org/warner/python-versioneer) This is a tool for managing a recorded version number in distutils-based python projects. The goal is to remove the tedious and error-prone "update the embedded version string" step from your release process. Making a new release should be as easy as recording a new tag in your version-control system, and maybe making new tarballs. ## Quick Install * `pip install versioneer` to somewhere to your $PATH * add a `[versioneer]` section to your setup.cfg (see below) * run `versioneer install` in your source tree, commit the results ## Version Identifiers Source trees come from a variety of places: * a version-control system checkout (mostly used by developers) * a nightly tarball, produced by build automation * a snapshot tarball, produced by a web-based VCS browser, like github's "tarball from tag" feature * a release tarball, produced by "setup.py sdist", distributed through PyPI Within each source tree, the version identifier (either a string or a number, this tool is format-agnostic) can come from a variety of places: * ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows about recent "tags" and an absolute revision-id * the name of the directory into which the tarball was unpacked * an expanded VCS keyword ($Id$, etc) * a `_version.py` created by some earlier build step For released software, the version identifier is closely related to a VCS tag. Some projects use tag names that include more than just the version string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool needs to strip the tag prefix to extract the version identifier. For unreleased software (between tags), the version identifier should provide enough information to help developers recreate the same tree, while also giving them an idea of roughly how old the tree is (after version 1.2, before version 1.3). Many VCS systems can report a description that captures this, for example `git describe --tags --dirty --always` reports things like "0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the 0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has uncommitted changes. The version identifier is used for multiple purposes: * to allow the module to self-identify its version: `myproject.__version__` * to choose a name and prefix for a 'setup.py sdist' tarball ## Theory of Operation Versioneer works by adding a special `_version.py` file into your source tree, where your `__init__.py` can import it. This `_version.py` knows how to dynamically ask the VCS tool for version information at import time. `_version.py` also contains `$Revision$` markers, and the installation process marks `_version.py` to have this marker rewritten with a tag name during the `git archive` command. As a result, generated tarballs will contain enough information to get the proper version. To allow `setup.py` to compute a version too, a `versioneer.py` is added to the top level of your source tree, next to `setup.py` and the `setup.cfg` that configures it. This overrides several distutils/setuptools commands to compute the version when invoked, and changes `setup.py build` and `setup.py sdist` to replace `_version.py` with a small static file that contains just the generated version data. ## Installation See [INSTALL.md](./INSTALL.md) for detailed installation instructions. ## Version-String Flavors Code which uses Versioneer can learn about its version string at runtime by importing `_version` from your main `__init__.py` file and running the `get_versions()` function. From the "outside" (e.g. in `setup.py`), you can import the top-level `versioneer.py` and run `get_versions()`. Both functions return a dictionary with different flavors of version information: * `['version']`: A condensed version string, rendered using the selected style. This is the most commonly used value for the project's version string. The default "pep440" style yields strings like `0.11`, `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section below for alternative styles. * `['full-revisionid']`: detailed revision identifier. For Git, this is the full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". * `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the commit date in ISO 8601 format. This will be None if the date is not available. * `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that this is only accurate if run in a VCS checkout, otherwise it is likely to be False or None * `['error']`: if the version string could not be computed, this will be set to a string describing the problem, otherwise it will be None. It may be useful to throw an exception in setup.py if this is set, to avoid e.g. creating tarballs with a version string of "unknown". Some variants are more useful than others. Including `full-revisionid` in a bug report should allow developers to reconstruct the exact code being tested (or indicate the presence of local changes that should be shared with the developers). `version` is suitable for display in an "about" box or a CLI `--version` output: it can be easily compared against release notes and lists of bugs fixed in various releases. The installer adds the following text to your `__init__.py` to place a basic version in `YOURPROJECT.__version__`: from ._version import get_versions __version__ = get_versions()['version'] del get_versions ## Styles The setup.cfg `style=` configuration controls how the VCS information is rendered into a version string. The default style, "pep440", produces a PEP440-compliant string, equal to the un-prefixed tag name for actual releases, and containing an additional "local version" section with more detail for in-between builds. For Git, this is TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags --dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and that this commit is two revisions ("+2") beyond the "0.11" tag. For released software (exactly equal to a known tag), the identifier will only contain the stripped tag, e.g. "0.11". Other styles are available. See [details.md](details.md) in the Versioneer source tree for descriptions. ## Debugging Versioneer tries to avoid fatal errors: if something goes wrong, it will tend to return a version of "0+unknown". To investigate the problem, run `setup.py version`, which will run the version-lookup code in a verbose mode, and will display the full contents of `get_versions()` (including the `error` string, which may help identify what went wrong). ## Known Limitations Some situations are known to cause problems for Versioneer. This details the most significant ones. More can be found on Github [issues page](https://github.com/warner/python-versioneer/issues). ### Subprojects Versioneer has limited support for source trees in which `setup.py` is not in the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are two common reasons why `setup.py` might not be in the root: * Source trees which contain multiple subprojects, such as [Buildbot](https://github.com/buildbot/buildbot), which contains both "master" and "slave" subprojects, each with their own `setup.py`, `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI distributions (and upload multiple independently-installable tarballs). * Source trees whose main purpose is to contain a C library, but which also provide bindings to Python (and perhaps other langauges) in subdirectories. Versioneer will look for `.git` in parent directories, and most operations should get the right version string. However `pip` and `setuptools` have bugs and implementation details which frequently cause `pip install .` from a subproject directory to fail to find a correct version string (so it usually defaults to `0+unknown`). `pip install --editable .` should work correctly. `setup.py install` might work too. Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in some later version. [Bug #38](https://github.com/warner/python-versioneer/issues/38) is tracking this issue. The discussion in [PR #61](https://github.com/warner/python-versioneer/pull/61) describes the issue from the Versioneer side in more detail. [pip PR#3176](https://github.com/pypa/pip/pull/3176) and [pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve pip to let Versioneer work correctly. Versioneer-0.16 and earlier only looked for a `.git` directory next to the `setup.cfg`, so subprojects were completely unsupported with those releases. ### Editable installs with setuptools <= 18.5 `setup.py develop` and `pip install --editable .` allow you to install a project into a virtualenv once, then continue editing the source code (and test) without re-installing after every change. "Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a convenient way to specify executable scripts that should be installed along with the python package. These both work as expected when using modern setuptools. When using setuptools-18.5 or earlier, however, certain operations will cause `pkg_resources.DistributionNotFound` errors when running the entrypoint script, which must be resolved by re-installing the package. This happens when the install happens with one version, then the egg_info data is regenerated while a different version is checked out. Many setup.py commands cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into a different virtualenv), so this can be surprising. [Bug #83](https://github.com/warner/python-versioneer/issues/83) describes this one, but upgrading to a newer version of setuptools should probably resolve it. ### Unicode version strings While Versioneer works (and is continually tested) with both Python 2 and Python 3, it is not entirely consistent with bytes-vs-unicode distinctions. Newer releases probably generate unicode version strings on py2. It's not clear that this is wrong, but it may be surprising for applications when then write these strings to a network connection or include them in bytes-oriented APIs like cryptographic checksums. [Bug #71](https://github.com/warner/python-versioneer/issues/71) investigates this question. ## Updating Versioneer To upgrade your project to a new release of Versioneer, do the following: * install the new Versioneer (`pip install -U versioneer` or equivalent) * edit `setup.cfg`, if necessary, to include any new configuration settings indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. * re-run `versioneer install` in your source tree, to replace `SRC/_version.py` * commit any changed files ## Future Directions This tool is designed to make it easily extended to other version-control systems: all VCS-specific components are in separate directories like src/git/ . The top-level `versioneer.py` script is assembled from these components by running make-versioneer.py . In the future, make-versioneer.py will take a VCS name as an argument, and will construct a version of `versioneer.py` that is specific to the given VCS. It might also take the configuration arguments that are currently provided manually during installation by editing setup.py . Alternatively, it might go the other direction and include code from all supported VCS systems, reducing the number of intermediate scripts. ## License To make Versioneer easier to embed, all its code is dedicated to the public domain. The `_version.py` that it creates is also in the public domain. Specifically, both are released under the Creative Commons "Public Domain Dedication" license (CC0-1.0), as described in https://creativecommons.org/publicdomain/zero/1.0/ . """ from __future__ import print_function try: import configparser except ImportError: import ConfigParser as configparser import errno import json import os import re import subprocess import sys class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_root(): """Get the project root directory. We require that all commands are run from the project root, i.e. the directory that contains setup.py, setup.cfg, and versioneer.py . """ root = os.path.realpath(os.path.abspath(os.getcwd())) setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): # allow 'python path/to/setup.py COMMAND' root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) setup_py = os.path.join(root, "setup.py") versioneer_py = os.path.join(root, "versioneer.py") if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): err = ("Versioneer was unable to run the project root directory. " "Versioneer requires setup.py to be executed from " "its immediate directory (like 'python setup.py COMMAND'), " "or in a way that lets it use sys.argv[0] to find the root " "(like 'python path/to/setup.py COMMAND').") raise VersioneerBadRootError(err) try: # Certain runtime workflows (setup.py install/develop in a setuptools # tree) execute all dependencies in a single python process, so # "versioneer" may be imported multiple times, and python's shared # module-import table will cache the first one. So we can't use # os.path.dirname(__file__), as that will find whichever # versioneer.py was first imported, even in later projects. me = os.path.realpath(os.path.abspath(__file__)) me_dir = os.path.normcase(os.path.splitext(me)[0]) vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) if me_dir != vsr_dir: print("Warning: build in %s is using versioneer.py from %s" % (os.path.dirname(me), versioneer_py)) except NameError: pass return root def get_config_from_root(root): """Read the project setup.cfg file to determine Versioneer config.""" # This might raise EnvironmentError (if setup.cfg is missing), or # configparser.NoSectionError (if it lacks a [versioneer] section), or # configparser.NoOptionError (if it lacks "VCS="). See the docstring at # the top of versioneer.py for instructions on writing your setup.cfg . setup_cfg = os.path.join(root, "setup.cfg") parser = configparser.SafeConfigParser() with open(setup_cfg, "r") as f: parser.readfp(f) VCS = parser.get("versioneer", "VCS") # mandatory def get(parser, name): if parser.has_option("versioneer", name): return parser.get("versioneer", name) return None cfg = VersioneerConfig() cfg.VCS = VCS cfg.style = get(parser, "style") or "" cfg.versionfile_source = get(parser, "versionfile_source") cfg.versionfile_build = get(parser, "versionfile_build") cfg.tag_prefix = get(parser, "tag_prefix") if cfg.tag_prefix in ("''", '""'): cfg.tag_prefix = "" cfg.parentdir_prefix = get(parser, "parentdir_prefix") cfg.verbose = get(parser, "verbose") return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" # these dictionaries contain VCS-specific tools LONG_VERSION_PY = {} HANDLERS = {} def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None for c in commands: try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git p = subprocess.Popen([c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None)) break except EnvironmentError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %s" % dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %s" % (commands,)) return None, None stdout = p.communicate()[0].strip() if sys.version_info[0] >= 3: stdout = stdout.decode() if p.returncode != 0: if verbose: print("unable to run %s (error)" % dispcmd) print("stdout was %s" % stdout) return None, p.returncode return stdout, p.returncode LONG_VERSION_PY['git'] = ''' # This file helps to compute a version number in source trees obtained from # git-archive tarball (such as those provided by githubs download-from-tag # feature). Distribution tarballs (built by setup.py sdist) and build # directories (produced by setup.py build) will contain a much shorter file # that just contains the computed version number. # This file is released into the public domain. Generated by # versioneer-0.18 (https://github.com/warner/python-versioneer) """Git implementation of _version.py.""" import errno import os import re import subprocess import sys def get_keywords(): """Get the keywords needed to look up the version information.""" # these strings will be replaced by git during git-archive. # setup.py/versioneer.py will grep for the variable names, so they must # each be defined on a line of their own. _version.py will just call # get_keywords(). git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} return keywords class VersioneerConfig: """Container for Versioneer configuration parameters.""" def get_config(): """Create, populate and return the VersioneerConfig() object.""" # these strings are filled in when 'setup.py versioneer' creates # _version.py cfg = VersioneerConfig() cfg.VCS = "git" cfg.style = "%(STYLE)s" cfg.tag_prefix = "%(TAG_PREFIX)s" cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" cfg.verbose = False return cfg class NotThisMethod(Exception): """Exception raised if a method is not valid for the current scenario.""" LONG_VERSION_PY = {} HANDLERS = {} def register_vcs_handler(vcs, method): # decorator """Decorator to mark a method as the handler for a particular VCS.""" def decorate(f): """Store f in HANDLERS[vcs][method].""" if vcs not in HANDLERS: HANDLERS[vcs] = {} HANDLERS[vcs][method] = f return f return decorate def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): """Call the given command(s).""" assert isinstance(commands, list) p = None for c in commands: try: dispcmd = str([c] + args) # remember shell=False, so use git.cmd on windows, not just git p = subprocess.Popen([c] + args, cwd=cwd, env=env, stdout=subprocess.PIPE, stderr=(subprocess.PIPE if hide_stderr else None)) break except EnvironmentError: e = sys.exc_info()[1] if e.errno == errno.ENOENT: continue if verbose: print("unable to run %%s" %% dispcmd) print(e) return None, None else: if verbose: print("unable to find command, tried %%s" %% (commands,)) return None, None stdout = p.communicate()[0].strip() if sys.version_info[0] >= 3: stdout = stdout.decode() if p.returncode != 0: if verbose: print("unable to run %%s (error)" %% dispcmd) print("stdout was %%s" %% stdout) return None, p.returncode return stdout, p.returncode def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %%s but none started with prefix %%s" %% (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: f = open(versionfile_abs, "r") for line in f.readlines(): if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) f.close() except EnvironmentError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if not keywords: raise NotThisMethod("no keywords at all, weird") date = keywords.get("date") if date is not None: # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = set([r.strip() for r in refnames.strip("()").split(",")]) # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %%d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%%s', no digits" %% ",".join(refs - tags)) if verbose: print("likely tags: %%s" %% ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] if verbose: print("picking %%s" %% r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %%s not under git control" %% root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%%s*" %% tag_prefix], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%%s'" %% describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%%s' doesn't start with prefix '%%s'" print(fmt %% (full_tag, tag_prefix)) pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" %% (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = run_command(GITS, ["show", "-s", "--format=%%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_pre(pieces): """TAG[.post.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post.devDISTANCE """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += ".post.dev%%d" %% pieces["distance"] else: # exception #1 rendered = "0.post.dev%%d" %% pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%%s" %% pieces["short"] else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%%s" %% pieces["short"] return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Eexceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%%d" %% pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%%s'" %% style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} def get_versions(): """Get version information or return default if unable to do so.""" # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have # __file__, we can work backwards from there to the root. Some # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which # case we can only use expanded keywords. cfg = get_config() verbose = cfg.verbose try: return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, verbose) except NotThisMethod: pass try: root = os.path.realpath(__file__) # versionfile_source is the relative path from the top of the source # tree (where the .git directory might live) to this file. Invert # this to find the root from __file__. for i in cfg.versionfile_source.split('/'): root = os.path.dirname(root) except NameError: return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to find root of source tree", "date": None} try: pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) return render(pieces, cfg.style) except NotThisMethod: pass try: if cfg.parentdir_prefix: return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) except NotThisMethod: pass return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} ''' @register_vcs_handler("git", "get_keywords") def git_get_keywords(versionfile_abs): """Extract version information from the given file.""" # the code embedded in _version.py can just fetch the value of these # keywords. When used from setup.py, we don't want to import _version.py, # so we do it with a regexp instead. This function is not used from # _version.py. keywords = {} try: f = open(versionfile_abs, "r") for line in f.readlines(): if line.strip().startswith("git_refnames ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["refnames"] = mo.group(1) if line.strip().startswith("git_full ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["full"] = mo.group(1) if line.strip().startswith("git_date ="): mo = re.search(r'=\s*"(.*)"', line) if mo: keywords["date"] = mo.group(1) f.close() except EnvironmentError: pass return keywords @register_vcs_handler("git", "keywords") def git_versions_from_keywords(keywords, tag_prefix, verbose): """Get version information from git keywords.""" if not keywords: raise NotThisMethod("no keywords at all, weird") date = keywords.get("date") if date is not None: # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 # -like" string, which we must then edit to make compliant), because # it's been around since git-1.5.3, and it's too difficult to # discover which version we're using, or to work around using an # older one. date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) refnames = keywords["refnames"].strip() if refnames.startswith("$Format"): if verbose: print("keywords are unexpanded, not using") raise NotThisMethod("unexpanded keywords, not a git-archive tarball") refs = set([r.strip() for r in refnames.strip("()").split(",")]) # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of # just "foo-1.0". If we see a "tag: " prefix, prefer those. TAG = "tag: " tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)]) if not tags: # Either we're using git < 1.8.3, or there really are no tags. We use # a heuristic: assume all version tags have a digit. The old git %d # expansion behaves like git log --decorate=short and strips out the # refs/heads/ and refs/tags/ prefixes that would let us distinguish # between branches and tags. By ignoring refnames without digits, we # filter out many common branch names like "release" and # "stabilization", as well as "HEAD" and "master". tags = set([r for r in refs if re.search(r'\d', r)]) if verbose: print("discarding '%s', no digits" % ",".join(refs - tags)) if verbose: print("likely tags: %s" % ",".join(sorted(tags))) for ref in sorted(tags): # sorting will prefer e.g. "2.0" over "2.0rc1" if ref.startswith(tag_prefix): r = ref[len(tag_prefix):] if verbose: print("picking %s" % r) return {"version": r, "full-revisionid": keywords["full"].strip(), "dirty": False, "error": None, "date": date} # no suitable tags, so version is "0+unknown", but full hex is still there if verbose: print("no suitable tags, using unknown + full revision id") return {"version": "0+unknown", "full-revisionid": keywords["full"].strip(), "dirty": False, "error": "no suitable tags", "date": None} @register_vcs_handler("git", "pieces_from_vcs") def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command): """Get version from 'git describe' in the root of the source tree. This only gets called if the git-archive 'subst' keywords were *not* expanded, and _version.py hasn't already been rewritten with a short version string, meaning we're inside a checked out source tree. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) if rc != 0: if verbose: print("Directory %s not under git control" % root) raise NotThisMethod("'git rev-parse --git-dir' returned error") # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] # if there isn't one, this yields HEX[-dirty] (no NUM) describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty", "--always", "--long", "--match", "%s*" % tag_prefix], cwd=root) # --long was added in git-1.5.5 if describe_out is None: raise NotThisMethod("'git describe' failed") describe_out = describe_out.strip() full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root) if full_out is None: raise NotThisMethod("'git rev-parse' failed") full_out = full_out.strip() pieces = {} pieces["long"] = full_out pieces["short"] = full_out[:7] # maybe improved later pieces["error"] = None # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] # TAG might have hyphens. git_describe = describe_out # look for -dirty suffix dirty = git_describe.endswith("-dirty") pieces["dirty"] = dirty if dirty: git_describe = git_describe[:git_describe.rindex("-dirty")] # now we have TAG-NUM-gHEX or HEX if "-" in git_describe: # TAG-NUM-gHEX mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) if not mo: # unparseable. Maybe git-describe is misbehaving? pieces["error"] = ("unable to parse git-describe output: '%s'" % describe_out) return pieces # tag full_tag = mo.group(1) if not full_tag.startswith(tag_prefix): if verbose: fmt = "tag '%s' doesn't start with prefix '%s'" print(fmt % (full_tag, tag_prefix)) pieces["error"] = ("tag '%s' doesn't start with prefix '%s'" % (full_tag, tag_prefix)) return pieces pieces["closest-tag"] = full_tag[len(tag_prefix):] # distance: number of commits since tag pieces["distance"] = int(mo.group(2)) # commit: short hex revision ID pieces["short"] = mo.group(3) else: # HEX: no tags pieces["closest-tag"] = None count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"], cwd=root) pieces["distance"] = int(count_out) # total number of commits # commit date: see ISO-8601 comment in git_versions_from_keywords() date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) return pieces def do_vcs_install(manifest_in, versionfile_source, ipy): """Git-specific installation logic for Versioneer. For Git, this means creating/changing .gitattributes to mark _version.py for export-subst keyword substitution. """ GITS = ["git"] if sys.platform == "win32": GITS = ["git.cmd", "git.exe"] files = [manifest_in, versionfile_source] if ipy: files.append(ipy) try: me = __file__ if me.endswith(".pyc") or me.endswith(".pyo"): me = os.path.splitext(me)[0] + ".py" versioneer_file = os.path.relpath(me) except NameError: versioneer_file = "versioneer.py" files.append(versioneer_file) present = False try: f = open(".gitattributes", "r") for line in f.readlines(): if line.strip().startswith(versionfile_source): if "export-subst" in line.strip().split()[1:]: present = True f.close() except EnvironmentError: pass if not present: f = open(".gitattributes", "a+") f.write("%s export-subst\n" % versionfile_source) f.close() files.append(".gitattributes") run_command(GITS, ["add", "--"] + files) def versions_from_parentdir(parentdir_prefix, root, verbose): """Try to determine the version from the parent directory name. Source tarballs conventionally unpack into a directory that includes both the project name and a version string. We will also support searching up two directory levels for an appropriately named parent directory """ rootdirs = [] for i in range(3): dirname = os.path.basename(root) if dirname.startswith(parentdir_prefix): return {"version": dirname[len(parentdir_prefix):], "full-revisionid": None, "dirty": False, "error": None, "date": None} else: rootdirs.append(root) root = os.path.dirname(root) # up a level if verbose: print("Tried directories %s but none started with prefix %s" % (str(rootdirs), parentdir_prefix)) raise NotThisMethod("rootdir doesn't start with parentdir_prefix") SHORT_VERSION_PY = """ # This file was generated by 'versioneer.py' (0.18) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. import json version_json = ''' %s ''' # END VERSION_JSON def get_versions(): return json.loads(version_json) """ def versions_from_file(filename): """Try to determine the version from _version.py if present.""" try: with open(filename) as f: contents = f.read() except EnvironmentError: raise NotThisMethod("unable to read _version.py") mo = re.search(r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: mo = re.search(r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S) if not mo: raise NotThisMethod("no version_json in _version.py") return json.loads(mo.group(1)) def write_to_version_file(filename, versions): """Write the given version number to the given _version.py file.""" os.unlink(filename) contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) with open(filename, "w") as f: f.write(SHORT_VERSION_PY % contents) print("set %s to '%s'" % (filename, versions["version"])) def plus_or_dot(pieces): """Return a + if we don't already have one, else return a .""" if "+" in pieces.get("closest-tag", ""): return "." return "+" def render_pep440(pieces): """Build up version string, with post-release "local version identifier". Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty Exceptions: 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += plus_or_dot(pieces) rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" else: # exception #1 rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) if pieces["dirty"]: rendered += ".dirty" return rendered def render_pep440_pre(pieces): """TAG[.post.devDISTANCE] -- No -dirty. Exceptions: 1: no tags. 0.post.devDISTANCE """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += ".post.dev%d" % pieces["distance"] else: # exception #1 rendered = "0.post.dev%d" % pieces["distance"] return rendered def render_pep440_post(pieces): """TAG[.postDISTANCE[.dev0]+gHEX] . The ".dev0" means dirty. Note that .dev0 sorts backwards (a dirty tree will appear "older" than the corresponding clean one), but you shouldn't be releasing software with -dirty anyways. Exceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += plus_or_dot(pieces) rendered += "g%s" % pieces["short"] else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" rendered += "+g%s" % pieces["short"] return rendered def render_pep440_old(pieces): """TAG[.postDISTANCE[.dev0]] . The ".dev0" means dirty. Eexceptions: 1: no tags. 0.postDISTANCE[.dev0] """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"] or pieces["dirty"]: rendered += ".post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" else: # exception #1 rendered = "0.post%d" % pieces["distance"] if pieces["dirty"]: rendered += ".dev0" return rendered def render_git_describe(pieces): """TAG[-DISTANCE-gHEX][-dirty]. Like 'git describe --tags --dirty --always'. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] if pieces["distance"]: rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render_git_describe_long(pieces): """TAG-DISTANCE-gHEX[-dirty]. Like 'git describe --tags --dirty --always -long'. The distance/hash is unconditional. Exceptions: 1: no tags. HEX[-dirty] (note: no 'g' prefix) """ if pieces["closest-tag"]: rendered = pieces["closest-tag"] rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) else: # exception #1 rendered = pieces["short"] if pieces["dirty"]: rendered += "-dirty" return rendered def render(pieces, style): """Render the given version pieces into the requested style.""" if pieces["error"]: return {"version": "unknown", "full-revisionid": pieces.get("long"), "dirty": None, "error": pieces["error"], "date": None} if not style or style == "default": style = "pep440" # the default if style == "pep440": rendered = render_pep440(pieces) elif style == "pep440-pre": rendered = render_pep440_pre(pieces) elif style == "pep440-post": rendered = render_pep440_post(pieces) elif style == "pep440-old": rendered = render_pep440_old(pieces) elif style == "git-describe": rendered = render_git_describe(pieces) elif style == "git-describe-long": rendered = render_git_describe_long(pieces) else: raise ValueError("unknown style '%s'" % style) return {"version": rendered, "full-revisionid": pieces["long"], "dirty": pieces["dirty"], "error": None, "date": pieces.get("date")} class VersioneerBadRootError(Exception): """The project root directory is unknown or missing key files.""" def get_versions(verbose=False): """Get the project version from whatever source is available. Returns dict with two keys: 'version' and 'full'. """ if "versioneer" in sys.modules: # see the discussion in cmdclass.py:get_cmdclass() del sys.modules["versioneer"] root = get_root() cfg = get_config_from_root(root) assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" handlers = HANDLERS.get(cfg.VCS) assert handlers, "unrecognized VCS '%s'" % cfg.VCS verbose = verbose or cfg.verbose assert cfg.versionfile_source is not None, \ "please set versioneer.versionfile_source" assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" versionfile_abs = os.path.join(root, cfg.versionfile_source) # extract version from first of: _version.py, VCS command (e.g. 'git # describe'), parentdir. This is meant to work for developers using a # source checkout, for users of a tarball created by 'setup.py sdist', # and for users of a tarball/zipball created by 'git archive' or github's # download-from-tag feature or the equivalent in other VCSes. get_keywords_f = handlers.get("get_keywords") from_keywords_f = handlers.get("keywords") if get_keywords_f and from_keywords_f: try: keywords = get_keywords_f(versionfile_abs) ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) if verbose: print("got version from expanded keyword %s" % ver) return ver except NotThisMethod: pass try: ver = versions_from_file(versionfile_abs) if verbose: print("got version from file %s %s" % (versionfile_abs, ver)) return ver except NotThisMethod: pass from_vcs_f = handlers.get("pieces_from_vcs") if from_vcs_f: try: pieces = from_vcs_f(cfg.tag_prefix, root, verbose) ver = render(pieces, cfg.style) if verbose: print("got version from VCS %s" % ver) return ver except NotThisMethod: pass try: if cfg.parentdir_prefix: ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) if verbose: print("got version from parentdir %s" % ver) return ver except NotThisMethod: pass if verbose: print("unable to compute version") return {"version": "0+unknown", "full-revisionid": None, "dirty": None, "error": "unable to compute version", "date": None} def get_version(): """Get the short version string for this project.""" return get_versions()["version"] def get_cmdclass(): """Get the custom setuptools/distutils subclasses used by Versioneer.""" if "versioneer" in sys.modules: del sys.modules["versioneer"] # this fixes the "python setup.py develop" case (also 'install' and # 'easy_install .'), in which subdependencies of the main project are # built (using setup.py bdist_egg) in the same python process. Assume # a main project A and a dependency B, which use different versions # of Versioneer. A's setup.py imports A's Versioneer, leaving it in # sys.modules by the time B's setup.py is executed, causing B to run # with the wrong versioneer. Setuptools wraps the sub-dep builds in a # sandbox that restores sys.modules to it's pre-build state, so the # parent is protected against the child's "import versioneer". By # removing ourselves from sys.modules here, before the child build # happens, we protect the child from the parent's versioneer too. # Also see https://github.com/warner/python-versioneer/issues/52 cmds = {} # we add "version" to both distutils and setuptools from distutils.core import Command class cmd_version(Command): description = "report generated version string" user_options = [] boolean_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): vers = get_versions(verbose=True) print("Version: %s" % vers["version"]) print(" full-revisionid: %s" % vers.get("full-revisionid")) print(" dirty: %s" % vers.get("dirty")) print(" date: %s" % vers.get("date")) if vers["error"]: print(" error: %s" % vers["error"]) cmds["version"] = cmd_version # we override "build_py" in both distutils and setuptools # # most invocation pathways end up running build_py: # distutils/build -> build_py # distutils/install -> distutils/build ->.. # setuptools/bdist_wheel -> distutils/install ->.. # setuptools/bdist_egg -> distutils/install_lib -> build_py # setuptools/install -> bdist_egg ->.. # setuptools/develop -> ? # pip install: # copies source tree to a tempdir before running egg_info/etc # if .git isn't copied too, 'git describe' will fail # then does setup.py bdist_wheel, or sometimes setup.py install # setup.py egg_info -> ? # we override different "build_py" commands for both environments if "setuptools" in sys.modules: from setuptools.command.build_py import build_py as _build_py else: from distutils.command.build_py import build_py as _build_py class cmd_build_py(_build_py): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() _build_py.run(self) # now locate _version.py in the new build/ directory and replace # it with an updated value if cfg.versionfile_build: target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) cmds["build_py"] = cmd_build_py if "cx_Freeze" in sys.modules: # cx_freeze enabled? from cx_Freeze.dist import build_exe as _build_exe # nczeczulin reports that py2exe won't like the pep440-style string # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. # setup(console=[{ # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION # "product_version": versioneer.get_version(), # ... class cmd_build_exe(_build_exe): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _build_exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["build_exe"] = cmd_build_exe del cmds["build_py"] if 'py2exe' in sys.modules: # py2exe enabled? try: from py2exe.distutils_buildexe import py2exe as _py2exe # py3 except ImportError: from py2exe.build_exe import py2exe as _py2exe # py2 class cmd_py2exe(_py2exe): def run(self): root = get_root() cfg = get_config_from_root(root) versions = get_versions() target_versionfile = cfg.versionfile_source print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, versions) _py2exe.run(self) os.unlink(target_versionfile) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) cmds["py2exe"] = cmd_py2exe # we override different "sdist" commands for both environments if "setuptools" in sys.modules: from setuptools.command.sdist import sdist as _sdist else: from distutils.command.sdist import sdist as _sdist class cmd_sdist(_sdist): def run(self): versions = get_versions() self._versioneer_generated_versions = versions # unless we update this, the command will keep using the old # version self.distribution.metadata.version = versions["version"] return _sdist.run(self) def make_release_tree(self, base_dir, files): root = get_root() cfg = get_config_from_root(root) _sdist.make_release_tree(self, base_dir, files) # now locate _version.py in the new base_dir directory # (remembering that it may be a hardlink) and replace it with an # updated value target_versionfile = os.path.join(base_dir, cfg.versionfile_source) print("UPDATING %s" % target_versionfile) write_to_version_file(target_versionfile, self._versioneer_generated_versions) cmds["sdist"] = cmd_sdist return cmds CONFIG_ERROR = """ setup.cfg is missing the necessary Versioneer configuration. You need a section like: [versioneer] VCS = git style = pep440 versionfile_source = src/myproject/_version.py versionfile_build = myproject/_version.py tag_prefix = parentdir_prefix = myproject- You will also need to edit your setup.py to use the results: import versioneer setup(version=versioneer.get_version(), cmdclass=versioneer.get_cmdclass(), ...) Please read the docstring in ./versioneer.py for configuration instructions, edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. """ SAMPLE_CONFIG = """ # See the docstring in versioneer.py for instructions. Note that you must # re-run 'versioneer.py setup' after changing this section, and commit the # resulting files. [versioneer] #VCS = git #style = pep440 #versionfile_source = #versionfile_build = #tag_prefix = #parentdir_prefix = """ INIT_PY_SNIPPET = """ from ._version import get_versions __version__ = get_versions()['version'] del get_versions """ def do_setup(): """Main VCS-independent setup function for installing Versioneer.""" root = get_root() try: cfg = get_config_from_root(root) except (EnvironmentError, configparser.NoSectionError, configparser.NoOptionError) as e: if isinstance(e, (EnvironmentError, configparser.NoSectionError)): print("Adding sample versioneer config to setup.cfg", file=sys.stderr) with open(os.path.join(root, "setup.cfg"), "a") as f: f.write(SAMPLE_CONFIG) print(CONFIG_ERROR, file=sys.stderr) return 1 print(" creating %s" % cfg.versionfile_source) with open(cfg.versionfile_source, "w") as f: LONG = LONG_VERSION_PY[cfg.VCS] f.write(LONG % {"DOLLAR": "$", "STYLE": cfg.style, "TAG_PREFIX": cfg.tag_prefix, "PARENTDIR_PREFIX": cfg.parentdir_prefix, "VERSIONFILE_SOURCE": cfg.versionfile_source, }) ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") if os.path.exists(ipy): try: with open(ipy, "r") as f: old = f.read() except EnvironmentError: old = "" if INIT_PY_SNIPPET not in old: print(" appending to %s" % ipy) with open(ipy, "a") as f: f.write(INIT_PY_SNIPPET) else: print(" %s unmodified" % ipy) else: print(" %s doesn't exist, ok" % ipy) ipy = None # Make sure both the top-level "versioneer.py" and versionfile_source # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so # they'll be copied into source distributions. Pip won't be able to # install the package without this. manifest_in = os.path.join(root, "MANIFEST.in") simple_includes = set() try: with open(manifest_in, "r") as f: for line in f: if line.startswith("include "): for include in line.split()[1:]: simple_includes.add(include) except EnvironmentError: pass # That doesn't cover everything MANIFEST.in can do # (http://docs.python.org/2/distutils/sourcedist.html#commands), so # it might give some false negatives. Appending redundant 'include' # lines is safe, though. if "versioneer.py" not in simple_includes: print(" appending 'versioneer.py' to MANIFEST.in") with open(manifest_in, "a") as f: f.write("include versioneer.py\n") else: print(" 'versioneer.py' already in MANIFEST.in") if cfg.versionfile_source not in simple_includes: print(" appending versionfile_source ('%s') to MANIFEST.in" % cfg.versionfile_source) with open(manifest_in, "a") as f: f.write("include %s\n" % cfg.versionfile_source) else: print(" versionfile_source already in MANIFEST.in") # Make VCS-specific changes. For git, this means creating/changing # .gitattributes to mark _version.py for export-subst keyword # substitution. do_vcs_install(manifest_in, cfg.versionfile_source, ipy) return 0 def scan_setup_py(): """Validate the contents of setup.py against Versioneer's expectations.""" found = set() setters = False errors = 0 with open("setup.py", "r") as f: for line in f.readlines(): if "import versioneer" in line: found.add("import") if "versioneer.get_cmdclass()" in line: found.add("cmdclass") if "versioneer.get_version()" in line: found.add("get_version") if "versioneer.VCS" in line: setters = True if "versioneer.versionfile_source" in line: setters = True if len(found) != 3: print("") print("Your setup.py appears to be missing some important items") print("(but I might be wrong). Please make sure it has something") print("roughly like the following:") print("") print(" import versioneer") print(" setup( version=versioneer.get_version(),") print(" cmdclass=versioneer.get_cmdclass(), ...)") print("") errors += 1 if setters: print("You should remove lines like 'versioneer.VCS = ' and") print("'versioneer.versionfile_source = ' . This configuration") print("now lives in setup.cfg, and should be removed from setup.py") print("") errors += 1 return errors if __name__ == "__main__": cmd = sys.argv[1] if cmd == "setup": errors = do_setup() errors += scan_setup_py() if errors: sys.exit(1)