mixsqp/0000755000176200001440000000000014540660612011577 5ustar liggesusersmixsqp/NAMESPACE0000644000176200001440000000051414540622273013017 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(mixobjective) export(mixsqp) export(mixsqp_control_default) export(simulatemixdata) importFrom(Rcpp,evalCpp) importFrom(irlba,irlba) importFrom(stats,dnorm) importFrom(stats,rnorm) importFrom(stats,rt) importFrom(utils,modifyList) importFrom(utils,sessionInfo) useDynLib(mixsqp) mixsqp/LICENSE0000644000176200001440000000014513663203332012601 0ustar liggesusersYEAR: 2017-2020 COPYRIGHT HOLDER: Youngseok Kim, Peter Carbonetto, Matthew Stephens, Mihai Anitescu. mixsqp/data/0000755000176200001440000000000013565526670012523 5ustar liggesusersmixsqp/data/tacks.RData0000644000176200001440000004260713565526670014556 0ustar liggesusersż?o4QHJDK]J"I {BHE$ !#{T)-$u\>z>ց;\ļK120-<.r5wY ,)J+ YUW|E\g狩]'ީ*1*(m|eR>*A4V =I"i \C(ܲ(b~ShLUГ)G!y`hɶއmPR\,8y`K#=>k˽6t_Wg|IM ;iETm{Uajtw 'O1;rpFc`/lwۇ7,$im/3bOW ?IůۻׅoF' A;k\,+= 8xI ;~>[/OmU'UfUcG)9`uиf9c ,zm< ~hͩ%(uwteը/5dKԣ)#c- Zzw 66@sƛeapZASqz< &j"P;ґ` jj;UԉI?]cKm6#_(m,3.f?"9" ͙]Pm޿uwbt-{,4A?'ZaV 8ѵT%}SskLwߏb*/͌1Z}J3qժvԤD8vh@ M^Hn~+EleT螗T|uHs%(@퉾.+$rE8(4fՈcwne#`ҺgD+Oq*ј@.Ўu >cTk,Ɣ[yk8 Vn<قrc&( t9b{/hJu>RC% YQwyE@_;}^Ahalf}~6o]}O%]z;a|ԛMM)ϯ.fB_k|wY<>v}x؂h$Fy^3k᮷Wبe#A'[o3?lImxT,bfQY~&im=c,HY}zP;㗝Ho O )V@8°L&,-UjX쥗T^Dl. QQGa.iVKl9aA4sKnjO|j9/\ +5x\4U娜$*NFZ˗*}Wk^.5sVf,3ӦȧGuWw=u?Fl ~\?sJ|.+E"o;|h㔋d_GlȦ:MXx]H)pnqjxri2+j8oY11)U7j`ٜ:hZWOJq?f66MF\ NeM6׫=^gC:@n{9hܯa+/yZ43nMMc傑#vDznr5~ ;S8[WU7 Yg`@&n|QQ^L_d:vBY0Wxt8\-*¹Kk 7c6*?;yQq's6sçhti8LW !l“6~k^7c ׁ֭=EO%{ Uchw~2[c, )J!]:l H]3k g=`ū_{QldrrHrC+ uɇMz޸2m G5݀#f[ϚU=ջu+!"z*\:Z$jj ,Gh0.QE}#̳~>|Q:#;NKEz_7S#A,Xo0$'k-7y?(vG|# yE|B 14x4%Л* +ӮD/7" N?7 CRLJ_)Ww@sAZ8`7ho\FvnQ;y_೿?C>tzfo2T͕=]p5f{gœsHy))mrUnwkP޿h6v-JA..M| %ToHf }&t Y -W !m#j}Amu;HUT_64RY_aŇh익L9BdM ϛM9w)mtXn2#5+=o몺x0[])ta7G?7nQxy iig#R/}t<^Wn_ %Qz2=0ͿlF7>u5D'%o#Ll:ū{bZg(I5Vn_ܢpU|8).o u5~sT]kI %wG[7'vI>3KXSP8(Җ-̫8J&|G&>6ka8kg"\b eO(C֓d2sp~.pb:ҐT$ݽWYh>Q8da V{5yBOoF9TlS^ti;/uz,^y lŋ<_:6&?0,C z9˾CպIH:'f7EC^I$QеFCʴ:p\c=*M0$ku\~K3~5bFSH=j},2u5z+ʞ~}$F[~꺘=G ~6xDzk=5Z GYnRwՉ3ZPں5uf;, 6!e7Mt.BokP;rRWƙo߭~?P{ G֚B_qcP>2CNؙlЀ@Mt5iQ\ *R9o^?U\ΊBQxk,rovA߳h[n!ᅁbpuYIp0vѪ b6_$ gܾ0`<8X}WBCEc{ =e~0/+ש.9i(2A- X$?>[bF*'ƿ8r d,7k PUJ*lcвMD~Aw}*tJ4)<^ {o/y|)bkY@UB}+hZ'=hWP_o6C$^h2lŲ~{f밣jeIh&(tED[IZϬf]̡} <)-sQV {6y7^Dw)=iRBB.|fB1eUfW)V) Qהa"s<\֎A[J4ّ k8jr RImκ.4l]=S׫[5a}|V} Y۸*J YePN17};3~Q o_ѥ~i mq>8G>Z|Jlw)zz%pNMr3-bE9` ٱxB^*h=n 0ZX  ׫D K,,;#^[΂ ڟ8, s66uчG.ij'J%rj/->3,f+@,AOrG觅b%ch˘T&c!Nf?M|GRNP PiKߐ7sð4o)W5ˍY&C|K/pt}~m,~T)=#:5BՇꩄ@)Om\ܱd)>aziet8mײդx ݷ/ECok2tp){~= e 7V\IV9pTpsvoF3wQg^Ό,`4 .'b%#(e(pHtGb!xzuF[<1} V].QuǢI:~s^)E;c w\˦p+Y,d \})EoBpt&/1\NW{~ԕGp&QԔjuR>2w *hgbmV޿f'"}>ꕛцpyej4nخP?xߴu[2hڷcffc^R`j4,3V,Km^S‚OwM`.a4q""hӚ{gI0CL\ ˙wpˡq[Sw|gY =Bd:jQ'4 .ݔ^rEAˉ\@9(b[sR n K{QI /qϱ M_0RrQ2OЫ^»KJ8 vYnJ+D@{ 8'~Z(zU(9f4nʺA/c'Iл*"_8ٙ9ux䔑 8N=k6w%آ&3" Se-+2{sPMpAJϲt%' Cܸf^<7* uWq =U_^C61<>q{n%qmk:O옊PUD?\ς:e{Ì]м[цv&jm n?81V.ܵW>W}7IqOkrʴmhn:8qg[s pԝm!r|vZ k79\q\ 3_Xۻ3.F-ڟ1K5I"5O j\"NfC;CT㟦-ޮFgy羁G^5Ӟ$ߘvm)I䪅Β?ۡU!(-Pdp7^3k[@1|^?)>^Y ty`7Bkƹj(}4tZs4pؕ510X痄Lg*\fg@ IꩈP-1 T(n}^H>WK-,ݿ~P);:nouyu+KP6i/ )bɃR 8tu.<,X ThgH韁NX~vC0}^50k=L Wj +9wc҂Vqq-{&󂎬,NӴQeO۹.6?Pi> Ƕ?\:%FkJ;e7hfع{eU :l~7[w Ĺ5.(JUxΘmek]3Sbq[^h?iybff\+AW#!/활FWy3M H%{9fFsʜ^x3a ͆.d]'_ 5 Orz]P NCGPSzS}p&vԵ |vYҿZw%Ϡ{࿷>?`ѓs~E(tf-ZQNFa{e:%%>,Ɗ]\ˮ"_\;_[,zsL-B笭F@Ԇe3,s~{˝!$f-6L]oLr|)0ᔳq~Pf z'n.h\PV2CN}hHr ޱ ar͡ sw<{33.}8zLtw̟CWae}^f 7{~fo隅{ᨽ[t5D@`-zzb;!\~Xt[RÃ׊9q̕ z6OsnSBsCh{m`܏~MZ(_.rBv/ =-+B)B}=:*sUiv?ZlpϪ~s-댡@u~ķдZ$Y>A]а>..{U({nz |x{`F ?MAhk(=Z/Cwa3p%`LHPYދ *ΝQƍ\,yg7A 6m0>wYxnpM6DX6j=OφFA*eцېYjFr n3Kenj8z?C xc{NRwYZRLdd_\O|)q y=46Vq +]LԜZ`TE$伴c "ZBRY7}n4mJ2 YVԶrbCagY3U ^4wD',sÏWg|wSx8̞)n5WgUn2~VZp@_AKG_0a40|E( 7CJm3M=pYau L: zm>R:E'+JtB=~#ko. 8Oxq֏WYAT?%γ+]zF-D@s_B5<J$<W;}7Y i5x :o>{;t$Xi9=/.SZ( n(?Xwk tiy@j曉GP, n_a| =w7?zڄnrC4H <5u?h \sH7R^sHeow]O߲BOz!*׶n[u'T+T)p!Ԥ#(D(m9hHK_>^*Szc4 mfٌAś|E:gl8 *|I/.AU?PH۴A E оǮ1c7Tfa; s6?Ï1p8bah$3rT V $j f_?*nosJ?-4@>߼X|JD݂6CEtK7 ]NB"v!PN&Z1.wkFSHGYCKu*D:,nz >fo$K^dX|x V="ȆRKӹCա5ܹi@&zB~r@uK<8_ў2d+K|RJ@VC.J2v}=[ʰB.ANjͲšf0xQG?|E\Ym4Ƕ /:?q Ɗş^buYȈ:%O @-}*v1ɽV@9C)A_8hK̃c!a8V?=8wn0n=20%K=}п/لR? {@<N~B~NF~J~zڶSuD]^'&:v_gX(_uJ^uL^uN^}`T.}B7}DW}Fw}Hޗ -y5y=9ȹ@ MԞ#sŀ~ΐsC\"9nz%I59B?9HErNsw Yڹ{~s&89R{$s_힐++ZG>C^"=F5rϑ{i񵦘vHIro{ܫ%._nO)=N<ޗ@ξ[4 qq,ΐuuH(Kdhuʾ!`*N'zCR琺A."u\~2puU: uNzF2ZfӸK7Rԉn$u$+)ݤם%u)SIJXRג:sz(p]l"zLhZ]lk\wkG]94.'u:IOzR瓺y6N o }+HA҇뒲Ά(zBא>="}铼&Y.(eW>k3`}X8/i]o{?*ku#}I_HD7>o7>(zIN҇o%},k|^޻}q{pGs.ސ\5>޷>>9b y>\ ܀\܁!J~Pa)hs !s2!s2"s!2'"s+$j8t๒$3RvhH-}MdMd.NdnNE Oܝ\ܞ\FXδڋj<{${xoPD# OtoGK=*K$=E)[{ ^{4?A!{7!{W!{wa!Jo?= mosq{ڞ3}C{!w6{7"{$W"{&w"{("{[XdE\dE`d/FddovoxBޫi=jw[p;^"/ bRO$ޏ^ ސ^1_B}Hd/IdoIdIsUV{ {P^'%{SuW%{VNxfxOowuo,+odoLdLdLдt1$ɞ{r1Hx~7{,_{xO+ k^ \7@l!0/v: @8-p cs89 5M,,*1gqR>0\4A8u΃pi"V.Ήnp$+! NrZ?T,1b9kƜY̽8xFT@zZcs4! nC2?/fx\|C8 NpCgsF0w9$e:DXcj&o9ѹ'A.pR"᪲Z$sX"E.Us! #GF2™Ѹ p];19[[5c΍po[ vco\N89:7G8:Ύpwãqy퐗|Dp{tp}# H!߄aT&0WxsK1wh9D\b '1ҿ86cs$#C]ERijV/c4ksqjp%Kd 7K8ZΖp-bagŜi:Kx0[9_g9`|'-,s$0#&\1 wL8d%NQ/gJcs̈́s&3 M8i7řzO#\5%5i\v&6Kbqœ7K1s1'M GNʧ4R :pC̩cn} ؍\;s޺Vn8tnp'=SZ;\\~01s1ן9tЁU^$'@r-W0Gr)-PÉ IIns  fys8WQJYr,-asv858grN9K!9[!9ZE j 4 r1s r4\ -gus$99E9mz|hPH'i=7DrD$WDrF$wDrH s8Gދs8gs8>s8~ .|ӵ-~cε9|zs9y].h9{ g9|%W9>-?=ǜ R㜿9-o2= =p{d^W:w {扗)y 5 AL6b>"< [g7{^ҽ 4ς.9߳{bq{aC>a< v{jwaO]x=:+a=OwPc/aZ,^y){+b Z=4u^"hCj){QgcnhaGrlŞBHǼ mbhޏp^E! #O*~!{IxKDŽ5yOdޓAy(g'e?b #<{;â,-㢇.92/Y6H(#=14ok②{egxghx[p{jT챡ymaM+{2=8l؋c/-8i2Y:Wg'{w{yT' F.Db(`Ϗ<8a( =A4o*.mHSay2Gg2]")%JŞ[Ď=FrTC!${{){:hޤqQ^%%x.`S2aO4{cS#<«W~Y=P^(ި#{Vaϔ>N}בu.^S%MVmk{j`Uض*Ӯh,j{Th-irĞX݊jN$ɔrk;xѼ^&߈ {l{ı'.qJPyмbm3fckiY% Þ2eO:OՃ5l/aib/0q`omj/a[ OFC{w9;JqcO_7ѳ^`ٓ=},C4Oo۷Yc9*ȋe7p3#XB G y^c ")1>C=DGE܄=7>P!4ϢO.r<닱{Q{#ӛCiwGiǹbS5 Y_8,̖v +2.<]g>}@Z>:!?߯ßƘ}BK{}/57TVVD]O}*&k5~).7EܑT`pFpԤ,uPϙ{5T$Ω2T.,%*&r*n|C)V C[u+P170Jܡb4Zn(&&sB;S;ľc6'_PIb-?qRv|(vR,_KΤtNRi`WBDVQ< 7v\bdK o^XX"6%Js>Ƌ"Zy -zvbj쾝8}޺UF\,;kWf|Ck+BzSÑ6?!{byHkMu]oH2.NWڞTݬvo;|~ WXީ+Cp{8W:Qb4\#{zdѦ%g쐥z#;izW@*K KˑF͖[O?gx ^e̓|T4JӨXq kѥQُ?wҋb΋fߊٌ\(}hsB[k2}KUfK9wd%w۫?biG-Tb=|:^m%Ƞ Iz+,\w#얆 Ew'AqK1Wq: 鯭;'yya^05\ 1!Ts61df8%&,̓ӽ[,7bp2덐A-RȞcљb]Nm~nc~rt"ʹ[Jwqڽ%kQR^'GX䫕u 3KjBLPZNB>>=$ "@v787'OVDWvTOtOL"!Wݶ 5Y?љksD*OFY⚑⏏#ԥWnmC&&AD C19GH}Kyw!]xM;i.`cW)eð:yM&")4>uJA+K)jn%o7@k2~ʢC{7WE*sSޣ#7<pp )|~)Ƕ$WX#e OMH@X`ueHY+D0w R)vlk0Rh߃]w :4UW\>Y2 0Cѣ+#l"e "<='Jf7_zDŽ9UtFoe\qXK7'Y~@&uI7+" #Umeg+Ss^i!lV} (udge>lޯ̻Rh][+P#DrwcF| gh zm\I4}6E7n eWoj"Ӣrl=\hWm6OΌr9 m=3mx6 ehuV~TF{EV.}NFkعK2(a%N*۲4@K5Ϝ]XFLoD,WӪ Etc}_ߥ_g%*Rl#Z7{% ԌNw_oj:DjB|w(MF!RzSj\ɂ$"FI+KoBag^̍z@={̼ ?481m5\X#{ilNZ`KYzHs;oRe)\;cHuj'4+QKOiN=I~)6}4yix3TɡοRFS*v e s~QƒVwg^mixsqp/man/0000755000176200001440000000000014540411047012346 5ustar liggesusersmixsqp/man/mixsqp-package.Rd0000644000176200001440000000114413614570727015563 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mixsqp-package.R \docType{package} \name{mixsqp-package} \alias{mixsqp-package} \title{mixsqp: Sequential Quadratic Programming for Fast Maximum-Likelihood Estimation of Mixture Proportions} \description{ Provides optimization algorithms based on sequential quadratic programming (SQP) for maximum likelihood estimation of the mixture proportions in a finite mixture model where the component densities are known. To learn more, visit \url{https://github.com/stephenslab/mixsqp}, and see the help for function \code{\link{mixsqp}}. } mixsqp/man/mixsqp.Rd0000644000176200001440000003220414540565510014164 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/mixsqp.R \name{mixsqp} \alias{mixsqp} \alias{mixsqp_control_default} \title{Maximum-likelihood estimation of mixture proportions using SQP} \usage{ mixsqp( L, w = rep(1, nrow(L)), x0 = rep(1, ncol(L)), log = FALSE, control = list() ) mixsqp_control_default() } \arguments{ \item{L}{Matrix specifying the optimization problem to be solved. In the context of mixture-model fitting, \code{L[j,k]} should be the value of the kth mixture component density at the jth data point. \code{L} should be a numeric matrix with at least two columns, with all entries being non-negative and finite (and not missing). In some cases, it is easier or more natural to compute \code{log(L)}; for example, it is often easier to compute the log-likelihood rather than the likelihood. Setting \code{log = TRUE} will tell \code{mixsqp} to interpret this input as the logarithm of the data matrix. Note that, for large matrices, it is preferrable that the matrix is stored in double-precision; see \code{\link{storage.mode}}.} \item{w}{An optional numeric vector, with one entry for each row of \code{L}, specifying the "weights" associated with the rows of \code{L}. All weights must be finite, non-negative and not missing. Internally, the weights are normalized to sum to 1, which does not change the problem, but does change the value of the objective function reported. By default, all weights are equal.} \item{x0}{An optional numeric vector providing an initial estimate of the solution to the optimization problem. It should contain only finite, non-missing, non-negative values, and all entries of \code{L \%*\% x0} must be greater than zero (to ensure that the objective evaluates to a finite value at \code{x0}). The vector will be normalized to sum to 1. By default, \code{x0} is the vector with all equal values.} \item{log}{When \code{log = TRUE}, the input matrix \code{L} is interpreted as containing the logarithm of the data matrix.} \item{control}{A list of parameters controlling the behaviour of the optimization algorithm. See \sQuote{Details}.} } \value{ A list object with the following elements: \item{x}{If the SQP algorithm converges, this is the solution to the convex optimization problem. If the algorithm fails to converge, it is the best estimate of the solution achieved by the algorithm. Note that if the SQP algorithm terminates before reaching the solution, \code{x} may not satisfy the equality constraint; that is, the entries of \code{x} may not sum to 1.} \item{value}{The value of the objective function, \eqn{f(x)}, at \code{x}.} \item{grad}{The gradient of the objective function at \code{x}.} \item{hessian}{The Hessian of the objective function at \code{x}. The truncated SVD approximation of L is used to compute the Hessian when it is also used for mix-SQP.} \item{status}{A character string describing the status of the algorithm upon termination.} \item{progress}{A data frame containing more detailed information about the algorithm's progress. The data frame has one row per SQP iteration. For an explanation of the columns, see the description of the \code{verbose} control parameter in \sQuote{Details}. Missing values (\code{NA}'s) in the last row indicate that these quantities were not computed because convergence was reached before computing them. Also note that the storage of these quantities in the \code{progress} data frame is slightly different than in the console output (when \code{verbose = TRUE}) as the console output shows some quantities that were computed after the convergence check in the previous iteration.} } \description{ The \code{mixsqp} function uses a Sequential Quadratic Programming (SQP) algorithm to find the maximum likelihood estimates of mixture proportions in a (finite) mixture model. More generally, \code{mixsqp} solves the corresponding constrained, convex optimization problem, which is given below (see \sQuote{Details}). See \sQuote{References} for more details about the SQP algorithm. } \details{ \code{mixsqp} solves the following optimization problem. Let \eqn{L} be a matrix with \eqn{n} rows and \eqn{m} columns containing only non-negative entries, and let \eqn{w = (w_1, \ldots, w_n)} be a vector of non-negative "weights". \code{mixsqp} computes the value of vector \eqn{x = (x_1, \ldots, x_m)} minimizing the following objective function, \deqn{f(x) = -\sum_{j=1}^n w_j \log (\sum_{k=1}^m L_{jk} x_k),} subject to the constraint that \eqn{x} lie within the simplex; that is, the entries of \eqn{x} are non-negative and sum to 1. Implicitly, there is an additional constraint \eqn{L*x > 0} in order to ensure that the objective has a finite value. In practice, this constraint only needs to be checked for the initial estimate to ensure that it holds for all subsequent iterates. If all weights are equal, solving this optimization problem corresponds to finding the maximum-likelihood estimate of the mixture proportions \eqn{x} given \eqn{n} independent data points drawn from a mixture model with \eqn{m} components. In this case, \eqn{L_{jk}} is the likelihood for mixture component \eqn{k} and data point \eqn{j}. The Expectation Maximization (EM) algorithm can be used to solve this optimization problem, but it is intolerably slow in many interesting cases, and mixsqp is much faster. A special feature of this optimization problem is that the gradient of the objective does not change with re-scaling; for example, if all the entries of matrix \code{L} are multiplied by 100, the gradient does not change. A practical benefit of this property is that the optimization algorithm will behave similarly irrespective of the scale of \code{L}; for example, the same value for the convergence tolerance \code{convtol.sqp} will have the same effect at different scales. A related feature is that the solution to the optimization problem is invariant to rescaling the rows of \code{L}; for example, the solution will remain the same after all the entries in a row of \code{L} are multiplied by 10. A simple normalization scheme divides each row by the largest entry in the row so that all entries of \code{L} are at most 1: \code{L <- L / apply(L,1,max)} Occasionally, it can be helpful to normalize the rows when some of the entries are unusually large or unusually small. This can help to avoid numerical overflow or underflow errors. The SQP algorithm is implemented using the Armadillo C++ linear algebra library, which can automatically take advantage of multithreaded matrix computations to speed up \code{mixsqp} for large \code{L} matrices, but only when R has been configured with a multithreaded BLAS/LAPACK library (e.g., OpenBLAS). A "debugging mode" is provided to aid in reproducing convergence failures or other issues. When activated, mixsqp will generate an .RData file containing the exact \code{mixsqp} inputs, and will stop execution upon convergence failure. To activate the debugging mode, run \code{options(mixsqp.debug.mode = TRUE)} prior to calling \code{mixsqp}. By default, the output file is \code{mixsqp.RData}; the file can be changed by setting the \code{"mixsqp.debug.file"} global option. The \code{control} argument is a list in which any of the following named components will override the default optimization algorithm settings (as they are defined by \code{mixsqp_control_default}): \describe{ \item{\code{normalize.rows}}{When \code{normalize.rows = TRUE}, the rows of the data matrix \code{L} are automatically scaled so that the largest entry in each row is 1. This is the recommended setting for better stability of the optimization. When \code{log = TRUE}, this setting is ignored becase the rows are already normalized. Note that the objective is computed on the original (unnormalized) matrix to make the results easier to interpret.} \item{\code{tol.svd}}{Setting used to determine rank of truncated SVD approximation for L. The rank of the truncated singular value decomposition is determined by the number of singular values surpassing \code{tol.svd}. When \code{tol.svd = 0} or when \code{L} has 4 or fewer columns, all computations are performed using full L matrix.} \item{\code{convtol.sqp}}{A small, non-negative number specifying the convergence tolerance for SQP algorithm; convergence is reached when the maximum dual residual in the Karush-Kuhn-Tucker (KKT) optimality conditions is less than or equal to \code{convtol.sqp}. Smaller values will result in more stringent convergence criteria and more accurate solutions, at the expense of greater computation time. Note that changes to this tolerance parameter may require respective changes to \code{convtol.activeset} and/or \code{zero.threshold.searchdir} to obtain reliable convergence.} \item{\code{convtol.activeset}}{A small, non-negative number specifying the convergence tolerance for the active-set step. Smaller values will result in higher quality search directions for the SQP algorithm but possibly a greater per-iteration computational cost. Note that changes to this tolerance parameter can affect how reliably the SQP convergence criterion is satisfied, as determined by \code{convtol.sqp}.} \item{\code{zero.threshold.solution}}{A small, non-negative number used to determine the "active set"; that is, it determines which entries of the solution are exactly zero. Any entries that are less than or equal to \code{zero.threshold.solution} are considered to be exactly zero. Larger values of \code{zero.threshold.solution} may lead to speedups for matrices with many columns, at the (slight) risk of prematurely zeroing some co-ordinates.} \item{\code{zero.threshold.searchdir}}{A small, non-negative number used to determine when the search direction in the active-set step is considered "small enough". Note that changes to this tolerance parameter can affect how reliably the SQP convergence criterion is satisfied, as determined by \code{convtol.sqp}, so choose this parameter carefully.} \item{\code{suffdecr.linesearch}}{This parameter determines how stringent the "sufficient decrease" condition is for accepting a step size in the backtracking line search. Larger values will make the condition more stringent. This should be a positive number less than 1.} \item{\code{stepsizereduce}}{The multiplicative factor for decreasing the step size in the backtracking line search. Smaller values will yield a faster backtracking line search at the expense of a less fine-grained search. Should be a positive number less than 1.} \item{\code{minstepsize}}{The smallest step size accepted by the line search step. Should be a number greater than 0 and at most 1.} \item{\code{identity.contrib.increase}}{When the Hessian is not positive definite, a multiple of the identity is added to the Hessian to ensure a unique search direction. The factor for increasing the identity contribution in this modified Hessian is determined by this control parameter.} \item{\code{eps}}{A small, non-negative number that is added to the terms inside the logarithms to sidestep computing logarithms of zero. This prevents numerical problems at the cost of introducing a small inaccuracy in the solution. Increasing this number may lead to faster convergence but possibly a less accurate solution.} \item{\code{maxiter.sqp}}{Maximum number of SQP iterations to run before reporting a convergence failure; that is, the maximum number of quadratic subproblems that will be solved by the active-set method.} \item{\code{maxiter.activeset}}{Maximum number of active-set iterations taken to solve each of the quadratic subproblems. If \code{NULL}, the maximum number of active-set iterations is set to \code{min(20,1 + ncol(L))}.} \item{\code{numiter.em}}{Number of expectation maximization (EM) updates to perform prior to running mix-SQP. Although EM can often be slow to converge, this "pre-fitting" step can help to obtain a good initial estimate for mix-SQP at a small cost.} \item{\code{verbose}}{If \code{verbose = TRUE}, the algorithm's progress and a summary of the optimization settings are printed to the console. The algorithm's progress is displayed in a table with one row per SQP (outer loop) iteration, and with the following columns: "iter", the (outer loop) SQP iteration; "objective", the value of the objective function (see \eqn{f(x)}) at the current estimate of the solution, \eqn{x}; "max(rdual)", the maximum "dual residual" in the Karush-Kuhn-Tucker (KKT) conditions, which is used to monitor convergence (see \code{convtol.sqp}); "nnz", the number of non-zero co-ordinates in the current estimate, as determined by \code{zero.threshold.solution}; "max.diff", the maximum difference in the estimates between two successive iterations; "nqp", the number of (inner loop) active-set iterations taken to solve the quadratic subproblem; "nls", the number of iterations in the backtracking line search.} } } \examples{ set.seed(1) n <- 1e5 m <- 10 w <- rep(1,n)/n L <- simulatemixdata(n,m)$L out.mixsqp <- mixsqp(L,w) f <- mixobjective(L,out.mixsqp$x,w) print(f,digits = 16) } \references{ Y. Kim, P. Carbonetto, M. Stephens and M. Anitescu (2020). A fast algorithm for maximum likelihood estimation of mixture proportions using sequential quadratic programming. \emph{Journal of Computational and Graphical Statistics} \bold{29}, 261-273. \doi{10.1080/10618600.2019.1689985} } \seealso{ \code{\link{mixobjective}} } mixsqp/man/simulatemixdata.Rd0000644000176200001440000000457013614570727016052 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/datasim.R \name{simulatemixdata} \alias{simulatemixdata} \title{Create likelihood matrix from simulated data set} \usage{ simulatemixdata( n, m, simtype = c("n", "nt"), log = FALSE, normalize.rows = !log ) } \arguments{ \item{n}{Positive integer specifying the number of samples to generate and, consequently, the number of rows of the likelihood matrix L.} \item{m}{Integer 2 or greater specifying the number of mixture components.} \item{simtype}{The type of data to simulate. If \code{simtype = "n"}, simulate \code{n} random numbers from a mixture of three univariate normals with mean zero and standard deviation 1, 3 and 6. If \code{simtype = "nt"}, simulate from a mixture of three univariate normals (with zero mean and standard deviations 1, 3 and 5), and a t-distribution with 2 degrees of freedom.} \item{log}{If \code{log = TRUE}, return the} \item{normalize.rows}{If \code{normalize.rows = TRUE}, normalize the rows of the likelihood matrix so that the largest entry in each row is 1. The maximum-likelihood estimate of the mixture weights should be invariant to this normalization, and can improve the numerical stability of the optimization.} } \value{ \code{simulatemixdata} returns a list with three list elements: \item{x}{The vector of simulated random numbers (it has length n).} \item{s}{The standard deviations of the mixture components in the mixture-of-normals prior. The rules for selecting the standard deviations are based on the \code{autoselect.mixsd} function from the \code{ashr} package.} \item{L}{The n x m conditional likelihood matrix, in which individual entries (i,j) of the likelihood matrix are given by the normal density function with mean zero and variance \code{1 + s[j]^2}. If \code{normalize.rows = TRUE}, the entries in each row are normalized such that the larger entry in each row is 1. If \code{log = TRUE}, the matrix of log-likelihoods is returned.} } \description{ Simulate a data set, then compute the conditional likelihood matrix under a univariate normal likelihood and a mixture-of-normals prior. This models a simple nonparametric Empirical Bayes method applied to simulated data. } \examples{ # Generate the likelihood matrix for a data set with 1,000 samples # and a nonparametric Empirical Bayes model with 20 mixture # components. dat <- simulatemixdata(1000,20) } mixsqp/man/tacks.Rd0000644000176200001440000000173014540565510013750 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tacks.R \docType{data} \name{tacks} \alias{tacks} \title{Beckett & Diaconis tack rolling example.} \format{ \code{tacks} is a list with the following elements: \describe{ \item{L}{9 x 299 likelihood matrix.} \item{w}{Numeric vector of length 9 specifying the weights associated with the rows of \code{L}.} \item{x}{Solution provided by the \code{KWDual} solver.} } } \description{ This data set contains the likelihood matrix and weights for the Beckett-Diaconis tacks example, in which the data are modeled using a binomial mixture. These data were generated by running the "Bmix1" demo from the REBayes package, and saving the arguments passed to \code{KWDual}, as well as the (normalized) solution returned by the \code{KWDual} call. } \examples{ # The optimal solution for the tack example is extremely sparse. data(tacks) plot(tacks$x,type = "l",col = "royalblue") } \keyword{data} mixsqp/man/mixobjective.Rd0000644000176200001440000000302613573612732015337 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/objective.R \name{mixobjective} \alias{mixobjective} \title{Compute objective optimized by mixsqp.} \usage{ mixobjective(L, x, w = rep(1, nrow(L))) } \arguments{ \item{L}{Matrix specifying the optimization problem to be solved. In the context of mixture-model fitting, \code{L[j,k]} should be the value of the kth mixture component density at the jth data point. \code{L} should be a numeric matrix with at least two columns, with all entries being non-negative and finite (and not missing). Further, no column should be entirely zeros. For large matrices, it is preferrable that the matrix is stored in double-precision; see \code{\link{storage.mode}}.} \item{x}{The point at which the objective is evaluated in \code{mixobjective}; see argument \code{x0} in \code{\link{mixsqp}} for details.} \item{w}{An optional numeric vector, with one entry for each row of \code{L}, specifying the "weights" associated with the rows of \code{L}. All weights must be finite, non-negative and not missing. Internally, the weights are normalized to sum to 1, which does not change the problem, but does change the value of the objective function reported. By default, all weights are equal.} } \value{ The value of the objective at \code{x}. If any entry of \code{L \%*\% x} is less than or equal to zero, \code{Inf} is returned. } \description{ See \code{\link{mixsqp}} for a full description of the objective function optimized by the mix-SQP algorithm. } \seealso{ \code{\link{mixsqp}} } mixsqp/DESCRIPTION0000644000176200001440000000401314540660612013303 0ustar liggesusersEncoding: UTF-8 Type: Package Package: mixsqp Version: 0.3-54 Date: 2023-12-20 Title: Sequential Quadratic Programming for Fast Maximum-Likelihood Estimation of Mixture Proportions Authors@R: c(person("Youngseok","Kim",role="aut", email="youngseok@uchicago.edu"), person("Peter","Carbonetto",role=c("aut","cre"), email="peter.carbonetto@gmail.com"), person("Mihai","Anitescu",role="aut"), person("Matthew","Stephens",role="aut"), person("Jason","Willwerscheid",role="ctb"), person("Jean","Morrison",role="ctb")) URL: https://github.com/stephenslab/mixsqp BugReports: https://github.com/stephenslab/mixsqp/issues Depends: R (>= 3.3.0) Description: Provides an optimization method based on sequential quadratic programming (SQP) for maximum likelihood estimation of the mixture proportions in a finite mixture model where the component densities are known. The algorithm is expected to obtain solutions that are at least as accurate as the state-of-the-art MOSEK interior-point solver (called by function "KWDual" in the 'REBayes' package), and they are expected to arrive at solutions more quickly when the number of samples is large and the number of mixture components is not too large. This implements the "mix-SQP" algorithm, with some improvements, described in Y. Kim, P. Carbonetto, M. Stephens & M. Anitescu (2020) . License: MIT + file LICENSE Imports: utils, stats, irlba, Rcpp (>= 0.12.15) Suggests: testthat, knitr, rmarkdown LinkingTo: Rcpp, RcppArmadillo LazyData: true NeedsCompilation: yes VignetteBuilder: knitr RoxygenNote: 7.1.2 Packaged: 2023-12-20 17:48:56 UTC; pcarbo Author: Youngseok Kim [aut], Peter Carbonetto [aut, cre], Mihai Anitescu [aut], Matthew Stephens [aut], Jason Willwerscheid [ctb], Jean Morrison [ctb] Maintainer: Peter Carbonetto Repository: CRAN Date/Publication: 2023-12-20 21:50:02 UTC mixsqp/build/0000755000176200001440000000000014540624410012672 5ustar liggesusersmixsqp/build/vignette.rds0000644000176200001440000000031014540624410015223 0ustar liggesusersb```b`fcb`b2 1# 'YQ\XWR&σ,&'7$7M@e! I5k^bnj1.y) 3GZY_Ӄ -3'foHf e2|s  =XQĒD"~)iCmixsqp/build/partial.rdb0000644000176200001440000003543614540624404015035 0ustar liggesusers} |IzX<޶Ҍ$;ʻ^{wiך{GlrH ;+# @BB rWь3_IӚWW_}UU'R]=$aHv~>Ma8|ZZcy͒3 za>X1B*#,1I웏ϿVO? Jg fU)^9(쵑;MܼWRS |5Vkߐ?B\a?kkc7D|ĠQY nMVs^c[3\s .7ʝ`ƨ_ ͕J%7,++hnqj;[㷋woݼu},W7*B.6kAz;%#J%*=_lVƴ{5Îv4YOB{ؤ#vz%c%Z`W˖ iC60[!Cڌ *!4`ԥ5/δD3 y_N-S[me;!~P$Rkn~ȱeL66,?(!丨y }y^f Bx.TQsݯ"JU $TE \-8+W0aEW VaշU<~Հ)ӷ(ep|UڡF)k_~U Ĭʽ/Joq͹|Ҩhn3tvfv7ʚt caX'`40ucJflp}o=04n/|BI='~P"< 6x%酧 A:#1s )3|4&u"'"񝲓myH#5yjĨCDx j`Zciu8rQC="쉭&GD%HF!tzRFHkATXxio8Dc3 #XyIXb^ng\e*g,[F9kV!Zp58@ֹG.Km%Gs,(a25l(=fA7rwWQDfxERYdoA]uFU)U]""Ӑ =$EZ3EjD?+qK+Wg PR&j*BdC>y' πbnW|Dfl# DcJ2[DTO k "7~Ix uLdhƇxG8Y@x2H! ]c6o2 KmՎkde5}a̴xr6ɱ6ɦ6,-](3I,̹.H6=ؤɝCOi0sx늴 v7ѹ? ;eChxfs->|_1|o=FC If< 3frCΧ\b=< ;n٥0dCmk>eUĨC"×XTDz֘f.9(W}Y3%3kL M0ǕgsY&H7&WL,3hib^Տ1 1!m2[%vY"K)Ơ6ej$fs3 N09qH/oUG!KUHɏIq\҅H+[뭟rwK V)]U|xbʣt-a2{pE&W{d-uO-T49j#PȆ";)ћF0Ҽ#>}IouK4/" ½#8 Y _kFuz֊]h ktE)΢-yY̯֚8*d=p'<_S5V\e9J?Q b"W2*m`h;&$7%w*Wnx5CSf' .> 1S_#UU*i]T2yiJE"{6^>s rTOCI'LA#R0]J~x:m#{OmkȽ.R6i@%,(2AA=gU2ʦ(Z1Rw?[/ c/J6pr,NP%i#3D8nnJ~ZB<ݦ1Co+VئH߆|T̨#K43(CLe@gw=aV*!ƺ@@DD3%P:R/q<%VB<ݦ1@iYS@VGx-yY}|Z)Hx$ ?)H{HUKx@ge6.j^WD>_ي=ɿŒ +U3 `̰͌& a:r[tkXs%v +YS!q*ɥ4*yHu/{Ahko壝w)ci9ڵA:'FE^/:%;"sxi;Jpx~ެX3UmpjŖ#MQr-71ڞA!ȇ:ߞ)=Ðkʝ+5`NGRfݫeW5i}R0!GiP67i-cu< N1x?Fx#?xʷLǚz8 vc*S[`VJ7'SڶE-DM啪Eb*ɫ&nɞ"!ΦQErPkG~xp`#Y)p?X-وQy;bOфPt%@+tfìODp>MK5:,sM6՘PZƑo&fvk+Ebo 1js3Kk7)BOBߵ$Em ۧ,2F+|xbZƃt>(B!y3]ɄVMɟ˝}}_xˍGLB͸wR^Fy&2T;etջumPj}~xx1*i,x6V.H txr{ťtpʹB&_9sCB<]0:L=Q% R|sx46FӤuSA>41ad֟osAC' ڼgߒSB;Ȩ|JwXPoJu?d}##: uvm=&x 3A<NCf/Rr3Z.<%?+!Mg4Rh5q|lEFd6Uq9%+@ޅ+%OB<4Fʬc(_o/B#lϥiS1jE$6Y ;1]ս+UuX`/~а"Jp Xкf8q:dUq<{DMfPDXjղR{? Å粵s\B<a eñ->FW`Ӎ'q< ?GF&ޗ&٨tX(} kۮ~ՆiCgSyF>P ݾM0 WPIfKAȃYz1i*jcRAiWQ REE*1BT"mjnX4* [8kv9YFs"&l,_ZF#_ c3s‽hN.xѦ["JZDʩ,=qtɬ=xTl}XcxTs5arzNCN(*+!0k|j*M8 Yh,Ef ^hm9-!wE1ȱ7ƈ Q3!'*(/TxP3Ck*zUymh]@\wiSC FFt.KE^|Em!KsN8nf`)i|4.:S.1CXec ,@>֦W{[BU Ykus[Qw%LέI)ՆE&)cRO݇0ɧw;O>@*ɧ[b$<[5a2i4Q=!O4P?Mi#Tk$w4Nd±9ll`C0G." h쵬JzD ssWM$a2j<7mLih6J!:zLE`O̖3 +[K0oy}kä՘aV}p'?d9MBMWZĻ4X3 ]UJ&@5/4N5EfT g!뛥c̺֏$I}@A?dPIH:di6:I`ƭT%L%]c5ӷMDZ.R8Ü8s/:# 9sBO%wծ#[%U]"B94ds[e3o# 'tjc/dAK=4p KԲJv:B f D"=ef(`Ԃ~Q8Q-:ܑ떸`Àft}xv3TWĿ:pqf4.H&ʊz t@u&@S7 )eؽ8sxrVsbx0b,9w, Ͷwm[eWSSeӐ{%ef>o<ԕNh `r*ŪCWdROۤScQ{oj UT)W¾7*`r|bܪkkRIN"7<`ղ/P{7*oF&3zqIgPfj "VG׮llaj.~ Nt|=워ߌ"M5G7Q*56J.fෂ4areY`eUXB*"Y/ %27 'wΉC֯>ʩQxv k_w|i&/!Nk%HiSt^8oyZw5{|wòļRg-/gD /hL3 Os Og_fr!Co@u^;t LkZ*k ֠!hpˣFLnL2|Ph@5 ')ô3 ʣ_,A 'Hiq&R >y$N i;j>~&..m* o\47k;Εd#0QJ 'JX`~bHTUSAUXy1[/dذɫ{#Ln(ҰWa^p 9{ #A[y89XN]Prq o{|' nbeHv}]J]]<렾!8cf({2NNAN-WmL pmΊg^|'0]~Nxr>`&y(Mh%NC~ ןEG-(WiBxG&3Ns@ꄽ{kEiérM?0Ýo9\pvd /U:±bt7c:'G 5S?5Jw<0Ll܏aw ŠTvɍ՗FF\HuBH^ŰEM9X }}J@uZzYg+s=J"d "oIWt!%ix]*%^7k["[,d/p4hے(4 XU߼g~p`bXc5żC ' NJR TRdvŊ$sQNFߧ x;z'!":xUB];x.8 4 L?jyqj p r.(qڵ"cu}B tVg!{ʮ %?'!ݡ9 )Z}r|lCj]3ې{/:φ+nFCϝ!as}? M$LN1ۧO8AtJQtA`s;_7j2zuyVͯww$_6$=M> [ܫgr+gFVUބ:; CBw he.k<%`E, lzXbHd!GV )$f>_{9Aȭ sbA߅"Dd_5`UI}h${yM8 Yrbff9d^*ξ2/%0Ĭ MV`)|7? ]p EA*PNRTbq ht9[UZ}] ,ϯl?N]]NBuuCјpod4h]&|rlme.%\8h?'!nK(;;(ӷߓñA[{j횒KAU[xtrhF' y}*wկ* $9= U0w.b0Gt= 8ރ}V^2n<vW |Ӏ{{-|3j7s6j*X&wT]/?DžjxQYISs1ѓX X Eƛ͋t % ߉(.B]އU"|1yX#Crʮ %?)!n(;ah@aVD|JV :KPPriEcYMsZ d.f[g?Ja=o@ g hcZ쁓m8;K'1nގ7Api"rnP0kQj<6X :j흒;Y#5S#p8Y+Vܬ 0_Tmh(_q)a B¨P ϱ\3ߎejV+b\ZDU4VNmtq!F2C NW @3iO'ê [9ٟF<`bwEJ4Cy/d@>}?(!n{(;'‹cjK/A Nw &nd^[7F!*ӨM!B߇&7S7[4hQlUK+T3@02wW_|K?e»jӿ"jCT [a .0 pv]^RIUgS+ G!'9iTBͰ+w?D2^Z,cE7ڰ~$%W!Eɥd#CT056YxJ%Suk&&Ĩ.oUe`=4 = |ު i'Wc#arJ)~.gKRL88s|fGA09`(AlgwաΆiiUm> )3|cȏGd_J~xM㟢"lr/]Wj)_vԡ:Ԣ+E6FOsNgCD+ 6!#gE3l&+vYh V?y:yH& 7RM>t|QF5+ !kgGHrO; yg-6%+!nW(;q3g:;T{H(4P3ZOS\^υiQu{,ډJd!39E$d`ܛTjW9 $>LOH&g&%?'a2i@58fk/gmW kU O 9⁚ː/'fD4Q&ỞrNA֭ɚ fkxV0?3kbX e$<Q2RS[MU.q ҝFZyEUE^eITA0)K%$:9>GڣŽB'd/CeL9%EB<ݦPvGMվS <`J. <Pb}vk`J-Hp2Ef `+w{WzrŎ >𯿠KSs1'ok"W|oٱ_S~0m2xwPyggRINψ{{Q5=D:?;8gY#yi gٲ^`Mӫ;?-% P6ӓ[ĉ[ٔs8AɥMr1~Hj;3I5M-.[EP|tHitj6+09~߫*Tk} gїi[=s MRsWoB8yvgdajg(6vpdwcogS]\OɥRw5٭7tx8JjsfIܟʎ.NtVz ~p/佝W_@ ?'T<p>,x-ʶ3ns2 CCJSOuZUINTy5%FB<^ʽ:z%VB<ݦ?Qv;yK)|mKN5k9ɼQ3~ǩw4#3Xvb{8 9j@[̨1ȥPa㷬10ϼZZ1M^1RT058:a1%5X񭑢ͯiKD~r*6RrN8yF;%+fati(B5м)wY2C-%)됯w8R7$m6:͚òN/Iuz1 <ҽd*ѣX[ )ȱAыpHw*40 9ݐ@v%jz/O!tsmQ{xN^7arT},cnͣo&ִ #X8\Lib",4X2(-9h>d0(Smw*z@/CP23LN8Nt|vrm$: ZGkQw@b9̉)343pybeR<9a1c3*A亩E*2vu7P=AOgd1aR8 ;ea.Mwomcv8^oGQۧKuR]6dY_\+ aqxZk^zbjTq;@`j1uU˱W(IZ`cf>gZalТar [q y`Wݼ#9\f/d EHLlmiWz#]xPxW xy%Rfe{Jgo_WQQ3}KVҦ!'WU^*aTI1䀣Мkcs mjc 1]=ê ^r!U{o߾l` BF>ڨ~a8͒5\;[,<<;3xalp|ٱ譱;FGcwcܽ{f;󋏧glѽa!_KoUl}X^;В}he0' fF`ۖy{qឱ^. ܶ33]5*pW(l Ũ?z˾e3oA;rm#:%6xџ AW^ 3XNO)N_6WxRW!hժw-M/E Zp?kP}&|gb!ԝPY/wDD3e8/0eCy6]l_sR~׮$XQs5P3+`h8 >yAAQO6b.9&4T[;yr;/1?SDŽhYxm Z'zIL/6f9ߎ(>'Ɓ/Vcg'?;hƟK]4uR`+CRVk/\kZһLΑEK}M/ <}LpuȽs>Zh[;饢]^ БR^ؽ 9~z]ldwszpbaYf_ ˁp6ޥBJ:oKgiCmRzs_rW.''熡\*>tU6ٛi]zIXl[%Gz`.Xn.Jo]hZ7҇>yuج&]/65S)[ ҬTc /[ݢY535z-ڷR^+miST}uniY-4߿k)x\b /Utf6Ζْ~P+ܽjm{V3 .V^oo٠@~eUL玚 w/j]t ܔ0 Z*`[O56ZJVs/P lڲ6smZo[{aoo{vUk6Mml`S B5 jm-Txl5z¼ {6+|@w P?߲@6Fjv/ri[ Ny%V57,›wkIEA.]56]A%^;%,oj̤loQv.5.UV_jwmSG*f~edN zN5m6&.܋tsɯ^d9!8yE25FpeS)AzkvDdjFm#ZWιo>YWnQO3ZB98 I)'gl|i">}!8Exgb\$e6(R$(aroMV[Բ.Nmu9}2+Ef,S"ǐ'e @dTt:rVF\BNG!kJ]JV';A>վJ 9yl'QBS%dۗ0ʅӐ?m;QOg=y7).ġ}yHѭ\/r84f(E &~9&\=DHcֈ ݚrIyA~l.2i%Tu^Qh_ !KB▲ir9 6{Eߪq 8@=TttH_ "smixsqp/tests/0000755000176200001440000000000013565526670012754 5ustar liggesusersmixsqp/tests/testthat/0000755000176200001440000000000014540660612014601 5ustar liggesusersmixsqp/tests/testthat/test_mixsqp.R0000644000176200001440000003614714540566071017323 0ustar liggesuserscontext("mixsqp") skip_if_mixkwdual_doesnt_work <- function() { skip_if_not_installed("REBayes") skip_if_not_installed("Rmosek") skip_if(!is.element("mosek_lptoprob",getNamespaceExports("Rmosek"))) } test_that("Version number in mixsqp with verbose = TRUE is correct",{ L <- rbind(c(1,1,0), c(1,1,1)) out <- capture.output(mixsqp(L)) x <- unlist(strsplit(out[1]," "))[4] expect_equal(packageDescription("mixsqp")$Version,x) }) test_that(paste("mix-SQP allows zero likelihoods, but reports an error", "when initial estimate does not satisfy L*x > 0"),{ L <- rbind(c(1,1,0), c(1,1,1)) capture.output(out <- mixsqp(L)) expect_equal(out$status,mixsqp:::mixsqp.status.converged) expect_error(mixsqp(L,x0 = c(0,0,1))) }) test_that(paste("mix-SQP converges to correct solution even when initial", "estimate is very poor"),{ e <- 1e-8 L <- rbind(c(1,1,e), c(1,2,1)) capture.output(out1 <- mixsqp(L)) capture.output(out2 <- mixsqp(L,x0 = c(0,0,1))) expect_equal(out1$value,out2$value,tol = 1e-8) # This second example is particularly challenging because two of the # columns of the likelihood matrix are identical. L <- rbind(c(1,1,e), c(1,1,1)) capture.output(out1 <- mixsqp(L)) capture.output(out2 <- mixsqp(L,x0 = c(0,0,1))) expect_equal(out1$value,out2$value,tol = 1e-8) }) test_that(paste("mix-SQP gives correct solutions for 2 x 2 and", "2 x 3 likelihood matrices"),{ # In this first example, the correct solution is (1/2,1/2). e <- 1e-8 L <- rbind(c(1,e), c(e,1)) capture.output(out <- mixsqp(L)) expect_equal(out$x,c(0.5,0.5),tolerance = 1e-8,scale = 1) # In this second example, any solution of the form (x1,x2,0) gives # the same value for the objective, and the third mixture weight # should be exactly zero. L <- rbind(c(1,1,e), c(1,1,1)) capture.output(out1 <- mixsqp(L,x0 = c(1,1,0),control = list(eps = 0))) capture.output(out2 <- mixsqp(L,x0 = c(0,1,1),control = list(eps = 0))) expect_equal(out1$status,mixsqp:::mixsqp.status.converged) expect_equal(out2$status,mixsqp:::mixsqp.status.converged) expect_equal(out1$x[3],0,tolerance = 0) expect_equal(out2$x[3],0,tolerance = 0) }) test_that(paste("mix-SQP and KWDual return the same solution for", "1000 x 10 likelihood matrix, and mix-SQP correctly", "estimates the nonzeros"),{ # Simulate a 1,000 x 10 likelihood matrix. Note that I add row and # column names to the matrix to check that the column names are # retained in the solution vector. set.seed(1) n <- 1000 m <- 10 L <- simulatemixdata(n,m)$L rownames(L) <- paste0("x",1:n) colnames(L) <- paste0("s",1:m) # Apply mix-SQP solver to the data set. Check that the solution # entries are labeled correctly. capture.output(out1 <- mixsqp(L)) expect_equal(out1$status,mixsqp:::mixsqp.status.converged) expect_equal(names(out1$x),colnames(L)) # Apply KWDual solver to the data set. skip_if_mixkwdual_doesnt_work() out2 <- mixkwdual(L) expect_equal(names(out2$x),colnames(L)) # The outputted solutions, and the objective values at those # solutions, should be nearly identical. expect_equal(out1$x,out2$x,tolerance = 1e-4,scale = 1) expect_equal(out1$value,out2$value,tolerance = 1e-8,scale = 1) # The very small mixture weights estimated by KWDual are all smaller # in the mix-SQP output. i <- which(out2$x < 0.001) expect_equivalent(out1$x[i] < out2$x[i],rep(TRUE,length(i))) }) test_that(paste("mix-SQP & KWDual return the same solution for", "1000 x 10 likelihood matrix with unequal row weights"),{ # Simulate a 1000 x 10 likelihood matrix, and different weights for # the rows of this matrix. set.seed(1) L <- simulatemixdata(1000,10)$L w <- runif(1000) w <- w/sum(w) # Apply mix-SQP solver to the data set. capture.output(out1 <- mixsqp(L,w)) expect_equal(out1$status,mixsqp:::mixsqp.status.converged) # Apply KWDual solver to the data set. skip_if_mixkwdual_doesnt_work() out2 <- mixkwdual(L,w) # The outputted solutions, and the objective values at those # solutions, should be nearly identical. expect_equal(out1$x,out2$x,tolerance = 1e-4,scale = 1) expect_equal(out1$value,out2$value,tolerance = 1e-6,scale = 1) }) test_that(paste("mix-SQP returns the same solution regardless whether", "the likelihood matrix is normalized"),{ # Simulate two 100 x 10 likelihood matrices---one normalized and one # unnormalized---and different weights for the rows of this matrix. set.seed(1) L1 <- simulatemixdata(100,10,normalize.rows = TRUE)$L set.seed(1) L2 <- simulatemixdata(100,10,normalize.rows = FALSE)$L w <- runif(100) w <- w/sum(w) # Apply mix-SQP to normalized and unnormalized data sets. capture.output(out1 <- mixsqp(L1,w)) capture.output(out2 <- mixsqp(L2,w)) # The outputted solutions should be nearly identical (although the # values of the objectives will be different). expect_equal(out1$status,mixsqp:::mixsqp.status.converged) expect_equal(out2$status,mixsqp:::mixsqp.status.converged) expect_equal(out1$x,out2$x,tolerance = 1e-8,scale = 1) }) test_that(paste("mix-SQP returns the correct solution when log-likelihoods", "are provided"),{ # Simulate a 100 x 10 likelihood matrix as well as different weights # for the rows of this matrix. set.seed(1) L <- simulatemixdata(100,10,normalize.rows = FALSE)$L w <- runif(100) w <- w/sum(w) # Compute the log-likelihood matrix for the same data. set.seed(1) logL <- simulatemixdata(100,10,log = TRUE)$L # Apply mix-SQP to the likelihoods and the log-likelihoods. capture.output(out1 <- mixsqp(L,w)) capture.output(out2 <- mixsqp(logL,w,log = TRUE)) # The outputted solutions should be nearly identical (though the # values of the objectives will be different). expect_equal(out1$status,mixsqp:::mixsqp.status.converged) expect_equal(out2$status,mixsqp:::mixsqp.status.converged) expect_equal(out1$x,out2$x,tolerance = 1e-8,scale = 1) }) test_that(paste("mix-SQP returns the same solution when using full data", "matrix and the low-rank SVD approximation"),{ # Simulate a 1,000 x 80 likelihood matrix. set.seed(1) L <- simulatemixdata(1000,80)$L w <- runif(1000) w <- w/sum(w) # Apply mix-SQP to normalized and unnormalized data sets. capture.output(out1 <- mixsqp(L,w,control = list(tol.svd = 0))) capture.output(out2 <- mixsqp(L,w,control = list(tol.svd = 1e-8))) # The outputted solutions---and the gradients and Hessians at the # estimated solutions---should be nearly identical. expect_equal(out1$value,out2$value,tolerance = 1e-6,scale = 1) expect_equal(out1$x,out2$x,tolerance = 1e-6,scale = 1) expect_equal(out1$grad,out2$grad,tolerance = 1e-6,scale = 1) expect_equal(out1$hessian,out2$hessian,tolerance = 1e-6,scale = 1) }) test_that("mix-SQP successfully \"escapes\" a sparse initial estimate",{ set.seed(1) n <- 100 m <- 10 out <- simulate_data_koenker(n,m) L <- out$L w <- out$w x0 <- c(1,rep(0,m - 1)) capture.output(fit1 <- mixsqp(L,w,x0,control = list(numiter.em = 0))) expect_equal(fit1$status,mixsqp:::mixsqp.status.converged) # Compare mix-SQP solution to KWDual. skip_if_mixkwdual_doesnt_work() fit2 <- mixkwdual(L,w) expect_equal(fit1$x,fit2$x,tolerance = 1e-4,scale = 1) expect_lte(fit1$value,fit2$value) }) test_that(paste("mix-SQP gives correct solution for Beckett & Diaconis", "tack rolling example"),{ data(tacks) L <- tacks$L w <- tacks$w capture.output(out <- mixsqp(L,w)) # The objective value at the mix-SQP solution should be very close # to the objective value at the KWDual solution. expect_equal(out$status,mixsqp:::mixsqp.status.converged) expect_equal(mixobjective(L,out$x,w),mixobjective(L,tacks$x,w), tolerance = 1e-4) }) # This is mainly to test post-processing of the output when the # algorithm reaches the maximum number of iterations. This example is # used in one of the other tests above. test_that("mix-SQP gives warning with convergence failure",{ e <- 1e-8 L <- rbind(c(1,1,e), c(1,1,1)) expect_warning(capture_output(out <- mixsqp(L,x0 = c(0,1,1), control = list(numiter.em = 0, maxiter.sqp = 1)))) expect_equal(out$status,mixsqp.status.didnotconverge) expect_equal(dim(out$progress),c(1,7)) }) # This test comes from Issue #3. test_that(paste("mix-SQP gives correct solution for \"short and fat\" matrix,", "even when linear systems in active-set method are not", "necessarily s.p.d."),{ set.seed(1) L <- matrix(rgamma(1000,1,1),nrow = 10) capture.output(out1 <- mixsqp(L)) # The mix-SQP solution should be very close to the KWDual solution # and, more importantly, the quality of the mix-SQP solution should # be very similar, even when the Newton search direction in the # active-set method is not necessarily unique (i.e., the Hessian is # not s.p.d.). skip_if_mixkwdual_doesnt_work() out2 <- mixkwdual(L) expect_equal(out1$x,out2$x,tolerance = 1e-4,scale = 1) expect_equal(out1$value,out2$value,tolerance = 1e-6,scale = 1) }) # This test comes from Issue #5. test_that(paste("mix-SQP converges, and outputs correct solution, for example", "in which the \"dual residual\" never reaches exactly zero"),{ # Generate the data set for testing. set.seed(1) n <- 1e5 m <- 12 L <- simulatemixdata(n,m)$L # Here we also check convergence for the case when no numerical # stability measure is used for the active-set linear systems (i.e., # eps = 0). Also, when convtol.sqp = 0, the mix-SQP algorithm should # report that it failed to converge in this example. suppressWarnings(capture.output(out1 <- mixsqp(L,control = list(eps = 0,convtol.sqp = 0,maxiter.sqp = 10)))) capture.output(out2 <- mixsqp(L)) capture.output(out3 <- mixsqp(L,control = list(eps = 0))) expect_equal(out1$status,"exceeded maximum number of iterations") expect_equal(out2$status,mixsqp:::mixsqp.status.converged) expect_equal(out3$status,mixsqp:::mixsqp.status.converged) # When the mix-SQP iterates converge, they should be very close to # the KWDual solution. skip_if_mixkwdual_doesnt_work() out4 <- mixkwdual(L) expect_equal(out2$x,out4$x,tolerance = 1e-5,scale = 1) expect_equal(out3$x,out4$x,tolerance = 1e-5,scale = 1) expect_equal(out2$value,out4$value,tolerance = 1e-6,scale = 1) expect_equal(out3$value,out4$value,tolerance = 1e-6,scale = 1) }) test_that(paste("Case is properly handled in which all columns except", "one are filled with zeros"),{ set.seed(1) n <- 200 m <- 10 i <- 7 L <- simulatemixdata(n,m)$L L[,-i] <- 0 xsol <- rep(0,m) xsol[i] <- 1 expect_warning(capture.output(out1 <- mixsqp(L))) expect_equal(out1$status,mixsqp:::mixsqp.status.didnotrun) expect_null(out1$progress) expect_equal(out1$x,xsol) skip_if_mixkwdual_doesnt_work() expect_warning(capture.output(out2 <- mixkwdual(L))) expect_equal(out2$x,xsol) }) test_that("Case is properly handled in which one column of L is all zeros",{ set.seed(1) n <- 200 m <- 10 i <- 7 L <- simulatemixdata(n,m)$L # Run the mix-SQP algorithm when all columns have nonzeros. L[,i] <- 1e-8 capture.output(out1 <- mixsqp(L)) # Set one of the columns to be all zeros, and re-run the mix-SQP # algorithm. L[,i] <- 0 expect_warning(capture.output(out2 <- mixsqp(L))) # The two solutions should be pretty much the same. expect_equal(out1$x,out2$x,tolerance = 1e-4,scale = 1) expect_equal(out1$value,out2$value,tolerance = 1e-8,scale = 1) # Also check KWDual solution. skip_if_mixkwdual_doesnt_work() expect_warning(out3 <- mixkwdual(L)) expect_equal(out1$x,out3$x,tolerance = 0.001,scale = 1) expect_equal(out1$value,out3$value,tolerance = 1e-6,scale = 1) }) test_that("Case is properly handled when L has only one column",{ skip_if_mixkwdual_doesnt_work() set.seed(1) L <- matrix(runif(100)) suppressWarnings(out1 <- mixsqp(L)) suppressWarnings(out2 <- mixkwdual(L)) expect_equal(out1$x,1) expect_equal(out2$x,1) expect_equal(out1$value,out2$value) }) test_that(paste("mix-SQP converges to solution for \"flat\" objective even", "if initial progress is poor"),{ set.seed(1) n <- 10000 m <- 20 L <- matrix(runif(n*m),n,m) capture.output(out <- mixsqp(L)) expect_equal(out$status,mixsqp:::mixsqp.status.converged) }) # This test comes from Issue #19. test_that("mix-SQP converges in a more difficult example",{ load("flashr.example.RData") capture.output(out1 <- mixsqp(L)) expect_equal(out1$status,mixsqp:::mixsqp.status.converged) skip_if_mixkwdual_doesnt_work() out2 <- mixkwdual(L) expect_equal(out1$x,out2$x,tolerance = 0.001,scale = 1) }) # This test comes from Issue #29. test_that("mix-SQP converges despite poor initialization",{ load("ashr.example.RData") capture.output(out1 <- mixsqp(L,x0 = x0)) expect_equal(out1$status,mixsqp:::mixsqp.status.converged) }) # This test comes from Issue #30. test_that("mix-SQP works for difficult smashr example",{ load("smashr.example.RData") capture.output(out1 <- mixsqp(L,w,x0)) expect_equal(out1$status,mixsqp:::mixsqp.status.converged) skip_if_mixkwdual_doesnt_work() out2 <- mixkwdual(L) expect_equal(out1$x,out2$x,tolerance = 1e-6,scale = 1) }) # This example was generated by running: # # library(ashr) # set.seed(1) # logitp <- c(rep(0,800), runif(200,-3,3)) # p <- 1/(1 + exp(-logitp)) # n <- rep(100,1000) # x <- rbinom(1000,n,p) # out <- ash(rep(0,length(x)),1,lik = lik_binom(x,n,link = "logit"), # mode = "estimate") # test_that("mix-SQP works for difficult ashr example with binomial likelihood",{ skip_if_mixkwdual_doesnt_work() load("ashr.binom.example.RData") capture.output(out1 <- mixsqp(L)) out2 <- mixkwdual(L) expect_equal(out1$value,out2$value,tolerance = 1e-8,scale = 1) expect_equal(out1$x,out2$x,tolerance = 1e-4,scale = 1) }) # This test comes from stephens999/ashr Issue #76. test_that("mix-SQP works for a difficult mashr example",{ skip_if_mixkwdual_doesnt_work() skip_if_not(file.exists("mashr.example.RData")) load("mashr.example.RData") capture.output(out1 <- mixsqp(L,w)) out2 <- mixkwdual(L,w) expect_equal(out1$value,out2$value,tolerance = 1e-8,scale = 1) expect_equal(out1$x,out2$x,tolerance = 1e-4,scale = 1) }) # This test comes from Issue #42. test_that(paste("mix-SQP converges, and gives solution that is equally as", "good as KWDual for difficult NPMLE problem"),{ skip_if_not(file.exists("npmle.RData")) load("npmle.RData") capture.output(out1 <- mixsqp(L)) expect_equal(out1$status,mixsqp:::mixsqp.status.converged) skip_if_mixkwdual_doesnt_work() out2 <- mixkwdual(L) # The likelihood surface is very "flat", so the solutions are not # expected to be the same; however, the quality of the mix-SQP # solution should be as good, or nearly as good, as the solution # returned by the KWDual solver. expect_equal(out1$value,out2$value,tolerance = 1e-4,scale = 1) }) mixsqp/tests/testthat/smashr.example.RData0000644000176200001440000010421413573612732020454 0ustar liggesusers Xm8CQ2keCEvXsjf+))RMH5n"[#)i NI~sƿ >3?~ۧyCvken[k[ƂS{~>ԊON+S  k:hY ]~xO?>?5we.  M>Ҿ_ЬTkO,: +wy?=t7Ǖ<:,lNvA\~~IWٷ}dX^) ho}_ mxhG}bǜT?~2 Noj{ ϖ>ZY XfpƄSf<>?-o:zOÿ~~y1o}Jtz~~Iez_Ylu h`?aE+CXwyaA/~_2'"00s?r V ڮCOÿOt.Ȳ` O-yf3z0wE~kg}?޿lnKAGʵ:J++f O]yE*iz ,SU:t>;y1o}wZox~>7i<_.]cYݎvҩ(W$k"npOV [[m4 떯̿jϷ̝ uWV^l]#S!xƣj 7:&G{o[h=~7~Wϣ^zOci֣{S_~?-~?|o?5w]?wLSpQh3КM~7W{ĸ{|ŮAy{?ud\oXEW0%M~)<}y֣B/tDZ׃eGE5K E_w`Ѣc=Ay}y! +lCa@QV4*C>KF1|1;&6XG{x. $8㣁=΂mԃy1C\EվE32IQyp{t|s끮D]t뙮w~7~3 zƚq97;Wdy2h36G`.3R="XEkڐ@<Fh+;h=z{ ^EeOjVWux,fYP{QxS*_ `EΌ`~臷Omǃ S>x9ۡˮ _FӶ^ҡG̺C]EՎsn:uz>,sJ@g\6FMXG!xƗ6#oʡIoWngm1& (^gt$=sѦF@`vځenjʏzx}37t,6sFF ;f^.Z]g~>W)>yp}_:t$Ǔ7:_|끮ĭ7ʭg~'߸H+%;wpy7<+<=yISrr19}@ 7>އ)o}Lk>'ϼ>Zs1 o9ZƤ8FN?7 dVqڏګvˬ1a{ z ^]?Vw~6ϖbӧkyV5л[ӄUVhϩ=뛁%?>vl jVsKz X<.F zC>u}gz>9.Ɍ[^6fٸW&i0W--}'/H|A.^ xKhi(Or&Gxgi$^d:K\> o|W|;4ɧHc$_9q %Io||>K]|4q|Iߠ>ZshΪhuَ=Y:aܴ~{Jk4ך#qٙuFKCs#{uU 5o7 P>G+[0/}"xM.IH>{`=X02psoPT|u7Il[ x3zlp넾#U>a,sif{i`Ł)*wL]Py>Hr jE#U;څ"G,FR>VŚ`V˯{ޯ]'Uf>Ǹe͝OOy;+_U=㥓g2ǹwM_!w1sz#-ՎهKA N_|r^eGo=+Z(v}Ndt >qNҌ|V1nh<ʸު&[FE?*tZ0 p%X&|"7欲ڄƠx90z{\f(g,lk(#X6ߥ/yrw:sU V\ys<(!dnhqk7$h= m&).f̫~ |X ״P|:j9^½~,|al~'OLEGU`<7b7Fs`pe= ap9Ռqˠ$i fkm5/EUh>$Qmx[/j}:25qhF_K+'y~f9mZF8xnjZCŷ_= |<,?7nj֮)nQBWz5j_~EۇYVvqW`Y֥Hh=yVmvg,`2ݩP2!s(' VNV |OǕVt-PTVpk Xք9UÂhuv򷭌5b^vJёixd|}}FEN꿝l7g{Ƕ}ui'i߃R}Լ}-sAVʛSj%{BGa] hut36Ȝh=yjֱX0)f,~}cZo&,d^ oY/2Іl/>a#Md}?z,; ,|vP7dmgޭZ:zE{ƍFo|3vq줺>ꅌ`>9?!Fiͬ >O{=KǃxA狟O:d=pEr=q덬Gnr뙮w~!7n?gy HGyE3#!=/yJ[<&5O}C#z_}HKz%k>xH<$xC4^hE1h_'|#\34ߡ͗H>E-.#ϑ|I(O|4_Y|46I$ߧ^@ \#h3hChDB-C5|={H=I֓zGq*E]FeFm\=zdOD|PI=WrLZPZ/%TRo걤^sIzd=֛i=֫z6wspZ/tZoxR_-@\3hChDB-C5|?{h?$I\~Ϣ.Fe&oq:')DH\g~'~)駒~+׏%ZKմLŒdohگqlp/toxүl=jm3ϲ;\ FLrY bM1jmj1XkӫɊK~><˿y_2% _ u(rFo7#T۩]ߠ)2ϖV0> UNE5tfT߶LZluIM)TJy;-OԂC&0~n(mGGpKǃO:t>|)9?-*xrb7?cS ' <R9갚l4^QQ-V>43_194_ \_T,]89 %_z|Oe3u3*)\,S=3|ڭ`ّQ#U Aч >KVXW mnb|οq#}%ANj'on>|I[tH'z_t@ ~#ٯ~&ޯ}Z&^ wqPh&*M25:iqAٌ}+<.qΕ|[E'EՁݛӚ[165Q-Vw2mN&+],0(z\hn&7C3?uEՒ_b[qyhJ9Ӈgw?\4=$mX :6)wGw+= }g!/}J[z}`VgYH^̲[hG%՗-8tf'NʸUCΉѨ F8,;ɨƫʪYoN<SBӧ(ҖH(^\gjsM>)ciBihڃ''}*o?vMKI ,>1&Pkd:t3;=۷P^XjsP<}#`Ύ[kj1ޜ&wƨn ZRhJM!Qcv2fo"/Wsy6=٠)o_&nr F დu(ㅦѫ8ҾuwFt⁲ g{PY8mbԫ$>_P&_1ӡ%F㘃AQ@hJ]KT큛5AϩQ]OkaF %GєWO66 ,y){rP(4o,mѹn{`YT(~{"^'F-<ДڃW+d32+|Q-2TMƪ[W/i W}[ВY[uI-0^n9h~hiǞG^iդAQrҴ𱌟t((^ h~?yA]-y}}_:t$Ǔ7:_|&[/[od=r땮g޹@ OdqW~?Kwz9OyC#wޑ󐞗<%-w?yO}C#z_ܗ}J[>&5w| Od<+$xS4ޢx{4d<ś$UxILios8x^2._'|#\B|K4"|H4_'iIQ,wi>LeO|%u.'~9g6:f&G=7Ǎq3whsAubF#32V‰; ֌s+ZgdyC EɡC澽ؽFj*+K(,uʵ hrik2ˁrnEirД7b\l4Y\Bw`E߂)m uJYS6:j'fDsuװn¨;/M41Cb19̀`7tgoo(>M %T:86pe7瞁y7vVX;K(J&LQ|sa2;V=+eԘ58")cE5+돥 S:|n I hƚ3._n-mД>3Z#V=n񩿱,8G/DSE"e~1}[y;kN\i;F=e K<Ϛ&mD9hA%`i6cA]є'}Z1s[*~Χuo`,<ڡMɫ6ade X~+֠(yћ`ٺiʆ؀<] 7~z_i}~\bLˍAQf/_\6.\7 N/܏<EO d^9)Mb陌]792ƘTvΙ`·@Q7ի΂eU sl Б 78ɛ @UW)Y <(|Qi4Y-j4֤ӷєqyz#<>;2gq]TǼà(t\{Qܫ}FЯv8 $e?t&o @QuM0YF##ft`^xc=Y?9ٵ\ac+tDMZ(ms-y}}_:t$Ǔ7:_|&[/[od=r땮g~'߸H+~'^7<+zq=yISrr19}@ 7>}ݧc%{.OpGx3\C!/IS4ޢx{$Ex7I<ū4]x$qdO>_'|#\B.!͗h>E-.#ϑ|i(O|4_Y|46I$ߧ^@ \#zgpZz z Z! ^$YOMիh=ֻzzq8Ry>Bz"Wo$H^I\CiSIǒz-_%^LŒdZohZ٤Iz;W'zOɒ_ O A;H?KH?[h?k~~I~Gq*J&.FeFm\?~dA %\#~%g~'~)~+׏%ZKɴLŒdohگٴM_NN_%q5o`վ4Ց?"c 1xcIn_T7z˻Zu7s=/i@顺j|]C/YfC7e>Zκy!f-<><˽}_ XQ7AΚ~crA F o_jGl28Ms5 Vgv0?H7ԿTZ;NFY='GGƃO:t>|qIɆ_jW.3bNSpjՙ5Sn+}i!NwCuG.}yk7|]͕gE> 2#*~" g,:cd%Ta;ꏇtOSEWm]=/5]8{0ng7bL 654r<:h`A^kANScǁ= 6索<>ypd|@ YOtH+zn?F#ݯ~&]8UhTkɨv.Pv== 2Cu:"cf a qZ `b1[VXϫŻ" gk@9wNT[hUo'+'%4=:s{T"sO~dՠh&EǚUw&@CjdsW~AQ̮+;DT_8 =1OڰN` VlTTzӧ:(T /nnܻjcݍS/.gЋ1dWF)Sy1ʺK 0JGHGW4h j mYF}xrSUO[?q8X.dH%'l㨧z ̨+ca>~j1ՙ׶tGҘSQmsVGq<>yK߇{_2txA狛Onz녬'nȭWz/t?G_L;w'yC#=yHKz;y͝r_7>wއSr}NyELX;PT<վ(՘(W5uDuj˭қo:6;G[@uSe ƯNN7}@GP{'_M1 ձ>7z%*~κ]sAHsVEu< ,,(mudv9jxӲ[DCC6d2KTT1+;vE'z 9{(ҝVm8j!=k%4k/+K‡RE:}Mfq掕E1Ơ_(W x1`c~4cc#P}zIh攣6».K" 7E7ޚd P= Q{m'*%7CumIsp[] }"@xwrCYe {RbB'-ց"SГM{ ?_BP0P(>n ܷO :[lǘ9]3;]Jr&Tg5=QݧJm>: j_8ljW>6AW<냊;^#r'GG{ANj'o:tM]/d=q덬GnL;~7n?gy< 9gyGCz^󔜷yLk<=}AzW}F;zO}侦9I< $ x3\C!/x[4qiHI.$(xƻ\+4͇hD)oq׸|{4"'iIQr,wi>Le.&6|4oP5{Th }MqZƐcQyVKWdV3FiWh8xeq؅nr.߽P0 ̗]>޻T;[q2c#1Z^rFFeeM[Eξ9N{_8j9|5JTfs-Ļ_v| ՟wyn~9uhڰ?=|( ] tV.5(W3jG}Rrԑ/9sNN%瓫ߣVMVk\] F6.F6h<6Ny.jT 5}T7*X0#|i,X@HPd`qbK]Іs”i9vh騾+dAn87쮗}9ϛK8-j`DՑ 11N-_P:Dmz5}k:T)-a$A̯Y<,op?55P{K+h/%T[>սB X87riƋ=OnRpG C+"Gw˛sr, 4C`٪SA^zW1gvBϙ c7gz:R?Av=TgHU7vR|vlxAM& m󗎔p\G4o1_PJobQ=}GW:Ύה@u6k>@|s+Tf9ތMXL >Z5ݒZi+Q:9ua qڑe/ŲJsePCnVU=f\tYWP߸L rf'ㅞ}薠8V 3s1(yN<8ʾ=$yr= E:g7| e kA,joQ]lc8_zƐ].Dv:Q#5y;{c.lhf8|5"/ mK@{#LjvT7ݥ`n7iߛ`y=}@t='؄6{H㍠QcFKˡN՟ۣ:VV,ѕEODu,\JewmX$4 w,5XƛḋnnT0۝J%wSHBNڦul cD-fkQ¦m6=nĬO4z(?38nB!J~ݩ}.&=-u"P:kdnPޞZxg"v+o=1Ek6u+ݘ1D;VP99%^TkYЏ.Zh+ᨡa3QOXv_N_xYׄY؂:v`iOB]P{`UPNcSƺ qynte[1QhXN`O> 9Y&}}{{+-6tq24rIT;fZ_Ə_Au* y~v_}|}=ˍ/2t|擛oz![od=r땮g~'߸H+~'w^7<+zq9yISrr19}@ rG3zq!/}J[>\<@OpGhB.!HG=.$"'iIQr,wi>Le.&6i$ߧ^@ @\3hChShchzz'q&RUE]\=h=۸zq} EǓ77d$X!`Bi/\]$"m^w iy!~ *[:9X&`+m '\Tᴣ|^TYYPsmp3X%8z/PQ#1J ,W!ewut" 5-YP?}|zZTV`&Fe) ݍj5Zhh!jꀶ`eEwAaN{@F p_}|<{K߇{_2txA狛O2z녬'nȭWzn?F#ٯ~&ʜ9FBYmX7{OQb:T}PYvC/ 8 UJ8.fX@`I_ZYz59+K8&,ru_CP(ب\ ,Ψ:tvrovW7ռrvTv ٌv};M>{U \9"^V5;]isvݔP?Gk Wy8lBo.jY\u܈Wph/Eӹk2_+t`۹|"umPN俋u~*(Tj xq8iχUP{FHxTKU[*l3;Xev|qI目^z_dr뙮wn?Bo~$t{rp 9g!=/yJ[<&5w}AzW}F;zާc}3?b7l7VWT6##e(3lFFȲAEvlӭ~e@l3,2򚌃`2B%Oƣ,PsK:iXYܸ۾dPx{`~K/ oYvla+eTk⾜g[0njvUڽe躅3T飓޸*]]#  'GƄ, 0u Vn΋jZ ; :GcdsPԹo0nyS|$m=7V/LA5d;*D;*)L ČL3FylX Ee r%J֟К5`tQhRWtSh=!#=n(A52}1’s@ 5@٦P-Y7N4-s2Y7'@lcJufrQGeUP٘ޙ2pA9Q8kΑ=lFGZ;JǦMʹ[%grt QT٘q1`VGy#yoMꅣў'> Q[{=wKu`<Ӣ_j{85߶E{=Aa[Q!=^!ᜰrCcQfTÏ &i=O<)D72PcETfO fhvPm у =/!=)=qeZV 8 {'t?Yz<BȔ#`su=Pyk'h'CxY⬹6/UZ5vX)Tn瞶P#9rTv ?[73Z4r'=KǃO:t>|qI盬nĭ7J3]t?Bo~$t<rq=ϸ󎜇$)=oyLk<=}A!w_w>%O}Kcr_s9x $ p gxC4^"h!o|+4͇hD)oq׸|{\>HEO|4_Y|46|4;@E^mTW݉vlΪ6cc!C@e5~p7 m r{:^Uo,ѼX2752(T!"T&a:F${+(=1$R &V=p"\xz3ë٨Aڢ2v4a-!v2q~oi9ѨuK`͛0sg@̊W}? z< ͛+,= ʥƚ^i FN F^SP#3: ;hۦIhǢ!uЮs\\<=A9]R Uq5ki(p·JK"ͮ7UeuhCJi} UGUn9Bٮv۴ֈ[m&T50pCLPwn:PާqZP}nCl4}S1{1GB}ӼdݚZ P٣֠Z{ۋPn#De-0ڶEG[/u|S{p6XQ=X4&(j5(TR)PT=&B ]vڥ\ JoĹMV~ wЪl'(lMgoTN5hjai*!PQ//4]Y/m~XQ8h =QpF:z޲Ay`k|vм̶N c F]3n~OmރQuGۣZ&[ 2Мn5w>?O`nPX4 [1ӗЪBeUV+6 :^lzfնQVyEeS\G-&j{TYe`v`:.RX^8q4w|hۢHS򦁕w rwotk3,*Y` }/0/{%"S:*c;-n+]͢RThmPӼ T/+&(?G*P'< lxŽC$ޤ7X^P>ty`2tF5/4W,Ge.g||ɸE8՘VvڠLTEaԑ-q7X7fV.`6=O9e#0#AJԯ3-P[k ^xto<*;ݲ'B@, OBC Bsa=o\绵%84g`yP;X9>n:P( Zy0ٸQURC _NhtT.u'#CمPzlEJJ=GN]+N?'H'a"yp%Fڴm.WXp7> UmQLd/-w0> vC5;ovSXi[#@a+^| 6T= \c~PϩqP8}(P W꧔Q;Q}m,蛈j)\)tCk;?6Xn$粥 (T<>.XYpcG+gޯ*aBfTv]ޠJ2mB^%vYgB%vIP^O=KǃO:t>|qI盬nĭ7J3]t?Bo~$N =oyĝW<;r󒜧}yLk<=}A!w_w}HKz}侧/x7HIM|giKa/|4':ϓ|z'pZAB%B-C5\={H=zWo"(^EYHHǑzWϣ>Rꅤi=+i=wz(z*z,r\Rz0z27z4WslZpZ/N^I_H\h#~gpOڏ#C=2DEDMOU\?~~q8үy2~ /$DH\3iCiSIǒ~-ϕ6(&bOfڏj-CݴN崟NO\?_/_^=Xnf%|L笛#Rt_mx-un]LB?Xd: R}_J?}}ef٠ft&䀺ד5+AK Kn*>ّCus'GGmp:>ɽdOT)RF-RWG]˞` :ie7Hix^돣Ֆ+zX5K^j=6٪F?_K?O>{ˍ/:dEAWf`C.%6YOnO9zr/Fv2e_dE&uS>*~nc쮓#G\7T/X~h9X<0`d9iH.#|jKY:- fۃj':%׷^^r4{% u c(2mRvlx1N^;1@&Z<^:PukGu=2oůѪap+~#CDn\q,?b=u1r*ר=S0[sԽɆW Pg#xe7#`Dg#n1Of=F11rvE'&sG2z=M_,1w_ʯ'G~{ANj'}t>|qI目^z덮G^L;tD{N wWyF;z󒜧ޏyN{>O}C#z_q}HKzsrm+rv;x6u=vUgG3Oyɨϙ{=PJT<ϭc2Yܦ`Ɂqjw6XruЈ6b:~(0=KJhi GR7fw#uhxSTpwFP]uC)W+l mRr-U;X2N 6\?T%u,AaR X0<&S[z-iVT!~7;rgy_Dm쩅9[ѽ({]/,\^5 w%,Ypyac[DX7ia;Q^z8E]=A=ftS[nvxG6۟=bdzS1r.`+cڠ\nV;mæd% KuCLK­^v3Bhz5ޙx-?_Ju:/ran\p־ y_ځaCH~PMSB]L\`,3 >5z44` 6JK)ZnGGn~|#Yw/B%9FjWR?\Š MKKooHoԧaQsBr6(^/϶~2pԧr _>r'={ANj'o:tM^z덮G^L;tDwNσyB#wޑ󐞗<-=z_7x}GCz_޷>&5wx7H<+4xSxk\B.͇hD)oqG5.#|4ߤ(W|42ͧi:ϓ|I%` /K\ӝx 蛣(FD/G=Z)9y21ly zvjS}+22)Q-Q$" o[ 5aa9̀IA_^{k%zم W ܄nԵ*y 2% _8=)[_:YȷINfPe{bsB\ rqnѓ]VNmgld ?#Q7hژ㧩܋+[,ٯ畮yw?̼}.<=,qot0z KI4ht0쫲rG|A5/5ۿ Sf㛾CK{Oz8EfwF O*c/w umz5ԭ}wת+oZFwmxݹrt~vu]wo࿛m'K8&}GV)7;dgnDn3uoisu |bF Α4C 7jw24w3/Pp < N/aH)X:a"eW~*0h?XרF^Ӧ ,?vs%Ռ*6695"X<4|$XiQbYa77a!IfFA7JRiN< u'Wp⒯ d5CSH#[[E]Oaz3ah&P=y4X6H8\=xEhý_W‹SP3z@.λYFgy g/3Fԯ,X꾭a !P9=(,R3dXp]VṦ$) r9CClmWgkf&v~۰-D]#U)e RW^驯;=&\/qoKEH臺Z:| *~Nͽ: ?CVLq?6Xf1ڠ(ļx`շvGUzG׫ `<Pxn] z}֞{:hPS|yٚf?z5 W+E&)K|V|h-f%&*SeGZ7m^S68TtPk* ~VX ^ZblxOs[X(Fcz{(j`o.@{FߠW꓋9;~/dP;:iˊ lxnn<>yK߇/:^dE-|H$_$$7i>JU..͇iLio|\>O}Zh=+h=;h=KH=?ZC=ՋH=֛h=֫zwzz?h7DRꕴI띴J륤J뭴K\={z0z27sA\=ֻi=i=i=z>~?@\3~~ G1_shhhhg~#2O#6n~ׯs5H_3iCiSiZ*-`/&dohگٮM_NN_%Rʓe??;vY?>׺7z}_K?lt T{^ˀtީ9+OZglb?}iϠPaqy`n [ }fW dEc[ OD;8mkC/>}\)Jfu?X4khr4}sʈQRh^c{P7Le46}SwF}Lofy/B ݗR0翟ꈅhcQge#-<><{އ/7dx7d4 󳆩=SfjkCw|5`]ZZ3F^[5*[5h@1/7AC6\9/XQr360n*~Niɏe]'\O>g awj6]8JlYGޅ`w S\5uu6>F!ŏJ@sfO8CoPԇɆP8O̸:ztwNRЂ^jz_Ln6̻i;0`G=t: t_}|<{K߇/:^dO~{}GCz_޷>&5wgޯ5 ЭfG{u4~ 豎rQRkPϛ9q8i%c}YoL#nS,Gr#PV:ś;qs f: :79%v=Je9zRö'PS /A.}]uW.:u(^Q?ЏOBCN~:h<s;^akP $Gh34ߡ͗H>E-|H4_$or,wi>LeO|%u.'O `Q^:>ɨR/;u$hquus;T<IÌ=]3̷7KQT,޺>,l\lx" w ҷ f{b ,K*ZeԴ3}м/=GgD+d4T|Qyс%htɗ׍U/߽nBsOo b֢Gꋊc NB=ET>EOn ;'Lv~8@&zƢoP8OqĶ9syш5՞| fwM4v˪7lM |OvrǍyӚuB{m-2x;}eF+A]tB&hCҥs:Gg@wg汯z=L[:nаMݚ 0{φ_kC=&.U=tƠݧx5Y^?s¸jGzF'BC_FeNoN޸2,hn>9c }^+q]}.]CY*a5]}9 n馁W<ZEjS\N.(`rKlx{I.($!J0{-K)`3[5r  =LDw>:>~c-Q)|6cV(H^D`ıkU ϵQ'u@+ FٞFޛfgh^ʼn}>:/Ҹ'dmwт "k~V||]%苝TPWŲ.P<Z$'4TtUmzW5Aw^<۳}v|*ؾ냵  >(j2"yEo$ռT}7w$+:g\9Yx lg y ڃvk<>P%XޢwؤU]K췝6 0un8=b#Z|k+hyVO\#{ۂ"}Od'm%|ʑj+Nu}ѣ={)1duTxt#FeD1rÃT:lG} u?yۖ멋Vzy 6FRC/}twއ)o}N{p'x#\BxK$%5.iHI'(Wxƻ42iMqs $Gh34ߡ͗H>E-nIs$A/|W|42ͧiMqs/f=δ6E `_jY80ЗNhXo;Bc6q{ vly;4Q(Hw,r(WYxqSUV}uF5\B5}]mt̽g&o㞔 UP҂h۹ Bϓϣ^}rAƋ'on>|qIAiRWPݗ>sn z`ZI1@AKrG}A f>lq7fVW v~: }tzMPs*o/pֻ-h냂كV]gҍ> neVK0Mqў:-4f͵Wwk9(bі7',< }jY=a}P EǓ7:_|]/d=F#]z_D~3 P6kʏ[AAܺMфE'7NFAwBS;Tw`GV7]%.rKރ/i*D]4,vUsZknwE4^}uiST|[lpa(|gmg^YcVt|6灨@zUT*T] VgʾhBȠ_inWG/s}[-S R =:+ ^6 u/O[VLYyQ4OL<)N[XJYx bZIǠ1.tmfu[fl 3A co`AAAzܘ+Q{NJhk}V`IQ0`ApmAAf,͊ߖXtf<7<4֥۝20MO{ isPQʠ U`[窎q#}ANj'o:tM]/d=F#]z_~G_L;='=yƝw<%=OyKcz^s99> }g!/}J[z}3;>kUphWPry㱾堣hB{;:&4_ChlkE{C{w] r}: <4k7`*xM沎|em퉠YĐe;v#siߎ{7DU 6~pPΗy&2n,;Z0pWtGo&M4LkԻE֠ a}͢KИ #g0֦ێA%gkڥ%g^w? ҿ98P2? Ϧv˼ OOmy,}7}4CrAAݲ`ZN{4As>9ø+ebV(+=/w&uIâ/ `Uu@#, uv 6h>濯.3^6̻e,L;]fw| ϑKdјgGc3E!X4'0MZb\97Fo*]\yK߇/:^d%-w}O.^ oxWh<;/x[4xƃ4^$$7iMm.׹| >m|bAA`om;uM;VpMy@ eG { ~C KF]>qXiw'Asm[VDwVII!:s|ja E^@D 4jq1->6wG"b37np$|(KG. (H2.f^4s!P:jģ17ϛ,7Ǣ`3S}ApFdf$4ZNg+*~V>'һ3~,IvF鵻 ͻ;I?:t9w7W܂RfK(j:Xɔo@A!=; WkUImfiM_mv$P}mWe{? 6L_ ^~dO(X 3h!̼WHU>}Sv%*~Nܶ: .e^瀂禃%ko ?{>(QtqɊsOm:16K^8e0>`=RqLkt_Z?-lgޛn!v&9m7v\ Yo?=L[.)|]]@AJ`e01ھn` L_L$,N<[{ (H_[-|H;t/'᧖Mf,/BӿY g5,pc嗠ێg֦Xm{7kLW~2 }Y~,>{4Cl|zv8/6:>ƴƘu9EQnY4:XtOgVw=I ʔ/)x>m4.M׼!//ӤôC27o դ Rۚ|sg1:8lxH@`Y'`މm]فKvgRFO.n bV'@cvVe}aasZgv,0ɸ␂`iOEsΠ8_V 0DӬ##8Iq݈>o1v.`I!] {\` 2Zi}sCm%TSKE_M5[>(H2ru (_^Y|9Xz&\%T (8(H|v-3x^ځTCs+)]Χ"јivmFF<Ӥtt4 rȨ~{h*K5zDP69ZAM3WBhYA^4Z>tb蒻ò3}M߯=v>ۤAU4ffbvF~~L.wӤ,쯯 ʆ'^{$P U`i:V};aTe%}#ctVPڿ2"*[[m 0ɗcQ@W@A˕#F1TD3ښ8~wIPmXGRCvj+mRNzOt+^lxy;7G}>ow˔E`;r W߶,hcڸjР* OFӌD;1t;6ς_b\;}|)y}}_:txA狛O:d=p녬'z땮g޹@ OtH+~w^;oyĝW<;r󒜧1=>O}C#z_qޗ>%-w}O.^ oxWH<;4hE1qhF5.#|4ߤ(W|42ͧiMqsZꅤH덴I땴;i=KI=[i=kz.r`Z/&dZohZ٤Iz;W'zOH?W~ /!oگ9CA_DIDQ_h뇑~~׏#:G}HI;i?Ki?[i?k~. h?I?i?~6w~8~:~<|~tc))FRR-6Yj[4B_?ً[tͿ_׿_׿_׿_׿_׿_׿_׿_׿1ɿ ]Ålt`Q>c, Amixsqp/tests/testthat/ashr.example.RData0000644000176200001440000001255713573612732020124 0ustar liggesusers{TT[n kml"7lm\'6A ?5uc L$aM㒙H&br!5~ۅ|~k}:NkZ|~wc=G =98:;_:ڳj9 윓]Mv?595܀KWM 6w؏_[qG;!%{? }u6-9~D[4ѻ=ju7 vuDFQaMy Eqka]_u л` &Q5ֈl޼(UjX3V늓!%a նQzXG$.<ݒaG`yB3a|GbS;D#GuAݨë5lwgRI/ax/0/!`0M惟T+aΎ\6 nnE0Zqs5%|QV]|)HNiphW^Y.S>9Ek#Sx_4Ց3Toia{kZ^ Sm'R3vܒ+ے ]y0w }e:/V F~%=x8Qp4W iEu[`.٫0?:7oONひ)`j?:}awj;Fmd霡0g/\&>!h05o7r,w4xW0Mx_ ba񆃴 L-4FeKa|WОp*wzB{#ӽ'pO[ C7 | CQ{)ņ `}fîk&y3'ð AeV/dCMSڴ!N8? %Fð>0h'? 7, C77a_L]aXy{C<`˱l>10e.xV WBjRћ?}~~7G>+C-K~_e e'߄AQdfw0v/[ecaT{u?>Ob@QozSI=$W;x?NGz͟OkunݓH}ayB_9O|wNωп%A[E_ZCo|~З^X C{K;w }yJet+vϷпwYO<:@@0ۏ{/VG'X׶<zrgQHwoP> =w?.& }O Cz@v.>d z XCSTG)WtO(n^m.rhl׫;t!0tcPvq t?TRvm&]/R7ͫەmCAi[~:\|]Fk jrGjA>؜+N~,mʧcKX_lCot#s=CwiIa3۟psQt̿9Ex4 +T.X~[s>D}~+.7n^>+%۞B눤._CĚ;k\n$[ݭt[{Lq<* x?Q|u?>wsܿAjhHdG"ϹܿVYZ`%ܿ{Q ܿ2naP_Εrʡm-?Zr:!-o9hD~ $r>2:?HB"ϡ$rD HՅn erAD{hhljw4ܿ7= w"467\ϮgݛqpV̀w4ܿWhA[hCZߝАCml E64ܿ hȿlܿxhYp|!ܡ!А?}0~ *|4 _^p]bpRϯɿ^PqndCP/ j8ܿl 5oGTܿV&v@LWۙsC<*߯Pq o[7Z 5w*NPq$C5'*߼ P=&@MY/&RO*_ɿRIPqTPaPq2'TJ/려JPˠ$|Kcymcq$PR O %h(@I%o+(lPR݅J߆r(;%w<PPP>x݂sa@I7J$z 퇒oSu?>EuoPPEGWDCAQ( GPP OL(c!;~(BA(Q_w(y"#{(o/A" {A("{*(؟ߍ~~5}@Nuo +!cGo! 'yV@N9_<S 9_{JȹeS@Ny@NWr3S@N`m/ r?5_ɿ!'Ƴ}+݇go.'!soo'~~5} k_*dO!+D(?qq\> { UȸJ5dq?yod; [/2꿺QmoBɿ%@FBɿ% cSB(B(WWQA(w2'QE(7 2꿿'_;H~O)_R!%ֱyy@JRpHScgz?~t=yhN <{:1rc$nX::/ ]";d5>T/ }}{%y}v 0绎~h籖VVxgw˫mi^r޿Ֆװ5R wqj $! \H#F 5H!˅o,$ HHVy _[HvCB7<!?o$- @ zHHɿH6@B7%HfAS! _juhpڒ`ICL5O1_ H !]1nɿl>_yCL1&FBL1WS=b;-!ALwb? _</ bSE@bo 9s:bo2 1{bX=/|8^kq_;[G<_sqY^E?2/;8wsJQt|gp~iQtnY( 2ϭ Ei٦l<ܮtz=m]u&%ފjR̓O:7gN L7;ڬ̀^Qzm !Y !52!" !}ȿR%CH _. g !k ![oDvK^@H'/"7D!Zw"]O" ܿRCD!D8Z!/X@9k_z| . +5}j JY 鵿:<;(p>yȪs|!y(, #PV@ktǠ(hVqy QsO(~Ir i\gxiIlR!cQ~)m/k B@7o" y9yFB@Puo;%P]! _r?5o;! 7#}Po  [C@1aN"vhd$eN,[xR둿H5mixsqp/tests/testthat/ashr.binom.example.RData0000644000176200001440000011550413656554212021223 0ustar liggesusersWU׷c&vwq9[LlB.BAP BB,B19 " k\߱yk53g/f7e׫WozK,xŗdyVWaŷ?~-e_W_/q1f!7c x ~r'r5{+8/};~ߊ}߽uU\˟;w.Oo`>_]tͯ>[拵ޞ7go뻮't[]vr1ξŏ3zy!G}1o嵝}=̼k1K9>|^]앋OG]~+7om#z B^c5u?WzV?Z>~a_\<5=r{>{y#~p{uꅸ3^ڞ[NC]8u˾uyz־ߗ~Ni_g[3r!gouoru߿Yn_]xi?5o)-Wlgίz=\x`}^]r Y_8WO]x[_kq/F_uM>Wu??=uw]8Wy?9?WdoƩfl?'߿k]ZW獺r:[?Уr~]-gѿruQU:sϷr@]q6e;p9\O<_֕G/\\_\Uo+.Sz8vˊ_꫚g}s~;/sKOTwzS>YlO{c߻suoog`A;޴֍>inџ@jeo>hUkC<`o pk]x Uᴁ/,ѯtɽg_U e^js |>cUf;އ4g$t~n=ZS=ޝ=2>gvU|/fM]%-x|ujc*ZݾΛ]7K7=mTש8mc׼&>u̟註s3COI۷Xml|_uks?w>>Xon|:ܦOQ KUzu7g |~_ʮ;u Mc;s|8ރ? r?&г]>Yv8bboÇ7MrTI&~ٸվ4Wȋ~'K0|Ris~sϾCXOveY?4b~ߜ Kv'ϐSvgO=9|ۆza!ؓsw1o=ǎ{iwu0wˇ>w_u 'ħc䳝ÿ岞? W8_STBߣ\~ȟgߺCN F::笳/E]sF腝W9w^wo3tk?3\oo:8{~?h}Lz<|G]F>Np=Tt_~i7qs4,\ǻu\\-F|o| g stw}'WI=qph?=]w::|ӳ'~:O*ȯw8tDOzyuߍXnqvW}u׿3׹-ֿ!~ַw?c퉜Эx's>}~kܩ3zu+c}}IDB`2^{q8K/w~1n㮚7z[ţ{F~fZK|_x65w-?U6'_^ti3O T?nJn>;OV5f~3W|}U%5ag,޻Y g}wtGo|zoǾ X4kahŭ/9I]q~tE_\yIrUw|?$OuxmwNX9o]wÀ=ٸ>M|}ng?暝ǯ8z?^S {L'ƭk#eg)O8:z>hWzӸEwOqճN~K_}છ,{OԨٶt#+MzXE%]A>=ߎso?= @|P/:n/9u\ۂo18=ڸ݅^.j?9&?GS^O7?cO{y}B 77dW;N+c$:N^oqQ|9E7:(I}]PUکK j{u)޻~F|zնib+5;xluCo3u_s_~_п OYn=8\_1t=]CN:xvI~ϴ1|;[׉߽O~g_?bߗ=cŹ65Hc^9阪 ~͞:[ݟZ,g=?]Z]oZoپؑ}_k7]!b3=<ѳ z\X.cVz:NCA_>CaWMYo]`_μDvg?|>_җ/lq'/ۢ:ɪ>lCj*9{;n-'ߑvsnMwNƧ HCy?b\|<۝}<9txp wKɹ;"G9;9Ø-0Ύ'-C7dq1N_rYޟro )MQ>\gGd|`qu9u|Yg;_y*!rt [[q>3F?Z_)>^G'cwGٸgܶ`Orrj';5_ġ%'/O'?i9uE>wp> y~O>W| #g#9#'sGZ_\I^Y-Ol{"'t~'O}rO;szu+c}}IMzu]6g'i>>Һܷ>vp1nEWܲFSiߝI[wE_?o\ :}o|1q^;{֌SnM7ZuΖ=k Rj7ySצ{MUm f~n >kϫv0#+F}QGp}HT/_a?lvR|KUY{T7=iR|sܼ3{]g)q9m-F%z(:ؼtx?͠Gr#ГmC X >z}+R5wy↢Ի _ޢ[W7laV/3J ˎ3]{ޅ;\С]ܳ-ՇkVW7WL|;}j /~=&?IAsŹ!됛$+Xx2mɓAOc=~ߓxUM`ӕϬ{2vi[+C^Qg_I9&?$??%oɏ3Wןr$ni '/yk+ڴxy{NslzW1fȢlS1a[ޜ9<=OS|rAk>f1f< cp/mC-q9>1/AD7]>Yqܐ8oț$m7_sCOh;?Wȋ~'[ڹuWҹ/{q ;B2WKO;c'S]1w:?9]쐋Og'^wIzNٴ2#OqgĞ˼y1_q_9Ø-0Avv#5@-lYui/ۊ|`r#g3B߇38` ܐ88ǹo9lG <9yyƫ;;~ѱz|k?3\oo:8{~?h}Kzች'cH|G]F>Np=Tt_~c{W98v\e9p?:8Wxl9\7ϒvwްu^?36^p6 Χ?ٸgܶ`Orrj';5_#|:>:q]sk>wp> y~O>W| L;Gs~s`=_\I^Y-O1DNNW _o񗫯Ly%z7=#uۜSk3c_¥Xsީzg/g<'ZsEr.ŐeNr7ws-^hҩ~/>^kN{g7=F?NY_uO{NgXE++އNƋͧ6oqΕ̅ =V]^5=[rf ynmA>N腟.?%r'U>pꦯD\ ?/!JoU6-ym q`gK¶- FGo?>M^jl}xUetjM Gصz[nuXVn-s#_ޓ>zC4_uYCF+}G~YN'碇Cn"䮠c o,~;7G'?!~SO{g胁K[WsW?V3^ƿ1zqH~%?_p1=Ϻ'5p#//p:XG'GJ-13m/8`\LoW Z|\\e[^;.1{;Ͻbߺbn3S[b~?9ϢFfyg}iAFWժý>>87vY-Nj׺'}K4[tGŹxz~ZͩK=u3>F]3j^]O~O;n27[o/v 9Y/ ?F|9'rx'z6䳟%|rAuqv?гqC1f< cp/m׳m9>o;1х?'=Ø'w{p|>*7ͣ/Ǐ!m7_9=nAB^c۩"~?ЇUgN.>gW&Ʈ?rvOp!Wc.?֕lWbܰ88ǹo9lG <9yyƫ;;~쇁o:WOpz}W:8{/za|[/<$c|G]oꡈcc"7_۝sݗx׿\=kqEߪ}AS g stw}'[gI=qphFT||Mvrl3nog:Owk]"G6U/?t|2ݿgiqyϝ7r?Cӿ:W| YG3$W[~~d.rSE~0 8#q_=e^_7ۼk=zBq/nU  kO;5o""w~[9+r2r硧$WՖ=h+ӿϖoq3?u~_Cޣ6_0_u/ }&TozZ]ꂭ.|WU;^ l:Ww+mrKorwGv~:ckkfzw4_u]/񊾰 v]jٳ3y$ ٹօ)..I -?;4j2+vRS/y?QO#"P6ˤ݇W}Vh ż<8E6 \KM|qn^O7FgisC I)~'ÿ!/t_c!O=aOx̶yboXsč7_YbAX,FxTէ۝/S۷.Xୗ+>!sg>jZ (ݖ_2~g޸9=*c^t[1gu}8fޫ }~DyA:4Ӫb=ciޛ,yڍCwm?~yf/ {>vgl}s ׸ox;|Ÿ ݱf6zgiae}9~#5@-l9q'|`rGΎ .>=z'4tߺj^ǽ8meB/#?o'vd]C}PE"W/Bozolo*g],\ǻu\\-Fg;og:N]/؟/8}S߉?\}'3\Qt||Mvrl3no'|9ǝyׯȑCKd>gY{~?,q~8<փ!_*7߹|f?'7Suo9%?l{"'t~'O}r/׸:8_W_2=ѧߗzۏWEosvr~0N8mӇP[v bƷ*FQ;׍khGVVŤ.yeƍگ~']zϹ]xo~뺠s+7>kVrm|#l|:}>?ޛ%U#fI]nh~mT\ǭ֭ww'4CHNs~M3tҦ_^{w/i-ό~kO]-rųN:j-؛op豺GClsG{\l}⛓O>1o}\)Uu1cV[px+':A:oܱբ3o✤ϛ3OW|_|_ձWRTkRs)~zi˰biok;v-v'{q:뾶Y#kn١ɪ+q]Y,uJ# ~ߡ_}aQw-+/j^~=F𓈃d>㰭ۆ?uȝ"9e־ӆ=_~ >GE¡Vkt]n/npxn>3[m|8=~2{l ^.~W蠗7!&? ~K #,~>yA75p#/W;{$D뻗]8r8IסIŧ=߿.G 3G_lK&/:x^z15^ݲĎwS^k7c<ѫ>pb'ry40O~v^yv`ԐN{68*ΟuݓNyA^iv^#/|>Ɖ/I38~:?}_3od;Pq6e3~o^=u3>\n#;ZO~O;rXm\%֛zV؛sy"ygA> z?߹\~гqC1f< cp/m]s՞9>o{DvgK8/uy y~zwQ%Wȋ~'OmJr~G6YǭW?ֿlG_^l9~;tߜ.v'OγǓsG=Ns}^؇~;%{#ÿ H[>axrk>[.s_Qk+quc9;'1qz1n_^g\ǷuLOsF*!rt [[q>3F}G8^G~6 O<>r?,ѳFס>\Et_#U1κԗx׿\=kp݈clw ]ǩ3cos|j:;s$|8]8j4~?;o}N{m 8Qrj';5_#|:>yuߍXnqyϝ7r?Cӿ:U._÷o֑s~=;Oo^w>qr8iK~b?1DNNW _qup@\}ezI~_ws?l?^]8e:ps{zmQ4Ȇϸag/vXլ=;iF߻lyU}~ݶw7?i0b6g53)CNX_93z9jۆ9ىgܨG->|vY_ԇv^melٷ*w]bѯ6{gmyGJtݰ3O-no#y/RӢ/I)KZ#M|e듋 //=w}a|{w/4㥮F{xx O| Zzv};\)U_ްX׬n3o(J yWC>ݨC_+Mz̿.mo=belLbuտv7Պ6Dصli-U鳭6#=uvU[Ֆ8%v|=8/~IoJf_POZO":6Gu!wKwbo l0vRS/y?QO"PuWjSD7wFvEo:a{G ¿5$N%)&? }-?KY+ؠ^ 7'.K${$ןؿaQ_;U,|nq6c?]/mr7Lqejzc<뫫nŻ{{ݰv]2IłNy6]ϳ/yͱ~q/~߹ퟫ8N;pq#c;cM|֡?xةOO~O;ϜsV >9=%bo牞M' ~Лv.wT~ZW@b}g1L~iN^rk9waAnݜ?ed/a.G_9b.Gy~&.Yk>:cc#~x {s;n3iA?*cƗmYTyOֿt;i +>㸳=\Y{] c~7] 9Ǘ.vOq.m'Ӂ3~]ro[N~gb6ccz B;>rroOg7/#.so?gG <]'qlsm׏sՅ3,gC]uq S}7vdswp?ZW}}Do#7&'/ꁜ9}Y/Ow8rX>7>38u\۟|sfͯğ~1sun_B9>Gvrog+_9wٯw893w]u3ӵ>xgru k.|nsXv{YoA x>Ыѿ=}łutC/oIW,q7/mg>';~|z7/[{By'6}z_Yg|zqYOۻa7ˣ{b,8i};bҬ}Kro\ճۃWXT|n_]`njr1fU/k90"'9ѕ=ghx1C߸l*Q䪾C~/Mn~~&bvٹv=-Ɖ?~~C/[v: W.ͷ]潊Xm{,Y~/n{Fo-zނ-k|_ϫoúDq޴S[{-D'.L9go:gF%BΡ׎}*Fw 'Ս{m# D;E%]O*n: vRS/y?~1/ŭmD7wf>a˴o'e/'|zߓ?x?~G<toO\I;#}Fn|FKc?p1ӣ٥O`۱E_\eW}1޻P*ߵE1q6.9 ~Y/h#&>3uoIЇ/[OsOY1~Yz.wY~;־1oź7t%AB/rx;xZ̿z ^w/7;Wr.[X!\y9'z\X.둧qC1fqK8c{;tg>z5eԳW֏m2?^\ݐ~ts+OW7+Ν4io:;َw\<%~{㻮;tszsA;'ɹ0ods=~G9;97aO[>;k힫?so_V"\71v#| ~s8 `qu9u|Yg;_69O#xwuO?rt 3\oA9zr~ա#?o'vd]s㸳g<0Pı\_9szc_{) 86F~N.m\=o|¸g|}'WIgwp>z$_rg#p] g8s['Co߭o~쉜9`\_~b;stW~_owsa?^]ى+Npz5zxEͲ+wU1`ζ#Vyb^-mx~4yv?bfQw5iٍ7]sF;o:RzyЙsNtdUyx|oYh6j+>pSnk㼿_=}4˭`ŋN=i?Ϟ=lO ^Vs>-߸qz)]b-~>/]}J̀Úl{8B"k/_^UKDm:L\?$=1^kq,ȇE ?k! ?!O\/  }?-5C=Nw/,FmqOq}yx8wk_tc=G®3.<^//u;_ުu7l%i><~ǍSD_ztbXϽ3`'ճAS D9^W7ݻxr?oc_KOGW?I^C->`Mv &^˹-&C3z|U^Y% _߽o]8 3||snӠ^O7g<]ʹ/S\^I+b}Ia_c}zc?[s6gG'3l.-fcgOk轏,zm;/|6#{c^ouI;nzȟNxU1~g_wq/ s;+r/ji;v71t=>rr"ׂ; _g _YM߽O~g;ggŹ}raӽ~{nOOʞ:[W{ѥO''Ybvqg/7;W؛sy"ygA> z?߹\НZӍ/kJ~8Aq}r18헶'|\[9>oW =~OÞ?ӤApnoÇy:톼 ?WI?^9?\iߑvǖ;:1Cy?b\|<۝}<9mwaW}臸3^bOeqǼ>cǽ;yC;Ύ'-.vODZg;9~?Їe=G&Ʈ?rvOp!Wc.?֕lWbܰ88ǹo9lG <9yyƫ;;~ѱz|k?3\oo:8{=h} OmΓ#s~rz>Fס>\1v_169U1κ՗x׿\=kp݈clw ]ǩ3cos|j:;s$|8]8j4~?;o}N{m //סx⸳_39rqz̧yWW8~O6ٯGyyz 3=+_5|f;GBsׂ?\I^Y-ζ'rF];~2_7~'ο:r1>$W[~~d.rqxua/o77- ?w.N9fǣO<ˆfZ␭lsj+F/S:g[U%˿NDMy57vwjۚ?}J7]V<iKЦoM{/>fYqQZu&CۿE6&u1/^1nG/ŨO^L|Cs|xq˯KGwCN*vj/ͧt+]јUodWw > ?GOyf?|!ıG]s[F\Ѕ?!o{-v+8w:{Ƕ ̨`Fwbڶg>¯8xbWSGxW~]x{_h~/~aΤmkzշf;~2Cn$o5u/}9T{旼 '^VwSO'׀ |î9Oݝ- OZ_۵ٳ&3|2tr~G;zǺt+AD/$x<ؗZw{wHA]3~mHqط]̸g/j1ug_ŧ{NSsW,b5Oۯ!F⭹o=;z4hY

#?v[jȞ:[O+''Y}7ƿĘ_[o/vd/;|/\yt~w.n,tg=6L =O'1/acOs0|v⮷{sbl{;ƛd/BvgfUae}9~cǽ;yC;Ύ'-.vODZg;9~?Їe=ֿk-US>\gGd[W~]֋q::笳/Fס>\Et_#gޒU1κ՗x׿\=kp݈clw ]ǩ3cos|j:;s$|8]8j4~?;o}N{m //סx⸳_39rqz̧yWW8~O6ٯGyyz 3=+_5|f;GBs]p\NZ~vny} v=3*9`\꾁K?q5񗫯Ly%z7=#uۜSk3.<>m`ݏ`hÕxxjo{vbƀA^jx1/RڣgnWtɁ^ϗm/+wo6n͠_>Ч.yޢ݋s.̓΂<y@ы+u-kC?|;wZ 6nzw0s K߭WEιn9yG~4{}QȅC7!? \w ?onqB[ܾb˼~YڿWn5=R̻nW<8+]ٻu )}w{+Tu7}CG[{ֺ%%vv;Os 1[>axrbWt{|}\ֳgaV&Ʈ?rvOp!Wc.?֕lWbܰ88ǹo9lG <9yyƫ;;~ѱz|k?3\oo:8{=h} zች'cwG|WC}b}zc&7qsm{e9p?:8Wxl9\7/X>y7>Cqzxy\78N\= :_菧N[{ozdq~=u78̻~E\^"~'d?7κask>wp> y~O>W| YG3QP\zu׿3׹-ֿ!p'ݿ[qmO䌺JwrdN?'׿o`O;szu+c}}IMzu]6g'Vlc*9r]ݸSGPw3 WeUdԃ&ݡm+0/iө&{3}7g߳#֨8!Gtt}ƭedm{yi^n_sMK{::kxFqg~t^iןq]C7WA!~/2`̍^+?u??>Ň E-=`vXq˜E+yjzE͋m,у.(sgqf1~>Bu;nbfe[dVsُ5={~eF%B;(9oO_Cn 7=]o ~=?{=?~Z=6Ŏ/y?b'^C!/y]%5]8`ܯ>ᯢp͊Q|GrŸcw,?ݣh.3}2ޣ&CʿWWXzz]~0~:?}?ai?oTŹgۮC؝`''Y}dz/7;W~i~xۻn69>oW =~OÞ|>̣/Ǐ!m7_Kw_E'O&OohfV+;Sl*cߑvmN;c'S]1w:?9]쐋Og'N銇|I^؇~;%\w[s>v;Os 1[>axrbWt{|}\ֳgJv}+quc9;'1qz1n_^g\Ƿu?<5m\|f֗q ly1vw}~>YNG~U:~ч롈cc[۸9Y׿{^rqrqm<t,a8u`fl$W[~~d.rqxuaL7p(>#V]¢}yb&OȟsWlys//f<{b=0ǽX|vmcЛy/obvq^|fejze>;h۷ߵQ;͠ygO+}ꒋWk}3gb7ҴI؍Y{ﳺ<î*~+3yz=\+Q /?&;+>:"<_#r–\e ?GO5M9>#[}ai?  C/j؂U6ӬaA|^f4jzFOU|_ٲtR;N~]x2-Y}mF%BΎEL~}<#~ _X> w׾/k zswWﷱ/vtc~}x > ph_\ڗ#7t܄h֓a?!Ν8]wmg%`>gNzw4Ξ¿񷈗g쟱RM-^,Wpe?qpDXݑ ^{Fߏu(QQS~$ߟ~UY]k_ރyk_~7qa7{>mZ?"}7gt99{b=c{wهP.8c?c߻|Ȟ:[w4''Y}_[o/vd~7DDϦ| sqc;гqC1f< cp/m [bw7+^Ѕ?'aO([<ηyr>;:}kwKɹ;|w6~] c~|x}%1Ů8l'ǯogOMe|`rGΎ .>=z'4tߺj^ǽ8mgY{~?,q~8<փ!_*7߹|f?wߜ?XO}:׿pw?~ַw?c퉜QWNW _qup@\}eẓO/ֻY`2^{q>!_)>X=wi[S'ݣ\׆GtzqԘ7/x1Ip/ۤO~[덊/?"Muo1g@eh?wo??ߤ/ޛAbm[L{nNG>x;KjT}ܥ]KAgvwEMyoϰ6c|[|tRCGmqJѫ_\12W\zb慷YE;?ض?\ݧբ#Bo{xpz[__r-VӚ֫v}n!~kb7o1gAȇSjϳ@.X/pZB|=u~;^&/Za5k zbRb^o=o_qaˡ?ZSSL[z_ffs׎_ḅW}`o_/l[?o[tN83V\0Ə?F|%cro]~=Q?o^Gƾ%GOfڿMgVǓ& |~@/ _wGzw:%o~/C.z7_ 'ÿtI.ǮA󆄽 M' +۴x%}G14}M-:߭<\H{0~&a;^wwAX}Y~74)o@"~'#T+;u g;BrSގ;c'S]1w:?9]쐋Og'OZ/C?ĝ{r.;G9;9Ø-0Avvk>[.3r|`rGΎ .>=z'4tߺj^ǽ8meB/#?o'vd]C_7_z(X}"9+6rq~,\ǻu\\-Fg;og:N]/؟/8}S߉?\}'3\Qt||Mvrl3no'|9ǝyׯȑCKd>gY{~?,q~8<փ!_*7߹|f?wߜ?XO}:׿pw?~ַw?c퉜QWNW _qup@\}eẓO/ֻY`2^{qZ*Ř>Etf|tŔ>k[Eͳ'vsya~^ U=3B/5Ǽt|?֥glsv&{C{_מwCfǒ=wjЙx"ݯpϋnnwňc^3= /qsdGI ?!ÝWFy͠of,yrKMy_bL:.?) q?v1C,nZJϩ#jަ<ڰ]𥳐'.:kGӝ~ǟ߁O^O759t+A O87b=vG.N {A'?T~Ar~l@OWߗ[yޣM{r[μ׵NM@{qb ]ϳz˒~ዱ40}^'_Iߡk ~.<{>vgl}\ 3toKߓ0l_>[~7DDϦ| sqcZ=Ѕg=0>9c>yϷ_ڮoc;s|8ޙ7${Az ؟؇=o[|>̣/Ǐ!m7_σ~qc<V?Rap[OWoG>ƗVwxwNƧcu~2~s!<9vgO}^^^؇~;%\w[s>v;Os 1[>axrbWt{|}\ֳgX8庉돜\}{Oi耿u8m7/{3qx:OsF*!rt [[q>3~?Z_)>^xboI9p?d9=U}PEt_Iom\_=^}Y/Ow86[׍ :vwްu^?36^p6 Χ?ٸgܶ`Orrj';5_#|:>yuߍXnqyϝ7r?Cӿ:U._÷o֑s~)kۋ Mg'O?nF6*FL_/RW=?{cԱ:n>?ska$v.>[Jm'sycaCWOtxc\9zBW!L ?!Kךo&zGk (6.*~]S?_,O w?:,^?uĈtՔϮ'.P~ҳg{Y'w>vgl}\Z~G<g=C{1l_>[ϔ+~7DDϦ| sqc;0}簏1'9n>~i'dl{;ƛd/BvgnmLoÇy:톼 ?y"~']*}5}jg;Brq;:1Cy?b\|<۝}<9w@za!ؓsw1o=q׌gruq(7?Z_)>^xboI9p?d9=U}PE"W/BoBoolo*g]rx~u_qŵrnD_б|o|ܷnp>5soz>syu.?Oםη>l'={—Po;۞uɜ~Ou~ߟ8w\ W<\]oamN)Q\xOy~qyO:ި=K kV?8𣋧{׃}U /R Hl˰>ߠbTyOrxoz=g{ kKgyR}՗=Ϛto^]+ޡx+|_J1<ݷUo޾\z|7DO"=EMysdry?x ?GO5NȇS@.X{ϗ_櫦KeXZybhy|bX_qZ+E?rJy|#mdy|qK“y=F%BVFŭ%;HLjCn 7r;d ,o~bG?旼_?!Cqn‰wa?}N9x .N 63|;#)tK "^XyҠ^ e{I ;r7p"?^Ʒߏ=Tt/xa_T~eqNwV,-7ʿ-J;^wyn}fOߧM{C.!'r=[~D_b=cbl=HCCw(W2}_~|rawǹw4GǓg^Q~O2֛zg^/\yt~w.n,tгqC1f< cp/m o9>oW =~OÞ̟]~vYoÇy:톼 ?y"~'s+;0}jg;Brv;:1Cy?b\|<۝}<9םw^؇~;%\w[s>v;Os 1[>axrbWt{|}\ֳ 8庉돜\}{Oi耿u8m7/{3qx:OsF*!rt [[q>3~?Z_)>^xboI9p?d9=U}PEt_Iom\_=^}Y/Ow86[׍ :vwްu^?36^p6 Χ?ٸgܶ`Orrj';5_#|:>yuߍXnqyϝ7r?Cӿ:U._÷o֑s~)<3?uFyWyu|7_#T28\?~Ź/ϛ\]r{sBo'.< 87s-߰>C/1 M~/'Ï3.t+A O8?_Nrؗc/(Ǻ(/c0gOO).OqeJ{ 1;%wGo{]򻉫~{idn1t=>rr"W X[O!w!=mg{zOC؝qZ w?ߓ|zŎcߵ^{|9'rx'z6䳟7Co{ l?uǿ8}ه>9qK۵W=aU/vxgx].cb =߭m2?^\ݐ~w}^_E'OzW8ו*#})wx wNƧcu~2~s!<9vgOힾ׵^؇~;%\w[s>v;Os 1[>axrbWt{|}\ֳO8庉돜\}{Oi耿u8m7/{3qx:OsF*!rt [[q>3F}G8^G~6 O<>r?,#ot PıJE1rV-m\_=^}Y/Ow86[׍ :vwްu^?36^p6 Χ?ٸgܶ`Orrj';5_#|:>yuߍXnqyϝ7r?Cӿ:U._÷o֑s~)&L_)I͠?_C1gJ5K}Ȱt_:=>"{y2(+X_r1okJ;D/6w=tO?y}{ a>'|~p ?GO58CE>/?  Cޗ{O7_Tҿ{F/o}g??ǯ8tok^&EVQGOy_ḅ>07/r_? qW J:&. rcߚwWT ~wU=ƾ%GO^.C ЍsN<o؏x@_[kB/?7?Bğo-%E~2=$tw8Q? ]8`|E}Ģs~}c/,[W\_~qOo/?8y;n₠߹ެx>8SЩ1]CNz,}z/3/Cwه]PZVۼp;Ͳaw;g=C= zŎcߡ^ {s.OCa |D9>oW =~OÞ[|>̣/Ǐ!m7_V~wc"~'s+ۣoXwo|9;tߜ.v'OγǓsIZ/C?ĝ{r.;G9;9Ø-0Avvk>[.-}o|`rGΎ .>=z'4tߺj^ǽ8mgY{~?,q~8<փ!_*7߹|f?wߜ?XO}:׿pw?~ַw?c퉜QWNW _qup@\}eẓO/ֻY`2^{q=Et>nEy'7|w۱\x(ݻ~_[?R޳?ҧY?{~[1{O{{ jKgyr =ϫn$v2r:}{pp }5twy_Qѣߺx~'?ǯ8t{y?vv/uDtOcd=]^*o_/<%??/?;OLjCn 71x7oKQﷱ/vtc~/>tdoƹ '/oo)x .V?93|;#)tK #] n'.N%#\;%>z_ {A'_OhW~?Iqw2EcOw+O?+}rEރ [ ߙ KߛY~;nC.!'ru(w9%/|1|1)*~:?}߾GŹG O|֡?82}GÓg螘'a~Yoپؑ}+WV!bo牞M' |rA{Vg=0>9c>yϷ_ڮ _μ&p% г]>z([ae}9~wзO[] cvrzt.\"\71v#| ~s8 `qu9u|Yg;_y=~7^yc?^\3vz |9gơ޻Oh} zች'cwG|WC}8V_1F %cuk߫/)ǹz c}AS g stw}'WI=qphF<]w::|ӳ' __C-qgf+r?O'>qm_;8Ag3{WAkv:w.ُ='7Suo9%?l{"gUz's>}~kq/Ы/W_KrunzG֫"9;9?^gfwhyxvK,{G{ϗU?z+{^!?˽ }_W}-.y/:&nG/={=ҽK#ݷ[oޮT|4+DG{\/s>: s\{k|-_@.X=Ãns{#ï8E~?ڹq%?V?zS?_vd=.o7/r[?߫8=?;NLjCn 76U ~wNy|;1} @|PtЍsNt, |~@W _{g&?wGS耗E$?ct ~O\'Ŀ|#}'s]8`|f}¸M}Ew E+?WP]򻕹wJy;n✠ߦl}U~7tRyA/wYi~Lgh''Ym'a~Yoپؑ}o/W\P!bo牞M' |rA{CS z` }sǘ}7o]('9wp3o \I.l?{2ڥq_ї/KA8N1+wW8מcߑve?v2>uc~y;xr=U}臸3^bOeqǼ>cǽ;yC;Ύ'-.vODZg;9~?Їe=ڕ[._S>\gGd[W~]֋q::笳/ڕ s\{C>\_r:}۴^7_TҩWPڱAѹ>9s;*ڧ+*ڧۇ޺Ϫ'.:Ʌc_S ['^ܚb; b|QS~ҡ8ޣ&?8"}w{]VA{z 1t=>rr"{/|1|1+{>oCM ~Igx;|Ÿ ݃Iz([ae}9~uc~y;xrn>C/'2czdyw]<mgǓD§c䳝ÿ岞?m)M]Bߣ\~2NC+?خiŸaq{qssَxr4@ߍW9w^wc>׌gruq(7?Z_)>^xboI9p?d9=U}PE"W/BoBoolo*g]rx~u_qŵrnD_б|o|ܷnp>5soz>syu.?Oםη>l'={—Po;۞uɜ~Ou~ߟ8w\ W<\]oamN)T\O_<(R+VtNە ҽ[וOU'yt+c6 n/.$׈fVޯ]T[ Ngto^tH*}^QZޯ]h_޷ݽRo޶+D6w =N?ym{_}NhSnr :{ȇS@.Xp(n. [y?uKŽsytܶ5\]ۤ{wϷ:]:ϗ'.mZuPC.!'rX~X_b=cbl=]Q~}u~;;*ݳpw;Maw;g=Cw{b~Yoپؑ},WB>ޜ9<=O7ō{ l?uǿ8}ه>9qK{›bl{;ƛd/Bv'8/uy y~n-ϻ!WI?Ɠ[s+{[cߑve;GwNƧcu~2~s!<9vgOν.}kwKɹ;|w6~] c~|x}%1Ů8l'ǯogϭ{K&Ʈ?rvOp!Wc.?֕lWbܰ88ǹo9lG <9yyƫ;;~ѱz|k?3\oo:8{=h} zች'cwG|WC}b}zc&7qsm{e9p?:8Wxl9\7/X>y7>Cqzxy\78N\= :_菧N[{ozdq~=u78̻~E\^"~'d?7κask>wp> y~O>W| YG3QP\zu׿3׹-ֿ!p'ݿ[qmO䌺JwrdN?'׿o`O;szu+c}}IMzu]6g'̷K0oO)JI*w/ڥ{m'{k+{U zwזl )c.]^ezoN~==AŕjKgyҹ:7Kn-?r ڕP|ߦY~to:S^Juo++(*ڔDŽ_qy~?zkۺjw]yqK“y7/rV)J8ҽj1+됛.ȍ}{zm_>~ax > p]yztmOnpvo؏x@A8zw:%o~M.z7_ 'ÿtI.w_ {A'Ҹ^%WbK}}wzy}??7Wmixsqp/tests/testthat/flashr.example.RData0000644000176200001440000013435013573612732020442 0ustar liggesuserswW*Ly_׫'/Rƽ\=7v;ưSF IƔ珮Yfh#3K{F98Jrwr"-P: V-I9f˿D~݋gF6_P̣~ 0MᦎOg]k^FnULcloI'HŎ2s%bαG|Q9z`b%">~g-C7o(TM"^.F_y,s7o .1Lˆw< 7+' ʵaWr±6=rPs=95x7Xzm2!@zS8EۘU8\xvn51PI :8wr(~ZIу𘤐'w`LiDѾH;+,d7Ң=zXlQUz!r+vb_ϷOާQob)Bj%@o/rޜ^g P얔PNcc;l,ʨF*9nYA*DbğԢyTKZ't o_ 9 LA%۟:"W,OY#ve?\1"K$J-;ڿ{,\ĄAgδ™^)Xx4wG. 0R90z4^bx.'9.inS0F`w (.lx]4 eu%{$"YnZfy6ˏ2zr'DK)oRV|Qj{Okޕp~I1q4"vnm^ѾX;*|!60_%Bn:fo\|'>^ݪq  ;#"UgȓZ0JUS `o7a C|}3?_^2{|J[MU#lJؠ@hX|%\T$Wplkf,0qԀ='L|?Li!HIri8jٗ`amiXs6̈qg3Jy"}5ibn=>qފ- ?i]L=m>~tլ/ C˛ߧ$}`WxAk!hu qCA읏\Ia{&mFhYgW?lYJ>#N4@~7!_R c+?YZ b^ϦM]?_j\Eo/hșq7R|a,_y(t_i˺yL0u/sGc˕B!61[[et.*px v32G >KogiYx^0^{Wgb~H[ɨ4\$go,(I~dܠDmPEsRF%P3f}5Gy4*{ eOb|k_ B8e%PIXϸDi/S^<طaϷۼߜgqgsTr/O<\~ߕUn]XNw@ݔRsPa[E` y7FǨ\}9sbptb&DJ6>՚|߅!чyM*rϱֹ٤7"e:-X:=nt܎uyFM:446oNHV>e'Iطoo|Wޞi5%LQ VJV8D%wGI>Al zGڼr.xy˶lh{z% oT߹S3V8D!ѝK+iuiVV?qUoWŻ>vM_[8_qNn}_\~B:++Ng.)y |rYy;:K>'{o?3pG8aen EB bB:8Xt`5OSEdR 7waarŷJt8Bw"N6}XB?d'Qm{ 7jAU_H~U[sJBbȮxk'F7h} m'*w9Ug9T{}%ey.KWڅ9\W:YCUVolw@ER~ż<<ԃyG2[{hD\%B<j ?m/"Z"(T_blimQeݳ_a>]p7 6{<[X gȥ892|BMV'= <@x3!fS<s`#98Pt1QfRd\+$ݞ.8ʅlP)45һ_rV~H[~\5I^$ҥڪ,1lVK_i!dO`9'r-aGRԁJS o k|Ҿdr0$‰wGGoI`H (_q 8q|G"(j ["DnV%dm:Ei.+!׶m!Ag?fiLiVq*DEub?{خ^Agb'2!ruYsoh֭=_3 xw aDl*w?ʏ5¤<5gsXXLmRytdTgR}8K G!^}hTU;]d8@b/w%8g <K/;CqyO}V.",E##~rY @ΜS`]VyDA*t4IhZQVt]`=vѺM{ tvgU+PNѱ{i JHoS\mgO?CSF.$?9^kxz@?W?Ϗ\ꈹGKK)aE#gӬFzǼ =UZGvFa0"7Im%/F5HөKs{˨*DËnA?-WA}Ӓqs~tM?bߞ/{+KF~qKfS!k)>gӃա^kǎU&WZG| Ձ_e Hʸ"džGvi?,V6e/?W)Kw,IA RgP d'fuyH,soߏ3" N4Os8'5 Lc^ECpBdq/r拡qARflR@0Ii-p'فܳWaRQvÁigl'sx/lbd,O O;F.MXJjb[T3$׭ aM誟c.,lFʜSzdy_mNrq)@T$y/6߃:χn7^<#}sOD$c'Ww~o^]/c퀹\匑J=O.+&}'O9mFU;STGzg2}mM~ZrJrđJ:*0s12i'_bL= T}@XD4}+:Zߌ-Gjt_` ig`{A1C;>QtQihJW2jei5|_DJ0LYLLa/aNpo:dwăW=Oi(Ku7jLr#;vzE+Nj1AY[}d#}Tbx]H/wr/Aq {\u^V驇de\^.&~2_J<=J88Vs.XxjS.FVC>Eb7|Yjh~TJ"I=z佁]N'ܳY"b) mKQ\)Z70=*SE#;T_5ix<O ΫW)!v<jkkNGOt7ـc+mYl5A fvR_Ś`Gf(_A)1cw"h?e$:NV1@]&s 'd>Qw4%' ߋEXI~+r\~sl;@yPƈoƺ~A  9\IXS |^ \=4FX`]Do˧ENRۗXZ|< /`U<+s]oO|Zt7O\9G"*+j0 ȝk~i -`FLV\?sd@cK;k@F)$qke);7ɡ,#31wCH=c+4>}J4ޡ1f0u { ~7qի61ʝMRVt.\ftX;0ačnZ =O {@6[K=Ν0g{nlޏρm LߛRp+ V=iPM@o_-2B*^A-(߁w1Fa0rď%܍ĭ{\[5R,L3P o :Zs t#rUF.oJkNlY0de,*tr)#̃ueWA `8s4 bn A1Y6w;.枉>&tZ]ޞ>FӇOQJaOuHM'Kn:S_]Ii&B10"'y2WoxvzS}!r(vTsREvT_:#m r+<%`D ({1Zx|ѭXDdTiON{z-jaMCwޭ>?Ԉ=şu&rA|t(Vic^=v6_{K*bqVԟ8lL*s|Z"Re,KHCvQfJCv}OQZ[8RYҚhhojէU/Z%sn][WedCWJdZ2 xo~Ț4>B 7R,? @ҴkgaT&'MٻZ?kGy#?Zǘ,@e}ʟx ZzV F%p12Ѳ i|D'ԒCB+,1Eo(Z1O\Og|=.k8@q >9O:*^s-}8;qpl~v叠Qz&3a.BŶy J?l! /֪;|g!S! .߾ p3v8LSQ9|ϕ5FB*R#P1|W2^2Bs5rS=V[~=ME;[|]ڐM sZ է GW-SJUiVhOĖ&734U,^~?ȎZ{?*6TnoO:.JƐ#D.3F)UPiI#H'bQ!b}:TnnEo?2"N߸~A!-^+0_ .qyv8Z%Uv#DB4#5l}0=#';)闀A0E[=MEa%? ;B: =rzj@ux~,{뻵5ЅS;\_ԲӄH2 1ii@vv#Nb?z+GW@";#y%t?HDؠޣ-R`& f9+o! r7[Wt:i6߃i -uwʔ\Ԙ y@N\ُm˂-i;!=a!yTNszw  <j} &qɪ—gm5\<A{;z8ʀOR~~^<:J_ġ;$ab(qibN\'{-c}g*(^x_+fNd89CTUIiog* Ԥ}0ɶ[OԔiSKUv;<[R\&{o."I~JW;8M{ӎ%3Ҿ֚nQy?xDWǸ/y/&@!.-N4QNp>QZt&mjXǡ-(q$2ϊf!ɝ_=SWKDsdfVʡKt hnk?q_;ffLm<%'I03na#|\S}(3<2#^_ǀ2sE8rį{Z>\vs#" jFuxvL"uǔT/쟒rT[l`e`ŗs`O^h (wE۵Jh`v(a@&B{ck"*W4|+WҠ<<㸋(v^/UX$lh=7Xyq>2Z4@O1X"m~SLqt,yS#4PPD2 [T_6nfrzȿ $1V_7>.AĨjm>ǝl*rfw_ K ?YJKueuT僵-2M9??ÇkdFrhN^d&j20< U7@ZMȡP֘c@\c[Lp7|^Zr`xs}O:xs~T/4o*ٙ S`*"͑ɏGPGTy_Dۿ%M0}Z~u%g[ ˃[M=>am9]+u Ja߅c prY4%/'~5}}Dw?"A\ư0q5Aړy@ |h@qM a0/(z֘솖YrBJGT—|J]s; 2>"]?+C2rz {T=_lc6?.W%a58J*cm>U7 _xxQIqy;!l8T9{0=4cSU'8[LxŊfaK4͛*g.֪)ֶdE-y2%/&,! _ΉϒZ)ؼM'Sd#A7qr,p gZ%3i -_C ri*թ.{KHGp7v|cP?鋾`4z@g0r}Xqn7Ɋ5J[{wOM)WqNR:`ӫ ,b5>Dž/OFq7<>FX"0}FO}i3xK菰."dOn$MivS_4BThW/j4>2uύc/a0bsro_o  Auk0`ȿJ(SS _".~ԩX`" P*6r"ttKĄ5[trFlkT`mÊK߅oxNNqGϷ+w]WB.k{,`I9( 2[l0䍷&#u=|'K-0rZW 0:R'j`}=>pt)`9]/F}0F_=F,eNÜ])#{,IV!_seIq{h]vYƢ*<m>=ˌ8͠YEY҆Lz_'GNL%wb Uak#+Pz965( yדi%0ٰ#uG_Sil6Ӫ04 ΦY;xZ1*LjvQ}li2~=T7+coҘД#,^Hjl!'.|{-~tGQHsXb0Aݛa5 qd,Z@1ޣUX"jnhpwk D:|YbSX^L%f@D~ג߂7B GR ?Y 0].$ ߏ8@ S! y[Ag¹%zG1bB c$ C=pq7CV'; Y9:ML(?tߵ<(tI0nKC j=Iߤ= 3fG{`L@tx[ealθxLyFoUqZz 8RA?Qٚ~5LE aڍ8 >BHo̦ MI ^ՇއQ 8wb7wK+s`g`)r_tsٜAN]oU/;ojLg^{bnyaB6o.,w6O/8{D;[5w8Eӭ@ q@OKÌ z6+3`zzxm>]^q 5߯QRMZfQ$5Q^%I5t{t0|߇iw}uњ;8j+lV>OLzwA;?? .g{~Ǭw`EuEBe<Ι|RMǮvugio=ƿy\SMSÒI0 h,*ra@fuu'L_сy/# BݡiB35=d {דg`Z]g|,IJ?v,0|u%v0dҊ^`ܓ:ÑVVο!cF i^3/)C?62HwB|Oc6A./6eeZHo Lll$u%$ tm=0F$_/ >s;DPyfL{ c`bXx_ V?|D]7KUD`&9D$\H,%~ c,:0I.C'T+UURz>YWrCR`C£h 0& <b䡇n}GYAq,OK: ,-gig$L۔$/q3a61:s+GΎMGT4N1<;(`R=sMt/;ʇi1 <}v:IA¥v1TfL ӔE=%"#XiM# .6NB/t"39+ 0D`/\U>ٵc}{f#Fz;fELˤm_/W',ܩ :n:&\;w 3 X??aK{Y>c?,㌃am/ XO68~F˜Sΰ|h_hh 8)߁kz=,GIOt“q=\){nrq0Xx_ .3Q 2<侁޹NoVHȈzho^Go<AX J7afB|%Fwl%٢I8JzJ:EijWKˋg{"t Gϋtꖦ2^{ -%tm-\Z#h+J>NQ0~zT7%[ݏ=`@̼2̧e\~\?G2Ӽ>B۾%ב(B ?s*g3xm]3$ J;0_>DKqQAл:"3H)oj֎a S/ cra֥ 蚣2z lYC'me#̮,Ipgrս~*`_LrM wT9SM _KC[stMG){q1;u}v珳 kwܨa wx`VŶ&?ERGÊ-#7V$ĚA\3i #Lvu_qb"$ByT{)xRqEL:9{fC\YKQ0lH 7T=y>w`T+1~۠&ni#%EU~n){eسMX'qgd&~~AO~s}WF4*&RFPϼkU0R FJ !zVpl>`W=sx>S,lyke<x߉7B\ӓ﫯š}|Vkwue`:\*1 +^^9y/P|l[>~}ў^@c zgsood@jĿu74}K2f>w%7nKm.af΁qѱpl5Yp@F9U ` ~:E}hmtAcȩ\qP#,Ι90n\ֺъͅDl jӥM}켠PWity[JfS9q(4jve0g?yx}02Le})aK{<4rW d2{EQ].(D>\Df?etI20 ?,.CNFW?4E 2Wiߗ)Qz[ IuZӖ_KU_aO$?dLFR Bqno=+Y_aOء[ݕ^{ʀz=2`PZ脾N.)(#.R̼^\Nsam6Bp99R\}b}h* I*o-1FH|hk(̉3yhZfhw )/pdJ%tk "]*yftw;ГR@ϑih./ lmr`Ont]J}ߝ<~v’'_Kbº3`[AC-4dxhP ]~՘\wTP(zǠs3O]}@ыx$DBO}XV1)(E5b@L97 9y<x9cw@m}ueOx߳x(> ߿)`ϣX| T"Sw,,hޛ7V:f%~KU~ٹ0wv'MgQ>G=_^-TǏak`>y= gV-IzVi]1;J_8^LNSFjDA E p}1?U2vSn(>Oָ0% %ނ^&H^dT@7ɛݷ`Cf(;A]kfq~籗Ơ[N6gކq~w&(k_%}]{rzzq3кsɡ+9@er0_\', &NqEpҽ0{pՇtw]a8j3O!筻tTYn[̲O!r|s:8.oh ycGзimfl\)ŅLh쪦I,t$^X챸d9,`,3GòƱ @ H'xy5< 2:oMxQ' yiͶV}m hw/ѐQ %NWwp/唭Ԫ70 ?T"䯡@6G~w҆"?w?#"{/a&O-ĵ \KZ6X*5YsRZori z=~Wp0S$Oe 뎡$EʀﲚZ[V 1*Ìb: U1\>IM Yvy_B&_14n'=? g̛x祵|ऽ/s?i(=x+:,6 2}΀Qh!UJ[#9<,aw5kNa#:i6=s*7w8o"f*y~K߿}4NfHHNx’WC tSىS?~)ھ *"rx=T[gI!{6m WI3``GZ `'sU`qUX aqfsL4jg0ņ &I<.w0ބI ۨ9eUŽkA4ou 0';.SY窰BފĝoY>b'm0Li ^D BÆ;8o0׵XSo QbPQkzy$w gvVӇ^”6(/GPp;K'#FJ8^`DGVᮧQ__q2YH.@)P?c!ԮX? b!BsAP=2$HLB=Aw={0?Geݑ++$& 'aVs$J7Į-Y;6}!ڈtn*W&uL@ϛhoHgi]vL 1Y"%8Uc6[@?-J_^X~Oq$!yb_eAލFbB-4=6|^oͯ!OmbW0ꃐ[AqKLh>{+ݿ_U w7L BcwC=P crx`8ه!_͓'y4ځ;ŠY*9(Pwv$MsN`?fQJ_ ް ۻ3=)/wrwf}X׷™7sAG(c~QكrGƊb:L^ȸͥkN\P'[1h|U3^KQdb^ ,6qO&(aX, Md{\ΐ%zׇKv H}l [ŐZKszڂ"GSЅNPQ C2zЄJS]X}1yݡ$okiuיr,vZtpu.;sWAkn^Z 9ٚN, 4Mw8'EjLW{Y#e8ahR?I__Vtj0`tz/ݨxD2vi:v7͈P_Rn* B/CƩr'0Y5/+ŒE&JZ/ QYϷe#3 _ً>K$!˞${IcS1ӹ EbHi+7]@}׍~y9 ;5p1I isLtY<\~#&m:Wy`-h3+Ș&CLM2L%zC2% s`s4ϩm4z`8ly)\#*1aq1œ͟o:- WQdɝYXMb=# hW9G1n5;tP s+N$=y`@ROǡDȜ{11⋀K:ap7KYu֗4}Qf0ĕd(p(ҭP\Las]#uh ΩN+#Jډ;uxI 'IjndvuZ-LQ'`j}hIkY3,g'pMk2>S}DWfW@m`-ʃ)fU'kZTo."m= uO1DZPk APFq=F4avjqPt qwŠ@Q|M 072r?L rOp{>_^s8gnYgW=H+ЬaUFaMFVl Sk<0Ĕnц;V ԀT޹,z~H|7iv/̽(۲ }䩱0`ϸ`\ys[0WquhBwpҏ8抟2MܲdX*7FRoVRf@Wc5/V ȋ0,=U` 3LؽuЖ> ?MʯaIn,N<''c,8Ϭ,S?C٪hf[X t~c~@wc0z<0O=L)}mߗΟ&32At /<Ύ˷ǧ@WF[мBo.G^|byC?%iƮg5ws^[ Ӱ\ -g`]9h5`C-:~MCW r^M^TIЃom0CLIkNfnٗJc_tY$̘>{eZw_VJ !ypa.,:cv|.[ArCv; Mxybk8t %kcܫnO /?%tz_\P?NúPYeIx3T>jУCNr?e|ό`'MRzG' Jg;&+'9MI?4Rí'S_{Mє_w̡gǠJO?R_tŬ쇰A!R&W>@}JxhW h<+8Fe$J!0 <6|Բ*- vmz zrS 6q`+jy"T0sSכDrZx-ʱWd"Ļ6&('aM+U3gj^ o14.+@.6 r3-7+Qx||p+pBdB_G}sQ.ɯLԴZhw E}qL}ߏ2m'H24N6K^aa'i(0xG%# k$SX3QOp0TiI  ^K}#Zcu;^\9h n l }zҗ65K̶ t,`Y#Me![3Bo]3k̷ojv _.>W@?\򥾕̘i+1h]HewĿ`]v ;`̳)5W0 ^x*,y8CӳACk0"T;d/Y%csE2S^Q4[%6%u#i6 +WU7:Cc)@=)Iή,,]p?u]l WP |b'Qg>&Cm0[Xz7ZV@]]JU>G4*d(nmVw; %{yf bnӼlkUH aРȗ|&~y,eށߟmLj9n,# \x zwx^OMfooPy؃,^\zZ=D_cƂ+`pkWҲtM^MJen$GT~ VUn^B%k?u@^ k_5yҖ7{?oZC< ": &{ W`X  d:6˯I04cEBg{a麟w.ӌ(ro\Eiٍ0R\/>gdvd:u 's`FclaEU>%;'=-<΀YhXd^2(_n<ミ؂"9|!#,twegoKϗ1I3u rx͇y_2蠛rqZ^ WFlnzAy=h_Mv KOr VT6}f)gwoQ={]\؉` 3_=3&ם\VVNXA=pӁ__ow5b ̭Ea]I=Xa=1X .h5vnS)Bx-}dmKg QdGXvwcKٳQ׷&|f^/X^ P/{ ./`p{8,`~\߇ta2#"M%mѹi:ǒ[mU2S硕_v! BKk˃1&~EFRQv;$P=`wcTjEwX[rnh[spFAv‡o9)q`C6<}xNvޔPt)dW))3z-4==!B*J"ԅ0pIkJ4;X "-; _YmVPb!?N=O&[`$0k V# Ma 5j0vEzHu(q\)X ~*coWW׳5F9fw":+{J~;q{8ߤd&ɏsr`]!O*Y8߫_MRgNh;@- rڟ.D!`9+׷}45AhmX{h PY$SiK rZ"SWg֘e( zTC;` L4ht&W󁦸 З |Fa(tV%YT$%_'Կ1M34}etT`^4}lE3ohSအ`+ YBЂ/#a-ޤh7:Ewgnu(ufx 6WM؞s XAh u==yFD:-Ѐ j15MPVivhmkK3H'Xў3 3|Bfo˙r@,^CqndX~sd %2Ȏd0uij@oo\ y? -bU mzgs֜744mR>Gk/mU0fD5Ik ЖaZAShQj.ÆjJmmy;sM}aUƑEz9BQra%_fg {0u c EO9iBObf0`(%H HQfJCh*X3dv9lHnO西s!P Q 0%[n)]7ξ~ l3'A66Z_ y'*nǼ]Ɵۺ ,0MAhic.onDJ]N7a$׀NpYYKZ)dOur +RRBSf-h*T'v rJ_0kUhsQDn>w ֪߰~QyƳxXe` s UT?)t wvhBlwͷCOg0D\T> |g>/טLšj&(!0I'`mcT^9m<`=gOB2I_T^ šMzj ֣S'G" #ϥ KnR&ЭgЇhj0}[^B7+/,4)t^C{SITcޜ~J^iv:OJ¹1W?+akB:ֽ^$ĈdB5$$L5yrl ۊefatrO'N,/xv~[y'-P(M-Œ >?߾rv 1FAMcL=G~9joEhTSmz-2^{J#ݵJ{o:|%ӕB?!2.,Sky`+ȝXF=4%sy+pONůa8krqXe=mm7{E a㲅 &?VUY7@SZ+,4P$\d,e谄ԧ͔n MѓP<,]kTS2W->>Űhr<}54x2Dރ晏/ŲR&CjLtp qӄ Vʇ{PkD<C%Phn[xzF(l~l}㰏2`a^f24=<IC4',ds>Z 퇵F|q0(<0(``:ZR"5s5 ݇š\gL,H!-4iXΑft t \Ͽ{%<+lR52jX ܕ9#ȷ*ջ6$jM$qۡF«ۍ$TUl*ҭ 9449Qo?'m%pWC cK':ći u.7?x^ʷIkV|K"4vjFf7 4Qs scä,g'g>5tTԆֹ <n%5V~g80wT0,- =~_Om@ У2^8̌/"ݡ+GX_B#Z<^o**"4$ ra嶵˃|4Zq~.F0I@=cWWP1ec- phY'Mb_A*TŕPjz昬\nhi~eц5a^lyHǧ3Q7ZxI{c[{ tPW sBߺhN;PESt'2PP]5?z7^N?͐Ah؜Bb@/D6Xַt]C7 GτǕ6<o[Jf NR4wq7ckBN[ +h{q6*`׉0ew#~\\D1o}Zx#!cg_}\E^ԑw*xy2μ|Y7Zs@"[pt304_I&?VdWܽL"L|"Pfe%"H6{4_C2t[01VI"zZӱ&:v~o S'nu[h7޵bCƕ$PUɐ~ /NAIs莭H= SdMx &|Gg~Dd,3toCe%ZD',&Hy66:$4E>,'jn /YXKj+ڹ3'9pl>0@_WX㫖hf8Qb}Z=`~‚M{Hg]ho,݁Xe|3,u-8b`A]7[g&廮b0ڎ%^N$c"Cx.r56WH'~Mo9~&Lv*eʷ[θEc 7X4[.g p7P߱#xF7ԝ] *6c:/:a,t|&gaǡ"vT]a-I.`.w yCri.>TBh 5uy,~9P~Q{J@_kxᜟu4̵6s]̯74a/6ـܷ^C:l.j:- ˞;aWe<\g2^I?!eL``1?m>*swS T;?c A XR `} 8O;z8 k4y'G>BSwrZ wEo3I 6XQy ߐNn=/;r"ϯҕ$^x#w@{N bB|{hJ&b+<,>@N=(0 ;#8/F sќ$L |e#`hyNIl :պOcrW8{C#CvP7 >&&̳#-~X,!ޜMIuf,no5j X:EL_Ǐ3Dݕ1nŰ' Na8yaܲ?$4F~E/?|^wz 5Lg͡ĬPXd?:) -5!o'iw)g:YB>4Г |q[u5ifKZ0mSNqY84-4YDsS%#/)Iu8^ ?1K3 %$"`>Cٕ ?xM<J=R0VַD"0pSI~ $l)#4up |⬕̽PJE*IjyZ@}9S{w:lXp5zŝZ7D۠]fyx|VV%z@EBɑl ^.`A@0qzJ伺_q=NUi<(zcF0i.6~8v1agk?^PHg\Qn ='QN^hzqUV0jKz}a0żuޯ^:7x5itKhyBr# s%jL]eSUq9xʮ%蝈LT&ڊ~ Sa-Ug _Y!.YSFl`%khb"O>F+h4"Z#ډmw`x{),;aC"!sQ3u'Ե)=OE zM>҂jS޻eX&rѥ՞w"h_:B}TGeR֭n RՎ9̟1]!puEfKɄ68yW.Tvm8\u/5VϠ+-}5-s5Z Np!TM`B)\1 0]3Z}8ŬwgUNe`zvj*(tɍڒWIl]!@[唺.)>lyɈLJ. :Lו ,o{xs>S-j-, '9,~POKBFHږ̯#oy2g2I9,4c炐ʏQeHaGA_kuv,W'_'X'ѥE'=EhرO/Wq~QHe`ti-LX8b44!sgQ߮’fD[z^wE4( qTjF~Pg ۔ iZ~A7GkbU}.i,;Y+kwXp aEdM-ZL\3|(8F -^}!xb F Vق^mӟC`ҊFBm,xV@ I307Лt0n%Anmu PۡN#q>4>++8 }M얬}_ [38Uh2.+; r/]LV vMdW=h:c&i$e.P-wǦVw.58Ce«$/ 2 O]q|ԜԱxV(D ݮ?^V{'i @k*BԊKܙПUsUpig[x> $%3˧W貟ҵ||bJV`0dJƲmqI.R-tUua6YCBјߺ 1wO|b84< 'لW{abۧ`̕aJZB Х[;/{Dq.1Ν<9n}|)"XT? tj XwqߚTk 5яV{5aQ`!]C旆aP$Q@6OQ98ԋ3jYCQ.t:Us$%$'9#$t)M(;]Tߙ:_UUH~LZ+3:w.ɏ;dVbI }ϻ2-(zrz|V H2GjƝgqtD:QFA2Yx`+E,}⃦ǙFZ8NI}h3|7.j s;9[X<]K5՗ưMm._ 4>jQG-a֜C, ]=t`y{ `-FwL_\#F?e#EA}qom֣Ӵm,g~1.;v<)/rRXN`էQ"ą.! |Wm[,wY ކ47.J?g@Y- /!i2mu>hkfrKka'.Wfv[Hc0J\lq 2?@M,qŰPM) ՝{kUuX@[4U<9< 4:C~Փ@*k 臙=l`@_)[ g{2H#^v ֧_BD-~Qo;o*LM=ܮXF3Urb2RZjdiz0]_&3,]$Ҵ,LN9:lo?K[R ȫt/H 8(n;]!K;L`=-27PzX9i=A0)@o [>n+IQ~ Μ-(<7o 䐧iq C<3+doChxC\F[!=5?QkRU5eQvY]U0FCI;Q޺;~tיŗ5nE(m.]k^}OUƠ۝`4+`VhtJ=.kq gg#Sk{b?џϣLnKowxK V:^%<߆DE10 kAf :%A=ǏLl~bP}UCa%'\H8~ë325L{:k|k[| &ۢx:أxg-U}&g~uqd,k"|#LwRZ#,OyB}^ ~u_kM4_GXXZ`J\=Btʝ`hJ,D߆'z1ڱҲ7W`YTٹ*}[Q;t-yj?~fmLGb\zWwGi Xlp: CN_xȯ.9؁={) ȟ"a(wC ~T_FgMַ޻[~$[PMCܟLIDՔ\Li& 최dPuX4B<"Ē4e${{c [z=XKa[O)E信XĭՒ2>;r—IJNΏmDjj-o2 kC:"n}>jb•Tk+tń:e9R:&8Z _0x&ӭq+lO76r߀;KAڿbҊ? ͇OFpm=ZVkBRW& F=Яhލ1_Fhp.VXuym"}Wyq?b 3B%3 -ۀ-ξ&F1Hп{n`'_[0n_?0Ѳ[A>rF G:~>{do\z'$ӛ^.7 װecPϵ\͞ f zY([TԲ5Ѫ  ;}Gb!:rkI1kQU"iRU F3:K,:,3y#k6 ^L5Fʜ۝:`w!e\%@;1nEZnR9U¨K/Ŗ!) rW¬|Ih !V>w0aKZݿ8G7~^0~՜ɍHC]ίTeCH פLAYЇ%ia}s[ׇ(xH~;io(kmS [BcB?|_g@N1~KB޵{1v2rl?/?9̺EℲeV}':'Y}SQWY<2-1 )4H;w|!7.ܮNQMEc,+im ]0ho62a&޿pcE0 k0s#<'X2SkE~s[\$a$ Mv3"lkn 1\ǁyaH5܊4ZwCиDiаqjNRn=8 8Y:"N}7Oԣ|Ⱥ]:ĭB_:lԺ; 7 7I1 :Ltf/$~I#۷,#Wȃ*m!uwuk-"0XW3u!4w&h77?FW͞/,;==ѾLlM 4Н3J6lzׁ<3z.6pf\;n,25E!߷ Tߐ1mtSs^qÒ_5a<21+9<;սC1C{AqEnSV LcPTd}MHN _~CiNbw$+^1ZOJNHt9!G%gzujKIO.|᎑꟧Aw+ržuRQMQ@EZ̧> ^4)zَM;um;=e?U o斅"0쵪_ȁN -#0x֊-}(.I\A.'/`<<@X0:}y]n*aoݳؓze >yG-uZ|R+)gh&1nutm2ιD]y@{P{8!5&Y-c74@ʜ|.-toϗA zg`ǐ󲹦[Y^wJ v'Ozҿ?]|2(aW$%!zQk[ 8ETc * D{kuG]GwlںIF |i uO`wQ6g#V O#X} VH8A>R݌EJ|Ÿ}of㠳k:TZ;4~jР#{MQz%FH9%w+:o?V`n2`s a% ?9؜HwEkoa;S'(_SVS$f 3֔'64=_w/S]~"J{+K8bO˒ 0iL Ux#ovVW\lt,PGdP߃n9{*ێnwHY743LE{[AgوfRϛ LfIa=/RG]@uzn|{*ԔcsJ|TO:w&y@o~M _Hϰ@H2OBG\[%jFuNFhѼ|6.w6vy]:9AͿó~0{U]a#!iSܖ yNoa:AvY ǧOtak6Fro:ߕ1F?N/}qO0t(]Tϕ_gI³׋E)q]c/eܭvd3!{מ%p,9QnivԿx+ujj >k4w}KP2xKlxj!͉kL@{tNDo~ߔ 2==ȴue#:,eĿl3*ߗ꫔" *3Xz7hnnէG!;dҧrw5/uvTmx}$XR[ưl_d24|_WmȤGϤ5>- ?׼~٥X@Bf.V >}j814dxbEd;@(+ VKjgРntFNΨ23`<)3T,X'o4ʇZ4aڳ9Q5J#OuZ0Xs]< dƊ1좠XE5:V>4i?Q++2y™9tr+0=d#u`O/ bH ("+nVDl}%ŸÛXvF]d4s!SxZ`J}# &oi+#C#Vm1vh$-)ModD X~_Gl,Dۮ,Y,r<0[Զӭ?ȮWyv'V깰U'?sC^}E nrE9ͿC@ Zb[Pf_"Cg8Q3]|[uK:š32* n=T L|NuL%jԧTW.>PC/l܇f_]ZCx_io 0Oyfs*7hCMv0fCgejZz#TMH&^CP3j8ijs] `w AqEF^䟮i# &DDHc;7Zz ꬄVk E@1xO);:H-?IzMĕoW[B0xdU^B,*%7zlsgn_3eFK&/a- }d!thÇss7l=4Ғ7 <V %tn,fE/_ WQ@:m[\`&pg?ryD^hc+uv k/\Lֳ9 [gլqDV-8i ImNv7@NSA&P[+]! rp=HFq$zǓi_ٓP۶өy sG7ټ$rQ'Uw՜Pv5uN9ڥ˫!$^܂7vx5R/ LncoN89ޯͺxx9Z6v4iéGYrRasFVlF kW7/ El3OMA۰d YXIcMqH6ѤCmwQzeiv1*6_/+vs푣F4I+~:9?Htr?w~ڙ!(K)Ƭiٽ[WFW$N Mzu:7CV~[ JSqJ !*Y#oI_i(zcb{V-'>ȯa8l%*:7=o\})~GRtPzo4j/ b>[@4 7>Zڑ5} ~yzI^IiNk|s =GVJւ;_T#Q"|O 'zŤQj 't!ufuИhHMx L-AO\V Z%{ኛҬNg-S;E2]AbJ5$߰ M?B+#4mRW%eǢ{GSy@"E {㎁ ;@7͝1kq?.|4J;^h)%e$e'AAe4P.qFiM!=meZ#d خڇMRlfP?r̴σ%O%08{ V$tFQ/.cK֗!v6'}wd?mzMpAnhZ`vFFN!րGd\uvF;ƽ ZVj/QZ3(̎Om,l\c})*F< m6S\Z ?zd}ɵ [Ѵ{GELJCο`vV}oՃI|I}vζ[4Sn:*e0$:rp~/k/Ҹ"{>i$Y qhp1vkW# TbQ8z 9K>Fe=H,Y, x`+co><[,O 7^V=?oN1[:ՏQ HᎨjhu;m լ`~!z]ƹNBj+C|%O2>@kT7#Ƹd5w##5ߘ'_«NRhgv[bEjy}Qs2,پػ%xǴNM"Ω!J l'??WP/mbIU׻9Зolfmir09D \A?wvv)74$fpW*pB/Vz~dm {t4}T]y缮ZK~,9CV/d"j^0rE;UA羯~ޠa.m579J}6 j&⭁}Lmk-qe+tafgpGsŽUN/!P5ݞO0/o.MOGC׏>}o]Au$ze9Q.nds:F?l(2uȌ9ejA

aҫ$ƶjb+2Cvsc:r|.H-aڎ RbN҃pbpX2^4o5]DL;Hn>+ cק^H,e$}9RˢN1Ћ ѷ.x#1c['z,\Z8-S?&Q__?Fr}@8:MHѣs!34tEN&Oe%c\bfY.)(BflzaΤ<(+5>g| b@{\B߲ v{95?1o'^r#9z(~QHܢt&1Sν&pmCEt&oʛ6/ ~nb_C=HwFqCs\8hۈd%16GJCruώG>"۾(H*ѵ3&6=7+k"*.W Xz"#[W"àE 0ԿV+@S•=}V ?*`܀.W묺Drg805`I!". }+_O c#34ضfWǬ7| pOw=^61\̾ |=K}M Hyhu${_>傩M1}݊By7©~iZF_W_% Y+ ^W)rcxjX<}bAW:< K^N41z{~)x9(|h(0V>}RaÉ isrzfuzߖ"dZUɰVvV*u+o /rf.'`7pHod|5όZ.C-|pb /Qm9uGA]ofznQ߿ ]Tf_uu=H& rUFᬺw5eU"A&KTq<Zz }3J3}>ER^`~~Wgb__lf4cFN|_}6fik]r~u9>m*ɂJm ZOVsְꮌ[RW^YuQ+ggANeaV=`Gs~scS0zaq8H_Ĕ\x&B/5G֕ hO5g5{׶t@t`:sK` fqB$i"CxM::BJIn@y~Ji+4R8x1wbh3wݾU:uk2~ =? P2o2_M|a lXq#ƣ9ڗb%APWEdtC;)%~AmgIpt #wa`+$聬[ pArAsVbHL!M\&SY<:kR(Pȕ%H<-nFHJFzHhF^@qԽ6AeI$^gc[A\ζmineCq/ca❋x-4mixsqp/tests/testthat/test_simulatemixdata.R0000644000176200001440000000026213565526670021171 0ustar liggesuserscontext("simulatemixdata") test_that("simulatemixdata generates matrix with the correct dimensions",{ dat <- simulatemixdata(1000,20) expect_equal(dim(dat$L),c(1000,20)) }) mixsqp/tests/testthat.R0000644000176200001440000000006713565526670014742 0ustar liggesuserslibrary(testthat) library(mixsqp) test_check("mixsqp") mixsqp/src/0000755000176200001440000000000014540624410012362 5ustar liggesusersmixsqp/src/misc.cpp0000644000176200001440000000104313655140024014017 0ustar liggesusers#include "misc.h" using namespace arma; // FUNCTION DEFINITIONS // -------------------- // Scale each column A[,i] by b[i]. void scalecols (mat& A, const vec& b) { unsigned int n = A.n_cols; for (unsigned int i = 0; i < n; i++) A.col(i) *= b[i]; } // Normalize each row of A so that the entries in each row sum to 1. void normalizerows (mat& A) { vec b = sum(A,1); A.each_col() /= b; } // Scale each row of A so that the largest entry in each row is 1. void normalizerowsbymax (mat& A) { vec b = max(A,1); A.each_col() /= b; } mixsqp/src/mixem.cpp0000644000176200001440000000346213655155746014233 0ustar liggesusers#include "mixem.h" #include "misc.h" #include "objective.h" using namespace Rcpp; using namespace arma; // FUNCTION DEFINITIONS // -------------------- // Perform several EM updates of the mixture weights. // // [[Rcpp::depends(RcppArmadillo)]] // [[Rcpp::export]] List mixem_rcpp (const arma::mat& L, const arma::vec& w, const arma::vec& z, const arma::vec& x0, const arma::vec& eps, int numiter, double zerothresholdsolution, bool verbose) { vec obj(numiter); vec nnz(numiter); vec dmax(numiter); int m = L.n_cols; mat P = L; vec x = x0; vec xold(m); vec d(m); for (unsigned int i = 0; i < numiter; i++) { // Store the current estimate of the mixture weights. xold = x; // Run a single EM update. mixem_update(L,w,x,P); // Compute the value of the objective at x. obj(i) = compute_objective(L,w,x,z,eps); // Record the algorithm's progress. nnz(i) = sum(x > zerothresholdsolution); d = abs(x - xold); dmax(i) = d.max(); if (verbose) Rprintf("%4d %+0.9e -- EM -- %4d 1.00e+00 %0.2e -- --\n", i + 1,obj(i),int(nnz(i)),dmax(i)); } return List::create(Named("x") = x, Named("objective") = obj, Named("nnz") = nnz, Named("max.diff") = dmax); } // Perform a single EM update of the mixture weights. void mixem_update (const mat& L, const vec& w, vec& x, mat& P) { double e = 1e-15; // Compute the n x m matrix of posterior mixture assignment // probabilities (L is an n x m matrix). This is the "E step". // // The equivalent R code when e = 0 is // // P <- t(t(L) * x) // P <- P / rowSums(P) // P = L; scalecols(P,x + e); normalizerowsbymax(P); P += e; normalizerows(P); // Update the mixture weights. This is the "M step". x = trans(P) * w; } mixsqp/src/mixem.h0000644000176200001440000000034013655155762013666 0ustar liggesusers#ifndef INCLUDE_MIXEM #define INCLUDE_MIXEM #include // FUNCTION DECLARATIONS // --------------------- void mixem_update (const arma::mat& L, const arma::vec& w, arma::vec& x, arma::mat& P); #endif mixsqp/src/mixsqp.cpp0000644000176200001440000003203513655311773014425 0ustar liggesusers// This is included to suppress the warnings from solve() when the // system is singular or close to singular. #define ARMA_DONT_PRINT_ERRORS #include "objective.h" #include "mixem.h" using namespace Rcpp; using namespace arma; // FUNCTION DECLARATIONS // --------------------- void compute_grad (const mat& L, const mat& U, const mat& V, const vec& w, const vec& x, const vec& e, vec& g, mat& H, mat& Z, bool usesvd); int activesetqp (const mat& H, const vec& g, vec& y, int maxiter, double zerosearchdir, double tol, double ainc); void compute_activeset_searchdir (const mat& H, const vec& y, vec& p, mat& B, double ainc); int backtracking_line_search (double f, const mat& L, const mat& U, const mat& V, const vec& w, const vec& z, const vec& g, const vec& x, const vec& y, const vec& e, bool usesvd, double suffdecr, double beta, double amin, double& a, vec& xnew); // FUNCTION DEFINITIONS // -------------------- // SQP algorithm for computing a maximum-likelihood estimate of a // mixture model. For more information, see the help and comments // accompanying the mixsqp R function and, in particular, see how // mixsqp_rcpp is called inside the mixsqp function. // // [[Rcpp::depends(RcppArmadillo)]] // [[Rcpp::export]] List mixsqp_rcpp (const arma::mat& L, const arma::mat& U, const arma::mat& V, const arma::vec& w, const arma::vec& z, const arma::vec& x0, bool usesvd, bool runem, double convtolsqp, double convtolactiveset, double zerothresholdsolution, double zerothresholdsearchdir, double suffdecr, double stepsizereduce, double minstepsize, double identitycontribincrease, const arma::vec& eps, int maxitersqp, int maxiteractiveset, bool verbose) { // Get the number columns of the data matrix. int m = L.n_cols; // PREPARE DATA STRUCTURES // ----------------------- // Initialize storage for the outputs obj, gmin, nnz, nqp and dmax. vec obj(maxitersqp,fill::zeros); vec gmin(maxitersqp,fill::zeros); vec nnz(maxitersqp,fill::zeros); vec nqp(maxitersqp); vec nls(maxitersqp); vec stepsize(maxitersqp); vec dmax(maxitersqp); nqp.fill(-1); nls.fill(-1); stepsize.fill(-1); dmax.fill(-1); // Initialize the solution. vec x = x0; double status = 1; int i; // Initialize storage for matrices and vectors used in the // computations below. vec xold(m); vec g(m); vec ghat(m); mat H(m,m); uvec j0(m); uvec j1(m); vec y(m); vec d(m); vec xnew(m); mat P = L; mat Z; if (usesvd) Z = L; else Z = U; // Repeat until the convergence criterion is met, or until we reach // the maximum number of (outer loop) iterations. for (i = 0; i < maxitersqp; i++) { // Store the current estimate of the mixture weights. xold = x; // Perform a single EM update. if (runem) mixem_update(L,w,x,P); // Find the zero (j0) and non-zero (j1) co-ordinates. j0 = find(x <= zerothresholdsolution); j1 = find(x > zerothresholdsolution); // Zero any co-ordinates that are below the specified threshold. x(j0).fill(0); // Compute the value of the objective at x. obj(i) = compute_objective(L,U,V,w,x,z,eps,usesvd); // Compute the gradient and Hessian. compute_grad(L,U,V,w,x,eps,g,H,Z,usesvd); // Report on the algorithm's progress. Here we compute: the // smallest gradient value, or, equivalently, dual residual, // corresponding to the nonzero co-ordinates (gmin), which is used // as a convergence criterion; and the number of nonzeros in the // solution (nnz). Note that only the dual residuals (gmin's) // corresponding to the nonzero co-ordinates are relevant. gmin(i) = 1 + g(j1).min(); nnz(i) = sum(x > 0); if (verbose) { if (i == 0) Rprintf("%4d %+0.9e %+0.3e%4d ------ ------ -- --\n", i + 1,obj(i),-gmin(i),int(nnz(i))); else Rprintf("%4d %+0.9e %+0.3e%4d %0.2e %0.2e %3d %3d\n",i + 1,obj(i), -gmin(i),(int) nnz(i),stepsize(i-1),dmax(i-1), (int) nqp(i-1),(int) nls(i-1)); } // Check convergence. Convergence is reached with the maximum dual // residual is small. The negative of "gmin" is also the maximum // dual residual (denoted as "rdual" on p. 609 of Boyd & // Vandenberghe, "Convex Optimization", 2009). if (gmin(i) >= -convtolsqp) { status = 0; i++; break; } // This is also a good point to check for a user interrupt; if the // user requests an interrupt, then an exception is thrown and // control is returned to the R console. checkUserInterrupt(); // Solve the quadratic subproblem to obtain a search direction. ghat = g - H*x + 1; y = x; nqp(i) = (double) activesetqp(H,ghat,y,maxiteractiveset, zerothresholdsearchdir,convtolactiveset, identitycontribincrease); // Extra code used to diagnose line search issues: // // if (verbose) // Rprintf("%0.2e\n",norm(x - y,"inf")); // // Run backtracking line search. nls(i) = (double) backtracking_line_search(obj(i),L,U,V,w,z,g,x,y,eps, usesvd,suffdecr,stepsizereduce, minstepsize,stepsize(i),xnew); // Update the solution, and store the largest change in the // mixture weights. d = abs(xnew - xold); dmax(i) = d.max(); x = xnew; } // CONSTRUCT OUTPUT // ---------------- return List::create(Named("x") = x, Named("status") = status, Named("objective") = obj.head(i), Named("max.rdual") = -gmin.head(i), Named("nnz") = nnz.head(i), Named("stepsize") = stepsize.head(i), Named("max.diff") = dmax.head(i), Named("nqp") = nqp.head(i), Named("nls") = nls.head(i)); } // Return a or b, which ever is smaller. inline double min (double a, double b) { double y; if (a < b) y = a; else y = b; return y; } // Compute the gradient and Hessian of the (unmodified) objective at x. void compute_grad (const mat& L, const mat& U, const mat& V, const vec& w, const vec& x, const vec& e, vec& g, mat& H, mat& Z, bool usesvd) { vec u; if (usesvd) { u = U*(trans(V)*x) + e; g = -V * (trans(U) * (w/u)); Z = U; Z.each_col() %= (sqrt(w)/u); H = V * (trans(Z) * Z) * trans(V); } else { u = L*x + e; g = -trans(L) * (w/u); Z = L; Z.each_col() %= (sqrt(w)/u); H = trans(Z) * Z; } } // Return the largest step size maintaining feasibility (x >= 0) for // the given the search direction (p); inline void feasible_stepsize (const vec& x, const vec& p, int& j, double& a) { uvec i = find(p < 0); a = 1; j = -1; if (!i.is_empty()) { vec t = -x(i)/p(i); j = t.index_min(); if (t(j) < 1) a = t(j); j = i(j); } } // This implements the active-set method from p. 472 of of Nocedal & // Wright, Numerical Optimization, 2nd ed, 2006. int activesetqp (const mat& H, const vec& g, vec& y, int maxiter, double zerosearchdir, double tol, double ainc) { int m = g.n_elem; int k; int iter; double a; vec b(m); vec p(m); vec bs(m); vec ps(m); mat Hs(m,m); mat Bs(m,m); uvec i(m); uvec j(m); bool add_to_working_set; // This vector is used to keep track of the working set; all zero // entries of "t" are co-ordinates belonging to the working set. uvec t = (y > 0); // Run active set method to solve the quadratic subproblem. for (iter = 0; iter < maxiter; iter++) { // Find the co-ordinates inside (j) and outside (i) the working // set. i = find(t != 0); j = find(t == 0); // Make sure the co-ordinates in the working set are set to zero. y(j).fill(0); // Define the smaller quadratic subproblem. Hs = H(i,i); b = g; b(i) += Hs*y(i); bs = b(i); // Solve the quadratic subproblem to obtain a search direction. p.fill(0); compute_activeset_searchdir(Hs,bs,ps,Bs,ainc); p(i) = ps; // Reset the step size. a = 1; add_to_working_set = false; // Check that the search direction is close to zero. if (norm(p,"inf") <= zerosearchdir) { // Calculate b for all co-ordinates. b = g + H*y; // If all the Lagrange multiplers in the working set (that is, // zeroed co-ordinates) are positive, or nearly positive, we // have reached a suitable solution. if (j.is_empty()) { iter++; break; } else if (b(j).min() >= -tol) { iter++; break; } else { // Find a co-ordinate with the smallest multiplier, and remove // it from the working set. k = j(b(j).index_min()); t(k) = 1; } // In this next part, we consider adding a co-ordinate to the // working set (but only if there are two or more non-zero // co-ordinates). } else { // Define the step size. feasible_stepsize(y,p,k,a); if (k >= 0 && a < 1) { // Blocking constraint exists; find and add it to the // working set (but only if there are two or more non-zero // co-ordinates). if (i.n_elem > 1) add_to_working_set = true; } // Move to the new iteration along the search direction. The new // iterate must have only positive entries. y += a*p; j = find(y < 0); y(j).fill(0); // Make sure all co-ordinates in the working set are set to // zero. y(j).fill(0); if (add_to_working_set) { t(k) = 0; y(k) = 0; } } } return iter; } // Get the initial scalar multiplier for the identity matrix based on // examining the diagonal entries of the Hessian. inline double init_hessian_correction (const mat& H, double a0) { double d = H.diag().min(); double a; if (d > a0) a = 0; else a = a0 - d; return a; } // This implements Algorithm 3.3, "Cholesky with added multiple of the // identity", from Nocedal & Wright, 2nd ed, p. 51. void compute_activeset_searchdir (const mat& H, const vec& y, vec& p, mat& B, double ainc) { double a0 = 1e-15; double amax = 1e15; int n = y.n_elem; mat I(n,n,fill::eye); mat R(n,n); // Get the initial scalar multiplier for the identity matrix. double a = init_hessian_correction(H,a0); // Repeat until a modified Hessian is found that is symmetric // positive definite, or until we cannot modify it any longer. while (true) { // Compute the modified Hessian. B = H + a*I; // Attempt to compute the Cholesky factorization of the modified // Hessian. If this fails, increase the contribution of the // identity matrix in the modified Hessian. if (a*ainc > amax) break; else if (chol(R,B)) break; else if (a <= 0) a = a0; else a *= ainc; } // Compute the search direction using the modified Hessian. p = solve(B,-y); } // This implements the backtracking line search algorithm from p. 37 // of Nocedal & Wright, Numerical Optimization, 2nd ed, 2006. // the search direction is given by p = y - x. int backtracking_line_search (double f, const mat& L, const mat& U, const mat& V, const vec& w, const vec& z, const vec& g, const vec& x, const vec& y, const vec& e, bool usesvd, double suffdecr, double beta, double amin, double& a, vec& xnew) { int k; double afeas; double fnew; int nls = 0; // Determine the largest step size maintaining feasibility; if it is // larger than the minimum step size, return the minimum step size // that maintains feasibility of the solution. Otherwise, continue // to backtracking line search. vec p = y - x; feasible_stepsize(x,p,k,afeas); if (afeas <= amin) { a = afeas; xnew = afeas*y + (1 - afeas)*x; } else { // Set the initial step size. a = min(1,afeas); // Iteratively reduce the step size until either (1) we can't reduce // any more (because we have hit the minimum step size constraint), // or (2) the new candidate solution satisfies the "sufficient // decrease" condition. while (true) { xnew = a*y + (1 - a)*x; fnew = compute_objective(L,U,V,w,xnew,z,e,usesvd); nls++; // Check whether the new candidate solution satisfies the // sufficient decrease condition, and remains feasible. If so, // accept this candidate solution. if ((xnew.min() >= 0) && (fnew + sum(xnew) <= f + sum(x) + suffdecr*a*dot(y - x,g + 1))) break; // If we cannot decrease the step size further, terminate the // backtracking line search, and set the step size to be the // minimum step size. else if (a*beta < amin) { // We need to terminate backtracking line search because we have // arrived at the smallest allowable step size. a = amin; xnew = a*y + (1 - a)*x; if (xnew.min() < 0) { a = 0; xnew = x; } break; } // The new candidate does not satisfy the sufficient decrease // condition, so we need to try again with a smaller step size. a *= beta; } } return nls; } mixsqp/src/Makevars0000644000176200001440000000033114540624242014056 0ustar liggesusersPKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) -DARMA_DONT_PRINT_ERRORS \ -DARMA_NO_DEBUG -DARMA_USE_BLAS -DARMA_DONT_USE_OPENMP -DARMA_WARN_LEVEL=1 PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) mixsqp/src/Makevars.win0000644000176200001440000000033114540624246014656 0ustar liggesusersPKG_CXXFLAGS = $(SHLIB_OPENMP_CXXFLAGS) -DARMA_DONT_PRINT_ERRORS \ -DARMA_NO_DEBUG -DARMA_USE_BLAS -DARMA_DONT_USE_OPENMP -DARMA_WARN_LEVEL=1 PKG_LIBS = $(SHLIB_OPENMP_CXXFLAGS) $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS) mixsqp/src/misc.h0000644000176200001440000000041513655140076013475 0ustar liggesusers#ifndef INCLUDE_MISC #define INCLUDE_MISC #include // FUNCTION DECLARATIONS // --------------------- void scalecols (arma::mat& A, const arma::vec& b); void normalizerows (arma::mat& A); void normalizerowsbymax (arma::mat& A); #endif mixsqp/src/objective.h0000644000176200001440000000073013655140572014515 0ustar liggesusers#ifndef INCLUDE_OBJECTIVE #define INCLUDE_OBJECTIVE #include // FUNCTION DECLARATIONS // --------------------- double compute_objective (const arma::mat& L, const arma::vec& w, const arma::vec& x, const arma::vec& z, const arma::vec& e); double compute_objective (const arma::mat& L, const arma::mat& U, const arma::mat& V, const arma::vec& w, const arma::vec& x, const arma::vec& z, const arma::vec& e, bool usesvd); #endif mixsqp/src/objective.cpp0000644000176200001440000000215113655141223015041 0ustar liggesusers#include "objective.h" using namespace Rcpp; using namespace arma; // FUNCTION DECLARATIONS // --------------------- double compute_objective_helper (const vec& u, const vec& w, const vec& z); // FUNCTION DEFINITIONS // -------------------- // Compute the value of the (unmodified) objective at x. double compute_objective (const mat& L, const vec& w, const vec& x, const vec& z, const vec& e) { vec u = L*x + e; return compute_objective_helper(u,w,z); } // Compute the value of the (unmodified) objective at x, using either // the exact matrix L, or a low-rank SVD approximation of L. double compute_objective (const mat& L, const mat& U, const mat& V, const vec& w, const vec& x, const vec& z, const vec& e, bool usesvd) { vec u; if (usesvd) u = U*(trans(V)*x); else u = L*x; u += e; return compute_objective_helper(u,w,z); } // Compute the value of the (unmodified) objective at x, after // precalculating u = L*x + e. double compute_objective_helper (const vec& u, const vec& w, const vec& z) { if (u.min() <= 0) stop("Objective is -Inf"); return -sum(w % (z + log(u))); } mixsqp/src/RcppExports.cpp0000644000176200001440000001120014234475547015370 0ustar liggesusers// Generated by using Rcpp::compileAttributes() -> do not edit by hand // Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 #include #include using namespace Rcpp; #ifdef RCPP_USE_GLOBAL_ROSTREAM Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); #endif // mixem_rcpp List mixem_rcpp(const arma::mat& L, const arma::vec& w, const arma::vec& z, const arma::vec& x0, const arma::vec& eps, int numiter, double zerothresholdsolution, bool verbose); RcppExport SEXP _mixsqp_mixem_rcpp(SEXP LSEXP, SEXP wSEXP, SEXP zSEXP, SEXP x0SEXP, SEXP epsSEXP, SEXP numiterSEXP, SEXP zerothresholdsolutionSEXP, SEXP verboseSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< const arma::mat& >::type L(LSEXP); Rcpp::traits::input_parameter< const arma::vec& >::type w(wSEXP); Rcpp::traits::input_parameter< const arma::vec& >::type z(zSEXP); Rcpp::traits::input_parameter< const arma::vec& >::type x0(x0SEXP); Rcpp::traits::input_parameter< const arma::vec& >::type eps(epsSEXP); Rcpp::traits::input_parameter< int >::type numiter(numiterSEXP); Rcpp::traits::input_parameter< double >::type zerothresholdsolution(zerothresholdsolutionSEXP); Rcpp::traits::input_parameter< bool >::type verbose(verboseSEXP); rcpp_result_gen = Rcpp::wrap(mixem_rcpp(L, w, z, x0, eps, numiter, zerothresholdsolution, verbose)); return rcpp_result_gen; END_RCPP } // mixsqp_rcpp List mixsqp_rcpp(const arma::mat& L, const arma::mat& U, const arma::mat& V, const arma::vec& w, const arma::vec& z, const arma::vec& x0, bool usesvd, bool runem, double convtolsqp, double convtolactiveset, double zerothresholdsolution, double zerothresholdsearchdir, double suffdecr, double stepsizereduce, double minstepsize, double identitycontribincrease, const arma::vec& eps, int maxitersqp, int maxiteractiveset, bool verbose); RcppExport SEXP _mixsqp_mixsqp_rcpp(SEXP LSEXP, SEXP USEXP, SEXP VSEXP, SEXP wSEXP, SEXP zSEXP, SEXP x0SEXP, SEXP usesvdSEXP, SEXP runemSEXP, SEXP convtolsqpSEXP, SEXP convtolactivesetSEXP, SEXP zerothresholdsolutionSEXP, SEXP zerothresholdsearchdirSEXP, SEXP suffdecrSEXP, SEXP stepsizereduceSEXP, SEXP minstepsizeSEXP, SEXP identitycontribincreaseSEXP, SEXP epsSEXP, SEXP maxitersqpSEXP, SEXP maxiteractivesetSEXP, SEXP verboseSEXP) { BEGIN_RCPP Rcpp::RObject rcpp_result_gen; Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< const arma::mat& >::type L(LSEXP); Rcpp::traits::input_parameter< const arma::mat& >::type U(USEXP); Rcpp::traits::input_parameter< const arma::mat& >::type V(VSEXP); Rcpp::traits::input_parameter< const arma::vec& >::type w(wSEXP); Rcpp::traits::input_parameter< const arma::vec& >::type z(zSEXP); Rcpp::traits::input_parameter< const arma::vec& >::type x0(x0SEXP); Rcpp::traits::input_parameter< bool >::type usesvd(usesvdSEXP); Rcpp::traits::input_parameter< bool >::type runem(runemSEXP); Rcpp::traits::input_parameter< double >::type convtolsqp(convtolsqpSEXP); Rcpp::traits::input_parameter< double >::type convtolactiveset(convtolactivesetSEXP); Rcpp::traits::input_parameter< double >::type zerothresholdsolution(zerothresholdsolutionSEXP); Rcpp::traits::input_parameter< double >::type zerothresholdsearchdir(zerothresholdsearchdirSEXP); Rcpp::traits::input_parameter< double >::type suffdecr(suffdecrSEXP); Rcpp::traits::input_parameter< double >::type stepsizereduce(stepsizereduceSEXP); Rcpp::traits::input_parameter< double >::type minstepsize(minstepsizeSEXP); Rcpp::traits::input_parameter< double >::type identitycontribincrease(identitycontribincreaseSEXP); Rcpp::traits::input_parameter< const arma::vec& >::type eps(epsSEXP); Rcpp::traits::input_parameter< int >::type maxitersqp(maxitersqpSEXP); Rcpp::traits::input_parameter< int >::type maxiteractiveset(maxiteractivesetSEXP); Rcpp::traits::input_parameter< bool >::type verbose(verboseSEXP); rcpp_result_gen = Rcpp::wrap(mixsqp_rcpp(L, U, V, w, z, x0, usesvd, runem, convtolsqp, convtolactiveset, zerothresholdsolution, zerothresholdsearchdir, suffdecr, stepsizereduce, minstepsize, identitycontribincrease, eps, maxitersqp, maxiteractiveset, verbose)); return rcpp_result_gen; END_RCPP } static const R_CallMethodDef CallEntries[] = { {"_mixsqp_mixem_rcpp", (DL_FUNC) &_mixsqp_mixem_rcpp, 8}, {"_mixsqp_mixsqp_rcpp", (DL_FUNC) &_mixsqp_mixsqp_rcpp, 20}, {NULL, NULL, 0} }; RcppExport void R_init_mixsqp(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } mixsqp/vignettes/0000755000176200001440000000000014540624410013603 5ustar liggesusersmixsqp/vignettes/mixsqp-intro.Rmd0000644000176200001440000000620214540570527016732 0ustar liggesusers--- title: "Illustration of mixsqp applied to a small data set, and a large one" author: "Youngseok Kim, Peter Carbonetto and Matthew Stephens" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{mixsqp-intro} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE,results = "hold",comment = "#", fig.align = "center",eval = FALSE) ``` In this vignette, we illustrate the use of the sequential quadratic programming (SQP) algorithm implemented in `mixsqp`. ## Environment set-up Load the `mixsqp` package. ```{r load-pkgs, eval=TRUE, message=FALSE} library(mixsqp) ``` Next, initialize the sequence of pseudorandom numbers. ```{r set-seed, eval=TRUE} set.seed(1) ``` ## Generate a small data set We begin with a small example to show how `mixsqp` works. ```{r sim-data-small, eval=TRUE} L <- simulatemixdata(1000,20)$L dim(L) ``` This call to `simulatemixdata` created an $n \times m$ conditional likelihood matrix for a mixture of zero-centered normals, with $n = 1000$ and $m = 20$. By default, `simulatemixdata` normalizes the rows of the likelihood matrix so that the maximum entry in each row is 1. ## Fit mixture model Now we fit the mixture model using the SQP algorithm: ```{r fit-model-mixsqp-small, eval=TRUE} fit.sqp <- mixsqp(L) ``` In this example, the SQP algorithm converged to a solution in a small number of iterations. By default, `mixsqp` outputs information on its progress. It begins by summarizing the optimization problem and the algorithm settings used. (Since we did not change these settings in the `mixsqp` call, all the settings shown here are the default settings.) After that, it outputs, at each iteration, information about the current solution, such as the value of the objective ("objective") and the number of nonzeros ("nnz"). The "max(rdual)" column shows the quantity used to assess convergence. It reports the maximum value of the "dual residual"; the SQP solver terminates when the maximum dual residual is less than `conv.tol`, which by default is $10^{-8}$. In this example, we see that the dual residual shrinks rapidly toward zero. Another useful indicator of convergence is the "max.diff" column---it reports the maximum difference between the solution estimates at two successive iterations. We normally expect these differences to shrink as we approach the solution, which is precisely what we see in this example. This information is also provided in the return value, which we can use, for example, to create a plot of the objective value at each iteration of the SQP algorithm: ```{r plot-sqp-progress, eval=TRUE, fig.height=5, fig.width=7} numiter <- nrow(fit.sqp$progress) plot(1:numiter,fit.sqp$progress$objective,type = "b", pch = 20,lwd = 2,xlab = "SQP iteration", ylab = "objective",xaxp = c(1,numiter,numiter - 1)) ``` ## Session information This next code chunk gives information about the computing environment used to generate the results contained in this vignette, including the version of R and the packages used. ```{r session-info, eval=TRUE} sessionInfo() ``` mixsqp/R/0000755000176200001440000000000014540622461012000 5ustar liggesusersmixsqp/R/tsvd.R0000644000176200001440000000223213614570727013112 0ustar liggesusers# Compute a truncated SVD approximation U*V' to rectangular matrix X, # such that X is an n x m matrix, U is an n x k matrix, and V is an m # x k matrix, where k <= min(n,m). The rank, k, is determined by the # number of singular values surpassing the tolerance, "tol". # # Note that this function will only work if min(dim(X)) is 2 or # greater. # # If irlba fails, the return value is NULL. # tsvd <- function (X, tol) { r <- min(dim(X)) k <- 2 # Iteratively increase the number of singular vectors in the SVD # until it is accurate enough (based on the tolerance setting, # "tol"), or until we hit an upper limit. while (TRUE) { out <- tryCatch(irlba(X,k,tol = 1,svtol = 0.01*tol), error = function (e) NULL, warning = function (e) NULL) if (is.null(out)) return(NULL) else if (k == r) break else if (min(out$d) < tol) break else k <- min(2*k,r) } # Get the truncated SVD. i <- which(out$d > tol) if (length(i) < 2) i <- 1:2 d <- out$d[i] U <- out$u[,i] V <- out$v[,i] U <- scale.cols(U,sqrt(d)) V <- scale.cols(V,sqrt(d)) return(list(U = U,V = V)) } mixsqp/R/zzz.R0000644000176200001440000000027713627754334013000 0ustar liggesusers# This is called when the package is first loaded. .onLoad <- function (libname, pkgname) { options(mixsqp.debug.mode = FALSE) options(mixsqp.debug.file = "mixsqp.RData") invisible() } mixsqp/R/tacks.R0000644000176200001440000000172214540565240013233 0ustar liggesusers#' @name tacks #' #' @title Beckett & Diaconis tack rolling example. #' #' @docType data #' #' @description This data set contains the likelihood matrix and #' weights for the Beckett-Diaconis tacks example, in which the data #' are modeled using a binomial mixture. These data were generated by #' running the "Bmix1" demo from the REBayes package, and saving the #' arguments passed to \code{KWDual}, as well as the (normalized) #' solution returned by the \code{KWDual} call. #' #' @format \code{tacks} is a list with the following elements: #' #' \describe{ #' \item{L}{9 x 299 likelihood matrix.} #' #' \item{w}{Numeric vector of length 9 specifying the weights #' associated with the rows of \code{L}.} #' #' \item{x}{Solution provided by the \code{KWDual} #' solver.} #' } #' #' @keywords data #' #' @examples #' #' # The optimal solution for the tack example is extremely sparse. #' data(tacks) #' plot(tacks$x,type = "l",col = "royalblue") #' NULL mixsqp/R/datasim.R0000644000176200001440000001233413614570727013560 0ustar liggesusers#' @title Create likelihood matrix from simulated data set #' #' @description Simulate a data set, then compute the conditional #' likelihood matrix under a univariate normal likelihood and a #' mixture-of-normals prior. This models a simple nonparametric #' Empirical Bayes method applied to simulated data. #' #' @param n Positive integer specifying the number of samples to #' generate and, consequently, the number of rows of the likelihood #' matrix L. #' #' @param m Integer 2 or greater specifying the number of mixture #' components. #' #' @param simtype The type of data to simulate. If \code{simtype = #' "n"}, simulate \code{n} random numbers from a mixture of three #' univariate normals with mean zero and standard deviation 1, 3 and #' 6. If \code{simtype = "nt"}, simulate from a mixture of three #' univariate normals (with zero mean and standard deviations 1, 3 and #' 5), and a t-distribution with 2 degrees of freedom. #' #' @param log If \code{log = TRUE}, return the #' #' @param normalize.rows If \code{normalize.rows = TRUE}, normalize #' the rows of the likelihood matrix so that the largest entry in each #' row is 1. The maximum-likelihood estimate of the mixture weights #' should be invariant to this normalization, and can improve the #' numerical stability of the optimization. #' #' @return \code{simulatemixdata} returns a list with three list #' elements: #' #' \item{x}{The vector of simulated random numbers (it has length n).} #' #' \item{s}{The standard deviations of the mixture components in the #' mixture-of-normals prior. The rules for selecting the standard #' deviations are based on the \code{autoselect.mixsd} function from #' the \code{ashr} package.} #' #' \item{L}{The n x m conditional likelihood matrix, in which #' individual entries (i,j) of the likelihood matrix are given by the #' normal density function with mean zero and variance \code{1 + #' s[j]^2}. If \code{normalize.rows = TRUE}, the entries in each row #' are normalized such that the larger entry in each row is 1. If #' \code{log = TRUE}, the matrix of log-likelihoods is returned.} #' #' @examples #' #' # Generate the likelihood matrix for a data set with 1,000 samples #' # and a nonparametric Empirical Bayes model with 20 mixture #' # components. #' dat <- simulatemixdata(1000,20) #' #' @importFrom stats rnorm #' @importFrom stats dnorm #' @importFrom stats rt #' #' @export #' simulatemixdata <- function (n, m, simtype = c("n","nt"), log = FALSE, normalize.rows = !log) { # CHECK INPUTS # ------------ # Input argument n should be at least 1, and m should be at least 2. if (!(is.numeric(n) & n >= 1 & is.finite(n) & !missing(n) & round(n) == n & length(n) == 1)) stop("Argument \"n\" should be a finite, positive integer") if (!(is.numeric(m) & m >= 2 & is.finite(m) & !missing(m) & round(m) == m & length(m) == 1)) stop("Argument \"m\" should be a positive integer greater than 1") # Get the choice of data to simulate. if (!is.character(simtype)) stop("Argument \"simtype\" should be a character vector") simtype <- match.arg(simtype) # Input arguments "log" and "normalize.rows" should be TRUE or FALSE. verify.logical.arg(log) verify.logical.arg(normalize.rows) if (log & normalize.rows) stop("Arguments \"log\" and \"normalize.rows\" cannot both be TRUE.") # SIMULATE DATA FROM MIXTURE # -------------------------- # Argument "simtype" controls how the random numbers are generated. k <- floor(n/4) if (simtype == "n") x <- c(rnorm(n - 2*k),3*rnorm(k),6*rnorm(k)) else if (simtype == "nt") x <- c(rnorm(n - 3*k),3*rnorm(k),5*rnorm(k),rt(k,df = 2)) # SELECT VARIANCES FOR MIXTURE MODEL # ---------------------------------- # Try to select a reasonable set of standard deviations that should # be used for the mixture model based on the values of x. This is # code is based on the autoselect.mixsd function from the ashr # package. smin <- 1/10 if (all(x^2 < 1)) smax <- 1 else smax <- 2*sqrt(max(x^2 - 1)) s <- c(0,logspace(smin,smax,m - 1)) # CREATE LIKELIHOOD MATRIX # ------------------------ # Entry (i,j) of the conditional likelihood matrix is equal to # N(x[i]; 0, se[i]^2 + s[j]^2), the normal density at x[i] with zero # mean and variance se[i]^2 + s[j]^2, where se[i] is the standard # error assigned to sample i. Here, all s.e.'s are assumed to be 1. L <- matrix(0,n,m) for (j in 1:m) L[,j] <- dnorm(x,sd = sqrt(1 + s[j]^2),log = log) # NORMALIZE LIKELIHOOD MATRIX # --------------------------- # Normalize the rows of the likelihood matrix so that the largest # entry in each row is 1. if (normalize.rows) L <- normalize.likelihoods(L) # Return the simulated data points (x), the standard deviations # specifying the mixture prior (s), and the conditional likelihood # matrix (L). return(list(x = x,s = s,L = L)) } # Roger Koenker's code for simulating an n x m data matrix. This is # used for testing only. simulate_data_koenker <- function (n, m) { k <- floor(n/4) x <- c(rnorm(n - 2*k),3*rnorm(k),6*rnorm(k)) w <- rep(1/n,n) s <- c(0,logspace(1/10,2*sqrt(max(x^2 - 1)),m - 1)) L <- matrix(0,n,m) for (i in 1:m) L[,i] <- dnorm(x,sd = sqrt(1 + s[i]^2)) return(list(L = L,w = w)) } mixsqp/R/objective.R0000644000176200001440000000513013655140370014074 0ustar liggesusers#' @title Compute objective optimized by mixsqp. #' #' @description See \code{\link{mixsqp}} for a full description of the #' objective function optimized by the mix-SQP algorithm. #' #' @param L Matrix specifying the optimization problem to be solved. #' In the context of mixture-model fitting, \code{L[j,k]} should be #' the value of the kth mixture component density at the jth data #' point. \code{L} should be a numeric matrix with at least two #' columns, with all entries being non-negative and finite (and not #' missing). Further, no column should be entirely zeros. For large #' matrices, it is preferrable that the matrix is stored in #' double-precision; see \code{\link{storage.mode}}. #' #' @param x The point at which the objective is evaluated in #' \code{mixobjective}; see argument \code{x0} in \code{\link{mixsqp}} #' for details. #' #' @param w An optional numeric vector, with one entry for each row of #' \code{L}, specifying the "weights" associated with the rows of #' \code{L}. All weights must be finite, non-negative and not #' missing. Internally, the weights are normalized to sum to 1, #' which does not change the problem, but does change the value of the #' objective function reported. By default, all weights are equal. #' #' @return The value of the objective at \code{x}. If any entry of #' \code{L \%*\% x} is less than or equal to zero, \code{Inf} is #' returned. #' #' @seealso \code{\link{mixsqp}} #' #' @export #' mixobjective <- function (L, x, w = rep(1,nrow(L))) { # CHECK & PROCESS INPUTS # ---------------------- # Check input L and, if necessary, coerce the likelihood matrix to # be in double precision. verify.likelihood.matrix(L) if (storage.mode(L) != "double") storage.mode(L) <- "double" # Check and process the estimate of the solution. x <- verify.estimate(x,L) # Check and process the weights. w <- verify.weights(L,w) # COMPUTE OBJECTIVE VALUE # ----------------------- return(mixobj(L,w,x)) } # Compute the value of the objective at x; arguments L and w specify # the objective, and e is an additional constant that can be set to a # small, positive number (zero by default) to better ensure numerical # stability of the optimization. Argument z is an additional # "normalization factor" used to recover the objective with the # unnormalized L after normalizing the rows of L; setting z[i] to a # value different than zero is equivalent to multiplying the ith row # of L by exp(z[i]). mixobj <- function (L, w, x, z = rep(0,length(w)), e = 0) { y <- drop(L %*% x) + e if (all(y > 0)) return(-sum(w * (z + log(y)))) else return(Inf) } mixsqp/R/RcppExports.R0000644000176200001440000000151514234475547014431 0ustar liggesusers# Generated by using Rcpp::compileAttributes() -> do not edit by hand # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 mixem_rcpp <- function(L, w, z, x0, eps, numiter, zerothresholdsolution, verbose) { .Call('_mixsqp_mixem_rcpp', PACKAGE = 'mixsqp', L, w, z, x0, eps, numiter, zerothresholdsolution, verbose) } mixsqp_rcpp <- function(L, U, V, w, z, x0, usesvd, runem, convtolsqp, convtolactiveset, zerothresholdsolution, zerothresholdsearchdir, suffdecr, stepsizereduce, minstepsize, identitycontribincrease, eps, maxitersqp, maxiteractiveset, verbose) { .Call('_mixsqp_mixsqp_rcpp', PACKAGE = 'mixsqp', L, U, V, w, z, x0, usesvd, runem, convtolsqp, convtolactiveset, zerothresholdsolution, zerothresholdsearchdir, suffdecr, stepsizereduce, minstepsize, identitycontribincrease, eps, maxitersqp, maxiteractiveset, verbose) } mixsqp/R/mixsqp.R0000644000176200001440000006732114540622461013455 0ustar liggesusers# Possible convergence status messages in mixsqp. mixsqp.status.converged <- "converged to optimal solution" mixsqp.status.didnotconverge <- "exceeded maximum number of iterations" mixsqp.status.didnotrun <- "SQP algorithm was not run" #' @title Maximum-likelihood estimation of mixture proportions using SQP #' #' @description The \code{mixsqp} function uses a Sequential Quadratic #' Programming (SQP) algorithm to find the maximum likelihood #' estimates of mixture proportions in a (finite) mixture model. More #' generally, \code{mixsqp} solves the corresponding constrained, #' convex optimization problem, which is given below (see #' \sQuote{Details}). See \sQuote{References} for more details about #' the SQP algorithm. #' #' @details \code{mixsqp} solves the following optimization problem. #' Let \eqn{L} be a matrix with \eqn{n} rows and \eqn{m} columns #' containing only non-negative entries, and let \eqn{w = (w_1, #' \ldots, w_n)} be a vector of non-negative "weights". \code{mixsqp} #' computes the value of vector \eqn{x = (x_1, \ldots, x_m)} #' minimizing the following objective function, \deqn{f(x) = #' -\sum_{j=1}^n w_j \log (\sum_{k=1}^m L_{jk} x_k),} subject to the #' constraint that \eqn{x} lie within the simplex; that is, the #' entries of \eqn{x} are non-negative and sum to 1. Implicitly, #' there is an additional constraint \eqn{L*x > 0} in order to ensure #' that the objective has a finite value. In practice, this constraint #' only needs to be checked for the initial estimate to ensure that it #' holds for all subsequent iterates. #' #' If all weights are equal, solving this optimization problem #' corresponds to finding the maximum-likelihood estimate of the #' mixture proportions \eqn{x} given \eqn{n} independent data points #' drawn from a mixture model with \eqn{m} components. In this case, #' \eqn{L_{jk}} is the likelihood for mixture component \eqn{k} and #' data point \eqn{j}. #' #' The Expectation Maximization (EM) algorithm can be used to solve #' this optimization problem, but it is intolerably slow in many #' interesting cases, and mixsqp is much faster. #' #' A special feature of this optimization problem is that the gradient #' of the objective does not change with re-scaling; for example, if #' all the entries of matrix \code{L} are multiplied by 100, the #' gradient does not change. A practical benefit of this property is #' that the optimization algorithm will behave similarly irrespective #' of the scale of \code{L}; for example, the same value for the #' convergence tolerance \code{convtol.sqp} will have the same effect #' at different scales. #' #' A related feature is that the solution to the optimization problem #' is invariant to rescaling the rows of \code{L}; for example, the #' solution will remain the same after all the entries in a row of #' \code{L} are multiplied by 10. A simple normalization scheme #' divides each row by the largest entry in the row so that all #' entries of \code{L} are at most 1: \code{L <- L / apply(L,1,max)} #' Occasionally, it can be helpful to normalize the rows when some of #' the entries are unusually large or unusually small. This can help #' to avoid numerical overflow or underflow errors. #' #' The SQP algorithm is implemented using the Armadillo C++ linear #' algebra library, which can automatically take advantage of #' multithreaded matrix computations to speed up \code{mixsqp} for #' large \code{L} matrices, but only when R has been configured with a #' multithreaded BLAS/LAPACK library (e.g., OpenBLAS). #' #' A "debugging mode" is provided to aid in reproducing convergence #' failures or other issues. When activated, mixsqp will generate an #' .RData file containing the exact \code{mixsqp} inputs, and will #' stop execution upon convergence failure. To activate the debugging #' mode, run \code{options(mixsqp.debug.mode = TRUE)} prior to calling #' \code{mixsqp}. By default, the output file is \code{mixsqp.RData}; #' the file can be changed by setting the \code{"mixsqp.debug.file"} #' global option. #' #' The \code{control} argument is a list in which any of the #' following named components will override the default optimization #' algorithm settings (as they are defined by #' \code{mixsqp_control_default}): #' #' \describe{ #' #' \item{\code{normalize.rows}}{When \code{normalize.rows = TRUE}, the #' rows of the data matrix \code{L} are automatically scaled so that #' the largest entry in each row is 1. This is the recommended setting #' for better stability of the optimization. When \code{log = TRUE}, #' this setting is ignored becase the rows are already normalized. #' Note that the objective is computed on the original (unnormalized) #' matrix to make the results easier to interpret.} #' #' \item{\code{tol.svd}}{Setting used to determine rank of truncated #' SVD approximation for L. The rank of the truncated singular value #' decomposition is determined by the number of singular values #' surpassing \code{tol.svd}. When \code{tol.svd = 0} or when \code{L} #' has 4 or fewer columns, all computations are performed using full L #' matrix.} #' #' \item{\code{convtol.sqp}}{A small, non-negative number #' specifying the convergence tolerance for SQP algorithm; convergence #' is reached when the maximum dual residual in the Karush-Kuhn-Tucker #' (KKT) optimality conditions is less than or equal to #' \code{convtol.sqp}. Smaller values will result in more stringent #' convergence criteria and more accurate solutions, at the expense of #' greater computation time. Note that changes to this tolerance #' parameter may require respective changes to #' \code{convtol.activeset} and/or \code{zero.threshold.searchdir} to #' obtain reliable convergence.} #' #' \item{\code{convtol.activeset}}{A small, non-negative number #' specifying the convergence tolerance for the active-set #' step. Smaller values will result in higher quality search #' directions for the SQP algorithm but possibly a greater #' per-iteration computational cost. Note that changes to this #' tolerance parameter can affect how reliably the SQP convergence #' criterion is satisfied, as determined by \code{convtol.sqp}.} #' #' \item{\code{zero.threshold.solution}}{A small, non-negative #' number used to determine the "active set"; that is, it determines #' which entries of the solution are exactly zero. Any entries that #' are less than or equal to \code{zero.threshold.solution} are #' considered to be exactly zero. Larger values of #' \code{zero.threshold.solution} may lead to speedups for matrices #' with many columns, at the (slight) risk of prematurely zeroing some #' co-ordinates.} #' #' \item{\code{zero.threshold.searchdir}}{A small, non-negative #' number used to determine when the search direction in the #' active-set step is considered "small enough". Note that changes to #' this tolerance parameter can affect how reliably the SQP #' convergence criterion is satisfied, as determined by #' \code{convtol.sqp}, so choose this parameter carefully.} #' #' \item{\code{suffdecr.linesearch}}{This parameter determines how #' stringent the "sufficient decrease" condition is for accepting a #' step size in the backtracking line search. Larger values will make #' the condition more stringent. This should be a positive number less #' than 1.} #' #' \item{\code{stepsizereduce}}{The multiplicative factor for #' decreasing the step size in the backtracking line search. Smaller #' values will yield a faster backtracking line search at the expense #' of a less fine-grained search. Should be a positive number less than #' 1.} #' #' \item{\code{minstepsize}}{The smallest step size accepted by the #' line search step. Should be a number greater than 0 and at most 1.} #' #' \item{\code{identity.contrib.increase}}{When the Hessian is not #' positive definite, a multiple of the identity is added to the #' Hessian to ensure a unique search direction. The factor for #' increasing the identity contribution in this modified Hessian is #' determined by this control parameter.} #' #' \item{\code{eps}}{A small, non-negative number that is added to the #' terms inside the logarithms to sidestep computing logarithms of #' zero. This prevents numerical problems at the cost of introducing a #' small inaccuracy in the solution. Increasing this number may lead #' to faster convergence but possibly a less accurate solution.} #' #' \item{\code{maxiter.sqp}}{Maximum number of SQP iterations to #' run before reporting a convergence failure; that is, the maximum #' number of quadratic subproblems that will be solved by the #' active-set method.} #' #' \item{\code{maxiter.activeset}}{Maximum number of active-set #' iterations taken to solve each of the quadratic subproblems. If #' \code{NULL}, the maximum number of active-set iterations is set to #' \code{min(20,1 + ncol(L))}.} #' #' \item{\code{numiter.em}}{Number of expectation maximization (EM) #' updates to perform prior to running mix-SQP. Although EM can often #' be slow to converge, this "pre-fitting" step can help to obtain a #' good initial estimate for mix-SQP at a small cost.} #' #' \item{\code{verbose}}{If \code{verbose = TRUE}, the algorithm's #' progress and a summary of the optimization settings are printed to #' the console. The algorithm's progress is displayed in a table with #' one row per SQP (outer loop) iteration, and with the following #' columns: "iter", the (outer loop) SQP iteration; "objective", the #' value of the objective function (see \eqn{f(x)}) at the current #' estimate of the solution, \eqn{x}; "max(rdual)", the maximum "dual #' residual" in the Karush-Kuhn-Tucker (KKT) conditions, which is used #' to monitor convergence (see \code{convtol.sqp}); "nnz", the number #' of non-zero co-ordinates in the current estimate, as determined by #' \code{zero.threshold.solution}; "max.diff", the maximum difference #' in the estimates between two successive iterations; "nqp", the #' number of (inner loop) active-set iterations taken to solve the #' quadratic subproblem; "nls", the number of iterations in the #' backtracking line search.} #' } #' #' @param L Matrix specifying the optimization problem to be solved. #' In the context of mixture-model fitting, \code{L[j,k]} should be #' the value of the kth mixture component density at the jth data #' point. \code{L} should be a numeric matrix with at least two #' columns, with all entries being non-negative and finite (and not #' missing). In some cases, it is easier or more natural to compute #' \code{log(L)}; for example, it is often easier to compute the #' log-likelihood rather than the likelihood. Setting \code{log = TRUE} #' will tell \code{mixsqp} to interpret this input as the logarithm of #' the data matrix. Note that, for large matrices, it is preferrable #' that the matrix is stored in double-precision; see #' \code{\link{storage.mode}}. #' #' @param w An optional numeric vector, with one entry for each row of #' \code{L}, specifying the "weights" associated with the rows of #' \code{L}. All weights must be finite, non-negative and not #' missing. Internally, the weights are normalized to sum to 1, #' which does not change the problem, but does change the value of the #' objective function reported. By default, all weights are equal. #' #' @param x0 An optional numeric vector providing an initial estimate #' of the solution to the optimization problem. It should contain only #' finite, non-missing, non-negative values, and all entries of #' \code{L \%*\% x0} must be greater than zero (to ensure that the #' objective evaluates to a finite value at \code{x0}). The vector #' will be normalized to sum to 1. By default, \code{x0} is the vector #' with all equal values. #' #' @param log When \code{log = TRUE}, the input matrix \code{L} is #' interpreted as containing the logarithm of the data matrix. #' #' @param control A list of parameters controlling the behaviour of #' the optimization algorithm. See \sQuote{Details}. #' #' @return A list object with the following elements: #' #' \item{x}{If the SQP algorithm converges, this is the solution to #' the convex optimization problem. If the algorithm fails to #' converge, it is the best estimate of the solution achieved by the #' algorithm. Note that if the SQP algorithm terminates before #' reaching the solution, \code{x} may not satisfy the equality #' constraint; that is, the entries of \code{x} may not sum to 1.} #' #' \item{value}{The value of the objective function, \eqn{f(x)}, at #' \code{x}.} #' #' \item{grad}{The gradient of the objective function at \code{x}.} #' #' \item{hessian}{The Hessian of the objective function at #' \code{x}. The truncated SVD approximation of L is used to compute #' the Hessian when it is also used for mix-SQP.} #' #' \item{status}{A character string describing the status of the #' algorithm upon termination.} #' #' \item{progress}{A data frame containing more detailed information #' about the algorithm's progress. The data frame has one row per SQP #' iteration. For an explanation of the columns, see the description #' of the \code{verbose} control parameter in \sQuote{Details}. Missing #' values (\code{NA}'s) in the last row indicate that these quantities were #' not computed because convergence was reached before computing #' them. Also note that the storage of these quantities in the #' \code{progress} data frame is slightly different than in the console #' output (when \code{verbose = TRUE}) as the console output shows some #' quantities that were computed after the convergence check in the #' previous iteration.} #' #' @references #' #' Y. Kim, P. Carbonetto, M. Stephens and M. Anitescu (2020). A fast #' algorithm for maximum likelihood estimation of mixture proportions #' using sequential quadratic programming. \emph{Journal of #' Computational and Graphical Statistics} \bold{29}, #' 261-273. \doi{10.1080/10618600.2019.1689985} #' #' @seealso \code{\link{mixobjective}} #' #' @examples #' set.seed(1) #' n <- 1e5 #' m <- 10 #' w <- rep(1,n)/n #' L <- simulatemixdata(n,m)$L #' out.mixsqp <- mixsqp(L,w) #' f <- mixobjective(L,out.mixsqp$x,w) #' print(f,digits = 16) #' #' @useDynLib mixsqp #' #' @importFrom utils modifyList #' @importFrom utils sessionInfo #' @importFrom irlba irlba #' @importFrom Rcpp evalCpp #' #' @export #' mixsqp <- function (L, w = rep(1,nrow(L)), x0 = rep(1,ncol(L)), log = FALSE, control = list()) { # SAVE INPUTS (debug mode only) # ----------------------------- if (getOption("mixsqp.debug.mode")) { out.file <- getOption("mixsqp.debug.file") sinfo <- sessionInfo() message("mixsqp debugging mode is turned on; writing mixsqp inputs and ", "sessionInfo to ",out.file) save(list = c("L","w","x0","log","control","sinfo"),file = out.file) } # CHECK & PROCESS INPUTS # ---------------------- # Check and process the likelihood matrix and, if necessary, coerce # the likelihood matrix to be in double-precision. verify.logical.arg(log) if (!is.matrix(L)) stop("Input argument \"L\" should be a numeric matrix") if (log) L <- normalize.loglikelihoods(L) verify.likelihood.matrix(L) if (storage.mode(L) != "double") storage.mode(L) <- "double" # Get the number of rows (n) and columns (m) of the matrix L. n <- nrow(L) m <- ncol(L) coords <- colnames(L) # Check and process the weights. w <- verify.weights(L,w) # Check and process the initial estimate of the solution. To ensure # that the algorithm reaches the solution, we also require that L*x0 # > 0 hold, which we can check by asking whether the value of the # objective is finite. x0 <- verify.estimate(x0,L) if (is.infinite(mixobj(L,w,x0))) stop(paste("Input \"x0\" is not a valid initial estimate; all entries", "of the matrix-vector product L %*% x0 should be positive")) # Get the optimization algorithm settings. if (!is.list(control)) stop("Argument \"control\" should be a list") control0 <- mixsqp_control_default() if (any(!is.element(names(control),names(control0)))) stop("Argument \"control\" contains unknown parameter names") control <- modifyList(control0,control,keep.null = TRUE) normalize.rows <- control$normalize.rows tol.svd <- control$tol.svd convtol.sqp <- control$convtol.sqp convtol.activeset <- control$convtol.activeset zero.threshold.solution <- control$zero.threshold.solution zero.threshold.searchdir <- control$zero.threshold.searchdir suffdecr.linesearch <- control$suffdecr.linesearch stepsizereduce <- control$stepsizereduce minstepsize <- control$minstepsize identity.contrib.increase <- control$identity.contrib.increase eps <- control$eps maxiter.sqp <- control$maxiter.sqp maxiter.activeset <- control$maxiter.activeset numiter.em <- control$numiter.em verbose <- control$verbose # If the maximum number of active-set iterations is set to NULL, set # it to be equal to 1 + ncol(L), or 100, whichever is smaller. if (is.null(maxiter.activeset)) maxiter.activeset <- min(20,m + 1) # Input arguments "maxiter.sqp" and "maxiter.activeset" should be # scalars that are integers greater than zero. verify.maxiter.arg(maxiter.activeset) verify.maxiter.arg(maxiter.sqp) maxiter.sqp <- as.integer(maxiter.sqp) maxiter.activeset <- as.integer(maxiter.activeset) # Input arguments "convtol.sqp", "convtol.activeset", # "zero.threshold.solution", "zero.threshold.searchdir", # "numiter.em", "identity.contrib.increase", and "eps" should be # non-negative scalars. Additionally, "zero.threshold.solution" # should be less than 1/m. Also, post a warning if eps is within # range of the largest value in one of the rows of the matrix L. verify.nonneg.scalar.arg(tol.svd) verify.nonneg.scalar.arg(convtol.sqp) verify.nonneg.scalar.arg(convtol.activeset) verify.nonneg.scalar.arg(numiter.em) verify.nonneg.scalar.arg(zero.threshold.solution) verify.nonneg.scalar.arg(zero.threshold.searchdir) verify.nonneg.scalar.arg(suffdecr.linesearch) verify.nonneg.scalar.arg(stepsizereduce) verify.nonneg.scalar.arg(minstepsize) verify.nonneg.scalar.arg(identity.contrib.increase) verify.nonneg.scalar.arg(eps) if (!(0 < stepsizereduce & stepsizereduce < 1 & identity.contrib.increase > 0 & suffdecr.linesearch > 0 & minstepsize > 0)) stop(paste("Control parameter \"stepsizereduce\" must be greater than", "0 and less than 1, and \"suffdecr.linesearch\",", "\"identity.contrib.increase\" and \"minstepsize\" must be", "positive")) if (zero.threshold.solution >= 1/m) stop(paste("Behavior of algorithm will be unpredictable if", "zero.threshold > 1/m, where m = ncol(X)")) # Input arguments "normalize.rows" and "verbose" should be TRUE or # FALSE. verify.logical.arg(normalize.rows) verify.logical.arg(verbose) # When all the entries of one or more columns are zero, the mixture # weights associated with those columns are necessarily zero. Here # we handle this situation. nonzero.cols <- which(apply(L,2,max) > 0) if (m == 1 | length(nonzero.cols) == 1) { warning(paste("Only one column of \"L\" has positive entries; this", "corresponds to the trivial solution \"x\" in which", "x[i] = 1 for one column i, and all other entries of", "\"x\" are zero. No optimization algorithm was needed.")) x <- rep(0,m) x[nonzero.cols] <- 1 names(x) <- coords return(list(x = x, status = mixsqp.status.didnotrun, value = mixobj(L,w,x), progress = NULL)) } else if (length(nonzero.cols) < m) { warning(paste("One or more columns of \"L\" are all zeros; solution", "entries associated with these columns are trivially", "zero")) L <- L[,nonzero.cols] x0 <- x0[nonzero.cols] x0 <- x0/sum(x0) m0 <- m m <- length(nonzero.cols) } else m0 <- m # If requested, normalize the rows of L. Note that the rows will # already be normalized when log = TRUE. if (normalize.rows & !log) { out <- normalize.rows(L) L <- out$A z <- log(out$z) rm(out) } else z <- rep(0,n) # Print a brief summary of the analysis, if requested. if (verbose) { cat(sprintf("Running mix-SQP algorithm 0.3-54 on %d x %d matrix\n",n,m)) cat(sprintf("convergence tol. (SQP): %0.1e\n",convtol.sqp)) cat(sprintf("conv. tol. (active-set): %0.1e\n",convtol.activeset)) cat(sprintf("zero threshold (solution): %0.1e\n",zero.threshold.solution)) cat(sprintf("zero thresh. (search dir.): %0.1e\n", zero.threshold.searchdir)) cat(sprintf("l.s. sufficient decrease: %0.1e\n",suffdecr.linesearch)) cat(sprintf("step size reduction factor: %0.1e\n",stepsizereduce)) cat(sprintf("minimum step size: %0.1e\n",minstepsize)) cat(sprintf("max. iter (SQP): %d\n",maxiter.sqp)) cat(sprintf("max. iter (active-set): %d\n",maxiter.activeset)) cat(sprintf("number of EM iterations: %d\n",numiter.em)) } # COMPUTE TRUNCATED SVD # --------------------- U <- matrix(0,n,1) V <- matrix(0,m,1) use.svd <- FALSE if (tol.svd > 0 & m > 4) { if (verbose) cat(sprintf("Computing SVD of %d x %d matrix.\n",n,m)) t1 <- proc.time() out <- tsvd(L,tol.svd) t2 <- proc.time() if (is.null(out)) { if (verbose) cat("Matrix is not low-rank; falling back to full matrix.\n") } else { if (verbose) { cat(sprintf("SVD computation took %0.2f seconds.\n", t2["elapsed"] - t1["elapsed"])) cat(sprintf("Rank of matrix is estimated to be %d.\n",ncol(out$U))) } if (ncol(out$U) < m) { # Only use the SVD of L if it might be worthwhile to do so. U <- out$U V <- out$V rownames(U) <- rownames(L) rownames(V) <- colnames(L) L <- tcrossprod(U,V) use.svd <- TRUE } rm(out) } } # INITIALIZE SOLUTION # ------------------- x <- x0 # Adjust the numerical safeguard to accommodate negative entries in # the SVD reconstruction of L, or L itself (if we ever allow it). if (use.svd) eps <- eps - min(0,min(tcrossprod(U,V))) else eps <- eps - min(0,min(L)) eps <- rep(eps,n) # RUN A FEW ITERATIONS OF EM # -------------------------- # Print the column labels for reporting the algorithm's progress. if (verbose) cat("iter objective max(rdual) nnz stepsize max.diff nqp nls\n") t1 <- proc.time() if (numiter.em > 0) { out <- run.mixem.updates(L,w,x,z,numiter.em,eps,zero.threshold.solution, verbose) x <- out$x progress.em <- out$progress rm(out) } else progress.em <- NULL # SOLVE OPTIMIZATION PROBLEM USING mix-SQP # ---------------------------------------- runem <- TRUE out <- mixsqp_rcpp(L,U,V,w,z,x,use.svd,runem,convtol.sqp,convtol.activeset, zero.threshold.solution,zero.threshold.searchdir, suffdecr.linesearch,stepsizereduce,minstepsize, identity.contrib.increase,eps,maxiter.sqp, maxiter.activeset,verbose) t2 <- proc.time() if (verbose) cat(sprintf("Optimization took %0.2f seconds.\n", t2["elapsed"] - t1["elapsed"])) # Make sure solution sums to 1. x <- drop(out$x) x <- x/sum(x) # Get the algorithm convergence status. The convention is that # status = 0 means that the algorithm has successfully converged to # the optimal solution, and a status = 1 means that the algorithm # reached the maximum number of iterations before converging to a # solution. if (out$status == 0) { status <- mixsqp.status.converged if (verbose) cat("Convergence criteria met---optimal solution found.\n") } else { status <- mixsqp.status.didnotconverge msg <- paste(strwrap(paste("Failed to converge within iterations limit.", "If \"maxiter.sqp\" is small, consider increasing it. Otherwise,", "convergence failure is typically a numerical issue remedied by", "increasing \"eps\" slightly, at the cost of slightly less accurate", "solution; see help(mixsqp). An issue report may also be submitted", "to https://github.com/stephenslab/mixsqp/issues, accompanied by an", ".rds or .RData file containing the mixsqp inputs. If these inputs", "are not accessible, an .RData file containing the inputs can be", "generated by setting options(mixsqp.debug.mode = TRUE) before", "running mixsqp.")),collapse = "\n") if (getOption("mixsqp.debug.mode")) stop(msg) else warning(msg) } # POST-PROCESS RESULT # ------------------- # The last entries of stepsize, max.diff, nqp and nls may not have been # assigned if the SQP algorithm converged successfully (as indicated # by negative values), in which case we should more appropriately # assign them missing values (NA). out$stepsize[out$stepsize < 0] <- NA out$max.diff[out$max.diff < 0] <- NA out$nqp[out$nqp < 0] <- NA out$nls[out$nls < 0] <- NA # Compute the objective, gradient and Hessian at the estimated # solution. e <- control$eps f <- mixobj(L,w,x,z) u <- drop(L %*% x + e) g <- drop((-w/u) %*% L) if (use.svd) H <- V %*% crossprod(sqrt(w)/u * U) %*% t(V) else H <- crossprod(sqrt(w)/u * L) # If necessary, insert the zero mixture weights associated with the # columns of zeros. if (m < m0) { xnz <- x x <- rep(0,m0) x[nonzero.cols] <- xnz } # Label the elements of the solution (x) by the column labels of the # likelihood matrix (L). names(x) <- coords names(g) <- colnames(L) rownames(H) <- colnames(L) colnames(H) <- colnames(L) # CONSTRUCT OUTPUT # ---------------- return(list(x = x, status = status, value = f, grad = g, hessian = H, progress = rbind(progress.em, data.frame(objective = out$objective, max.rdual = out$max.rdual, nnz = out$nnz, stepsize = out$stepsize, max.diff = out$max.diff, nqp = out$nqp, nls = out$nls)))) } #' @rdname mixsqp #' #' @export #' mixsqp_control_default <- function() list(normalize.rows = TRUE, tol.svd = 1e-6, convtol.sqp = 1e-8, convtol.activeset = 1e-10, zero.threshold.solution = 1e-8, zero.threshold.searchdir = 1e-14, suffdecr.linesearch = 0.01, stepsizereduce = 0.75, minstepsize = 1e-8, identity.contrib.increase = 10, eps = 1e-8, maxiter.sqp = 1000, maxiter.activeset = NULL, numiter.em = 10, verbose = TRUE) # This function is used within mixsqp to run several EM updates. run.mixem.updates <- function (L, w, x, z, numiter, eps, zero.threshold, verbose) { out <- mixem_rcpp(L,w,z,x,eps,numiter,zero.threshold,verbose) progress <- data.frame(objective = drop(out$objective), max.rdual = rep(as.numeric(NA),numiter), nnz = drop(out$nnz), stepsize = rep(1,numiter), max.diff = drop(out$max.diff), nqp = rep(as.numeric(NA),numiter), nls = rep(as.numeric(NA),numiter)) return(list(x = drop(out$x),progress = progress)) } mixsqp/R/misc.R0000644000176200001440000001227513614570727013075 0ustar liggesusers# Verify that a logical argument is either TRUE or FALSE. verify.logical.arg <- function (x, arg.name = deparse(substitute(x))) { arg.name <- sprintf("\"%s\"",arg.name) if (!(is.atomic(x) & is.logical(x) & length(x) == 1 & all(!is.na(x)) & all(x == TRUE | x == FALSE))) stop(paste("Argument",arg.name,"should be TRUE or FALSE")) return(TRUE) } # Verify that a non-negative scalar argument is satisfactory. verify.nonneg.scalar.arg <- function (x, arg.name = deparse(substitute(x))) { arg.name <- sprintf("\"%s\"",arg.name) if (!(is.atomic(x) & is.numeric(x) & length(x) == 1 & all(!is.na(x)) & all(is.finite(x)) & all(x >= 0))) stop(paste("Argument",arg.name,"should be a non-negative number")) return(TRUE) } # Verify that a "maxiter" argument---that is, an argument giving the # maximum number of iterations---is valid. It should be a positive, # finite, non-missing integer. verify.maxiter.arg <- function (x, arg.name = deparse(substitute(x))) { arg.name <- sprintf("\"%s\"",arg.name) if (!(is.atomic(x) & is.numeric(x) & length(x) == 1 & all(!is.na(x)) & all(is.finite(x)) & all(x > 0) & all(round(x) == x))) stop(paste("Argument",arg.name,"should be an integer value", "greater than zero")) return(TRUE) } # Verify that the likelihood matrix specifying the optimization # problem is valid. The likelihood matrix should be a numeric matrix # with at least two columns. It is assumed that the input argument is # named "L". If the matrix is not valid, an error is reported; # otherwise, TRUE is returned. verify.likelihood.matrix <- function (L) { msg <- paste("Input argument \"L\" should be a numeric matrix with >= 2", "columns, >= 1 rows, all its entries should be non-negative,", "finite and not NA, and some entries should be positive") if (!is.matrix(L)) stop(msg) else if (!(nrow(L) >= 1 & ncol(L) >= 1 & is.numeric(L))) stop(msg) else if (!(all(L >= 0) & all(is.finite(L)) & !any(is.na(L)) & any(L > 0))) stop(msg) return(TRUE) } # Verify that the vector weights specifying the optimization problem # is valid, then return the normalized weights in double-precision. It # is assumed that the weights argument is named "w", and that the # likelihood matrix argument is named "L". The weights should be a # numeric vector with all non-negative entries, in which the length is # equal to the number of rows of L. Furthermore, the weights should # sum to 1; if not, the weights must be normalized to sum to 1. # # Input L should be the provided likelihood matrix. # # If the weights are not valid, an error is reported; otherwise, the # normalized weights (coerced to double-precision) are returned. verify.weights <- function (L, w) { msg <- paste("Input argument \"w\" should be a numeric vector with", "non-negative, finite and non-missing entries, and with", "one entry per row of L") if (!(is.atomic(w) & is.numeric(w))) stop(msg) else if (!(all(w >= 0) & all(is.finite(w)) & !any(is.na(w)) & length(w) == nrow(L))) stop(msg) storage.mode(w) <- "double" return(w/sum(w)) } # Verify that the estimate of the solution to the optimization problem # is valid, then normalize this estimate if necessary. Argument x # should be a numeric vector with non-negative entries, in which the # length is equal to the number of columns of L. # # Input L should be the provided likelihood matrix. It is assumed that # the argument providing L is named "L". # # If x is not valid, an error is reported; otherwise, the normalized # initial estimate (coerced to double-precision) is returned. verify.estimate <- function (x, L, arg.name = deparse(substitute(x))) { arg.name <- sprintf("\"%s\"",arg.name) msg <- paste("Argument",arg.name,"should be a numeric vector with", "only non-negative, finite and non-missing entries, with one", "entry per column of L") if (!(is.atomic(x) & is.numeric(x))) stop(msg) if (!(all(x >= 0) & all(is.finite(x)) & !any(is.na(x)) & length(x) == ncol(L))) stop(msg) storage.mode(x) <- "double" return(x/sum(x)) } # Generates a vector of n points that are equally spaced on the # logarithmic scale. Note that x and y should be positive numbers. logspace <- function (x, y, n) 2^seq(log2(x),log2(y),length = n) # Scale each column A[,i] by b[i]. scale.cols <- function (A, b) t(t(A) * b) # Normalize the rows of A so that the largest entry in each row is 1. normalize.likelihoods <- function (A) A / apply(A,1,max) # Compute B = exp(A) and normalize the rows of B so that the largest # entry in each row is 1. normalize.loglikelihoods <- function (A) exp(A - apply(A,1,max)) # Normalize the rows of matrix A such that the maximum entry in each # row is 1. The return value is a list containing the normalized # matrix and the vector of normalizing factors. Note that all entries # in the matrix A must be non-negative. normalize.rows <- function (A) { z <- apply(A,1,max) return(list(A = A/z,z = z)) } mixsqp/R/mixsqp-package.R0000644000176200001440000000100613614570727015042 0ustar liggesusers#' mixsqp: Sequential Quadratic Programming for Fast Maximum-Likelihood #' Estimation of Mixture Proportions #' #' Provides optimization algorithms based on sequential quadratic #' programming (SQP) for maximum likelihood estimation of the mixture #' proportions in a finite mixture model where the component densities #' are known. To learn more, visit #' \url{https://github.com/stephenslab/mixsqp}, and see the help for #' function \code{\link{mixsqp}}. #' #' @docType package #' #' @name mixsqp-package #' NULL mixsqp/MD50000644000176200001440000000433314540660612012112 0ustar liggesusers3ba63f95d1d3788b405d2ce1381890bc *DESCRIPTION 25e4857662b0cde3a3e9176b7393b250 *LICENSE ccbb9a155776e065f8933ee409759435 *NAMESPACE 28e2fa3d984a16e636ffc2d7358ac2f2 *R/RcppExports.R 43b8288790289b05b57a25f2a437b6ed *R/datasim.R c0c28eb6ee669d6a657396581a292104 *R/misc.R a625fc32b81fbae5723dfcfc27dd3a21 *R/mixsqp-package.R 28d189f06046aa868025e8b137dc4114 *R/mixsqp.R 83cc43690d61b4f655141627c28b5ab5 *R/objective.R 160841f7c3dc595284ceeb4869e36ba5 *R/tacks.R 58619133f056fc9c59220c4473fc4c47 *R/tsvd.R ef8ba67bdeb1975429bb55d67b24fb23 *R/zzz.R f3ed803bad09f869d8a3d9bf13278c79 *build/partial.rdb 5c3f33ea8eae18a61e326ac34dd988df *build/vignette.rds dd4d6715cf0d5f3a70627ff1fe582cc8 *data/tacks.RData 94db9ec7171b2b36a401b5267eee1048 *inst/CITATION 554297bcb1f7837ccc4378bd51ba58bf *inst/code/test.rmosek.R 4e8a90adfc5bc8b7845ce391769114f5 *inst/doc/mixsqp-intro.R ce6635ee1298f3033c32def4618f091a *inst/doc/mixsqp-intro.Rmd 5a04fadc46b5a6eaa22b9231a3a472b5 *inst/doc/mixsqp-intro.html f50eac9a801aad9111498f0feaa1c939 *man/mixobjective.Rd 35b1db4855b894849ea1021c1bb1256f *man/mixsqp-package.Rd 6cf12b6a16f37cf863fce6d96a50d0c2 *man/mixsqp.Rd dc29373d2f51a8043a01d3b6e8bd949d *man/simulatemixdata.Rd 581402ab78d7a387d2f48ef9b1247502 *man/tacks.Rd 731d052ab5c96a61416e62ca5f1c9e20 *src/Makevars 731d052ab5c96a61416e62ca5f1c9e20 *src/Makevars.win 7982dede7506cfc2283d533f162afb6c *src/RcppExports.cpp f25455145e2e1e22dc305639a8c0cc2b *src/misc.cpp b790799117c1d9029d376993564e1ea2 *src/misc.h abd4f287f908bf99d58b3555296777c2 *src/mixem.cpp 7c5e704ea15d1a0245f8e41c313a2561 *src/mixem.h c6995cc80f697d91d99a03d108eb50e5 *src/mixsqp.cpp c4489180bef302a2e7e5e4730922e937 *src/objective.cpp b696b5275860bbf6f69841ec76296375 *src/objective.h 3207e79b7820a3bd19f9b28c4be29932 *tests/testthat.R 62cdbf4d6cd72c841841e821beec7898 *tests/testthat/ashr.binom.example.RData 9dcf86932a33a2728d772f6231784be8 *tests/testthat/ashr.example.RData 1557fe52b96a0825a5a7498f355c4a04 *tests/testthat/flashr.example.RData 02dc39ca5aea56005fc5ec7c7af74c91 *tests/testthat/smashr.example.RData 3211ad5d2e04199f5f4cc2c62d1f8320 *tests/testthat/test_mixsqp.R 742e92ffb37fc1dece48caad7b68d4b7 *tests/testthat/test_simulatemixdata.R ce6635ee1298f3033c32def4618f091a *vignettes/mixsqp-intro.Rmd mixsqp/inst/0000755000176200001440000000000014540624410012550 5ustar liggesusersmixsqp/inst/doc/0000755000176200001440000000000014540624410013315 5ustar liggesusersmixsqp/inst/doc/mixsqp-intro.R0000644000176200001440000000174214540624407016124 0ustar liggesusers## ----setup, include=FALSE----------------------------------------------------- knitr::opts_chunk$set(collapse = TRUE,results = "hold",comment = "#", fig.align = "center",eval = FALSE) ## ----load-pkgs, eval=TRUE, message=FALSE-------------------------------------- library(mixsqp) ## ----set-seed, eval=TRUE------------------------------------------------------ set.seed(1) ## ----sim-data-small, eval=TRUE------------------------------------------------ L <- simulatemixdata(1000,20)$L dim(L) ## ----fit-model-mixsqp-small, eval=TRUE---------------------------------------- fit.sqp <- mixsqp(L) ## ----plot-sqp-progress, eval=TRUE, fig.height=5, fig.width=7------------------ numiter <- nrow(fit.sqp$progress) plot(1:numiter,fit.sqp$progress$objective,type = "b", pch = 20,lwd = 2,xlab = "SQP iteration", ylab = "objective",xaxp = c(1,numiter,numiter - 1)) ## ----session-info, eval=TRUE-------------------------------------------------- sessionInfo() mixsqp/inst/doc/mixsqp-intro.Rmd0000644000176200001440000000620214540570527016444 0ustar liggesusers--- title: "Illustration of mixsqp applied to a small data set, and a large one" author: "Youngseok Kim, Peter Carbonetto and Matthew Stephens" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{mixsqp-intro} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(collapse = TRUE,results = "hold",comment = "#", fig.align = "center",eval = FALSE) ``` In this vignette, we illustrate the use of the sequential quadratic programming (SQP) algorithm implemented in `mixsqp`. ## Environment set-up Load the `mixsqp` package. ```{r load-pkgs, eval=TRUE, message=FALSE} library(mixsqp) ``` Next, initialize the sequence of pseudorandom numbers. ```{r set-seed, eval=TRUE} set.seed(1) ``` ## Generate a small data set We begin with a small example to show how `mixsqp` works. ```{r sim-data-small, eval=TRUE} L <- simulatemixdata(1000,20)$L dim(L) ``` This call to `simulatemixdata` created an $n \times m$ conditional likelihood matrix for a mixture of zero-centered normals, with $n = 1000$ and $m = 20$. By default, `simulatemixdata` normalizes the rows of the likelihood matrix so that the maximum entry in each row is 1. ## Fit mixture model Now we fit the mixture model using the SQP algorithm: ```{r fit-model-mixsqp-small, eval=TRUE} fit.sqp <- mixsqp(L) ``` In this example, the SQP algorithm converged to a solution in a small number of iterations. By default, `mixsqp` outputs information on its progress. It begins by summarizing the optimization problem and the algorithm settings used. (Since we did not change these settings in the `mixsqp` call, all the settings shown here are the default settings.) After that, it outputs, at each iteration, information about the current solution, such as the value of the objective ("objective") and the number of nonzeros ("nnz"). The "max(rdual)" column shows the quantity used to assess convergence. It reports the maximum value of the "dual residual"; the SQP solver terminates when the maximum dual residual is less than `conv.tol`, which by default is $10^{-8}$. In this example, we see that the dual residual shrinks rapidly toward zero. Another useful indicator of convergence is the "max.diff" column---it reports the maximum difference between the solution estimates at two successive iterations. We normally expect these differences to shrink as we approach the solution, which is precisely what we see in this example. This information is also provided in the return value, which we can use, for example, to create a plot of the objective value at each iteration of the SQP algorithm: ```{r plot-sqp-progress, eval=TRUE, fig.height=5, fig.width=7} numiter <- nrow(fit.sqp$progress) plot(1:numiter,fit.sqp$progress$objective,type = "b", pch = 20,lwd = 2,xlab = "SQP iteration", ylab = "objective",xaxp = c(1,numiter,numiter - 1)) ``` ## Session information This next code chunk gives information about the computing environment used to generate the results contained in this vignette, including the version of R and the packages used. ```{r session-info, eval=TRUE} sessionInfo() ``` mixsqp/inst/doc/mixsqp-intro.html0000644000176200001440000017211614540624410016665 0ustar liggesusers Illustration of mixsqp applied to a small data set, and a large one

Illustration of mixsqp applied to a small data set, and a large one

Youngseok Kim, Peter Carbonetto and Matthew Stephens

2023-12-20

In this vignette, we illustrate the use of the sequential quadratic programming (SQP) algorithm implemented in mixsqp.

Environment set-up

Load the mixsqp package.

library(mixsqp)

Next, initialize the sequence of pseudorandom numbers.

set.seed(1)

Generate a small data set

We begin with a small example to show how mixsqp works.

L <- simulatemixdata(1000,20)$L
dim(L)
# [1] 1000   20

This call to simulatemixdata created an \(n \times m\) conditional likelihood matrix for a mixture of zero-centered normals, with \(n = 1000\) and \(m = 20\). By default, simulatemixdata normalizes the rows of the likelihood matrix so that the maximum entry in each row is 1.

Fit mixture model

Now we fit the mixture model using the SQP algorithm:

fit.sqp <- mixsqp(L)
# Running mix-SQP algorithm 0.3-54 on 1000 x 20 matrix
# convergence tol. (SQP):     1.0e-08
# conv. tol. (active-set):    1.0e-10
# zero threshold (solution):  1.0e-08
# zero thresh. (search dir.): 1.0e-14
# l.s. sufficient decrease:   1.0e-02
# step size reduction factor: 7.5e-01
# minimum step size:          1.0e-08
# max. iter (SQP):            1000
# max. iter (active-set):     20
# number of EM iterations:    10
# Computing SVD of 1000 x 20 matrix.
# Matrix is not low-rank; falling back to full matrix.
# iter        objective max(rdual) nnz stepsize max.diff nqp nls
#    1 +6.825854400e-01  -- EM --   20 1.00e+00 3.43e-02  --  --
#    2 +6.608901094e-01  -- EM --   20 1.00e+00 1.12e-02  --  --
#    3 +6.501637569e-01  -- EM --   20 1.00e+00 8.83e-03  --  --
#    4 +6.441429345e-01  -- EM --   20 1.00e+00 7.64e-03  --  --
#    5 +6.405379612e-01  -- EM --   20 1.00e+00 6.44e-03  --  --
#    6 +6.382623445e-01  -- EM --   20 1.00e+00 5.36e-03  --  --
#    7 +6.367520429e-01  -- EM --   20 1.00e+00 4.46e-03  --  --
#    8 +6.357009493e-01  -- EM --   20 1.00e+00 3.75e-03  --  --
#    9 +6.349366492e-01  -- EM --   20 1.00e+00 3.18e-03  --  --
#   10 +6.343584376e-01  -- EM --   20 1.00e+00 2.73e-03  --  --
#    1 +6.339053898e-01 +1.856e-02  20  ------   ------   --  --
#    2 +6.281996199e-01 +1.384e-03   4 1.00e+00 4.36e-01  20   1
#    3 +6.281978243e-01 +8.849e-07   4 1.00e+00 3.56e-03   2   1
#    4 +6.281978243e-01 -1.816e-08   4 1.00e+00 6.59e-06   2   1
# Optimization took 0.00 seconds.
# Convergence criteria met---optimal solution found.

In this example, the SQP algorithm converged to a solution in a small number of iterations.

By default, mixsqp outputs information on its progress. It begins by summarizing the optimization problem and the algorithm settings used. (Since we did not change these settings in the mixsqp call, all the settings shown here are the default settings.)

After that, it outputs, at each iteration, information about the current solution, such as the value of the objective (“objective”) and the number of nonzeros (“nnz”).

The “max(rdual)” column shows the quantity used to assess convergence. It reports the maximum value of the “dual residual”; the SQP solver terminates when the maximum dual residual is less than conv.tol, which by default is \(10^{-8}\). In this example, we see that the dual residual shrinks rapidly toward zero.

Another useful indicator of convergence is the “max.diff” column—it reports the maximum difference between the solution estimates at two successive iterations. We normally expect these differences to shrink as we approach the solution, which is precisely what we see in this example.

This information is also provided in the return value, which we can use, for example, to create a plot of the objective value at each iteration of the SQP algorithm:

numiter <- nrow(fit.sqp$progress)
plot(1:numiter,fit.sqp$progress$objective,type = "b",
     pch = 20,lwd = 2,xlab = "SQP iteration",
     ylab = "objective",xaxp = c(1,numiter,numiter - 1))

Session information

This next code chunk gives information about the computing environment used to generate the results contained in this vignette, including the version of R and the packages used.

sessionInfo()
# R version 3.6.2 (2019-12-12)
# Platform: x86_64-apple-darwin15.6.0 (64-bit)
# Running under: macOS Catalina 10.15.7
# 
# Matrix products: default
# BLAS:   /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
# LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
# 
# locale:
# [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
# 
# attached base packages:
# [1] stats     graphics  grDevices utils     datasets  methods   base     
# 
# other attached packages:
# [1] mixsqp_0.3-54
# 
# loaded via a namespace (and not attached):
#  [1] Rcpp_1.0.8      lattice_0.20-38 digest_0.6.23   grid_3.6.2     
#  [5] R6_2.4.1        jsonlite_1.7.2  magrittr_2.0.1  evaluate_0.14  
#  [9] highr_0.8       stringi_1.4.3   rlang_1.0.6     cli_3.5.0      
# [13] irlba_2.3.3     jquerylib_0.1.4 Matrix_1.3-4    bslib_0.3.1    
# [17] rmarkdown_2.21  tools_3.6.2     stringr_1.4.0   xfun_0.36      
# [21] yaml_2.2.0      fastmap_1.1.0   compiler_3.6.2  htmltools_0.5.4
# [25] knitr_1.37      sass_0.4.0
mixsqp/inst/CITATION0000644000176200001440000000216014540622255013711 0ustar liggesuserscitHeader("To cite the mixsqp package, please use:") bibentry(bibtype = "Article", title = paste("A fast algorithm for maximum likelihood estimation", "of mixture proportions using sequential quadratic", "programming"), author = c(person("Youngseok Kim"), person("Peter Carbonetto"), person("Matthew Stephens"), person("Mihai Anitescu")), journal = "Journal of Computational and Graphical Statistics", volume = 29, number = 2, pages = "261--273", year = "2020", url = "https://doi.org/10.1080/10618600.2019.1689985", textVersion = paste("Youngseok Kim, Peter Carbonetto, Matthew Stephens and", "Mihai Anitescu (2020). A fast algorithm for maximum", "likelihood estimation of mixture proportions using", "sequential quadratic programming. Journal of Computational", "and Graphical Statistics 29(2), 261-273,", "doi:10.1080/10618600.2019.1689985")) mixsqp/inst/code/0000755000176200001440000000000013565526670013501 5ustar liggesusersmixsqp/inst/code/test.rmosek.R0000644000176200001440000000077113565526670016107 0ustar liggesusers# Here is a small example to test that Rmosek works. If it runs # without error, it means your Rmosek installation is working # properly. library(Rmosek) lo1 <- list() lo1$sense <- "max" lo1$c <- c(3,1,5,1) lo1$A <- Matrix(c(3,1,2,0, 2,1,3,1, 0,2,0,3), nrow=3, byrow=TRUE, sparse=TRUE) lo1$bc <- rbind(blc = c(30,15,-Inf), buc = c(30,Inf,25)) lo1$bx <- rbind(blx = c(0,0,0,0), bux = c(Inf,10,Inf,Inf)) r <- mosek(lo1)