cvxopt-1.1.4/0000755000175000017500000000000011674452555012104 5ustar sonnesonnecvxopt-1.1.4/doc/0000755000175000017500000000000011674452555012651 5ustar sonnesonnecvxopt-1.1.4/doc/Makefile0000644000175000017500000000431311674452555014312 0ustar sonnesonne# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html web pickle htmlhelp latex changes linkcheck help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " pickle to make pickle files (usable by e.g. sphinx-web)" @echo " htmlhelp to make HTML files and a HTML help project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview over all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" clean: -rm -rf build/* html: mkdir -p build/html build/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html @echo @echo "Build finished. The HTML pages are in build/html." pickle: mkdir -p build/pickle build/doctrees $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle @echo @echo "Build finished; now you can process the pickle files or run" @echo " sphinx-web build/pickle" @echo "to start the sphinx-web server." web: pickle htmlhelp: mkdir -p build/htmlhelp build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in build/htmlhelp." latex: mkdir -p build/latex build/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex @echo @echo "Build finished; the LaTeX files are in build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: mkdir -p build/changes build/doctrees $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes @echo @echo "The overview file is in build/changes." linkcheck: mkdir -p build/linkcheck build/doctrees $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in build/linkcheck/output.txt." cvxopt-1.1.4/doc/source/0000755000175000017500000000000011674452555014151 5ustar sonnesonnecvxopt-1.1.4/doc/source/c-api.rst0000644000175000017500000001714011674452555015677 0ustar sonnesonne.. _c-capi: ***** C API ***** The API can be used to extend CVXOPT with interfaces to external C routines and libraries. A C program that creates or manipulates the dense or sparse matrix objects defined in CVXOPT must include the :const:`cvxopt.h` header file in the :const:`src` directory of the distribution. Before the C API can be used in an extension module it must be initialized by calling the macro :cmacro:`import_cvxopt`. As an example we show the module initialization from the :mod:`cvxopt.blas` module, which itself uses the API: .. highlight:: c :: #if PY_MAJOR_VERSION >= 3 static PyModuleDef blas_module = { PyModuleDef_HEAD_INIT, "blas", blas__doc__, -1, blas_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_blas(void) { PyObject *m; if (!(m = PyModule_Create(&blas_module))) return NULL; if (import_cvxopt() < 0) return NULL; return m; } #else PyMODINIT_FUNC initblas(void) { PyObject *m; m = Py_InitModule3("cvxopt.blas", blas_functions, blas__doc__); if (import_cvxopt() < 0) return ; } #endif Dense Matrices ============== As can be seen from the header file :const:`cvxopt.h`, a :class:`matrix` is essentially a structure with four fields. The fields :cmember:`nrows` and :cmember:`ncols` are two integers that specify the dimensions. The :cmember:`id` field controls the type of the matrix and can have values :const:`DOUBLE`, :const:`INT`, and :const:`COMPLEX`. The :cmember:`buffer` field is an array that contains the matrix elements stored contiguously in column-major order. The following C functions can be used to create matrices. .. cfunction:: matrix * Matrix_New(int nrows, int ncols, int id) Returns a :class:`matrix` object of type `id` with `nrows` rows and `ncols` columns. The elements of the matrix are uninitialized. .. cfunction:: matrix * Matrix_NewFromMatrix(matrix *src, int id) Returns a copy of the matrix `src` converted to type `id`. The following type conversions are allowed: :const:`'i'` to :const:`'d'`, :const:`'i'` to :const:`'z'`, and :const:`'d'` to :const:`'z'`. .. cfunction:: matrix * Matrix_NewFromSequence(PyListObject *x, int id) Creates a matrix of type `id` from the Python sequence type `x`. The returned matrix has size ``(len(x), 1)``. The size can be changed by modifying the :cmember:`nrows` and :cmember:`ncols` fields of the returned matrix. To illustrate the creation and manipulation of dense matrices (as well as the Python C API), we show the code for the :func:`cvxopt.uniform` function described in the section :ref:`s-random`. :: PyObject * uniform(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *obj; int i, nrows, ncols = 1; double a = 0, b = 1; char *kwlist[] = {"nrows", "ncols", "a", "b", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist, &nrows, &ncols, &a, &b)) return NULL; if ((nrows<0) || (ncols<0)) { PyErr_SetString(PyExc_TypeError, "dimensions must be non-negative"); return NULL; } if (!(obj = Matrix_New(nrows, ncols, DOUBLE))) return PyErr_NoMemory(); for (i = 0; i < nrows*ncols; i++) MAT_BUFD(obj)[i] = Uniform(a,b); return (PyObject *)obj; } Sparse Matrices =============== Sparse matrices are stored in compressed column storage (CCS) format. For a general `nrows` by `ncols` sparse matrix with `nnz` nonzero entries this means the following. The sparsity pattern and the nonzero values are stored in three fields: :cmember:`values` A :const:`'d'` or :const:`'z'` matrix of size ``(nnz,1)`` with the nonzero entries of the matrix stored columnwise. :cmember:`rowind` An array of integers of length `nnz` containing the row indices of the nonzero entries, stored in the same order as :cmember:`values`. :cmember:`colptr` An array of integers of length `ncols` + 1 with for each column of the matrix the index of the first element in :cmember:`values` from that column. More precisely, ``colptr[0]`` is :const:`0`, and for k = 0, 1, ..., `ncols` - 1, ``colptr[k+1]`` is equal to ``colptr[k]`` plus the number of nonzeros in column `k` of the matrix. Thus, ``colptr[ncols]`` is equal to `nnz`, the number of nonzero entries. For example, for the matrix .. math:: A=\left [\begin{array}{cccc} 1 & 0 & 0 & 5\\ 2 & 0 & 4 & 0\\ 0 & 0 & 0 & 6\\ 3 & 0 & 0 & 0 \end{array}\right] the elements of :cmember:`values`, :cmember:`rowind`, and :cmember:`colptr` are: :cmember:`values`: 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 :cmember:`rowind`: 0, 1,3, 1, 0, 2 :cmember:`colptr`: 0, 3, 3, 4, 6. It is crucial that for each column the row indices in :cmember:`rowind` are sorted; the equivalent representation :cmember:`values`: 3.0, 2.0, 1.0, 4.0, 5.0, 6.0 :cmember:`rowind`: 3, 1, 0, 1, 0, 2 :cmember:`colptr`: 0, 3, 3, 4, 6 is not allowed (and will likely cause the program to crash). The :cmember:`nzmax` field specifies the number of non-zero elements the matrix can store. It is equal to the length of :cmember:`rowind` and :cmember:`values`; this number can be larger that ``colptr[nrows]``, but never less. This field makes it possible to preallocate a certain amount of memory to avoid reallocations if the matrix is constructed sequentially by filling in elements. In general the :cmember:`nzmax` field can safely be ignored, however, since it will always be adjusted automatically as the number of non-zero elements grows. The :cmember:`id` field controls the type of the matrix and can have values :const:`DOUBLE` and :const:`COMPLEX`. Sparse matrices are created using the following functions from the API. .. cfunction:: spmatrix * SpMatrix_New(int nrows, int ncols, int nzmax, int id) Returns a sparse zero matrix with `nrows` rows and `ncols` columns. `nzmax` is the number of elements that will be allocated (the length of the :cmember:`values` and :cmember:`rowind` fields). .. cfunction:: spmatrix * SpMatrix_NewFromMatrix(spmatrix *src, int id) Returns a copy the sparse matrix \var{src}. .. cfunction:: spmatrix * SpMatrix_NewFromIJV(matrix *I, matrix *J, matrix *V, int nrows, int ncols, int nzmax, int id) Creates a sparse matrix with `nrows` rows and `ncols` columns from a triplet description. `I` and `J` must be integer matrices and `V` either a double or complex matrix, or :const:`NULL`. If `V` is :const:`NULL` the values of the entries in the matrix are undefined, otherwise they are specified by `V`. Repeated entries in `V` are summed. The number of allocated elements is given by `nzmax`, which is adjusted if it is smaller than the required amount. We illustrate use of the sparse matrix class by listing the source code for the :attr:`real` method, which returns the real part of a sparse matrix: :: static PyObject * spmatrix_real(spmatrix *self) { if (SP_ID(self) != COMPLEX) return (PyObject *)SpMatrix_NewFromMatrix(self, 0, SP_ID(self)); spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), SP_NNZ(self), DOUBLE); if (!ret) return PyErr_NoMemory(); int i; for (i=0; i < SP_NNZ(self); i++) SP_VALD(ret)[i] = creal(SP_VALZ(self)[i]); memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t)); memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t)); return (PyObject *)ret; } cvxopt-1.1.4/doc/source/normappr.png0000644000175000017500000006052011674452555016520 0ustar sonnesonnePNG  IHDR,d(sBIT|d pHYsaa?i IDATx{tׄRQ.P[]TrbR!xWED ^zNAʢ&%hkAED8 9B$1v}csO&نib.ZB``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[E``[ o.ۭ8 8PM)))ѣխ[7SYYY?iQX~z;V.KTZZŋK.eo߮ɓ'w*..֯khܸq:`iZ]?~\ ̙3sϵ܈#TWW_11Ν;u-跿f͚G KVZ?\ ,hqǏkݺ{|aEF뮻NEEE(p4KvءDЍ7ިΝ;W^={Μ9#Iڿ$)55o|-#:{{o[N~$JvwݾZkuNبz-_\=$iԨQٳ_ra5GƃC` @bb9nI&I{=H֯Vbb%_~*.. GGv m8.p]`8 1b֭[F2vÇ5mڴ 8`;h"#FwբE[nE\&L5{lBUX]cvC m8V1LEeKa0!$-+,<<% XmXmXmXmXm64o7YDGVnԳgOeeeEkuN|r5v 7}vM2 \mqCG` /\uuuJLLԘ1conlIIrrrw^]veJOO3<=zй[gBXl*:w4|@D!tV3,l,l,l,l,l,lVRLLٳGǏWBB\.233uQ ǏGU>}dFyرcР^Z֘1cTYYiQsiVd銍W\B9s7oƌھ}ս{wIREE#(//!5\s}chY+,AXnx X¯#644hƍI۷TTTr!ĉ7oԧO媯Wjj߼9rDϟDcX4w\]5kV󫪪$Inoi:uTXk.P7nxxh+kuQNzCW^$]OVll%I~ۨar\Vqqq@8tRȢ,TYY'O*??_~].N(>>^[LɊDcXکw*--mMT^^o߮-[Gԩӵa=Mk\ZZV|K̜9Sӟ|ˡC4|ptMV]]rrrTSS{nkN4<;B' 0O 0Q4hmۦΝ;뮻RVV:رհT4h>[B' 0WXmXmXmXmXmX%{ĉuW+..Nݺuӷm\o={hJHHRff=jAXpi]׶m+(55U?OtRrرcР^Z֘1cTYYi`iZ]D[رc3fh*//W%IJNN#<e!}pЉ1C4r\744hƍI۷TTTdEX`TSS^xA7o֣>*I*//W}}RSSKIIё#GtH 8J8ٳNԩS'-[L>$Jvs2MSNR^"W00 ,\P?uiٳgdɒl?##o ^W^2%W_}jIRZZbbbL?O(I[Za4KsC_4B(`ب 0@ڷoreeeJNNV\\UA` ;vSN8pbcc 6ַLEEJKK5m4 +a ܹsuWhԨQrݪ҆ vZ=cW9t萆nI٪SNNjjjw^mc͉gvG3@D!tV#`z>_oQw~4YvϞ=Z`vܩX7Nׯ_ ;> ty c:Xl*:w4|@D!tV3,l,l,l,l,l,l[ɓo-g?^ r\ѣG-pKV\O?TWII֮]:Է5vX544@WÇ5fUVVZ3iV4'OԕW^dڹs4p@ $544hƍI۷TTTz"ӧ{np r+55oٔ9rDϟtXBdܹ… %IUUU$i:uTDk&ŋ~z=s6lXȶ75<+kuQ\-]T˖-Ӝ9s|%I~TWW0 \V]\\b-T@[‚n2o׾}+++Srr"U*H=SբExbJOO׆ T[[^QQRM6-ϟI&'{Q$IuM7);;[uuuQMMm9h~:h3DØjiǎv>0_g-X@;wTllƍ|ׯ׈: ty c:E``[E``[E``[E``[E``[E` @mm{1M8Q={TLLrss]vϞ=?~rGFb,ʕ+_hԩ$0;xƎh:|ƌH 8N8ѵ^SNIjժfQ||6nܨݻKnf%''+??_yyyp"4f744hƍI۷TTT"Iyy땚7/%%EG- pKTUUIn<-4}ha iGǂj+kuQ&jy2 C.m6VK'{,ڇ& P||7LɊ2Ѯ?-=$$SXϰIllӵaWTTTӦM:ϼSX09e͛7ٳ:s]ӧO%ISLQ||:Ç릛nRvvꔓݻwXs p gI`gY{מX?1C4F` P~t1IM;a:z+Iڳg,X;w*66VƍS~~sGV#5o_1^ɥC1C4F`h|HFFҶqK{~chY-(gs<\6uzN\G[G1 ЪFjE浜֦N:JGQ)9 "uV-Ý"8y4%_=DwHUkW}>EY`)ml5i4{XWXb5(\EudA`5 X)q[?2;HkO[E,{޿plʾk;=sŬ=o+Dv{hBG?A~Dh7'}p9nV_!}I{ٖvx꫃]?RtD>tKAȰ궅pn[NG]ֲYHo#re8%\ cYmm͛$kذaz嗭.̋~Bl[ѡ=궻C>u-~8jOǺ~˯qp7"q, v[fcxM V'Nݻ\]w^|EZJ/<OΪoK/O9\M-OːT|~-"~m.5EbăE֏h}pb|u M÷Oml~}nGx`5n M6D^Ww}$[oձc4|}݊"WGn;|ȶ<\lHv)g#A#:RC$E㱣9PmRa=FaTTTM>,}z뭷,̞ øO8[DuQG 3…Fא!CH8`EY6qo{^?uDEp'> QUUnUUUE$Q EǥԖLti)Ra"nuMi};v)[:YYo6v~t K%&&6{7%|<^o.J oEsjM0ǴB#`ōeN877i?X4 ܵkoZCCy 7#G ivVYYiaya//iK/5>qD3))/[]?]0ӑivޯڣǴᆴmב]07\`b+oZ.]4h }G\HnN:__oO> iveh4;#ӧ7?XoV.J Mߊ~.о]07\`,6si޽[7p%ݿRSSH8͔)SDefffmБ5d4=twߣ>_I[گ©P]}.0<%fΝ:-\VWW7{WӚJ\'|RFRBBʔQFUUUi~ۺiܯ.U8u~ ]Smٶm[O˸g߾}ncZ~~_jذa넢k„ ZhƏ#G7uI999!yHт~+OGEWXBdZjUjҥZl̙Ӧ$&&oW۴vrUW)--Mv km]߾}%]ط~Nw- }_*}+U8u~jߵwF %D*{nz)))͞-++$ :4z"- '}mב]jj^| ~ג`'ZUշ_SGwQ] 7\`%bO=rssh"-^]N:UoРuiԨQꪫB]nTkiVbkM:U*,,l2}͚5JJJjԗ~Lt~%oES B#@oY4ei盆a'O6weܹ{fllYQQv9sСf߾}כ[n5Njř;vDܦM̂sզa3̂}5vSL1~io?y5ט7X;Lu~7qDv+W4_u7 0ׯ_d>v_]J[ivߵuF ƎkĘa4Yv̙fLLyر&O8aG?2x;kEr7,s6i\= G $ IDAT!C.̌53ۊ]`4;v5~awf.]o|-Cj^mեFk^mב][o1L}3,l,l,l5z4qDS111mLcc򔖖=z(..N\sz!:u>#ߴ-[ܹsjlVVL+ŠC` I 7~IRJJJe*C\XBuwWUUK.[r*ekuNW]]o]a_v/?SNi„ Okm2?11QΝS}}vd^uuᗑbˈjqdΑA;Gsdp:xSNi:v옶nݪC-*Iڷo_~]!૰W_=!b&MR׮]f͚&׬Y#0twFZ%"7oٳguIҁTXX(I2e$n޽{_Jϟ׮]|_y߿ _h/^,ۭ &wQnn~ <8{8 "sѱc$]簠@2 CGUccv-0?sL^b wzǵpˆT=z466k>|@KBy<KzqdΑA;G30y-S1]="- "- "- #0w+@XhI!Z,_S[[{L'NTϞ=fݳgƏ\.effѣ.jڵ'|R  *XR+W_|SJjjرjhhPAAV^Çk̘1lҥK5oNf|bYUUUٳ,Y&f̘۷\ݻw$UTT(99Y<|73g|r-ZHא!C}}00'ąWa8 R+,-hc544hƍI۷TTT䛶e;wNYYYM%4+x JXک\JMM#GUW]=z/p0K;UUUIn<-4u)߲]tQ||߲.˷-{Xl,##o㱠Z]FT"Sbb$o^uu Ð-{9׫k׮~>*..QN*7YӀ}+++Srr$9OUUUC`,tmذA*--մi|&M]j͚5Mf;3Re-aټyΞ=3gH8BIҔ)S\ >\wqUWW]yOۖҢExbnM0Arssuk#|qEcǎIjE?aѣ۷$iϞ=Z`vܩX7Nׯ6}YXB~z,-\P:ujd/(t# PgXmXmXmXmXmX%@;wm&˥.]V]]]٣+!!A.K:zEUB` @YYTSS5k_}ݧ_x<1cƨ=!襗^a%%%In8qB>N>o|Q||6nܨݻKnf%''+??_yyyV`{\a @N$I M'$$(&&F111jhhƍ +Էo_(5ND` ޫ={jΜ9裏TWWO͚5K *//W}}RSSOIIё#Gty [p_wܡ}ϙ3G=$Jvw2MSNR^"S4@8p@iiiJMMՊ+~[O}hĈZn}ڵKִi"W0P|K222TRRzJ#FлᆱEiܸq/I8r„ JOOٳuIeggriܹs`| @1 %@'())I?O4 "%%%޽{ue)==],Ř.x|mXmXmXmXmXmXB`ժUQBB߼={hJHHRff=jAXtq=ӧ h2;vTPPիW3f*++-p4M",==]+TXX3g͘1C۷oWyyw.IPrry嵸]0[pd.1]u7Њ+:bCC6nܨL_X}*--MEEE.pKN8y)//O}_^^zKIIё#GtH 8%@s_Yf5;JvnSNFb. qFa} iG' zzV,T[[x@=z꥚Iui*11QT]]j!kzCK'/~,ڏӇ~̝wީ]~я~MO4I~<6xO (t K;[MҲi۵eC:uRzz6lؠ~cKKKӟԪ]+,!2sLOj=,uM7);;[uuuQMMm9qc1 Ai۶mܹ.eeeӎ;Z +. M> PE``[E``[E``[E``[E``[E` ֭[xԿriz7ݳgƏ\.effѣT 8%+Wԧ~竤Dk׮U]]TZZ[;vTPPիW3f*++- 4Mp'O+l2ܹs8p[Jf̘۷\ݻw$UTT(99YHР7*33V$o߾JKKSQQQ"Oݻu 7HU__TeSRRt?>eB` s窮N .$UUUIn߲n[iԩSpX /siذa!nFF4#@^^eD%KrsstR-[LsMOLL$UWWS]]-0rZvqqqh@XtRC; n Bnn';;ɼ(>>^[LɊT#XSO)77W-ŋ*==]6lPmmozEEJKK5mڴH 8_?&M'xڣF$:tHÇM7ݤl)''G555ڻwﶱn@4رgK٣ hΝոq㔟~tn @1 Ŧ`bL<>x1 HQzXRi947F{j;@Xgg?谚О\#!ђk^W~u=Є4Z|mZ\-,`3_%. ҝكW#]9ؗݯ.ь&gC/\m޷8FSgC-['Wl] =gfz+I|évhomvnhW[[y)))I6l^~eZ]BԳcOb@۷ݭ\n~B6~Kmf׶o^ 4;XlڴiZv,Y-[hx<$l!iЄy0s8=D} {w~BѿLIAv#;)^m)%,6mڤy^}ݒ[oUǎuw+&̈w~{P.M}*PͷipiG}{aFEEEJHHӛLzˢʀ t=_s{^mN]y"['[ Пgܚ kfFא!CH8`EYEeV6B.Unu,FUUU8pt훏]nmv'e^G[5a\vsё޷PQXl_z`vnO/§=n{͡F{z=w$j̴݆p^ᔚ;Z;g5'"w)4X(11٫(վ-j|%RSS2IСC( p KM:U*,,l2}͚5JJJȑ#- pn I&i„ ={>3 0@^W^|Ew.+,aas=ɓ;襗^iVZ%$$Ҏk޽8qjũ[n+WZ]ZTٺu<ﯸ8\.M\ ӧOW~~mۦW^yEO~KZ]^Xr>S͟?_%%%ZvꔖRˋZr M:UO ִiӴvZ-YD[lxz.-jo#pd0=qTX]q*,,ԙ3g.)zu1K 'OԕW^dڹs4p@ "xEEEJHHӛLzˢʢ6|8[qE,6w ͛7OyyyӧD54Р ڼy}QˊjOݻu 7X] ЬkȐ!~WQRRR$I, d8)a67w\]5kեDٳgw$SNZl|AnsU]].\hu)@4p@n7p2ø"t!۶mSLLL~'I*,,ƍyD;_Ypvޭ^{M<q-YĚ`+/_RÆ 8C(Zq8WWX"dZjU۷jkk衇R^TSS#I: pcccխ[Di端_MKKKSLL~?1]$v\-]T˖-Ӝ9sB]^fTWWNq8W%B*{m^?ɓ'|.Kwy6l2ܚoY_, sss}?!,?#0zjlll92IСC* ak0Ŧz&ϡ7MSyyyھ}l٢=zXXa۱c:uSO=\-ZH/N+WwhYFIII9rq:+G`.][o^:uw] NsW\QFvJ6lڵkcqGOӀzꫯ_ C~~#qEő?OϬ.%j^Z/>}gu7~ˋiiiڱcG߱`K N}1a67 CGU߾},qΞ= 5d=M x8+Bx1"- "- "ȪU&gΜ믿ޢJ#CzGէOf%>>^~fRZZ ߷~]N4b *[‚n:ZbE+7ڇ'Nh޼yS>}Z\NzRllj=:uT+[‚0w\]5kV|1bRSSemۦ\РDmڴIEEE^K-htx0/t K?o~{܈:zzI?~uСp wFzTTTcz̿rnܸyɺ|n޼P"aSvvSO9Y1/..Nn[!:FuQ_ ~VX1t2-ɸ\.\.HXS<~h̘1jkk]튊R||$c---lr8AGeoew$,ԤFcs8p@v]gϞXܹsJLLTttt8B,e~򓟨WvUTT'N׏~#EFF*##C~׫[J=F`$k׮_^|g={|A婫KjkkSmmmOg7`^}qfF.p$6ͣԩSUUUO/n:?Uuuu xbRdyF `=EHX jkkxb%$$(::Z1115kJJJz-vZEDDx%%%9`-v%%%׿tu\.mذAYnv=!D/aA`}窯t KEE:::-z̋^`z 2]Dcڝ8nuwwMӱcǴy^tuui̘1RBBrrrjPP%,O=x IRddvޭܞ"##"ͦ*)!!AOVLLm0/(T 2]HX_oQ{{>^{M۷oΝ;{izWz]f)##c FDrr<9rhHX׫;rzǴ~ːEC.pa 4ݺuK_|Eq!a jEFFjʔ)^9r4o޼0FXG!;;[#GܹsfUTT\[lQ||OhժUJLLVuu٣3fhF`zaCYYۧ .C#F̙3~zYFڪu֩VW^fӄ m۶)66}P0/ڰ(a2]HXL0/t "a`Z$,LZx͚5K%%%hѢEPVV ?+))IŪһᆱmذAvYŋZpuҥK? <%,,X?\իWĉr劆.IjhhPbb6mڤ"ۢG % F0z(7,Ap8zݭG*++'Y+==]2"DRHXvݭ6۷Oǎ͛%IW\э7^rr._7o;dR6nܨ7xCݻw+''G,IX/..Nn[3fL,%z'ޮÇ^׵sΠlŊӜNNgPp\r\F1( !!A tEDD_ֆ /IjiiXE6W>|8A | 6,A[nA'Onٳg=;wm@uQuu"##5eEEE)##CYAZr8,~ȑ#5w\ũY*//ז-[zW4{l=SWW ֦ڞjc}nFaz(eeeڷo.\1B3gf͚^h֭GyDŚ8qb̋F!a2]HXL0/t "a`Z$,LǏԤI-áKɓ[v"""< FCIIjjoo޽{JOOYnv=!D/a~hllѣ{Mo5eM6MǏt KEE:::z̋^`z 2]懻I6lN/;7(7*0p$,Aޮ3gh齦wuui̘1RBBrrrjPІ%Hեiiii3gRRRdTUU"}G:}bbb 0? رc߯_]=srrz-+55U˗/Wii}~b iNSN38 (\.\.a J4Paa {nN||{1߿24̋F0 L8ڰNRXXs" ^z%jڱc9rDmmm7o^a޽Ւ%K/z1;wOhժUJLLVuu٣I&ԩS CP% t#aCzzl6{jݺuիWe4aeffj۶mw܀y($,P  IqsEC.pa`Z$,Lir:4ip8tR]C]]]3f3JXiΜ9JIIfSUUGӊ1:DHXB,''~aj*--ճ>u+VxLs:r:ACN"`0'p\r\F1(g?N:rSD~H{r2|Ckpoa1#G֦y 􋪃رc~]&I:<(IZlOhժUJLLVuu٣3fhF> 867?mĉtW;fNZnjkkuUl6M0AڶmbccnB/Q{Iq Cs sL8FQP*p Cs sL80-E{0z`vaCggl٢ŋkԨQPaaahѢEPVV1qA⇦&Sffx.\n8p@eeetϟp XU0aJUZZr:z.IJKKSbbUTT+ KѣGՓH㕞C+Da1`$,!rݸqC)))󒓓ueݼyӀm ̅F#a fIR\\Ǽ8jeF[b4)i@4.cZ-ɗ}Q rrcP"a xIRKKǼl69~q N;+`2?*a!2ydv={c޹s甘h"%D uvvLohhPeeV\i`to=hG-_6c0TQ%Oǎu5IuAIҲedUXXٳgkSWW 4zh=FJY ުY%~Zl@Z~a'NT}}ۿ96Muuu?~$F[n(=#*..ĉ _= hw:9Ͼ.m9_cK{rb)i1s;T 2]HXLfBJ(zؾ@ŷsr$,ަ(G0f*Sc{\~]ɺ'fSFFt)1qtWAw}Aޗ}dlE__S 9y{Sm}vEQrr<9r{,@$,ٴi^}Uuuuiذam6@ZMXBQh5_3Ɂc d%1&a ql?(*aQ#SRjj%T_>5~ a kjҤI5kF*..իWUVVftx@L=h;-1&wԩS;hϞ=R||ϟ7|SiiiFMZP hF}ovi}eSp9uX{,7<(7,ePe!8hCfT 4Ν7C8aexÂ^ì=Z*(R oXBS=ƍ'ݮT;F>F5}=ի}Z]III*..VUU}]hÆ ڵkW#/JJJ_+77W~եtUVV$555D}233%SV\rܹSfϞ-)eth+c~߂;*Y`>sʐبѣGjʔ)6m?nPdKssF;wp{O˗/?31.ŜxX7d at4l0M:U_~?>cC)66VV5}ݺuꫯt)"C_? pV[[ۧcǎiF/uM>PSOxEINN$?ވcN߂^,`ƍz7$Iڽ{rrr dggKFJssL1=..g>cN߂7,aRUUΞ=k|9sF}y ڹs12rرc߯W^yEa>/;E-xx&ӦMSiiO&$$xδtEDD_֓O>c=֡*k$Iڵkvޭ~:A_#+>>Ϸ(---=玹Q~ 0_WAVZZnݺ/>F=yyyA wsKIIҭ[zc9w$iƌFX?YPuu"## {饗TXX۷kǎFVff:;;u^z-7N=Asǚ(7,&#GjܹSss***T^^-[P}ݫ_|QK,Ѳes~رc~]&voTw ˖-n72!cɒ%zGqFutthr\o3@Iy17;G-8ʴo>]pA1bfΜk͚5FݮZ]]x6MQn'Nf\/ͦ:?ׯ+??_Ңx@/V^mth>/s( Ӣ "a`Z$,Li0-EHX "a`Z$,Li0-EHX LwIDAT"a`Z$,Li0-EHX "a`Z$,Li0-EHX "a`Z$,Li0-EHX "a`Z$,Lm RQYIENDB`cvxopt-1.1.4/doc/source/matrices.rst0000644000175000017500000012724011674452555016520 0ustar sonnesonne.. _c-matrices: ************************* Dense and Sparse Matrices ************************* This chapter describes the two CVXOPT matrix types: :class:`matrix ` objects, used for dense matrix computations, and :class:`spmatrix ` objects, used for sparse matrix computations. .. _s-dense-matrices: Dense Matrices ============== A dense matrix is created by calling the function :func:`matrix`. The arguments specify the values of the coefficients, the dimensions, and the type (integer, double, or complex) of the matrix. .. function:: cvxopt.matrix(x[, size[, tc]]) ``size`` is a tuple of length two with the matrix dimensions. The number of rows and/or the number of columns can be zero. ``tc`` stands for type code. The possible values are :const:`'i'`, :const:`'d'`, and :const:`'z'`, for integer, real (double), and complex matrices, respectively. ``x`` can be a number, a sequence of numbers, a dense or sparse matrix, a one- or two-dimensional NumPy array, or a list of lists of matrices and numbers. * If ``x`` is a number (Python integer, float, or complex number), a matrix is created with the dimensions specified by ``size`` and with all the coefficients equal to ``x``. The default value of ``size`` is ``(1,1)``, and the default value of ``tc`` is the type of ``x``. If necessary, the type of ``x`` is converted (from integer to double when used to create a matrix of type :const:`'d'`, and from integer or double to complex when used to create a matrix of type :const:`'z'`). >>> from cvxopt import matrix >>> A = matrix(1, (1,4)) >>> print(A) [ 1 1 1 1] >>> A = matrix(1.0, (1,4)) >>> print(A) [ 1.00e+00 1.00e+00 1.00e+00 1.00e+00] >>> A = matrix(1+1j) >>> print(A) [ 1.00e+00+j1.00e+00] * If ``x`` is a sequence of numbers (list, tuple, array, :mod:`array` array, ...), then the numbers are interpreted as the coefficients of a matrix in column-major order. The length of ``x`` must be equal to the product of ``size[0]`` and ``size[1]``. If ``size`` is not specified, a matrix with one column is created. If ``tc`` is not specified, it is determined from the elements of ``x`` (and if that is impossible, for example because ``x`` is an empty list, a value :const:`'i'` is used). Type conversion takes place as for scalar ``x``. The following example shows several ways to define the same integer matrix. >>> A = matrix([0, 1, 2, 3], (2,2)) >>> A = matrix((0, 1, 2, 3), (2,2)) >>> A = matrix(range(4), (2,2)) >>> from array import array >>> A = matrix(array('i', [0,1,2,3]), (2,2)) >>> print(A) [ 0 2] [ 1 3] In Python 2.7 the following also works. >>> A = matrix(xrange(4), (2,2)) * If ``x`` is a dense or sparse matrix, then the coefficients of ``x`` are copied, in column-major order, to a new matrix of the given size. The total number of elements in the new matrix (the product of ``size[0]`` and ``size[1]``) must be the same as the product of the dimensions of ``x``. If ``size`` is not specified, the dimensions of ``x`` are used. The default value of ``tc`` is the type of ``x``. Type conversion takes place when the type of ``x`` differs from ``tc``, in a similar way as for scalar ``x``. >>> A = matrix([1., 2., 3., 4., 5., 6.], (2,3)) >>> print(A) [ 1.00e+00 3.00e+00 5.00e+00] [ 2.00e+00 4.00e+00 6.00e+00] >>> B = matrix(A, (3,2)) >>> print(B) [ 1.00e+00 4.00e+00] [ 2.00e+00 5.00e+00] [ 3.00e+00 6.00e+00] >>> C = matrix(B, tc='z') >>> print(C) [ 1.00e+00-j0.00e+00 4.00e+00-j0.00e+00] [ 2.00e+00-j0.00e+00 5.00e+00-j0.00e+00] [ 3.00e+00-j0.00e+00 6.00e+00-j0.00e+00] In Python 2.7 NumPy arrays can be converted to matrices. >>> from numpy import array >>> x = array([[1., 2., 3.], [4., 5., 6.]]) >>> x array([[ 1. 2. 3.] [ 4. 5. 6.]]) >>> print(matrix(x)) [ 1.00e+00 2.00e+00 3.00e+00] [ 4.00e+00 5.00e+00 6.00e+00] * If ``x`` is a list of lists of dense or sparse matrices and numbers (Python integer, float, or complex), then each element of ``x`` is interpreted as a block-column stored in column-major order. If ``size`` is not specified, the block-columns are juxtaposed to obtain a matrix with ``len(x)`` block-columns. If ``size`` is specified, then the matrix with ``len(x)`` block-columns is resized by copying its elements in column-major order into a matrix of the dimensions given by ``size``. If ``tc`` is not specified, it is determined from the elements of ``x`` (and if that is impossible, for example because ``x`` is a list of empty lists, a value :const:`'i'` is used). The same rules for type conversion apply as for scalar ``x``. >>> print(matrix([[1., 2.], [3., 4.], [5., 6.]])) [ 1.00e+00 3.00e+00 5.00e+00] [ 2.00e+00 4.00e+00 6.00e+00] >>> A1 = matrix([1, 2], (2,1)) >>> B1 = matrix([6, 7, 8, 9, 10, 11], (2,3)) >>> B2 = matrix([12, 13, 14, 15, 16, 17], (2,3)) >>> B3 = matrix([18, 19, 20], (1,3)) >>> C = matrix([[A1, 3.0, 4.0, 5.0], [B1, B2, B3]]) >>> print(C) [ 1.00e+00 6.00e+00 8.00e+00 1.00e+01] [ 2.00e+00 7.00e+00 9.00e+00 1.10e+01] [ 3.00e+00 1.20e+01 1.40e+01 1.60e+01] [ 4.00e+00 1.30e+01 1.50e+01 1.70e+01] [ 5.00e+00 1.80e+01 1.90e+01 2.00e+01] A matrix with a single block-column can be represented by a single list (i.e., if ``x`` is a list of lists, and has length one, then the argument ``x`` can be replaced by ``x[0]``). >>> D = matrix([B1, B2, B3]) >>> print(D) [ 6 8 10] [ 7 9 11] [ 12 14 16] [ 13 15 17] [ 18 19 20] .. _s-sparse-matrices: Sparse Matrices =============== A general :class:`spmatrix ` object can be thought of as a *triplet description* of a sparse matrix, i.e., a list of entries of the matrix, with for each entry the value, row index, and column index. Entries that are not included in the list are assumed to be zero. For example, the sparse matrix .. math:: A = \left[ \begin{array}{rrrrr} 0 & 2 & 0 & 0 & 3 \\ 2 & 0 & 0 & 0 & 0 \\ -1 & -2 & 0 & 4 & 0 \\ 0 & 0 & 1 & 0 & 0 \end{array} \right] has the triplet description .. math:: (2,1,0), \qquad (-1,2,0), \qquad (2,0,1), \qquad (-2,2,1), \qquad (1,3,2), \qquad (4,2,3), \qquad (3,0,4). The list may include entries with a zero value, so triplet descriptions are not necessarily unique. The list .. math:: (2,1,0), \qquad (-1,2,0), \qquad (0,3,0), \qquad (2,0,1), \qquad (-2,2,1), \qquad (1,3,2), \qquad (4,2,3), \qquad (3,0,4) is another triplet description of the same matrix. An :class:`spmatrix` object corresponds to a particular triplet description of a sparse matrix. We will refer to the entries in the triplet description as the *nonzero entries* of the object, even though they may have a numerical value zero. Three functions are provided to create sparse matrices. The first, :func:`spmatrix`, constructs a sparse matrix from a triplet description. .. function:: cvxopt.spmatrix(x, I, J[, size[, tc]]) ``I`` and ``J`` are sequences of integers (lists, tuples, :mod:`array` arrays, ...) or integer matrices (:class:`matrix ` objects with typecode :const:`'i'`), containing the row and column indices of the nonzero entries. The lengths of ``I`` and ``J`` must be equal. If they are matrices, they are treated as lists of indices stored in column-major order, i.e., as lists ``list(I)``, respectively, ``list(J)``. ``size`` is a tuple of nonnegative integers with the row and column dimensions of the matrix. The ``size`` argument is only needed when creating a matrix with a zero last row or last column. If ``size`` is not specified, it is determined from ``I`` and ``J``: the default value for ``size[0]`` is ``max(I)+1`` if ``I`` is nonempty and zero otherwise. The default value for ``size[1]`` is ``max(J)+1`` if ``J`` is nonempty and zero otherwise. ``tc`` is the typecode, :const:`'d'` or :const:`'z'`, for double and complex matrices, respectively. Integer sparse matrices are not implemented. ``x`` can be a number, a sequence of numbers, or a dense matrix. This argument specifies the numerical values of the nonzero entries. - If ``x`` is a number (Python integer, float, or complex), a matrix is created with the sparsity pattern defined by ``I`` and ``J``, and nonzero entries initialized to the value of ``x``. The default value of ``tc`` is :const:`'d'` if ``x`` is integer or float, and :const:`'z'` if ``x`` is complex. The following code creates a 4 by 4 sparse identity matrix. >>> from cvxopt import spmatrix >>> A = spmatrix(1.0, range(4), range(4)) >>> print(A) [ 1.00e+00 0 0 0 ] [ 0 1.00e+00 0 0 ] [ 0 0 1.00e+00 0 ] [ 0 0 0 1.00e+00] - If ``x`` is a sequence of numbers, a sparse matrix is created with the entries of ``x`` copied to the entries indexed by ``I`` and ``J``. The list ``x`` must have the same length as ``I`` and ``J``. The default value of ``tc`` is determined from the elements of ``x``: :const:`'d'` if ``x`` contains integers and floating-point numbers or if ``x`` is an empty list, and :const:`'z'` if ``x`` contains at least one complex number. >>> A = spmatrix([2,-1,2,-2,1,4,3], [1,2,0,2,3,2,0], [0,0,1,1,2,3,4]) >>> print(A) [ 0 2.00e+00 0 0 3.00e+00] [ 2.00e+00 0 0 0 0 ] [-1.00e+00 -2.00e+00 0 4.00e+00 0 ] [ 0 0 1.00e+00 0 0 ] - If ``x`` is a dense matrix, a sparse matrix is created with all the entries of ``x`` copied, in column-major order, to the entries indexed by ``I`` and ``J``. The matrix ``x`` must have the same length as ``I`` and ``J``. The default value of ``tc`` is :const:`'d'` if ``x`` is an :const:`'i'` or :const:`'d'` matrix, and :const:`'z'` otherwise. If ``I`` and ``J`` contain repeated entries, the corresponding values of the coefficients are added. The function :func:`sparse` constructs a sparse matrix from a block-matrix description. .. function:: cvxopt.sparse(x[, tc]) ``tc`` is the typecode, :const:`'d'` or :const:`'z'`, for double and complex matrices, respectively. ``x`` can be a :class:`matrix`, :class:`spmatrix`, or a list of lists of matrices (:class:`matrix` or :class:`spmatrix` objects) and numbers (Python integer, float, or complex). * If ``x`` is a :class:`matrix` or :class:`spmatrix` object, then a sparse matrix of the same size and the same numerical value is created. Numerical zeros in ``x`` are treated as structural zeros and removed from the triplet description of the new sparse matrix. * If ``x`` is a list of lists of matrices (:class:`matrix` or :class:`spmatrix` objects) and numbers (Python integer, float, or complex) then each element of ``x`` is interpreted as a (block-)column matrix stored in colum-major order, and a block-matrix is constructed by juxtaposing the ``len(x)`` block-columns (as in :func:`matrix `). Numerical zeros are removed from the triplet description of the new matrix. >>> from cvxopt import matrix, spmatrix, sparse >>> A = matrix([[1., 2., 0.], [2., 1., 2.], [0., 2., 1.]]) >>> print(A) [ 1.00e+00 2.00e+00 0.00e+00] [ 2.00e+00 1.00e+00 2.00e+00] [ 0.00e+00 2.00e+00 1.00e+00] >>> B = spmatrix([], [], [], (3,3)) >>> print(B) [0 0 0] [0 0 0] [0 0 0] >>> C = spmatrix([3, 4, 5], [0, 1, 2], [0, 1, 2]) >>> print(C) [ 3.00e+00 0 0 ] [ 0 4.00e+00 0 ] [ 0 0 5.00e+00] >>> D = sparse([[A, B], [B, C]]) >>> print(D) [ 1.00e+00 2.00e+00 0 0 0 0 ] [ 2.00e+00 1.00e+00 2.00e+00 0 0 0 ] [ 0 2.00e+00 1.00e+00 0 0 0 ] [ 0 0 0 3.00e+00 0 0 ] [ 0 0 0 0 4.00e+00 0 ] [ 0 0 0 0 0 5.00e+00] A matrix with a single block-column can be represented by a single list. >>> D = sparse([A, C]) >>> print(D) [ 1.00e+00 2.00e+00 0 ] [ 2.00e+00 1.00e+00 2.00e+00] [ 0 2.00e+00 1.00e+00] [ 3.00e+00 0 0 ] [ 0 4.00e+00 0 ] [ 0 0 5.00e+00] The function :func:`spdiag` constructs a block-diagonal sparse matrix from a list of matrices. .. function:: cvxopt.spdiag(x) ``x`` is a dense or sparse matrix with a single row or column, or a list of square dense or sparse matrices or scalars. If ``x`` is a matrix, a sparse diagonal matrix is returned with the entries of ``x`` on its diagonal. If ``x`` is list, a sparse block-diagonal matrix is returned with the elements in the list as its diagonal blocks. >>> from cvxopt import matrix, spmatrix, spdiag >>> A = 3.0 >>> B = matrix([[1,-2],[-2,1]]) >>> C = spmatrix([1,1,1,1,1],[0,1,2,0,0,],[0,0,0,1,2]) >>> D = spdiag([A, B, C]) >>> print(D) [ 3.00e+00 0 0 0 0 0 ] [ 0 1.00e+00 -2.00e+00 0 0 0 ] [ 0 -2.00e+00 1.00e+00 0 0 0 ] [ 0 0 0 1.00e+00 1.00e+00 1.00e+00] [ 0 0 0 1.00e+00 0 0 ] [ 0 0 0 1.00e+00 0 0 ] .. _s-arithmetic: Arithmetic Operations ===================== The following table lists the arithmetic operations defined for dense and sparse matrices. In the table ``A`` and ``B`` are dense or sparse matrices of compatible dimensions, ``c`` is a scalar (a Python number or a dense 1 by 1 matrix), ``D`` is a dense matrix, and ``e`` is a Python number. +------------------------------------+-------------------------+ | Unary plus/minus | ``+A, -A`` | +------------------------------------+-------------------------+ | Addition | ``A + B, A + c, c + A`` | +------------------------------------+-------------------------+ | Subtraction | ``A - B, A - c, c - A`` | +------------------------------------+-------------------------+ | Matrix multiplication | ``A * B`` | +------------------------------------+-------------------------+ | Scalar multiplication and division | ``c * A, A * c, A / c`` | +------------------------------------+-------------------------+ | Remainder after division | ``D % c`` | +------------------------------------+-------------------------+ | Elementwise exponentiation | ``D**e`` | +------------------------------------+-------------------------+ The type of the result of these operations generally follows the Python conventions. For example, if ``A`` and ``c`` are integer, then in Python 2 the division ``A/c`` is interpreted as integer division and results in a type :const:`'i'` matrix, while in Python 3 it is interpreted as standard divison and results in a type :const:`'d'` matrix. An exception to the Python conventions is elementwise exponentiation: if ``D`` is an integer matrix and ``e`` is an integer number than ``D**e`` is a matrix of type :const:`'d'`. Addition, subtraction, and matrix multiplication with two matrix operands result in a sparse matrix if both matrices are sparse, and in a dense matrix otherwise. The result of a scalar multiplication or division is dense if ``A`` is dense, and sparse if ``A`` is sparse. Postmultiplying a matrix with a number ``c`` means the same as premultiplying, i.e., scalar multiplication. Dividing a matrix by ``c`` means dividing all its entries by ``c``. If ``c`` in the expressions ``A+c``, ``c+A``, ``A-c``, ``c-A`` is a number, then it is interpreted as a dense matrix with the same dimensions as ``A``, type given by the type of ``c``, and all its entries equal to ``c``. If ``c`` is a 1 by 1 dense matrix and ``A`` is not 1 by 1, then ``c`` is interpreted as a dense matrix with the same size of ``A`` and all entries equal to ``c[0]``. If ``c`` is a 1 by 1 dense matrix, then, if possible, the products ``c*A`` and ``A*c`` are interpreted as matrix-matrix products. If the product cannot be interpreted as a matrix-matrix product because the dimensions of ``A`` are incompatible, then the product is interpreted as the scalar multiplication with ``c[0]``. The division ``A/c`` and remainder ``A%c`` with ``c`` a 1 by 1 matrix are always interpreted as ``A/c[0]``, resp., ``A%c[0]``. The following in-place operations are also defined, but only if they do not change the type (sparse or dense, integer, real, or complex) of the matrix ``A``. These in-place operations do not return a new matrix but modify the existing object ``A``. +---------------------------------------------+--------------------+ | In-place addition | ``A += B, A += c`` | +---------------------------------------------+--------------------+ | In-place subtraction | ``A -= B, A -= c`` | +---------------------------------------------+--------------------+ | In-place scalar multiplication and division | ``A *= c, A /= c`` | +---------------------------------------------+--------------------+ | In-place remainder | ``A %= c`` | +---------------------------------------------+--------------------+ For example, if ``A`` has typecode :const:`'i'`, then ``A += B`` is allowed if ``B`` has typecode :const:`'i'`. It is not allowed if ``B`` has typecode :const:`'d'` or :const:`'z'` because the addition ``A+B`` results in a :const:`'d'` or :const:`'z'` matrix and therefore cannot be assigned to ``A`` without changing its type. As another example, if ``A`` is a sparse matrix, then ``A += 1.0`` is not allowed because the operation ``A = A + 1.0`` results in a dense matrix, so it cannot be assigned to ``A`` without changing its type. In-place matrix-matrix products are not allowed. (Except when ``c`` is a 1 by 1 dense matrix, in which case ``A *= c`` is interpreted as the scalar product ``A *= c[0]``.) In-place remainder is only defined for dense ``A``. It is important to know when a matrix operation creates a new object. The following rules apply. * A simple assignment (``A = B``) is given the standard Python interpretation, i.e., it assigns to the variable ``A`` a reference (or pointer) to the object referenced by ``B``. >>> B = matrix([[1.,2.], [3.,4.]]) >>> print(B) [ 1.00e+00 3.00e+00] [ 2.00e+00 4.00e+00] >>> A = B >>> A[0,0] = -1 >>> print(B) # modifying A[0,0] also modified B[0,0] [-1.00e+00 3.00e+00] [ 2.00e+00 4.00e+00] * The regular (i.e., not in-place) arithmetic operations always return new objects. >>> B = matrix([[1.,2.], [3.,4.]]) >>> A = +B >>> A[0,0] = -1 >>> print(B) # modifying A[0,0] does not modify B[0,0] [ 1.00e+00 3.00e+00] [ 2.00e+00 4.00e+00] * The in-place operations directly modify the coefficients of the existing matrix object and do not create a new object. >>> B = matrix([[1.,2.], [3.,4.]]) >>> A = B >>> A *= 2 >>> print(B) # in-place operation also changed B [ 2.00e+00 6.00e+00] [ 4.00e+00 8.00e+00] >>> A = 2*A >>> print(B) # regular operation creates a new A, so does not change B [ 2.00e+00 6.00e+00] [ 4.00e+00 8.00e+00] .. _s-indexing: Indexing and Slicing ==================== Matrices can be indexed using one or two arguments. In single-argument indexing of a matrix ``A``, the index runs from ``-len(A)`` to ``len(A)-1``, and is interpreted as an index in the one-dimensional array of coefficients of ``A`` in column-major order. Negative indices have the standard Python interpretation: for negative ``k``, ``A[k]`` is the same element as ``A[len(A) + k]``. Four different types of one-argument indexing are implemented. 1. The index can be a single integer. This returns a number, e.g., ``A[0]`` is the first element of ``A``. 2. The index can be an integer matrix. This returns a column matrix: the command ``A[matrix([0,1,2,3])]`` returns the 4 by 1 matrix consisting of the first four elements of ``A``. The size of the index matrix is ignored: ``A[matrix([0,1,2,3], (2,2))]`` returns the same 4 by 1 matrix. 3. The index can be a list of integers. This returns a column matrix, e.g., ``A[[0,1,2,3]]`` is the 4 by 1 matrix consisting of elements 0, 1, 2, 3 of ``A``. 4. The index can be a Python slice. This returns a matrix with one column (possibly 0 by 1, or 1 by 1). For example, ``A[::2]`` is the column matrix defined by taking every other element of ``A``, stored in column-major order. ``A[0:0]`` is a matrix with size (0,1). Thus, single-argument indexing returns a scalar (if the index is an integer), or a matrix with one column. This is consistent with the interpretation that single-argument indexing accesses the matrix in column-major order. Note that an index list or an index matrix are equivalent, but they are both useful, especially when we perform operations on index sets. For example, if ``I`` and ``J`` are lists then ``I+J`` is the concatenated list, and ``2*I`` is ``I`` repeated twice. If they are matrices, these operations are interpreted as arithmetic operations. For large index sets, indexing with integer matrices is also faster than indexing with lists. The following example illustrates one-argument indexing. >>> from cvxopt import matrix, spmatrix >>> A = matrix(range(16), (4,4), 'd') >>> print(A) [ 0.00e+00 4.00e+00 8.00e+00 1.20e+01] [ 1.00e+00 5.00e+00 9.00e+00 1.30e+01] [ 2.00e+00 6.00e+00 1.00e+01 1.40e+01] [ 3.00e+00 7.00e+00 1.10e+01 1.50e+01] >>> A[4] 4.0 >>> I = matrix([0, 5, 10, 15]) >>> print(A[I]) # the diagonal [ 0.00e+00] [ 5.00e+00] [ 1.00e+01] [ 1.50e+01] >>> I = [0,2]; J = [1,3] >>> print(A[2*I+J]) # duplicate I and append J [ 0.00e+00] [ 2.00e+00] [ 0.00e+00] [ 2.00e+00] [ 1.00e+00] [ 3.00e+00] >>> I = matrix([0, 2]); J = matrix([1, 3]) >>> print(A[2*I+J]) # multiply I by 2 and add J [ 1.00e+00] [ 7.00e+00] >>> print(A[4::4]) # get every fourth element skipping the first four [ 4.00e+00] [ 8.00e+00] [ 1.20e+01] In two-argument indexing the arguments can be any combinations of the four types listed above. The first argument indexes the rows of the matrix and the second argument indexes the columns. If both indices are scalars, then a scalar is returned. In all other cases, a matrix is returned. We continue the example. >>> print(A[:,1]) [ 4.00e+00] [ 5.00e+00] [ 6.00e+00] [ 7.00e+00] >>> J = matrix([0, 2]) >>> print(A[J,J]) [ 0.00e+00 8.00e+00] [ 2.00e+00 1.00e+01] >>> print(A[:2, -2:]) [ 8.00e+00 1.20e+01] [ 9.00e+00 1.30e+01] >>> A = spmatrix([0,2,-1,2,-2,1], [0,1,2,0,2,1], [0,0,0,1,1,2]) >>> print(A[:, [0,1]]) [ 0.00e+00 2.00e+00] [ 2.00e+00 0 ] [-1.00e+00 -2.00e+00] >>> B = spmatrix([0,2*1j,0,-2], [1,2,1,2], [0,0,1,1,]) >>> print(B[-2:,-2:]) [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00] [ 0.00e+00+j2.00e+00 -2.00e+00-j0.00e+00] Expressions of the form ``A[I]`` or ``A[I,J]`` can also appear on the left-hand side of an assignment. The right-hand side must be a scalar (i.e., a number or a 1 by 1 dense matrix), a sequence of numbers, or a dense or sparse matrix. If the right-hand side is a scalar, it is interpreted as a dense matrix with identical entries and the dimensions of the left-hand side. If the right-hand side is a sequence of numbers (list, tuple, :mod:`array` array, range object, ...) its values are interpreted as the coefficients of a dense matrix in column-major order. If the right-hand side is a matrix (:class:`matrix` or :class:`spmatrix`), it must have the same size as the left-hand side. Sparse matrices are converted to dense in the assignment to a dense matrix. Indexed assignments are only allowed if they do not change the type of the matrix. For example, if ``A`` is a matrix with type :const:`'d'`, then ``A[I] = B`` is only permitted if ``B`` is an integer, a float, or a matrix of type :const:`'i'` or :const:`'d'`. If ``A`` is an integer matrix, then ``A[I] = B`` is only permitted if ``B`` is an integer or an integer matrix. The following examples illustrate indexed assignment. >>> A = matrix(range(16), (4,4)) >>> A[::2,::2] = matrix([[-1, -2], [-3, -4]]) >>> print(A) [ -1 4 -3 12] [ 1 5 9 13] [ -2 6 -4 14] [ 3 7 11 15] >>> A[::5] += 1 >>> print(A) [ 0 4 -3 12] [ 1 6 9 13] [ -2 6 -3 14] [ 3 7 11 16] >>> A[0,:] = -1, 1, -1, 1 >>> print(A) [ -1 1 -1 1] [ 1 6 9 13] [ -2 6 -3 14] [ 3 7 11 16] >>> A[2:,2:] = range(4) >>> print(A) [ -1 1 -1 1] [ 1 6 9 13] [ -2 6 0 2] [ 3 7 1 3] >>> A = spmatrix([0,2,-1,2,-2,1], [0,1,2,0,2,1], [0,0,0,1,1,2]) >>> print(A) [ 0.00e+00 2.00e+00 0 ] [ 2.00e+00 0 1.00e+00] [-1.00e+00 -2.00e+00 0 ] >>> C = spmatrix([10,-20,30], [0,2,1], [0,0,1]) >>> print(C) [ 1.00e+01 0 ] [ 0 3.00e+01] [-2.00e+01 0 ] >>> A[:,0] = C[:,0] >>> print(A) [ 1.00e+01 2.00e+00 0 ] [ 0 0 1.00e+00] [-2.00e+01 -2.00e+00 0 ] >>> D = matrix(range(6), (3,2)) >>> A[:,0] = D[:,0] >>> print(A) [ 0.00e+00 2.00e+00 0 ] [ 1.00e+00 0 1.00e+00] [ 2.00e+00 -2.00e+00 0 ] >>> A[:,0] = 1 >>> print(A) [ 1.00e+00 2.00e+00 0 ] [ 1.00e+00 0 1.00e+00] [ 1.00e+00 -2.00e+00 0 ] >>> A[:,0] = 0 >>> print(A) [ 0.00e+00 2.00e+00 0 ] [ 0.00e+00 0 1.00e+00] [ 0.00e+00 -2.00e+00 0 ] Attributes and Methods ====================== Dense and sparse matrices have the following attributes. .. attribute:: size A tuple with the dimensions of the matrix. The size of the matrix can be changed by altering this attribute, as long as the number of elements in the matrix remains unchanged. .. attribute:: typecode A character, either :const:`'i'`, :const:`'d'`, or :const:`'z'`, for integer, real, and complex matrices, respectively. A read-only attribute. .. method:: trans() Returns the transpose of the matrix as a new matrix. One can also use ``A.T`` instead of ``A.trans()``. .. method:: ctrans() Returns the conjugate transpose of the matrix as a new matrix. One can also use ``A.H`` instead of ``A.ctrans()``. .. method:: real() For complex matrices, returns the real part as a real matrix. For integer and real matrices, returns a copy of the matrix. .. method:: imag For complex matrices, returns the imaginary part as a real matrix. For integer and real matrices, returns an integer or real zero matrix. In addition, sparse matrices have the following attributes. .. attribute:: V A single-column dense matrix containing the numerical values of the nonzero entries in column-major order. Making an assignment to the attribute is an efficient way of changing the values of the sparse matrix, without changing the sparsity pattern. When the attribute :attr:`V` is read, a *copy* of :attr:`V` is returned, as a new dense matrix. This implies, for example, that an indexed assignment ``A.V[I] = B`` does not work, or at least cannot be used to modify ``A``. Instead the attribute :attr:`V` will be read and returned as a new matrix; then the elements of this new matrix are modified. .. attribute:: I A single-column integer dense matrix with the row indices of the entries in :attr:`V`. A read-only attribute. .. attribute:: J A single-column integer dense matrix with the column indices of the entries in :attr:`V`. A read-only attribute. .. attribute:: CCS A triplet (column pointers, row indices, values) with the compressed-column-storage representation of the matrix. A read-only attribute. This attribute can be used to export sparse matrices to other packages such as MOSEK. The next example below illustrates assignments to :attr:`V`. >>> from cvxopt import spmatrix, matrix >>> A = spmatrix(range(5), [0,1,1,2,2], [0,0,1,1,2]) >>> print(A) [ 0.00e+00 0 0 ] [ 1.00e+00 2.00e+00 0 ] [ 0 3.00e+00 4.00e+00] >>> B = spmatrix(A.V, A.J, A.I, (4,4)) # transpose and add a zero row and column >>> print(B) [ 0.00e+00 1.00e+00 0 0 ] [ 0 2.00e+00 3.00e+00 0 ] [ 0 0 4.00e+00 0 ] [ 0 0 0 0 ] >>> B.V = matrix([1., 7., 8., 6., 4.]) # assign new values to nonzero entries >>> print(B) [ 1.00e+00 7.00e+00 0 0 ] [ 0 8.00e+00 6.00e+00 0 ] [ 0 0 4.00e+00 0 ] [ 0 0 0 0 ] The following attributes and methods are defined for dense matrices. .. method:: tofile(f) Writes the elements of the matrix in column-major order to a binary file ``f``. .. method:: fromfile(f) Reads the contents of a binary file ``f`` into the matrix object. The last two methods are illustrated in the following examples. >>> from cvxopt import matrix, spmatrix >>> A = matrix([[1.,2.,3.], [4.,5.,6.]]) >>> print(A) [ 1.00e+00 4.00e+00] [ 2.00e+00 5.00e+00] [ 3.00e+00 6.00e+00] >>> f = open('mat.bin','wb') >>> A.tofile(f) >>> f.close() >>> B = matrix(0.0, (2,3)) >>> f = open('mat.bin','rb') >>> B.fromfile(f) >>> f.close() >>> print(B) [ 1.00e+00 3.00e+00 5.00e+00] [ 2.00e+00 4.00e+00 6.00e+00] >>> A = spmatrix(range(5), [0,1,1,2,2], [0,0,1,1,2]) >>> f = open('test.bin','wb') >>> A.V.tofile(f) >>> A.I.tofile(f) >>> A.J.tofile(f) >>> f.close() >>> f = open('test.bin','rb') >>> V = matrix(0.0, (5,1)); V.fromfile(f) >>> I = matrix(0, (5,1)); I.fromfile(f) >>> J = matrix(0, (5,1)); J.fromfile(f) >>> B = spmatrix(V, I, J) >>> print(B) [ 0.00e+00 0 0 ] [ 1.00e+00 2.00e+00 0 ] [ 0 3.00e+00 4.00e+00] Note that the :func:`dump` and :func:`load` functions in the :mod:`pickle` module offer a convenient alternative for writing matrices to files and reading matrices from files. Built-In Functions ================== Many Python built-in functions and operations can be used with matrix arguments. We list some useful examples. .. function:: len(x) If ``x`` is a dense matrix, returns the product of the number of rows and the number of columns. If ``x`` is a sparse matrix, returns the number of nonzero entries. .. function:: bool([x]) Returns :const:`False` if ``x`` is a zero matrix and :const:`True` otherwise. .. function:: max(x) If ``x`` is a dense matrix, returns the maximum element of ``x``. If ``x`` is a sparse, returns the maximum nonzero element of ``x``. .. function:: min(x) If ``x`` is a dense matrix, returns the minimum element of ``x``. If ``x`` is a sparse matrix, returns the minimum nonzero element of ``x``. .. function:: abs(x) Returns a matrix with the absolute values of the elements of ``x``. .. function:: sum(x[, start = 0.0]) Returns the sum of ``start`` and the elements of ``x``. Dense and sparse matrices can be used as arguments to the :func:`list`, :func:`tuple`, :func:`zip`, :func:`map`, and :func:`filter` functions described in the Python Library Reference. However, one should note that when used with sparse matrix arguments, these functions only consider the nonzero entries. For example, ``list(A)`` and ``tuple(A)`` construct a list, respectively a tuple, from the elements of ``A`` if ``A`` is dense, and of the nonzero elements of ``A`` if ``A`` is sparse. ``list(zip(A, B, ...))`` returns a list of tuples, with the i-th tuple containing the i-th elements (or nonzero elements) of ``A``, ``B``, .... >>> from cvxopt import matrix >>> A = matrix([[-11., -5., -20.], [-6., 0., 7.]]) >>> B = matrix(range(6), (3,2)) >>> list(A) [-11.0, -5.0, -20.0, -6.0, 0.0, 7.0] >>> tuple(B) (0, 1, 2, 3, 4, 5) >>> list(zip(A, B)) [(-11.0, 0), (-5.0, 1), (-20.0, 2), (-6.0, 3), (0.0, 4), (7.0, 5)] ``list(map(f, A))``, where ``f`` is a function and ``A`` is a dense matrix, returns a list constructed by applying ``f`` to each element of ``A``. If ``A`` is sparse, the function ``f`` is applied to each nonzero element of ``A``. Multiple arguments can be provided, for example, as in ``map(f, A, B)``, if ``f`` is a function with two arguments. In the following example, we return an integer 0-1 matrix with the result of an elementwise comparison. >>> A = matrix([ [0.5, -0.1, 2.0], [1.5, 0.2, -0.1], [0.3, 1.0, 0.0]]) >>> print(A) [ 5.00e-01 1.50e+00 3.00e-01] [-1.00e-01 2.00e-01 1.00e+00] [ 2.00e+00 -1.00e-01 0.00e+00] >>> print(matrix(list(map(lambda x: 0 <= x <= 1, A), A.size))) [ 1 0 1] [ 0 1 1] [ 0 0 1] ``list(filter(f, A))``, where ``f`` is a function and ``A`` is a matrix, returns a list containing the elements of ``A`` (or nonzero elements of ``A`` is ``A`` is sparse) for which ``f`` is true. >>> A = matrix([[5, -4, 10, -7], [-1, -5, -6, 2], [6, 1, 5, 2], [-1, 2, -3, -7]]) >>> print(A) [ 5 -1 6 -1] [ -4 -5 1 2] [ 10 -6 5 -3] [ -7 2 2 -7] >>> list(filter(lambda x: x%2, A)) # list of odd elements in A [5, -7, -1, -5, 1, 5, -1, -3, -7] >>> list(filter(lambda x: -2 < x < 3, A)) # list of elements between -2 and 3 [-1, 2, 1, 2, -1, 2] It is also possible to iterate over matrix elements, as illustrated in the following example. >>> A = matrix([[5, -3], [9, 11]]) >>> for x in A: print(max(x,0)) ... 5 0 9 11 >>> [max(x,0) for x in A] [5, 0, 9, 11] The expression ``x in A`` returns :const:`True` if an element of ``A`` (or a nonzero element of ``A`` if ``A`` is sparse) is equal to ``x`` and :const:`False` otherwise. Other Matrix Functions ====================== The following functions can be imported from CVXOPT. .. function:: cvxopt.sqrt(x) The elementwise square root of a dense matrix ``x``. The result is returned as a real matrix if ``x`` is an integer or real matrix and as a complex matrix if ``x`` is a complex matrix. Raises an exception when ``x`` is an integer or real matrix with negative elements. As an example we take the elementwise square root of the sparse matrix .. math:: A = \left[ \begin{array}{rrrrr} 0 & 2 & 0 & 0 & 3 \\ 2 & 0 & 0 & 0 & 0 \\ 1 & 2 & 0 & 4 & 0 \\ 0 & 0 & 1 & 0 & 0 \end{array} \right] >>> from cvxopt import spmatrix, sqrt >>> A = spmatrix([2,1,2,2,1,3,4], [1,2,0,2,3,0,2], [0,0,1,1,2,3,3]) >>> B = spmatrix(sqrt(A.V), A.I, A.J) >>> print(B) [ 0 1.41e+00 0 1.73e+00] [ 1.41e+00 0 0 0 ] [ 1.00e+00 1.41e+00 0 2.00e+00] [ 0 0 1.00e+00 0 ] .. function:: cvxopt.sin(x) The sine function applied elementwise to a dense matrix ``x``. The result is returned as a real matrix if ``x`` is an integer or real matrix and as a complex matrix otherwise. .. function:: cvxopt.cos(x) The cosine function applied elementwise to a dense matrix ``x``. The result is returned as a real matrix if ``x`` is an integer or real matrix and as a complex matrix otherwise. .. function:: cvxopt.exp(x) The exponential function applied elementwise to a dense matrix ``x``. The result is returned as a real matrix if ``x`` is an integer or real matrix and as a complex matrix otherwise. .. function:: cvxopt.log(x) The natural logarithm applied elementwise to a dense matrix ``x``. The result is returned as a real matrix if ``x`` is an integer or real matrix and as a complex matrix otherwise. Raises an exception when ``x`` is an integer or real matrix with nonpositive elements, or a complex matrix with zero elements. .. function:: cvxopt.mul(x0, [, x1 [, x2 ...]]) If the arguments are dense or sparse matrices of the same size, returns the elementwise product of its arguments. The result is a sparse matrix if one or more of its arguments is sparse, and a dense matrix otherwise. If the arguments include scalars, a scalar product with the scalar is made. (A 1 by 1 dense matrix is treated as a scalar if the dimensions of the other arguments are not all 1 by 1.) :func:`mul` can also be called with an iterable (list, tuple, range object, or generator) as its single argument, if the iterable generates a list of dense or sparse matrices or scalars. >>> from cvxopt import matrix, spmatrix, mul >>> A = matrix([[1.0, 2.0], [3.0, 4.0]]) >>> B = spmatrix([2.0, 3.0], [0, 1], [0, 1]) >>> print(mul(A, B, -1.0)) [-2.00e+00 0 ] [ 0 -1.20e+01] >>> print(mul( matrix([k, k+1]) for k in [1,2,3] )) [ 6] [ 24] .. function:: cvxopt.div(x, y) Returns the elementwise division of ``x`` by ``y``. ``x`` is a dense or sparse matrix, or a scalar (Python number of 1 by 1 dense matrix). ``y`` is a dense matrix or a scalar. .. function:: cvxopt.max(x0[, x1[, x2 ...]]) When called with a single matrix argument, returns the maximum of the elements of the matrix (including the zero entries, if the matrix is sparse). When called with multiple arguments, the arguments must be matrices of the same size, or scalars, and the elementwise maximum is returned. A 1 by 1 dense matrix is treated as a scalar if the other arguments are not all 1 by 1. If one of the arguments is scalar, and the other arguments are not all 1 by 1, then the scalar argument is interpreted as a dense matrix with all its entries equal to the scalar. The result is a sparse matrix if all its arguments are sparse matrices. The result is a number if all its arguments are numbers. The result is a dense matrix if at least one of the arguments is a dense matrix. :func:`max ` can also be called with an iterable (list, tuple, range object, or generator) as its single argument, if the iterable generates a list of dense or sparse matrices or scalars. >>> from cvxopt import matrix, spmatrix, max >>> A = spmatrix([2, -3], [0, 1], [0, 1]) >>> print(max(A, -A, 1)) [ 2.00e+00 1.00e+00] [ 1.00e+00 3.00e+00] It is important to note the difference between this :func:`max ` and the built-in :func:`max`, explained in the previous section. >>> from cvxopt import spmatrix >>> A = spmatrix([-1.0, -2.0], [0,1], [0,1]) >>> max(A) # built-in max of a sparse matrix takes maximum over nonzero elements -1.0 >>> max(A, -1.5) Traceback (most recent call last): File "", line 1, in NotImplementedError: matrix comparison not implemented >>> from cvxopt import max >>> max(A) # cvxopt.max takes maximum over all the elements 0.0 >>> print(max(A, -1.5)) [-1.00e+00 0.00e+00] [ 0.00e+00 -1.50e+00] .. function:: cvxopt.min(x0[, x1[, x2 ...]]) When called with a single matrix argument, returns the minimum of the elements of the matrix (including the zero entries, if the matrix is sparse). When called with multiple arguments, the arguments must be matrices of the same size, or scalars, and the elementwise maximum is returned. A 1 by 1 dense matrix is treated as a scalar if the other arguments are not all 1 by 1. If one of the arguments is scalar, and the other arguments are not all 1 by 1, then the scalar argument is interpreted as a dense matrix with all its entries equal to the scalar. :func:`min ` can also be called with an iterable (list, tuple, range object, or generator) as its single argument, if the iterable generates a list of dense or sparse matrices or scalars. .. _s-random: Randomly Generated Matrices =========================== The CVXOPT package provides two functions :func:`normal ` and :func:`uniform ` for generating randomly distributed matrices. The default installation relies on the pseudo-random number generators in the Python standard library :mod:`random`. Alternatively, the random number generators in the `GNU Scientific Library (GSL) `_ can be used, if this option is selected during the installation of CVXOPT. The random matrix functions based on GSL are faster than the default functions based on the :mod:`random` module. .. function:: cvxopt.normal(nrows[, ncols = 1[, mean = 0.0[, std = 1.0]]]) Returns a type :const:`'d'` dense matrix of size ``nrows`` by ``ncols`` with elements chosen from a normal distribution with mean ``mean`` and standard deviation ``std``. .. function:: cvxopt.uniform(nrows[, ncols = 1[, a = 0.0[, b = 1.0]]]) Returns a type :const:`'d'` dense matrix of size ``nrows`` by ``ncols`` matrix with elements uniformly distributed between ``a`` and ``b``. .. function:: cvxopt.setseed([value]) Sets the state of the random number generator. ``value`` must be an integer. If ``value`` is absent or equal to zero, the value is taken from the system clock. If the Python random number generators are used, this is equivalent to :samp:`random.seed(value)`. .. function:: cvxopt.getseed() Returns the current state of the random number generator. This function is only available if the GSL random number generators are installed. (The state of the random number generators in the Python :mod:`random` module can be managed via the functions :func:`random.getstate` and :func:`random.setstate`.) .. _s-array-interface: The NumPy Array Interface ========================= This section only applies to the Python 2 version of CVXOPT. The CVXOPT :class:`matrix` object is compatible with the NumPy Array Interface, which allows Python objects that represent multidimensional arrays to exchange data using information stored in the attribute :attr:`__array_struct__`. As already mentioned in the section :ref:`s-dense-matrices`, a two-dimensional array object (for example, a NumPy matrix or two-dimensional array) can be converted to a CVXOPT :class:`matrix` object by using the :func:`matrix ` constructor. Conversely, CVXOPT matrices can be used as array-like objects in NumPy. The following example illustrates the compatibility of CVXOPT matrices and NumPy arrays. >>> from cvxopt import matrix >>> a = matrix(range(6), (2,3), 'd') >>> print(a) [ 0.00e+00 2.00e+00 4.00e+00] [ 1.00e+00 3.00e+00 5.00e+00] >>> from numpy import array >>> b = array(a) >>> b array([[ 0. 2. 4.] [ 1. 3. 5.]]) >>> a*b array([[ 0. 4. 16.] [ 1. 9. 25.]]) >>> from numpy import mat >>> c = mat(a) >>> c matrix([[ 0. 2. 4.] [ 1. 3. 5.]]) >>> a.T * c matrix([[ 1., 3., 5.], [ 3., 13., 23.], [ 5., 23., 41.]]) In the first product, ``a * b`` is interpreted as NumPy array multiplication, i.e., componentwise multiplication. The second product ``a.T * c`` is interpreted as NumPy matrix multiplication, i.e., standard matrix multiplication. cvxopt-1.1.4/doc/source/spsolvers.rst0000644000175000017500000005174611674452555016760 0ustar sonnesonne.. role:: raw-html(raw) :format: html .. _c-spsolvers: *********************** Sparse Linear Equations *********************** In this section we describe routines for solving sparse sets of linear equations. A real symmetric or complex Hermitian sparse matrix is stored as an :class:`spmatrix ` object ``X`` of size (:math:`n`, :math:`n`) and an additional character argument ``uplo`` with possible values :const:`'L'` and :const:`'U'`. If ``uplo`` is :const:`'L'`, the lower triangular part of ``X`` contains the lower triangular part of the symmetric or Hermitian matrix, and the upper triangular matrix of ``X`` is ignored. If ``uplo`` is :const:`'U'`, the upper triangular part of ``X`` contains the upper triangular part of the matrix, and the lower triangular matrix of ``X`` is ignored. A general sparse square matrix of order :math:`n` is represented by an :class:`spmatrix` object of size (:math:`n`, :math:`n`). Dense matrices, which appear as right-hand sides of equations, are stored using the same conventions as in the BLAS and LAPACK modules. .. _s-orderings: Matrix Orderings **************** CVXOPT includes an interface to the AMD library for computing approximate minimum degree orderings of sparse matrices. .. seealso:: * `AMD code, documentation, copyright, and license `_ * P. R. Amestoy, T. A. Davis, I. S. Duff, Algorithm 837: AMD, An Approximate Minimum Degree Ordering Algorithm, ACM Transactions on Mathematical Software, 30(3), 381-388, 2004. .. function:: cvxopt.amd.order(A[, uplo = 'L']) Computes the approximate mimimum degree ordering of a symmetric sparse matrix :math:`A`. The ordering is returned as an integer dense matrix with length equal to the order of :math:`A`. Its entries specify a permutation that reduces fill-in during the Cholesky factorization. More precisely, if ``p = order(A)`` , then ``A[p, p]`` has sparser Cholesky factors than ``A``. As an example we consider the matrix .. math:: \left[ \begin{array}{rrrr} 10 & 0 & 3 & 0 \\ 0 & 5 & 0 & -2 \\ 3 & 0 & 5 & 0 \\ 0 & -2 & 0 & 2 \end{array}\right]. >>> from cvxopt import spmatrix, amd >>> A = spmatrix([10,3,5,-2,5,2], [0,2,1,2,2,3], [0,0,1,1,2,3]) >>> P = amd.order(A) >>> print(P) [ 1] [ 0] [ 2] [ 3] .. _s-umfpack: General Linear Equations ************************ The module :mod:`cvxopt.umfpack` includes four functions for solving sparse non-symmetric sets of linear equations. They call routines from the UMFPACK library, with all control options set to the default values described in the UMFPACK user guide. .. seealso:: * `UMFPACK code, documentation, copyright, and license `_ * T. A. Davis, Algorithm 832: UMFPACK -- an unsymmetric-pattern multifrontal method with a column pre-ordering strategy, ACM Transactions on Mathematical Software, 30(2), 196-199, 2004. .. function:: cvxopt.umfpack.linsolve(A, B[, trans = 'N']) Solves a sparse set of linear equations .. math:: AX & = B \quad (\mathrm{trans} = \mathrm{'N'}), \\ A^TX & = B \quad (\mathrm{trans} = \mathrm{'T'}), \\ A^HX & = B \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is a sparse matrix and :math:`B` is a dense matrix. The arguments ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`) as ``A``. On exit ``B`` contains the solution. Raises an :exc:`ArithmeticError` if the coefficient matrix is singular. In the following example we solve an equation with coefficient matrix .. math:: :label: e-sp-Adef A = \left[\begin{array}{rrrrr} 2 & 3 & 0 & 0 & 0 \\ 3 & 0 & 4 & 0 & 6 \\ 0 &-1 &-3 & 2 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 4 & 2 & 0 & 1 \end{array}\right]. >>> from cvxopt import spmatrix, matrix, umfpack >>> V = [2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1] >>> I = [0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4] >>> J = [0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4, 4] >>> A = spmatrix(V,I,J) >>> B = matrix(1.0, (5,1)) >>> umfpack.linsolve(A,B) >>> print(B) [ 5.79e-01] [-5.26e-02] [ 1.00e+00] [ 1.97e+00] [-7.89e-01] The function :func:`linsolve ` is equivalent to the following three functions called in sequence. .. function:: cvxopt.umfpack.symbolic(A) Reorders the columns of ``A`` to reduce fill-in and performs a symbolic LU factorization. ``A`` is a sparse, possibly rectangular, matrix. Returns the symbolic factorization as an opaque C object that can be passed on to :func:`numeric `. .. function:: cvxopt.umfpack.numeric(A, F) Performs a numeric LU factorization of a sparse, possibly rectangular, matrix ``A``. The argument ``F`` is the symbolic factorization computed by :func:`symbolic ` applied to the matrix ``A``, or another sparse matrix with the same sparsity pattern, dimensions, and type. The numeric factorization is returned as an opaque C object that that can be passed on to :func:`solve `. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.umfpack.solve(A, F, B[, trans = 'N']) Solves a set of linear equations .. math:: AX & = B \quad (\mathrm{trans} = \mathrm{'N'}), \\ A^TX & = B \quad (\mathrm{trans} = \mathrm{'T'}), \\ A^HX & = B \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is a sparse matrix and :math:`B` is a dense matrix. The arguments ``A`` and ``B`` must have the same type. The argument ``F`` is a numeric factorization computed by :func:`numeric `. On exit ``B`` is overwritten by the solution. These separate functions are useful for solving several sets of linear equations with the same coefficient matrix and different right-hand sides, or with coefficient matrices that share the same sparsity pattern. The symbolic factorization depends only on the sparsity pattern of the matrix, and not on the numerical values of the nonzero coefficients. The numerical factorization on the other hand depends on the sparsity pattern of the matrix and on its the numerical values. As an example, suppose :math:`A` is the matrix :eq:`e-sp-Adef` and .. math:: B = \left[\begin{array}{rrrrr} 4 & 3 & 0 & 0 & 0 \\ 3 & 0 & 4 & 0 & 6 \\ 0 &-1 &-3 & 2 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 4 & 2 & 0 & 2 \end{array}\right], which differs from :math:`A` in its first and last entries. The following code computes .. math:: \newcommand{\ones}{\mathbf 1} x = A^{-T}B^{-1}A^{-1}\ones. >>> from cvxopt import spmatrix, matrix, umfpack >>> VA = [2, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 1] >>> VB = [4, 3, 3, -1, 4, 4, -3, 1, 2, 2, 6, 2] >>> I = [0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4] >>> J = [0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 4, 4] >>> A = spmatrix(VA, I, J) >>> B = spmatrix(VB, I, J) >>> x = matrix(1.0, (5,1)) >>> Fs = umfpack.symbolic(A) >>> FA = umfpack.numeric(A, Fs) >>> FB = umfpack.numeric(B, Fs) >>> umfpack.solve(A, FA, x) >>> umfpack.solve(B, FB, x) >>> umfpack.solve(A, FA, x, trans='T') >>> print(x) [ 5.81e-01] [-2.37e-01] [ 1.63e+00] [ 8.07e+00] [-1.31e-01] .. _s-cholmod: Positive Definite Linear Equations ********************************** :mod:`cvxopt.cholmod` is an interface to the Cholesky factorization routines of the CHOLMOD package. It includes functions for Cholesky factorization of sparse positive definite matrices, and for solving sparse sets of linear equations with positive definite matrices. The routines can also be used for computing :raw-html:`LDLT` (or :raw-html:`LDLH` factorizations of symmetric indefinite matrices (with :math:`L` unit lower-triangular and :math:`D` diagonal and nonsingular) if such a factorization exists. .. seealso:: `CHOLMOD code, documentation, copyright, and license `_ .. function:: cvxopt.cholmod.linsolve(A, B[, p = None, uplo = 'L']) Solves .. math:: AX = B with :math:`A` sparse and real symmetric or complex Hermitian. ``B`` is a dense matrix of the same type as ``A``. On exit it is overwritten with the solution. The argument ``p`` is an integer matrix with length equal to the order of :math:`A`, and specifies an optional reordering. If ``p`` is not specified, CHOLMOD uses a reordering from the AMD library. Raises an :exc:`ArithmeticError` if the factorization does not exist. As an example, we solve .. math:: :label: e-A-pd \left[ \begin{array}{rrrr} 10 & 0 & 3 & 0 \\ 0 & 5 & 0 & -2 \\ 3 & 0 & 5 & 0 \\ 0 & -2 & 0 & 2 \end{array}\right] X = \left[ \begin{array}{cc} 0 & 4 \\ 1 & 5 \\ 2 & 6 \\ 3 & 7 \end{array} \right]. >>> from cvxopt import matrix, spmatrix, cholmod >>> A = spmatrix([10, 3, 5, -2, 5, 2], [0, 2, 1, 3, 2, 3], [0, 0, 1, 1, 2, 3]) >>> X = matrix(range(8), (4,2), 'd') >>> cholmod.linsolve(A,X) >>> print(X) [-1.46e-01 4.88e-02] [ 1.33e+00 4.00e+00] [ 4.88e-01 1.17e+00] [ 2.83e+00 7.50e+00] .. function:: cvxopt.cholmod.splinsolve(A, B[, p = None, uplo = 'L']) Similar to :func:`linsolve ` except that ``B`` is an :class:`spmatrix ` and that the solution is returned as an output argument (as a new :class:`spmatrix`). ``B`` is not modified. The following code computes the inverse of the coefficient matrix in :eq:`e-A-pd` as a sparse matrix. >>> X = cholmod.splinsolve(A, spmatrix(1.0,range(4),range(4))) >>> print(X) [ 1.22e-01 0 -7.32e-02 0 ] [ 0 3.33e-01 0 3.33e-01] [-7.32e-02 0 2.44e-01 0 ] [ 0 3.33e-01 0 8.33e-01] The functions :func:`linsolve ` and :func:`splinsolve ` are equivalent to :func:`symbolic ` and :func:`numeric ` called in sequence, followed by :func:`solve `, respectively, :func:`spsolve `. .. function:: cvxopt.cholmod.symbolic(A[, p = None, uplo = 'L']) Performs a symbolic analysis of a sparse real symmetric or complex Hermitian matrix :math:`A` for one of the two factorizations: .. math:: :label: e-chol-ll PAP^T = LL^T, \qquad PAP^T = LL^H, and .. math:: :label: e-chol-ldl PAP^T = LDL^T, \qquad PAP^T = LDL^H, where :math:`P` is a permutation matrix, :math:`L` is lower triangular (unit lower triangular in the second factorization), and :math:`D` is nonsingular diagonal. The type of factorization depends on the value of :attr:`options['supernodal']` (see below). If ``uplo`` is :const:`'L'`, only the lower triangular part of ``A`` is accessed and the upper triangular part is ignored. If ``uplo`` is :const:`'U'`, only the upper triangular part of ``A`` is accessed and the lower triangular part is ignored. If ``p`` is not provided, a reordering from the AMD library is used. The symbolic factorization is returned as an opaque C object that can be passed to :func:`numeric `. .. function:: cvxopt.cholmod.numeric(A, F) Performs a numeric factorization of a sparse symmetric matrix as :eq:`e-chol-ll` or :eq:`e-chol-ldl`. The argument ``F`` is the symbolic factorization computed by :func:`symbolic ` applied to the matrix ``A``, or to another sparse matrix with the same sparsity pattern and typecode, or by :func:`numeric ` applied to a matrix with the same sparsity pattern and typecode as ``A``. If ``F`` was created by a :func:`symbolic ` with ``uplo`` equal to :const:`'L'`, then only the lower triangular part of ``A`` is accessed and the upper triangular part is ignored. If it was created with ``uplo`` equal to :const:`'U'`, then only the upper triangular part of ``A`` is accessed and the lower triangular part is ignored. On successful exit, the factorization is stored in ``F``. Raises an :exc:`ArithmeticError` if the factorization does not exist. .. function:: cvxopt.cholmod.solve(F, B[, sys = 0]) Solves one of the following linear equations where ``B`` is a dense matrix and ``F`` is the numeric factorization :eq:`e-chol-ll` or :eq:`e-chol-ldl` computed by :func:`numeric `. ``sys`` is an integer with values between 0 and 8. +---------+--------------------+ | ``sys`` | equation | +---------+--------------------+ | 0 | :math:`AX = B` | +---------+--------------------+ | 1 | :math:`LDL^TX = B` | +---------+--------------------+ | 2 | :math:`LDX = B` | +---------+--------------------+ | 3 | :math:`DL^TX=B` | +---------+--------------------+ | 4 | :math:`LX=B` | +---------+--------------------+ | 5 | :math:`L^TX=B` | +---------+--------------------+ | 6 | :math:`DX=B` | +---------+--------------------+ | 7 | :math:`P^TX=B` | +---------+--------------------+ | 8 | :math:`PX=B` | +---------+--------------------+ (If ``F`` is a Cholesky factorization of the form :eq:`e-chol-ll`, :math:`D` is an identity matrix in this table. If ``A`` is complex, :math:`L^T` should be replaced by :math:`L^H`.) The matrix ``B`` is a dense :const:`'d'` or :const:`'z'` matrix, with the same type as ``A``. On exit it is overwritten by the solution. .. function:: cvxopt.cholmod.spsolve(F, B[, sys = 0]) Similar to :func:`solve `, except that ``B`` is a class:`spmatrix`, and the solution is returned as an output argument (as an :class:`spmatrix`). ``B`` must have the same typecode as ``A``. For the same example as above: >>> X = matrix(range(8), (4,2), 'd') >>> F = cholmod.symbolic(A) >>> cholmod.numeric(A, F) >>> cholmod.solve(F, X) >>> print(X) [-1.46e-01 4.88e-02] [ 1.33e+00 4.00e+00] [ 4.88e-01 1.17e+00] [ 2.83e+00 7.50e+00] .. function:: cvxopt.cholmod.diag(F) Returns the diagonal elements of the Cholesky factor :math:`L` in :eq:`e-chol-ll`, as a dense matrix of the same type as ``A``. Note that this only applies to Cholesky factorizations. The matrix :math:`D` in an :raw-html:`LDLT` factorization can be retrieved via :func:`solve ` with ``sys`` equal to 6. In the functions listed above, the default values of the control parameters described in the CHOLMOD user guide are used, except for :cdata:`Common->print` which is set to 0 instead of 3 and :cdata:`Common->supernodal` which is set to 2 instead of 1. These parameters (and a few others) can be modified by making an entry in the dictionary :attr:`cholmod.options`. The meaning of these parameters is as follows. :attr:`options['supernodal']` If equal to 0, a factorization :eq:`e-chol-ldl` is computed using a simplicial algorithm. If equal to 2, a factorization :eq:`e-chol-ll` is computed using a supernodal algorithm. If equal to 1, the most efficient of the two factorizations is selected, based on the sparsity pattern. Default: 2. :attr:`options['print']` A nonnegative integer that controls the amount of output printed to the screen. Default: 0 (no output). As an example that illustrates :func:`diag ` and the use of :attr:`cholmod.options`, we compute the logarithm of the determinant of the coefficient matrix in :eq:`e-A-pd` by two methods. >>> import math >>> from cvxopt.cholmod import options >>> from cvxopt import log >>> F = cholmod.symbolic(A) >>> cholmod.numeric(A, F) >>> print(2.0 * sum(log(cholmod.diag(F)))) 5.50533153593 >>> options['supernodal'] = 0 >>> F = cholmod.symbolic(A) >>> cholmod.numeric(A, F) >>> Di = matrix(1.0, (4,1)) >>> cholmod.solve(F, Di, sys=6) >>> print(-sum(log(Di))) 5.50533153593 Example: Covariance Selection ***************************** This example illustrates the use of the routines for sparse Cholesky factorization. We consider the problem .. math:: :label: e-covsel \newcommand{\Tr}{\mathop{\bf tr}} \begin{array}{ll} \mbox{minimize} & -\log\det K + \Tr(KY) \\ \mbox{subject to} & K_{ij}=0,\quad (i,j) \not \in S. \end{array} The optimization variable is a symmetric matrix :math:`K` of order :math:`n` and the domain of the problem is the set of positive definite matrices. The matrix :math:`Y` and the index set :math:`S` are given. We assume that all the diagonal positions are included in :math:`S`. This problem arises in maximum likelihood estimation of the covariance matrix of a zero-mean normal distribution, with constraints that specify that pairs of variables are conditionally independent. We can express :math:`K` as .. math:: \newcommand{\diag}{\mathop{\bf diag}} K(x) = E_1\diag(x)E_2^T+E_2\diag(x)E_1^T where :math:`x` are the nonzero elements in the lower triangular part of :math:`K`, with the diagonal elements scaled by 1/2, and .. math:: E_1 = \left[ \begin{array}{cccc} e_{i_1} & e_{i_2} & \cdots & e_{i_q} \end{array}\right], \qquad E_2 = \left[ \begin{array}{cccc} e_{j_1} & e_{j_2} & \cdots & e_{j_q} \end{array}\right], where (:math:`i_k`, :math:`j_k`) are the positions of the nonzero entries in the lower-triangular part of :math:`K`. With this notation, we can solve problem :eq:`e-covsel` by solving the unconstrained problem .. math:: \newcommand{\Tr}{\mathop{\bf tr}} \begin{array}{ll} \mbox{minimize} & f(x) = -\log\det K(x) + \Tr(K(x)Y). \end{array} The code below implements Newton's method with a backtracking line search. The gradient and Hessian of the objective function are given by .. math:: \newcommand{\diag}{\mathop{\bf diag}} \begin{split} \nabla f(x) & = 2 \diag( E_1^T (Y - K(x)^{-1}) E_2)) \\ & = 2\diag(Y_{IJ} - \left(K(x)^{-1}\right)_{IJ}) \\ \nabla^2 f(x) & = 2 (E_1^T K(x)^{-1} E_1) \circ (E_2^T K(x)^{-1} E_2) + 2 (E_1^T K(x)^{-1} E_2) \circ (E_2^T K(x)^{-1} E_1) \\ & = 2 \left(K(x)^{-1}\right)_{II} \circ \left(K(x)^{-1}\right)_{JJ} + 2 \left(K(x)^{-1}\right)_{IJ} \circ \left(K(x)^{-1}\right)_{JI}, \end{split} where :math:`\circ` denotes Hadamard product. :: from cvxopt import matrix, spmatrix, log, mul, blas, lapack, amd, cholmod def covsel(Y): """ Returns the solution of minimize -log det K + Tr(KY) subject to K_{ij}=0, (i,j) not in indices listed in I,J. Y is a symmetric sparse matrix with nonzero diagonal elements. I = Y.I, J = Y.J. """ I, J = Y.I, Y.J n, m = Y.size[0], len(I) N = I + J*n # non-zero positions for one-argument indexing D = [k for k in range(m) if I[k]==J[k]] # position of diagonal elements # starting point: symmetric identity with nonzero pattern I,J K = spmatrix(0.0, I, J) K[::n+1] = 1.0 # Kn is used in the line search Kn = spmatrix(0.0, I, J) # symbolic factorization of K F = cholmod.symbolic(K) # Kinv will be the inverse of K Kinv = matrix(0.0, (n,n)) for iters in range(100): # numeric factorization of K cholmod.numeric(K, F) d = cholmod.diag(F) # compute Kinv by solving K*X = I Kinv[:] = 0.0 Kinv[::n+1] = 1.0 cholmod.solve(F, Kinv) # solve Newton system grad = 2*(Y.V - Kinv[N]) hess = 2*(mul(Kinv[I,J],Kinv[J,I]) + mul(Kinv[I,I],Kinv[J,J])) v = -grad lapack.posv(hess,v) # stopping criterion sqntdecr = -blas.dot(grad,v) print("Newton decrement squared:%- 7.5e" %sqntdecr) if (sqntdecr < 1e-12): print("number of iterations: ", iters+1) break # line search dx = +v dx[D] *= 2 # scale the diagonal elems f = -2.0 * sum(log(d)) # f = -log det K s = 1 for lsiter in range(50): Kn.V = K.V + s*dx try: cholmod.numeric(Kn, F) except ArithmeticError: s *= 0.5 else: d = cholmod.diag(F) fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V) if (fn < f - 0.01*s*sqntdecr): break s *= 0.5 K.V = Kn.V return K cvxopt-1.1.4/doc/source/conf.py0000644000175000017500000001322411674452555015452 0ustar sonnesonne# -*- coding: utf-8 -*- # # CVXOPT documentation build configuration file, created by # sphinx-quickstart on Sat Dec 27 20:54:35 2008. # # This file is execfile()d with the current directory set to its containing dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. import sys, os # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. #sys.path.append(os.path.abspath('some/directory')) # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.pngmath'] # Add any paths that contain templates here, relative to this directory. templates_path = ['.templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General substitutions. project = 'CVXOPT' #copyright = '2004-2009, Joachim Dahl, Lieven Vandenberghe' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. version = '1.1.1' # The full version, including alpha/beta/rc tags. release = '1.1.1' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directories, that shouldn't be searched # for source files. #exclude_dirs = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. add_function_parentheses = False # If true, the current module name will be prepended to all description # unit titles (such as .. function::). add_module_names = False # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = 'cvxopt.css' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = "CVXOPT User's Guide" # A shorter title for the navigation bar. Default is the same as html_title. html_short_title = "user's guide" # The name of an image file (within the static path) to place at the top of # the sidebar. html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['.static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' html_last_updated_fmt = '' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. html_use_modindex = False # If false, no index is generated. html_use_index = False # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, the reST sources are included in the HTML build as _sources/. html_copy_source = False # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'CVXOPTdoc' # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ ('index', 'CVXOPT.tex', 'CVXOPT Documentation', 'Joachim Dahl, Lieven Vandenberghe', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True cvxopt-1.1.4/doc/source/blas.rst0000644000175000017500000010046611674452555015633 0ustar sonnesonne.. _c-blas: ****************** The BLAS Interface ****************** The :mod:`cvxopt.blas` module provides an interface to the double-precision real and complex Basic Linear Algebra Subprograms (BLAS). The names and calling sequences of the Python functions in the interface closely match the corresponding Fortran BLAS routines (described in the references below) and their functionality is exactly the same. Many of the operations performed by the BLAS routines can be implemented in a more straightforward way by using the matrix arithmetic of the section :ref:`s-arithmetic`, combined with the slicing and indexing of the section :ref:`s-indexing`. As an example, ``C = A * B`` gives the same result as the BLAS call ``gemm(A, B, C)``. The BLAS interface offers two advantages. First, some of the functions it includes are not easily implemented using the basic matrix arithmetic. For example, BLAS includes functions that efficiently exploit symmetry or triangular matrix structure. Second, there is a performance difference that can be significant for large matrices. Although our implementation of the basic matrix arithmetic makes internal calls to BLAS, it also often requires creating temporary matrices to store intermediate results. The BLAS functions on the other hand always operate directly on their matrix arguments and never require any copying to temporary matrices. Thus they can be viewed as generalizations of the in-place matrix addition and scalar multiplication of the section :ref:`s-arithmetic` to more complicated operations. .. seealso:: * C. L. Lawson, R. J. Hanson, D. R. Kincaid, F. T. Krogh, Basic Linear Algebra Subprograms for Fortran Use, ACM Transactions on Mathematical Software, 5(3), 309-323, 1975. * J. J. Dongarra, J. Du Croz, S. Hammarling, R. J. Hanson, An Extended Set of Fortran Basic Linear Algebra Subprograms, ACM Transactions on Mathematical Software, 14(1), 1-17, 1988. * J. J. Dongarra, J. Du Croz, S. Hammarling, I. Duff, A Set of Level 3 Basic Linear Algebra Subprograms, ACM Transactions on Mathematical Software, 16(1), 1-17, 1990. .. _s-conventions: Matrix Classes ============== The BLAS exploit several types of matrix structure: symmetric, Hermitian, triangular, and banded. We represent all these matrix classes by dense real or complex :class:`matrix ` objects, with additional arguments that specify the structure. **Vector** A real or complex :math:`n`-vector is represented by a :class:`matrix` of type :const:`'d'` or :const:`'z'` and length :math:`n`, with the entries of the vector stored in column-major order. **General matrix** A general real or complex :math:`m` by :math:`n` matrix is represented by a real or complex :class:`matrix` of size (:math:`m`, :math:`n`). **Symmetric matrix** A real or complex symmetric matrix of order :math:`n` is represented by a real or complex :class:`matrix` of size (:math:`n`, :math:`n`), and a character argument ``uplo`` with two possible values: :const:`'L'` and :const:`'U'`. If ``uplo`` is :const:`'L'`, the lower triangular part of the symmetric matrix is stored; if ``uplo`` is :const:`'U'`, the upper triangular part is stored. A square :class:`matrix` ``X`` of size (:math:`n`, :math:`n`) can therefore be used to represent the symmetric matrices .. math:: \left[\begin{array}{ccccc} X[0,0] & X[1,0] & X[2,0] & \cdots & X[n-1,0] \\ X[1,0] & X[1,1] & X[2,1] & \cdots & X[n-1,1] \\ X[2,0] & X[2,1] & X[2,2] & \cdots & X[n-1,2] \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & X[n-1,n-1] \end{array}\right] \quad \mbox{(uplo = 'L')}, \left[\begin{array}{ccccc} X[0,0] & X[0,1] & X[0,2] & \cdots & X[0,n-1] \\ X[0,1] & X[1,1] & X[1,2] & \cdots & X[1,n-1] \\ X[0,2] & X[1,2] & X[2,2] & \cdots & X[2,n-1] \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ X[0,n-1] & X[1,n-1] & X[2,n-1] & \cdots & X[n-1,n-1] \end{array}\right] \quad \mbox{(uplo = U')}. **Complex Hermitian matrix** A complex Hermitian matrix of order :math:`n` is represented by a :class:`matrix` of type :const:`'z'` and size (:math:`n`, :math:`n`), and a character argument ``uplo`` with the same meaning as for symmetric matrices. A complex :class:`matrix` ``X`` of size (:math:`n`, :math:`n`) can represent the Hermitian matrices .. math:: \left[\begin{array}{ccccc} \Re X[0,0] & \bar X[1,0] & \bar X[2,0] & \cdots & \bar X[n-1,0] \\ X[1,0] & \Re X[1,1] & \bar X[2,1] & \cdots & \bar X[n-1,1] \\ X[2,0] & X[2,1] & \Re X[2,2] & \cdots & \bar X[n-1,2] \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & \Re X[n-1,n-1] \end{array}\right] \quad \mbox{(uplo = 'L')}, \left[\begin{array}{ccccc} \Re X[0,0] & X[0,1] & X[0,2] & \cdots & X[0,n-1] \\ \bar X[0,1] & \Re X[1,1] & X[1,2] & \cdots & X[1,n-1] \\ \bar X[0,2] & \bar X[1,2] & \Re X[2,2] & \cdots & X[2,n-1] \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ \bar X[0,n-1] & \bar X[1,n-1] & \bar X[2,n-1] & \cdots & \Re X[n-1,n-1] \end{array}\right] \quad \mbox{(uplo = 'U')}. **Triangular matrix** A real or complex triangular matrix of order :math:`n` is represented by a real or complex :class:`matrix` of size (:math:`n`, :math:`n`), and two character arguments: an argument ``uplo`` with possible values :const:`'L'` and :const:`'U'` to distinguish between lower and upper triangular matrices, and an argument ``diag`` with possible values :const:`'U'` and :const:`'N'` to distinguish between unit and non-unit triangular matrices. A square :class:`matrix` ``X`` of size (:math:`n`, :math:`n`) can represent the triangular matrices .. math:: \left[\begin{array}{ccccc} X[0,0] & 0 & 0 & \cdots & 0 \\ X[1,0] & X[1,1] & 0 & \cdots & 0 \\ X[2,0] & X[2,1] & X[2,2] & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & X[n-1,n-1] \end{array}\right] \quad \mbox{(uplo = 'L', diag = 'N')}, \left[\begin{array}{ccccc} 1 & 0 & 0 & \cdots & 0 \\ X[1,0] & 1 & 0 & \cdots & 0 \\ X[2,0] & X[2,1] & 1 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ X[n-1,0] & X[n-1,1] & X[n-1,2] & \cdots & 1 \end{array}\right] \quad \mbox{(uplo = 'L', diag = 'U')}, \left[\begin{array}{ccccc} X[0,0] & X[0,1] & X[0,2] & \cdots & X[0,n-1] \\ 0 & X[1,1] & X[1,2] & \cdots & X[1,n-1] \\ 0 & 0 & X[2,2] & \cdots & X[2,n-1] \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & X[n-1,n-1] \end{array}\right] \quad \mbox{(uplo = 'U', diag = 'N')}, \left[\begin{array}{ccccc} 1 & X[0,1] & X[0,2] & \cdots & X[0,n-1] \\ 0 & 1 & X[1,2] & \cdots & X[1,n-1] \\ 0 & 0 & 1 & \cdots & X[2,n-1] \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & 1 \end{array}\right] \quad \mbox{(uplo = 'U', diag = 'U')}. **General band matrix** A general real or complex :math:`m` by :math:`n` band matrix with :math:`k_l` subdiagonals and :math:`k_u` superdiagonals is represented by a real or complex :class:`matrix` ``X`` of size (:math:`k_l + k_u + 1`, :math:`n`), and the two integers :math:`m` and :math:`k_l`. The diagonals of the band matrix are stored in the rows of ``X``, starting at the top diagonal, and shifted horizontally so that the entries of column :math:`k` of the band matrix are stored in column :math:`k` of ``X``. A :class:`matrix` ``X`` of size (:math:`k_l + k_u + 1`, :math:`n`) therefore represents the :math:`m` by :math:`n` band matrix .. math:: \left[ \begin{array}{ccccccc} X[k_u,0] & X[k_u-1,1] & X[k_u-2,2] & \cdots & X[0,k_u] & 0 & \cdots \\ X[k_u+1,0] & X[k_u,1] & X[k_u-1,2] & \cdots & X[1,k_u] & X[0,k_u+1] & \cdots \\ X[k_u+2,0] & X[k_u+1,1] & X[k_u,2] & \cdots & X[2,k_u] & X[1,k_u+1] & \cdots \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots \\ X[k_u+k_l,0] & X[k_u+k_l-1,1] & X[k_u+k_l-2,2] & \cdots & & & \\ 0 & X[k_u+k_l,1] & X[k_u+k_l-1,2] & \cdots & & & \\ \vdots & \vdots & \vdots & \ddots & & & \end{array}\right]. **Symmetric band matrix** A real or complex symmetric band matrix of order :math:`n` with :math:`k` subdiagonals, is represented by a real or complex matrix ``X`` of size (:math:`k+1`, :math:`n`), and an argument ``uplo`` to indicate whether the subdiagonals (``uplo`` is :const:`'L'`) or superdiagonals (``uplo`` is :const:`'U'`) are stored. The :math:`k+1` diagonals are stored as rows of ``X``, starting at the top diagonal (i.e., the main diagonal if ``uplo`` is :const:`'L'`, or the :math:`k`-th superdiagonal if ``uplo`` is :const:`'U'`) and shifted horizontally so that the entries of the :math:`k`-th column of the band matrix are stored in column :math:`k` of ``X``. A :class:`matrix` ``X`` of size (:math:`k+1`, :math:`n`) can therefore represent the band matrices .. math:: \left[ \begin{array}{ccccccc} X[0,0] & X[1,0] & X[2,0] & \cdots & X[k,0] & 0 & \cdots \\ X[1,0] & X[0,1] & X[1,1] & \cdots & X[k-1,1] & X[k,1] & \cdots \\ X[2,0] & X[1,1] & X[0,2] & \cdots & X[k-2,2] & X[k-1,2] & \cdots \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots \\ X[k,0] & X[k-1,1] & X[k-2,2] & \cdots & & & \\ 0 & X[k,1] & X[k-1,2] & \cdots & & & \\ \vdots & \vdots & \vdots & \ddots & & & \end{array}\right] \quad \mbox{(uplo = 'L')}, \left[ \begin{array}{ccccccc} X[k,0] & X[k-1,1] & X[k-2,2] & \cdots & X[0,k] & 0 & \cdots \\ X[k-1,1] & X[k,1] & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\ X[k-2,2] & X[k-1,2] & X[k,2] & \cdots & X[2,k] & X[1,k+1] & \cdots \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots \\ X[0,k] & X[1,k] & X[2,k] & \cdots & & & \\ 0 & X[0,k+1] & X[1,k+1] & \cdots & & & \\ \vdots & \vdots & \vdots & \ddots & & & \end{array}\right] \quad \mbox{(uplo='U')}. **Hermitian band matrix** A complex Hermitian band matrix of order :math:`n` with :math:`k` subdiagonals is represented by a complex matrix of size (:math:`k+1`, :math:`n`) and an argument ``uplo``, with the same meaning as for symmetric band matrices. A :class:`matrix` ``X`` of size (:math:`k+1`, :math:`n`) can represent the band matrices .. math:: \left[ \begin{array}{ccccccc} \Re X[0,0] & \bar X[1,0] & \bar X[2,0] & \cdots & \bar X[k,0] & 0 & \cdots \\ X[1,0] & \Re X[0,1] & \bar X[1,1] & \cdots & \bar X[k-1,1] & \bar X[k,1] & \cdots \\ X[2,0] & X[1,1] & \Re X[0,2] & \cdots & \bar X[k-2,2] & \bar X[k-1,2] & \cdots \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots \\ X[k,0] & X[k-1,1] & X[k-2,2] & \cdots & & & \\ 0 & X[k,1] & X[k-1,2] & \cdots & & & \\ \vdots & \vdots & \vdots & \ddots & & & \end{array}\right] \quad \mbox{(uplo = 'L')}, \left[ \begin{array}{ccccccc} \Re X[k,0] & X[k-1,1] & X[k-2,2] & \cdots & X[0,k] & 0 & \cdots \\ \bar X[k-1,1] & \Re X[k,1] & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\ \bar X[k-2,2] & \bar X[k-1,2] & \Re X[k,2] & \cdots & X[2,k] & X[1,k+1] & \cdots \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots \\ \bar X[0,k] & \bar X[1,k] & \bar X[2,k] & \cdots & & & \\ 0 & \bar X[0,k+1] & \bar X[1,k+1] & \cdots & & & \\ \vdots & \vdots & \vdots & \ddots & & & \end{array}\right] \quad \mbox{(uplo='U')}. **Triangular band matrix** A triangular band matrix of order :math:`n` with :math:`k` subdiagonals or superdiagonals is represented by a real complex matrix of size (:math:`k+1`, :math:`n`) and two character arguments ``uplo`` and ``diag``, with similar conventions as for symmetric band matrices. A :class:`matrix` ``X`` of size (:math:`k+1`, :math:`n`) can represent the band matrices .. math:: \left[ \begin{array}{cccc} X[0,0] & 0 & 0 & \cdots \\ X[1,0] & X[0,1] & 0 & \cdots \\ X[2,0] & X[1,1] & X[0,2] & \cdots \\ \vdots & \vdots & \vdots & \ddots \\ X[k,0] & X[k-1,1] & X[k-2,2] & \cdots \\ 0 & X[k,1] & X[k-1,1] & \cdots \\ \vdots & \vdots & \vdots & \ddots \end{array}\right] \quad \mbox{(uplo = 'L', diag = 'N')}, \left[ \begin{array}{cccc} 1 & 0 & 0 & \cdots \\ X[1,0] & 1 & 0 & \cdots \\ X[2,0] & X[1,1] & 1 & \cdots \\ \vdots & \vdots & \vdots & \ddots \\ X[k,0] & X[k-1,1] & X[k-2,2] & \cdots \\ 0 & X[k,1] & X[k-1,2] & \cdots \\ \vdots & \vdots & \vdots & \ddots \end{array}\right] \quad \mbox{(uplo = 'L', diag = 'U')}, \left[ \begin{array}{ccccccc} X[k,0] & X[k-1,1] & X[k-2,3] & \cdots & X[0,k] & 0 & \cdots\\ 0 & X[k,1] & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\ 0 & 0 & X[k,2] & \cdots & X[2,k] & X[1,k+1] & \cdots \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots \end{array}\right] \quad \mbox{(uplo = 'U', diag = 'N')}, \left[ \begin{array}{ccccccc} 1 & X[k-1,1] & X[k-2,3] & \cdots & X[0,k] & 0 & \cdots\\ 0 & 1 & X[k-1,2] & \cdots & X[1,k] & X[0,k+1] & \cdots \\ 0 & 0 & 1 & \cdots & X[2,k] & X[1,k+1] & \cdots \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots \end{array}\right] \quad \mbox{(uplo = 'U', diag = 'U')}. When discussing BLAS functions in the following sections we will omit several less important optional arguments that can be used to select submatrices for in-place operations. The complete specification is documented in the docstrings of the source code, and can be viewed with the :program:`pydoc` help program. .. _s-blas-1: Level 1 BLAS ============ The level 1 functions implement vector operations. .. function:: cvxopt.blas.scal(alpha, x) Scales a vector by a constant: .. math:: x := \alpha x. If ``x`` is a real :class:`matrix`, the scalar argument ``alpha`` must be a Python integer or float. If ``x`` is complex, ``alpha`` can be an integer, float, or complex. .. function:: cvxopt.blas.nrm2(x) Euclidean norm of a vector: returns .. math:: \|x\|_2. .. function:: cvxopt.blas.asum(x) 1-Norm of a vector: returns .. math:: \|x\|_1 \quad \mbox{($x$ real)}, \qquad \|\Re x\|_1 + \|\Im x\|_1 \quad \mbox{($x$ complex)}. .. function:: cvxopt.blas.iamax(x) Returns .. math:: \mathop{\rm argmax}_{k=0,\ldots,n-1} |x_k| \quad \mbox{($x$ real)}, \qquad \mathop{\rm argmax}_{k=0,\ldots,n-1} |\Re x_k| + |\Im x_k| \quad \mbox{($x$ complex)}. If more than one coefficient achieves the maximum, the index of the first :math:`k` is returned. .. function:: cvxopt.blas.swap(x, y) Interchanges two vectors: .. math:: x \leftrightarrow y. ``x`` and ``y`` are matrices of the same type (:const:`'d'` or :const:`'z'`). .. function:: cvxopt.blas.copy(x, y) Copies a vector to another vector: .. math:: y := x. ``x`` and ``y`` are matrices of the same type (:const:`'d'` or :const:`'z'`). .. function:: cvxopt.blas.axpy(x, y[, alpha = 1.0]) Constant times a vector plus a vector: .. math:: y := \alpha x + y. ``x`` and ``y`` are matrices of the same type (:const:`'d'` or :const:`'z'`). If ``x`` is real, the scalar argument ``alpha`` must be a Python integer or float. If ``x`` is complex, ``alpha`` can be an integer, float, or complex. .. function:: cvxopt.blas.dot(x, y) Returns .. math:: x^Hy. ``x`` and ``y`` are matrices of the same type (:const:`'d'` or :const:`'z'`). .. function:: cvxopt.blas.dotu(x, y) Returns .. math:: x^Ty. ``x`` and ``y`` are matrices of the same type (:const:`'d'` or :const:`'z'`). .. _s-blas-2: Level 2 BLAS ============ The level 2 functions implement matrix-vector products and rank-1 and rank-2 matrix updates. Different types of matrix structure can be exploited using the conventions of the section :ref:`s-conventions`. .. function:: cvxopt.blas.gemv(A, x, y[, trans = 'N', alpha = 1.0, beta = 0.0]) Matrix-vector product with a general matrix: .. math:: y & := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \\ y & := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), \\ y & := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}). The arguments ``A``, ``x``, and ``y`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.symv(A, x, y[, uplo = 'L', alpha = 1.0, beta = 0.0]) Matrix-vector product with a real symmetric matrix: .. math:: y := \alpha A x + \beta y, where :math:`A` is a real symmetric matrix. The arguments ``A``, ``x``, and ``y`` must have type :const:`'d'`, and ``alpha`` and ``beta`` must be real. .. function:: cvxopt.blas.hemv(A, x, y[, uplo = 'L', alpha = 1.0, beta = 0.0]) Matrix-vector product with a real symmetric or complex Hermitian matrix: .. math:: y := \alpha A x + \beta y, where :math:`A` is real symmetric or complex Hermitian. The arguments ``A``, ``x``, ``y`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.trmv(A, x[, uplo = 'L', trans = 'N', diag = 'N']) Matrix-vector product with a triangular matrix: .. math:: x & := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \\ x & := A^T x \quad (\mathrm{trans} = \mathrm{'T'}), \\ x & := A^H x \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is square and triangular. The arguments ``A`` and ``x`` must have the same type (:const:`'d'` or :const:`'z'`). .. function:: cvxopt.blas.trsv(A, x[, uplo = 'L', trans = 'N', diag = 'N']) Solution of a nonsingular triangular set of linear equations: .. math:: x & := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \\ x & := A^{-T}x \quad (\mathrm{trans} = \mathrm{'T'}), \\ x & := A^{-H}x \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is square and triangular with nonzero diagonal elements. The arguments ``A`` and ``x`` must have the same type (:const:`'d'` or :const:`'z'`). .. function:: cvxopt.blas.gbmv(A, m, kl, x, y[, trans = 'N', alpha = 1.0, beta = 0.0]) Matrix-vector product with a general band matrix: .. math:: y & := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \\ y & := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}), \\ y & := \alpha A^H x + \beta y \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is a rectangular band matrix with :math:`m` rows and :math:`k_l` subdiagonals. The arguments ``A``, ``x``, ``y`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.sbmv(A, x, y[, uplo = 'L', alpha = 1.0, beta = 0.0]) Matrix-vector product with a real symmetric band matrix: .. math:: y := \alpha Ax + \beta y, where :math:`A` is a real symmetric band matrix. The arguments ``A``, ``x``, ``y`` must have type :const:`'d'`, and ``alpha`` and ``beta`` must be real. .. function:: cvxopt.blas.hbmv(A, x, y[, uplo = 'L', alpha = 1.0, beta = 0.0]) Matrix-vector product with a real symmetric or complex Hermitian band matrix: .. math:: y := \alpha Ax + \beta y, where :math:`A` is a real symmetric or complex Hermitian band matrix. The arguments ``A``, ``x``, ``y`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.tbmv(A, x[, uplo = 'L', trans = 'N', diag = 'N']) Matrix-vector product with a triangular band matrix: .. math:: x & := Ax \quad (\mathrm{trans} = \mathrm{'N'}), \\ x & := A^T x \quad (\mathrm{trans} = \mathrm{'T'}), \\ x & := A^H x \quad (\mathrm{trans} = \mathrm{'C'}). The arguments ``A`` and ``x`` must have the same type (:const:`'d'` or :const:`'z'`). .. function:: cvxopt.blas.tbsv(A, x[, uplo = 'L', trans = 'N', diag = 'N']) Solution of a triangular banded set of linear equations: .. math:: x & := A^{-1}x \quad (\mathrm{trans} = \mathrm{'N'}), \\ x & := A^{-T} x \quad (\mathrm{trans} = \mathrm{'T'}), \\ x & := A^{-H} x \quad (\mathrm{trans} = \mathrm{'T'}), where :math:`A` is a triangular band matrix of with nonzero diagonal elements. The arguments ``A`` and ``x`` must have the same type (:const:`'d'` or :const:`'z'`). .. function:: cvxopt.blas.ger(x, y, A[, alpha = 1.0]) General rank-1 update: .. math:: A := A + \alpha x y^H, where :math:`A` is a general matrix. The arguments ``A``, ``x``, and ``y`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.geru(x, y, A[, alpha = 1.0]) General rank-1 update: .. math:: A := A + \alpha x y^T, where :math:`A` is a general matrix. The arguments ``A``, ``x``, and ``y`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.syr(x, A[, uplo = 'L', alpha = 1.0]) Symmetric rank-1 update: .. math:: A := A + \alpha xx^T, where :math:`A` is a real symmetric matrix. The arguments ``A`` and ``x`` must have type :const:`'d'`. ``alpha`` must be a real number. .. function:: cvxopt.blas.her(x, A[, uplo = 'L', alpha = 1.0]) Hermitian rank-1 update: .. math:: A := A + \alpha xx^H, where :math:`A` is a real symmetric or complex Hermitian matrix. The arguments ``A`` and ``x`` must have the same type (:const:`'d'` or :const:`'z'`). ``alpha`` must be a real number. .. function:: cvxopt.blas.syr2(x, y, A[, uplo = 'L', alpha = 1.0]) Symmetric rank-2 update: .. math:: A := A + \alpha (xy^T + yx^T), where :math:`A` is a real symmetric matrix. The arguments ``A``, ``x``, and ``y`` must have type :const:`'d'`. ``alpha`` must be real. .. function:: cvxopt.blas.her2(x, y, A[, uplo = 'L', alpha = 1.0]) Symmetric rank-2 update: .. math:: A := A + \alpha xy^H + \bar \alpha yx^H, where :math:`A` is a a real symmetric or complex Hermitian matrix. The arguments ``A``, ``x``, and ``y`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` are only allowed if ``A`` is complex. As an example, the following code multiplies the tridiagonal matrix .. math:: A = \left[\begin{array}{rrrr} 1 & 6 & 0 & 0 \\ 2 & -4 & 3 & 0 \\ 0 & -3 & -1 & 1 \end{array}\right] with the vector :math:`x = (1,-1,2,-2)`. >>> from cvxopt import matrix >>> from cvxopt.blas import gbmv >>> A = matrix([[0., 1., 2.], [6., -4., -3.], [3., -1., 0.], [1., 0., 0.]]) >>> x = matrix([1., -1., 2., -2.]) >>> y = matrix(0., (3,1)) >>> gbmv(A, 3, 1, x, y) >>> print(y) [-5.00e+00] [ 1.20e+01] [-1.00e+00] The following example illustrates the use of :func:`tbsv `. >>> from cvxopt import matrix >>> from cvxopt.blas import tbsv >>> A = matrix([-6., 5., -1., 2.], (1,4)) >>> x = matrix(1.0, (4,1)) >>> tbsv(A, x) # x := diag(A)^{-1}*x >>> print(x) [-1.67e-01] [ 2.00e-01] [-1.00e+00] [ 5.00e-01] .. _s-blas-3: Level 3 BLAS ============ The level 3 BLAS include functions for matrix-matrix multiplication. .. function:: cvxopt.blas.gemm(A, B, C[, transA = 'N', transB = 'N', alpha = 1.0, beta = 0.0]) Matrix-matrix product of two general matrices: .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} C := \alpha \op(A) \op(B) + \beta C where .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \op(A) = \left\{ \begin{array}{ll} A & \mathrm{transA} = \mathrm{'N'} \\ A^T & \mathrm{transA} = \mathrm{'T'} \\ A^H & \mathrm{transA} = \mathrm{'C'} \end{array} \right. \qquad \op(B) = \left\{ \begin{array}{ll} B & \mathrm{transB} = \mathrm{'N'} \\ B^T & \mathrm{transB} = \mathrm{'T'} \\ B^H & \mathrm{transB} = \mathrm{'C'}. \end{array} \right. The arguments ``A``, ``B``, and ``C`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.symm(A, B, C[, side = 'L', uplo = 'L', alpha =1.0, beta = 0.0]) Product of a real or complex symmetric matrix :math:`A` and a general matrix :math:`B`: .. math:: C & := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'}), \\ C & := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}). The arguments ``A``, ``B``, and ``C`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.hemm(A, B, C[, side = 'L', uplo = 'L', alpha = 1.0, beta = 0.0]) Product of a real symmetric or complex Hermitian matrix :math:`A` and a general matrix :math:`B`: .. math:: C & := \alpha AB + \beta C \quad (\mathrm{side} = \mathrm{'L'}), \\ C & := \alpha BA + \beta C \quad (\mathrm{side} = \mathrm{'R'}). The arguments ``A``, ``B``, and ``C`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.trmm(A, B[, side = 'L', uplo = 'L', transA = 'N', diag = 'N', alpha = 1.0]) Product of a triangular matrix :math:`A` and a general matrix :math:`B`: .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \begin{split} B & := \alpha\op(A)B \quad (\mathrm{side} = \mathrm{'L'}), \\ B & := \alpha B\op(A) \quad (\mathrm{side} = \mathrm{'R'}) \end{split} where .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \op(A) = \left\{ \begin{array}{ll} A & \mathrm{transA} = \mathrm{'N'} \\ A^T & \mathrm{transA} = \mathrm{'T'} \\ A^H & \mathrm{transA} = \mathrm{'C'}. \end{array} \right. The arguments ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.trsm(A, B[, side = 'L', uplo = 'L', transA = 'N', diag = 'N', alpha = 1.0]) Solution of a nonsingular triangular system of equations: .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \begin{split} B & := \alpha \op(A)^{-1}B \quad (\mathrm{side} = \mathrm{'L'}), \\ B & := \alpha B\op(A)^{-1} \quad (\mathrm{side} = \mathrm{'R'}), \end{split} where .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \op(A) = \left\{ \begin{array}{ll} A & \mathrm{transA} = \mathrm{'N'} \\ A^T & \mathrm{transA} = \mathrm{'T'} \\ A^H & \mathrm{transA} = \mathrm{'C'}, \end{array} \right. :math:`A` is triangular and :math:`B` is a general matrix. The arguments ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.syrk(A, C[, uplo = 'L', trans = 'N', alpha = 1.0, beta = 0.0]) Rank-:math:`k` update of a real or complex symmetric matrix :math:`C`: .. math:: C & := \alpha AA^T + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), \\ C & := \alpha A^TA + \beta C \quad (\mathrm{trans} = \mathrm{'T'}), where :math:`A` is a general matrix. The arguments ``A`` and ``C`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.herk(A, C[, uplo = 'L', trans = 'N', alpha = 1.0, beta = 0.0]) Rank-:math:`k` update of a real symmetric or complex Hermitian matrix :math:`C`: .. math:: C & := \alpha AA^H + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), \\ C & := \alpha A^HA + \beta C \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is a general matrix. The arguments ``A`` and ``C`` must have the same type (:const:`'d'` or :const:`'z'`). ``alpha`` and ``beta`` must be real. .. function:: cvxopt.blas.syr2k(A, B, C[, uplo = 'L', trans = 'N', alpha = 1.0, beta = 0.0]) Rank-:math:`2k` update of a real or complex symmetric matrix :math:`C`: .. math:: C & := \alpha (AB^T + BA^T) + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), \\ C & := \alpha (A^TB + B^TA) + \beta C \quad (\mathrm{trans} = \mathrm{'T'}). :math:`A` and :math:`B` are general real or complex matrices. The arguments ``A``, ``B``, and ``C`` must have the same type. Complex values of ``alpha`` and ``beta`` are only allowed if ``A`` is complex. .. function:: cvxopt.blas.her2k(A, B, C[, uplo = 'L', trans = 'N', alpha = 1.0, beta = 0.0]) Rank-:math:`2k` update of a real symmetric or complex Hermitian matrix :math:`C`: .. math:: C & := \alpha AB^H + \bar \alpha BA^H + \beta C \quad (\mathrm{trans} = \mathrm{'N'}), \\ C & := \alpha A^HB + \bar\alpha B^HA + \beta C \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` and :math:`B` are general matrices. The arguments ``A``, ``B``, and ``C`` must have the same type (:const:`'d'` or :const:`'z'`). Complex values of ``alpha`` are only allowed if ``A`` is complex. ``beta`` must be real. cvxopt-1.1.4/doc/source/coneprog.rst0000644000175000017500000022563711674452555016536 0ustar sonnesonne.. _c-coneprog: **************** Cone Programming **************** In this chapter we consider convex optimization problems of the form .. math:: \begin{array}{ll} \mbox{minimize} & (1/2) x^TPx + q^T x \\ \mbox{subject to} & G x \preceq h \\ & Ax = b. \end{array} The linear inequality is a generalized inequality with respect to a proper convex cone. It may include componentwise vector inequalities, second-order cone inequalities, and linear matrix inequalities. The main solvers are :func:`conelp ` and :func:`coneqp `, described in the sections :ref:`s-conelp` and :ref:`s-coneqp`. The function :func:`conelp` is restricted to problems with linear cost functions, and can detect primal and dual infeasibility. The function :func:`coneqp` solves the general quadratic problem, but requires the problem to be strictly primal and dual feasible. For convenience (and backward compatibility), simpler interfaces to these function are also provided that handle pure linear programs, quadratic programs, second-order cone programs, and semidefinite programs. These are described in the sections :ref:`s-lpsolver`, :ref:`s-qp`, :ref:`s-socpsolver`, :ref:`s-sdpsolver`. In the section :ref:`s-conelp-struct` we explain how custom solvers can be implemented that exploit structure in cone programs. The last two sections describe optional interfaces to external solvers, and the algorithm parameters that control the cone programming solvers. .. _s-conelp: Linear Cone Programs ==================== .. function:: cvxopt.solvers.conelp(c, G, h[, dims[, A, b[, primalstart[, dualstart[, kktsolver]]]]]) Solves a pair of primal and dual cone programs .. math:: \begin{array}[t]{ll} \mbox{minimize} & c^T x \\ \mbox{subject to} & G x + s = h \\ & Ax = b \\ & s \succeq 0 \end{array} \qquad\qquad \begin{array}[t]{ll} \mbox{maximize} & -h^T z - b^T y \\ \mbox{subject to} & G^T z + A^T y + c = 0 \\ & z \succeq 0. \end{array} The primal variables are :math:`x` and :math:`s`. The dual variables are :math:`y`, :math:`z`. The inequalities are interpreted as :math:`s \in C`, :math:`z\in C`, where :math:`C` is a cone defined as a Cartesian product of a nonnegative orthant, a number of second-order cones, and a number of positive semidefinite cones: .. math:: C = C_0 \times C_1 \times \cdots \times C_M \times C_{M+1} \times \cdots \times C_{M+N} with .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \newcommand{\svec}{\mathop{\mathbf{vec}}} \newcommand{\symm}{{\mbox{\bf S}}} \begin{split} C_0 & = \{ u \in \reals^l \;| \; u_k \geq 0, \; k=1, \ldots,l\}, \\ C_{k+1} & = \{ (u_0, u_1) \in \reals \times \reals^{r_{k}-1} \; | \; u_0 \geq \|u_1\|_2 \}, \quad k=0,\ldots, M-1, \\ C_{k+M+1} &= \left\{ \svec(u) \; | \; u \in \symm^{t_k}_+ \right\}, \quad k=0,\ldots,N-1. \end{split} In this definition, :math:`\mathbf{vec}(u)` denotes a symmetric matrix :math:`u` stored as a vector in column major order. The structure of :math:`C` is specified by ``dims``. This argument is a dictionary with three fields. ``dims['l']``: :math:`l`, the dimension of the nonnegative orthant (a nonnegative integer). ``dims['q']``: :math:`[r_0, \ldots, r_{M-1}]`, a list with the dimensions of the second-order cones (positive integers). ``dims['s']``: :math:`[t_0, \ldots, t_{N-1}]`, a list with the dimensions of the positive semidefinite cones (nonnegative integers). The default value of ``dims`` is ``{'l': G.size[0], 'q': [], 's': []}``, i.e., by default the inequality is interpreted as a componentwise vector inequality. The arguments ``c``, ``h``, and ``b`` are real single-column dense matrices. ``G`` and ``A`` are real dense or sparse matrices. The number of rows of ``G`` and ``h`` is equal to .. math:: K = l + \sum_{k=0}^{M-1} r_k + \sum_{k=0}^{N-1} t_k^2. The columns of ``G`` and ``h`` are vectors in .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \reals^l \times \reals^{r_0} \times \cdots \times \reals^{r_{M-1}} \times \reals^{t_0^2} \times \cdots \times \reals^{t_{N-1}^2}, where the last :math:`N` components represent symmetric matrices stored in column major order. The strictly upper triangular entries of these matrices are not accessed (i.e., the symmetric matrices are stored in the :const:`'L'`-type column major order used in the :mod:`blas` and :mod:`lapack` modules). The default values for ``A`` and ``b`` are matrices with zero rows, meaning that there are no equality constraints. ``primalstart`` is a dictionary with keys :const:`'x'` and :const:`'s'`, used as an optional primal starting point. ``primalstart['x']`` and ``primalstart['s']`` are real dense matrices of size (:math:`n`, 1) and (:math:`K`, 1), respectively, where :math:`n` is the length of ``c``. The vector ``primalstart['s']`` must be strictly positive with respect to the cone :math:`C`. ``dualstart`` is a dictionary with keys :const:`'y'` and :const:`'z'`, used as an optional dual starting point. ``dualstart['y']`` and ``dualstart['z']`` are real dense matrices of size (:math:`p`, 1) and (:math:`K`, 1), respectively, where :math:`p` is the number of rows in ``A``. The vector ``dualstart['s']`` must be strictly positive with respect to the cone :math:`C`. The role of the optional argument ``kktsolver`` is explained in the section :ref:`s-conelp-struct`. :func:`conelp` returns a dictionary that contains the result and information about the accuracy of the solution. The most important fields have keys :const:`'status'`, :const:`'x'`, :const:`'s'`, :const:`'y'`, :const:`'z'`. The :const:`'status'` field is a string with possible values :const:`'optimal'`, :const:`'primal infeasible'`, :const:`'dual infeasible'`, and :const:`'unknown'`. The meaning of the :const:`'x'`, :const:`'s'`, :const:`'y'`, :const:`'z'` fields depends on the value of :const:`'status'`. :const:`'optimal'` In this case the :const:`'x'`, :const:`'s'`, :const:`'y'`, and :const:`'z'` entries contain the primal and dual solutions, which approximately satisfy .. math:: Gx + s = h, \qquad Ax = b, \qquad G^T z + A^T y + c = 0, s \succeq 0, \qquad z \succeq 0, \qquad s^T z = 0. The other entries in the output dictionary summarize the accuracy with which these optimality conditions are satisfied. The fields :const:`'primal objective'`, :const:`'dual objective'`, and :const:`'gap'` give the primal objective :math:`c^Tx`, dual objective :math:`-h^Tz - b^Ty`, and the gap :math:`s^Tz`. The field :const:`'relative gap'` is the relative gap, defined as .. math:: \frac{ s^Tz }{ \max\{ -c^Tx, -h^Tz-b^Ty \} } \quad \mbox{if} \quad \max\{ -c^Tx, -h^Tz-b^Ty \} > 0 and :const:`None` otherwise. The fields :const:`'primal infeasibility'` and :const:`'dual infeasibility'` are the residuals in the primal and dual equality constraints, defined as .. math:: \max\{ \frac{ \|Gx+s-h\|_2 }{ \max\{1, \|h\|_2\} }, \frac{ \|Ax-b\|_2 }{ \max\{1,\|b\|_2\} } \}, \qquad \frac{ \|G^Tz + A^Ty + c\|_2 }{ \max\{1, \|c\|_2\} }, respectively. :const:`'primal infeasible'` The :const:`'x'` and :const:`'s'` entries are :const:`None`, and the :const:`'y'`, :const:`'z'` entries provide an approximate certificate of infeasibility, i.e., vectors that approximately satisfy .. math:: G^T z + A^T y = 0, \qquad h^T z + b^T y = -1, \qquad z \succeq 0. The field :const:`'residual as primal infeasibility certificate'` gives the residual .. math:: \frac{ \|G^Tz + A^Ty\|_2 }{ \max\{1, \|c\|_2\} }. :const:`'dual infeasible'` The :const:`'y'` and :const:`'z'` entries are :const:`None`, and the :const:`'x'` and :const:`'s'` entries contain an approximate certificate of dual infeasibility .. math:: Gx + s = 0, \qquad Ax=0, \qquad c^T x = -1, \qquad s \succeq 0. The field :const:`'residual as dual infeasibility certificate'` gives the residual .. math:: \max\{ \frac{ \|Gx + s\|_2 }{ \max\{1, \|h\|_2\} }, \frac{ \|Ax\|_2 }{ \max\{1, \|b\|_2\} } \}. :const:`'unknown'` This indicates that the algorithm terminated early due to numerical difficulties or because the maximum number of iterations was reached. The :const:`'x'`, :const:`'s'`, :const:`'y'`, :const:`'z'` entries contain the iterates when the algorithm terminated. Whether these entries are useful, as approximate solutions or certificates of primal and dual infeasibility, can be determined from the other fields in the dictionary. The fields :const:`'primal objective'`, :const:`'dual objective'`, :const:`'gap'`, :const:`'relative gap'`, :const:`'primal infeasibility'`, :const:`'dual infeasibility'` are defined as when :const:`'status'` is :const:`'optimal'`. The field :const:`'residual as primal infeasibility certificate'` is defined as .. math:: \frac{ \|G^Tz+A^Ty\|_2 }{ -(h^Tz + b^Ty) \max\{1, \|h\|_2 \} }. if :math:`h^Tz+b^Ty < 0`, and :const:`None` otherwise. A small value of this residual indicates that :math:`y` and :math:`z`, divided by :math:`-h^Tz-b^Ty`, are an approximate proof of primal infeasibility. The field :const:`'residual as dual infeasibility certificate'` is defined as .. math:: \max\{ \frac{ \|Gx+s\|_2 }{ -c^Tx \max\{ 1, \|h\|_2 \} }, \frac{ \|Ax\|_2 }{ -c^Tx \max\{1,\|b\|_2\} }\} if :math:`c^Tx < 0`, and as :const:`None` otherwise. A small value indicates that :math:`x` and :math:`s`, divided by :math:`-c^Tx` are an approximate proof of dual infeasibility. It is required that .. math:: \newcommand{\Rank}{\mathop{\bf rank}} \Rank(A) = p, \qquad \Rank(\left[\begin{array}{c} G \\ A \end{array}\right]) = n, where :math:`p` is the number or rows of :math:`A` and :math:`n` is the number of columns of :math:`G` and :math:`A`. As an example we solve the problem .. math:: \begin{array}{ll} \mbox{minimize} & -6x_1 - 4x_2 - 5x_3 \\*[1ex] \mbox{subject to} & 16x_1 - 14x_2 + 5x_3 \leq -3 \\*[1ex] & 7x_1 + 2x_2 \leq 5 \\*[1ex] & \left\| \left[ \begin{array}{c} 8x_1 + 13x_2 - 12x_3 - 2 \\ -8x_1 + 18x_2 + 6x_3 - 14 \\ x_1 - 3x_2 - 17x_3 - 13 \end{array}\right] \right\|_2 \leq -24x_1 - 7x_2 + 15x_3 + 12 \\*[3ex] & \left\| \left[ \begin{array}{c} x_1 \\ x_2 \\ x_3 \end{array} \right] \right\|_2 \leq 10 \\*[3ex] & \left[\begin{array}{ccc} 7x_1 + 3x_2 + 9x_3 & -5x_1 + 13x_2 + 6x_3 & x_1 - 6x_2 - 6x_3\\ -5x_1 + 13x_2 + 6x_3 & x_1 + 12x_2 - 7x_3 & -7x_1 -10x_2 - 7x_3\\ x_1 - 6x_2 -6x_3 & -7x_1 -10x_2 -7 x_3 & -4x_1 -28 x_2 -11x_3 \end{array}\right] \preceq \left[\begin{array}{ccc} 68 & -30 & -19 \\ -30 & 99 & 23 \\ -19 & 23 & 10 \end{array}\right]. \end{array} >>> from cvxopt import matrix, solvers >>> c = matrix([-6., -4., -5.]) >>> G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4.], [-14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28.], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11.]]) >>> h = matrix( [ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10.] ) >>> dims = {'l': 2, 'q': [4, 4], 's': [3]} >>> sol = solvers.conelp(c, G, h, dims) >>> sol['status'] 'optimal' >>> print(sol['x']) [-1.22e+00] [ 9.66e-02] [ 3.58e+00] >>> print(sol['z']) [ 9.30e-02] [ 2.04e-08] [ 2.35e-01] [ 1.33e-01] [-4.74e-02] [ 1.88e-01] [ 2.79e-08] [ 1.85e-09] [-6.32e-10] [-7.59e-09] [ 1.26e-01] [ 8.78e-02] [-8.67e-02] [ 8.78e-02] [ 6.13e-02] [-6.06e-02] [-8.67e-02] [-6.06e-02] [ 5.98e-02] Only the entries of ``G`` and ``h`` defining the lower triangular portions of the coefficients in the linear matrix inequalities are accessed. We obtain the same result if we define ``G`` and ``h`` as below. >>> G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., 0., 1., -7., 0., 0., -4.], [-14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 0., 12., -10., 0., 0., -28.], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 0., -7., -7., 0., 0., -11.]]) >>> h = matrix( [ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., 0., 99., 23., 0., 0., 10.] ) .. _s-coneqp: Quadratic Cone Programs ======================= .. function:: cvxopt.solvers.coneqp(P, q[, G, h[, dims[, A, b[, initvals[, kktsolver]]]]]) Solves a pair of primal and dual quadratic cone programs .. math:: \begin{array}[t]{ll} \mbox{minimize} & (1/2) x^T Px + q^T x \\ \mbox{subject to} & G x + s = h \\ & Ax = b \\ & s \succeq 0 \end{array} and .. math:: \newcommand{\Range}{\mbox{\textrm{range}}} \begin{array}[t]{ll} \mbox{maximize} & -(1/2) (q+G^Tz+A^Ty)^T P^\dagger (q+G^Tz+A^Ty) -h^T z - b^T y \\ \mbox{subject to} & q + G^T z + A^T y \in \Range(P) \\ & z \succeq 0. \end{array} The primal variables are :math:`x` and the slack variable :math:`s`. The dual variables are :math:`y` and :math:`z`. The inequalities are interpreted as :math:`s \in C`, :math:`z\in C`, where :math:`C` is a cone defined as a Cartesian product of a nonnegative orthant, a number of second-order cones, and a number of positive semidefinite cones: .. math:: C = C_0 \times C_1 \times \cdots \times C_M \times C_{M+1} \times \cdots \times C_{M+N} with .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \newcommand{\svec}{\mathop{\mathbf{vec}}} \newcommand{\symm}{{\mbox{\bf S}}} \begin{split} C_0 & = \{ u \in \reals^l \;| \; u_k \geq 0, \; k=1, \ldots,l\}, \\ C_{k+1} & = \{ (u_0, u_1) \in \reals \times \reals^{r_{k}-1} \; | \; u_0 \geq \|u_1\|_2 \}, \quad k=0,\ldots, M-1, \\ C_{k+M+1} &= \left\{ \svec(u) \; | \; u \in \symm^{t_k}_+ \right\}, \quad k=0,\ldots,N-1. \end{split} In this definition, :math:`\mathbf{vec}(u)` denotes a symmetric matrix :math:`u` stored as a vector in column major order. The structure of :math:`C` is specified by ``dims``. This argument is a dictionary with three fields. ``dims['l']``: :math:`l`, the dimension of the nonnegative orthant (a nonnegative integer). ``dims['q']``: :math:`[r_0, \ldots, r_{M-1}]`, a list with the dimensions of the second-order cones (positive integers). ``dims['s']``: :math:`[t_0, \ldots, t_{N-1}]`, a list with the dimensions of the positive semidefinite cones (nonnegative integers). The default value of ``dims`` is ``{'l': G.size[0], 'q': [], 's': []}``, i.e., by default the inequality is interpreted as a componentwise vector inequality. ``P`` is a square dense or sparse real matrix, representing a positive semidefinite symmetric matrix in :const:`'L'` storage, i.e., only the lower triangular part of ``P`` is referenced. ``q`` is a real single-column dense matrix. The arguments ``h`` and ``b`` are real single-column dense matrices. ``G`` and ``A`` are real dense or sparse matrices. The number of rows of ``G`` and ``h`` is equal to .. math:: K = l + \sum_{k=0}^{M-1} r_k + \sum_{k=0}^{N-1} t_k^2. The columns of ``G`` and ``h`` are vectors in .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \reals^l \times \reals^{r_0} \times \cdots \times \reals^{r_{M-1}} \times \reals^{t_0^2} \times \cdots \times \reals^{t_{N-1}^2}, where the last :math:`N` components represent symmetric matrices stored in column major order. The strictly upper triangular entries of these matrices are not accessed (i.e., the symmetric matrices are stored in the :const:`'L'`-type column major order used in the :mod:`blas` and :mod:`lapack` modules). The default values for ``G``, ``h``, ``A``, and ``b`` are matrices with zero rows, meaning that there are no inequality or equality constraints. ``initvals`` is a dictionary with keys :const:`'x'`, :const:`'s'`, :const:`'y'`, :const:`'z'` used as an optional starting point. The vectors ``initvals['s']`` and ``initvals['z']`` must be strictly positive with respect to the cone :math:`C`. If the argument ``initvals`` or any the four entries in it are missing, default starting points are used for the corresponding variables. The role of the optional argument ``kktsolver`` is explained in the section :ref:`s-conelp-struct`. :func:`coneqp` returns a dictionary that contains the result and information about the accuracy of the solution. The most important fields have keys :const:`'status'`, :const:`'x'`, :const:`'s'`, :const:`'y'`, :const:`'z'`. The :const:`'status'` field is a string with possible values :const:`'optimal'` and :const:`'unknown'`. :const:`'optimal'` In this case the :const:`'x'`, :const:`'s'`, :const:`'y'`, and :const:`'z'` entries contain primal and dual solutions, which approximately satisfy .. math:: Gx+s = h, \qquad Ax = b, \qquad Px + G^Tz + A^T y + q = 0, s \succeq 0, \qquad z \succeq 0, \qquad s^T z = 0. :const:`'unknown'` This indicates that the algorithm terminated early due to numerical difficulties or because the maximum number of iterations was reached. The :const:`'x'`, :const:`'s'`, :const:`'y'`, :const:`'z'` entries contain the iterates when the algorithm terminated. The other entries in the output dictionary summarize the accuracy with which the optimality conditions are satisfied. The fields :const:`'primal objective'`, :const:`'dual objective'`, and :const:`'gap'` give the primal objective :math:`c^Tx`, the dual objective calculated as .. math:: (1/2) x^TPx + q^T x + z^T(Gx-h) + y^T(Ax-b) and the gap :math:`s^Tz`. The field :const:`'relative gap'` is the relative gap, defined as .. math:: \frac{s^Tz}{-\mbox{primal objective}} \quad \mbox{if\ } \mbox{primal objective} < 0, \qquad \frac{s^Tz}{\mbox{dual objective}} \quad \mbox{if\ } \mbox{dual objective} > 0, \qquad and :const:`None` otherwise. The fields :const:`'primal infeasibility'` and :const:`'dual infeasibility'` are the residuals in the primal and dual equality constraints, defined as .. math:: \max\{ \frac{\|Gx+s-h\|_2}{\max\{1, \|h\|_2\}}, \frac{\|Ax-b\|_2}{\max\{1,\|b\|_2\}} \}, \qquad \frac{\|Px + G^Tz + A^Ty + q\|_2}{\max\{1, \|q\|_2\}}, respectively. It is required that the problem is solvable and that .. math:: \newcommand{\Rank}{\mathop{\bf rank}} \Rank(A) = p, \qquad \Rank(\left[\begin{array}{c} P \\ G \\ A \end{array}\right]) = n, where :math:`p` is the number or rows of :math:`A` and :math:`n` is the number of columns of :math:`G` and :math:`A`. As an example, we solve a constrained least-squares problem .. math:: \begin{array}{ll} \mbox{minimize} & \|Ax - b\|_2^2 \\ \mbox{subject to} & x \succeq 0 \\ & \|x\|_2 \leq 1 \end{array} with .. math:: A = \left[ \begin{array}{rrr} 0.3 & 0.6 & -0.3 \\ -0.4 & 1.2 & 0.0 \\ -0.2 & -1.7 & 0.6 \\ -0.4 & 0.3 & -1.2 \\ 1.3 & -0.3 & -2.0 \end{array} \right], \qquad b = \left[ \begin{array}{r} 1.5 \\ 0.0 \\ -1.2 \\ -0.7 \\ 0.0 \end{array} \right]. >>> from cvxopt import matrix, solvers >>> A = matrix([ [ .3, -.4, -.2, -.4, 1.3 ], [ .6, 1.2, -1.7, .3, -.3 ], [-.3, .0, .6, -1.2, -2.0 ] ]) >>> b = matrix([ 1.5, .0, -1.2, -.7, .0]) >>> m, n = A.size >>> I = matrix(0.0, (n,n)) >>> I[::n+1] = 1.0 >>> G = matrix([-I, matrix(0.0, (1,n)), I]) >>> h = matrix(n*[0.0] + [1.0] + n*[0.0]) >>> dims = {'l': n, 'q': [n+1], 's': []} >>> x = solvers.coneqp(A.T*A, -A.T*b, G, h, dims)['x'] >>> print(x) [ 7.26e-01] [ 6.18e-01] [ 3.03e-01] .. _s-lpsolver: Linear Programming ================== The function :func:`lp ` is an interface to :func:`conelp ` for linear programs. It also provides the option of using the linear programming solvers from GLPK or MOSEK. .. function:: cvxopt.solvers.lp(c, G, h[, A, b[, solver[, primalstart[, dualstart]]]]) Solves the pair of primal and dual linear programs .. math:: \begin{array}[t]{ll} \mbox{minimize} & c^T x \\ \mbox{subject to} & G x + s = h \\ & Ax = b \\ & s \succeq 0 \end{array} \qquad\qquad \begin{array}[t]{ll} \mbox{maximize} & -h^T z - b^T y \\ \mbox{subject to} & G^T z + A^T y + c = 0 \\ & z \succeq 0. \end{array} The inequalities are componentwise vector inequalities. The ``solver`` argument is used to choose among three solvers. When it is omitted or :const:`None`, the CVXOPT function :func:`conelp ` is used. The external solvers GLPK and MOSEK (if installed) can be selected by setting ``solver`` to :const:`'glpk'` or :const:`'mosek'`; see the section :ref:`s-external`. The meaning of the other arguments and the return value are the same as for :func:`conelp` called with ``dims`` equal to ``{'l': G.size[0], 'q': [], 's': []}``. The initial values are ignored when ``solver`` is :const:`'mosek'` or :const:`'glpk'`. With the GLPK option, the solver does not return certificates of primal or dual infeasibility: if the status is :const:`'primal infeasible'` or :const:`'dual infeasible'`, all entries of the output dictionary are :const:`None`. If the GLPK or MOSEK solvers are used, and the code returns with status :const:`'unknown'`, all the other fields in the output dictionary are :const:`None`. As a simple example we solve the LP .. math:: \begin{array}[t]{ll} \mbox{minimize} & -4x_1 - 5x_2 \\ \mbox{subject to} & 2x_1 + x_2 \leq 3 \\ & x_1 + 2x_2 \leq 3 \\ & x_1 \geq 0, \quad x_2 \geq 0. \end{array} >>> from cvxopt import matrix, solvers >>> c = matrix([-4., -5.]) >>> G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]]) >>> h = matrix([3., 3., 0., 0.]) >>> sol = solvers.lp(c, G, h) >>> print(sol['x']) [ 1.00e+00] [ 1.00e+00] .. _s-qp: Quadratic Programming ===================== The function :func:`qp ` is an interface to :func:`coneqp ` for quadratic programs. It also provides the option of using the quadratic programming solver from MOSEK. .. function:: cvxopt.solvers.qp(P, q[, G, h[, A, b[, solver[, initvals]]]]) Solves the pair of primal and dual convex quadratic programs .. math:: \begin{array}[t]{ll} \mbox{minimize} & (1/2) x^TPx + q^T x \\ \mbox{subject to} & Gx \preceq h \\ & Ax = b \end{array} and .. math:: \newcommand{\Range}{\mbox{\textrm{range}}} \begin{array}[t]{ll} \mbox{maximize} & -(1/2) (q+G^Tz+A^Ty)^T P^\dagger (q+G^Tz+A^Ty) -h^T z - b^T y \\ \mbox{subject to} & q + G^T z + A^T y \in \Range(P) \\ & z \succeq 0. \end{array} The inequalities are componentwise vector inequalities. The default CVXOPT solver is used when the ``solver`` argument is absent or :const:`None`. The MOSEK solver (if installed) can be selected by setting ``solver`` to :const:`'mosek'`; see the section :ref:`s-external`. The meaning of the other arguments and the return value is the same as for :func:`coneqp ` called with `dims` equal to ``{'l': G.size[0], 'q': [], 's': []}``. When ``solver`` is :const:`'mosek'`, the initial values are ignored, and the :const:`'status'` string in the solution dictionary can take four possible values: :const:`'optimal'`, :const:`'unknown'`. :const:`'primal infeasible'`, :const:`'dual infeasible'`. :const:`'primal infeasible'` This means that a certificate of primal infeasibility has been found. The :const:`'x'` and :const:`'s'` entries are :const:`None`, and the :const:`'z'` and :const:`'y'` entries are vectors that approximately satisfy .. math:: G^Tz + A^T y = 0, \qquad h^Tz + b^Ty = -1, \qquad z \succeq 0. :const:`'dual infeasible'` This means that a certificate of dual infeasibility has been found. The :const:`'z'` and :const:`'y'` entries are :const:`None`, and the :const:`'x'` and :const:`'s'` entries are vectors that approximately satisfy .. math:: Px = 0, \qquad q^Tx = -1, \qquad Gx + s = 0, \qquad Ax=0, \qquad s \succeq 0. As an example we compute the trade-off curve on page 187 of the book `Convex Optimization `_, by solving the quadratic program .. math:: \newcommand{\ones}{{\bf 1}} \begin{array}{ll} \mbox{minimize} & -\bar p^T x + \mu x^T S x \\ \mbox{subject to} & \ones^T x = 1, \quad x \succeq 0 \end{array} for a sequence of positive values of :math:`\mu`. The code below computes the trade-off curve and produces two figures using the `Matplotlib `_ package. .. image:: portfolio2.png :width: 400px .. image:: portfolio1.png :width: 400px :: from math import sqrt from cvxopt import matrix from cvxopt.blas import dot from cvxopt.solvers import qp import pylab # Problem data. n = 4 S = matrix([[ 4e-2, 6e-3, -4e-3, 0.0 ], [ 6e-3, 1e-2, 0.0, 0.0 ], [-4e-3, 0.0, 2.5e-3, 0.0 ], [ 0.0, 0.0, 0.0, 0.0 ]]) pbar = matrix([.12, .10, .07, .03]) G = matrix(0.0, (n,n)) G[::n+1] = -1.0 h = matrix(0.0, (n,1)) A = matrix(1.0, (1,n)) b = matrix(1.0) # Compute trade-off. N = 100 mus = [ 10**(5.0*t/N-1.0) for t in range(N) ] portfolios = [ qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus ] returns = [ dot(pbar,x) for x in portfolios ] risks = [ sqrt(dot(x, S*x)) for x in portfolios ] # Plot trade-off curve and optimal allocations. pylab.figure(1, facecolor='w') pylab.plot(risks, returns) pylab.xlabel('standard deviation') pylab.ylabel('expected return') pylab.axis([0, 0.2, 0, 0.15]) pylab.title('Risk-return trade-off curve (fig 4.12)') pylab.yticks([0.00, 0.05, 0.10, 0.15]) pylab.figure(2, facecolor='w') c1 = [ x[0] for x in portfolios ] c2 = [ x[0] + x[1] for x in portfolios ] c3 = [ x[0] + x[1] + x[2] for x in portfolios ] c4 = [ x[0] + x[1] + x[2] + x[3] for x in portfolios ] pylab.fill(risks + [.20], c1 + [0.0], '#F0F0F0') pylab.fill(risks[-1::-1] + risks, c2[-1::-1] + c1, facecolor = '#D0D0D0') pylab.fill(risks[-1::-1] + risks, c3[-1::-1] + c2, facecolor = '#F0F0F0') pylab.fill(risks[-1::-1] + risks, c4[-1::-1] + c3, facecolor = '#D0D0D0') pylab.axis([0.0, 0.2, 0.0, 1.0]) pylab.xlabel('standard deviation') pylab.ylabel('allocation') pylab.text(.15,.5,'x1') pylab.text(.10,.7,'x2') pylab.text(.05,.7,'x3') pylab.text(.01,.7,'x4') pylab.title('Optimal allocations (fig 4.12)') pylab.show() .. _s-socpsolver: Second-Order Cone Programming ============================= The function :func:`socp ` is a simpler interface to :func:`conelp ` for cone programs with no linear matrix inequality constraints. .. function:: cvxopt.solvers.socp(c[, Gl, hl[, Gq, hq[, A, b[, solver[, primalstart[, dualstart]]]]]]) Solves the pair of primal and dual second-order cone programs .. math:: \begin{array}[t]{ll} \mbox{minimize} & c^T x \\ \mbox{subject to} & G_k x + s_k = h_k, \quad k = 0, \ldots, M \\ & Ax = b \\ & s_0 \succeq 0 \\ & s_{k0} \geq \|s_{k1}\|_2, \quad k = 1,\ldots,M \end{array} and .. math:: \begin{array}[t]{ll} \mbox{maximize} & - \sum_{k=0}^M h_k^Tz_k - b^T y \\ \mbox{subject to} & \sum_{k=0}^M G_k^T z_k + A^T y + c = 0 \\ & z_0 \succeq 0 \\ & z_{k0} \geq \|z_{k1}\|_2, \quad k=1,\ldots,M. \end{array} The inequalities .. math:: s_0 \succeq 0, \qquad z_0 \succeq 0 are componentwise vector inequalities. In the other inequalities, it is assumed that the variables are partitioned as .. math:: \newcommand{\reals}{{\mbox{\bf R}}} s_k = (s_{k0}, s_{k1}) \in\reals\times\reals^{r_{k}-1}, \qquad z_k = (z_{k0}, z_{k1}) \in\reals\times\reals^{r_{k}-1}, \qquad k=1,\ldots,M. The input argument ``c`` is a real single-column dense matrix. The arguments ``Gl`` and ``hl`` are the coefficient matrix :math:`G_0` and the right-hand side :math:`h_0` of the componentwise inequalities. ``Gl`` is a real dense or sparse matrix; ``hl`` is a real single-column dense matrix. The default values for ``Gl`` and ``hl`` are matrices with zero rows. The argument ``Gq`` is a list of :math:`M` dense or sparse matrices :math:`G_1`, ..., :math:`G_M`. The argument ``hq`` is a list of :math:`M` dense single-column matrices :math:`h_1`, \ldots, :math:`h_M`. The elements of ``Gq`` and ``hq`` must have at least one row. The default values of ``Gq`` and ``hq`` are empty lists. ``A`` is dense or sparse matrix and ``b`` is a single-column dense matrix. The default values for ``A`` and ``b`` are matrices with zero rows. The ``solver`` argument is used to choose between two solvers: the CVXOPT :func:`conelp ` solver (used when ``solver`` is absent or equal to :const:`None` and the external solver MOSEK (``solver`` is :const:`'mosek'`); see the section :ref:`s-external`. With the :const:`'mosek'` option the code does not accept problems with equality constraints. ``primalstart`` and ``dualstart`` are dictionaries with optional primal, respectively, dual starting points. ``primalstart`` has elements :const:`'x'`, :const:`'sl'`, :const:`'sq'`. ``primalstart['x']`` and ``primalstart['sl']`` are single-column dense matrices with the initial values of :math:`x` and :math:`s_0`; ``primalstart['sq']`` is a list of single-column matrices with the initial values of :math:`s_1`, \ldots, :math:`s_M`. The initial values must satisfy the inequalities in the primal problem strictly, but not necessarily the equality constraints. ``dualstart`` has elements :const:`'y'`, :const:`'zl'`, :const:`'zq'`. ``dualstart['y']`` and ``dualstart['zl']`` are single-column dense matrices with the initial values of :math:`y` and :math:`z_0`. ``dualstart['zq']`` is a list of single-column matrices with the initial values of :math:`z_1`, \ldots, :math:`z_M`. These values must satisfy the dual inequalities strictly, but not necessarily the equality constraint. The arguments ``primalstart`` and ``dualstart`` are ignored when the MOSEK solver is used. :func:`socp` returns a dictionary that include entries with keys :const:`'status'`, :const:`'x'`, :const:`'sl'`, :const:`'sq'`, :const:`'y'`, :const:`'zl'`, :const:`'zq'`. The :const:`'sl'` and :const:`'zl'` fields are matrices with the primal slacks and dual variables associated with the componentwise linear inequalities. The :const:`'sq'` and :const:`'zq'` fields are lists with the primal slacks and dual variables associated with the second-order cone inequalities. The other entries in the output dictionary have the same meaning as in the output of :func:`conelp `. As an example, we solve the second-order cone program .. math:: \begin{array}{ll} \mbox{minimize} & -2x_1 + x_2 + 5x_3 \\*[2ex] \mbox{subject to} & \left\| \left[\begin{array}{c} -13 x_1 + 3 x_2 + 5 x_3 - 3 \\ -12 x_1 + 12 x_2 - 6 x_3 - 2 \end{array}\right] \right\|_2 \leq -12 x_1 - 6 x_2 + 5x_3 - 12 \\*[2ex] & \left\| \left[\begin{array}{c} -3 x_1 + 6 x_2 + 2 x_3 \\ x_1 + 9 x_2 + 2 x_3 + 3 \\ -x_1 - 19 x_2 + 3 x_3 - 42 \end{array}\right] \right\|_2 \leq -3x_1 + 6x_2 - 10x_3 + 27. \end{array} >>> from cvxopt import matrix, solvers >>> c = matrix([-2., 1., 5.]) >>> G = [ matrix( [[12., 13., 12.], [6., -3., -12.], [-5., -5., 6.]] ) ] >>> G += [ matrix( [[3., 3., -1., 1.], [-6., -6., -9., 19.], [10., -2., -2., -3.]] ) ] >>> h = [ matrix( [-12., -3., -2.] ), matrix( [27., 0., 3., -42.] ) ] >>> sol = solvers.socp(c, Gq = G, hq = h) >>> sol['status'] optimal >>> print(sol['x']) [-5.02e+00] [-5.77e+00] [-8.52e+00] >>> print(sol['zq'][0]) [ 1.34e+00] [-7.63e-02] [-1.34e+00] >>> print(sol['zq'][1]) [ 1.02e+00] [ 4.02e-01] [ 7.80e-01] [-5.17e-01] .. _s-sdpsolver: Semidefinite Programming ======================== The function :func:`sdp ` is a simple interface to :func:`conelp ` for cone programs with no second-order cone constraints. It also provides the option of using the DSDP semidefinite programming solver. .. function:: cvxopt.solvers.sdp(c[, Gl, hl[, Gs, hs[, A, b[, solver[, primalstart[, dualstart]]]]]]) Solves the pair of primal and dual semidefinite programs .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} \begin{array}[t]{ll} \mbox{minimize} & c^T x \\ \mbox{subject to} & G_0 x + s_0 = h_0 \\ & G_k x + \svec{(s_k)} = \svec{(h_k)}, \quad k = 1, \ldots, N \\ & Ax = b \\ & s_0 \succeq 0 \\ & s_k \succeq 0, \quad k=1,\ldots,N \end{array} and .. math:: \newcommand{\Tr}{\mathop{\mathbf{tr}}} \newcommand{\svec}{\mathop{\mathbf{vec}}} \begin{array}[t]{ll} \mbox{maximize} & -h_0^Tz_0 - \sum_{k=1}^N \Tr(h_kz_k) - b^Ty \\ \mbox{subject to} & G_0^Tz_0 + \sum_{k=1}^N G_k^T \svec(z_k) + A^T y + c = 0 \\ & z_0 \succeq 0 \\ & z_k \succeq 0, \quad k=1,\ldots,N. \end{array} The inequalities .. math:: s_0 \succeq 0, \qquad z_0 \succeq 0 are componentwise vector inequalities. The other inequalities are matrix inequalities (\ie, the require the left-hand sides to be positive semidefinite). We use the notation :math:`\mathbf{vec}(z)` to denote a symmetric matrix :math:`z` stored in column major order as a column vector. The input argument ``c`` is a real single-column dense matrix. The arguments ``Gl`` and ``hl`` are the coefficient matrix :math:`G_0` and the right-hand side :math:`h_0` of the componentwise inequalities. ``Gl`` is a real dense or sparse matrix; ``hl`` is a real single-column dense matrix. The default values for ``Gl`` and ``hl`` are matrices with zero rows. ``Gs`` and ``hs`` are lists of length :math:`N` that specify the linear matrix inequality constraints. ``Gs`` is a list of :math:`N` dense or sparse real matrices :math:`G_1`, \ldots, :math:`G_M`. The columns of these matrices can be interpreted as symmetric matrices stored in column major order, using the BLAS :const:`'L'`-type storage (i.e., only the entries corresponding to lower triangular positions are accessed). ``hs`` is a list of :math:`N` dense symmetric matrices :math:`h_1`, \ldots, :math:`h_N`. Only the lower triangular elements of these matrices are accessed. The default values for ``Gs`` and ``hs`` are empty lists. ``A`` is a dense or sparse matrix and ``b`` is a single-column dense matrix. The default values for ``A`` and ``b`` are matrices with zero rows. The ``solver`` argument is used to choose between two solvers: the CVXOPT :func:`conelp ` solver (used when ``solver`` is absent or equal to :const:`None`) and the external solver DSDP5 (``solver`` is :const:`'dsdp'`); see the section :ref:`s-external`. With the :const:`'dsdp'` option the code does not accept problems with equality constraints. The optional argument ``primalstart`` is a dictionary with keys :const:`'x'`, :const:`'sl'`, and :const:`'ss'`, used as an optional primal starting point. ``primalstart['x']`` and ``primalstart['sl']`` are single-column dense matrices with the initial values of :math:`x` and :math:`s_0`; ``primalstart['ss']`` is a list of square matrices with the initial values of :math:`s_1`, \ldots, :math:`s_N`. The initial values must satisfy the inequalities in the primal problem strictly, but not necessarily the equality constraints. ``dualstart`` is a dictionary with keys :const:`'y'`, :const:`'zl'`, :const:`'zs'`, used as an optional dual starting point. ``dualstart['y']`` and ``dualstart['zl']`` are single-column dense matrices with the initial values of :math:`y` and :math:`z_0`. ``dualstart['zs']`` is a list of square matrices with the initial values of :math:`z_1`, \ldots, :math:`z_N`. These values must satisfy the dual inequalities strictly, but not necessarily the equality constraint. The arguments ``primalstart`` and ``dualstart`` are ignored when the DSDP solver is used. :func:`sdp` returns a dictionary that includes entries with keys :const:`'status'`, :const:`'x'`, :const:`'sl'`, :const:`'ss'`, :const:`'y'`, :const:`'zl'`, :const:`'ss'`. The :const:`'sl'` and :const:`'zl'` fields are matrices with the primal slacks and dual variables associated with the componentwise linear inequalities. The :const:`'ss'` and :const:`'zs'` fields are lists with the primal slacks and dual variables associated with the second-order cone inequalities. The other entries in the output dictionary have the same meaning as in the output of :func:`conelp `. We illustrate the calling sequence with a small example. .. math:: \begin{array}{ll} \mbox{minimize} & x_1 - x_2 + x_3 \\ \mbox{subject to} & x_1 \left[ \begin{array}{cc} -7 & -11 \\ -11 & 3 \end{array}\right] + x_2 \left[ \begin{array}{cc} 7 & -18 \\ -18 & 8 \end{array}\right] + x_3 \left[ \begin{array}{cc} -2 & -8 \\ -8 & 1 \end{array}\right] \preceq \left[ \begin{array}{cc} 33 & -9 \\ -9 & 26 \end{array}\right] \\*[1ex] & x_1 \left[ \begin{array}{ccc} -21 & -11 & 0 \\ -11 & 10 & 8 \\ 0 & 8 & 5 \end{array}\right] + x_2 \left[ \begin{array}{ccc} 0 & 10 & 16 \\ 10 & -10 & -10 \\ 16 & -10 & 3 \end{array}\right] + x_3 \left[ \begin{array}{ccc} -5 & 2 & -17 \\ 2 & -6 & -7 \\ -17 & 8 & 6 \end{array}\right] \preceq \left[ \begin{array}{ccc} 14 & 9 & 40 \\ 9 & 91 & 10 \\ 40 & 10 & 15 \end{array} \right] \end{array} >>> from cvxopt import matrix, solvers >>> c = matrix([1.,-1.,1.]) >>> G = [ matrix([[-7., -11., -11., 3.], [ 7., -18., -18., 8.], [-2., -8., -8., 1.]]) ] >>> G += [ matrix([[-21., -11., 0., -11., 10., 8., 0., 8., 5.], [ 0., 10., 16., 10., -10., -10., 16., -10., 3.], [ -5., 2., -17., 2., -6., 8., -17., -7., 6.]]) ] >>> h = [ matrix([[33., -9.], [-9., 26.]]) ] >>> h += [ matrix([[14., 9., 40.], [9., 91., 10.], [40., 10., 15.]]) ] >>> sol = solvers.sdp(c, Gs=G, hs=h) >>> print(sol['x']) [-3.68e-01] [ 1.90e+00] [-8.88e-01] >>> print(sol['zs'][0]) [ 3.96e-03 -4.34e-03] [-4.34e-03 4.75e-03] >>> print(sol['zs'][1]) [ 5.58e-02 -2.41e-03 2.42e-02] [-2.41e-03 1.04e-04 -1.05e-03] [ 2.42e-02 -1.05e-03 1.05e-02] Only the entries in ``Gs`` and ``hs`` that correspond to lower triangular entries need to be provided, so in the example ``h`` and ``G`` may also be defined as follows. >>> G = [ matrix([[-7., -11., 0., 3.], [ 7., -18., 0., 8.], [-2., -8., 0., 1.]]) ] >>> G += [ matrix([[-21., -11., 0., 0., 10., 8., 0., 0., 5.], [ 0., 10., 16., 0., -10., -10., 0., 0., 3.], [ -5., 2., -17., 0., -6., 8., 0., 0., 6.]]) ] >>> h = [ matrix([[33., -9.], [0., 26.]]) ] >>> h += [ matrix([[14., 9., 40.], [0., 91., 10.], [0., 0., 15.]]) ] .. _s-conelp-struct: Exploiting Structure ==================== By default, the functions :func:`conelp ` and :func:`coneqp ` exploit no problem structure except (to some limited extent) sparsity. Two mechanisms are provided for implementing customized solvers that take advantage of problem structure. **Providing a function for solving KKT equations** The most expensive step of each iteration of :func:`conelp ` or :func:`coneqp ` is the solution of a set of linear equations (*KKT equations*) of the form .. math:: :label: e-conelp-kkt \left[\begin{array}{ccc} P & A^T & G^T \\ A & 0 & 0 \\ G & 0 & -W^T W \end{array}\right] \left[\begin{array}{c} u_x \\ u_y \\ u_z \end{array}\right] = \left[\begin{array}{c} b_x \\ b_y \\ b_z \end{array}\right] (with :math:`P = 0` in :func:`conelp`). The matrix :math:`W` depends on the current iterates and is defined as follows. We use the notation of the sections :ref:`s-conelp` and :ref:`s-coneqp`. Let .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} u = \left(u_\mathrm{l}, \; u_{\mathrm{q},0}, \; \ldots, \; u_{\mathrm{q},M-1}, \; \svec{(u_{\mathrm{s},0})}, \; \ldots, \; \svec{(u_{\mathrm{s},N-1})}\right), \qquad \newcommand{\reals}{{\mbox{\bf R}}} \newcommand{\symm}{{\mbox{\bf S}}} u_\mathrm{l} \in\reals^l, \qquad u_{\mathrm{q},k} \in\reals^{r_k}, \quad k = 0,\ldots,M-1, \qquad u_{\mathrm{s},k} \in\symm^{t_k}, \quad k = 0,\ldots,N-1. Then :math:`W` is a block-diagonal matrix, .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} Wu = \left( W_\mathrm{l} u_\mathrm{l}, \; W_{\mathrm{q},0} u_{\mathrm{q},0}, \; \ldots, \; W_{\mathrm{q},M-1} u_{\mathrm{q},M-1},\; W_{\mathrm{s},0} \svec{(u_{\mathrm{s},0})}, \; \ldots, \; W_{\mathrm{s},N-1} \svec{(u_{\mathrm{s},N-1})} \right) with the following diagonal blocks. * The first block is a *positive diagonal scaling* with a vector :math:`d`: .. math:: \newcommand{\diag}{\mbox{\bf diag}\,} W_\mathrm{l} = \diag(d), \qquad W_\mathrm{l}^{-1} = \diag(d)^{-1}. This transformation is symmetric: .. math:: W_\mathrm{l}^T = W_\mathrm{l}. * The next :math:`M` blocks are positive multiples of *hyperbolic Householder transformations*: .. math:: W_{\mathrm{q},k} = \beta_k ( 2 v_k v_k^T - J), \qquad W_{\mathrm{q},k}^{-1} = \frac{1}{\beta_k} ( 2 Jv_k v_k^T J - J), \qquad k = 0,\ldots,M-1, where .. math:: \beta_k > 0, \qquad v_{k0} > 0, \qquad v_k^T Jv_k = 1, \qquad J = \left[\begin{array}{cc} 1 & 0 \\ 0 & -I \end{array}\right]. These transformations are also symmetric: .. math:: W_{\mathrm{q},k}^T = W_{\mathrm{q},k}. * The last :math:`N` blocks are *congruence transformations* with nonsingular matrices: .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} W_{\mathrm{s},k} \svec{(u_{\mathrm{s},k})} = \svec{(r_k^T u_{\mathrm{s},k} r_k)}, \qquad W_{\mathrm{s},k}^{-1} \svec{(u_{\mathrm{s},k})} = \svec{(r_k^{-T} u_{\mathrm{s},k} r_k^{-1})}, \qquad k = 0,\ldots,N-1. In general, this operation is not symmetric: .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} W_{\mathrm{s},k}^T \svec{(u_{\mathrm{s},k})} = \svec{(r_k u_{\mathrm{s},k} r_k^T)}, \qquad \qquad W_{\mathrm{s},k}^{-T} \svec{(u_{\mathrm{s},k})} = \svec{(r_k^{-1} u_{\mathrm{s},k} r_k^{-T})}, \qquad \qquad k = 0,\ldots,N-1. It is often possible to exploit problem structure to solve :eq:`e-conelp-kkt` faster than by standard methods. The last argument ``kktsolver`` of :func:`conelp ` and :func:`coneqp ` allows the user to supply a Python function for solving the KKT equations. This function will be called as ``f = kktsolver(W)``, where ``W`` is a dictionary that contains the parameters of the scaling: * ``W['d']`` is the positive vector that defines the diagonal scaling. ``W['di']`` is its componentwise inverse. * ``W['beta']`` and ``W['v']`` are lists of length :math:`M` with the coefficients and vectors that define the hyperbolic Householder transformations. * ``W['r']`` is a list of length :math:`N` with the matrices that define the the congruence transformations. ``W['rti']`` is a list of length :math:`N` with the transposes of the inverses of the matrices in ``W['r']``. The function call ``f = kktsolver(W)`` should return a routine for solving the KKT system :eq:`e-conelp-kkt` defined by ``W``. It will be called as ``f(bx, by, bz)``. On entry, ``bx``, ``by``, ``bz`` contain the right-hand side. On exit, they should contain the solution of the KKT system, with the last component scaled, i.e., on exit, .. math:: b_x := u_x, \qquad b_y := u_y, \qquad b_z := W u_z. In other words, the function returns the solution of .. math:: \left[\begin{array}{ccc} P & A^T & G^TW^{-1} \\ A & 0 & 0 \\ G & 0 & -W^T \end{array}\right] \left[\begin{array}{c} \hat u_x \\ \hat u_y \\ \hat u_z \end{array}\right] = \left[\begin{array}{c} b_x \\ b_y \\ b_z \end{array}\right]. **Specifying constraints via Python functions** In the default use of :func:`conelp ` and :func:`coneqp `, the linear constraints and the quadratic term in the objective are parameterized by CVXOPT matrices ``G``, ``A``, ``P``. It is possible to specify these parameters via Python functions that evaluate the corresponding matrix-vector products and their adjoints. * If the argument ``G`` of :func:`conelp` or :func:`coneqp` is a Python function, then ``G(x, y[, alpha = 1.0, beta = 0.0, trans = 'N'])`` should evaluate the matrix-vector products .. math:: y := \alpha Gx + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \qquad y := \alpha G^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}). * Similarly, if the argument ``A`` is a Python function, then ``A(x, y[, alpha = 1.0, beta = 0.0, trans = 'N'])`` should evaluate the matrix-vector products .. math:: y := \alpha Ax + \beta y \quad (\mathrm{trans} = \mathrm{'N'}), \qquad y := \alpha A^T x + \beta y \quad (\mathrm{trans} = \mathrm{'T'}). * If the argument ``P`` of :func:`coneqp` is a Python function, then ``P(x, y[, alpha = 1.0, beta = 0.0])`` should evaluate the matrix-vector products .. math:: y := \alpha Px + \beta y. If ``G``, ``A``, or ``P`` are Python functions, then the argument ``kktsolver`` must also be provided. We illustrate these features with three applications. **Example: 1-norm approximation** The optimization problem .. math:: \begin{array}{ll} \mbox{minimize} & \|Pu-q\|_1 \end{array} can be formulated as a linear program .. math:: \newcommand{\ones}{{\bf 1}} \begin{array}{ll} \mbox{minimize} & \ones^T v \\ \mbox{subject to} & -v \preceq Pu - q \preceq v. \end{array} By exploiting the structure in the inequalities, the cost of an iteration of an interior-point method can be reduced to the cost of least-squares problem of the same dimensions. (See section 11.8.2 in the book `Convex Optimization `_.) The code below takes advantage of this fact. :: from cvxopt import blas, lapack, solvers, matrix, spmatrix, mul, div def l1(P, q): """ Returns the solution u, w of the l1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve the equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0. c = matrix(n*[0.0] + m*[1.0]) def G(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): if trans=='N': # y := alpha * [P, -I; -P, -I] * x + beta*y u = P*x[:n] y[:m] = alpha * ( u - x[n:]) + beta * y[:m] y[m:] = alpha * (-u - x[n:]) + beta * y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y y[:n] = alpha * P.T * (x[:m] - x[m:]) + beta * y[:n] y[n:] = -alpha * (x[:m] + x[m:]) + beta * y[n:] h = matrix([q, -q]) dims = {'l': 2*m, 'q': [], 's': []} def F(W): """ Returns a function f(x, y, z) that solves [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] [ P -I -D1^{-1} 0 ] [ z[:m] ] = [ bz[:m] ] [-P -I 0 -D2^{-1} ] [ z[m:] ] [ bz[m:] ] where D1 = diag(di[:m])^2, D2 = diag(di[m:])^2 and di = W['di']. """ # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and # d1 = di[:m].^2, d2 = di[m:].^2. di = W['di'] d1, d2 = di[:m]**2, di[m:]**2 D = div( mul(d1,d2), d1+d2 ) A = P.T * spmatrix(4*D, range(m), range(m)) * P lapack.potrf(A) def f(x, y, z): """ On entry bx, bz are stored in x, z. On exit x, z contain the solution, with z scaled: z./di is returned instead of z. """" # Solve for x[:n]: # # A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:] # + (2*D1*D2*(D1+D2)^{-1}) * (bz[:m] - bz[m:]) ). x[:n] += P.T * ( mul(div(d1-d2, d1+d2), x[n:]) + mul(2*D, z[:m]-z[m:]) ) lapack.potrs(A, x) # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bz[:m] - D2*bz[m:] + (D1-D2)*P*x[:n]) u = P*x[:n] x[n:] = div(x[n:] - mul(d1, z[:m]) - mul(d2, z[m:]) + mul(d1-d2, u), d1+d2) # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bz[:m]) # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bz[m:]) z[:m] = mul(di[:m], u - x[n:] - z[:m]) z[m:] = mul(di[m:], -u - x[n:] - z[m:]) return f sol = solvers.conelp(c, G, h, dims, kktsolver = F) return sol['x'][:n], sol['z'][m:] - sol['z'][:m] **Example: SDP with diagonal linear term** The SDP .. math:: \newcommand{\diag}{\mbox{\bf diag}\,} \newcommand{\ones}{{\bf 1}} \begin{array}{ll} \mbox{minimize} & \ones^T x \\ \mbox{subject to} & W + \diag(x) \succeq 0 \end{array} can be solved efficiently by exploiting properties of the diag operator. :: from cvxopt import blas, lapack, solvers, matrix def mcsdp(w): """ Returns solution x, z to (primal) minimize sum(x) subject to w + diag(x) >= 0 (dual) maximize -tr(w*z) subject to diag(z) = 1 z >= 0. """ n = w.size[0] c = matrix(1.0, (n,1)) def G(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): """ y := alpha*(-diag(x)) + beta*y. """ if trans=='N': # x is a vector; y is a symmetric matrix in column major order. y *= beta y[::n+1] -= alpha * x else: # x is a symmetric matrix in column major order; y is a vector. y *= beta y -= alpha * x[::n+1] def cngrnc(r, x, alpha = 1.0): """ Congruence transformation x := alpha * r'*x*r. r and x are square matrices. """ # Scale diagonal of x by 1/2. x[::n+1] *= 0.5 # a := tril(x)*r a = +r tx = matrix(x, (n,n)) blas.trmm(tx, a, side = 'L') # x := alpha*(a*r' + r*a') blas.syr2k(r, a, tx, trans = 'T', alpha = alpha) x[:] = tx[:] dims = {'l': 0, 'q': [], 's': [n]} def F(W): """ Returns a function f(x, y, z) that solves -diag(z) = bx -diag(x) - r*r'*z*r*r' = bz where r = W['r'][0] = W['rti'][0]^{-T}. """ rti = W['rti'][0] # t = rti*rti' as a nonsymmetric matrix. t = matrix(0.0, (n,n)) blas.gemm(rti, rti, t, transB = 'T') # Cholesky factorization of tsq = t.*t. tsq = t**2 lapack.potrf(tsq) def f(x, y, z): """ On entry, x contains bx, y is empty, and z contains bz stored in column major order. On exit, they contain the solution, with z scaled (vec(r'*z*r) is returned instead of z). We first solve ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bz*t) and take z = - rti' * (diag(x) + bz) * rti. """ # tbst := t * bz * t tbst = +z cngrnc(t, tbst) # x := x - diag(tbst) = bx - diag(rti*rti' * bz * rti*rti') x -= tbst[::n+1] # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bz*t)) lapack.potrs(tsq, x) # z := z + diag(x) = bz + diag(x) z[::n+1] += x # z := -vec(rti' * z * rti) # = -vec(rti' * (diag(x) + bz) * rti cngrnc(rti, z, alpha = -1.0) return f sol = solvers.conelp(c, G, w[:], dims, kktsolver = F) return sol['x'], sol['z'] **Example: Minimizing 1-norm subject to a 2-norm constraint** In the second example, we use a similar trick to solve the problem .. math:: \begin{array}{ll} \mbox{minimize} & \|u\|_1 \\ \mbox{subject to} & \|Au - b\|_2 \leq 1. \end{array} The code below is efficient, if we assume that the number of rows in :math:`A` is greater than or equal to the number of columns. :: def qcl1(A, b): """ Returns the solution u, z of (primal) minimize || u ||_1 subject to || A * u - b ||_2 <= 1 (dual) maximize b^T z - ||z||_2 subject to || A'*z ||_inf <= 1. Exploits structure, assuming A is m by n with m >= n. """ m, n = A.size # Solve equivalent cone LP with variables x = [u; v]. # # minimize [0; 1]' * x # subject to [ I -I ] * x <= [ 0 ] (componentwise) # [-I -I ] * x <= [ 0 ] (componentwise) # [ 0 0 ] * x <= [ 1 ] (SOC) # [-A 0 ] [ -b ] # # maximize -t + b' * w # subject to z1 - z2 = A'*w # z1 + z2 = 1 # z1 >= 0, z2 >=0, ||w||_2 <= t. c = matrix(n*[0.0] + n*[1.0]) h = matrix( 0.0, (2*n + m + 1, 1)) h[2*n] = 1.0 h[2*n+1:] = -b def G(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): y *= beta if trans=='N': # y += alpha * G * x y[:n] += alpha * (x[:n] - x[n:2*n]) y[n:2*n] += alpha * (-x[:n] - x[n:2*n]) y[2*n+1:] -= alpha * A*x[:n] else: # y += alpha * G'*x y[:n] += alpha * (x[:n] - x[n:2*n] - A.T * x[-m:]) y[n:] -= alpha * (x[:n] + x[n:2*n]) def Fkkt(W): """ Returns a function f(x, y, z) that solves [ 0 G' ] [ x ] = [ bx ] [ G -W'*W ] [ z ] [ bz ]. """ # First factor # # S = G' * W**-1 * W**-T * G # = [0; -A]' * W3^-2 * [0; -A] + 4 * (W1**2 + W2**2)**-1 # # where # # W1 = diag(d1) with d1 = W['d'][:n] = 1 ./ W['di'][:n] # W2 = diag(d2) with d2 = W['d'][n:] = 1 ./ W['di'][n:] # W3 = beta * (2*v*v' - J), W3^-1 = 1/beta * (2*J*v*v'*J - J) # with beta = W['beta'][0], v = W['v'][0], J = [1, 0; 0, -I]. # As = W3^-1 * [ 0 ; -A ] = 1/beta * ( 2*J*v * v' - I ) * [0; A] beta, v = W['beta'][0], W['v'][0] As = 2 * v * (v[1:].T * A) As[1:,:] *= -1.0 As[1:,:] -= A As /= beta # S = As'*As + 4 * (W1**2 + W2**2)**-1 S = As.T * As d1, d2 = W['d'][:n], W['d'][n:] d = 4.0 * (d1**2 + d2**2)**-1 S[::n+1] += d lapack.potrf(S) def f(x, y, z): # z := - W**-T * z z[:n] = -div( z[:n], d1 ) z[n:2*n] = -div( z[n:2*n], d2 ) z[2*n:] -= 2.0*v*( v[0]*z[2*n] - blas.dot(v[1:], z[2*n+1:]) ) z[2*n+1:] *= -1.0 z[2*n:] /= beta # x := x - G' * W**-1 * z x[:n] -= div(z[:n], d1) - div(z[n:2*n], d2) + As.T * z[-(m+1):] x[n:] += div(z[:n], d1) + div(z[n:2*n], d2) # Solve for x[:n]: # # S*x[:n] = x[:n] - (W1**2 - W2**2)(W1**2 + W2**2)^-1 * x[n:] x[:n] -= mul( div(d1**2 - d2**2, d1**2 + d2**2), x[n:]) lapack.potrs(S, x) # Solve for x[n:]: # # (d1**-2 + d2**-2) * x[n:] = x[n:] + (d1**-2 - d2**-2)*x[:n] x[n:] += mul( d1**-2 - d2**-2, x[:n]) x[n:] = div( x[n:], d1**-2 + d2**-2) # z := z + W^-T * G*x z[:n] += div( x[:n] - x[n:2*n], d1) z[n:2*n] += div( -x[:n] - x[n:2*n], d2) z[2*n:] += As*x[:n] return f dims = {'l': 2*n, 'q': [m+1], 's': []} sol = solvers.conelp(c, G, h, dims, kktsolver = Fkkt) if sol['status'] == 'optimal': return sol['x'][:n], sol['z'][-m:] else: return None, None **Example: 1-norm regularized least-squares** As an example that illustrates how structure can be exploited in :func:`coneqp `, we consider the 1-norm regularized least-squares problem .. math:: \begin{array}{ll} \mbox{minimize} & \|Ax - y\|_2^2 + \|x\|_1 \end{array} with variable :math:`x`. The problem is equivalent to the quadratic program .. math:: \newcommand{\ones}{{\bf 1}} \begin{array}{ll} \mbox{minimize} & \|Ax - y\|_2^2 + \ones^T u \\ \mbox{subject to} & -u \preceq x \preceq u \end{array} with variables :math:`x` and :math:`u`. The implementation below is efficient when :math:`A` has many more columns than rows. :: from cvxopt import matrix, spdiag, mul, div, blas, lapack, solvers, sqrt import math def l1regls(A, y): """ Returns the solution of l1-norm regularized least-squares problem minimize || A*x - y ||_2^2 + || x ||_1. """ m, n = A.size q = matrix(1.0, (2*n,1)) q[:n] = -2.0 * A.T * y def P(u, v, alpha = 1.0, beta = 0.0 ): """ v := alpha * 2.0 * [ A'*A, 0; 0, 0 ] * u + beta * v """ v *= beta v[:n] += alpha * 2.0 * A.T * (A * u[:n]) def G(u, v, alpha=1.0, beta=0.0, trans='N'): """ v := alpha*[I, -I; -I, -I] * u + beta * v (trans = 'N' or 'T') """ v *= beta v[:n] += alpha*(u[:n] - u[n:]) v[n:] += alpha*(-u[:n] - u[n:]) h = matrix(0.0, (2*n,1)) # Customized solver for the KKT system # # [ 2.0*A'*A 0 I -I ] [x[:n] ] [bx[:n] ] # [ 0 0 -I -I ] [x[n:] ] = [bx[n:] ]. # [ I -I -D1^-1 0 ] [zl[:n]] [bzl[:n]] # [ -I -I 0 -D2^-1 ] [zl[n:]] [bzl[n:]] # # where D1 = W['di'][:n]**2, D2 = W['di'][n:]**2. # # We first eliminate zl and x[n:]: # # ( 2*A'*A + 4*D1*D2*(D1+D2)^-1 ) * x[:n] = # bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] + # D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - # D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] # # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n] - D2*bzl[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] # # zl[:n] = D1 * ( x[:n] - x[n:] - bzl[:n] ) # zl[n:] = D2 * (-x[:n] - x[n:] - bzl[n:] ). # # The first equation has the form # # (A'*A + D)*x[:n] = rhs # # and is equivalent to # # [ D A' ] [ x:n] ] = [ rhs ] # [ A -I ] [ v ] [ 0 ]. # # It can be solved as # # ( A*D^-1*A' + I ) * v = A * D^-1 * rhs # x[:n] = D^-1 * ( rhs - A'*v ). S = matrix(0.0, (m,m)) Asc = matrix(0.0, (m,n)) v = matrix(0.0, (m,1)) def Fkkt(W): # Factor # # S = A*D^-1*A' + I # # where D = 2*D1*D2*(D1+D2)^-1, D1 = d[:n]**-2, D2 = d[n:]**-2. d1, d2 = W['di'][:n]**2, W['di'][n:]**2 # ds is square root of diagonal of D ds = math.sqrt(2.0) * div( mul( W['di'][:n], W['di'][n:]), sqrt(d1+d2) ) d3 = div(d2 - d1, d1 + d2) # Asc = A*diag(d)^-1/2 Asc = A * spdiag(ds**-1) # S = I + A * D^-1 * A' blas.syrk(Asc, S) S[::m+1] += 1.0 lapack.potrf(S) def g(x, y, z): x[:n] = 0.5 * ( x[:n] - mul(d3, x[n:]) + mul(d1, z[:n] + mul(d3, z[:n])) - mul(d2, z[n:] - mul(d3, z[n:])) ) x[:n] = div( x[:n], ds) # Solve # # S * v = 0.5 * A * D^-1 * ( bx[:n] - # (D2-D1)*(D1+D2)^-1 * bx[n:] + # D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - # D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] ) blas.gemv(Asc, x, v) lapack.potrs(S, v) # x[:n] = D^-1 * ( rhs - A'*v ). blas.gemv(Asc, v, x, alpha=-1.0, beta=1.0, trans='T') x[:n] = div(x[:n], ds) # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n] - D2*bzl[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] x[n:] = div( x[n:] - mul(d1, z[:n]) - mul(d2, z[n:]), d1+d2 )\ - mul( d3, x[:n] ) # zl[:n] = D1^1/2 * ( x[:n] - x[n:] - bzl[:n] ) # zl[n:] = D2^1/2 * ( -x[:n] - x[n:] - bzl[n:] ). z[:n] = mul( W['di'][:n], x[:n] - x[n:] - z[:n] ) z[n:] = mul( W['di'][n:], -x[:n] - x[n:] - z[n:] ) return g return solvers.coneqp(P, q, G, h, kktsolver = Fkkt)['x'][:n] .. _s-external: Optional Solvers ================ CVXOPT includes optional interfaces to several other optimization libraries. **GLPK** :func:`lp ` with the ``solver`` option set to :const:`'glpk'` uses the simplex algorithm in `GLPK (GNU Linear Programming Kit) `_. **MOSEK** :func:`lp `, :func:`socp `, and :func:`qp ` with the ``solver`` option set to :const:`'mosek'` option use `MOSEK `_ version 5. **DSDP** :func:`sdp ` with the ``solver`` option set to :const:`'dsdp'` uses the `DSDP5.8 `_. GLPK, MOSEK and DSDP are not included in the CVXOPT distribution and need to be installed separately. .. _s-parameters: Algorithm Parameters ==================== In this section we list some algorithm control parameters that can be modified without editing the source code. These control parameters are accessible via the dictionary :attr:`solvers.options`. By default the dictionary is empty and the default values of the parameters are used. One can change the parameters in the default solvers by adding entries with the following key values. :const:`'show_progress'` :const:`True` or :const:`False`; turns the output to the screen on or off (default: :const:`True`). :const:`'maxiters'` maximum number of iterations (default: :const:`100`). :const:`'abstol'` absolute accuracy (default: :const:`1e-7`). :const:`'reltol'` relative accuracy (default: :const:`1e-6`). :const:`'feastol'` tolerance for feasibility conditions (default: :const:`1e-7`). :const:`'refinement'` number of iterative refinement steps when solving KKT equations (default: :const:`0` if the problem has no second-order cone or matrix inequality constraints; :const:`1` otherwise). For example the command >>> from cvxopt import solvers >>> solvers.options['show_progress'] = False turns off the screen output during calls to the solvers. The tolerances :const:`'abstol'`, :const:`'reltol'` and :const:`'feastol'` have the following meaning. :func:`conelp ` terminates with status :const:`'optimal'` if .. math:: s \succeq 0, \qquad \frac{\|Gx + s - h\|_2} {\max\{1,\|h\|_2\}} \leq \epsilon_\mathrm{feas}, \qquad \frac{\|Ax-b\|_2}{\max\{1,\|b\|_2\}} \leq \epsilon_\mathrm{feas}, \qquad and .. math:: z \succeq 0, \qquad \frac{\|G^Tz + A^Ty + c\|_2}{\max\{1,\|c\|_2\}} \leq \epsilon_\mathrm{feas}, and .. math:: s^T z \leq \epsilon_\mathrm{abs} \qquad \mbox{or} \qquad \left( \min\left\{c^Tx, h^T z + b^Ty \right\} < 0 \quad \mbox{and} \quad \frac{s^Tz} {-\min\{c^Tx, h^Tz + b^T y\}} \leq \epsilon_\mathrm{rel} \right). It returns with status :const:`'primal infeasible'` if .. math:: z \succeq 0, \qquad \qquad \frac{\|G^Tz +A^Ty\|_2}{\max\{1, \|c\|_2\}} \leq \epsilon_\mathrm{feas}, \qquad h^Tz +b^Ty = -1. It returns with status :const:`'dual infeasible'` if .. math:: s \succeq 0, \qquad \qquad \frac{\|Gx+s\|_2}{\max\{1, \|h\|_2\}} \leq \epsilon_\mathrm{feas}, \qquad \frac{\|Ax\|_2}{\max\{1, \|b\|_2\}} \leq \epsilon_\mathrm{feas}, \qquad c^Tx = -1. The functions :func:`lp ` and :func:`sdp ` call :func:`conelp` and hence use the same stopping criteria. The function :func:`coneqp ` terminates with status :const:`'optimal'` if .. math:: s \succeq 0, \qquad \frac{\|Gx + s - h\|_2} {\max\{1,\|h\|_2\}} \leq \epsilon_\mathrm{feas}, \qquad \frac{\|Ax-b\|_2}{\max\{1,\|b\|_2\}} \leq \epsilon_\mathrm{feas}, and .. math:: z \succeq 0, \qquad \frac{\|Px + G^Tz + A^Ty + q\|_2}{\max\{1,\|q\|_2\}} \leq \epsilon_\mathrm{feas}, and at least one of the following three conditions is satisfied: .. math:: s^T z \leq \epsilon_\mathrm{abs} or .. math:: \left( \frac{1}{2}x^TPx + q^Tx < 0, \quad \mbox{and}\quad \frac{s^Tz} {-(1/2)x^TPx - q^Tx} \leq \epsilon_\mathrm{rel} \right) or .. math:: \left( L(x,y,z) > 0 \quad \mbox{and} \quad \frac{s^Tz} {L(x,y,z)} \leq \epsilon_\mathrm{rel} \right). Here .. math:: L(x,y,z) = \frac{1}{2}x^TPx + q^Tx + z^T (Gx-h) + y^T(Ax-b). The function :func:`qp ` calls :func:`coneqp` and hence uses the same stopping criteria. The control parameters listed in the GLPK documentation are set to their default values and can be customized by making an entry in :attr:`solvers.options`. The keys in the dictionary are strings with the name of the GLPK parameter. For example, the command >>> from cvxopt import solvers >>> solvers.options['LPX_K_MSGLEV'] = 0 turns off the screen output subsequent calls :func:`lp ` with the :const:`'glpk'` option. The MOSEK interior-point algorithm parameters are set to their default values. They can be modified by adding an entry :attr:`solvers.options['MOSEK']`. This entry is a dictionary with MOSEK parameter/value pairs, with the parameter names imported from :mod:`mosek`. For details see Section 15 of the MOSEK Python API Manual. For example the commands >>> from cvxopt import solvers >>> import mosek >>> solvers.options['MOSEK'] = {mosek.iparam.log: 0} turn off the screen output during calls of :func:`lp` or :func:`socp` with the :const:`'mosek'` option. The following control parameters in :attr:`solvers.options` affect the execution of the DSDP algorithm: :const:`'DSDP_Monitor'` the interval (in number of iterations) at which output is printed to the screen (default: :const:`0`). :const:`'DSDP_MaxIts'` maximum number of iterations. :const:`'DSDP_GapTolerance'` relative accuracy (default: :const:`1e-5`). cvxopt-1.1.4/doc/source/solvers.rst0000644000175000017500000013557411674452555016417 0ustar sonnesonne.. _c-solvers: ***************************** Nonlinear Convex Optimization ***************************** In this chapter we consider nonlinear convex optimization problems of the form .. math:: \begin{array}{ll} \mbox{minimize} & f_0(x) \\ \mbox{subject to} & f_k(x) \leq 0, \quad k=1,\ldots,m \\ & G x \preceq h \\ & A x = b. \end{array} The functions :math:`f_k` are convex and twice differentiable and the linear inequalities are generalized inequalities with respect to a proper convex cone, defined as a product of a nonnegative orthant, second-order cones, and positive semidefinite cones. The basic functions are :func:`cp ` and :func:`cpl `, described in the sections :ref:`s-cp` and :ref:`s-cpl`. A simpler interface for geometric programming problems is discussed in the section :ref:`s-gp`. In the section :ref:`s-nlcp` we explain how custom solvers can be implemented that exploit structure in specific classes of problems. The last section describes the algorithm parameters that control the solvers. .. _s-cp: Problems with Nonlinear Objectives ================================== .. function:: cvxopt.solvers.cp(F[, G, h[, dims[, A, b[, kktsolver]]]]) Solves a convex optimization problem .. math:: :label: e-nlcp \begin{array}{ll} \mbox{minimize} & f_0(x) \\ \mbox{subject to} & f_k(x) \leq 0, \quad k=1,\ldots,m \\ & G x \preceq h \\ & A x = b. \end{array} The argument ``F`` is a function that evaluates the objective and nonlinear constraint functions. It must handle the following calling sequences. * ``F()`` returns a tuple (``m``, ``x0``), where :math:`m` is the number of nonlinear constraints and :math:`x_0` is a point in the domain of :math:`f`. ``x0`` is a dense real matrix of size (:math:`n`, 1). * ``F(x)``, with ``x`` a dense real matrix of size (:math:`n`, 1), returns a tuple (``f``, ``Df``). ``f`` is a dense real matrix of size (:math:`m+1`, 1), with ``f[k]`` equal to :math:`f_k(x)`. (If :math:`m` is zero, ``f`` can also be returned as a number.) ``Df`` is a dense or sparse real matrix of size (:math:`m` + 1, :math:`n`) with ``Df[k,:]`` equal to the transpose of the gradient :math:`\nabla f_k(x)`. If :math:`x` is not in the domain of :math:`f`, ``F(x)`` returns :const:`None` or a tuple (:const:`None`, :const:`None`). * ``F(x,z)``, with ``x`` a dense real matrix of size (:math:`n`, 1) and ``z`` a positive dense real matrix of size (:math:`m` + 1, 1) returns a tuple (``f``, ``Df``, ``H``). ``f`` and ``Df`` are defined as above. ``H`` is a square dense or sparse real matrix of size (:math:`n`, :math:`n`), whose lower triangular part contains the lower triangular part of .. math:: z_0 \nabla^2f_0(x) + z_1 \nabla^2f_1(x) + \cdots + z_m \nabla^2f_m(x). If ``F`` is called with two arguments, it can be assumed that :math:`x` is in the domain of :math:`f`. The linear inequalities are with respect to a cone :math:`C` defined as a Cartesian product of a nonnegative orthant, a number of second-order cones, and a number of positive semidefinite cones: .. math:: C = C_0 \times C_1 \times \cdots \times C_M \times C_{M+1} \times \cdots \times C_{M+N} with .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \newcommand{\svec}{\mathop{\mathbf{vec}}} \newcommand{\symm}{{\mbox{\bf S}}} \begin{split} C_0 & = \{ u \in \reals^l \;| \; u_k \geq 0, \; k=1, \ldots,l\},\\ C_{k+1} & = \{ (u_0, u_1) \in \reals \times \reals^{r_{k}-1} \; | \; u_0 \geq \|u_1\|_2 \}, \quad k=0,\ldots, M-1, \\ C_{k+M+1} & = \left\{ \svec(u) \; | \; u \in \symm^{t_k}_+ \right\}, \quad k=0,\ldots,N-1. \end{split} Here :math:`\mathbf{vec}(u)` denotes a symmetric matrix :math:`u` stored as a vector in column major order. The arguments ``h`` and ``b`` are real single-column dense matrices. ``G`` and ``A`` are real dense or sparse matrices. The default values for ``A`` and ``b`` are sparse matrices with zero rows, meaning that there are no equality constraints. The number of rows of ``G`` and ``h`` is equal to .. math:: K = l + \sum_{k=0}^{M-1} r_k + \sum_{k=0}^{N-1} t_k^2. The columns of ``G`` and ``h`` are vectors in .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \reals^l \times \reals^{r_0} \times \cdots \times \reals^{r_{M-1}} \times \reals^{t_0^2} \times \cdots \times \reals^{t_{N-1}^2}, where the last :math:`N` components represent symmetric matrices stored in column major order. The strictly upper triangular entries of these matrices are not accessed (i.e., the symmetric matrices are stored in the :const:`'L'`-type column major order used in the :mod:`blas` and :mod:`lapack` modules). The argument ``dims`` is a dictionary with the dimensions of the cones. It has three fields. ``dims['l']``: :math:`l`, the dimension of the nonnegative orthant (a nonnegative integer). ``dims['q']``: :math:`[r_0, \ldots, r_{M-1}]`, a list with the dimensions of the second-order cones (positive integers). ``dims['s']``: :math:`[t_0, \ldots, t_{N-1}]`, a list with the dimensions of the positive semidefinite cones (nonnegative integers). The default value of ``dims`` is ``{'l': h.size[0], 'q': [], 's': []}``, i.e., the default assumption is that the linear inequalities are componentwise inequalities. The role of the optional argument ``kktsolver`` is explained in the section :ref:`s-nlcp`. :func:`cp` returns a dictionary that contains the result and information about the accuracy of the solution. The most important fields have keys :const:`'status'`, :const:`'x'`, :const:`'snl'`, :const:`'sl'`, :const:`'y'`, :const:`'znl'`, :const:`'zl'`. The possible values of the :const:`'status'` key are: :const:`'optimal'` In this case the :const:`'x'` entry of the dictionary is the primal optimal solution, the :const:`'snl'` and :const:`'sl'` entries are the corresponding slacks in the nonlinear and linear inequality constraints, and the :const:`'znl'`, :const:`'zl'` and :const:`'y'` entries are the optimal values of the dual variables associated with the nonlinear inequalities, the linear inequalities, and the linear equality constraints. These vectors approximately satisfy the Karush-Kuhn-Tucker (KKT) conditions .. math:: \nabla f_0(x) + D\tilde f(x)^T z_\mathrm{nl} + G^T z_\mathrm{l} + A^T y = 0, \tilde f(x) + s_\mathrm{nl} = 0, \quad k=1,\ldots,m, \qquad Gx + s_\mathrm{l} = h, \qquad Ax = b, s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad z_\mathrm{nl} \succeq 0, \qquad z_\mathrm{l} \succeq 0, s_\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l} = 0 where :math:`\tilde f = (f_1,\ldots, f_m)`. :const:`'unknown'` This indicates that the algorithm terminated before a solution was found, due to numerical difficulties or because the maximum number of iterations was reached. The :const:`'x'`, :const:`'snl'`, :const:`'sl'`, :const:`'y'`, :const:`'znl'`, and :const:`'zl'` entries contain the iterates when the algorithm terminated. :func:`cp` solves the problem by applying :func:`cpl ` to the epigraph form problem .. math:: \begin{array}{ll} \mbox{minimize} & t \\ \mbox{subject to} & f_0(x) \leq t \\ & f_k(x) \leq 0, \quad k =1, \ldots, m \\ & Gx \preceq h \\ & Ax = b. \end{array} The other entries in the output dictionary of :func:`cp` describe the accuracy of the solution and are copied from the output of :func:`cpl ` applied to this epigraph form problem. :func:`cp` requires that the problem is strictly primal and dual feasible and that .. math:: \newcommand{\Rank}{\mathop{\bf rank}} \Rank(A) = p, \qquad \Rank \left( \left[ \begin{array}{cccccc} \sum_{k=0}^m z_k \nabla^2 f_k(x) & A^T & \nabla f_1(x) & \cdots \nabla f_m(x) & G^T \end{array} \right] \right) = n, for all :math:`x` and all positive :math:`z`. **Example: equality constrained analytic centering** The equality constrained analytic centering problem is defined as .. math:: \begin{array}{ll} \mbox{minimize} & -\sum\limits_{i=1}^m \log x_i \\ \mbox{subject to} & Ax = b. \end{array} The function :func:`acent` defined below solves the problem, assuming it is solvable. :: from cvxopt import solvers, matrix, spdiag, log def acent(A, b): m, n = A.size def F(x=None, z=None): if x is None: return 0, matrix(1.0, (n,1)) if min(x) <= 0.0: return None f = -sum(log(x)) Df = -(x**-1).T if z is None: return f, Df H = spdiag(z[0] * x**-2) return f, Df, H return solvers.cp(F, A=A, b=b)['x'] **Example: robust least-squares** The function :func:`robls` defined below solves the unconstrained problem .. math:: \begin{array}{ll} \mbox{minimize} & \sum\limits_{k=1}^m \phi((Ax-b)_k), \end{array} \qquad \phi(u) = \sqrt{\rho + u^2}, where :math:`A \in\mathbf{R}^{m\times n}`. :: from cvxopt import solvers, matrix, spdiag, sqrt, div def robls(A, b, rho): m, n = A.size def F(x=None, z=None): if x is None: return 0, matrix(0.0, (n,1)) y = A*x-b w = sqrt(rho + y**2) f = sum(w) Df = div(y, w).T * A if z is None: return f, Df H = A.T * spdiag(z[0]*rho*(w**-3)) * A return f, Df, H return solvers.cp(F)['x'] **Example: analytic centering with cone constraints** .. math:: \begin{array}{ll} \mbox{minimize} & -\log(1-x_1^2) -\log(1-x_2^2) -\log(1-x_3^2) \\ \mbox{subject to} & \|x\|_2 \leq 1 \\ & x_1 \left[\begin{array}{rrr} -21 & -11 & 0 \\ -11 & 10 & 8 \\ 0 & 8 & 5 \end{array}\right] + x_2 \left[\begin{array}{rrr} 0 & 10 & 16 \\ 10 & -10 & -10 \\ 16 & -10 & 3 \end{array}\right] + x_3 \left[\begin{array}{rrr} -5 & 2 & -17 \\ 2 & -6 & 8 \\ -17 & -7 & 6 \end{array}\right] \preceq \left[\begin{array}{rrr} 20 & 10 & 40 \\ 10 & 80 & 10 \\ 40 & 10 & 15 \end{array}\right]. \end{array} :: from cvxopt import matrix, log, div, spdiag, solvers def F(x = None, z = None): if x is None: return 0, matrix(0.0, (3,1)) if max(abs(x)) >= 1.0: return None u = 1 - x**2 val = -sum(log(u)) Df = div(2*x, u).T if z is None: return val, Df H = spdiag(2 * z[0] * div(1 + u**2, u**2)) return val, Df, H G = matrix([ [0., -1., 0., 0., -21., -11., 0., -11., 10., 8., 0., 8., 5.], [0., 0., -1., 0., 0., 10., 16., 10., -10., -10., 16., -10., 3.], [0., 0., 0., -1., -5., 2., -17., 2., -6., 8., -17., -7., 6.] ]) h = matrix([1.0, 0.0, 0.0, 0.0, 20., 10., 40., 10., 80., 10., 40., 10., 15.]) dims = {'l': 0, 'q': [4], 's': [3]} sol = solvers.cp(F, G, h, dims) print(sol['x']) [ 4.11e-01] [ 5.59e-01] [-7.20e-01] .. _s-cpl: Problems with Linear Objectives =============================== .. function:: cvxopt.solvers.cpl(c, F[, G, h[, dims[, A, b[, kktsolver]]]]) Solves a convex optimization problem with a linear objective .. math:: \begin{array}{ll} \mbox{minimize} & c^T x \\ \mbox{subject to} & f_k(x) \leq 0, \quad k=0,\ldots,m-1 \\ & G x \preceq h \\ & A x = b. \end{array} ``c`` is a real single-column dense matrix. ``F`` is a function that evaluates the nonlinear constraint functions. It must handle the following calling sequences. * ``F()`` returns a tuple (``m``, ``x0``), where ``m`` is the number of nonlinear constraints and ``x0`` is a point in the domain of :math:`f`. ``x0`` is a dense real matrix of size (:math:`n`, 1). * ``F(x)``, with ``x`` a dense real matrix of size (:math:`n`, 1), returns a tuple (``f``, ``Df``). ``f`` is a dense real matrix of size (:math:`m`, 1), with ``f[k]`` equal to :math:`f_k(x)`. ``Df`` is a dense or sparse real matrix of size (:math:`m`, :math:`n`) with ``Df[k,:]`` equal to the transpose of the gradient :math:`\nabla f_k(x)`. If :math:`x` is not in the domain of :math:`f`, ``F(x)`` returns :const:`None` or a tuple (:const:`None`, :const:`None`). * ``F(x,z)``, with ``x`` a dense real matrix of size (:math:`n`, 1) and ``z`` a positive dense real matrix of size (:math:`m`, 1) returns a tuple (``f``, ``Df``, ``H``). ``f`` and ``Df`` are defined as above. ``H`` is a square dense or sparse real matrix of size (:math:`n`, :math:`n`), whose lower triangular part contains the lower triangular part of .. math:: z_0 \nabla^2f_0(x) + z_1 \nabla^2f_1(x) + \cdots + z_{m-1} \nabla^2f_{m-1}(x). If ``F`` is called with two arguments, it can be assumed that :math:`x` is in the domain of :math:`f`. The linear inequalities are with respect to a cone :math:`C` defined as a Cartesian product of a nonnegative orthant, a number of second-order cones, and a number of positive semidefinite cones: .. math:: C = C_0 \times C_1 \times \cdots \times C_M \times C_{M+1} \times \cdots \times C_{M+N} with .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \newcommand{\svec}{\mathop{\mathbf{vec}}} \newcommand{\symm}{{\mbox{\bf S}}} \begin{split} C_0 &= \{ u \in \reals^l \;| \; u_k \geq 0, \; k=1, \ldots,l\}, \\ C_{k+1} &= \{ (u_0, u_1) \in \reals \times \reals^{r_{k}-1} \; | \; u_0 \geq \|u_1\|_2 \}, \quad k=0,\ldots, M-1, \\ C_{k+M+1} &= \left\{ \svec(u) \; | \; u \in \symm^{t_k}_+ \right\}, \quad k=0,\ldots,N-1. \end{split} Here :math:`\mathbf{vec}(u)` denotes a symmetric matrix :math:`u` stored as a vector in column major order. The arguments ``h`` and ``b`` are real single-column dense matrices. ``G`` and ``A`` are real dense or sparse matrices. The default values for ``A`` and ``b`` are sparse matrices with zero rows, meaning that there are no equality constraints. The number of rows of ``G`` and ``h`` is equal to .. math:: K = l + \sum_{k=0}^{M-1} r_k + \sum_{k=0}^{N-1} t_k^2. The columns of ``G`` and ``h`` are vectors in .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \reals^l \times \reals^{r_0} \times \cdots \times \reals^{r_{M-1}} \times \reals^{t_0^2} \times \cdots \times \reals^{t_{N-1}^2}, where the last :math:`N` components represent symmetric matrices stored in column major order. The strictly upper triangular entries of these matrices are not accessed (i.e., the symmetric matrices are stored in the :const:`'L'`-type column major order used in the :mod:`blas` and :mod:`lapack` modules. The argument ``dims`` is a dictionary with the dimensions of the cones. It has three fields. ``dims['l']``: :math:`l`, the dimension of the nonnegative orthant (a nonnegative integer). ``dims['q']``: :math:`[r_0, \ldots, r_{M-1}]`, a list with the dimensions of the second-order cones (positive integers). ``dims['s']``: :math:`[t_0, \ldots, t_{N-1}]`, a list with the dimensions of the positive semidefinite cones (nonnegative integers). The default value of ``dims`` is ``{'l': h.size[0], 'q': [], 's': []}``, i.e., the default assumption is that the linear inequalities are componentwise inequalities. The role of the optional argument ``kktsolver`` is explained in the section :ref:`s-nlcp`. :func:`cpl` returns a dictionary that contains the result and information about the accuracy of the solution. The most important fields have keys :const:`'status'`, :const:`'x'`, :const:`'snl'`, :const:`'sl'`, :const:`'y'`, :const:`'znl'`, :const:`'zl'`. The possible values of the :const:`'status'` key are: :const:`'optimal'` In this case the :const:`'x'` entry of the dictionary is the primal optimal solution, the :const:`'snl'` and :const:`'sl'` entries are the corresponding slacks in the nonlinear and linear inequality constraints, and the :const:`'znl'`, :const:`'zl'`, and :const:`'y'` entries are the optimal values of the dual variables associated with the nonlinear inequalities, the linear inequalities, and the linear equality constraints. These vectors approximately satisfy the Karush-Kuhn-Tucker (KKT) conditions .. math:: c + Df(x)^T z_\mathrm{nl} + G^T z_\mathrm{l} + A^T y = 0, f(x) + s_\mathrm{nl} = 0, \quad k=1,\ldots,m, \qquad Gx + s_\mathrm{l} = h, \qquad Ax = b, s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad z_\mathrm{nl} \succeq 0, \qquad z_\mathrm{l} \succeq 0, s_\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l} = 0. :const:`'unknown'` This indicates that the algorithm terminated before a solution was found, due to numerical difficulties or because the maximum number of iterations was reached. The :const:`'x'`, :const:`'snl'`, :const:`'sl'`, :const:`'y'`, :const:`'znl'`, and :const:`'zl'` entries contain the iterates when the algorithm terminated. The other entries in the output dictionary describe the accuracy of the solution. The entries :const:`'primal objective'`, :const:`'dual objective'`, :const:`'gap'`, and :const:`'relative gap'` give the primal objective :math:`c^Tx`, the dual objective, calculated as .. math:: c^Tx + z_\mathrm{nl}^T f(x) + z_\mathrm{l}^T (Gx - h) + y^T(Ax-b), the duality gap .. math:: s_\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l}, and the relative gap. The relative gap is defined as .. math:: \frac{\mbox{gap}}{-\mbox{primal objective}} \quad \mbox{if\ } \mbox{primal objective} < 0, \qquad \frac{\mbox{gap}}{\mbox{dual objective}} \quad \mbox{if\ } \mbox{dual objective} > 0, and :const:`None` otherwise. The entry with key :const:`'primal infeasibility'` gives the residual in the primal constraints, .. math:: \newcommand{\ones}{{\bf 1}} \frac{\| ( f(x) + s_{\mathrm{nl}}, Gx + s_\mathrm{l} - h, Ax-b ) \|_2} {\max\{1, \| ( f(x_0) + \ones, Gx_0 + \ones-h, Ax_0-b) \|_2 \}} where :math:`x_0` is the point returned by ``F()``. The entry with key :const:`'dual infeasibility'` gives the residual .. math:: \newcommand{\ones}{{\bf 1}} \frac { \| c + Df(x)^Tz_\mathrm{nl} + G^Tz_\mathrm{l} + A^T y \|_2} { \max\{ 1, \| c + Df(x_0)^T\ones + G^T\ones \|_2 \} }. :func:`cpl` requires that the problem is strictly primal and dual feasible and that .. math:: \newcommand{\Rank}{\mathop{\bf rank}} \Rank(A) = p, \qquad \Rank\left(\left[\begin{array}{cccccc} \sum_{k=0}^{m-1} z_k \nabla^2 f_k(x) & A^T & \nabla f_0(x) & \cdots \nabla f_{m-1}(x) & G^T \end{array}\right]\right) = n, for all :math:`x` and all positive :math:`z`. **Example: floor planning** This example is the floor planning problem of section 8.8.2 in the book `Convex Optimization `_: .. math:: \begin{array}{ll} \mbox{minimize} & W + H \\ \mbox{subject to} & A_{\mathrm{min}, k}/h_k - w_k \leq 0, \quad k=1,\ldots, 5 \\ & x_1 \geq 0, \quad x_2 \geq 0, \quad x_4 \geq 0 \\ & x_1 + w_1 + \rho \leq x_3, \quad x_2 + w_2 + \rho \leq x_3, \quad x_3 + w_3 + \rho \leq x_5, \\ & x_4 + w_4 + \rho \leq x_5, \quad x_5 + w_5 \leq W \\ & y_2 \geq 0, \quad y_3 \geq 0, \quad y_5 \geq 0 \\ & y_2 + h_2 + \rho \leq y_1, \quad y_1 + h_1 + \rho \leq y_4, y_3 + h_3 + \rho \leq y_4, \\ & y_4 + h_4 \leq H, \quad y_5 + h_5 \leq H \\ & h_k/\gamma \leq w_k \leq \gamma h_k, \quad k=1,\ldots,5. \end{array} This problem has 22 variables .. math:: \newcommand{\reals}{{\mbox{\bf R}}} W, \qquad H, \qquad x\in\reals^5, \qquad y\in\reals^5, \qquad w\in\reals^5, \qquad h\in\reals^5, 5 nonlinear inequality constraints, and 26 linear inequality constraints. The code belows defines a function :func:`floorplan` that solves the problem by calling :func:`cp`, then applies it to 4 instances, and creates a figure. :: import pylab from cvxopt import solvers, matrix, spmatrix, mul, div def floorplan(Amin): # minimize W+H # subject to Amink / hk <= wk, k = 1,..., 5 # x1 >= 0, x2 >= 0, x4 >= 0 # x1 + w1 + rho <= x3 # x2 + w2 + rho <= x3 # x3 + w3 + rho <= x5 # x4 + w4 + rho <= x5 # x5 + w5 <= W # y2 >= 0, y3 >= 0, y5 >= 0 # y2 + h2 + rho <= y1 # y1 + h1 + rho <= y4 # y3 + h3 + rho <= y4 # y4 + h4 <= H # y5 + h5 <= H # hk/gamma <= wk <= gamma*hk, k = 1, ..., 5 # # 22 Variables W, H, x (5), y (5), w (5), h (5). # # W, H: scalars; bounding box width and height # x, y: 5-vectors; coordinates of bottom left corners of blocks # w, h: 5-vectors; widths and heigths of the 5 blocks rho, gamma = 1.0, 5.0 # min spacing, min aspect ratio # The objective is to minimize W + H. There are five nonlinear # constraints # # -wk + Amink / hk <= 0, k = 1, ..., 5 c = matrix(2*[1.0] + 20*[0.0]) def F(x=None, z=None): if x is None: return 5, matrix(17*[0.0] + 5*[1.0]) if min(x[17:]) <= 0.0: return None f = -x[12:17] + div(Amin, x[17:]) Df = matrix(0.0, (5,22)) Df[:,12:17] = spmatrix(-1.0, range(5), range(5)) Df[:,17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5)) if z is None: return f, Df H = spmatrix( 2.0* mul(z, div(Amin, x[17::]**3)), range(17,22), range(17,22) ) return f, Df, H G = matrix(0.0, (26,22)) h = matrix(0.0, (26,1)) G[0,2] = -1.0 # -x1 <= 0 G[1,3] = -1.0 # -x2 <= 0 G[2,5] = -1.0 # -x4 <= 0 G[3, [2, 4, 12]], h[3] = [1.0, -1.0, 1.0], -rho # x1 - x3 + w1 <= -rho G[4, [3, 4, 13]], h[4] = [1.0, -1.0, 1.0], -rho # x2 - x3 + w2 <= -rho G[5, [4, 6, 14]], h[5] = [1.0, -1.0, 1.0], -rho # x3 - x5 + w3 <= -rho G[6, [5, 6, 15]], h[6] = [1.0, -1.0, 1.0], -rho # x4 - x5 + w4 <= -rho G[7, [0, 6, 16]] = -1.0, 1.0, 1.0 # -W + x5 + w5 <= 0 G[8,8] = -1.0 # -y2 <= 0 G[9,9] = -1.0 # -y3 <= 0 G[10,11] = -1.0 # -y5 <= 0 G[11, [7, 8, 18]], h[11] = [-1.0, 1.0, 1.0], -rho # -y1 + y2 + h2 <= -rho G[12, [7, 10, 17]], h[12] = [1.0, -1.0, 1.0], -rho # y1 - y4 + h1 <= -rho G[13, [9, 10, 19]], h[13] = [1.0, -1.0, 1.0], -rho # y3 - y4 + h3 <= -rho G[14, [1, 10, 20]] = -1.0, 1.0, 1.0 # -H + y4 + h4 <= 0 G[15, [1, 11, 21]] = -1.0, 1.0, 1.0 # -H + y5 + h5 <= 0 G[16, [12, 17]] = -1.0, 1.0/gamma # -w1 + h1/gamma <= 0 G[17, [12, 17]] = 1.0, -gamma # w1 - gamma * h1 <= 0 G[18, [13, 18]] = -1.0, 1.0/gamma # -w2 + h2/gamma <= 0 G[19, [13, 18]] = 1.0, -gamma # w2 - gamma * h2 <= 0 G[20, [14, 18]] = -1.0, 1.0/gamma # -w3 + h3/gamma <= 0 G[21, [14, 19]] = 1.0, -gamma # w3 - gamma * h3 <= 0 G[22, [15, 19]] = -1.0, 1.0/gamma # -w4 + h4/gamma <= 0 G[23, [15, 20]] = 1.0, -gamma # w4 - gamma * h4 <= 0 G[24, [16, 21]] = -1.0, 1.0/gamma # -w5 + h5/gamma <= 0 G[25, [16, 21]] = 1.0, -gamma # w5 - gamma * h5 <= 0.0 # solve and return W, H, x, y, w, h sol = solvers.cpl(c, F, G, h) return sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], sol['x'][12:17], sol['x'][17:] pylab.figure(facecolor='w') pylab.subplot(221) Amin = matrix([100., 100., 100., 100., 100.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.subplot(222) Amin = matrix([20., 50., 80., 150., 200.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], 'facecolor = #D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.subplot(223) Amin = matrix([180., 80., 80., 80., 80.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], 'facecolor = #D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.subplot(224) Amin = matrix([20., 150., 20., 200., 110.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], 'facecolor = #D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.show() .. image:: floorplan.png :width: 600px .. _s-gp: Geometric Programming ===================== .. function:: cvxopt.solvers.gp(K, F, g[, G, h[, A, b]]) Solves a geometric program in convex form .. math:: \newcommand{\lse}{\mathop{\mathbf{lse}}} \begin{array}{ll} \mbox{minimize} & f_0(x) = \lse(F_0x+g_0) \\ \mbox{subject to} & f_i(x) = \lse(F_ix+g_i) \leq 0, \quad i=1,\ldots,m \\ & Gx \preceq h \\ & Ax=b \end{array} where .. math:: \newcommand{\lse}{\mathop{\mathbf{lse}}} \lse(u) = \log \sum_k \exp(u_k), \qquad F = \left[ \begin{array}{cccc} F_0^T & F_1^T & \cdots & F_m^T \end{array}\right]^T, \qquad g = \left[ \begin{array}{cccc} g_0^T & g_1^T & \cdots & g_m^T \end{array}\right]^T, and the vector inequality denotes componentwise inequality. ``K`` is a list of :math:`m` + 1 positive integers with ``K[i]`` equal to the number of rows in :math:`F_i`. ``F`` is a dense or sparse real matrix of size ``(sum(K), n)``. ``g`` is a dense real matrix with one column and the same number of rows as ``F``. ``G`` and ``A`` are dense or sparse real matrices. Their default values are sparse matrices with zero rows. ``h`` and ``b`` are dense real matrices with one column. Their default values are matrices of size (0, 1). :func:`gp` returns a dictionary with keys :const:`'status'`, :const:`'x'`, :const:`'snl'`, :const:`'sl'`, :const:`'y'`, :const:`'znl'`, and :const:`'zl'`. The possible values of the :const:`'status'` key are: :const:`'optimal'` In this case the :const:`'x'` entry is the primal optimal solution, the :const:`'snl'` and :const:`'sl'` entries are the corresponding slacks in the nonlinear and linear inequality constraints. The :const:`'znl'`, :const:`'zl'`, and :const:`'y'` entries are the optimal values of the dual variables associated with the nonlinear and linear inequality constraints and the linear equality constraints. These values approximately satisfy .. math:: \nabla f_0(x) + \sum_{k=1}^m z_{\mathrm{nl},k} \nabla f_k(x) + G^T z_\mathrm{l} + A^T y = 0, f_k(x) + s_{\mathrm{nl},k} = 0, \quad k = 1,\ldots,m \qquad Gx + s_\mathrm{l} = h, \qquad Ax = b, s_\mathrm{nl}\succeq 0, \qquad s_\mathrm{l}\succeq 0, \qquad z_\mathrm{nl} \succeq 0, \qquad z_\mathrm{l} \succeq 0, s_\mathrm{nl}^T z_\mathrm{nl} + s_\mathrm{l}^T z_\mathrm{l} =0. :const:`'unknown'` This indicates that the algorithm terminated before a solution was found, due to numerical difficulties or because the maximum number of iterations was reached. The :const:`'x'`, :const:`'snl'`, :const:`'sl'`, :const:`'y'`, :const:`'znl'`, and :const:`'zl'` contain the iterates when the algorithm terminated. The other entries in the output dictionary describe the accuracy of the solution, and are taken from the output of :func:`cp `. As an example, we solve the small GP of section 2.4 of the paper `A Tutorial on Geometric Programming `_. The posynomial form of the problem is .. math:: \begin{array}{ll} \mbox{minimize} & w^{-1} h^{-1} d^{-1} \\ \mbox{subject to} & (2/A_\mathrm{wall}) hw + (2/A_\mathrm{wall})hd \leq 1 \\ & (1/A_\mathrm{flr}) wd \leq 1 \\ & \alpha wh^{-1} \leq 1 \\ & (1/\beta) hw^{-1} \leq 1 \\ & \gamma wd^{-1} \leq 1 \\ & (1/\delta)dw^{-1} \leq 1 \end{array} with variables :math:`h`, :math:`w`, :math:`d`. :: from cvxopt import matrix, log, exp, solvers Aflr = 1000.0 Awall = 100.0 alpha = 0.5 beta = 2.0 gamma = 0.5 delta = 2.0 F = matrix( [[-1., 1., 1., 0., -1., 1., 0., 0.], [-1., 1., 0., 1., 1., -1., 1., -1.], [-1., 0., 1., 1., 0., 0., -1., 1.]]) g = log( matrix( [1.0, 2/Awall, 2/Awall, 1/Aflr, alpha, 1/beta, gamma, 1/delta]) ) K = [1, 2, 1, 1, 1, 1, 1] h, w, d = exp( solvers.gp(K, F, g)['x'] ) .. _s-nlcp: Exploiting Structure ==================== By default, the functions :func:`cp ` and :func:`cpl ` do not exploit problem structure. Two mechanisms are provided for implementing customized solvers that take advantage of problem structure. **Providing a function for solving KKT equations** The most expensive step of each iteration of :func:`cp ` is the solution of a set of linear equations (*KKT equations*) of the form .. math:: :label: e-cp-kkt \left[\begin{array}{ccc} H & A^T & \tilde G^T \\ A & 0 & 0 \\ \tilde G & 0 & -W^T W \end{array}\right] \left[\begin{array}{c} u_x \\ u_y \\ u_z \end{array}\right] = \left[\begin{array}{c} b_x \\ b_y \\ b_z \end{array}\right], where .. math:: H = \sum_{k=0}^m z_k \nabla^2f_k(x), \qquad \tilde G = \left[\begin{array}{cccc} \nabla f_1(x) & \cdots & \nabla f_m(x) & G^T \end{array}\right]^T. The matrix :math:`W` depends on the current iterates and is defined as follows. Suppose .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} u = \left( u_\mathrm{nl}, \; u_\mathrm{l}, \; u_{\mathrm{q},0}, \; \ldots, \; u_{\mathrm{q},M-1}, \; \svec{(u_{\mathrm{s},0})}, \; \ldots, \; \svec{(u_{\mathrm{s},N-1})} \right), \qquad where .. math:: \newcommand{\reals}{{\mbox{\bf R}}} \newcommand{\symm}{{\mbox{\bf S}}} u_\mathrm{nl} \in \reals^m, \qquad u_\mathrm{l} \in \reals^l, \qquad u_{\mathrm{q},k} \in \reals^{r_k}, \quad k = 0, \ldots, M-1, \qquad u_{\mathrm{s},k} \in \symm^{t_k}, \quad k = 0, \ldots, N-1. Then :math:`W` is a block-diagonal matrix, .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} Wu = \left( W_\mathrm{nl} u_\mathrm{nl}, \; W_\mathrm{l} u_\mathrm{l}, \; W_{\mathrm{q},0} u_{\mathrm{q},0}, \; \ldots, \; W_{\mathrm{q},M-1} u_{\mathrm{q},M-1},\; W_{\mathrm{s},0} \svec{(u_{\mathrm{s},0})}, \; \ldots, \; W_{\mathrm{s},N-1} \svec{(u_{\mathrm{s},N-1})} \right) with the following diagonal blocks. * The first block is a *positive diagonal scaling* with a vector :math:`d_{\mathrm{nl}}`: .. math:: \newcommand{\diag}{\mbox{\bf diag}\,} W_\mathrm{nl} = \diag(d_\mathrm{nl}), \qquad W_\mathrm{nl}^{-1} = \diag(d_\mathrm{nl})^{-1}. This transformation is symmetric: .. math:: W_\mathrm{nl}^T = W_\mathrm{nl}. * The second block is a *positive diagonal scaling* with a vector :math:`d_{\mathrm{l}}`: .. math:: \newcommand{\diag}{\mbox{\bf diag}\,} W_\mathrm{l} = \diag(d_\mathrm{l}), \qquad W_\mathrm{l}^{-1} = \diag(d_\mathrm{l})^{-1}. This transformation is symmetric: .. math:: W_\mathrm{l}^T = W_\mathrm{l}. * The next :math:`M` blocks are positive multiples of *hyperbolic Householder transformations*: .. math:: W_{\mathrm{q},k} = \beta_k ( 2 v_k v_k^T - J), \qquad W_{\mathrm{q},k}^{-1} = \frac{1}{\beta_k} ( 2 Jv_k v_k^T J - J), \qquad k = 0,\ldots,M-1, where .. math:: \beta_k > 0, \qquad v_{k0} > 0, \qquad v_k^T Jv_k = 1, \qquad J = \left[\begin{array}{cc} 1 & 0 \\ 0 & -I \end{array}\right]. These transformations are also symmetric: .. math:: W_{\mathrm{q},k}^T = W_{\mathrm{q},k}. * The last :math:`N` blocks are *congruence transformations* with nonsingular matrices: .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} W_{\mathrm{s},k} \svec{(u_{\mathrm{s},k})} = \svec{(r_k^T u_{\mathrm{s},k} r_k)}, \qquad W_{\mathrm{s},k}^{-1} \svec{(u_{\mathrm{s},k})} = \svec{(r_k^{-T} u_{\mathrm{s},k} r_k^{-1})}, \qquad k = 0,\ldots,N-1. In general, this operation is not symmetric, and .. math:: \newcommand{\svec}{\mathop{\mathbf{vec}}} W_{\mathrm{s},k}^T \svec{(u_{\mathrm{s},k})} = \svec{(r_k u_{\mathrm{s},k} r_k^T)}, \qquad \qquad W_{\mathrm{s},k}^{-T} \svec{(u_{\mathrm{s},k})} = \svec{(r_k^{-1} u_{\mathrm{s},k} r_k^{-T})}, \qquad k = 0,\ldots,N-1. It is often possible to exploit problem structure to solve :eq:`e-cp-kkt` faster than by standard methods. The last argument ``kktsolver`` of :func:`cp ` allows the user to supply a Python function for solving the KKT equations. This function will be called as ``f = kktsolver(x, z, W)``. The argument ``x`` is the point at which the derivatives in the KKT matrix are evaluated. ``z`` is a positive vector of length it :math:`m` + 1, containing the coefficients in the 1,1 block :math:`H`. ``W`` is a dictionary that contains the parameters of the scaling: * ``W['dnl']`` is the positive vector that defines the diagonal scaling for the nonlinear inequalities. ``W['dnli']`` is its componentwise inverse. * ``W['d']`` is the positive vector that defines the diagonal scaling for the componentwise linear inequalities. ``W['di']`` is its componentwise inverse. * ``W['beta']`` and ``W['v']`` are lists of length :math:`M` with the coefficients and vectors that define the hyperbolic Householder transformations. * ``W['r']`` is a list of length :math:`N` with the matrices that define the the congruence transformations. ``W['rti']`` is a list of length :math:`N` with the transposes of the inverses of the matrices in ``W['r']``. The function call ``f = kktsolver(x, z, W)`` should return a routine for solving the KKT system :eq:`e-cp-kkt` defined by ``x``, ``z``, ``W``. It will be called as ``f(bx, by, bz)``. On entry, ``bx``, ``by``, ``bz`` contain the right-hand side. On exit, they should contain the solution of the KKT system, with the last component scaled, i.e., on exit, .. math:: b_x := u_x, \qquad b_y := u_y, \qquad b_z := W u_z. The role of the argument ``kktsolver`` in the function :func:`cpl ` is similar, except that in :eq:`e-cp-kkt`, .. math:: H = \sum_{k=0}^{m-1} z_k \nabla^2f_k(x), \qquad \tilde G = \left[\begin{array}{cccc} \nabla f_0(x) & \cdots & \nabla f_{m-1}(x) & G^T \end{array}\right]^T. **Specifying constraints via Python functions** In the default use of :func:`cp `, the arguments ``G`` and ``A`` are the coefficient matrices in the constraints of :eq:`e-cp-kkt`. It is also possible to specify these matrices by providing Python functions that evaluate the corresponding matrix-vector products and their adjoints. * If the argument ``G`` of :func:`cp` is a Python function, then ``G(u, v[, alpha = 1.0, beta = 0.0, trans = 'N'])`` should evaluates the matrix-vector products .. math:: v := \alpha Gu + \beta v \quad (\mathrm{trans} = \mathrm{'N'}), \qquad v := \alpha G^T u + \beta v \quad (\mathrm{trans} = \mathrm{'T'}). * Similarly, if the argument ``A`` is a Python function, then ``A(u, v[, alpha = 1.0, beta = 0.0, trans = 'N'])`` should evaluate the matrix-vector products .. math:: v \alpha Au + \beta v \quad (\mathrm{trans} = \mathrm{'N'}), \qquad v := \alpha A^T u + \beta v \quad (\mathrm{trans} = \mathrm{'T'}). * In a similar way, when the first argument ``F`` of :func:`cp ` returns matrices of first derivatives or second derivatives ``Df``, ``H``, these matrices can be specified as Python functions. If ``Df`` is a Python function, then ``Df(u, v[, alpha = 1.0, beta = 0.0, trans = 'N'])`` should evaluate the matrix-vector products .. math:: v := \alpha Df(x) u + \beta v \quad (\mathrm{trans} = \mathrm{'N'}), \qquad v := \alpha Df(x)^T u + \beta v \quad (\mathrm{trans} = \mathrm{'T'}). If ``H`` is a Python function, then ``H(u, v[, alpha, beta])`` should evaluate the matrix-vector product .. math:: v := \alpha H u + \beta v. If ``G``, ``A``, ``Df``, or ``H`` are Python functions, then the argument ``kktsolver`` must also be provided. As an example, we consider the unconstrained problem .. math:: \begin{array}{ll} \mbox{minimize} & (1/2)\|Ax-b\|_2^2 - \sum_{i=1}^n \log(1-x_i^2) \end{array} where :math:`A` is an :math:`m` by :math:`n` matrix with :math:`m` less than :math:`n`. The Hessian of the objective is diagonal plus a low-rank term: .. math:: \newcommand{\diag}{\mbox{\bf diag}\,} H = A^TA + \diag(d), \qquad d_i = \frac{2(1+x_i^2)}{(1-x_i^2)^2}. We can exploit this property when solving :eq:`e-cp-kkt` by applying the matrix inversion lemma. We first solve .. math:: \newcommand{\diag}{\mbox{\bf diag}\,} (A \diag(d)^{-1}A^T + I) v = (1/z_0) A \diag(d)^{-1}b_x, \qquad and then obtain .. math:: \newcommand{\diag}{\mbox{\bf diag}\,} u_x = \diag(d)^{-1}(b_x/z_0 - A^T v). The following code follows this method. It also uses BLAS functions for matrix-matrix and matrix-vector products. :: from cvxopt import matrix, spdiag, mul, div, log, blas, lapack, solvers, base def l2ac(A, b): """ Solves minimize (1/2) * ||A*x-b||_2^2 - sum log (1-xi^2) assuming A is m x n with m << n. """ m, n = A.size def F(x = None, z = None): if x is None: return 0, matrix(0.0, (n,1)) if max(abs(x)) >= 1.0: return None # r = A*x - b r = -b blas.gemv(A, x, r, beta = -1.0) w = x**2 f = 0.5 * blas.nrm2(r)**2 - sum(log(1-w)) # gradf = A'*r + 2.0 * x ./ (1-w) gradf = div(x, 1.0 - w) blas.gemv(A, r, gradf, trans = 'T', beta = 2.0) if z is None: return f, gradf.T else: def Hf(u, v, alpha = 1.0, beta = 0.0): # v := alpha * (A'*A*u + 2*((1+w)./(1-w)).*u + beta *v v *= beta v += 2.0 * alpha * mul(div(1.0+w, (1.0-w)**2), u) blas.gemv(A, u, r) blas.gemv(A, r, v, alpha = alpha, beta = 1.0, trans = 'T') return f, gradf.T, Hf # Custom solver for the Newton system # # z[0]*(A'*A + D)*x = bx # # where D = 2 * (1+x.^2) ./ (1-x.^2).^2. We apply the matrix inversion # lemma and solve this as # # (A * D^-1 *A' + I) * v = A * D^-1 * bx / z[0] # D * x = bx / z[0] - A'*v. S = matrix(0.0, (m,m)) v = matrix(0.0, (m,1)) def Fkkt(x, z, W): ds = (2.0 * div(1 + x**2, (1 - x**2)**2))**-0.5 Asc = spdiag(ds) * A blas.syrk(Asc, S) S[::m+1] += 1.0 lapack.potrf(S) a = z[0] def g(x, y, z): x[:] = mul(x, ds) / a blas.gemv(Asc, x, v) lapack.potrs(S, v) blas.gemv(Asc, v, x, alpha = -1.0, beta = 1.0, trans = 'T') x[:] = mul(x, ds) return g return solvers.cp(F, kktsolver = Fkkt)['x'] .. _s-parameters2: Algorithm Parameters ==================== The following algorithm control parameters are accessible via the dictionary :attr:`solvers.options`. By default the dictionary is empty and the default values of the parameters are used. One can change the parameters in the default solvers by adding entries with the following key values. :const:`'show_progress'` :const:`True` or :const:`False`; turns the output to the screen on or off (default: :const:`True`). :const:`'maxiters'` maximum number of iterations (default: :const:`100`). :const:`'abstol'` absolute accuracy (default: :const:`1e-7`). :const:`'reltol'` relative accuracy (default: :const:`1e-6`). :const:`'feastol'` tolerance for feasibility conditions (default: :const:`1e-7`). :const:`'refinement'` number of iterative refinement steps when solving KKT equations (default: :const:`1`). For example the command >>> from cvxopt import solvers >>> solvers.options['show_progress'] = False turns off the screen output during calls to the solvers. The tolerances :const:`abstol`, :const:`reltol` and :const:`feastol` have the following meaning in :func:`cpl `. :func:`cpl` returns with status :const:`'optimal'` if .. math:: \newcommand{\ones}{{\bf 1}} \frac{\| c + Df(x)^Tz_\mathrm{nl} + G^Tz_\mathrm{l} + A^T y \|_2 } {\max\{ 1, \| c + Df(x_0)^T\ones + G^T\ones \|_2 \}} \leq \epsilon_\mathrm{feas}, \qquad \frac{\| ( f(x) + s_{\mathrm{nl}}, Gx + s_\mathrm{l} - h, Ax-b ) \|_2} {\max\{1, \| ( f(x_0) + \ones, Gx_0 + \ones-h, Ax_0-b) \|_2 \}} \leq \epsilon_\mathrm{feas} where :math:`x_0` is the point returned by ``F()``, and .. math:: \mathrm{gap} \leq \epsilon_\mathrm{abs} \qquad \mbox{or} \qquad \left( c^Tx < 0, \quad \frac{\mathrm{gap}} {-c^Tx} \leq \epsilon_\mathrm{rel} \right) \qquad \mbox{or} \qquad \left( L(x,y,z) > 0, \quad \frac{\mathrm{gap}} {L(x,y,z)} \leq \epsilon_\mathrm{rel} \right) where .. math:: \mathrm{gap} = \left[\begin{array}{c} s_\mathrm{nl} \\ s_\mathrm{l} \end{array}\right]^T \left[\begin{array}{c} z_\mathrm{nl} \\ z_\mathrm{l} \end{array}\right], \qquad L(x,y,z) = c^Tx + z_\mathrm{nl}^T f(x) + z_\mathrm{l}^T (Gx-h) + y^T(Ax-b). The functions :func:`cp ` and :func:`gp ` call :func:`cpl` and hence use the same stopping criteria (with :math:`x_0 = 0` for :func:`gp`). cvxopt-1.1.4/doc/source/copyright.rst0000644000175000017500000000372011674452555016715 0ustar sonnesonne.. role:: raw-html(raw) :format: html ********************* Copyright and License ********************* | | :raw-html:`©` 2010-2011 L. Vandenberghe. | :raw-html:`©` 2004-2009 J. Dahl and L. Vandenberghe. CVXOPT is free software; you can redistribute it and/or modify it under the terms of the `GNU General Public License `_ as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. CVXOPT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the `GNU General Public License `_ for more details. .. raw:: html
The CVXOPT distribution includes the source code of part of the `SuiteSparse `_ collection of sparse matrix algorithms. The copyright and license information for the included libraries is as follows. * **AMD** Version 2.2. Copyright (c) 2007 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. * **CHOLMOD** Version 1.7.1. Copyright (c) 2005-2009 by the University of Florida, Timothy A. Davis, and W. Hager. * **COLAMD** Version 2.7. Copyright (c) 1998-2007 by Timothy A. Davis. * **UMFPACK** Version 5.4.0. Copyright (c) 1994-2009 by Timothy A. Davis. UMFPACK and the Supernodal module of CHOLMOD are licensed under the terms of the `GNU General Public License, version 2 `_ or higher. The other CHOLMOD modules, AMD, and COLAMD are licensed under the terms of the `GNU Lesser General Public License, version 2.1 `_ or higher. For more details, consult the README files in the source directories or the documentation at `www.cise.ufl.edu/research/sparse `_. cvxopt-1.1.4/doc/source/index.rst0000644000175000017500000000046311674452555016015 0ustar sonnesonne###### CVXOPT ###### **Release 1.1.4 -- December 21, 2011** **Joachim Dahl & Lieven Vandenberghe** .. toctree:: copyright.rst intro.rst matrices.rst blas.rst lapack.rst fftw.rst spsolvers.rst coneprog.rst solvers.rst modeling.rst c-api.rst printing.rst cvxopt-1.1.4/doc/source/portfolio2.png0000644000175000017500000006675511674452555017001 0ustar sonnesonnePNG  IHDR,d(sBIT|d pHYsaa?i IDATxwtTg&@HDz4&"E"AkÎW kA/ ]P$Bt5hBNHIf%93dG3]#p @F,,,,,,,,,,,,,,,,,rWȑ#ӦMӳ28M߾}vo>KIoUÆ $ۭnݺ[nZhkFn[׷R?($$DC IwlС-*ۭbŊIF!ۭ.ױ bŊ W#~v˗Ojժe}}|v5.%Ѻ{t=1b$IǎS믿j1bls7|p%$$W^IsRR:vUVW^1b^z%IVrJtt *$ۭ޽{_c/_g}VmڴQhhn7oט1ctwdɒ*P:y믽>_VBB~E2.q\)sLNN֞={4o&666弩SeOqqqyvz+S>ܸ\.zj3i$s-`SRsN>mx S^=SP!s5ט&M9syzȸ\.4wj{1.ڵˌ3Ԯ]-[9w^3~xSvmS`ASdI#cǎegQb l- w1m۶5%J07Ŋ3mڴ1//_nn6lBBBL׮]?zgDFF{ה,Y(P/_ 4%5Ƙ>\.3a„tuܹ4r_<²uVStiShQbŊ+ mѢE'?11t͸ne˖K7ow~yRJȑ#Xzurrri۶q\槟~"esΙ;'N07t 1gϞMɓ&$$͛7ys=ҾR&^zIu֙@ӵkL_cYvq\jժijOLL4;w6.˼isSF#l2rL5\.ӪU+fx r̸q4hq\fѢE)\Ҹ\.Ӷm[s̙4Wr!C\MI&eƎvegJ.mߟ|y'MPPdˉ'Lɒ%M@@پ}sƎk\.OFc g19rFaÆO>jѢTR}I?.Pռys~P֭=  }/+x15oPNݵDFFuJNNV6mԵkW]{rڲe,XsΥqIp~=z+\.Wj?~<˱cTx+J] =C S~C=X%%%]r!r[gF(HV8ӊ+fUWR|-Zh^=r6 0;… eC=3gdӼytqmܸQoOo|M}ݚ:uSNUrrr-))ISLT=3<9.~+Vd [DѣG+!!Ak֬ŋ{\*تUt{~ƞO/"Erĉx>a\l (Z?Nfv{G ̙3eQLL-[nIuIsn"Es@xر=5Ou6oެgϪf͚i6|3k,L-'|RZnN<>Y^ U ߿Ǻn|z4gIgA``͛ݻkԩӧOeZYqWgC:Ow8Xv\RJy>^>nҤ1YR7,cV\؁r6"Yٳ^kXv u]5k,%%%]~_37,I^GLL]yjn:t$UZU HyhV2h7nN-^X }z4k,JLLxY׻K7noCi߾})|Z3)Iz$Rԡ &&撗9KÇu KK.*VM2W^nqϟ_O?tǓO?e~Xh?rRR|IcԿL?x'R>|8#G|߰aCn͙3'uO֋/SEf̘3f(^~%I<בgz߄gx˗Oߟr1F>}ꫯjĉn?|J'N+q۷o{1h0a:t蠅 ^2>@cƌo3fĉբE x ݻ5|,XPO=TuS*!!A_}U\qiǎz饗4sLjJEQllnݪ 6h֬YP$f͚*WfΜ Lzӧ*T e˖Z|5k-[*..NS6m{nkE֭v5tPm۶M tSw^7^$=~}a9s馛LPPPj1Ƙ/ԯ_bŊvڙ+W^m?㒯/}+ SfMӯ_?|L_N 6 LܹsνT%K˄|RJN:4%$$_|є+W(PTVͼ[&11>,iϟs׮]kzaʔ)co .lԩcezcyW2?ccj×z_}_)X)Qݻ믿LÆ MHHHkr\.iӦl/yo{_|s{a1ׯ7. 6̧ c.cXСC\|p(QBӏ?mcjƌڳg}}9,!K#<ٳg+&&狋K1Fu̙l$o͜9S وG5jP޽xe?^GV۶mUlY:uJ+VPTT4hQ Ȣʝ駟͒@6"e1B7o֑#G?~U\Y{^|aC`Xyv˩S4d-[VAAA_>n2dZhEvk^mٲez=7&X.-r=lPWzu͚5KaaaJNNVXXX۹sfϞcǎ3gNSRf͚澢Efr0;057y2zEK9]z\?%DFܹ.\hwChs9}'ԭ[W/Hj׮mGY.'Knt)͝;7ӦMSٲeոql{3fH4imy򒰻Km۶u UREsYf _3fݻU|{ݻ%I6lPpp${5kW׮]UbŔIƍS6mtw[R ,4|6lt 7?W=RINNVrrr$q\r)))ITti9sFC|z5j}ٜy˓;Ť{9s(,,2`r}:X .ON,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,]{?`we@B__._a%1"uo_ƁA)uLbER_+T>?}:X SQ 9r¹nT\Ɓ|y)0^>,E3gg@M?\87_>+tx #*IeJgm}|G`q( IDAT(7a40gs|˲*WB<˹r~t#8Y3!9t¹FH.%+H.>,EV 8xzRm]:\9kşЧšhx!hd~)9:FAʕ@R=#Чšh QoGFORCRT#$*\*[>,E9Q+ޝZuy(}tHyNEwqYi[ ٳG:~¹ K_o*WzBIŊRB DwqJNV(8p|:b5A֠O;CѸ@jǏgH(Y2@RP4n򖄄 ;{ &G^8PIJ\$|G`q(7O\k@vp۽Z ;{ &]e[>,E$'[ERԷc.[Tux{A"O;CѸps˴={.%q"C*U܏>,E>GlsK}V`5*:xn*I 6|G`q(7'9ڽ=KROp/Z{ RE*[Vr{p>t#8xBΝҎ]ٳM}7.݂/P4n.+#wJnkĪUjլ[ժV \K}P4n,PmPRB@R%k P4n@^btP#%gX\GJUFJ%pt#88!uiCg`rt#8Ο#8DGK_8tiF zu &)AnBwq)&&m ]DB.5.ܪUt#8gZkyq˚Ԟ:xJٲq O;CѸ9q/~gυ]CB*U }:X jHGx&YxFKn!F )4DwqVrރɱc9Y#$ނIp }:X c~5m )K5kJ7ޘ6T"oo@^@wqRIL~U:y:~5RRZLʗv`t#8' _m Hio*D|G`q(7n~%۶I[Z_Yڷ:v[sL.&UXOt#8rӧQO0ٺ 'O[KnI[WS &5kT0ЧšhlINv&XA䦛z.|-Qdt#8aiFi&qLIJճ&3j-|G`q(78ˑ#BֱPA[7,U$xšh`3gPi?i~XHJR Чšh3vN"#'IIRBRÆRF J'2>,Equ9ך5ڵR\ufM[/jb aO;CѸ k=դI*THŋW~g[vIٲSOI H&X&<\zQ >y6s=1cFKaÆ Ӝ9s.;wj*X:v(JDDD}*].\>@jӦ=@f}ҝۨQ#={V۶mKy׫YfO裏fX#ÇҡCҼyҗ_JkJII'u,-jw;ѧ]aUpaw}iׯ<~)ǦMT;p6nܨ޽{ ?M4Q_>ĚRRԩ֤o!-_ 7ܐnN:(5iאu;VN[Χobb󭑔C^jLz{wL+yrHI:}^~e}嗊 7ܠ^zI=zH9_~1c٣ *ܟz9ԛ\.%%%yp 6L[nUppn;V]fF, VHkd~}),LCX O<X NII?X!e\k"}͚VHSQ Y>,Erc~Bʗ_JI*IoֵN>|'@v3Fg+|wT5rRƄ2Y(: (sH۷K!!֤n] B 9Ç !ek_@+؅>,E1k̙$}S¬M|%aIҬYDuki{kBrFX48Cra̛'?.|ԫu:.>,Ecm52gtTRzM 3K4{T뮳!KV!~5’%&&;VB*>q gJ_}ek]Z!;/FX=믿w\JJJ2(!4?}d5Om[Ϭr5vW<" ݥ׌[z=ԧTr;t˥:u]?qhʊR/i#1H p]@fo^k׮ ,^-'*%mU4I:|ؚT睄_޽ *Ν;/3bCBBl v.3kY믗޺/永ݗʍq#SL"Zk|>RfptaÆ] #4yVhkǮ]S@&MoT.@VԺ+&FjZ{`N#,UINN΁JriQbd5t5ҧ4hT/FXvmw |p5RFֿ{d4\_Eqd)<MYP*XКHڱCSW/0+rҩgw{c\.6ƍ$>sF]:UjڔҢEt:uJWV…ᅲ>P;xq驧Gʖ:E`6mO8;S;vقe_d>bRBBBmw@/;HgK IK?.+gwe O?Teʔ 1FZZ;֚RҀr_VZ 摘۷lSe@$͛'#m$խ+}5?%~y_cLk (;*,,LwyMGb4gHw!-[&m`t[1A 9%!AyMi.sgW Gwn ȌQF^:tHFw4~T5/妛-[ +9bv+22R5JwlƍjԨm,Ƒ]3#e{^~Y]}/FX.%>>^ \1d:u[o~͚BXNI۶mӶmRŋ}4$$$h֬YR%~#<\z%iF];iLA<:ܔ^{yAAA2eJNyFZQYJj2ϱsX<2ѾQF:ujժ@UREv|Tcn,O @NO;V^ pvchܸII҄ ҫJ[?hweM|رcTllڷoK64n\[ IGKJ]y}:*aFR2eԡCG{$o^#G8FNI='rtҤI;E`O4j(=cZ|yھ}{-[Y#իgUyuifiS:]%,qiС=zoT`xkʻZe2jUz~Xvޭ`9s&+-w}ֲvW=")RDz?Tɒ%s".=T5n]+^~1M6;vΞ=dM0Aڵ2 g$%I/ IwmXOXy_,kc5lP޽ƎG}T7o֎;yfUX2Ki+,^,4d@//$ozgrJ%&&* @Z|nc}N?K_~)u`wEJЧK||f̘o]5kT||bccUX1]^q#.NjZ:p@ZDjO;c ,p5orr ;o;yRjJOijV-+W>J_8KrDRԣc*aO=~m:uRlKsZea(_R;?2 k-X [R۶vW`?a$A9PIzǼgNAk,] @n@w~X"wrԤt}"vW}:%a@nfO?VR#6?^3i,vmp. s(~7 >j@VO;CѸsnY*WN "/ar$s礯"d9, FV6,Wjŋѣ7ސڴgsVZɕ1r\ZreTs1wڳǚҼ7R&D~>;zFGGêV/ܹSJR5,Ȕg{BB3+z;=ڴiׯr͛գG=6T\'~]Z^*Zjc/ KAz;6sLڲe esɓS}tR~7UPrኀ۲Ez1i@ RD ͛7dɒ9\9GZVjז>jc簤ciС߯%Jȑ#5{lv,-?nR"I#FosΥW`A=s5jew.dt]vW@w~X$رcZ~bcc&Mh.]nߖ/ڵ vy}:U`Kh믿!4v"`tIC[oUj%I0a6mdsu9{w)8X5+tg5mT'OT k׮,۷oWDDfϞms֭ڵRh?ayTT)޽[+VHsiӦZnM̚%}RÆvW;ˊ+4yd(QBi.]Z2/#H}XD kK||B3&>>^9\pժIr]@z zl͚5]vWXͳ& %aO?e*,,LdѢE{飏>BU+͟/}T>~1F ҤIRֲPRR]bcn狈ڴ^zMNDw~X<"##h"9rD]wn5m6F|~1V r}:E`ٷoJ* ;vy:tH*TCv֭ݻ͛%8}:ŤJ*i֭^m۶M+Wነ *EFJ_}EXn~!Krr% +>rՈ#,9uu] ۥzxja9rF 'Pe9)qckߕO+>{IXÆ K'{*QDsUn]=v<G} +9ɱ#,WÆ _ow)94}$=RvW }:E`ɋhΰ~tKCw~XF8{=3*^^z%*>4nXCV$Z%owEЧ_gVZ^թSG3fነ%&Jaa&_~IXc'ݧgլYjժi9\raä)<\*Sj.,zѣ*P@Wl71c- o9,mڴQpplK> IDATt:w'OjժU6T};wJ"j%͟/\vW}:E`Yt:tvGUҥuAM8QK.Ւ%Kt]w]fq3g&M7JE]w|E&OgyF'OLH"zwXYq,c~ RݺvWrt"INҺuxj֬ *dwYقƝ&N >LzA}:U`Kh9gFY3O&|HRLL[oUժUSTT$i„ ڴi_JݻK걓=Ų{QӦMuI5h@vҹs$I۷oWDDfϞms7II_NI? ].#,/J*ݻwkŊi5mT֭2ѣeˤٳ ˊ+4yd(QBiy8ҥȑ;xfx,kypzڷ^~jp)~XWp֬YڵkpEW$k0v_@ 8PO?ʖ-0I1F-{ァ> / ~UG)$jp9~1F ҤIRֲPRR]bc7}ԷҀvWtEȑ#twiӦv-hYk6[0id岻"Ч_ƝunE*\XZN "WЧ_aXnV^Xe˖vY#9Yz!kG',gϞUϞ=hѢt:t蠯JADŘ1…ҷJ_ow5R~ /˗w=*AD4rG"Za~d9d=IMFK"2ݼ3:)Y?xr9p^k{߫P^umܸQ'Ovw<4`9,DqwEqNW}qܹs-;w+JÆI JKVrwWyYg^知C6m9s+G\aF3FJL֯v~wWPsI#ׇ!`rS<~ @}%>>^?CڵKu\b۶⻂']Ax,Ӎ7ިt~[7|T{z^y6xD`/ԱcGOӦMӏ?'h.uH+KJ <\3p^/,___?СC]Z`VyFz )#CVwWP>#HnWfdUPP-ZC. nzkҫV;,gΜ=ܣI&iܸqʒ$uM)))nuAi O>jPY4eK***ryCڷo*CmziFOV] #ˡCԯ_rkԨΝ;WY#/K}G ?Çu5qEM4j4`4e;yD`̙3uyvá>@ n 5-?)RJd C^xuU{$?0>7|7W2qcGqhw۷׿z-IܹsuUWi۶mjݺ+DM?_7OJNn <9,%u)QF.x=?\x@3 o; X7uӧ.]o+tNW[>s@`ܹ ^ǥ]jԎ|NWWÂ:Sŷ1޶XPRSߗGkWwWIyyy4ih-[J.x(߿_å}ݒ ׍,_UY[\Y<~LgOwWO敁eȐ!ʕ+].\0;_,g[QQ-ZݻEn;%%E[=1c=H\)yp_%Kh޼yHJرcCUVBuEgΜь3dYF[$I~~m *O:*EyJɑ֭M$??wW`rNge^y0Ԍ Ë|9a5k'ݣM+.G\?f̐zvw5bQVwR.Ae*fswEds:OA`(vXY);[jwW`]V=$ C#=t𠔙IX@#͓,>Hrw5 (]>Ζz|P=xy"EYsJ;KҧJ "`s:OŐ0TF[ +[T꥗u_]OӋ_ ވ9,[Nl>,]P |#}Դ[xc xq髯 +p/ \|Ҝ9R.ގ!aˇ_~)JVwV}K7$5n,!٦-K1$ r8ѣ,1aVA`fΔҊ__jbHEÌ ۥ)S_xUŢs=*EGK_*,U۝P)~8dhhm kX9,^駥liV ⅖-yGz={wwWT!aU[퓺u RSy8$@mbHXX,6:?]ڹ!=cH0Fz!V ,^w˥+UÐ0ˇ۶I{K5UŢjs8QppiF׷@XP{[ViR=RFԲ.ZZz5ץ[ouw5aEUg7H7$#\!܅9,G`+gJRAktUPR} GyD'V,HhjcHE]ì,[qYj0TCªbQӹQҥ[J~~\R}<8] tba sX<܋/J'HZfX<ڵ_59,uG񼕞=? TŢ*Ai8T &Nv ~#x yhwW.YTyBFuSa2UŢJwӧn47ߍJ,ǐ0pHEl6m&ujp%, { WX,f0] WX+,FX#, ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ", ,yyy4ih-[J]ׯW׮]5|K M6wUZZO[nuYv˖-߿Zl4;JOOW|| ks;4pwvZkɒ%JLL$Kɓ(,j޽ڱcbbb$Iqqqԩ~ieff:\4vXСCjժ$P]tљ3g4c (99Yk֬Qzzn6l٢o]#<'Ojʔ) Vvv|}}ݲ+,j*5JӦMSk.-]V$pp'ƍջwoM8Q ҉'n:gXӤI4bIuw귿q ɓ'G(wt*00P!!!3frrrj+)saaa Ptt-[Vud˼㎚x+s&M^zI&裏*\.Vc.v}nu$usEEEz'xefp+F`86L68nZ&LPZZ.7Uoqcjرc}v\RaaaU^c]1հf͚sssWnr[e+ꟺs%q.gfp>u*±;D3hܸqJMMՂ 4hР2۸3Koc]1K ]n/Iw$EDDTndd2-YѲmO]9bsUqE.V>gC= ?tߋqK 2drJ *,,nL_+++VTTE{jѢ$),,LݺuӢE\GjС5WsIIIT|7x8UcwN+pB͙3GG.w9uUE kIDAT*c}5M65s5>d4 40Gq3mp4K-3?iٲiذͲe\IJJ2v>|إĉfѦYf& lܸlذƚӬY3drrrjm`]ӯ_?s___`:ud^y^:}f9_vK8vXҮϵiƥ]j۶mp,,,,,,udzwZ… euȑ:ٞn /pEn޼Yv][nkۯ ׮][᾵iF>`uJŋo:g]Bƍ+Z矯NihXJ;wN5rwW,,,LaaaW~EN:]g\qj5j(hBjҤbbb.IڵkSv*sϩK. :v쨷zvڴijܹԺuk{eTϞ=0=_,޽{ySV4a9se$iϞ=۷*Gt7N͛7WPP﯃Vկ_?*$$D<~rMOOW||j5jH7|222Dzڸqcu?nkݒV#))I2Ƹ=KڵiFcƌq#Ghȑk7|S2%7Лom_ڴiSOO5 11Q}f̘7矕~I4{l?^իˬ?jĉeQffO}%IVVV?sڱc Pĉի*-X@Zx&LPfEiѺ|r>PBB>vm0`BCCpBǻ`uE.~ӦMӹsrJ!e-Zp~ş=zGZn5kho| áSꮻҡCԼy*}Po@ɓ'W̝wiڶm{Ϻp_+b7o^֭M``9qℳȄ$g[bbiҤ9uꔳphcÇݶ0پ}l櫯r7zhcҥK]Ynlf޼y.ol^tyc8>h c̖-[1Ɯ={4m$&&[n&&&SOF3g8gl6ymfʾ{u۴icƌ}ʔ)nݻw,OnjҤ4h ???=UNNNm:QuQgۦMԧO5mft= ACiĈjٲs={T`, :func:`min `, :func:`abs ` and :func:`sum ` (see the section :ref:`s-functions`). A more general Python convex modeling package is `CVXMOD `_. .. _s-variables: Variables ========= Optimization variables are represented by :class:`variable` objects. .. function:: cvxopt.modeling.variable([size[, name]]) A vector variable. The first argument is the dimension of the vector (a positive integer with default value 1). The second argument is a string with a name for the variable. The name is optional and has default value :const:`""`. It is only used when displaying variables (or objects that depend on variables, such as functions or constraints) using :func:`print` statements, when calling the built-in functions :func:`repr` or :func:`str`, or when writing linear programs to MPS files. The function :func:`!len` returns the length of a :class:`variable`. A :class:`variable` ``x`` has two attributes. .. attribute:: name The name of the variable. .. attribute:: value Either :const:`None` or a dense :const:`'d'` matrix of size ``len(x)`` by 1. The attribute ``x.value`` is set to :const:`None` when the variable ``x`` is created. It can be given a numerical value later, typically by solving an LP that has ``x`` as one of its variables. One can also make an explicit assignment ``x.value = y``. The assigned value ``y`` must be an integer or float, or a dense :const:`'d'` matrix of size ``(len(x), 1)``. If ``y`` is an integer or float, all the elements of ``x.value`` are set to the value of ``y``. >>> from cvxopt import matrix >>> from cvxopt.modeling import variable >>> x = variable(3,'a') >>> len(x) 3 >>> print(x.name) a >>> print(x.value) None >>> x.value = matrix([1.,2.,3.]) >>> print(x.value) [ 1.00e+00] [ 2.00e+00] [ 3.00e+00] >>> x.value = 1 >>> print(x.value) [ 1.00e+00] [ 1.00e+00] [ 1.00e+00] .. _s-functions: Functions ========= Objective and constraint functions can be defined via overloaded operations on variables and other functions. A function ``f`` is interpreted as a column vector, with length ``len(f)`` and with a value that depends on the values of its variables. Functions have two public attributes. .. attribute:: variables Returns a copy of the list of variables of the function. .. attribute:: value The function value. If any of the variables of ``f`` has value :const:`None`, then ``f.value()`` returns :const:`None`. Otherwise, it returns a dense :const:`'d'` matrix of size ``(len(f),1)`` with the function value computed from the :attr:`value` attributes of the variables of ``f``. Three types of functions are supported: affine, convex piecewise-linear, and concave piecewise-linear. **Affine functions** represent vector valued functions of the form .. math:: f(x_1,\ldots,x_n) = A_1 x_1 + \cdots + A_n x_n + b. The coefficients can be scalars or dense or sparse matrices. The constant term is a scalar or a column vector. Affine functions result from the following operations. **Unary operations** For a variable ``x``, the unary operation ``+x`` results in an affine function with ``x`` as variable, coefficient 1.0, and constant term 0.0. The unary operation ``-x`` returns an affine function with ``x`` as variable, coefficient -1.0, and constant term 0.0. For an affine function ``f``, ``+f`` is a copy of ``f``, and ``-f`` is a copy of ``f`` with the signs of its coefficients and constant term reversed. **Addition and subtraction** Sums and differences of affine functions, variables and constants result in new affine functions. The constant terms in the sum can be of type integer or float, or dense or sparse :const:`'d'` matrices with one column. The rules for addition and subtraction follow the conventions for matrix addition and subtraction in the section :ref:`s-arithmetic`, with variables and affine functions interpreted as dense :const:`'d'` matrices with one column. In particular, a scalar term (integer, float, 1 by 1 dense :const:`'d'` matrix, variable of length 1, or affine function of length 1) can be added to an affine function or variable of length greater than 1. **Multiplication** Suppose ``v`` is an affine function or a variable, and ``a`` is an integer, float, sparse or dense :const:`'d'` matrix. The products ``a * v`` and ``v * a`` are valid affine functions whenever the product is allowed under the rules for matrix and scalar multiplication of the section :ref:`s-arithmetic`, with ``v`` interpreted as a :const:`'d'` matrix with one column. In particular, the product ``a * v`` is defined if ``a`` is a scalar (integer, float, or 1 by 1 dense :const:`'d'` matrix), or a matrix (dense or sparse) with ``a.size[1]`` equal to ``len(v)``. The operation ``v * a`` is defined if ``a`` is scalar, or if ``len(v)`` is 1 and ``a`` is a matrix with one column. **Inner products** The following two functions return scalar affine functions defined as inner products of a constant vector with a variable or affine function. .. function:: cvxopt.modeling.sum(v) The argument is an affine function or a variable. The result is an affine function of length 1, with the sum of the components of the argument ``v``. .. function:: cvxopt.modeling.dot(u, v) If ``v`` is a variable or affine function and ``u`` is a :const:`'d'` matrix of size ``(len(v), 1)``, then ``dot(u, v)`` and ``dot(v, u)`` are equivalent to ``u.trans() * v``. If ``u`` and ``v`` are dense matrices, then :func:`dot` is equivalent to the function :func:`blas.dot `, i.e., it returns the inner product of the two matrices. In the following example, the variable ``x`` has length 1 and ``y`` has length 2. The functions ``f`` and ``g`` are given by .. math:: f(x,y) &= \left[ \begin{array}{c} 2 \\ 2 \end{array}\right] x + y + \left[ \begin{array}{c} 3 \\ 3 \end{array}\right], \\ g(x,y) &= \left[ \begin{array}{cc} 1 & 3 \\ 2 & 4 \end{array}\right] f(x,y) + \left[ \begin{array}{cc} 1 & 1 \\ 1 & 1 \end{array} \right] y + \left[ \begin{array}{c} 1 \\ -1 \end{array} \right] \\ &= \left[ \begin{array}{c} 8 \\ 12 \end{array}\right] x + \left[ \begin{array}{cc} 2 & 4 \\ 3 & 5 \end{array}\right] y + \left[ \begin{array}{c} 13 \\ 17\end{array}\right]. >>> from cvxopt.modeling import variable >>> x = variable(1,'x') >>> y = variable(2,'y') >>> f = 2*x + y + 3 >>> A = matrix([[1., 2.], [3.,4.]]) >>> b = matrix([1.,-1.]) >>> g = A*f + sum(y) + b >>> print(g) affine function of length 2 constant term: [ 1.30e+01] [ 1.70e+01] linear term: linear function of length 2 coefficient of variable(2,'y'): [ 2.00e+00 4.00e+00] [ 3.00e+00 5.00e+00] coefficient of variable(1,'x'): [ 8.00e+00] [ 1.20e+01] **In-place operations** For an affine function ``f`` the operations ``f += u`` and ``f -= u``, with ``u`` a constant, a variable or an affine function, are allowed if they do not change the length of ``f``, i.e., if ``u`` has length ``len(f)`` or length 1. In-place multiplication ``f *= u`` and division ``f /= u`` are allowed if ``u`` is an integer, float, or 1 by 1 matrix. **Indexing and slicing** Variables and affine functions admit single-argument indexing of the four types described in the section :ref:`s-indexing`. The result of an indexing or slicing operation is an affine function. >>> x = variable(4,'x') >>> f = x[::2] >>> print(f) linear function of length 2 linear term: linear function of length 2 coefficient of variable(4,'x'): [ 1.00e+00 0 0 0 ] [ 0 0 1.00e+00 0 ] >>> y = variable(3,'x') >>> g = matrix(range(12),(3,4),'d')*x - 3*y + 1 >>> print(g[0] + g[2]) affine function of length 1 constant term: [ 2.00e+00] linear term: linear function of length 1 coefficient of variable(4,'x'): [ 2.00e+00 8.00e+00 1.40e+01 2.00e+01] coefficient of variable(3,'x'): [-3.00e+00 0 -3.00e+00] The general expression of a **convex piecewise-linear** function is .. math:: f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n + \sum_{k=1}^K \max (y_1, y_2, \ldots, y_{m_k}). The maximum in this expression is a componentwise maximum of its vector arguments, which can be constant vectors, variables, affine functions or convex piecewise-linear functions. The general expression for a **concave piecewise-linear** function is .. math:: f(x_1,\ldots,x_n) = b + A_1 x_1 + \cdots + A_n x_n + \sum_{k=1}^K \min (y_1, y_2, \ldots, y_{m_k}). Here the arguments of the :func:`!min` can be constants, variables, affine functions or concave piecewise-linear functions. Piecewise-linear functions can be created using the following operations. **Maximum** If the arguments in ``f = max(y1, y2, ...)`` do not include any variables or functions, then the Python built-in :func:`!max` is evaluated. If one or more of the arguments are variables or functions, :func:`!max` returns a piecewise-linear function defined as the elementwise maximum of its arguments. In other words, ``f[k] = max(y1[k], y2[k], ...)`` for ``k`` = 0, ..., ``len(f) - 1``. The length of ``f`` is equal to the maximum of the lengths of the arguments. Each argument must have length equal to ``len(f)`` or length one. Arguments with length one are interpreted as vectors of length ``len(f)`` with identical entries. The arguments can be scalars of type integer or float, dense :const:`'d'` matrices with one column, variables, affine functions or convex piecewise-linear functions. With one argument, ``f = max(u)`` is interpreted as ``f = max(u[0], u[1], ..., u[len(u)-1])``. **Minimum** Similar to :func:`!max` but returns a concave piecewise-linear function. The arguments can be scalars of type integer or float, dense :const:`'d'` matrices with one column, variables, affine functions or concave piecewise-linear functions. **Absolute value** If ``u`` is a variable or affine function then ``f = abs(u)`` returns the convex piecewise-linear function ``max(u, -u)``. **Unary plus and minus** ``+f`` creates a copy of ``f``. ``-f`` is a concave piecewise-linear function if ``f`` is convex and a convex piecewise-linear function if ``f`` is concave. **Addition and subtraction** Sums and differences involving piecewise-linear functions are allowed if they result in convex or concave functions. For example, one can add two convex or two concave functions, but not a convex and a concave function. The command ``sum(f)`` is equivalent to ``f[0] + f[1] + ... + f[len(f) - 1]``. **Multiplication** Scalar multiplication ``a * f`` of a piecewise-linear function ``f`` is defined if ``a`` is an integer, float, 1 by 1 :const:`'d'` matrix. Matrix-matrix multiplications ``a * f`` or ``f * a`` are only defined if ``a`` is a dense or sparse 1 by 1 matrix. **Indexing and slicing** Piecewise-linear functions admit single-argument indexing of the four types described in the section :ref:`s-indexing`. The result of an indexing or slicing operation is a new piecewise-linear function. In the following example, ``f`` is the 1-norm of a vector variable ``x`` of length 10, ``g`` is its infinity-norm, and ``h`` is the function .. math:: h(x) = \sum_k \phi(x[k]), \qquad \phi(u) = \left\{\begin{array}{ll} 0 & |u| \leq 1 \\ |u|-1 & 1 \leq |u| \leq 2 \\ 2|u|-3 & |u| \geq 2. \end{array}\right. >>> from cvxopt.modeling import variable, max >>> x = variable(10, 'x') >>> f = sum(abs(x)) >>> g = max(abs(x)) >>> h = sum(max(0, abs(x)-1, 2*abs(x)-3)) **In-place operations** If ``f`` is piecewise-linear then the in-place operations ``f += u``, ``f -= u``, ``f *= u``, ``f /= u`` are defined if the corresponding expanded operations ``f = f + u``, ``f = f - u``, ``f = f * u``, and ``f = f/u`` are defined and if they do not change the length of ``f``. .. _s-constraints: Constraints =========== Linear equality and inequality constraints of the form .. math:: f(x_1,\ldots,x_n) = 0, \qquad f(x_1,\ldots,x_n) \preceq 0, where :math:`f` is a convex function, are represented by :class:`constraint` objects. Equality constraints are created by expressions of the form :: f1 == f2 Here ``f1`` and ``f2`` can be any objects for which the difference ``f1 - f2`` yields an affine function. Inequality constraints are created by expressions of the form :: f1 <= f2 f2 >= f1 where ``f1`` and ``f2`` can be any objects for which the difference ``f1 - f2`` yields a convex piecewise-linear function. The comparison operators first convert the expressions to ``f1 - f2 == 0``, resp., ``f1 - f2 <= 0``, and then return a new :class:`constraint` object with constraint function ``f1 - f2``. In the following example we create three constraints .. math:: \newcommand{\ones}{{\bf 1}} 0 \preceq x \preceq \ones, \qquad \ones^T x = 2, for a variable of length 5. >>> x = variable(5,'x') >>> c1 = (x <= 1) >>> c2 = (x >= 0) >>> c3 = (sum(x) == 2) The built-in function :func:`!len` returns the dimension of the constraint function. Constraints have four public attributes. .. attribute:: type Returns :const:`'='` if the constraint is an equality constraint, and **'<'** if the constraint is an inequality constraint. .. attribute:: value Returns the value of the constraint function. .. attribute:: multiplier For a constraint ``c``, ``c.multiplier`` is a :class:`variable` object of dimension ``len(c)``. It is used to represent the Lagrange multiplier or dual variable associated with the constraint. Its value is initialized as :const:`None`, and can be modified by making an assignment to ``c.multiplier.value``. .. attribute:: name The name of the constraint. Changing the name of a constraint also changes the name of the multiplier of ``c``. For example, the command ``c.name = 'newname'`` also changes ``c.multiplier.name`` to ``'newname_mul'``. .. _s-lp: Optimization Problems ===================== Optimization problems are be constructed by calling the following function. .. function:: cvxopt.modeling.op([objective[, constraints[, name]]]) The first argument specifies the objective function to be minimized. It can be an affine or convex piecewise-linear function with length 1, a :class:`variable` with length 1, or a scalar constant (integer, float, or 1 by 1 dense :const:`'d'` matrix). The default value is 0.0. The second argument is a single :class:`constraint`, or a list of :class:`constraint` objects. The default value is an empty list. The third argument is a string with a name for the problem. The default value is the empty string. The following attributes and methods are useful for examining and modifying optimization problems. .. attribute:: objective The objective or cost function. One can write to this attribute to change the objective of an existing problem. .. method:: variables Returns a list of the variables of the problem. .. method:: constraints Returns a list of the constraints. .. method:: inequalities Returns a list of the inequality constraints. .. method:: equalities Returns a list of the equality constraints. .. method:: delconstraint(c) Deletes constraint ``c`` from the problem. .. :: addconstraint(c) Adds constraint ``c`` to the problem. An optimization problem with convex piecewise-linear objective and constraints can be solved by calling the method :func:`solve`. .. method:: solve([format[, solver]]) This function converts the optimization problem to a linear program in matrix form and then solves it using the solver described in the section :ref:`s-lpsolver`. The first argument is either :const:`'dense'` or :const:`'sparse'`, and denotes the matrix types used in the matrix representation of the LP. The default value is :const:`'dense'`. The second argument is either :const:`None`, :const:`'glpk'`, or :const:`'mosek'`, and selects one of three available LP solvers: the default solver written in Python, the GLPK solver (if installed) or the MOSEK LP solver (if installed); see the section :ref:`s-lpsolver`. The default value is :const:`None`. The solver reports the outcome of optimization by setting the attribute :attr:`self.status` and by modifying the :attr:`value` attributes of the variables and the constraint multipliers of the problem. * If the problem is solved to optimality, :attr:`self.status` is set to :const:`'optimal'`. The :attr:`value` attributes of the variables in the problem are set to their computed solutions, and the :attr:`value` attributes of the multipliers of the constraints of the problem are set to the computed dual optimal solution. * If it is determined that the problem is infeasible, :attr:`self.status` is set to :const:`'primal infeasible'`. The :attr:`value` attributes of the variables are set to :const:`None`. The :attr:`value` attributes of the multipliers of the constraints of the problem are set to a certificate of primal infeasibility. With the :const:`'glpk'` option, :func:`solve` does not provide certificates of infeasibility. * If it is determined that the problem is dual infeasible, :attr:`self.status` is set to :const:`'dual infeasible'`. The :attr:`value` attributes of the multipliers of the constraints of the problem are set to :const:`None`. The :attr:`value` attributes of the variables are set to a certificate of dual infeasibility. With the :const:`'glpk'` option, :func:`solve` does not provide certificates of infeasibility. * If the problem was not solved successfully, :attr:`self.status` is set to :const:`'unknown'`. The :attr:`value` attributes of the variables and the constraint multipliers are set to :const:`None`. We refer to the section :ref:`s-lpsolver` for details on the algorithms and the different solver options. As an example we solve the LP .. math:: \begin{array}{ll} \mbox{minimize} & -4x - 5y \\ \mbox{subject to} & 2x +y \leq 3 \\ & x +2y \leq 3 \\ & x \geq 0, \quad y \geq 0. \end{array} >>> from cvxopt.modeling import op >>> x = variable() >>> y = variable() >>> c1 = ( 2*x+y <= 3 ) >>> c2 = ( x+2*y <= 3 ) >>> c3 = ( x >= 0 ) >>> c4 = ( y >= 0 ) >>> lp1 = op(-4*x-5*y, [c1,c2,c3,c4]) >>> lp1.solve() >>> lp1.status 'optimal' >>> print(lp1.objective.value()) [-9.00e+00] >>> print(x.value) [ 1.00e+00] >>> print(y.value) [ 1.00e+00] >>> print(c1.multiplier.value) [ 1.00e+00] >>> print(c2.multiplier.value) [ 2.00e+00] >>> print(c3.multiplier.value) [ 2.87e-08] >>> print(c4.multiplier.value) [ 2.80e-08] We can solve the same LP in matrix form as follows. >>> from cvxopt.modeling import op, dot >>> x = variable(2) >>> A = matrix([[2.,1.,-1.,0.], [1.,2.,0.,-1.]]) >>> b = matrix([3.,3.,0.,0.]) >>> c = matrix([-4.,-5.]) >>> ineq = ( A*x <= b ) >>> lp2 = op(dot(c,x), ineq) >>> lp2.solve() >>> print(lp2.objective.value()) [-9.00e+00] >>> print(x.value) [ 1.00e+00] [ 1.00e+00] >>> print(ineq.multiplier.value) [1.00e+00] [2.00e+00] [2.87e-08] [2.80e-08] The :class:`op` class also includes two methods for writing and reading files in `MPS format `_. .. method:: tofile(filename) If the problem is an LP, writes it to the file `filename` using the MPS format. Row and column labels are assigned based on the variable and constraint names in the LP. .. method:: fromfile(filename) Reads the LP from the file `filename`. The file must be a fixed-format MPS file. Some features of the MPS format are not supported: comments beginning with dollar signs, the row types 'DE', 'DL', 'DG', and 'DN', and the capability of reading multiple righthand side, bound or range vectors. Examples ======== **Norm and Penalty Approximation** In the first example we solve the norm approximation problems .. math:: \begin{array}{ll} \mbox{minimize} & \|Ax - b\|_\infty, \end{array} \qquad \begin{array}{ll} \mbox{minimize} & \|Ax - b\|_1 \end{array}, and the penalty approximation problem .. math:: \begin{array}{ll} \mbox{minimize} & \sum_k \phi((Ax-b)_k), \end{array} \qquad \phi(u) = \left\{\begin{array}{ll} 0 & |u| \leq 3/4 \\ |u|-3/4 & 3/4 \leq |u| \leq 3/2 \\ 2|u|-9/4 & |u| \geq 3/2. \end{array}\right. We use randomly generated data. The code uses the `Matplotlib `_ package for plotting the histograms of the residual vectors for the two solutions. It generates the figure shown below. :: from cvxopt import normal from cvxopt.modeling import variable, op, max, sum import pylab m, n = 500, 100 A = normal(m,n) b = normal(m) x1 = variable(n) op(max(abs(A*x1-b))).solve() x2 = variable(n) op(sum(abs(A*x2-b))).solve() x3 = variable(n) op(sum(max(0, abs(A*x3-b)-0.75, 2*abs(A*x3-b)-2.25))).solve() pylab.subplot(311) pylab.hist(A*x1.value-b, m/5) pylab.subplot(312) pylab.hist(A*x2.value-b, m/5) pylab.subplot(313) pylab.hist(A*x3.value-b, m/5) pylab.show() .. image:: normappr.png :width: 600px Equivalently, we can formulate and solve the problems as LPs. :: t = variable() x1 = variable(n) op(t, [-t <= A*x1-b, A*x1-b<=t]).solve() u = variable(m) x2 = variable(n) op(sum(u), [-u <= A*x2+b, A*x2+b <= u]).solve() v = variable(m) x3 = variable(n) op(sum(v), [v >= 0, v >= A*x3+b-0.75, v >= -(A*x3+b)-0.75, v >= 2*(A*x3-b)-2.25, v >= -2*(A*x3-b)-2.25]).solve() **Robust Linear Programming** The robust LP .. math:: \begin{array}{ll} \mbox{minimize} & c^T x \\ \mbox{subject to} & \sup_{\|v\|_\infty \leq 1} (a_i+v)^T x \leq b_i, \qquad i=1,\ldots,m \end{array} is equivalent to the problem .. math:: \begin{array}{ll} \mbox{minimize} & c^Tx \\ \mbox{subject to} & a_i^Tx + \|x\|_1 \leq b_i, \qquad i=1,\ldots,m. \end{array} The following code computes the solution and the solution of the equivalent LP .. math:: \newcommand{\ones}{{\bf 1}} \begin{array}{ll} \mbox{minimize} & c^Tx \\ \mbox{subject to} & a_i^Tx + \ones^Ty \leq b_i, \qquad i=1,\ldots,m \\ & -y \preceq x \preceq y \end{array} for randomly generated data. :: from cvxopt import normal, uniform from cvxopt.modeling import variable, dot, op, sum m, n = 500, 100 A = normal(m,n) b = uniform(m) c = normal(n) x = variable(n) op(dot(c,x), A*x+sum(abs(x)) <= b).solve() x2 = variable(n) y = variable(n) op(dot(c,x2), [A*x2+sum(y) <= b, -y <= x2, x2 <= y]).solve() **1-Norm Support Vector Classifier** The following problem arises in classification: .. math:: \newcommand{\ones}{{\bf 1}} \begin{array}{ll} \mbox{minimize} & \|x\|_1 + \ones^Tu \\ \mbox{subject to} & Ax \succeq \ones -u \\ & u \succeq 0. \end{array} It can be solved as follows. :: x = variable(A.size[1],'x') u = variable(A.size[0],'u') op(sum(abs(x)) + sum(u), [A*x >= 1-u, u >= 0]).solve() An equivalent unconstrained formulation is :: x = variable(A.size[1],'x') op(sum(abs(x)) + sum(max(0,1-A*x))).solve() cvxopt-1.1.4/doc/source/lapack.rst0000644000175000017500000016320011674452555016140 0ustar sonnesonne.. role:: raw-html(raw) :format: html .. _c-lapack: ******************** The LAPACK Interface ******************** The module :mod:`cvxopt.lapack` includes functions for solving dense sets of linear equations, for the corresponding matrix factorizations (LU, Cholesky, :raw-html:`LDLT`), for solving least-squares and least-norm problems, for QR factorization, for symmetric eigenvalue problems, singular value decomposition, and Schur factorization. In this chapter we briefly describe the Python calling sequences. For further details on the underlying LAPACK functions we refer to the LAPACK Users' Guide and manual pages. The BLAS conventional storage scheme of the section :ref:`s-conventions` is used. As in the previous chapter, we omit from the function definitions less important arguments that are useful for selecting submatrices. The complete definitions are documented in the docstrings in the source code. .. seealso:: `LAPACK Users' Guide, Third Edition, SIAM, 1999 `_ General Linear Equations ======================== .. function:: cvxopt.lapack.gesv(A, B[, ipiv = None]) Solves .. math:: A X = B, where :math:`A` and :math:`B` are real or complex matrices, with :math:`A` square and nonsingular. The arguments ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). On entry, ``B`` contains the right-hand side :math:`B`; on exit it contains the solution :math:`X`. The optional argument ``ipiv`` is an integer matrix of length at least :math:`n`. If ``ipiv`` is provided, then :func:`gesv` solves the system, replaces ``A`` with the triangular factors in an LU factorization, and returns the permutation matrix in ``ipiv``. If ``ipiv`` is not specified, then :func:`gesv` solves the system but does not return the LU factorization and does not modify ``A``. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.getrf(A, ipiv) LU factorization of a general, possibly rectangular, real or complex matrix, .. math:: A = PLU, where :math:`A` is :math:`m` by :math:`n`. The argument ``ipiv`` is an integer matrix of length at least min{:math:`m`, :math:`n`}. On exit, the lower triangular part of ``A`` is replaced by :math:`L`, the upper triangular part by :math:`U`, and the permutation matrix is returned in ``ipiv``. Raises an :exc:`ArithmeticError` if the matrix is not full rank. .. function:: cvxopt.lapack.getrs(A, ipiv, B[, trans = 'N']) Solves a general set of linear equations .. math:: AX & = B \quad (\mathrm{trans} = \mathrm{'N'}), \\ A^TX & = B \quad (\mathrm{trans} = \mathrm{'T'}), \\ A^HX & = B \quad (\mathrm{trans} = \mathrm{'C'}), given the LU factorization computed by :func:`gesv ` or :func:`getrf `. On entry, ``A`` and ``ipiv`` must contain the factorization as computed by :func:`gesv` or :func:`getrf`. On entry, ``B`` contains the right-hand side :math:`B`; on exit it contains the solution :math:`X`. ``B`` must have the same type as ``A``. .. function:: cvxopt.lapack.getri(A, ipiv) Computes the inverse of a matrix. On entry, ``A`` and ``ipiv`` must contain the factorization as computed by :func:`gesv ` or :func:`getrf `. On exit, ``A`` contains the matrix inverse. In the following example we compute .. math:: x = (A^{-1} + A^{-T})b for randomly generated problem data, factoring the coefficient matrix once. >>> from cvxopt import matrix, normal >>> from cvxopt.lapack import gesv, getrs >>> n = 10 >>> A = normal(n,n) >>> b = normal(n) >>> ipiv = matrix(0, (n,1)) >>> x = +b >>> gesv(A, x, ipiv) # x = A^{-1}*b >>> x2 = +b >>> getrs(A, ipiv, x2, trans='T') # x2 = A^{-T}*b >>> x += x2 Separate functions are provided for equations with band matrices. .. function:: cvxopt.lapack.gbsv(A, kl, B[, ipiv = None]) Solves .. math:: A X = B, where :math:`A` and :math:`B` are real or complex matrices, with :math:`A` :math:`n` by :math:`n` and banded with :math:`k_l` subdiagonals. The arguments ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). On entry, ``B`` contains the right-hand side :math:`B`; on exit it contains the solution :math:`X`. The optional argument ``ipiv`` is an integer matrix of length at least :math:`n`. If ``ipiv`` is provided, then ``A`` must have :math:`2k_l + k_u + 1` rows. On entry the diagonals of :math:`A` are stored in rows :math:`k_l + 1` to :math:`2k_l + k_u + 1` of ``A``, using the BLAS format for general band matrices (see the section :ref:`s-conventions`). On exit, the factorization is returned in ``A`` and ``ipiv``. If ``ipiv`` is not provided, then ``A`` must have :math:`k_l + k_u + 1` rows. On entry the diagonals of :math:`A` are stored in the rows of ``A``, following the standard BLAS format for general band matrices. In this case, :func:`gbsv` does not modify ``A`` and does not return the factorization. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.gbtrf(A, m, kl, ipiv) LU factorization of a general :math:`m` by :math:`n` real or complex band matrix with :math:`k_l` subdiagonals. The matrix is stored using the BLAS format for general band matrices (see the section :ref:`s-conventions`), by providing the diagonals (stored as rows of a :math:`k_u + k_l + 1` by :math:`n` matrix ``A``), the number of rows :math:`m`, and the number of subdiagonals :math:`k_l`. The argument ``ipiv`` is an integer matrix of length at least min{:math:`m`, :math:`n`}. On exit, ``A`` and ``ipiv`` contain the details of the factorization. Raises an :exc:`ArithmeticError` if the matrix is not full rank. .. function:: cvxopt.lapack.gbtrs({A, kl, ipiv, B[, trans = 'N']) Solves a set of linear equations .. math:: AX & = B \quad (\mathrm{trans} = \mathrm{'N'}), \\ A^TX & = B \quad (\mathrm{trans} = \mathrm{'T'}), \\ A^HX & = B \quad (\mathrm{trans} = \mathrm{'C'}), with :math:`A` a general band matrix with :math:`k_l` subdiagonals, given the LU factorization computed by :func:`gbsv ` or :func:`gbtrf `. On entry, ``A`` and ``ipiv`` must contain the factorization as computed by :func:`gbsv` or :func:`gbtrf`. On entry, ``B`` contains the right-hand side :math:`B`; on exit it contains the solution :math:`X`. ``B`` must have the same type as ``A``. As an example, we solve a linear equation with .. math:: A = \left[ \begin{array}{cccc} 1 & 2 & 0 & 0 \\ 3 & 4 & 5 & 0 \\ 6 & 7 & 8 & 9 \\ 0 & 10 & 11 & 12 \end{array}\right], \qquad B = \left[\begin{array}{c} 1 \\ 1 \\ 1 \\ 1 \end{array}\right]. >>> from cvxopt import matrix >>> from cvxopt.lapack import gbsv, gbtrf, gbtrs >>> n, kl, ku = 4, 2, 1 >>> A = matrix([[0., 1., 3., 6.], [2., 4., 7., 10.], [5., 8., 11., 0.], [9., 12., 0., 0.]]) >>> x = matrix(1.0, (n,1)) >>> gbsv(A, kl, x) >>> print(x) [ 7.14e-02] [ 4.64e-01] [-2.14e-01] [-1.07e-01] The code below illustrates how one can reuse the factorization returned by :func:`gbsv `. >>> Ac = matrix(0.0, (2*kl+ku+1,n)) >>> Ac[kl:,:] = A >>> ipiv = matrix(0, (n,1)) >>> x = matrix(1.0, (n,1)) >>> gbsv(Ac, kl, x, ipiv) # solves A*x = 1 >>> print(x) [ 7.14e-02] [ 4.64e-01] [-2.14e-01] [-1.07e-01] >>> x = matrix(1.0, (n,1)) >>> gbtrs(Ac, kl, ipiv, x, trans='T') # solve A^T*x = 1 >>> print(x) [ 7.14e-02] [ 2.38e-02] [ 1.43e-01] [-2.38e-02] An alternative method uses :func:`gbtrf ` for the factorization. >>> Ac[kl:,:] = A >>> gbtrf(Ac, n, kl, ipiv) >>> x = matrix(1.0, (n,1)) >>> gbtrs(Ac, kl, ipiv, x) # solve A^T*x = 1 >>> print(x) [ 7.14e-02] [ 4.64e-01] [-2.14e-01] [-1.07e-01] >>> x = matrix(1.0, (n,1)) >>> gbtrs(Ac, kl, ipiv, x, trans='T') # solve A^T*x = 1 >>> print(x) [ 7.14e-02] [ 2.38e-02] [ 1.43e-01] [-2.38e-02] The following functions can be used for tridiagonal matrices. They use a simpler matrix format, with the diagonals stored in three separate vectors. .. function:: cvxopt.lapack.gtsv(dl, d, du, B)) Solves .. math:: A X = B, where :math:`A` is an :math:`n` by :math:`n` tridiagonal matrix. The subdiagonal of :math:`A` is stored as a matrix ``dl`` of length :math:`n-1`, the diagonal is stored as a matrix ``d`` of length :math:`n`, and the superdiagonal is stored as a matrix ``du`` of length :math:`n-1`. The four arguments must have the same type (:const:`'d'` or :const:`'z'`). On exit ``dl``, ``d``, ``du`` are overwritten with the details of the LU factorization of :math:`A`. On entry, ``B`` contains the right-hand side :math:`B`; on exit it contains the solution :math:`X`. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.gttrf(dl, d, du, du2, ipiv) LU factorization of an :math:`n` by :math:`n` tridiagonal matrix. The subdiagonal of :math:`A` is stored as a matrix ``dl`` of length :math:`n-1`, the diagonal is stored as a matrix ``d`` of length :math:`n`, and the superdiagonal is stored as a matrix ``du`` of length :math:`n-1`. ``dl``, ``d`` and ``du`` must have the same type. ``du2`` is a matrix of length :math:`n-2`, and of the same type as ``dl``. ``ipiv`` is an :const:`'i'` matrix of length :math:`n`. On exit, the five arguments contain the details of the factorization. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.gttrs(dl, d, du, du2, ipiv, B[, trans = 'N']) Solves a set of linear equations .. math:: AX & = B \quad (\mathrm{trans} = \mathrm{'N'}), \\ A^TX & = B \quad (\mathrm{trans} = \mathrm{'T'}), \\ A^HX & = B \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is an :math:`n` by :math:`n` tridiagonal matrix. The arguments ``dl``, ``d``, ``du``, ``du2``, and ``ipiv`` contain the details of the LU factorization as returned by :func:`gttrf `. On entry, ``B`` contains the right-hand side :math:`B`; on exit it contains the solution :math:`X`. ``B`` must have the same type as the other arguments. Positive Definite Linear Equations ================================== .. function:: cvxopt.lapack.posv(A, B[, uplo = 'L']) Solves .. math:: A X = B, where :math:`A` is a real symmetric or complex Hermitian positive definite matrix. On exit, ``B`` is replaced by the solution, and ``A`` is overwritten with the Cholesky factor. The matrices ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). Raises an :exc:`ArithmeticError` if the matrix is not positive definite. .. function:: cvxopt.lapack.potrf(A[, uplo = 'L']) Cholesky factorization .. math:: A = LL^T \qquad \mbox{or} \qquad A = LL^H of a positive definite real symmetric or complex Hermitian matrix :math:`A`. On exit, the lower triangular part of ``A`` (if ``uplo`` is :const:`'L'`) or the upper triangular part (if ``uplo`` is :const:`'U'`) is overwritten with the Cholesky factor or its (conjugate) transpose. Raises an :exc:`ArithmeticError` if the matrix is not positive definite. .. function:: cvxopt.lapack.potrs(A, B[, uplo = 'L']) Solves a set of linear equations .. math:: AX = B with a positive definite real symmetric or complex Hermitian matrix, given the Cholesky factorization computed by :func:`posv ` or :func:`potrf `. On entry, ``A`` contains the triangular factor, as computed by :func:`posv` or :func:`potrf`. On exit, ``B`` is replaced by the solution. ``B`` must have the same type as ``A``. .. function:: cvxopt.lapack.potri(A[, uplo = 'L']) Computes the inverse of a positive definite matrix. On entry, ``A`` contains the Cholesky factorization computed by :func:`potrf ` or :func:`posv `. On exit, it contains the matrix inverse. As an example, we use :func:`posv ` to solve the linear system .. math:: :label: e-kkt-example \newcommand{\diag}{\mathop{\bf diag}} \left[ \begin{array}{cc} -\diag(d)^2 & A \\ A^T & 0 \end{array} \right] \left[ \begin{array}{c} x_1 \\ x_2 \end{array} \right] = \left[ \begin{array}{c} b_1 \\ b_2 \end{array} \right] by block-elimination. We first pick a random problem. >>> from cvxopt import matrix, div, normal, uniform >>> from cvxopt.blas import syrk, gemv >>> from cvxopt.lapack import posv >>> m, n = 100, 50 >>> A = normal(m,n) >>> b1, b2 = normal(m), normal(n) >>> d = uniform(m) We then solve the equations .. math:: \newcommand{\diag}{\mathop{\bf diag}} \begin{split} A^T \diag(d)^{-2}A x_2 & = b_2 + A^T \diag(d)^{-2} b_1 \\ \diag(d)^2 x_1 & = Ax_2 - b_1. \end{split} >>> Asc = div(A, d[:, n*[0]]) # Asc := diag(d)^{-1}*A >>> B = matrix(0.0, (n,n)) >>> syrk(Asc, B, trans='T') # B := Asc^T * Asc = A^T * diag(d)^{-2} * A >>> x1 = div(b1, d) # x1 := diag(d)^{-1}*b1 >>> x2 = +b2 >>> gemv(Asc, x1, x2, trans='T', beta=1.0) # x2 := x2 + Asc^T*x1 = b2 + A^T*diag(d)^{-2}*b1 >>> posv(B, x2) # x2 := B^{-1}*x2 = B^{-1}*(b2 + A^T*diag(d)^{-2}*b1) >>> gemv(Asc, x2, x1, beta=-1.0) # x1 := Asc*x2 - x1 = diag(d)^{-1} * (A*x2 - b1) >>> x1 = div(x1, d) # x1 := diag(d)^{-1}*x1 = diag(d)^{-2} * (A*x2 - b1) There are separate routines for equations with positive definite band matrices. .. function:: cvxopt.lapack.pbsv(A, B[, uplo='L']) Solves .. math:: AX = B where :math:`A` is a real symmetric or complex Hermitian positive definite band matrix. On entry, the diagonals of :math:`A` are stored in ``A``, using the BLAS format for symmetric or Hermitian band matrices (see section :ref:`s-conventions`). On exit, ``B`` is replaced by the solution, and ``A`` is overwritten with the Cholesky factor (in the BLAS format for triangular band matrices). The matrices ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). Raises an :exc:`ArithmeticError` if the matrix is not positive definite. .. function:: cvxopt.lapack.pbtrf(A[, uplo = 'L']) Cholesky factorization .. math:: A = LL^T \qquad \mbox{or} \qquad A = LL^H of a positive definite real symmetric or complex Hermitian band matrix :math:`A`. On entry, the diagonals of :math:`A` are stored in ``A``, using the BLAS format for symmetric or Hermitian band matrices. On exit, ``A`` contains the Cholesky factor, in the BLAS format for triangular band matrices. Raises an :exc:`ArithmeticError` if the matrix is not positive definite. .. function:: cvxopt.lapack.pbtrs(A, B[, uplo = 'L']) Solves a set of linear equations .. math:: AX=B with a positive definite real symmetric or complex Hermitian band matrix, given the Cholesky factorization computed by :func:`pbsv ` or :func:`pbtrf `. On entry, ``A`` contains the triangular factor, as computed by :func:`pbsv` or :func:`pbtrf`. On exit, ``B`` is replaced by the solution. ``B`` must have the same type as ``A``. The following functions are useful for tridiagonal systems. .. function:: cvxopt.lapack.ptsv(d, e, B) Solves .. math:: A X = B, where :math:`A` is an :math:`n` by :math:`n` positive definite real symmetric or complex Hermitian tridiagonal matrix. The diagonal of :math:`A` is stored as a :const:`'d'` matrix ``d`` of length :math:`n` and its subdiagonal as a :const:`'d'` or :const:`'z'` matrix ``e`` of length :math:`n-1`. The arguments ``e`` and ``B`` must have the same type. On exit ``d`` contains the diagonal elements of :math:`D` in the :raw-html:`LDLT` or :raw-html:`LDLH` factorization of :math:`A`, and ``e`` contains the subdiagonal elements of the unit lower bidiagonal matrix :math:`L`. ``B`` is overwritten with the solution :math:`X`. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.pttrf(d, e) :raw-html:`LDLT` or :raw-html:`LDLH` factorization of an :math:`n` by :math:`n` positive definite real symmetric or complex Hermitian tridiagonal matrix :math:`A`. On entry, the argument ``d`` is a :const:`'d'` matrix with the diagonal elements of :math:`A`. The argument ``e`` is :const:`'d'` or :const:`'z'` matrix containing the subdiagonal of :math:`A`. On exit ``d`` contains the diagonal elements of :math:`D`, and ``e`` contains the subdiagonal elements of the unit lower bidiagonal matrix :math:`L`. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.pttrs(d, e, B[, uplo = 'L']) Solves a set of linear equations .. math:: AX = B where :math:`A` is an :math:`n` by :math:`n` positive definite real symmetric or complex Hermitian tridiagonal matrix, given its :raw-html:`LDLT` or :raw-html:`LDLH` factorization. The argument ``d`` is the diagonal of the diagonal matrix :math:`D`. The argument ``uplo`` only matters for complex matrices. If ``uplo`` is :const:`'L'`, then on exit ``e`` contains the subdiagonal elements of the unit bidiagonal matrix :math:`L`. If ``uplo`` is :const:`'U'`, then ``e`` contains the complex conjugates of the elements of the unit bidiagonal matrix :math:`L`. On exit, ``B`` is overwritten with the solution :math:`X`. ``B`` must have the same type as ``e``. Symmetric and Hermitian Linear Equations ======================================== .. function:: cvxopt.lapack.sysv(A, B[, ipiv = None, uplo = 'L']) Solves .. math:: AX = B where :math:`A` is a real or complex symmetric matrix of order :math:`n`. On exit, ``B`` is replaced by the solution. The matrices ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). The optional argument ``ipiv`` is an integer matrix of length at least equal to :math:`n`. If ``ipiv`` is provided, :func:`sysv` solves the system and returns the factorization in ``A`` and ``ipiv``. If ``ipiv`` is not specified, :func:`sysv` solves the system but does not return the factorization and does not modify ``A``. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.sytrf(A, ipiv[, uplo = 'L']) :raw-html:`LDLT` factorization .. math:: PAP^T = LDL^T of a real or complex symmetric matrix :math:`A` of order :math:`n`. ``ipiv`` is an :const:`'i'` matrix of length at least :math:`n`. On exit, ``A`` and ``ipiv`` contain the factorization. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.sytrs(A, ipiv, B[, uplo = 'L']) Solves .. math:: A X = B given the :raw-html:`LDLT` factorization computed by :func:`sytrf ` or :func:`sysv `. ``B`` must have the same type as ``A``. .. function:: cvxopt.lapack.sytri(A, ipiv[, uplo = 'L']) Computes the inverse of a real or complex symmetric matrix. On entry, ``A`` and ``ipiv`` contain the :raw-html:`LDLT` factorization computed by :func:`sytrf ` or :func:`sysv `. On exit, ``A`` contains the inverse. .. function:: cvxopt.lapack.hesv(A, B[, ipiv = None, uplo = 'L']) Solves .. math:: A X = B where :math:`A` is a real symmetric or complex Hermitian of order :math:`n`. On exit, ``B`` is replaced by the solution. The matrices ``A`` and ``B`` must have the same type (:const:`'d'` or :const:`'z'`). The optional argument ``ipiv`` is an integer matrix of length at least :math:`n`. If ``ipiv`` is provided, then :func:`hesv` solves the system and returns the factorization in ``A`` and ``ipiv``. If ``ipiv`` is not specified, then :func:`hesv` solves the system but does not return the factorization and does not modify ``A``. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.hetrf(A, ipiv[, uplo = 'L']) :raw-html:`LDLH` factorization .. math:: PAP^T = LDL^H of a real symmetric or complex Hermitian matrix of order :math:`n`. ``ipiv`` is an :const:`'i'` matrix of length at least :math:`n`. On exit, ``A`` and ``ipiv`` contain the factorization. Raises an :exc:`ArithmeticError` if the matrix is singular. .. function:: cvxopt.lapack.hetrs(A, ipiv, B[, uplo = 'L']) Solves .. math:: A X = B given the :raw-html:`LDLH` factorization computed by :func:`hetrf ` or :func:`hesv `. .. function:: cvxopt.lapack.hetri(A, ipiv[, uplo = 'L']) Computes the inverse of a real symmetric or complex Hermitian matrix. On entry, ``A`` and ``ipiv`` contain the :raw-html:`LDLH` factorization computed by :func:`hetrf ` or :func:`hesv `. On exit, ``A`` contains the inverse. As an example we solve the KKT system :eq:`e-kkt-example`. >>> from cvxopt.lapack import sysv >>> K = matrix(0.0, (m+n,m+n)) >>> K[: (m+n)*m : m+n+1] = -d**2 >>> K[:m, m:] = A >>> x = matrix(0.0, (m+n,1)) >>> x[:m], x[m:] = b1, b2 >>> sysv(K, x, uplo='U') Triangular Linear Equations =========================== .. function:: cvxopt.lapack.trtrs(A, B[, uplo = 'L', trans = 'N', diag = 'N']) Solves a triangular set of equations .. math:: AX & = B \quad (\mathrm{trans} = \mathrm{'N'}), \\ A^TX & = B \quad (\mathrm{trans} = \mathrm{'T'}), \\ A^HX & = B \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is real or complex and triangular of order :math:`n`, and :math:`B` is a matrix with :math:`n` rows. ``A`` and ``B`` are matrices with the same type (:const:`'d'` or :const:`'z'`). :func:`trtrs` is similar to :func:`blas.trsm `, except that it raises an :exc:`ArithmeticError` if a diagonal element of ``A`` is zero (whereas :func:`blas.trsm` returns :const:`inf` values). .. function:: cvxopt.lapack.trtri(A[, uplo = 'L', diag = 'N']) Computes the inverse of a real or complex triangular matrix :math:`A`. On exit, ``A`` contains the inverse. .. function:: cvxopt.lapack.tbtrs(A, B[, uplo = 'L', trans = 'T', diag = 'N']) Solves a triangular set of equations .. math:: AX & = B \quad (\mathrm{trans} = \mathrm{'N'}), \\ A^TX & = B \quad (\mathrm{trans} = \mathrm{'T'}), \\ A^HX & = B \quad (\mathrm{trans} = \mathrm{'C'}), where :math:`A` is real or complex triangular band matrix of order :math:`n`, and :math:`B` is a matrix with :math:`n` rows. The diagonals of :math:`A` are stored in ``A`` using the BLAS conventions for triangular band matrices. ``A`` and ``B`` are matrices with the same type (:const:`'d'` or :const:`'z'`). On exit, ``B`` is replaced by the solution :math:`X`. Least-Squares and Least-Norm Problems ===================================== .. function:: cvxopt.lapack.gels(A, B[, trans = 'N']) Solves least-squares and least-norm problems with a full rank :math:`m` by :math:`n` matrix :math:`A`. 1. ``trans`` is :const:`'N'`. If :math:`m` is greater than or equal to :math:`n`, :func:`gels` solves the least-squares problem .. math:: \begin{array}{ll} \mbox{minimize} & \|AX-B\|_F. \end{array} If :math:`m` is less than or equal to :math:`n`, :func:`gels` solves the least-norm problem .. math:: \begin{array}{ll} \mbox{minimize} & \|X\|_F \\ \mbox{subject to} & AX = B. \end{array} 2. ``trans`` is :const:`'T'` or :const:`'C'` and ``A`` and ``B`` are real. If :math:`m` is greater than or equal to :math:`n`, :func:`gels` solves the least-norm problem .. math:: \begin{array}{ll} \mbox{minimize} & \|X\|_F \\ \mbox{subject to} & A^TX=B. \end{array} If :math:`m` is less than or equal to :math:`n`, :func:`gels` solves the least-squares problem .. math:: \begin{array}{ll} \mbox{minimize} & \|A^TX-B\|_F. \end{array} 3. ``trans`` is :const:`'C'` and ``A`` and ``B`` are complex. If :math:`m` is greater than or equal to :math:`n`, :func:`gels` solves the least-norm problem .. math:: \begin{array}{ll} \mbox{minimize} & \|X\|_F \\ \mbox{subject to} & A^HX=B. \end{array} If :math:`m` is less than or equal to :math:`n`, :func:`gels` solves the least-squares problem .. math:: \begin{array}{ll} \mbox{minimize} & \|A^HX-B\|_F. \end{array} ``A`` and ``B`` must have the same typecode (:const:`'d'` or :const:`'z'`). ``trans`` = :const:`'T'` is not allowed if ``A`` is complex. On exit, the solution :math:`X` is stored as the leading submatrix of ``B``. The matrix ``A`` is overwritten with details of the QR or the LQ factorization of :math:`A`. Note that :func:`gels` does not check whether :math:`A` is full rank. The following functions compute QR and LQ factorizations. .. function:: cvxopt.lapack.geqrf(A, tau) QR factorization of a real or complex matrix ``A``: .. math:: A = Q R. If :math:`A` is :math:`m` by :math:`n`, then :math:`Q` is :math:`m` by :math:`m` and orthogonal/unitary, and :math:`R` is :math:`m` by :math:`n` and upper triangular (if :math:`m` is greater than or equal to :math:`n`), or upper trapezoidal (if :math:`m` is less than or equal to :math:`n`). ``tau`` is a matrix of the same type as ``A`` and of length min{:math:`m`, :math:`n`}. On exit, :math:`R` is stored in the upper triangular/trapezoidal part of ``A``. The matrix :math:`Q` is stored as a product of min{:math:`m`, :math:`n`} elementary reflectors in the first min{:math:`m`, :math:`n`} columns of ``A`` and in ``tau``. .. function:: cvxopt.lapack.gelqf(A, tau) LQ factorization of a real or complex matrix ``A``: .. math:: A = L Q. If :math:`A` is :math:`m` by :math:`n`, then :math:`Q` is :math:`n` by :math:`n` and orthogonal/unitary, and :math:`L` is :math:`m` by :math:`n` and lower triangular (if :math:`m` is less than or equal to :math:`n`), or lower trapezoidal (if :math:`m` is greater than or equal to :math:`n`). ``tau`` is a matrix of the same type as ``A`` and of length min{:math:`m`, :math:`n`}. On exit, :math:`L` is stored in the lower triangular/trapezoidal part of ``A``. The matrix :math:`Q` is stored as a product of min{:math:`m`, :math:`n`} elementary reflectors in the first min{:math:`m`, :math:`n`} rows of ``A`` and in ``tau``. .. function:: cvxopt.lapack.geqp3(A, jpvt, tau) QR factorization with column pivoting of a real or complex matrix :math:`A`: .. math:: A P = Q R. If :math:`A` is :math:`m` by :math:`n`, then :math:`Q` is :math:`m` by :math:`m` and orthogonal/unitary, and :math:`R` is :math:`m` by :math:`n` and upper triangular (if :math:`m` is greater than or equal to :math:`n`), or upper trapezoidal (if :math:`m` is less than or equal to :math:`n`). ``tau`` is a matrix of the same type as ``A`` and of length min{:math:`m`, :math:`n`}. ``jpvt`` is an integer matrix of length :math:`n`. On entry, if ``jpvt[k]`` is nonzero, then column :math:`k` of :math:`A` is permuted to the front of :math:`AP`. Otherwise, column :math:`k` is a free column. On exit, ``jpvt`` contains the permutation :math:`P`: the operation :math:`AP` is equivalent to ``A[:, jpvt-1]``. :math:`R` is stored in the upper triangular/trapezoidal part of ``A``. The matrix :math:`Q` is stored as a product of min{:math:`m`, :math:`n`} elementary reflectors in the first min{:math:`m`,:math:`n`} columns of ``A`` and in ``tau``. In most applications, the matrix :math:`Q` is not needed explicitly, and it is sufficient to be able to make products with :math:`Q` or its transpose. The functions :func:`unmqr ` and :func:`ormqr ` multiply a matrix with the orthogonal matrix computed by :func:`geqrf `. .. function:: cvxopt.lapack.unmqr(A, tau, C[, side = 'L', trans = 'N']) Product with a real orthogonal or complex unitary matrix: .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \begin{split} C & := \op(Q)C \quad (\mathrm{side} = \mathrm{'L'}), \\ C & := C\op(Q) \quad (\mathrm{side} = \mathrm{'R'}), \\ \end{split} where .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \op(Q) = \left\{ \begin{array}{ll} Q & \mathrm{trans} = \mathrm{'N'} \\ Q^T & \mathrm{trans} = \mathrm{'T'} \\ Q^H & \mathrm{trans} = \mathrm{'C'}. \end{array}\right. If ``A`` is :math:`m` by :math:`n`, then :math:`Q` is square of order :math:`m` and orthogonal or unitary. :math:`Q` is stored in the first min{:math:`m`, :math:`n`} columns of ``A`` and in ``tau`` as a product of min{:math:`m`, :math:`n`} elementary reflectors, as computed by :func:`geqrf `. The matrices ``A``, ``tau``, and ``C`` must have the same type. ``trans`` = :const:`'T'` is only allowed if the typecode is :const:`'d'`. .. function:: cvxopt.lapack.ormqr(A, tau, C[, side = 'L', trans = 'N']) Identical to :func:`unmqr ` but works only for real matrices, and the possible values of ``trans`` are :const:`'N'` and :const:`'T'`. As an example, we solve a least-squares problem by a direct call to :func:`gels `, and by separate calls to :func:`geqrf `, :func:`ormqr `, and :func:`trtrs `. >>> from cvxopt import blas, lapack, matrix, normal >>> m, n = 10, 5 >>> A, b = normal(m,n), normal(m,1) >>> x1 = +b >>> lapack.gels(+A, x1) # x1[:n] minimizes || A*x - b ||_2 >>> tau = matrix(0.0, (n,1)) >>> lapack.geqrf(A, tau) # A = [Q1, Q2] * [R1; 0] >>> x2 = +b >>> lapack.ormqr(A, tau, x2, trans='T') # x2 := [Q1, Q2]' * x2 >>> lapack.trtrs(A[:n,:], x2, uplo='U') # x2[:n] := R1^{-1} * x2[:n] >>> blas.nrm2(x1[:n] - x2[:n]) 3.0050798580569307e-16 The next two functions make products with the orthogonal matrix computed by :func:`gelqf `. .. function:: cvxopt.lapack.unmlq(A, tau, C[, side = 'L', trans = 'N']) Product with a real orthogonal or complex unitary matrix: .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \begin{split} C & := \op(Q)C \quad (\mathrm{side} = \mathrm{'L'}), \\ C & := C\op(Q) \quad (\mathrm{side} = \mathrm{'R'}), \\ \end{split} where .. math:: \newcommand{\op}{\mathop{\mathrm{op}}} \op(Q) = \left\{ \begin{array}{ll} Q & \mathrm{trans} = \mathrm{'N'}, \\ Q^T & \mathrm{trans} = \mathrm{'T'}, \\ Q^H & \mathrm{trans} = \mathrm{'C'}. \end{array}\right. If ``A`` is :math:`m` by :math:`n`, then :math:`Q` is square of order :math:`n` and orthogonal or unitary. :math:`Q` is stored in the first min{:math:`m`, :math:`n`} rows of ``A`` and in ``tau`` as a product of min{:math:`m`, :math:`n`} elementary reflectors, as computed by :func:`gelqf `. The matrices ``A``, ``tau``, and ``C`` must have the same type. ``trans`` = :const:`'T'` is only allowed if the typecode is :const:`'d'`. .. function:: cvxopt.lapack.ormlq(A, tau, C[, side = 'L', trans = 'N']) Identical to :func:`unmlq ` but works only for real matrices, and the possible values of ``trans`` or :const:`'N'` and :const:`'T'`. As an example, we solve a least-norm problem by a direct call to :func:`gels `, and by separate calls to :func:`gelqf `, :func:`ormlq `, and :func:`trtrs `. >>> from cvxopt import blas, lapack, matrix, normal >>> m, n = 5, 10 >>> A, b = normal(m,n), normal(m,1) >>> x1 = matrix(0.0, (n,1)) >>> x1[:m] = b >>> lapack.gels(+A, x1) # x1 minimizes ||x||_2 subject to A*x = b >>> tau = matrix(0.0, (m,1)) >>> lapack.gelqf(A, tau) # A = [L1, 0] * [Q1; Q2] >>> x2 = matrix(0.0, (n,1)) >>> x2[:m] = b # x2 = [b; 0] >>> lapack.trtrs(A[:,:m], x2) # x2[:m] := L1^{-1} * x2[:m] >>> lapack.ormlq(A, tau, x2, trans='T') # x2 := [Q1, Q2]' * x2 >>> blas.nrm2(x1 - x2) 0.0 Finally, if the matrix :math:`Q` is needed explicitly, it can be generated from the output of :func:`geqrf ` and :func:`gelqf ` using one of the following functions. .. function:: cvxopt.lapack.ungqr(A, tau) If ``A`` has size :math:`m` by :math:`n`, and ``tau`` has length :math:`k`, then, on entry, the first ``k`` columns of the matrix ``A`` and the entries of ``tau`` contai an unitary or orthogonal matrix :math:`Q` of order :math:`m`, as computed by :func:`geqrf `. On exit, the first min{:math:`m`, :math:`n`} columns of :math:`Q` are contained in the leading columns of ``A``. .. function:: cvxopt.lapack.orgqr(A, tau) Identical to :func:`ungqr ` but works only for real matrices. .. function:: cvxopt.lapack.unglq(A, tau) If ``A`` has size :math:`m` by :math:`n`, and ``tau`` has length :math:`k`, then, on entry, the first ``k`` rows of the matrix ``A`` and the entries of ``tau`` contain a unitary or orthogonal matrix :math:`Q` of order :math:`n`, as computed by :func:`gelqf `. On exit, the first min{:math:`m`, :math:`n`} rows of :math:`Q` are contained in the leading rows of ``A``. .. function:: cvxopt.lapack.orglq(A, tau) Identical to :func:`unglq ` but works only for real matrices. We illustrate this with the QR factorization of the matrix .. math:: A = \left[\begin{array}{rrr} 6 & -5 & 4 \\ 6 & 3 & -4 \\ 19 & -2 & 7 \\ 6 & -10 & -5 \end{array} \right] = \left[\begin{array}{cc} Q_1 & Q_2 \end{array}\right] \left[\begin{array}{c} R \\ 0 \end{array}\right]. >>> from cvxopt import matrix, lapack >>> A = matrix([ [6., 6., 19., 6.], [-5., 3., -2., -10.], [4., -4., 7., -5] ]) >>> m, n = A.size >>> tau = matrix(0.0, (n,1)) >>> lapack.geqrf(A, tau) >>> print(A[:n, :]) # Upper triangular part is R. [-2.17e+01 5.08e+00 -4.76e+00] [ 2.17e-01 -1.06e+01 -2.66e+00] [ 6.87e-01 3.12e-01 -8.74e+00] >>> Q1 = +A >>> lapack.orgqr(Q1, tau) >>> print(Q1) [-2.77e-01 3.39e-01 -4.10e-01] [-2.77e-01 -4.16e-01 7.35e-01] [-8.77e-01 -2.32e-01 -2.53e-01] [-2.77e-01 8.11e-01 4.76e-01] >>> Q = matrix(0.0, (m,m)) >>> Q[:, :n] = A >>> lapack.orgqr(Q, tau) >>> print(Q) # Q = [ Q1, Q2] [-2.77e-01 3.39e-01 -4.10e-01 -8.00e-01] [-2.77e-01 -4.16e-01 7.35e-01 -4.58e-01] [-8.77e-01 -2.32e-01 -2.53e-01 3.35e-01] [-2.77e-01 8.11e-01 4.76e-01 1.96e-01] The orthogonal matrix in the factorization .. math:: A = \left[ \begin{array}{rrrr} 3 & -16 & -10 & -1 \\ -2 & -12 & -3 & 4 \\ 9 & 19 & 6 & -6 \end{array}\right] = Q \left[\begin{array}{cc} R_1 & R_2 \end{array}\right] can be generated as follows. >>> A = matrix([ [3., -2., 9.], [-16., -12., 19.], [-10., -3., 6.], [-1., 4., -6.] ]) >>> m, n = A.size >>> tau = matrix(0.0, (m,1)) >>> lapack.geqrf(A, tau) >>> R = +A >>> print(R) # Upper trapezoidal part is [R1, R2]. [-9.70e+00 -1.52e+01 -3.09e+00 6.70e+00] [-1.58e-01 2.30e+01 1.14e+01 -1.92e+00] [ 7.09e-01 -5.57e-01 2.26e+00 2.09e+00] >>> lapack.orgqr(A, tau) >>> print(A[:, :m]) # Q is in the first m columns of A. [-3.09e-01 -8.98e-01 -3.13e-01] [ 2.06e-01 -3.85e-01 9.00e-01] [-9.28e-01 2.14e-01 3.04e-01] Symmetric and Hermitian Eigenvalue Decomposition ================================================ The first four routines compute all or selected eigenvalues and eigenvectors of a real symmetric matrix :math:`A`: .. math:: \newcommand{\diag}{\mathop{\bf diag}} A = V\diag(\lambda)V^T,\qquad V^TV = I. .. function:: cvxopt.lapack.syev(A, W[, jobz = 'N', uplo = 'L']) Eigenvalue decomposition of a real symmetric matrix of order :math:`n`. ``W`` is a real matrix of length at least :math:`n`. On exit, ``W`` contains the eigenvalues in ascending order. If ``jobz`` is :const:`'V'`, the eigenvectors are also computed and returned in ``A``. If ``jobz`` is :const:`'N'`, the eigenvectors are not returned and the contents of ``A`` are destroyed. Raises an :exc:`ArithmeticError` if the eigenvalue decomposition fails. .. function:: cvxopt.lapack.syevd(A, W[, jobz = 'N', uplo = 'L']) This is an alternative to :func:`syev `, based on a different algorithm. It is faster on large problems, but also uses more memory. .. function:: cvxopt.lapack.syevx(A, W[, jobz = 'N', range = 'A', uplo = 'L', vl = 0.0, vu = 0.0, il = 1, iu = 1, Z = None]) Computes selected eigenvalues and eigenvectors of a real symmetric matrix of order :math:`n`. ``W`` is a real matrix of length at least :math:`n`. On exit, ``W`` contains the eigenvalues in ascending order. If ``range`` is :const:`'A'`, all the eigenvalues are computed. If ``range`` is :const:`'I'`, eigenvalues :math:`i_l` through :math:`i_u` are computed, where :math:`1 \leq i_l \leq i_u \leq n`. If ``range`` is :const:`'V'`, the eigenvalues in the interval :math:`(v_l, v_u]` are computed. If ``jobz`` is :const:`'V'`, the (normalized) eigenvectors are computed, and returned in ``Z``. If ``jobz`` is :const:`'N'`, the eigenvectors are not computed. In both cases, the contents of ``A`` are destroyed on exit. ``Z`` is optional (and not referenced) if ``jobz`` is :const:`'N'`. It is required if ``jobz`` is :const:`'V'` and must have at least :math:`n` columns if ``range`` is :const:`'A'` or :const:`'V'` and at least :math:`i_u - i_l + 1` columns if ``range`` is :const:`'I'`. :func:`syevx` returns the number of computed eigenvalues. .. function:: cvxopt.lapack.syevr(A, W[, jobz = 'N', range = 'A', uplo = 'L', vl = 0.0, vu = 0.0, il = 1, iu = n, Z = None]) This is an alternative to :func:`syevx `. :func:`syevr` is the most recent LAPACK routine for symmetric eigenvalue problems, and expected to supersede the three other routines in future releases. The next four routines can be used to compute eigenvalues and eigenvectors for complex Hermitian matrices: .. math:: \newcommand{\diag}{\mathop{\bf diag}} A = V\diag(\lambda)V^H,\qquad V^HV = I. For real symmetric matrices they are identical to the corresponding :func:`syev*` routines. .. function:: cvxopt.lapack.heev(A, W[, jobz = 'N', uplo = 'L']) Eigenvalue decomposition of a real symmetric or complex Hermitian matrix of order :math:`n`. The calling sequence is identical to :func:`syev `, except that ``A`` can be real or complex. .. function:: cvxopt.lapack.heevd(A, W[, jobz = 'N'[, uplo = 'L']]) This is an alternative to :func:`heev `. .. function:: cvxopt.lapack.heevx(A, W[, jobz = 'N', range = 'A', uplo = 'L', vl = 0.0, vu = 0.0, il = 1, iu = n, Z = None]) Computes selected eigenvalues and eigenvectors of a real symmetric or complex Hermitian matrix. The calling sequence is identical to :func:`syevx `, except that ``A`` can be real or complex. ``Z`` must have the same type as ``A``. .. function:: cvxopt.lapack.heevr(A, W[, jobz = 'N', range = 'A', uplo = 'L', vl = 0.0, vu = 0.0, il = 1, iu = n, Z = None]) This is an alternative to :func:`heevx `. Generalized Symmetric Definite Eigenproblems ============================================ Three types of generalized eigenvalue problems can be solved: .. math:: :label: e-gevd \newcommand{\diag}{\mathop{\bf diag}} \begin{split} AZ & = BZ\diag(\lambda)\quad \mbox{(type 1)}, \\ ABZ & = Z\diag(\lambda) \quad \mbox{(type 2)}, \\ BAZ & = Z\diag(\lambda) \quad \mbox{(type 3)}, \end{split} with :math:`A` and :math:`B` real symmetric or complex Hermitian, and :math:`B` is positive definite. The matrix of eigenvectors is normalized as follows: .. math:: Z^H BZ = I \quad \mbox{(types 1 and 2)}, \qquad Z^H B^{-1}Z = I \quad \mbox{(type 3)}. .. function:: cvxopt.lapack.sygv(A, B, W[, itype = 1, jobz = 'N', uplo = 'L']) Solves the generalized eigenproblem :eq:`e-gevd` for real symmetric matrices of order :math:`n`, stored in real matrices ``A`` and ``B``. ``itype`` is an integer with possible values 1, 2, 3, and specifies the type of eigenproblem. ``W`` is a real matrix of length at least :math:`n`. On exit, it contains the eigenvalues in ascending order. On exit, ``B`` contains the Cholesky factor of :math:`B`. If ``jobz`` is :const:`'V'`, the eigenvectors are computed and returned in ``A``. If ``jobz`` is :const:`'N'`, the eigenvectors are not returned and the contents of ``A`` are destroyed. .. function:: cvxopt.lapack.hegv(A, B, W[, itype = 1, jobz = 'N', uplo = 'L']) Generalized eigenvalue problem :eq:`e-gevd` of real symmetric or complex Hermitian matrix of order :math:`n`. The calling sequence is identical to :func:`sygv `, except that ``A`` and ``B`` can be real or complex. Singular Value Decomposition ============================ .. function:: cvxopt.lapack.gesvd(A, S[, jobu = 'N', jobvt = 'N', U = None, Vt = None]) Singular value decomposition .. math:: A = U \Sigma V^T, \qquad A = U \Sigma V^H of a real or complex :math:`m` by :math:`n` matrix :math:`A`. ``S`` is a real matrix of length at least min{:math:`m`, :math:`n`}. On exit, its first min{:math:`m`, :math:`n`} elements are the singular values in descending order. The argument ``jobu`` controls how many left singular vectors are computed. The possible values are :const:`'N'`, :const:`'A'`, :const:`'S'` and :const:`'O'`. If ``jobu`` is :const:`'N'`, no left singular vectors are computed. If ``jobu`` is :const:`'A'`, all left singular vectors are computed and returned as columns of ``U``. If ``jobu`` is :const:`'S'`, the first min{:math:`m`, :math:`n`} left singular vectors are computed and returned as columns of ``U``. If ``jobu`` is :const:`'O'`, the first min{:math:`m`, :math:`n`} left singular vectors are computed and returned as columns of ``A``. The argument ``U`` is \None\ (if ``jobu`` is :const:`'N'` or :const:`'A'`) or a matrix of the same type as ``A``. The argument ``jobvt`` controls how many right singular vectors are computed. The possible values are :const:`'N'`, :const:`'A'`, :const:`'S'` and :const:`'O'`. If ``jobvt`` is :const:`'N'`, no right singular vectors are computed. If ``jobvt`` is :const:`'A'`, all right singular vectors are computed and returned as rows of ``Vt``. If ``jobvt`` is :const:`'S'`, the first min{:math:`m`, :math:`n`} right singular vectors are computed and their (conjugate) transposes are returned as rows of ``Vt``. If ``jobvt`` is :const:`'O'`, the first min{:math:`m`, :math:`n`} right singular vectors are computed and their (conjugate) transposes are returned as rows of ``A``. Note that the (conjugate) transposes of the right singular vectors (i.e., the matrix :math:`V^H`) are returned in ``Vt`` or ``A``. The argument ``Vt`` can be :const:`None` (if ``jobvt`` is :const:`'N'` or :const:`'A'`) or a matrix of the same type as ``A``. On exit, the contents of ``A`` are destroyed. .. function:: cvxopt.lapack.gesdd(A, S[, jobz = 'N', U = None, Vt = None]) Singular value decomposition of a real or complex :math:`m` by :math:`n` matrix.. This function is based on a divide-and-conquer algorithm and is faster than :func:`gesvd `. ``S`` is a real matrix of length at least min{:math:`m`, :math:`n`}. On exit, its first min{:math:`m`, :math:`n`} elements are the singular values in descending order. The argument ``jobz`` controls how many singular vectors are computed. The possible values are :const:`'N'`, :const:`'A'`, :const:`'S'` and :const:`'O'`. If ``jobz`` is :const:`'N'`, no singular vectors are computed. If ``jobz`` is :const:`'A'`, all :math:`m` left singular vectors are computed and returned as columns of ``U`` and all :math:`n` right singular vectors are computed and returned as rows of ``Vt``. If ``jobz`` is :const:`'S'`, the first min{:math:`m`, :math:`n`} left and right singular vectors are computed and returned as columns of ``U`` and rows of ``Vt``. If ``jobz`` is :const:`'O'` and :math:`m` is greater than or equal to :math:`n`, the first :math:`n` left singular vectors are returned as columns of ``A`` and the :math:`n` right singular vectors are returned as rows of ``Vt``. If ``jobz`` is :const:`'O'` and :math:`m` is less than :math:`n`, the :math:`m` left singular vectors are returned as columns of ``U`` and the first :math:`m` right singular vectors are returned as rows of ``A``. Note that the (conjugate) transposes of the right singular vectors are returned in ``Vt`` or ``A``. The argument ``U`` can be :const:`None` (if ``jobz`` is :const:`'N'` or :const:`'A'` of ``jobz`` is :const:`'O'` and :math:`m` is greater than or equal to :math:`n`) or a matrix of the same type as ``A``. The argument ``Vt`` can be \None\ (if ``jobz`` is :const:`'N'` or :const:`'A'` or ``jobz`` is :const:`'O'` and :math`m` is less than :math:`n`) or a matrix of the same type as ``A``. On exit, the contents of ``A`` are destroyed. Schur and Generalized Schur Factorization ========================================= .. function:: cvxopt.lapack.gees(A[, w = None, V = None, select = None]) Computes the Schur factorization .. math:: A = V S V^T \quad \mbox{($A$ real)}, \qquad A = V S V^H \quad \mbox{($A$ complex)} of a real or complex :math:`n` by :math:`n` matrix :math:`A`. If :math:`A` is real, the matrix of Schur vectors :math:`V` is orthogonal, and :math:`S` is a real upper quasi-triangular matrix with 1 by 1 or 2 by 2 diagonal blocks. The 2 by 2 blocks correspond to complex conjugate pairs of eigenvalues of :math:`A`. If :math:`A` is complex, the matrix of Schur vectors :math:`V` is unitary, and :math:`S` is a complex upper triangular matrix with the eigenvalues of :math:`A` on the diagonal. The optional argument ``w`` is a complex matrix of length at least :math:`n`. If it is provided, the eigenvalues of ``A`` are returned in ``w``. The optional argument ``V`` is an :math:`n` by :math:`n` matrix of the same type as ``A``. If it is provided, then the Schur vectors are returned in ``V``. The argument ``select`` is an optional ordering routine. It must be a Python function that can be called as ``f(s)`` with a complex argument ``s``, and returns :const:`True` or :const:`False`. The eigenvalues for which ``select`` returns :const:`True` will be selected to appear first along the diagonal. (In the real Schur factorization, if either one of a complex conjugate pair of eigenvalues is selected, then both are selected.) On exit, ``A`` is replaced with the matrix :math:`S`. The function :func:`gees` returns an integer equal to the number of eigenvalues that were selected by the ordering routine. If ``select`` is :const:`None`, then :func:`gees` returns 0. As an example we compute the complex Schur form of the matrix .. math:: A = \left[\begin{array}{rrrrr} -7 & -11 & -6 & -4 & 11 \\ 5 & -3 & 3 & -12 & 0 \\ 11 & 11 & -5 & -14 & 9 \\ -4 & 8 & 0 & 8 & 6 \\ 13 & -19 & -12 & -8 & 10 \end{array}\right]. >>> A = matrix([[-7., 5., 11., -4., 13.], [-11., -3., 11., 8., -19.], [-6., 3., -5., 0., -12.], [-4., -12., -14., 8., -8.], [11., 0., 9., 6., 10.]]) >>> S = matrix(A, tc='z') >>> w = matrix(0.0, (5,1), 'z') >>> lapack.gees(S, w) 0 >>> print(S) [ 5.67e+00+j1.69e+01 -2.13e+01+j2.85e+00 1.40e+00+j5.88e+00 -4.19e+00+j2.05e-01 3.19e+00-j1.01e+01] [ 0.00e+00-j0.00e+00 5.67e+00-j1.69e+01 1.09e+01+j5.93e-01 -3.29e+00-j1.26e+00 -1.26e+01+j7.80e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 1.27e+01+j3.43e-17 -6.83e+00+j2.18e+00 5.31e+00-j1.69e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 -1.31e+01-j0.00e+00 -2.60e-01-j0.00e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 -7.86e+00-j0.00e+00] >>> print(w) [ 5.67e+00+j1.69e+01] [ 5.67e+00-j1.69e+01] [ 1.27e+01+j3.43e-17] [-1.31e+01-j0.00e+00] [-7.86e+00-j0.00e+00] An ordered Schur factorization with the eigenvalues in the left half of the complex plane ordered first, can be computed as follows. >>> S = matrix(A, tc='z') >>> def F(x): return (x.real < 0.0) ... >>> lapack.gees(S, w, select = F) 2 >>> print(S) [-1.31e+01-j0.00e+00 -1.72e-01+j7.93e-02 -2.81e+00+j1.46e+00 3.79e+00-j2.67e-01 5.14e+00-j4.84e+00] [ 0.00e+00-j0.00e+00 -7.86e+00-j0.00e+00 -1.43e+01+j8.31e+00 5.17e+00+j8.79e+00 2.35e+00-j7.86e-01] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 5.67e+00+j1.69e+01 -1.71e+01-j1.41e+01 1.83e+00-j4.63e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 5.67e+00-j1.69e+01 -8.75e+00+j2.88e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 1.27e+01+j3.43e-17] >>> print(w) [-1.31e+01-j0.00e+00] [-7.86e+00-j0.00e+00] [ 5.67e+00+j1.69e+01] [ 5.67e+00-j1.69e+01] [ 1.27e+01+j3.43e-17] .. function:: cvxopt.lapack.gges(A, B[, a = None, b = None, Vl = None, Vr = None, select = None]) Computes the generalized Schur factorization .. math:: A = V_l S V_r^T, \quad B = V_l T V_r^T \quad \mbox{($A$ and $B$ real)}, A = V_l S V_r^H, \quad B = V_l T V_r^H, \quad \mbox{($A$ and $B$ complex)} of a pair of real or complex :math:`n` by :math:`n` matrices :math:`A`, :math:`B`. If :math:`A` and :math:`B` are real, then the matrices of left and right Schur vectors :math:`V_l` and :math:`V_r` are orthogonal, :math:`S` is a real upper quasi-triangular matrix with 1 by 1 or 2 by 2 diagonal blocks, and :math:`T` is a real triangular matrix with nonnegative diagonal. The 2 by 2 blocks along the diagonal of :math:`S` correspond to complex conjugate pairs of generalized eigenvalues of :math:`A`, :math:`B`. If :math:`A` and :math:`B` are complex, the matrices of left and right Schur vectors :math:`V_l` and :math:`V_r` are unitary, :math:`S` is complex upper triangular, and :math:`T` is complex upper triangular with nonnegative real diagonal. The optional arguments ``a`` and ``b`` are :const:`'z'` and :const:`'d'` matrices of length at least :math:`n`. If these are provided, the generalized eigenvalues of ``A``, ``B`` are returned in ``a`` and ``b``. (The generalized eigenvalues are the ratios ``a[k] / b[k]``.) The optional arguments ``Vl`` and ``Vr`` are :math:`n` by :math:`n` matrices of the same type as ``A`` and ``B``. If they are provided, then the left Schur vectors are returned in ``Vl`` and the right Schur vectors are returned in ``Vr``. The argument ``select`` is an optional ordering routine. It must be a Python function that can be called as ``f(x,y)`` with a complex argument ``x`` and a real argument ``y``, and returns :const:`True` or :const:`False`. The eigenvalues for which ``select`` returns :const:`True` will be selected to appear first on the diagonal. (In the real Schur factorization, if either one of a complex conjugate pair of eigenvalues is selected, then both are selected.) On exit, ``A`` is replaced with the matrix :math:`S` and ``B`` is replaced with the matrix :math:`T`. The function :func:`gges` returns an integer equal to the number of eigenvalues that were selected by the ordering routine. If ``select`` is :const:`None`, then :func:`gges` returns 0. As an example, we compute the generalized complex Schur form of the matrix :math:`A` of the previous example, and .. math:: B = \left[\begin{array}{ccccc} 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 \end{array}\right]. >>> A = matrix([[-7., 5., 11., -4., 13.], [-11., -3., 11., 8., -19.], [-6., 3., -5., 0., -12.], [-4., -12., -14., 8., -8.], [11., 0., 9., 6., 10.]]) >>> B = matrix(0.0, (5,5)) >>> B[:19:6] = 1.0 >>> S = matrix(A, tc='z') >>> T = matrix(B, tc='z') >>> a = matrix(0.0, (5,1), 'z') >>> b = matrix(0.0, (5,1)) >>> lapack.gges(S, T, a, b) 0 >>> print(S) [ 6.64e+00-j8.87e+00 -7.81e+00-j7.53e+00 6.16e+00-j8.51e-01 1.18e+00+j9.17e+00 5.88e+00-j4.51e+00] [ 0.00e+00-j0.00e+00 8.48e+00+j1.13e+01 -2.12e-01+j1.00e+01 5.68e+00+j2.40e+00 -2.47e+00+j9.38e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 -1.39e+01-j0.00e+00 6.78e+00-j0.00e+00 1.09e+01-j0.00e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 -6.62e+00-j0.00e+00 -2.28e-01-j0.00e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 -2.89e+01-j0.00e+00] >>> print(T) [ 6.46e-01-j0.00e+00 4.29e-01-j4.79e-02 2.02e-01-j3.71e-01 1.08e-01-j1.98e-01 -1.95e-01+j3.58e-01] [ 0.00e+00-j0.00e+00 8.25e-01-j0.00e+00 -2.17e-01+j3.11e-01 -1.16e-01+j1.67e-01 2.10e-01-j3.01e-01] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 7.41e-01-j0.00e+00 -3.25e-01-j0.00e+00 5.87e-01-j0.00e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 8.75e-01-j0.00e+00 4.84e-01-j0.00e+00] [ 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00 0.00e+00-j0.00e+00] >>> print(a) [ 6.64e+00-j8.87e+00] [ 8.48e+00+j1.13e+01] [-1.39e+01-j0.00e+00] [-6.62e+00-j0.00e+00] [-2.89e+01-j0.00e+00] >>> print(b) [ 6.46e-01] [ 8.25e-01] [ 7.41e-01] [ 8.75e-01] [ 0.00e+00] Example: Analytic Centering =========================== The analytic centering problem is defined as .. math:: \begin{array}{ll} \mbox{minimize} & -\sum\limits_{i=1}^m \log(b_i-a_i^Tx). \end{array} In the code below we solve the problem using Newton's method. At each iteration the Newton direction is computed by solving a positive definite set of linear equations .. math:: \newcommand{\diag}{\mathop{\bf diag}} \newcommand{\ones}{\mathbf 1} A^T \diag(b-Ax)^{-2} A v = -\diag(b-Ax)^{-1}\ones (where :math:`A` has rows :math:`a_i^T`), and a suitable step size is determined by a backtracking line search. We use the level-3 BLAS function :func:`blas.syrk ` to form the Hessian matrix and the LAPACK function :func:`posv ` to solve the Newton system. The code can be further optimized by replacing the matrix-vector products with the level-2 BLAS function :func:`blas.gemv `. :: from cvxopt import matrix, log, mul, div, blas, lapack from math import sqrt def acent(A,b): """ Returns the analytic center of A*x <= b. We assume that b > 0 and the feasible set is bounded. """ MAXITERS = 100 ALPHA = 0.01 BETA = 0.5 TOL = 1e-8 m, n = A.size x = matrix(0.0, (n,1)) H = matrix(0.0, (n,n)) for iter in xrange(MAXITERS): # Gradient is g = A^T * (1./(b-A*x)). d = (b - A*x)**-1 g = A.T * d # Hessian is H = A^T * diag(d)^2 * A. Asc = mul( d[:,n*[0]], A ) blas.syrk(Asc, H, trans='T') # Newton step is v = -H^-1 * g. v = -g lapack.posv(H, v) # Terminate if Newton decrement is less than TOL. lam = blas.dot(g, v) if sqrt(-lam) < TOL: return x # Backtracking line search. y = mul(A*v, d) step = 1.0 while 1-step*max(y) < 0: step *= BETA while True: if -sum(log(1-step*y)) < ALPHA*step*lam: break step *= BETA x += step*v cvxopt-1.1.4/doc/source/printing.rst0000644000175000017500000001134711674452555016543 0ustar sonnesonne.. _c-printing: ***************** Matrix Formatting ***************** This appendix describes ways to customize the formatting of CVXOPT matrices. As with other Python objects, the functions :func:`repr` and :func:`str` return strings with printable representations of matrices. The command '``print A``' executes '``str(A)``', whereas the command '``A``' calls '``repr(A)``'. The following example illustrates the default formatting of dense matrices. >>> from cvxopt import matrix >>> A = matrix(range(50), (5,10), 'd') >>> A <5x10 matrix, tc='d'> >>> print(A) [ 0.00e+00 5.00e+00 1.00e+01 1.50e+01 2.00e+01 2.50e+01 3.00e+01 ... ] [ 1.00e+00 6.00e+00 1.10e+01 1.60e+01 2.10e+01 2.60e+01 3.10e+01 ... ] [ 2.00e+00 7.00e+00 1.20e+01 1.70e+01 2.20e+01 2.70e+01 3.20e+01 ... ] [ 3.00e+00 8.00e+00 1.30e+01 1.80e+01 2.30e+01 2.80e+01 3.30e+01 ... ] [ 4.00e+00 9.00e+00 1.40e+01 1.90e+01 2.40e+01 2.90e+01 3.40e+01 ... ] The format is parameterized by the dictionary :data:`options` in the module :mod:`cvxopt.printing`. The parameters :attr:`options['iformat']` and :attr:`options['dformat']` determine, respectively, how integer and double/complex numbers are printed. The entries are Python format strings with default values :const:`'\% .2e'` for :const:`'d'` and :const:`'z'` matrices and :const:`\% i'` for :const:`'i'` matrices. The parameters :attr:`options['width']` and :attr:`options['height']` specify the maximum number of columns and rows that are shown. If :attr:`options['width']` is set to a negative value, all columns are displayed. If :attr:`options['height']` is set to a negative value, all rows are displayed. The default values of :attr:`options['width']` and :attr:`options['height']` are 7 and -1, respectively. >>> from cvxopt import printing >>> printing.options {'width': 7, 'dformat': '% .2e', 'iformat': '% i', 'height': -1} >>> printing.options['dformat'] = '%.1f' >>> printing.options['width'] = -1 >>> print(A) [ 0.0 5.0 10.0 15.0 20.0 25.0 30.0 35.0 40.0 45.0] [ 1.0 6.0 11.0 16.0 21.0 26.0 31.0 36.0 41.0 46.0] [ 2.0 7.0 12.0 17.0 22.0 27.0 32.0 37.0 42.0 47.0] [ 3.0 8.0 13.0 18.0 23.0 28.0 33.0 38.0 43.0 48.0] [ 4.0 9.0 14.0 19.0 24.0 29.0 34.0 39.0 44.0 49.0] In order to make the built-in Python functions :func:`repr` and :func:`str` accessible for further customization, two functions are provided in CVXOPT. The function :func:`cvxopt.matrix_repr` is used when :func:`repr` is called with a matrix argument; and :func:`cvxopt.matrix_str` is used when :func:`str` is called with a matrix argument. By default, the functions are set to :func:`printing.matrix_repr_default` and :func:`printing.matrix_str_default`, respectively, but they can be redefined to any other Python functions. For example, if we prefer ``A`` to return the same output as ``print A``, we can simply redefine :func:`cvxopt.matrix_repr` as shown below. >>> import cvxopt >>> from cvxopt import matrix, printing >>> A = matrix(range(4), (2,2), 'd') >>> A <2x2 matrix, tc='d'> >>> cvxopt.matrix_repr = printing.matrix_str_default >>> A [ 0.00e+00 2.00e+00] [ 1.00e+00 3.00e+00] The formatting for sparse matrices is similar. The functions :func:`repr` and :func:`str` for sparse matrices are :func:`cvxopt.spmatrix_repr` and :func:`cvxopt.spmatrix_str`, respectively. By default, they are set to :func:`printing.spmatrix_repr_default` and :func:`printing.spmatrix_repr_str`. >>> import cvxopt >>> from cvxopt import printing, spmatrix >>> A = spmatrix(range(5), range(5), range(5), (5,10)) >>> A <5x10 sparse matrix, tc='d', nnz=5> >>> print(A) [ 0.00e+00 0 0 0 0 0 0 ... ] [ 0 1.00e+00 0 0 0 0 0 ... ] [ 0 0 2.00e+00 0 0 0 0 ... ] [ 0 0 0 3.00e+00 0 0 0 ... ] [ 0 0 0 0 4.00e+00 0 0 ... ] >>> cvxopt.spmatrix_repr = printing.spmatrix_str_default >>> A [ 0.00e+00 0 0 0 0 0 0 ... ] [ 0 1.00e+00 0 0 0 0 0 ... ] [ 0 0 2.00e+00 0 0 0 0 ... ] [ 0 0 0 3.00e+00 0 0 0 ... ] [ 0 0 0 0 4.00e+00 0 0 ... ] As can be seen from the example, the default behaviour is to print the entire matrix including structural zeros. An alternative triplet printing style is defined in :func:`printing.spmatrix_str_triplet`. >>> cvxopt.spmatrix_str = printing.spmatrix_str_triplet >>> print(A) (0,0) 0.00e+00 (1,1) 1.00e+00 (2,2) 2.00e+00 (3,3) 3.00e+00 (4,4) 4.00e+00 cvxopt-1.1.4/doc/source/fftw.rst0000644000175000017500000001551311674452555015656 0ustar sonnesonne.. _c-fftw: ******************* Discrete Transforms ******************* The :mod:`cvxopt.fftw` module is an interface to the FFTW library and contains routines for discrete Fourier, cosine, and sine transforms. This module is optional, and only installed when the FFTW library is made available during the CVXOPT installation. .. seealso:: `FFTW3 code, documentation, copyright and license `_ Discrete Fourier Transform ========================== .. function:: cvxopt.fftw.dft(X) Replaces the columns of a dense complex matrix with their discrete Fourier transforms: if ``X`` has :math:`n` rows, .. math:: X[k,:] := \sum_{j=0}^{n-1} e^{-2\pi j k \sqrt{-1}/n} X[j,:], \qquad k=0,\ldots,n-1. .. function:: cvxopt.fftw.idft(X) Replaces the columns of a dense complex matrix with their inverse discrete Fourier transforms: if ``X`` has :math:`n` rows, .. math:: X[k,:] := \frac{1}{n} \sum_{j=0}^{n-1} e^{2\pi j k \sqrt{-1}/n} X[j,:], \qquad k=0,\ldots,n-1. The module also includes a discrete *N*-dimensional Fourier transform. The input matrix is interpreted as an *N*-dimensional matrix stored in column-major order. The discrete *N*-dimensional Fourier transform computes the corresponding one-dimensional transform along each dimension. For example, the two-dimensional transform applies a one-dimensional transform to all the columns of the matrix, followed by a one-dimensional transform to all the rows of the matrix. .. function:: cvxopt.fftw.dftn(X[, dims = X.size]) Replaces a dense complex matrix with its *N*-dimensional discrete Fourier transform. The dimensions of the *N*-dimensional matrix are given by the *N*-tuple ``dims``. The two-dimensional transform is computed as ``dftn(X, X.size)``. .. function:: cvxopt.fftw.idftn(X[, dims = X.size]) Replaces a dense complex *N*-dimensional matrix with its inverse *N*-dimensional discrete Fourier transform. The dimensions of the matrix are given by the tuple ``dims``. The two-dimensional inverse transform is computed as ``idftn(X, X.size)``. Discrete Cosine Transform ========================= .. function:: cvxopt.fftw.dct(X[, type = 2]) Replaces the columns of a dense real matrix with their discrete cosine transforms. The second argument, an integer between 1 and 4, denotes the type of transform (DCT-I, DCT-II, DCT-III, DCT-IV). The DCT-I transform requires that the row dimension of ``X`` is at least 2. These transforms are defined as follows (for a matrix with :math:`n` rows). .. math:: \mbox{DCT-I:} \qquad X[k,:] & := X[0,:] + (-1)^k X[n-1,:] + 2 \sum_{j=1}^{n-2} X[j,:] \cos(\pi j k /(n-1)), \qquad k=0,\ldots,n-1.\\ \mbox{DCT-II:} \qquad X[k,:] & := 2 \sum_{j=0}^{n-1} X[j,:] \cos(\pi(j+1/2)k/n), \qquad k=0,\ldots,n-1.\\ \mbox{DCT-III:} \qquad X[k,:] & := X[0,:] + 2 \sum_{j=1}^{n-1} X[j,:] \cos(\pi j(k+1/2)/n), \qquad k=0,\ldots,n-1.\\ \mbox{DCT-IV:} \qquad X[k,:] & := 2 \sum_{j=0}^{n-1} X[j,:] \cos(\pi (j+1/2)(k+1/2)/n), \qquad k=0,\ldots,n-1. .. function:: cvxopt.fftw.idct(X[, type = 2]) Replaces the columns of a dense real matrix with the inverses of the discrete cosine transforms defined above. The module also includes a discrete *N*-dimensional cosine transform. The input matrix is interpreted as an *N*-dimensional matrix stored in column-major order. The discrete *N*-dimensional cosine transform computes the corresponding one-dimensional transform along each dimension. For example, the two-dimensional transform applies a one-dimensional transform to all the rows of the matrix, followed by a one-dimensional transform to all the columns of the matrix. .. function:: cvxopt.fftw.dctn(X[, dims = X.size, type = 2]) Replaces a dense real matrix with its *N*-dimensional discrete cosine transform. The dimensions of the *N*-dimensional matrix are given by the *N*-tuple ``dims``. The two-dimensional transform is computed as ``dctn(X, X.size)``. .. function:: cvxopt.fftw.idctn(X[, dims = X.size, type = 2]) Replaces a dense real *N*-dimensional matrix with its inverse *N*-dimensional discrete cosine transform. The dimensions of the matrix are given by the tuple ``dims``. The two-dimensional inverse transform is computed as ``idctn(X, X.size)``. Discrete Sine Transform ======================= .. function:: cvxopt.fftw.dst(X, dims[, type = 1]) Replaces the columns of a dense real matrix with their discrete sine transforms. The second argument, an integer between 1 and 4, denotes the type of transform (DST-I, DST-II, DST-III, DST-IV). These transforms are defined as follows (for a matrix with :math:`n` rows). .. math:: \mbox{DST-I:} \qquad X[k,:] & := 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi(j+1)(k+1)/(n+1)), \qquad k=0,\ldots,n-1.\\ \mbox{DST-II:} \qquad X[k,:] & := 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi(j+1/2)(k+1)/n), \qquad k=0,\ldots,n-1.\\ \mbox{DST-III:} \qquad X[k,:] & := (-1)^k X[n-1,:] + 2 \sum_{j=0}^{n-2} X[j,:] \sin(\pi(j+1)(k+1/2)/n), \qquad k=0,\ldots,n-1. \\ \mbox{DST-IV:} \qquad X[k,:] & := 2 \sum_{j=0}^{n-1} X[j,:] \sin(\pi (j+1/2)(k+1/2)/n), \qquad k=0,\ldots,n-1. .. function:: cvxopt.fftw.idst(X, dims[, type = 1]) Replaces the columns of a dense real matrix with the inverses of the discrete sine transforms defined above. The module also includes a discrete *N*-dimensional sine transform. The input matrix is interpreted as an *N*-dimensional matrix stored in column-major order. The discrete *N*-dimensional sine transform computes the corresponding one-dimensional transform along each dimension. For example, the two-dimensional transform applies a one-dimensional transform to all the rows of the matrix, followed by a one-dimensional transform to all the columns of the matrix. .. function:: cvxopt.fftw.dstn(X[, dims = X.size, type = 2]) Replaces a dense real matrix with its *N*-dimensional discrete sine transform. The dimensions of the *N*-dimensional matrix are given by the *N*-tuple ``dims``. The two-dimensional transform is computed as ``dstn(X, X.size)``. .. function:: cvxopt.fftw.idstn(X[, dims = X.size, type = 2]) Replaces a dense real *N*-dimensional matrix with its inverse *N*-dimensional discrete sine transform. The dimensions of the matrix are given by the tuple ``dims``. The two-dimensional inverse transform is computed as ``idstn(X, X.size)``. cvxopt-1.1.4/doc/source/.static/0000755000175000017500000000000011674452555015516 5ustar sonnesonnecvxopt-1.1.4/doc/source/.static/cvxopt.css0000644000175000017500000002427611674452555017566 0ustar sonnesonne/* * Alternate Sphinx design * Originally created by Armin Ronacher for Werkzeug, adapted by Georg * Brandl. * Adapted for CVXOPT. */ body { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; font-size: 14px; letter-spacing: -0.01em; line-height: 150%; text-align: center; /* background-color: #AFC1C4; */ /* background-color: #BFD1D4; */ color: black; /* border: 1px solid #aaa; */ margin: 0px 20px 0px 20px; /* min-width: 740px; */ min-width: 800px; */ } a { /* color: #CA7900; */ color: black; text-decoration: underline; } a:hover { /* color: #2491CF; */ text-decoration: underline; } li[class="toctree-l1"] a, div.sphinxsidebar a { text-decoration: none !important; } li[class="toctree-l1"] a:hover, div.sphinxsidebar a:hover { text-decoration: underline !important; color: black !important; } li[class="toctree-l1"] ul { list-style-type: circle; } div.sphinxsidebarwrapper h3 a:hover { text-decoration: none !important; color: white !important; } pre { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.015em; padding: 0.5em; border: 1px solid #ccc; background-color: #f8f8f8; } td.linenos pre { padding: 0.5em 0; border: 0; background-color: transparent; color: #aaa; } table.highlighttable { margin-left: 0.5em; } table.highlighttable td { padding: 0 0.5em 0 0.5em; } cite, code { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 0.95em; letter-spacing: 0.01em; } hr { border: 1px solid #abc; margin: 2em; } tt { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; } /* function names */ tt.descname { font-style: normal; background-color: transparent; font-weight: bold; font-size: 1.2em; border: 0; } /* module name prepended to function name*/ tt.descclassname { font-style: normal; background-color: transparent; border: 0; } /* variables in function argument list and definition, :samp: */ tt.docutils.literal, dl.function em { font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-style: italic; background-color: transparent; border: 0; } /* function name in reference, and literals */ tt.xref.docutils.literal { font-style: normal; background-color: transparent; font-weight: bold; border: 0; } a tt { background-color: transparent; font-weight: bold; border: 0; /* color: #CA7900; */ } /* a tt:hover { color: #2491CF; } */ .field-list ul { margin: 0; padding-left: 1em; } .field-list p { margin: 0; } dl { margin-bottom: 15px; } dd p { margin-top: 0px; } dd ul, dd table { margin-bottom: 10px; } dd { margin-top: 3px; margin-bottom: 10px; margin-left: 30px; } .refcount { color: #060; } dt:target, .highlight { background-color: #fbe54e; } dl.glossary dt { font-weight: bold; font-size: 1.1em; } pre { line-height: 120%; } pre a { color: inherit; text-decoration: underline; } .first { margin-top: 0 !important; } div.document { background-color: white; text-align: left; /* background-image: url(contents.png); */ /* background-repeat: repeat-x; */ } /* div.documentwrapper { width: 100%; } */ div.clearer { clear: both; } div.related h3 { display: none; } div.related ul { /* background-image: url(navigation.png); */ height: 2em; list-style: none; border-top: 1px solid #ddd; border-bottom: 1px solid #ddd; margin: 0; padding-left: 10px; } div.related ul li { margin: 0; padding: 0; height: 2em; float: left; } div.related ul li.right { float: right; margin-right: 5px; } div.related ul li a { margin: 0; padding: 0 5px 0 5px; line-height: 1.75em; /* color: #EE9816; */ text-decoration: none; } div.related ul li a:hover { /* color: #3CA8E7; */ text-decoration: underline; } div.body { margin: 0; padding: 0.5em 20px 20px 20px; } div.documentwrapper{ float: left; width: 100%; } div.bodywrapper { /* margin: 0 240px 0 0; */ margin: 0 0 0 240px; border-left: 1px solid #ccc; } /* div.body a { text-decoration: underline; text-decoration: none; } */ div.body a:hover { color: #2491CF; } div.sphinxsidebar { margin: 0; padding: 0.5em 15px 15px 0; width: 210px; float: left; text-align: left; margin-left: -100%; } div.sphinxsidebar h4, div.sphinxsidebar h3 { margin: 1em 0 .2em 0; /* font-size: 0.9em; */ font-size: 1.1em; padding: 0.1em 0 0.1em 0.5em; color: white; border: 1px solid #86989B; background-color: #AFC1C4; } div.sphinxsidebar h3 a { color: white; } div.sphinxsidebar ul { padding-left: 1.5em; margin-top: 7px; list-style: none; padding: 0; line-height: 130%; } div.sphinxsidebar ul ul { list-style: square; margin-left: 20px; } p { margin: 0.8em 0 0.5em 0; } p.rubric { font-weight: bold; } div.sidebar { margin: 0 0 0.5em 1em; border: 1px solid #ddb; padding: 7px 7px 0 7px; background-color: #ffe; width: 40%; float: right; } div.quotebar { background-color: #f8f8f8; max-width: 250px; float: right; padding: 2px 7px; border: 1px solid #ccc; } p.sidebar-title { font-weight: bold; } div.topic { background-color: #f8f8f8; border: 1px solid #ccc; padding: 7px 7px 0 7px; margin: 10px 0 10px 0; } p.topic-title { font-size: 1.1em; font-weight: bold; } h1 { margin: 0; padding: 0.7em 0 0.3em 0; font-size: 1.5em; color: #11557C; } h2 { margin: 1.3em 0 0.2em 0; font-size: 1.35em; padding: 0; color: #11557C; } h3 { margin: 1em 0 -0.3em 0; font-size: 1.2em; } div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a { color: black!important; } h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { display: none; margin: 0 0 0 0.3em; padding: 0 0.2em 0 0.2em; color: #aaa!important; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { display: inline; } h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, h5 a.anchor:hover, h6 a.anchor:hover { color: #777; background-color: #eee; } table { border-collapse: collapse; margin: 0 -0.5em 0 -0.5em; } table.docutils{ margin-left: auto; margin-right: auto; width: 60%; margin-top: 1em; margin-bottom: 1em; } table td, table th { padding: 0.2em 0.5em 0.2em 0.5em; } div.footer { /* background-color: #E3EFF1; */ color: #86989B; padding: 3px 8px 3px 0; clear: both; font-size: 0.8em; text-align: right; } div.footer a { color: #86989B; text-decoration: underline; } div.pagination { margin-top: 2em; padding-top: 0.5em; border-top: 1px solid black; text-align: center; } div.sphinxsidebar ul.toc { margin: 1em 0 1em 0; padding: 0 0 0 0.5em; list-style: none; } div.sphinxsidebar ul.toc li { margin: 0.5em 0 0.5em 0; font-size: 0.9em; line-height: 130%; } div.sphinxsidebar ul.toc li p { margin: 0; padding: 0; } div.sphinxsidebar ul.toc ul { margin: 0.2em 0 0.2em 0; padding: 0 0 0 1.8em; } div.sphinxsidebar ul.toc ul li { padding: 0; } div.admonition, div.warning { font-size: 0.9em; margin: 1em 0 0 0; border: 1px solid #86989B; background-color: #f7f7f7; } div.admonition p, div.warning p { margin: 0.5em 1em 0.5em 1em; padding: 0; } div.admonition pre, div.warning pre { margin: 0.4em 1em 0.4em 1em; } div.admonition p.admonition-title, div.warning p.admonition-title { margin: 0; padding: 0.1em 0 0.1em 0.5em; color: white; border-bottom: 1px solid #86989B; font-weight: bold; background-color: #AFC1C4; } div.warning { border: 1px solid #940000; } div.warning p.admonition-title { background-color: #CF0000; border-bottom-color: #940000; } div.admonition ul, div.admonition ol, div.warning ul, div.warning ol { margin: 0.1em 0.5em 0.5em 3em; padding: 0; } div.versioninfo { margin: 1em 0 0 0; border: 1px solid #ccc; background-color: #DDEAF0; padding: 8px; line-height: 1.3em; font-size: 0.9em; } a.headerlink { color: #c60f0f!important; font-size: 1em; margin-left: 6px; padding: 0 4px 0 4px; text-decoration: none!important; visibility: hidden; } h1:hover > a.headerlink, h2:hover > a.headerlink, h3:hover > a.headerlink, h4:hover > a.headerlink, h5:hover > a.headerlink, h6:hover > a.headerlink, dt:hover > a.headerlink { visibility: visible; } a.headerlink:hover { background-color: #ccc; color: white!important; } table.indextable td { text-align: left; vertical-align: top; } table.indextable dl, table.indextable dd { margin-top: 0; margin-bottom: 0; } table.indextable tr.pcap { height: 10px; } table.indextable tr.cap { margin-top: 10px; background-color: #f2f2f2; } img.toggler { margin-right: 3px; margin-top: 3px; cursor: pointer; } form.pfform { margin: 10px 0 20px 0; } table.contentstable { width: 90%; } table.contentstable p.biglink { line-height: 150%; } a.biglink { font-size: 1.3em; } span.linkdescr { font-style: italic; padding-top: 5px; font-size: 90%; } ul.search { margin: 10px 0 0 20px; padding: 0; } ul.search li { padding: 5px 0 5px 20px; background-image: url(file.png); background-repeat: no-repeat; background-position: 0 7px; } ul.search li a { font-weight: bold; } ul.search li div.context { color: #888; margin: 2px 0 0 30px; text-align: left; } ul.keywordmatches li.goodmatch a { font-weight: bold; } img.math { vertical-align: middle; } div.math { text-align: center; } span.eqno { float: right; } img.logo { border: 0; } span.raise { vertical-align:super; font-size: .7em; } ul { list-style-type: disc; } cvxopt-1.1.4/doc/source/intro.rst0000644000175000017500000000574511674452555016051 0ustar sonnesonne.. _intro: ************ Introduction ************ CVXOPT is a free software package for convex optimization based on the Python programming language. It can be used with the interactive Python interpreter, on the command line by executing Python scripts, or integrated in other software via Python extension modules. Its main purpose is to make the development of software for convex optimization applications straightforward by building on Python's extensive standard library and on the strengths of Python as a high-level programming language. CVXOPT extends the built-in Python objects with two matrix objects: a :class:`matrix ` object for dense matrices and an :class:`spmatrix ` object for sparse matrices. These two matrix types are introduced in the chapter :ref:`c-matrices`, together with the arithmetic operations and functions defined for them. The following chapters (:ref:`c-blas` and :ref:`c-spsolvers`) describe interfaces to several libraries for dense and sparse matrix computations. The CVXOPT optimization routines are described in the chapters :ref:`c-coneprog` and :ref:`c-modeling`. These include convex optimization solvers written in Python, interfaces to a few other optimization libraries, and a modeling tool for piecewise-linear convex optimization problems. CVXOPT is organized in different modules. :mod:`cvxopt.blas ` Interface to most of the double-precision real and complex BLAS (:ref:`c-blas`). :mod:`cvxopt.lapack ` Interface to dense double-precision real and complex linear equation solvers and eigenvalue routines from LAPACK (:ref:`c-lapack`). :mod:`cvxopt.fftw ` An optional interface to the discrete transform routines from FFTW (:ref:`c-fftw`). :mod:`cvxopt.amd ` Interface to the approximate minimum degree ordering routine from AMD (:ref:`s-orderings`). :mod:`cvxopt.umfpack ` Interface to the sparse LU solver from UMFPACK (:ref:`s-umfpack`). :mod:`cvxopt.cholmod ` Interface to the sparse Cholesky solver from CHOLMOD (:ref:`s-cholmod`). :mod:`cvxopt.solvers ` Convex optimization routines and optional interfaces to solvers from GLPK, MOSEK, and DSDP5 (:ref:`c-coneprog` and :ref:`c-solvers`). :mod:`cvxopt.modeling ` Routines for specifying and solving linear programs and convex optimization problems with piecewise-linear cost and constraint functions (:ref:`c-modeling`). :mod:`cvxopt.info ` Defines a string :const:`version` with the version number of the CVXOPT installation and a function :func:`license` that prints the CVXOPT license. :mod:`cvxopt.printing ` Contains functions and parameters that control how matrices are formatted. The modules are described in detail in this manual and in the on-line Python help facility :program:`pydoc`. Several example scripts are included in the distribution. cvxopt-1.1.4/doc/source/portfolio1.png0000644000175000017500000013251011674452555016757 0ustar sonnesonnePNG  IHDR,d(sBIT|d pHYsaa?i IDATxwXS;a (8pVܶZGAVj K=Uu#:):U qTTjō eW ( \Ws$$ $IԐ\t"""""`!"""""ł """""R[,XHm`!"""""ł """""R[,XHm`!"""""ł """""R[,XHm`!"""""ł """""R[,XHm`!"""""ł """""R[,XHm`!"""""ł """""R[,XHm`!"""""ł """""R[,XHm`!"""""ł """""R[,XHm`!"""""ł4J.] Gӧ!^dǐ077ϴl޼y8{lÙ3gDG)N:/$I҂\.GxxxgJ???r8qBt"*fND%ŋammuFFFh޼9OGq zLLVh+LEK]Cl\[f>,nϞ=8<ϟ<&L 6믿Ɯ9s0o>>HJJ*P5uvvưa|NѸqc'˺>޽{3-/_66yhذaQpi\֭øq޽ѡC4ozzzS߿ժUöm0dd,_h,,,իWcʔ)8p 믿`!*E$ݻ矡 , cŊHKKøq2]۷Gr`llXr>>>33f'fffdׇ!!!ٳ'*Trʡ_~s 22022"##1qDl˗ϸ@EZnFΝabbTR~- p (S 6l3g"...cbb0{l4me˖>6mI&]p2kذ!L/_fz.]`رkk&ꇓsH__~ɸ PvmL>Y?aaacccB /y۶mKKl|҇\pݻw!`aaR||<Э[7it 6D6mI-0bĈL `ԩm%]]]ϟǽ{򕕈Ja!|ۼy30h |g9ngkk wwwܼygΜre8qoطoKܹs+W`ĉPd7]NYd&LիWիػw/,,,кukL0QQQصkvׯgjsܹٳ'cǥKPF<k׮a…ܹ3a``(ȑ#G^k׮3 1dT\Xd 9{.֭[z*6l؀I&v7رcܹ3,-- .`Ŋ8r.\rxWTX NQCaÆ!$$ @ٲeqA,]زeKvGA߾}abbAzx\/z95j^z[[[SuɴgϞE!Iz!<<ݺuCΝs\\\7k–Yt]t;pa8::g4"E""'sssI&I6lÇd2?g,ۼy$$\.=z4Wd2ԵkLnj#d2޽{sΒ\.ϴ,00089;;K2L244<==3[b$ɤ%KdZc)---˱%---iܸq=/%$$dY#f͚RƍdyesΕd2t̙ewޕttt$֭[wrrd2dggiyv$L&-]4q7od='I&I-ʴ<=ul+sܹ$ɤ:H߼y#}g喖\."##d6?L&6ٽn{&--M_%?~<ׯx\}%L&mڴ)SZj1'Hr<ۿݻ$$ool_pAdȑ# J6 #|{ Y&Y={̴ M4A@@@#UnЯ_LF^:36lwMpgjj]tǏ(a]UV CEdd$KMtgiԨQ066.!iz[d 2_OOÇJ˗3'''Cl}O7o>\m1AAA}6z LlmmѬY,DoqF_U^=:cclI_SGʮCp֥YmM4 VBѫW/ԨQ)テ,,,P^=-[r8s2<}Dbcc :~~~W,--ajj ===H+W;r{Ye/"=6 #|ߟ6mڄǏq6:}t9s2 -[X@ܯ$IB=+Ϟ=իW |7oyY_~},뒒 }}!۵k8zG;OA߾}+W\:?g^ϡanne˖ z>5j %Gy4lq^3n߾=lmm^8uuu >9r$j֬3g|X,yjH,,DofffpssCJJ mWWWhkkcݺu>Α#G\^ׯ_yNZF_VwŔJX {{{1"""ٳL=<+W 2*U™3g&M`řE.]0ydر:u"##q DDDvܹ3Zh]vѣGС^| ???zY^˖-Ë/2a )?}G|>qa]vRٲe+J}]96-_\jҤ'd2,c].]r%yP޽+d2:ce7OFbb4qDz꒮TvmQszjqƒTreiRhh4o޼l.gNJ$?~\޽TbEIOOOjР4c )...Έ(+,s_)))\7ay-v@GժUѳgBk@DDDD؇#ԩ/_x71ֆ rƍ`|MբE L>!!!EHSK䵻ρиqb0rH(J<~#i,Eիh޼y͚5DDDw$""""Kq^xQܑJaQSH3paRLLLey2V$Hyzzb֭xtuuÆ Ν;xDyy=x;wFJJ ;"NGV4XJJ \\\,:`"ԬY3gY6mZܑ8}4j֬Y :{5{$$$`,VHm%%%!!!ppp DG,X%nܸR,55ꫯ`jj*0Ǐի(DjA$8::?>ի':Q`ooR www,^Xt$&apQ$&&"!!ѽ ӧaccܹsj;k֬h"T\k׮ŭ[pIaCd?~(Dj~~~F=D!"Vtt4p}xzzb#i,{x~Ϟ=سgd2޽ڵkCRAReTSNa0a^~-[ѣر!5vYvڢ wA/h۶-\]]E!"VTTKgϞ#i,pݏnyfl޼9*U`˖-E4͛7oP(`nn. r\*>akk SSSxyyc*t yB۶mEGH,Xą  kkk!JsϞ=Ð!C;wB.gwK*<#HpvvL&Ù3gШQ#ё4Ĺs砧ݻB$۷o1b<^^^XHDDY;wӃRdRXI d*$I”)SpE̚5 ͚5(Ç&&& E5DGx2"RoƳg`ii): 0^^^ŀ0p@qرcfϞ 333B # BΞ= \Q8ugaΜ9e"I퍖-[ԩSlQL3gΠJ*J[na066vE""T*-Zooot ,Vm".]BTbcc1d#eHII~w :4cp*^,X믿 IgR'55VVV>V\jժDD!)) ...?1ax{{Tj `ΝCrТE QՏ?3g_}8DD䄈̛7#j,XJMMٳgYPuVVVexOOO1BtR @W^Ebb" &: Q +̰xbq2ܿvvv/z): P!!!СCEG!*QQQ>|8ʖ-۷s"Rppp7op!mVt$,DJ*J7o`ذaHLLݻa`` : 44NNNd8s 5j$:?m k]v?>ԩ#:w888@OOJŊbB$˗R0|pQٳgf|ѣ8DD#G E5DGl`!DTBWW|(DE*..022E!"ܹnnn033CXX*T :}X B54ԩS3lڴ !"$I7# j/_?N:BTߏ={`РAoSTXx1еkW+%_!".\04ÇSSS̜9St"*RRR]vaСطo hٲ(DEBRaܸqHNNyQ@DB%%%'-: 33317Ν;ԪUKt"*쌫Wb޼ypuu Q1{?~Ic]~sAF0vXq{OOO1Bt$,DLT'!*|ɰ6\P=-={m۶W^#Q>`!*f ODG!*t .ĵk/pN"-vډDI`4nXtB+W⫯/D$Ldd$표'Ny#Q`!*FoFll,+: Q j*q gϞE ') r5JtB5sL}]vQ)'''DDD`?~H$ "P(PLF%ֳgJ*aQ)qXr%F%: ĂO>(_$I„ ]vhѣGظq#  : o"S̚5 u˗YG Q~:^~HU-4/_> gΜ6/E.!* ZZZ6l(D%I\]]m۶q6{"*t$^^^h۶-;5S@HHa`` : GܹѤIqHHe˖ ]vYPBT޾}0iFtԩSQvmL|8DA^~ \|nnn6mHT Q!JHHkСCQr;;;Kt" 񰷷Ghh(.\b &*D/^$I3f(D9Zl"""0|/_^t"111pppݻwɻThX"R ===o^tlbɒ%hժYQy)lmmcl޼4 BڵkA$A__>lmmKٳ#aB3ܻw|(DZ`ܹ @___t"oƘ1cÇX";,DDT'!꯿š5kбcGtEt"׮]O?Tt$PBTH  иqcQ2IHH tRqHDXPQB IP~}Q3g?~ oooꊎCD%\pp0\]]a```Nҥ(TJ-Yׯ_ܹsQ\9qHIIY /8Q>(J1c'ŋXlڶm=zCD%DJJ OӧOcĉ;wHD‚(J%ѢE QIJJ=ʖ-UVCD%Drr2Nsaڴipss(XCPPի':B?_Z eʔJobƬY0}tё}XÇx w.: 2ΝúuйsgtQt"*޼yWWW~`B%BXYY BJ||<`ddqHJJ .]~ ΢# ņ ͏n"ׯ_aaaXp!DG"76 W^aĉQѲeKر# &M`ѢEPTEJBpp04i": "'|}}ѻwolRt"Rs?~<\+Tg8p .^ŋaÆؾ}; JaÆ߱cЯ_?{쁁<777>J8::KHH#]+V`Ѣ# 8rN<;wbСΝ;޽{6m,۶mCr===@NpMlٲK T*!1rHQ2e Xqpp@dd$<==1|pё >0443-ƣG2:_gG[[J:CCCI^*z!!!P*T : ǁ0d4nXt"Rcqqq͛7b4 z*4iWf͚"""r o߾Ŵi3z v1cƌ"ME#%%/^.: ј4iLMM9 )}˗/acc۷ocY~h%*$^xgYnll>'m۶šCwaٲe---̟?SN-T""" 4Htp$aҤIHLL֭[E!"5[[[DEEaׯHDK D~лwoۣlٲ;`>ke={D^"2}B"w>|GF:uD!"5sÇEϞ=EG*݋}eZv]Ai4L$Ituծ];T,}U"""ЬY3ovߦMJ2E 7n@Æ s,гgOXXX`񈏏GzsN?~۷oL&wAZ E"c1* tttн{wQHC='N) l=|cǎEll,W_DT,X|1{l̙3111hҤ vڅ!CdlRR2O7n zj <)))]6&OQĩPzꜸԩS+lܸQt"RCQQQA||<:6mڈDTl^Mӽ9F OOOqH3f 9W({_ѣGѲeKё(p G\p$aѢJo VjU6#,ܹy'O?D G(J)SߩHL6 صkQ&oرc@4nXt$"!HAAA?8~y&gϲXR <~>(a^x'J*6m8DFnܸc"-- ΝC DG"Mˆ>@TƎ+8 iӧ#>>;v`S0"{{{d2q6" ) +Wfff9tۇaÆagg\`+DÂ($!((Tbbbʕ+c̙ ttt15IQܹXWt 3f@\\|}}.]#P(PjUё -rT*!0fQHC>|{쁥%G!"@hh(a`` .X!@P&&&x%\\\PR%̚5Kt"RW\a``/(,X B"Ф7۶m"""0n8ATX!~keHJJ(9ݻwhҤ8D$؍7`oorʢ#5,DP(СCEG.) ~qH[n2 U&:c0lP 7k,|Mo߆-T*8t1Q.ۓ?޼y0_;vvڅO?akk>}BGXXRSS $66&L ~GqH(;o޼A`` 4h :Q‚?J%ttt8a$bbb{lllk?~s0E#88UVE&DZc׏MJ'O8z(7o.:Q+2$$$ƍԩ(TBƘ3g8D$Htt4Ǝ/_hٲHD%ŋ$ FJ(777x[l]:R簱燶mۊDT۔= zzzh׮(T8q۷oG޽ѬY3qHɓ'سgڷo/:Q;,D BڵEǠ(..NNNX"E!"bccagg`׮]ܹHDwX'::QQQڵ(T͞=/^ʕ+=ݻm۶[n#i ~RX[[ NB%M`` |}}ѳgOhBt"*f ppp;waKt$"&aDT*QlY4jHt*A ###̟?_t"*fptt͛7DqX$ AAA}lx1֮]˦`DLRRp5xzzb#i$~w?={B%ȥKn:o_}8DTp,[ ÇHc`!»e2P%'' Xt8DT޾}I&!44-HDMˆ`)_}ZQT?>> {{{+D`,tuuၗ/_b޼y}hϚ5 pŒ n߾ 6`93.J3===lݺ/^(kIwwwcܹݻ鼽i& >>> ӧO닻wbԩؾ};FFei711jTCTBOO;vEmL<=©SpM=֭?_PP*TcFtt4sMd3*6lu놝;wCDaBڿFunݺrJhM6v(`CCCaPfM^vލkעQFhԨ1w\|/`eeME044Dtt4vڅ,[LKR ooot [GcfÀP~}g쯫ƍ <[lիѩS'ݻWt"NDNy-5 =z􀻻{3jn IDATصkʕ+e_[[1qѭ[7bҥ XZZf`ݻ#66gΜMΝ;x5_Ϡp%''Cwʔ)#:FgΝ;1tPSH ,^)))Xv-@ 1cΜ9///SN|&R`dd^zN!wy"*'=0yd3Ft,7"""`cc9F'˖-CDDe,_\\\ԓHA8^Ѿ}{)$֭[ &qD ~z㫯D Áٳgh0p@)$PZZ<<sjL:qqqXlz!:BLtMt U"Z WWWTZ^^^sDz )$I0447|#:*ڵkb055CD/@ex{{7n&O,:B%IjԨkkk)TInܸ iӦ':^/v܉bsH0,HPT7o!"-"EFFVZ033B`…HKKahatMDDf̘zĉsLDO+)N^^Ν;w}Wt U8Y۷"*˗/cҤI$I<ݏ'66EP+,,+̰d9DTF3f  ID8HtUt U͛7#66'O"*`̘1Epp0lllD'RԩSk.##sEÆ ѷo_9DT?n߾;vEH)JVV\:N ÇX|"*FΝÒ%KЩS'ID8DGGCe :Tt UXlڴ 1EQX?~'ҥ ܁eʕ/PT*x#A ±c0rHXZZ!矘8q"qgHCd}yj֪U0{lAEWj .]FyZl̟mݺ5xPP ;THy1bbboNrrJ`Heggc̘1QNID@\V.]>Ø1cc۶mF@@@UÇc˖-vׯ6l֮]oh֬= ;9wj5':Ibb"-[GGGkNt=C~~>&N7n ZDD Ł9~7̞=ȀodFF/ccc9rf*^{ ޘf͚+++.#B1d 6Lt1,˗/7Ο?/:͛7;+ƍx9u-[z +WCDzN{X\\\p]n5BjՊ田8$I*:^PFFиqc|'s_]wwws;ԬYjՂ,>St$I^:D F^^,Y":%33Ǐb" X;&:*F$IpttB/ʕ+CyQ՘:u*RSSw^~)DDZC )ӕ+WnݺNS_,Y3g`ѢE<wڵCfF/H$bРAS;v ۷/,--E۱cv܉cԨQs؁x7pB>>'>c9DD%R̜92d^}U K.… E'R<|.\4gŋo@=&:;L: Xl-[s~-N*^ٳgh0p@)T* {A=PV-9Dz̙3Bͱa9DD؁֭äItԬY:uBӦMEQISSS.]!ӧOGժU!:Hݾ}&M%=Hg(v`GѼys"""`gg7XgƊ!j999?~<?~pXXXN""*5~#^]!7ojժA!k9s&nܸ͛7^tQ(j`144J*{###Z*(СCPimٲ7n3D=___ĨQФITRX`ee###EϵngΜXG%Aaa!  :aӦM}6f͚%:H#44&L@NDɓ'#99[n/fYD R^=qI|g@ K$s΢S>ĢEP^=|Ǣsٳg7|=zA[lΝ;zj4k ͚5÷~9sm۶x7~6=ܾ+!DJ{=Hݻc7o`bb 6GQn]R6ll2)Dz%-- SL%Dx̘1|*I'NÆ +z~~~󃁁222/,CJJ `ڴiHII?_Wp!'33W^Ç|r4jNNNsZ;rrr333I:7@rrSرcO:uN""F_XZZ{jժ\D#IUAՕ֭[! ;w1rHtUtPXڵk'WXbڷo/#2ѬY3) "QMrPbPTYCNNVZ%:Hbbbn:|?~""MpU <uԁ)0d$$$NtЫW/)b 4nܘWW*Xvv6OKKK!":rekOakkw~͛$_?3rrrzj)D&2{033DDu;̚5 vvv Zݻw駟b֬Y?"""PfMQkl\Zl):Hۇ`3""%aǏܹsVsAXX2GܹsܿElقlw%%% Xp""؁%77j*5k"//8(((@E|\ V1}t ((HtVSҴiS܎;EKT*/BvڅTN!RիW?Ċ+`kk+:H)vFL 2*RRR;w_~H{- ;; Fe˖vر"Œ$ 7ng}FJA ޽w.z?\\\˗/cS@PP]OOO)Du}̜9ضm""؁fΜ1c ""Y&ڷo5jN#ѐe|'2.]5j~8DDe̙3<@hh(LDTnj+k׮3R ڵk':E:u 7n"ڵkN8)Su֢st7n7hРJ4"""X|9,,,0|p)D%K}""QF(,,*Qjj*nܸѣGN{qqq ÀxQx1all!"9X6l :JIRT777)DrJ$&&bÆ CDs5 6LtJBժUѬY3)zڵkѹsg!R'O_EѣG9DD:?ɲp4iDt駟`ll3gN!R{kƦMD,E]aټy3 J R5,IIIwF!:Eݽ{x+!RF"88È^"$I000֮] F*Hxzzr+KRr5 T $SÇf͚nݺsA6m0yd9DD:OQKY5&1 !Iڴi#:Em߾999pwwB(1c̰w^9DDߟ⫯4 V^ [[[899!Ru!)) [l""EPr[/_F^^^,GXT* 1p@)z+,, 6m"Eƍ[nsCKdd$:uFҥKhӦ puԫWRDDQZ5)zkհ_-:H1sss믢sE,zzz{8w  FB[S_P| ./gΜFECۘ?"EPEq)QRҤI4i`ll?*R`jj:NKVBѽ{w)D~z$$$`<)v ipԫWG psX!*''~gozCDxH.==ׯ_'|":E/mܸ&&&?~"R0333رCt^9998q"`nn''z!+RT*aĆ衇b۶mhٲ%E鼍7իR0"J=,W^76m 0 (e˖ֶFD$XXXe˖So\N!yW\uжm[_tR `۶mEoN~!?wOFAA1zh"==2ҵ,~zX[[It NS`jj;w!"+\V={z۷;;;#99$=Xh233`Ȳ\QZ֭[HMMEΝE#66"*7oƕ+WKKK9DDzK .\%>>ğx"fTZ:Ji&`ȑStիWf;E,%HOOSXI˻ ޽{K.֨$IBQ~})zʇFy`bb¥`DDpKABB¿Su]v}Jh7xCtf{o>? .+":X`` vcׯ_T,XJPfbddd=_7n/1233YYYR J_rK_!;;ݺuwٞeffbҥhذ!ƌ#:\>}ЧO'[jfϞ-H9$Z¥Khxcz]GEҥK¬Y*_4I`hhAN+lOT>~'" @t ^~~~ D~ߴiжmb ǎ{1Y1qDC9DDT,Tn$I8;; .{쁹9>#)D:eڵPؼy""z,TnT*W;DWGahٲ"@tܙKXt*,#""͛77YXn""*,T.ɓ*ў={`aa{$I8uKKK9DDT X\HCCC~_I dXZZbsx1HԨQ֢SѣG 8W1DD: ֭[N;,,,СC)D:!//+V@z0d9DDTB/->>=B޽EZAt غu+߿)DDTFB/MR}$IBNNz):H'ahݺ5ڷo/:ʈ HԪU fffSBPPLMMOt NXf yH""Ł^J^^Ν;w}Wt^eCzi^={K.-'z)(((_-:E/矸y&:w,:H',[ Xv""zAXHtUt^8x 1p@)DZ/&&>|8U&:^z)S'UVZC7Q)Z ?""z I/,++ W\AǎE腴4={Btt41j(""]Ɓ^Xtt4dYM*IXXdY~!eVBժUw߉!"ā^$I033 a$,, h޼"Rqq*^Xxx8 $,#887BdY/U3f!"r^ݻwq-tIt^pgN!j8vvv=z _DDTZX4 $Iś:u*uV)D˿83]r֭Eۻw/ۇAQFs]jj*?PDEE-3/""* ,L044ĠAD(ֽ{0i$`ʔ)sMbb"x ݺuJ =$IEBϞ=lٲ4Nh4xbѐCCCnnnhذL""AXXjgΜ~(:Erssѯ_?\t ^^^pppDTfN=zHOO14h)S`ܸqIDD: +..ׯYf?DTjyyy8}4\TRM6ԩS 333љDD XX* ٳE),,ȑ#q1L0{D\8y$BCCZ 899zF""0XX]6h憽{΢)99h?Jll,dYF5ЩS';;vHDDzF)>ą xuɲٳg}$'Ȳ+W ,, 믿```hѢL""CX)gϞFE(7֬YΝ;c٢sDܹs8z(BBB###ԭ[cǎń PNљDD8S$I)>c)zj,ZڵŋE琞SՈBhh(BBBcȑ5jU&:zJDDիM`֭5kf9P=zd-Z`С?DFFժUC0f|駢ʌ =A$u֢Stӧ1h X[[#00KmB",, 8{,dY+.]D""ORpk3tVLL ޽梓Hn޼Yi… 0005틉'a""R,THIID˗/G044D`` ,--E'BȲȑ#z* Qvm 6IDDT!8PIw`/@ԪUKt8YqE"88n*Gʄ  љDDD $ իWG Dd|Ɂ?D'e.\#Gp!5Œ30vX^#""ÁpppSѽ{w$1ϟǑ#Gpa#FL"""a8իxK):#++ =z@RRV\ɓը4 Ν;W4M4ɓ1|p$"" XR```N ׯ.]///o^tiB $$abbf͚a6l""bp`!@dd$`mm-:EcƬY矋N"-UPP9r̄)7o :!""zSj5y 1rH;v &L@޽E')((@tt4BBB-Z ! IǣG94 ܰw^8;;g*9r٨R Zh#F`044IDD8T*D~ IDATзo_)ZKe̞=۷/\]]E'`8{,>\t%J*pttĈ#Я_?)DDD !""666[oooY;wٳE qqq8|0:J*hٲ%F޽{sH!""*gX\^^_NZWƢEо}{,^XtU2YÇwLLLyaR*=B 0@tVںu+f͚VZaբsȲ+W BJJJ}RMn'""$|s$ĄGcϞ=puu믿M6ΡJ`8pn݂17nco版"""Pn].i`1uG \~FFFhРf͚Bt"^㧰Rĉaggsss899aǎ;wGWLMMacc޽{#>>/33:v(:E:u 5vͥ? _}֬YL< i8i~+^z!::hڴ)0`h4~,_k&MΝ;X`ڵkHhѢ)Y1d$&&v%@ P8pW_}cǎŔ)SPfMDDDT,l۶ |HJJ;B탍}hР|||W%QT033;#C[\t _}KKKI?~SN8q `ee`hذD"""z,ϱgT^*:;;c$ ڵ+g;@ZPn]ܺuBz"<<5ѭ[7`׮]U$zA\TZ~)[oN$""2.\SWQXs5$&&GYV)))}6&L C$''/@NNagg':He\t ā*U7߄t":^HOO믿EϗVAA\\\PzuL4_J޽{޽;W֤nݺ`y&Ѽys̝;7t$""R,D`G```wss{.]k׮/jժq/{骬,IIIXr%Zn-:J!;;G޽{ kâ,>gXAC74 $Z45SsPLpAR^׺*@;bȢ_d&]PDasDx~K^~3wwy{йsgaΜ9($M6]tIh&,Oaccī(ןF___#&&5~x`kH cP\\ dggoEVT*t<|6665k͛ňɓ1yd+V ((H&,Oѻwo$&&B^rIc={6OOz&rrr_aرR"2̘1F`` F)uHT .Fjj*ܹsss 4AAApqq:<"""jLX k׮Err2<<<ѰG߾}l[qe%::k̙֬3"RTdW}aΜ9xwSPP;v`˖-ߵϥÃϥ53LXbԨQ>|8>cܽ{ݻwGbb"vڅxd2Yt(pttDff-ZH/J=\FO?Ejj*|||#uH>āuVsXZZJ"I K (( ,@AA^z%_^犋FFB[m6d2DEE!**JϮ]"''ZJ믿cKI RD-[`˖-{.,--{RGDDD K XXX`ҥXtiu  N! qYMPTXXVZ#F7c׮]شiN< ccc˘;wn}Ƅ̄L"u( fʕ Eh"i8y$6oތ;vüyxU K3 lRPĺu޽{cʕRܹs۷oGrr2._ SSS ,@>}&,HII ;lݼy3hi6BRRҠhбcG,X~~~055:D"""jD4#ǏZnڵ gFǎ~znݻ۷c|20b|ѣQ#ńQT011q^|BxyyIJ|2ƏZ7VꐚSN!>>;wL&C^_cȐ!RFDDDMfBTEׯԡݍ70vX!..R$jcݺu8y$Zh1c ,,瘈 f"##]t: χ+vZ888HRw=lڴ C6mc޼yܒf 77W^,u(zUXX777\r?|$$$ 11%%%֭0i$C#""f K3RGpwwGvv6BBBпCj]Xl޼ ÙA` T*XXX_:(++Ì3paR(?QQQعs'0p@,]I:HDDD&N&Mjgƾ}ەjիg =&,Mܕ+WٳgKJi4|Ӥnqk/^ի{n/F˖-JLX8R LC!KRq\v킉 N%K0Q!""F KT*ѺukkNP$44Vѣ(u8BAA֬Y$cԡ&J...RR'+V@XX 1x<@||<"""C;Xf Q!""F Kv9ܿRRk 3VX!u8MݻwcѢE}6d6\ "" KR 1}tC|ѣ ~CuVREDDDTgLXLX[[7gv ___#11r\ Rii)֬YB̛7͓:,""""aD!++ C :gvAxyy064}cǎa?0`J갈'N RL-["%%fffRdpʰ|r[رc^0aiJ%1qDClL8HIIiշK.aܹp8JQMԡCжmFs;˗1~xjlذ[>)SڵkXv-Q8>3)**™3gJJܸqcǎEQQбcGC2(XlbbbcϞ=:,""" ʂF3ꊼ<]RdP>#8psEBB"""jvx @Ν mqq1ݑP_ Jqq1>#9sK.{'uHDDDD0OT+tAJii)<==qaRdP]9s̙3Q+,MJx{{KHj5fϞ&M:$qDDD`o0}t""""&FRe˖ptt:J4 m6lR8qؿ?LLL0rH,Y:t:4"""f K#W\\'Obĉ >vaa!&LWbٲeprrjCQQQ8z(0c 6r F.++ ӧOoqg"44kZnM|Ej DDDD᧰FNTNYZZ OOO9rAAA>|x]CnMLDDD$1&,ܡC`oo`j5fϞ# @ݻذa֭[wsΈjDDDD0aiܹ .`̙ 2F?mۆYfkq֭[ڭ/"!!oԡc4bۻB 00 _o999mo.]ʭ FLT...>VHHV^1c 00ӧ'N ** 탉 Krkb"""F K#nݺ8˗/ǢE[oᆱACTT`ffOOOuRGDDDD5Ąqn޼)S81113/_^cZݻ .pkb"""F)R 1RRR=z@P8PRR[BP?DDDDMFJR]tw ___t ݻHJJBll,޽N:!""'O:4""""&,ݭ<///`ƍy+Unn.␔2 o-uhDDDDGIŋ믿0~x})))033uq%G^$FHTB&K9snnn066ƦM`iiԩSľ}`llaÆaɒ%:4""""GLX!R +++X[[ϜBV#99Y}Vŭo8r0m4rkb"""f K#VRoׯcܸq(**B||<:v쨷kCV#-- aii T؈a1aidN>L4I/Dom 55 7oބ |'K/&,J<<>5nLXCC1K@$&&~~~jٳ8<,-- pkb""""1&,Daa!Ο?OOZzj=zJJJ?#**[Q1ai$> !f̘mG,^oBBB!&NJJBllvk~ SL񈈈y`H(J=7GGGcpvvף[GƐ!C>5?LXCK.&99}zBx*&NMM...Xd zqycڵk?:uBbbޞ9}4 ### <ܹ^'""""zF@TfΜYlllqFmؚ8** Zhwww,Z[Qb(JXZZGOwwwXZZ"%%fff\5s`aaO> .DDDD 8!222j9s&L16mKKZYZZ ׯ_5+̙3[Qbb._|ֻt\]]Q^^dX[[?XCrr2bbb_WԩSk>Q0a1p* 2 Uֹ~:Ǝ"ǣcǎ4F^^~z [䘰LnvvvO|=??Gdd$w^㾯\XlݺB+DDDDd0r(JO|&LիWl2899ը3g@P -- xtR< Θlcĉ^>&Os!44/!J%"##[O</DDDDd0J\^Rxzz"++ 6lX}#==ڭ?c|Wܚ  j5f͚ nnnOl[ZZm۶!** ׯ_G6m`pkb""""j4G\=h41{l{i&s:v숕+Wb :^0a1`>A DBB<<<Cn~~>ݚxڵ.FDDDDd蘰0ccc?wa3f u^XlٲB8;;#<<RMDDDD7|){{{6lQ\x{{߿?kum" =z􀧧'Mg~!+ Tchժu}||p (jS_IDATf̘J7o>uUVK"Ν[nav˜Q+,8u^zJWQOO:AU*m_@"|)''62>{gehgOmڰ~?GV`M[&,ո}6*[[[k_JAA޳ ܽ{aaa QDճgOCfSNR@͐UZŤq/++{ɘU>=j9zTC;uι$L8:u)Oϵ)E6mĚ5kľ}d"!!v%%%Q<"!!A' ~MxѩS'$JKK5Ĝ4hpppJRܹsyhdj;+Ĉ#ӅL&111Ouk=so߾b"**JIIIwޢUV:u==۾}db:#Fʶ+V2LdffjjxE߾}uQ !ĪUt44Ԝ4hprro(ei4>\Gsw\B]\nnn*2d9nܸS_GGߚ̹Gpyu:\뚷9;;Jeر#m׺a¢gNK/3逿9P彋m{]N*VNC}ι3g_pmڴ)52us2u!]uxu= 8Rn߾ J׫RPPW]ۊ?[4Ĝwy^^^իJKKc,Z޽{u̹g>\ZG9VUVtxZ7&,MS ,}ҥ &H5G\稾p#}h45k222 {{Z7g666Ŏ W׶^um+nucPs*P}e=8\皟wUZkߘY޽ FS~IcmpĉJ号ՍAMOC9Ge9z\C;Gu !0{lDGG#22R>k]0a3777!99Y<:::1=ٳgRejqqqx7Ѿ}{=郸8233qyL4IGE!\Ubcc 5us5u*\뚧̹++Xf fΜz\jH #FkkkvZ/zzTKv-܄8p&&&bҤIb">>^tY[5رa9w1i$+/v%>3abb" ֠JsN!6n(6n(„L&~~~ڲGqZG2L̚5KdffCitZtLXAQQOED-+"6lؠS[rq[n3g ann./qv-'ͅyyyv\d{bԨQcǎD gggŴ˜d\qGZGڵ<{[nZW=V$"""""2L| """""2XLX`1a!"""""ń """""2XLXHBB~Ic\.իWd<\Vm\9Zp!_~غv.0a!"j Xta48L&uUEfffVlݺϯKhDDR@DԜ(..F˖-aoo_Uεt ܼy^^^h߾=LLL`ee}"-- 0x`/|2rBPP^{5j fffի+ӵkW?+^}UK.+Ā`nn{{{ÇcȐ!):w ???ܽ{W7ZjSNaĈhݺ5 {.|}}akkVZa8|ٳg1j(XXX1ݻĺiii:t({9loӵoݺr{vՐ8y$'V퍕+WB~Vj׵kW{U̘1ڵӾK,B[b~_’%KЭ[7{$"jJxHL/"44/"ݻÇj*|͛+ǜ9sн{w! H"LǏ#00h۶-֬YO?/F 8s ^z!)) fffXr%+}5L4 077ǹsJ9s`…())L8* }^}U:tƍѹu ֭[CPm۶HHH_qqq9s&N$᧟~ȑ#sN;7nڶmh :TBk'''sc(..Frr-e۷hyyy߿?ߣK.ؾ}; \x+VЉaŊxWO?A 88&L@NNlmmkt^ ADDufjj*j;Vt}akkZ.]u떶LV ;;;-2eo֖i4"rrh4Ç"##Cd2q k3g2L_^͎;L&:K,2L|W_~)Ĺst]]]L&Bq}amm-LR)>}}jGlRܽ{W[v!Ċ+e+d2YUw>Tٶk׮Gy\.'Oԩ \.Ο?/ҥKB&7xCDžL&UJDT0""=ӧ""" RgjaÆ 055E`` Wimj722BϞ=qum޽{1l0X[[kd2&Os `СvVGd2L8QV)SO:FǾw^^) ܹs^^^Pڟr9sp矕ܳşY\ QxH:v숏>#Gӧ-Z@iiiv +))uj !C7n"k׮}bOwۯ{u;vҮb0`W_}?Ǵi`ffBht #F6g9Wcǎ!;;[=2dS "jx 1zhxxx-Z#G믿M[wؼy3L_ƍêU0}t̞=ŋ!ɞxE* Fjj*F +WDAAN?>,--R1*1o6p} 335; QQQ3f [.aǏשgii(((q=zyyyXls=777( /xj,r>z Xx1 \gggT:O}bcc1f|7ԩv؁p|'pppѹ""j${ܟ(--|ptt-[&&&A<ֻspwwmڴr\rk+WݺuAJ;zuU?R C )fffC/k׮}믿.LMME۶m| =*d2Zz9(,,fmڴbȑܹs5%L!ň#"55Ur.a8 ƍ'lllh۶5jذaC~w-d2… ^_p,磬Lmjϊ.aBqU)lmmx饗Ŀ/:=^.$"jjdBBDDDDD ,&,DDDDDdbBDDDDD ,&,DDDDDdbBDDDDD ,&,DDDDDdbBDDDDD ,&,DDDDDdbBDDDDD ,&,DDDDDdbBDDDDD ,&,DDDDDdqmTBIENDB`cvxopt-1.1.4/doc/source/floorplan.png0000644000175000017500000002154611674452555016663 0ustar sonnesonnePNG  IHDR,d(sBIT|d pHYsaa?i IDATx_lqEB:J"zcD;ђݜw &&bBT0d] mԠfMAz{F.1& B~noLTu]Ǚ/J^JV@BJ&HKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  JRzЄjZ ʱ(яM$K˼c+0:\%X `,@ZHKi  -%X `,@ZHKi  -%X `j)=2T*'je0 |h@W>WqI`,@ZHKi  -ok\?;̼fy> PK0s7@pI`,@ZHKi  - wwuW)i (O?ݻwM7TM 닮;=m[cǏKOHO~:mK,)= =sh׮]|KO -@#Gċ/Xz @,0㩧M6 7j5""Ο?j5ZZZLt ́cpp0{'g) /so_̕Z{//. 's`+1o޼XzuUy0(̓`vg%X `fPqq]w9̨O?4v7t7`fT___tuuŝwZ `>|8?۷o/=hOǶmbɒ% B3b׮]|KOHK@#Gċ/Xz ` pU㩧M6 7j5""Ο?j5ZZZLN LMM188s=\<rqI`,@ZHKi  -%X `,@ZHKi  -%X `j)=ft xT䓈)###122J%>7|s\^8_We/kVz׀f…_"V^-o188gϞXvmkz߫V>`y @b~__|E9XtuuXIWM\)$pLOOǟXbE?(=:#Xr 8P~_Ǐ~Xre?'N`Q @5/ \u{?wk{~ğΝEO~+W,=:$X_F{c`` c||<[+}~F]V,G}4}3h noNSSS144.\@sq !׀OrKU ^0 @BRo"Xr 8|=,@ZHKi  -] Gƙ3gbzz:"">u5\Sr,Ν;O>r?22###QTq7^0{ $kP{X `,@Znݻw˗/)=(@iThkk7ҥK̙3oD___v8qD:tH@r u]WzP`ҩjq…V1<<G|,ǡC""bOĦM J,@:Nz+gϞ[1lٲXlYDDY&͛/,YRxͤ'XPit~{|111!X3ZB= ;Ϗ[o`  ;w… #-ZSSSoƫ?p,^D`  +WpKqk=c 6Ć JH -%XR*J o WGK+=<\q(%a@Zΰ m||`YwpIСC1x'bӦMWEM7zzzԩS[oŞ={ٳuӀo!XlٲXlYDDY&͛/,YRxM4o=˘(=hJǎǭZz -\4;w… #-ZSSSoƫ?p,^D[\2㥗^ӧOǵ^ׯ/=hh6l 6|Oa,@ZH=,4wy'^~bbb"Z[[#6o\49B>,z8w\ƻ[zqL3,4۷_֮]{o f͚Bca? ,n-&&& ,Ӏf'Xh j5>hkk+=9DvgϞScL o޽/XbE9W1 h6o߾8p@<pUӀf$XhX틁xG)=8JА͛7ǖ-[J*i@3`}{xg f`iccc'$!!ۍ7Z{//.  ,}W^yի fw ^^ |7Ե;vh,,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZH(azz:b||u5\SrM?~_EkkktttĖ-[\=xqΝ;O>r?22###QTq7^H3YpaիWǢEo[ Foooٳ'֮][z"@]P,4^{?jժ ʩSbǎ166Ǐo~oJOxx @R,׿_|Qz̘>,ϟ7FDl۶m;VZׯҥKg-=:9m'O8p@E4?1X`AI\gX?ϱbŊ~Pz o\Pq _(V\?ĉ188㷿my,\5=,+//7O~ӟܹshѢObʕQX ɓuxJ޼T^j< G}4}3`ax&4G"XLf`ѣG̙31==}QDDĺuk)9HDsnΝ'DW&HT*8|p|ͅY`νk'u“ax޽;>㘜X|yDOOOy ,@]V7nKƙ3g7ވ8yd ԕck׮'NġC 4 +=KZ-.\j5ѣ0u?:Ϗ'x"6mTx0 Pz{{'N:oVٳ'Ξ=-= f\ggg .-[,-[k֬y%K^3VP{XpǗ_~3H رc1[KOfK€sXpatttĢEbjj*|xWŋ ԕ+WpKqk=c3LueÆ aÆ39 -gX*J x+l`o066Vz\$ HKi  -%X `,@ZHKi  -Rz9ݻ?hii˗GOOOG,\RZظqc,]4Μ9oFɓ'D`뢏]6N8, pEh"oU… QVcxx8=>`Y4 СC1x'bӦMW, ߪ7zzzԩS[oŞ={ٳuholٲXlYDDY&͛/,YRxN4&rǗ_~Y'X\V+=h2ǎǭZz M@pI;w FGGG,Z(7ߌW_}5~Xxq4%\2㥗^ӧOǵ^ׯ/=&!X9;/|ALLLDkkkttt͛ݗ̆ bÆ g<8SCCCgC=ΝxwKqS۷o믿]6xb͚59̩ m j~a$㒰:WTJOx0vgϞSdK+=&{ٰwxcŊɸ$ (f߾}qx'(=HHE۷/Gy )̹>bͱe˖s̩xu;:: -2,:rHT*ы>WTرc `N8pHKi$;/|ALLLDkkkttt͛= gXhJCCCgC=ΝxwKa)m߾=>vڸ{^5kZr`bbb".E?TA?ڵ+Ξ="b޽/XbE9`۷/8O>d<`KqIDAT/ Mm߾}100?x<#o M矏ؼyslٲ.sXhJsw֭wttZ,4#GDRsJ%;VhJД8Pz=,@ZHKi  -%X1Yz4<=j)$ HKi  -%X `,@ZH˓Tggg  @j'eqI`,@Z ST*umiR5]!^7xǝzv%z?Ǎue;MuYޤg+0 -%X `,@Z8Fzr,[Gi$ HKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi  -%X `,@ZHKi    IENDB`cvxopt-1.1.4/doc/source/.templates/0000755000175000017500000000000011674452555016225 5ustar sonnesonnecvxopt-1.1.4/doc/build/0000755000175000017500000000000011705741762013744 5ustar sonnesonnecvxopt-1.1.4/INSTALL0000644000175000017500000000556011674452555013143 0ustar sonnesonneInstallation instructions for CVXOPT Version 1.1.4. The package requires version 2.7 or newer of Python, and is built from source, so the header files and libraries for Python must be installed, as well as the core binaries. The installation requires either ATLAS or BLAS + LAPACK. Using architecture optimized ATLAS libraries is recommended and gives a large performance improvement over standard BLAS & LAPACK libraries. Both header files and libraries must be installed. The following software libraries are optional. 1) The GNU Scientific Library GSL (www.gnu.org/software/gsl). 2) FFTW (www.fftw.org) is a C library for discrete Fourier transforms. 3) GLPK (www.gnu.org/software/glpk/glpk.html) is a linear programming package. 4) MOSEK version 6 (www.mosek.com) is a commercial library of convex optimization solvers. 5) DSDP5.8 (www-unix.mcs.anl.gov/DSDP) is a semidefinite programming solver. Configuration script: --------------------- Edit src/setup.py and update the following variables: - ATLAS_LIB_DIR: the directory containing the LAPACK and BLAS libraries. - BUILD_GSL: set this variable to 1 if you would like to use the GSL random number generators for constructing random matrices in CVXOPT. If BULD_GSL is 0, the Python random number generators will be used instead. - GSL_LIB_DIR: the directory containing libgsl. - GSL_iNC_DIR: the directory containing the GSL header files. - BUILD_FFTW: set this variable to 1 to install the cvxopt.fftw module, which is an interface to FFTW. - FFTW_LIB_DIR: the directory containing libfftw3. - FFTW_INC_DIR: the directory containing fftw.h. - BUILD_GLPK: set this variable to 1 to enable support for the linear programming solver GLPK. - GLPK_LIB_DIR: the directory containing libglpk. - GLPK_INC_DIR: the directory containing glpk.h. - BUILD_DSDP: set this variable to 1 to enable support for the semidefinite programming solver DSDP. - DSDP_LIB_DIR: the directory containing libdsdp. - DSDP_INC_DIR: the directory containing dsdp5.h. Support for the linear, second-order cone, and quadratic programming solvers in MOSEK is automatically enabled if the MOSEK Python interface pymosek.so is found in the user's PYTHONPATH. Compilation: ------------ CVXOPT can be installed globally (for all users on a UNIX system) by writing: python setup.py install It can also be installed locally in the home directory by typing: python setup.py install --home=~ This will install the libraries in /home/username/lib/python. In this case PYTHONPATH must be updated, e.g., under Bash write export PYTHONPATH = $PYTHONPATH:/home/username/lib/python Test it: -------- To test that the installation was successful, go to the examples directory and try one of the examples, for example, $ cd examples/doc/chap8 $ python lp.py If Python does not issue an error message installation was successful. cvxopt-1.1.4/src/0000755000175000017500000000000011674452555012673 5ustar sonnesonnecvxopt-1.1.4/src/python/0000755000175000017500000000000011674452555014214 5ustar sonnesonnecvxopt-1.1.4/src/python/printing.py0000644000175000017500000001250111674452555016417 0ustar sonnesonne# Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . options = {'dformat' : '% .2e', 'iformat' : '% i', 'width' : 7, 'height' : -1} def matrix_str_default(X): from sys import maxsize from cvxopt.printing import options width, height = options['width'], options['height'] iformat, dformat = options['iformat'], options['dformat'] sgn = ['-','+'] if X.typecode == 'i': fmt = iformat else: fmt = dformat s = "" m, n = X.size if width < 0: width = maxsize if height < 0: height = maxsize if width*height is 0: return "" if len(X) is 0: return "" rlist = range(0,min(m,height)) clist = range(0,min(n,width)) if X.typecode == 'z': twidth = max([ len(fmt % X[i,j].real + sgn[X[i,j].imag>0] + 'j' + \ (fmt % abs(X[i,j].imag)).lstrip() ) \ for i in rlist for j in clist ]) else: twidth = max([ len(fmt % X[i,j]) for i in rlist for j in clist ]) for i in rlist: s += '[' for j in clist: if X.typecode == 'z': s += format(fmt % X[i,j].real + sgn[X[i,j].imag>0] + 'j' +\ (fmt % abs(X[i,j].imag)).lstrip(), '>%i' %twidth) else: s += format(fmt % X[i,j], '>%i' %twidth) s += ' ' if width < n: s += '... ]\n' else: s = s[:-1] + ']\n' if height < m: s += "[" + min(n,width)*(center(':',twidth)+' ') if width < n: s += ' ]\n' else: s = s[:-1] + ']\n' return s def matrix_repr_default(X): return "<%ix%i matrix, tc='%c'>" %(X.size[0],X.size[1],X.typecode) def spmatrix_str_default(X): from sys import maxsize from cvxopt.printing import options width, height = options['width'], options['height'] iformat, dformat = options['iformat'], options['dformat'] sgn = ['-','+'] if X.typecode == 'i': fmt = iformat else: fmt = dformat s = "" m, n = X.size if width < 0: width = maxsize if height < 0: height = maxsize if width*height is 0: return "" rlist = range(0,min(m,height)) clist = range(0,min(n,width)) Xr = X[:min(m,height),:min(n,width)] Idx = list(zip(*(Xr.I,Xr.J))) if len(Idx) > 0: if X.typecode == 'z': twidth = max([ len(fmt % X[i,j].real + sgn[X[i,j].imag>0] + 'j' + \ (fmt % abs(X[i,j].imag)).lstrip() ) \ for i in rlist for j in clist ]) else: twidth = max([ len(fmt % X[i,j]) for i in rlist for j in clist ]) else: twidth = 1 for i in rlist: s += '[' for j in clist: if (i,j) in Idx: if X.typecode == 'z': s += format(fmt % X[i,j].real + sgn[X[i,j].imag>0] + 'j' + \ (fmt % abs(X[i,j].imag)).lstrip(), '>%i' %twidth) else: s += format(fmt % X[i,j], '>%i' %twidth) else: s += format(0, '^%i' %twidth) s += ' ' if width < n: s += '... ]\n' else: s = s[:-1] + "]\n" if height < m: s += "[" + min(n,width)*(format(':', '^%i' %twidth)+' ') if width < n: s += ' ]\n' else: s = s[:-1] + ']\n' return s def spmatrix_str_triplet(X): from cvxopt.printing import options iformat, dformat = options['iformat'], options['dformat'] sgn = ['-','+'] if X.typecode == 'i': fmt = iformat else: fmt = dformat s = "" if len(X) > 0: if X.typecode == 'z': twidth = max([ len(fmt % Xk.real + sgn[Xk.imag>0] + 'j' + \ (fmt % abs(Xk.imag)).lstrip() ) \ for Xk in X.V ]) else: twidth = max([ len(fmt % Xk) for Xk in X.V ]) imax = max([ len(str(i)) for i in X.I ]) jmax = max([ len(str(j)) for j in X.J ]) else: twidth = 0 for k in range(len(X)): s += "(" s += format(X.I[k], '>%i' %imax) + "," + \ format(X.J[k], '>%i' %jmax) s += ") " if X.typecode=='z': s += format(fmt % X.V[k].real + sgn[X.V[k].imag>0] + 'j' + \ (fmt % abs(X.V[k].imag)).lstrip(), '>%i' %twidth) else: s += format(fmt % X.V[k], '>%i' %twidth) s += "\n" return s def spmatrix_repr_default(X): return "<%ix%i sparse matrix, tc='%c', nnz=%i>" \ %(X.size[0],X.size[1],X.typecode,len(X.V)) cvxopt-1.1.4/src/python/cvxprog.py0000644000175000017500000024371611674452555016273 0ustar sonnesonne""" Convex programming solver. A primal-dual interior-point solver written in Python and interfaces for quadratic and geometric programming. Also includes an interface to the quadratic programming solver from MOSEK. """ # Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . __all__ = [] options = {} def cpl(c, F, G = None, h = None, dims = None, A = None, b = None, kktsolver = None, xnewcopy = None, xdot = None, xaxpy = None, xscal = None, ynewcopy = None, ydot = None, yaxpy = None, yscal = None): """ Solves a convex optimization problem with a linear objective minimize c'*x subject to f(x) <= 0 G*x <= h A*x = b. f is vector valued, convex and twice differentiable. The linear inequalities are with respect to a cone C defined as the Cartesian product of N + M + 1 cones: C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}. The first cone C_0 is the nonnegative orthant of dimension ml. The next N cones are second order cones of dimension mq[0], ..., mq[N-1]. The second order cone of dimension m is defined as { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }. The next M cones are positive semidefinite cones of order ms[0], ..., ms[M-1] >= 0. Input arguments (basic usage). c is a dense 'd' matrix of size (n,1). F is a function that handles the following arguments. F() returns a tuple (mnl, x0). mnl is the number of nonlinear inequality constraints. x0 is a point in the domain of f. F(x) returns a tuple (f, Df). f is a dense 'd' matrix of size (mnl, 1) containing f(x). Df is a dense or sparse 'd' matrix of size (mnl, n), containing the derivatives of f at x: Df[k,:] is the transpose of the gradient of fk at x. If x is not in dom f, F(x) returns None or (None, None). F(x, z) with z a positive 'd' matrix of size (mnl,1), returns a tuple (f, Df, H). f and Df are defined as above. H is a dense or sparse 'd' matrix of size (n,n). The lower triangular part of H contains the lower triangular part of sum_k z[k] * Hk where Hk is the Hessian of fk at x. If F is called with two arguments, it can be assumed that x is dom f. If Df and H are returned as sparse matrices, their sparsity patterns must be the same for each call to F(x) or F(x,z). dims is a dictionary with the dimensions of the components of C. It has three fields. - dims['l'] = ml, the dimension of the nonnegative orthant C_0. (ml >= 0.) - dims['q'] = mq = [ mq[0], mq[1], ..., mq[N-1] ], a list of N integers with the dimensions of the second order cones C_1, ..., C_N. (N >= 0 and mq[k] >= 1.) - dims['s'] = ms = [ ms[0], ms[1], ..., ms[M-1] ], a list of M integers with the orders of the semidefinite cones C_{N+1}, ..., C_{N+M}. (M >= 0 and ms[k] >= 0.) The default value of dims is {'l': G.size[0], 'q': [], 's': []}. G is a dense or sparse 'd' matrix of size (K,n), where K = ml + mq[0] + ... + mq[N-1] + ms[0]**2 + ... + ms[M-1]**2. Each column of G describes a vector v = ( v_0, v_1, ..., v_N, vec(v_{N+1}), ..., vec(v_{N+M}) ) in V = R^ml x R^mq[0] x ... x R^mq[N-1] x S^ms[0] x ... x S^ms[M-1] stored as a column vector [ v_0; v_1; ...; v_N; vec(v_{N+1}); ...; vec(v_{N+M}) ]. Here, if u is a symmetric matrix of order m, then vec(u) is the matrix u stored in column major order as a vector of length m**2. We use BLAS unpacked 'L' storage, i.e., the entries in vec(u) corresponding to the strictly upper triangular entries of u are not referenced. h is a dense 'd' matrix of size (K,1), representing a vector in V, in the same format as the columns of G. A is a dense or sparse 'd' matrix of size (p,n). The default value is a sparse 'd' matrix of size (0,n). b is a dense 'd' matrix of size (p,1). The default value is a dense 'd' matrix of size (0,1). It is assumed that rank(A) = p and rank([H; A; Df; G]) = n at all x in dom f. The other arguments are normally not needed. They make it possible to exploit certain types of structure, as described further below. Output arguments. Returns a dictionary with keys 'status', 'x', 'snl', 'sl', 'znl', 'zl', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack'. The 'status' field has values 'optimal' or 'unknown'. If status is 'optimal', x, snl, sl, y, znl, zl are an approximate solution of the primal and dual optimality conditions f(x) + snl = 0, G*x + sl = h, A*x = b Df(x)'*znl + G'*zl + A'*y + c = 0 snl >= 0, znl >= 0, sl >= 0, zl >= 0 snl'*znl + sl'* zl = 0. If status is 'unknown', x, snl, sl, y, znl, zl are the last iterates before termination. They satisfy snl > 0, znl > 0, sl > 0, zl > 0, but are not necessarily feasible. The values of the other fields are defined as follows. - 'primal objective': the primal objective c'*x. - 'dual objective': the dual objective L(x,y,znl,zl) = c'*x + znl'*f(x) + zl'*(G*x-h) + y'*(A*x-b). - 'gap': the duality gap snl'*znl + sl'*zl. - 'relative gap': the relative gap, defined as gap / -primal objective if the primal objective is negative, gap / dual objective if the dual objective is positive, and None otherwise. - 'primal infeasibility': the residual in the primal constraints, defined as || (f(x) + snl, G*x + sl - h, A*x-b) ||_2 divided by max(1, || (f(x0) + 1, G*x0 + 1 - h, A*x0 - b) ||_2 ) where x0 is the point returned by F(). - 'dual infeasibility': the residual in the dual constraints, defined as || c + Df(x)'*znl + G'*zl + A'*y ||_2 divided by max(1, || c + Df(x0)'*1 + G'*1 ||_2 ). - 'primal slack': the smallest primal slack, min( min_k sl_k, sup {t | sl >= te} ) where e = ( e_0, e_1, ..., e_N, e_{N+1}, ..., e_{M+N} ) is the identity vector in C. e_0 is an ml-vector of ones, e_k, k = 1,..., N, is the unit vector (1,0,...,0) of length mq[k], and e_k = vec(I) where I is the identity matrix of order ms[k]. - 'dual slack': the smallest dual slack, min( min_k zl_k, sup {t | zl >= te} ). If the exit status is 'optimal', then the primal and dual infeasibilities are guaranteed to be less than solvers.options['feastol'] (default 1e-7). The gap is less than solvers.options['abstol'] (default 1e-7) or the relative gap is less than solvers.options['reltol'] (defaults 1e-6). Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, snl, sl, znl, zl are close to optimal. Advanced usage. Three mechanisms are provided to express problem structure. 1. The user can provide a customized routine for solving linear equations ('KKT systems') [ sum_k zk*Hk(x) A' GG' ] [ ux ] [ bx ] [ A 0 0 ] [ uy ] = [ by ] [ GG 0 -W'*W ] [ uz ] [ bz ] where GG = [ Df(x); G ], uz = (uznl, uzl), bz = (bznl, bzl). z is a positive vector of length mnl and x is a point in the domain of f. W is a scaling matrix, i.e., a block diagonal mapping W*u = ( Wnl*unl, W0*u_0, ..., W_{N+M}*u_{N+M} ) defined as follows. - For the nonlinear block (Wnl): Wnl = diag(dnl), with dnl a positive vector of length mnl. - For the 'l' block (W_0): W_0 = diag(d), with d a positive vector of length ml. - For the 'q' blocks (W_{k+1}, k = 0, ..., N-1): W_{k+1} = beta_k * ( 2 * v_k * v_k' - J ) where beta_k is a positive scalar, v_k is a vector in R^mq[k] with v_k[0] > 0 and v_k'*J*v_k = 1, and J = [1, 0; 0, -I]. - For the 's' blocks (W_{k+N}, k = 0, ..., M-1): W_k * u = vec(r_k' * mat(u) * r_k) where r_k is a nonsingular matrix of order ms[k], and mat(x) is the inverse of the vec operation. The optional argument kktsolver is a Python function that will be called as g = kktsolver(x, z, W). W is a dictionary that contains the parameters of the scaling: - W['dnl'] is a positive 'd' matrix of size (mnl, 1). - W['dnli'] is a positive 'd' matrix with the elementwise inverse of W['dnl']. - W['d'] is a positive 'd' matrix of size (ml, 1). - W['di'] is a positive 'd' matrix with the elementwise inverse of W['d']. - W['beta'] is a list [ beta_0, ..., beta_{N-1} ] - W['v'] is a list [ v_0, ..., v_{N-1} ] - W['r'] is a list [ r_0, ..., r_{M-1} ] - W['rti'] is a list [ rti_0, ..., rti_{M-1} ], with rti_k the inverse of the transpose of r_k. The call g = kktsolver(x, z, W) should return a function g that solves the KKT system by g(x, y, z). On entry, x, y, z contain the righthand side bx, by, bz. On exit, they contain the solution, with uz scaled: W*uz is returned instead of uz. In other words, on exit x, y, z are the solution of [ sum_k zk*Hk(x) A' GG'*W^{-1} ] [ ux ] [ bx ] [ A 0 0 ] [ uy ] = [ by ]. [ GG 0 -W' ] [ uz ] [ bz ] 2. The linear operators Df*u, H*u, G*u and A*u can be specified by providing Python functions instead of matrices. This can only be done in combination with 1. above, i.e., it also requires the kktsolver argument. If G is a function, the call G(u, v, alpha, beta, trans) should evaluate the matrix-vector products v := alpha * G * u + beta * v if trans is 'N' v := alpha * G' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. If A is a function, the call A(u, v, alpha, beta, trans) should evaluate the matrix-vectors products v := alpha * A * u + beta * v if trans is 'N' v := alpha * A' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. If Df is a function, the call Df(u, v, alpha, beta, trans) should evaluate the matrix-vectors products v := alpha * Df(x) * u + beta * v if trans is 'N' v := alpha * Df(x)' * u + beta * v if trans is 'T'. If H is a function, the call H(u, v, alpha, beta) should evaluate the matrix-vectors product v := alpha * H * u + beta * v. 3. Instead of using the default representation of the primal variable x and the dual variable y as one-column 'd' matrices, we can represent these variables and the corresponding parameters c and b by arbitrary Python objects (matrices, lists, dictionaries, etc). This can only be done in combination with 1. and 2. above, i.e., it requires a user-provided KKT solver and a function description of the linear mappings. It also requires the arguments xnewcopy, xdot, xscal, xaxpy, ynewcopy, ydot, yscal, yaxpy. These arguments are functions defined as follows. If X is the vector space of primal variables x, then: - xnewcopy(u) creates a new copy of the vector u in X. - xdot(u, v) returns the inner product of two vectors u and v in X. - xscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in X. - xaxpy(u, v, alpha = 1.0, beta = 0.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in X. If Y is the vector space of primal variables y: - ynewcopy(u) creates a new copy of the vector u in Y. - ydot(u, v) returns the inner product of two vectors u and v in Y. - yscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in Y. - yaxpy(u, v, alpha = 1.0, beta = 0.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in Y. Control parameters. The following control parameters can be modified by adding an entry to the dictionary options. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] nonnegative integer (default: 1) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). """ import math from cvxopt import base, blas, misc from cvxopt.base import matrix, spmatrix STEP = 0.99 BETA = 0.5 ALPHA = 0.01 EXPON = 3 MAX_RELAXED_ITERS = 8 try: DEBUG = options['debug'] except KeyError: DEBUG = False try: MAXITERS = options['maxiters'] except KeyError: MAXITERS = 100 else: if type(MAXITERS) is not int or MAXITERS < 1: raise ValueError("options['maxiters'] must be a positive "\ "integer") try: ABSTOL = options['abstol'] except KeyError: ABSTOL = 1e-7 else: if type(ABSTOL) is not float and type(ABSTOL) is not int: raise ValueError("options['abstol'] must be a scalar") try: RELTOL = options['reltol'] except KeyError: RELTOL = 1e-6 else: if type(RELTOL) is not float and type(RELTOL) is not int: raise ValueError("options['reltol'] must be a scalar") try: FEASTOL = options['feastol'] except KeyError: FEASTOL = 1e-7 else: if (type(FEASTOL) is not float and type(FEASTOL) is not int) or \ FEASTOL <= 0.0: raise ValueError("options['feastol'] must be a positive "\ "scalar") if RELTOL <= 0.0 and ABSTOL <= 0.0: raise ValueError("at least one of options['reltol'] and " \ "options['abstol'] must be positive") try: show_progress = options['show_progress'] except KeyError: show_progress = True try: refinement = options['refinement'] except KeyError: refinement = 1 else: if type(refinement) is not int or refinement < 0: raise ValueError("options['refinement'] must be a "\ "nonnegative integer") if kktsolver is None: if dims and (dims['q'] or dims['s']): kktsolver = 'chol' else: kktsolver = 'chol2' defaultsolvers = ('ldl', 'ldl2', 'chol', 'chol2') if type(kktsolver) is str and kktsolver not in defaultsolvers: raise ValueError("'%s' is not a valid value for kktsolver" \ %kktsolver) try: mnl, x0 = F() except: raise ValueError("function call 'F()' failed") # Argument error checking depends on level of customization. customkkt = type(kktsolver) is not str operatorG = G is not None and type(G) not in (matrix, spmatrix) operatorA = A is not None and type(A) not in (matrix, spmatrix) if (operatorG or operatorA) and not customkkt: raise ValueError("use of function valued G, A requires a "\ "user-provided kktsolver") customx = (xnewcopy != None or xdot != None or xaxpy != None or xscal != None) if customx and (not operatorG or not operatorA or not customkkt): raise ValueError("use of non-vector type for x requires "\ "function valued G, A and user-provided kktsolver") customy = (ynewcopy != None or ydot != None or yaxpy != None or yscal != None) if customy and (not operatorA or not customkkt): raise ValueError("use of non vector type for y requires "\ "function valued A and user-provided kktsolver") if not customx: if type(x0) is not matrix or x0.typecode != 'd' or x0.size[1] != 1: raise TypeError("'x0' must be a 'd' matrix with one column") if type(c) is not matrix or c.typecode != 'd' or c.size != x0.size: raise TypeError("'c' must be a 'd' matrix of size (%d,%d)"\ %(x0.size[0],1)) if h is None: h = matrix(0.0, (0,1)) if type(h) is not matrix or h.typecode != 'd' or h.size[1] != 1: raise TypeError("'h' must be a 'd' matrix with 1 column") if not dims: dims = {'l': h.size[0], 'q': [], 's': []} # Dimension of the product cone of the linear inequalities. with 's' # components unpacked. cdim = dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) if h.size[0] != cdim: raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %cdim) if G is None: if customx: def G(x, y, trans = 'N', alpha = 1.0, beta = 0.0): if trans == 'N': pass else: xscal(beta, y) else: G = spmatrix([], [], [], (0, c.size[0])) if not operatorG: if G.typecode != 'd' or G.size != (cdim, c.size[0]): raise TypeError("'G' must be a 'd' matrix with size (%d, %d)"\ %(cdim, c.size[0])) def fG(x, y, trans = 'N', alpha = 1.0, beta = 0.0): misc.sgemv(G, x, y, dims, trans = trans, alpha = alpha, beta = beta) else: fG = G if A is None: if customx or customy: def A(x, y, trans = 'N', alpha = 1.0, beta = 0.0): if trans == 'N': pass else: yscal(beta, y) else: A = spmatrix([], [], [], (0, c.size[0])) if not operatorA: if A.typecode != 'd' or A.size[1] != c.size[0]: raise TypeError("'A' must be a 'd' matrix with %d columns" \ %c.size[0]) def fA(x, y, trans = 'N', alpha = 1.0, beta = 0.0): base.gemv(A, x, y, trans = trans, alpha = alpha, beta = beta) else: fA = A if not customy: if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size[1] != 1: raise TypeError("'b' must be a 'd' matrix with one column") if not operatorA and b.size[0] != A.size[0]: raise TypeError("'b' must have length %d" %A.size[0]) if b is None and customy: raise ValueEror("use of non vector type for y requires b") # kktsolver(x, z, W) returns a routine for solving # # [ sum_k zk*Hk(x) A' GG'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ] # [ GG 0 -W' ] [ uz ] [ bz ] # # where G = [Df(x); G]. if kktsolver in defaultsolvers: if kktsolver == 'ldl': factor = misc.kkt_ldl(G, dims, A, mnl) elif kktsolver == 'ldl2': factor = misc.kkt_ldl2(G, dims, A, mnl) elif kktsolver == 'chol': factor = misc.kkt_chol(G, dims, A, mnl) else: factor = misc.kkt_chol2(G, dims, A, mnl) def kktsolver(x, z, W): f, Df, H = F(x, z) return factor(W, H, Df) if xnewcopy is None: xnewcopy = matrix if xdot is None: xdot = blas.dot if xaxpy is None: xaxpy = blas.axpy if xscal is None: xscal = blas.scal def xcopy(x, y): xscal(0.0, y) xaxpy(x, y) if ynewcopy is None: ynewcopy = matrix if ydot is None: ydot = blas.dot if yaxpy is None: yaxpy = blas.axpy if yscal is None: yscal = blas.scal def ycopy(x, y): yscal(0.0, y) yaxpy(x, y) # Initial points x = xnewcopy(x0) y = ynewcopy(b); yscal(0.0, y) z, s = matrix(0.0, (mnl + cdim, 1)), matrix(0.0, (mnl + cdim, 1)) z[: mnl+dims['l']] = 1.0 s[: mnl+dims['l']] = 1.0 ind = mnl + dims['l'] for m in dims['q']: z[ind] = 1.0 s[ind] = 1.0 ind += m for m in dims['s']: z[ind : ind + m*m : m+1] = 1.0 s[ind : ind + m*m : m+1] = 1.0 ind += m**2 rx, ry = xnewcopy(x0), ynewcopy(b) rznl, rzl = matrix(0.0, (mnl, 1)), matrix(0.0, (cdim, 1)), dx, dy = xnewcopy(x), ynewcopy(y) dz, ds = matrix(0.0, (mnl + cdim, 1)), matrix(0.0, (mnl + cdim, 1)) lmbda = matrix(0.0, (mnl + dims['l'] + sum(dims['q']) + sum(dims['s']), 1)) lmbdasq = matrix(0.0, (mnl + dims['l'] + sum(dims['q']) + sum(dims['s']), 1)) sigs = matrix(0.0, (sum(dims['s']), 1)) sigz = matrix(0.0, (sum(dims['s']), 1)) dz2, ds2 = matrix(0.0, (mnl + cdim, 1)), matrix(0.0, (mnl + cdim, 1)) newx, newy = xnewcopy(x), ynewcopy(y) newz, news = matrix(0.0, (mnl + cdim, 1)), matrix(0.0, (mnl + cdim, 1)) newrx = xnewcopy(x0) newrznl = matrix(0.0, (mnl, 1)) rx0, ry0 = xnewcopy(x0), ynewcopy(b) rznl0, rzl0 = matrix(0.0, (mnl, 1)), matrix(0.0, (cdim, 1)), x0, dx0 = xnewcopy(x), xnewcopy(dx) y0, dy0 = ynewcopy(y), ynewcopy(dy) z0 = matrix(0.0, (mnl + cdim, 1)) dz0 = matrix(0.0, (mnl + cdim, 1)) dz20 = matrix(0.0, (mnl + cdim, 1)) s0 = matrix(0.0, (mnl + cdim, 1)) ds0 = matrix(0.0, (mnl + cdim, 1)) ds20 = matrix(0.0, (mnl + cdim, 1)) W0 = {} W0['dnl'] = matrix(0.0, (mnl, 1)) W0['dnli'] = matrix(0.0, (mnl, 1)) W0['d'] = matrix(0.0, (dims['l'], 1)) W0['di'] = matrix(0.0, (dims['l'], 1)) W0['v'] = [ matrix(0.0, (m, 1)) for m in dims['q'] ] W0['beta'] = len(dims['q']) * [ 0.0 ] W0['r'] = [ matrix(0.0, (m, m)) for m in dims['s'] ] W0['rti'] = [ matrix(0.0, (m, m)) for m in dims['s'] ] lmbda0 = matrix(0.0, (mnl + dims['l'] + sum(dims['q']) + sum(dims['s']), 1)) lmbdasq0 = matrix(0.0, (mnl + dims['l'] + sum(dims['q']) + sum(dims['s']), 1)) if show_progress: print("% 10s% 12s% 10s% 8s% 7s" %("pcost", "dcost", "gap", "pres", "dres")) relaxed_iters = 0 for iters in range(MAXITERS + 1): if refinement or DEBUG: # We need H to compute residuals of KKT equations. f, Df, H = F(x, z[:mnl]) else: f, Df = F(x) f = matrix(f, tc='d') if f.typecode != 'd' or f.size != (mnl, 1): raise TypeError("first output argument of F() must be a "\ "'d' matrix of size (%d, %d)" %(mnl, 1)) if type(Df) is matrix or type(Df) is spmatrix: if customx: raise ValueError("use of non-vector type for x "\ "requires function valued Df") if Df.typecode != 'd' or Df.size != (mnl, c.size[0]): raise TypeError("second output argument of F() must "\ "be a 'd' matrix of size (%d,%d)" %(mnl, c.size[0])) def fDf(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): base.gemv(Df, u, v, alpha = alpha, beta = beta, trans = trans) else: if not customkkt: raise ValueError("use of function valued Df requires "\ "a user-provided kktsolver") fDf = Df if refinement or DEBUG: if type(H) is matrix or type(H) is spmatrix: if customx: raise ValueError("use of non-vector type "\ "for x requires function valued H") if H.typecode != 'd' or H.size != (c.size[0], c.size[0]): raise TypeError("third output argument of F() must "\ "be a 'd' matrix of size (%d,%d)" \ %(c.size[0], c.size[0])) def fH(u, v, alpha = 1.0, beta = 0.0): base.symv(H, u, v, alpha = alpha, beta = beta) else: if not customkkt: raise ValueError("use of function valued H requires "\ "a user-provided kktsolver") fH = H gap = misc.sdot(s, z, dims, mnl) # rx = c + A'*y + Df'*z[:mnl] + G'*z[mnl:] xcopy(c, rx) fA(y, rx, beta = 1.0, trans = 'T') fDf(z[:mnl], rx, beta = 1.0, trans = 'T') fG(z[mnl:], rx, beta = 1.0, trans = 'T') resx = math.sqrt(xdot(rx, rx)) # ry = A*x - b ycopy(b, ry) fA(x, ry, alpha = 1.0, beta = -1.0) resy = math.sqrt(ydot(ry, ry)) # rznl = s[:mnl] + f blas.copy(s[:mnl], rznl) blas.axpy(f, rznl) resznl = blas.nrm2(rznl) # rzl = s[mnl:] + G*x - h blas.copy(s[mnl:], rzl) blas.axpy(h, rzl, alpha = -1.0) fG(x, rzl, beta = 1.0) reszl = misc.snrm2(rzl, dims) # Statistics for stopping criteria. # pcost = c'*x # dcost = c'*x + y'*(A*x-b) + znl'*f(x) + zl'*(G*x-h) # = c'*x + y'*(A*x-b) + znl'*(f(x)+snl) + zl'*(G*x-h+sl) # - z'*s # = c'*x + y'*ry + znl'*rznl + zl'*rzl - gap pcost = xdot(c,x) dcost = pcost + ydot(y, ry) + blas.dot(z[:mnl], rznl) + \ misc.sdot(z[mnl:], rzl, dims) - gap if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None pres = math.sqrt( resy**2 + resznl**2 + reszl**2 ) dres = resx if iters == 0: resx0 = max(1.0, resx) resznl0 = max(1.0, resznl) pres0 = max(1.0, pres) dres0 = max(1.0, dres) gap0 = gap theta1 = 1.0 / gap0 theta2 = 1.0 / resx0 theta3 = 1.0 / resznl0 phi = theta1 * gap + theta2 * resx + theta3 * resznl pres = pres / pres0 dres = dres / dres0 if show_progress: print("%2d: % 8.4e % 8.4e % 4.0e% 7.0e% 7.0e" \ %(iters, pcost, dcost, gap, pres, dres)) # Stopping criteria. if ( pres <= FEASTOL and dres <= FEASTOL and ( gap <= ABSTOL or (relgap is not None and relgap <= RELTOL) )) or \ iters == MAXITERS: sl, zl = s[mnl:], z[mnl:] ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(sl, m, ind) misc.symm(zl, m, ind) ind += m**2 ts = misc.max_step(s, dims, mnl) tz = misc.max_step(z, dims, mnl) if iters == MAXITERS: if show_progress: print("Terminated (maximum number of iterations "\ "reached).") status = 'unknown' else: if show_progress: print("Optimal solution found.") status = 'optimal' return {'status': status, 'x': x, 'y': y, 'znl': z[:mnl], 'zl': zl, 'snl': s[:mnl], 'sl': sl, 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective': dcost, 'primal slack': -ts, 'dual slack': -tz, 'primal infeasibility': pres, 'dual infeasibility': dres } # Compute initial scaling W: # # W * z = W^{-T} * s = lambda. # # lmbdasq = lambda o lambda if iters == 0: W = misc.compute_scaling(s, z, lmbda, dims, mnl) misc.ssqr(lmbdasq, lmbda, dims, mnl) # f3(x, y, z) solves # # [ H A' GG'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ]. # [ GG 0 -W' ] [ uz ] [ bz ] # # On entry, x, y, z contain bx, by, bz. # On exit, they contain ux, uy, uz. try: f3 = kktsolver(x, z[:mnl], W) except ArithmeticError: singular_kkt_matrix = False if iters == 0: raise ValueError("Rank(A) < p or "\ "Rank([H(x); A; Df(x); G]) < n") elif 0 < relaxed_iters < MAX_RELAXED_ITERS > 0: # The arithmetic error may be caused by a relaxed line # search in the previous iteration. Therefore we restore # the last saved state and require a standard line search. phi, gap = phi0, gap0 mu = gap / ( mnl + dims['l'] + len(dims['q']) + sum(dims['s']) ) blas.copy(W0['dnl'], W['dnl']) blas.copy(W0['dnli'], W['dnli']) blas.copy(W0['d'], W['d']) blas.copy(W0['di'], W['di']) for k in range(len(dims['q'])): blas.copy(W0['v'][k], W['v'][k]) W['beta'][k] = W0['beta'][k] for k in range(len(dims['s'])): blas.copy(W0['r'][k], W['r'][k]) blas.copy(W0['rti'][k], W['rti'][k]) xcopy(x0, x); ycopy(y0, y); blas.copy(s0, s); blas.copy(z0, z) blas.copy(lmbda0, lmbda) blas.copy(lmbdasq, lmbdasq0) xcopy(rx0, rx); ycopy(ry0, ry) resx = math.sqrt(xdot(rx, rx)) blas.copy(rznl0, rznl); blas.copy(rzl0, rzl); resznl = blas.nrm2(rznl) relaxed_iters = -1 try: f3 = kktsolver(x, z[:mnl], W) except ArithmeticError: singular_kkt_matrix = True else: singular_kkt_matrix = True if singular_kkt_matrix: sl, zl = s[mnl:], z[mnl:] ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(sl, m, ind) misc.symm(zl, m, ind) ind += m**2 ts = misc.max_step(s, dims, mnl) tz = misc.max_step(z, dims, mnl) if show_progress: print("Terminated (singular KKT matrix).") status = 'unknown' return {'status': status, 'x': x, 'y': y, 'znl': z[:mnl], 'zl': zl, 'snl': s[:mnl], 'sl': sl, 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective': dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz } # f4_no_ir(x, y, z, s) solves # # [ 0 ] [ H A' GG' ] [ ux ] [ bx ] # [ 0 ] + [ A 0 0 ] [ uy ] = [ by ] # [ W'*us ] [ GG 0 0 ] [ W^{-1}*uz ] [ bz ] # # lmbda o (uz + us) = bs. # # On entry, x, y, z, x, contain bx, by, bz, bs. # On exit, they contain ux, uy, uz, us. if iters == 0: ws3 = matrix(0.0, (mnl + cdim, 1)) wz3 = matrix(0.0, (mnl + cdim, 1)) def f4_no_ir(x, y, z, s): # Solve # # [ H A' GG' ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ] # [ GG 0 -W'*W ] [ W^{-1}*uz ] [ bz - W'*(lmbda o\ bs) ] # # us = lmbda o\ bs - uz. # s := lmbda o\ s # = lmbda o\ bs misc.sinv(s, lmbda, dims, mnl) # z := z - W'*s # = bz - W' * (lambda o\ bs) blas.copy(s, ws3) misc.scale(ws3, W, trans = 'T') blas.axpy(ws3, z, alpha = -1.0) # Solve for ux, uy, uz f3(x, y, z) # s := s - z # = lambda o\ bs - z. blas.axpy(z, s, alpha = -1.0) if iters == 0: wz2nl, wz2l = matrix(0.0, (mnl,1)), matrix(0.0, (cdim, 1)) def res(ux, uy, uz, us, vx, vy, vz, vs): # Evaluates residuals in Newton equations: # # [ vx ] [ 0 ] [ H A' GG' ] [ ux ] # [ vy ] -= [ 0 ] + [ A 0 0 ] [ uy ] # [ vz ] [ W'*us ] [ GG 0 0 ] [ W^{-1}*uz ] # # vs -= lmbda o (uz + us). # vx := vx - H*ux - A'*uy - GG'*W^{-1}*uz fH(ux, vx, alpha = -1.0, beta = 1.0) fA(uy, vx, alpha = -1.0, beta = 1.0, trans = 'T') blas.copy(uz, wz3) misc.scale(wz3, W, inverse = 'I') fDf(wz3[:mnl], vx, alpha = -1.0, beta = 1.0, trans = 'T') fG(wz3[mnl:], vx, alpha = -1.0, beta = 1.0, trans = 'T') # vy := vy - A*ux fA(ux, vy, alpha = -1.0, beta = 1.0) # vz := vz - W'*us - GG*ux fDf(ux, wz2nl) blas.axpy(wz2nl, vz, alpha = -1.0) fG(ux, wz2l) blas.axpy(wz2l, vz, alpha = -1.0, offsety = mnl) blas.copy(us, ws3) misc.scale(ws3, W, trans = 'T') blas.axpy(ws3, vz, alpha = -1.0) # vs -= lmbda o (uz + us) blas.copy(us, ws3) blas.axpy(uz, ws3) misc.sprod(ws3, lmbda, dims, mnl, diag = 'D') blas.axpy(ws3, vs, alpha = -1.0) # f4(x, y, z, s) solves the same system as f4_no_ir, but applies # iterative refinement. if iters == 0: if refinement or DEBUG: wx, wy = xnewcopy(c), ynewcopy(b) wz = matrix(0.0, (mnl + cdim, 1)) ws = matrix(0.0, (mnl + cdim, 1)) if refinement: wx2, wy2 = xnewcopy(c), ynewcopy(b) wz2 = matrix(0.0, (mnl + cdim, 1)) ws2 = matrix(0.0, (mnl + cdim, 1)) def f4(x, y, z, s): if refinement or DEBUG: xcopy(x, wx) ycopy(y, wy) blas.copy(z, wz) blas.copy(s, ws) f4_no_ir(x, y, z, s) for i in range(refinement): xcopy(wx, wx2) ycopy(wy, wy2) blas.copy(wz, wz2) blas.copy(ws, ws2) res(x, y, z, s, wx2, wy2, wz2, ws2) f4_no_ir(wx2, wy2, wz2, ws2) xaxpy(wx2, x) yaxpy(wy2, y) blas.axpy(wz2, z) blas.axpy(ws2, s) if DEBUG: res(x, y, z, s, wx, wy, wz, ws) print("KKT residuals:") print(" 'x': %e" %math.sqrt(xdot(wx, wx))) print(" 'y': %e" %math.sqrt(ydot(wy, wy))) print(" 'z': %e" %misc.snrm2(wz, dims, mnl)) print(" 's': %e" %misc.snrm2(ws, dims, mnl)) sigma, eta = 0.0, 0.0 for i in [0, 1]: # Solve # # [ 0 ] [ H A' GG' ] [ dx ] # [ 0 ] + [ A 0 0 ] [ dy ] = -(1 - eta)*r # [ W'*ds ] [ GG 0 0 ] [ W^{-1}*dz ] # # lmbda o (dz + ds) = -lmbda o lmbda + sigma*mu*e. # mu = gap / (mnl + dims['l'] + len(dims['q']) + sum(dims['s'])) # ds = -lmbdasq + sigma * mu * e blas.scal(0.0, ds) blas.axpy(lmbdasq, ds, n = mnl + dims['l'] + sum(dims['q']), alpha = -1.0) ds[:mnl + dims['l']] += sigma*mu ind = mnl + dims['l'] for m in dims['q']: ds[ind] += sigma*mu ind += m ind2 = ind for m in dims['s']: blas.axpy(lmbdasq, ds, n = m, offsetx = ind2, offsety = ind, incy = m + 1, alpha = -1.0) ds[ind : ind + m*m : m+1] += sigma*mu ind += m*m ind2 += m # (dx, dy, dz) := -(1-eta) * (rx, ry, rz) xscal(0.0, dx); xaxpy(rx, dx, alpha = -1.0 + eta) yscal(0.0, dy); yaxpy(ry, dy, alpha = -1.0 + eta) blas.scal(0.0, dz) blas.axpy(rznl, dz, alpha = -1.0 + eta) blas.axpy(rzl, dz, alpha = -1.0 + eta, offsety = mnl) try: f4(dx, dy, dz, ds) except ArithmeticError: if iters == 0: raise ValueError("Rank(A) < p or "\ "Rank([H(x); A; Df(x); G]) < n") else: sl, zl = s[mnl:], z[mnl:] ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(sl, m, ind) misc.symm(zl, m, ind) ind += m**2 ts = misc.max_step(s, dims, mnl) tz = misc.max_step(z, dims, mnl) if show_progress: print("Terminated (singular KKT matrix).") return {'status': 'unknown', 'x': x, 'y': y, 'znl': z[:mnl], 'zl': zl, 'snl': s[:mnl], 'sl': sl, 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective': dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz } # Inner product ds'*dz and unscaled steps are needed in the # line search. dsdz = misc.sdot(ds, dz, dims, mnl) blas.copy(dz, dz2) misc.scale(dz2, W, inverse = 'I') blas.copy(ds, ds2) misc.scale(ds2, W, trans = 'T') # Maximum steps to boundary. # # Also compute the eigenvalue decomposition of 's' blocks in # ds, dz. The eigenvectors Qs, Qz are stored in ds, dz. # The eigenvalues are stored in sigs, sigz. misc.scale2(lmbda, ds, dims, mnl) ts = misc.max_step(ds, dims, mnl, sigs) misc.scale2(lmbda, dz, dims, mnl) tz = misc.max_step(dz, dims, mnl, sigz) t = max([ 0.0, ts, tz ]) if t == 0: step = 1.0 else: step = min(1.0, STEP / t) # Backtrack until newx is in domain of f. backtrack = True while backtrack: xcopy(x, newx); xaxpy(dx, newx, alpha = step) t = F(newx) if t is None: newf = None else: newf, newDf = t[0], t[1] if newf is not None: backtrack = False else: step *= BETA # Merit function # # phi = theta1 * gap + theta2 * norm(rx) + # theta3 * norm(rznl) # # and its directional derivative dphi. phi = theta1 * gap + theta2 * resx + theta3 * resznl if i == 0: dphi = -phi else: dphi = -theta1 * (1 - sigma) * gap - \ theta2 * (1 - eta) * resx - \ theta3 * (1 - eta) * resznl # Line search. # # We use two types of line search. In a standard iteration we # use is a normal backtracking line search terminating with a # sufficient decrease of phi. In a "relaxed" iteration the # line search is terminated after one step, regardless of the # value of phi. We make at most MAX_RELAXED_ITERS consecutive # relaxed iterations. When starting a series of relaxed # iteration, we save the state at the end of the first line # search in the series (scaling, primal and dual iterates, # steps, sigma, eta, i.e., all information needed to resume # the line search at some later point). If a series of # MAX_RELAXED_ITERS relaxed iterations does not result in a # sufficient decrease compared to the value of phi at the start # of the series, then we resume the first line search in the # series as a standard line search (using the saved state). # On the other hand, if at some point during the series of # relaxed iterations we obtain a sufficient decrease of phi # compared with the value at the start of the series, then we # start a new series of relaxed line searches. # # To implement this we use a counter relaxed_iters. # # 1. If 0 <= relaxed_iters < MAX_RELAXED_ITERS, we use a # relaxed line search (one full step). If relaxed_iters # is 0, we save the value phi0 of the merit function at the # current point, as well as the state at the end of the # line search. If the relaxed line search results in a # sufficient decrease w.r.t. phi0, we reset relaxed_iters # to 0. Otherwise we increment relaxed_iters. # # 2. If relaxed_iters is MAX_RELAXED_ITERS, we use a standard # line search. If this results in a sufficient decrease # of the merit function compared with phi0, we set # relaxed_iters to 0. If phi decreased compared with phi0, # but not sufficiently, we set relaxed_iters to -1. # If phi increased compared with phi0, we resume the # backtracking at the last saved iteration, and after # completing the line search, set relaxed_iters to 0. # # 3. If relaxed_iters is -1, we use a standard line search # and increment relaxed_iters to 0. backtrack = True while backtrack: xcopy(x, newx); xaxpy(dx, newx, alpha = step) ycopy(y, newy); yaxpy(dy, newy, alpha = step) blas.copy(z, newz); blas.axpy(dz2, newz, alpha = step) blas.copy(s, news); blas.axpy(ds2, news, alpha = step) t = F(newx) newf, newDf = matrix(t[0], tc = 'd'), t[1] if type(newDf) is matrix or type(Df) is spmatrix: if newDf.typecode != 'd' or \ newDf.size != (mnl, c.size[0]): raise TypeError("second output argument "\ "of F() must be a 'd' matrix of size "\ "(%d,%d)" %(mnl, c.size[0])) def newfDf(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): base.gemv(newDf, u, v, alpha = alpha, beta = beta, trans = trans) else: newfDf = newDf # newrx = c + A'*newy + newDf'*newz[:mnl] + G'*newz[mnl:] xcopy(c, newrx) fA(newy, newrx, beta = 1.0, trans = 'T') newfDf(newz[:mnl], newrx, beta = 1.0, trans = 'T') fG(newz[mnl:], newrx, beta = 1.0, trans = 'T') newresx = math.sqrt(xdot(newrx, newrx)) # newrznl = news[:mnl] + newf blas.copy(news[:mnl], newrznl) blas.axpy(newf, newrznl) newresznl = blas.nrm2(newrznl) newgap = (1.0 - (1.0 - sigma) * step) * gap \ + step**2 * dsdz newphi = theta1 * newgap + theta2 * newresx + \ theta3 * newresznl if i == 0: if newgap <= (1.0 - ALPHA * step) * gap and \ ( 0 <= relaxed_iters < MAX_RELAXED_ITERS or \ newphi <= phi + ALPHA * step * dphi ): backtrack = False sigma = min(newgap/gap, (newgap/gap) ** EXPON) eta = 0.0 else: step *= BETA else: if relaxed_iters == -1 or ( relaxed_iters == 0 == MAX_RELAXED_ITERS ): # Do a standard line search. if newphi <= phi + ALPHA * step * dphi: relaxed_iters == 0 backtrack = False else: step *= BETA elif relaxed_iters == 0 < MAX_RELAXED_ITERS: if newphi <= phi + ALPHA * step * dphi: # Relaxed l.s. gives sufficient decrease. relaxed_iters = 0 else: # Save state. phi0, dphi0, gap0 = phi, dphi, gap step0 = step blas.copy(W['dnl'], W0['dnl']) blas.copy(W['dnli'], W0['dnli']) blas.copy(W['d'], W0['d']) blas.copy(W['di'], W0['di']) for k in range(len(dims['q'])): blas.copy(W['v'][k], W0['v'][k]) W0['beta'][k] = W['beta'][k] for k in range(len(dims['s'])): blas.copy(W['r'][k], W0['r'][k]) blas.copy(W['rti'][k], W0['rti'][k]) xcopy(x, x0); xcopy(dx, dx0) ycopy(y, y0); ycopy(dy, dy0) blas.copy(s, s0); blas.copy(z, z0) blas.copy(ds, ds0) blas.copy(dz, dz0) blas.copy(ds2, ds20) blas.copy(dz2, dz20) blas.copy(lmbda, lmbda0) blas.copy(lmbdasq, lmbdasq0) dsdz0 = dsdz sigma0, eta0 = sigma, eta xcopy(rx, rx0); ycopy(ry, ry0) blas.copy(rznl, rznl0); blas.copy(rzl, rzl0) relaxed_iters = 1 backtrack = False elif 0 <= relaxed_iters < MAX_RELAXED_ITERS > 0: if newphi <= phi0 + ALPHA * step0 * dphi0: # Relaxed l.s. gives sufficient decrease. relaxed_iters = 0 else: # Relaxed line search relaxed_iters += 1 backtrack = False elif relaxed_iters == MAX_RELAXED_ITERS > 0: if newphi <= phi0 + ALPHA * step0 * dphi0: # Series of relaxed line searches ends # with sufficient decrease w.r.t. phi0. backtrack = False relaxed_iters = 0 elif newphi >= phi0: # Resume last saved line search. phi, dphi, gap = phi0, dphi0, gap0 step = step0 blas.copy(W0['dnl'], W['dnl']) blas.copy(W0['dnli'], W['dnli']) blas.copy(W0['d'], W['d']) blas.copy(W0['di'], W['di']) for k in range(len(dims['q'])): blas.copy(W0['v'][k], W['v'][k]) W['beta'][k] = W0['beta'][k] for k in range(len(dims['s'])): blas.copy(W0['r'][k], W['r'][k]) blas.copy(W0['rti'][k], W['rti'][k]) xcopy(x0, x); xcopy(dx0, dx); ycopy(y0, y); ycopy(dy0, dy); blas.copy(s0, s); blas.copy(z0, z) blas.copy(ds0, ds) blas.copy(dz0, dz) blas.copy(ds20, ds2) blas.copy(dz20, dz2) blas.copy(lmbda0, lmbda) dsdz = dsdz0 sigma, eta = sigma0, eta0 relaxed_iters = -1 elif newphi <= phi + ALPHA * step * dphi: # Series of relaxed line searches ends with # with insufficient decrease w.r.t. phi0" backtrack = False relaxed_iters = -1 # Update x, y. xaxpy(dx, x, alpha = step) yaxpy(dy, y, alpha = step) # Replace nonlinear, 'l' and 'q' blocks of ds and dz with the # updated variables in the current scaling. # Replace 's' blocks of ds and dz with the factors Ls, Lz in a # factorization Ls*Ls', Lz*Lz' of the updated variables in the # current scaling. # ds := e + step*ds for nonlinear, 'l' and 'q' blocks. # dz := e + step*dz for nonlinear, 'l' and 'q' blocks. blas.scal(step, ds, n = mnl + dims['l'] + sum(dims['q'])) blas.scal(step, dz, n = mnl + dims['l'] + sum(dims['q'])) ind = mnl + dims['l'] ds[:ind] += 1.0 dz[:ind] += 1.0 for m in dims['q']: ds[ind] += 1.0 dz[ind] += 1.0 ind += m # ds := H(lambda)^{-1/2} * ds and dz := H(lambda)^{-1/2} * dz. # # This replaces the nonlinear, 'l' and 'q' components of ds and dz # with the updated variables in the new scaling. # The 's' components of ds and dz are replaced with # # diag(lmbda_k)^{1/2} * Qs * diag(lmbda_k)^{1/2} # diag(lmbda_k)^{1/2} * Qz * diag(lmbda_k)^{1/2} misc.scale2(lmbda, ds, dims, mnl, inverse = 'I') misc.scale2(lmbda, dz, dims, mnl, inverse = 'I') # sigs := ( e + step*sigs ) ./ lambda for 's' blocks. # sigz := ( e + step*sigz ) ./ lambda for 's' blocks. blas.scal(step, sigs) blas.scal(step, sigz) sigs += 1.0 sigz += 1.0 blas.tbsv(lmbda, sigs, n = sum(dims['s']), k = 0, ldA = 1, offsetA = mnl + dims['l'] + sum(dims['q']) ) blas.tbsv(lmbda, sigz, n = sum(dims['s']), k = 0, ldA = 1, offsetA = mnl + dims['l'] + sum(dims['q']) ) # dsk := Ls = dsk * sqrt(sigs). # dzk := Lz = dzk * sqrt(sigz). ind2, ind3 = mnl + dims['l'] + sum(dims['q']), 0 for k in range(len(dims['s'])): m = dims['s'][k] for i in range(m): blas.scal(math.sqrt(sigs[ind3+i]), ds, offset = ind2 + m*i, n = m) blas.scal(math.sqrt(sigz[ind3+i]), dz, offset = ind2 + m*i, n = m) ind2 += m*m ind3 += m # Update lambda and scaling. misc.update_scaling(W, lmbda, ds, dz) # Unscale s, z (unscaled variables are used only to compute # feasibility residuals). blas.copy(lmbda, s, n = mnl + dims['l'] + sum(dims['q'])) ind = mnl + dims['l'] + sum(dims['q']) ind2 = ind for m in dims['s']: blas.scal(0.0, s, offset = ind2) blas.copy(lmbda, s, offsetx = ind, offsety = ind2, n = m, incy = m+1) ind += m ind2 += m*m misc.scale(s, W, trans = 'T') blas.copy(lmbda, z, n = mnl + dims['l'] + sum(dims['q'])) ind = mnl + dims['l'] + sum(dims['q']) ind2 = ind for m in dims['s']: blas.scal(0.0, z, offset = ind2) blas.copy(lmbda, z, offsetx = ind, offsety = ind2, n = m, incy = m+1) ind += m ind2 += m*m misc.scale(z, W, inverse = 'I') gap = blas.dot(lmbda, lmbda) def cp(F, G = None, h = None, dims = None, A = None, b = None, kktsolver = None, xnewcopy = None, xdot = None, xaxpy = None, xscal = None, ynewcopy = None, ydot = None, yaxpy = None, yscal = None): """ Solves a convex optimization problem minimize f0(x) subject to fk(x) <= 0, k = 1, ..., mnl G*x <= h A*x = b. f = (f0, f1, ..., fmnl) is convex and twice differentiable. The linear inequalities are with respect to a cone C defined as the Cartesian product of N + M + 1 cones: C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}. The first cone C_0 is the nonnegative orthant of dimension ml. The next N cones are second order cones of dimension mq[0], ..., mq[N-1]. The second order cone of dimension m is defined as { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }. The next M cones are positive semidefinite cones of order ms[0], ..., ms[M-1] >= 0. Input arguments (basic usage). F is a function that handles the following arguments. F() returns a tuple (mnl, x0). mnl is the number of nonlinear inequality constraints. x0 is a point in the domain of f. F(x) returns a tuple (f, Df). f is a dense 'd' matrix of size (mnl+1,1) containing f(x). Df is a dense or sparse 'd' matrix of size (mnl+1, n), containing the derivatives of f at x: Df[k,:] is the transpose of the gradient of fk at x. If x is not in dom f, F(x) returns None or (None, None). F(x, z) with z a positive 'd' matrix of size (mnl+1,1), returns a tuple (f, Df, H). f and Df are defined as above. H is a dense or sparse 'd' matrix of size (n,n). The lower triangular part of H contains the lower triangular part of sum_k z[k] * Hk where Hk is the Hessian of fk at x. If F is called with two arguments, it can be assumed that x is dom f. If Df and H are returned as sparse matrices, their sparsity patterns must be the same for each call to F(x) or F(x,z). dims is a dictionary with the dimensions of the components of C. It has three fields. - dims['l'] = ml, the dimension of the nonnegative orthant C_0. (ml >= 0.) - dims['q'] = mq = [ mq[0], mq[1], ..., mq[N-1] ], a list of N integers with the dimensions of the second order cones C_1, ..., C_N. (N >= 0 and mq[k] >= 1.) - dims['s'] = ms = [ ms[0], ms[1], ..., ms[M-1] ], a list of M integers with the orders of the semidefinite cones C_{N+1}, ..., C_{N+M}. (M >= 0 and ms[k] >= 0.) The default value of dims = {'l': G.size[0], 'q': [], 's': []}. G is a dense or sparse 'd' matrix of size (K,n), where K = ml + mq[0] + ... + mq[N-1] + ms[0]**2 + ... + ms[M-1]**2. Each column of G describes a vector v = ( v_0, v_1, ..., v_N, vec(v_{N+1}), ..., vec(v_{N+M}) ) in V = R^ml x R^mq[0] x ... x R^mq[N-1] x S^ms[0] x ... x S^ms[M-1] stored as a column vector [ v_0; v_1; ...; v_N; vec(v_{N+1}); ...; vec(v_{N+M}) ]. Here, if u is a symmetric matrix of order m, then vec(u) is the matrix u stored in column major order as a vector of length m**2. We use BLAS unpacked 'L' storage, i.e., the entries in vec(u) corresponding to the strictly upper triangular entries of u are not referenced. h is a dense 'd' matrix of size (K,1), representing a vector in V, in the same format as the columns of G. A is a dense or sparse 'd' matrix of size (p,n). The default value is a sparse 'd' matrix of size (0,n). b is a dense 'd' matrix of size (p,1). The default value is a dense 'd' matrix of size (0,1). It is assumed that rank(A) = p and rank([H; A; Df; G]) = n at all x in dom f. The other arguments are normally not needed. They make it possible to exploit certain types of structure, as described below. Output arguments. cp() returns a dictionary with keys 'status', 'x', 'snl', 'sl', 'znl', 'zl', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack'. The 'status' field has values 'optimal' or 'unknown'. If status is 'optimal', x, snl, sl, y, znl, zl are approximate solutions of the primal and dual optimality conditions f(x)[1:] + snl = 0, G*x + sl = h, A*x = b Df(x)'*[1; znl] + G'*zl + A'*y + c = 0 snl >= 0, znl >= 0, sl >= 0, zl >= 0 snl'*znl + sl'* zl = 0. If status is 'unknown', x, snl, sl, y, znl, zl are the last iterates before termination. They satisfy snl > 0, znl > 0, sl > 0, zl > 0, but are not necessarily feasible. The values of the other fields are the values returned by cpl() applied to the epigraph form problem minimize t subjec to f0(x) <= t fk(x) <= 0, k = 1, ..., mnl G*x <= h A*x = b. Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, snl, sl, znl, zl are close to optimal. Advanced usage. Three mechanisms are provided to express problem structure. 1. The user can provide a customized routine for solving linear equations (`KKT systems') [ sum_k zk*Hk(x) A' GG' ] [ ux ] [ bx ] [ A 0 0 ] [ uy ] = [ by ] [ GG 0 -W'*W ] [ uz ] [ bz ] where GG = [ Df[1:,:]; G ], uz = (uznl, uzl), bz = (bznl, bzl). z is a positive vector of length mnl+1 and x is a point in the domain of f. W is a scaling matrix, a block diagonal mapping W*u = ( Wnl*unl, W0*u_0, ..., W_{N+M}*u_{N+M} ) defined as follows. - For the nonlinear block (Wnl): Wnl = diag(dnl), with dnl a positive vector of length mnl. - For the 'l' block (W_0): W_0 = diag(d), with d a positive vector of length ml. - For the 'q' blocks (W_{k+1}, k = 0, ..., N-1): W_{k+1} = beta_k * ( 2 * v_k * v_k' - J ) where beta_k is a positive scalar, v_k is a vector in R^mq[k] with v_k[0] > 0 and v_k'*J*v_k = 1, and J = [1, 0; 0, -I]. - For the 's' blocks (W_{k+N}, k = 0, ..., M-1): W_k * u = vec(r_k' * mat(u) * r_k) where r_k is a nonsingular matrix of order ms[k], and mat(x) is the inverse of the vec operation. The optional argument kktsolver is a Python function that will be called as g = kktsolver(x, z, W). W is a dictionary that contains the parameters of the scaling: - W['dnl'] is a positive 'd' matrix of size (mnl, 1). - W['dnli'] is a positive 'd' matrix with the elementwise inverse of W['dnl']. - W['d'] is a positive 'd' matrix of size (ml, 1). - W['di'] is a positive 'd' matrix with the elementwise inverse of W['d']. - W['beta'] is a list [ beta_0, ..., beta_{N-1} ] - W['v'] is a list [ v_0, ..., v_{N-1} ] - W['r'] is a list [ r_0, ..., r_{M-1} ] - W['rti'] is a list [ rti_0, ..., rti_{M-1} ], with rti_k the inverse of the transpose of r_k. The call g = kktsolver(x, z, W) should return a function g that solves the KKT system by g(ux, uy, uz). On entry, ux, uy, uz contain the righthand side bx, by, bz. On exit, they contain the solution, with uz scaled: (Wnl*uznl, Wl*uzl) is returned instead of (uznl, uzl). 2. The linear operators Df*u, H*u, G*u and A*u can be specified by providing Python functions instead of matrices. This can only be done in combination with 1. above, i.e., it requires the kktsolver argument. If G is a function, the call G(u, v, alpha, beta, trans) should evaluate the matrix-vector products v := alpha * G * u + beta * v if trans is 'N' v := alpha * G' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. If A is a function, the call A(u, v, alpha, beta, trans) should evaluate the matrix-vectors products v := alpha * A * u + beta * v if trans is 'N' v := alpha * A' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. If Df is a function, the call Df(u, v, alpha, beta, trans) should evaluate the matrix-vectors products v := alpha * Df(x) * u + beta * v if trans is 'N' v := alpha * Df(x)' * u + beta * v if trans is 'T'. If H is a function, the call H(u, v, alpha, beta) should evaluate the matrix-vectors product v := alpha * H * u + beta * v. 3. Instead of using the default representation of the primal variable x and the dual variable y as one-column 'd' matrices, we can represent these variables and the corresponding parameters c and b by arbitrary Python objects (matrices, lists, dictionaries, etc). This can only be done in combination with 1. and 2. above, i.e., it requires a user-provided KKT solver and a function description of the linear mappings. It also requires the arguments xnewcopy, xdot, xscal, xaxpy, ynewcopy, ydot, yscal, yaxpy. These arguments are functions defined as follows. If X is the vector space of primal variables x, then: - xnewcopy(u) creates a new copy of the vector u in X. - xdot(u, v) returns the inner product of two vectors u and v in X. - xscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in X. - xaxpy(u, v, alpha = 1.0, beta = 0.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in X. If Y is the vector space of primal variables y: - ynewcopy(u) creates a new copy of the vector u in Y. - ydot(u, v) returns the inner product of two vectors u and v in Y. - yscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in Y. - yaxpy(u, v, alpha = 1.0, beta = 0.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in Y. Control parameters. The following control parameters can be modified by adding an entry to the dictionary options. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] nonnegative integer (default: 1) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). """ import math from cvxopt import base, blas, misc from cvxopt.base import matrix, spmatrix mnl, x0 = F() # Argument error checking depends on level of customization. customkkt = type(kktsolver) is not str operatorG = G is not None and type(G) not in (matrix, spmatrix) operatorA = A is not None and type(A) not in (matrix, spmatrix) if (operatorG or operatorA) and not customkkt: raise ValueError("use of function valued G, A requires a "\ "user-provided kktsolver") customx = (xnewcopy != None or xdot != None or xaxpy != None or xscal != None) if customx and (not operatorG or not operatorA or not customkkt): raise ValueError("use of non-vector type for x requires "\ "function valued G, A and user-provided kktsolver") customy = (ynewcopy != None or ydot != None or yaxpy != None or yscal != None) if customy and (not operatorA or not customkkt): raise ValueError("use of non vector type for y requires "\ "function valued A and user-provided kktsolver") if not customx: if type(x0) is not matrix or x0.typecode != 'd' or x0.size[1] != 1: raise TypeError("'x0' must be a 'd' matrix with one column") if h is None: h = matrix(0.0, (0,1)) if type(h) is not matrix or h.typecode != 'd' or h.size[1] != 1: raise TypeError("'h' must be a 'd' matrix with one column") if not dims: dims = {'l': h.size[0], 'q': [], 's': []} # Dimension of the product cone of the linear inequalities. with 's' # components unpacked. cdim = dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) if h.size[0] != cdim: raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %cdim) if G is None: if customx: def G(x, y, trans = 'N', alpha = 1.0, beta = 0.0): if trans == 'N': pass else: xscal(beta, y) else: G = spmatrix([], [], [], (0, x0.size[0])) if type(G) is matrix or type(G) is spmatrix: if G.typecode != 'd' or G.size != (cdim, x0.size[0]): raise TypeError("'G' must be a 'd' matrix with size (%d, %d)"\ %(cdim, x0.size[0])) def fG(x, y, trans = 'N', alpha = 1.0, beta = 0.0): misc.sgemv(G, x, y, dims, trans = trans, alpha = alpha, beta = beta) else: fG = G if A is None: if customy: def A(x, y, trans = 'N', alpha = 1.0, beta = 0.0): if trans == 'N': pass else: xscal(beta, y) else: A = spmatrix([], [], [], (0, x0.size[0])) if type(A) is matrix or type(A) is spmatrix: if A.typecode != 'd' or A.size[1] != x0.size[0]: raise TypeError("'A' must be a 'd' matrix with %d columns" \ %x0.size[0]) def fA(x, y, trans = 'N', alpha = 1.0, beta = 0.0): base.gemv(A, x, y, trans = trans, alpha = alpha, beta = beta) else: fA = A if not customy: if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size[1] != 1: raise TypeError("'b' must be a 'd' matrix with one column") if not operatorA and b.size[0] != A.size[0]: raise TypeError("'b' must have length %d" %A.size[0]) if b is None and customy: raise ValueEror("use of non vector type for y requires b") if xnewcopy is None: xnewcopy = matrix if xdot is None: xdot = blas.dot if xaxpy is None: xaxpy = blas.axpy if xscal is None: xscal = blas.scal def xcopy(x, y): xscal(0.0, y) xaxpy(x, y) if ynewcopy is None: ynewcopy = matrix if ydot is None: ydot = blas.dot if yaxpy is None: yaxpy = blas.axpy if yscal is None: yscal = blas.scal def ycopy(x, y): yscal(0.0, y) yaxpy(x, y) # The problem is solved by applying cpl() to the epigraph form # # minimize t # subject to f0(x) - t <= 0 # f1(x) <= 0 # ... # fmnl(x) <= 0 # G*x <= h # A*x = b. # # The epigraph form variable is stored as a list [x, t]. # Epigraph form objective c = (0, 1). c = [ xnewcopy(x0), 1 ] xscal(0.0, c[0]) # Nonlinear inequalities for the epigraph problem # # f_e(x,t) = (f0(x) - t, f1(x), ..., fmnl(x)). # def F_e(x = None, z = None): if x is None: return mnl+1, [ x0, 0.0 ] else: if z is None: v = F(x[0]) if v is None or v[0] is None: return None, None val = matrix(v[0], tc = 'd') val[0] -= x[1] Df = v[1] else: val, Df, H = F(x[0], z) val = matrix(val, tc = 'd') val[0] -= x[1] if type(Df) in (matrix, spmatrix): def Df_e(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': base.gemv(Df, u[0], v, alpha = alpha, beta = beta, trans = 'N') v[0] -= alpha * u[1] else: base.gemv(Df, u, v[0], alpha = alpha, beta = beta, trans = 'T') v[1] = -alpha * u[0] + beta * v[1] else: def Df_e(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': Df(u[0], v, alpha = alpha, beta = beta, trans = 'N') v[0] -= alpha * u[1] else: Df(u, v[0], alpha = alpha, beta = beta, trans = 'T') v[1] = -alpha * u[0] + beta * v[1] if z is None: return val, Df_e else: if type(H) in (matrix, spmatrix): def H_e(u, v, alpha = 1.0, beta = 1.0): base.symv(H, u[0], v[0], alpha = alpha, beta = beta) v[1] += beta*v[1] else: def H_e(u, v, alpha = 1.0, beta = 1.0): H(u[0], v[0], alpha = alpha, beta = beta) v[1] += beta*v[1] return val, Df_e, H_e # Linear inequality constraints. # # G_e = [ G, 0 ] # if type(G) in (matrix, spmatrix): def G_e(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': misc.sgemv(G, u[0], v, dims, alpha = alpha, beta = beta) else: misc.sgemv(G, u, v[0], dims, alpha = alpha, beta = beta, trans = 'T') v[1] *= beta else: def G_e(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': G(u[0], v, alpha = alpha, beta = beta) else: G(u, v[0], alpha = alpha, beta = beta, trans = 'T') v[1] *= beta # Linear equality constraints. # # A_e = [ A, 0 ] # if type(A) in (matrix, spmatrix): def A_e(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': base.gemv(A, u[0], v, alpha = alpha, beta = beta) else: base.gemv(A, u, v[0], alpha = alpha, beta = beta, trans = 'T') v[1] *= beta else: def A_e(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': A(u[0], v, alpha = alpha, beta = beta) else: A(u, v[0], alpha = alpha, beta = beta, trans = 'T') v[1] *= beta # kktsolver(x, z, W) returns a routine for solving equations with # coefficient matrix # # [ H A' [Df[1:]; G]' ] # K = [ A 0 0 ]. # [ [Df[1:]; G] 0 -W'*W ] if kktsolver is None: if dims and (dims['q'] or dims['s']): kktsolver = 'chol' else: kktsolver = 'chol2' if kktsolver in ('ldl', 'chol', 'chol2', 'qr'): if kktsolver == 'ldl': factor = misc.kkt_ldl(G, dims, A, mnl) elif kktsolver == 'qr': factor = misc.kkt_qr(G, dims, A, mnl) elif kktsolver == 'chol': factor = misc.kkt_chol(G, dims, A, mnl) else: factor = misc.kkt_chol2(G, dims, A, mnl) def kktsolver(x, z, W): f, Df, H = F(x, z) return factor(W, H, Df[1:,:]) ux, uz = xnewcopy(x0), matrix(0.0, (mnl + cdim, 1)) def kktsolver_e(x, znl, W): We = W.copy() We['dnl'] = W['dnl'][1:] We['dnli'] = W['dnli'][1:] g = kktsolver(x[0], znl, We) f, Df = F(x[0]) if type(Df) is matrix or type(Df) is spmatrix: gradf0 = Df[0,:].T else: gradf0 = xnewcopy(x[0]) e0 = matrix(0.0, (mnl + 1, 1)) e0[0] = 1.0 Df(e0, gradf0, trans = 'T') def solve(x, y, z): # Solves # # [ [ H 0 ] [ A' ] [ Df' G'] ] [ ux ] [ bx ] # [ [ 0 0 ] [ 0 ] [ -e0' 0 ] ] [ ] [ ] # [ ] [ ] [ ] # [ [ A 0 ] 0 0 ] [ uy ] = [ by ]. # [ ] [ ] [ ] # [ [ Df -e0 ] 0 -W'*W ] [ uz ] [ bz ] # [ [ G 0 ] ] [ ] [ ] # # The solution is: # # uz[0] = -bx[1] # # [ ux[0] ] [ bx[0] + bx[1] * gradf0 ] # [ uy ] = K^-1 * [ by ]. # [ uz[1:] ] [ bz[1:] ] # # ux[1] = gradf0' * ux[0] - W['dnl'][0]**2 * uz[0] - bz[0] # = gradf0' * ux[0] + W['dnl'][0]**2 * bx[1] - bz[0]. # # Instead of uz we return the scaled solution W*uz. a = z[0] xcopy(x[0], ux) xaxpy(gradf0, ux, alpha = x[1]) blas.copy(z, uz, offsetx = 1) g(ux, y, uz) z[0] = -x[1] * W['dnl'][0] blas.copy(uz, z, offsety = 1) xcopy(ux, x[0]) x[1] = xdot(gradf0, x[0]) + W['dnl'][0]**2 * x[1] - a return solve def xnewcopy_e(x): return [ xnewcopy(x[0]), x[1] ] def xdot_e(x, y): return xdot(x[0], y[0]) + x[1]*y[1] def xaxpy_e(x, y, alpha = 1.0): xaxpy(x[0], y[0], alpha = alpha) y[1] += alpha*x[1] def xscal_e(alpha, x): xscal(alpha, x[0]) x[1] *= alpha sol = cpl(c, F_e, G_e, h, dims, A_e, b, kktsolver_e, xnewcopy_e, xdot_e, xaxpy_e, xscal_e) sol['x'] = sol['x'][0] sol['znl'], sol['snl'] = sol['znl'][1:], sol['snl'][1:] return sol def gp(K, F, g, G=None, h=None, A=None, b=None): """ Solves a geometric program minimize log sum exp (F0*x+g0) subject to log sum exp (Fi*x+gi) <= 0, i=1,...,m G*x <= h A*x = b Input arguments. K is a list of positive integers [K0, K1, K2, ..., Km]. F is a sum(K)xn dense or sparse 'd' matrix with block rows F0, F1, ..., Fm. Each Fi is Kixn. g is a sum(K)x1 dense or sparse 'd' matrix with blocks g0, g1, g2, ..., gm. Each gi is Kix1. G is an mxn dense or sparse 'd' matrix. h is an mx1 dense 'd' matrix. A is a pxn dense or sparse 'd' matrix. b is a px1 dense 'd' matrix. The default values for G, h, A and b are empty matrices with zero rows. Output arguments. Returns a dictionary with keys 'status', 'x', 'snl', 'sl', 'znl', 'zl', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack'. The 'status' field has values 'optimal' or 'unknown'. If status is 'optimal', x, snl, sl, y, znl, zl are approximate solutions of the primal and dual optimality conditions f(x)[1:] + snl = 0, G*x + sl = h, A*x = b Df(x)'*[1; znl] + G'*zl + A'*y + c = 0 snl >= 0, znl >= 0, sl >= 0, zl >= 0 snl'*znl + sl'* zl = 0, where fk(x) = log sum exp (Fk*x + gk). If status is 'unknown', x, snl, sl, y, znl, zl are the last iterates before termination. They satisfy snl > 0, znl > 0, sl > 0, zl > 0, but are not necessarily feasible. The values of the other fields are the values returned by cpl() applied to the epigraph form problem minimize t subjec to f0(x) <= t fk(x) <= 0, k = 1, ..., mnl G*x <= h A*x = b. Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, snl, sl, znl, zl are close to optimal. Control parameters. The following control parameters can be modified by adding an entry to the dictionary options. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] nonnegative integer (default: 1) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). """ import math from cvxopt import base, blas, misc from cvxopt.base import matrix, spmatrix if type(K) is not list or [ k for k in K if type(k) is not int or k <= 0 ]: raise TypeError("'K' must be a list of positive integers") mnl = len(K)-1 l = sum(K) if type(F) not in (matrix, spmatrix) or F.typecode != 'd' or \ F.size[0] != l: raise TypeError("'F' must be a dense or sparse 'd' matrix "\ "with %d rows" %l) if type(g) is not matrix or g.typecode != 'd' or g.size != (l,1): raise TypeError("'g' must be a dene 'd' matrix of "\ "size (%d,1)" %l) n = F.size[1] if G is None: G = spmatrix([], [], [], (0,n)) if h is None: h = matrix(0.0, (0,1)) if type(G) not in (matrix, spmatrix) or G.typecode != 'd' or \ G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) ml = G.size[0] if type(h) is not matrix or h.typecode != 'd' or h.size != (ml,1): raise TypeError("'h' must be a dense 'd' matrix of "\ "size (%d,1)" %ml) dims = {'l': ml, 's': [], 'q': []} if A is None: A = spmatrix([], [], [], (0,n)) if b is None: b = matrix(0.0, (0,1)) if type(A) not in (matrix, spmatrix) or A.typecode != 'd' or \ A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): raise TypeError("'b' must be a dense 'd' matrix of "\ "size (%d,1)" %p) y = matrix(0.0, (l,1)) u = matrix(0.0, (max(K),1)) Fsc = matrix(0.0, (max(K),n)) cs1 = [ sum(K[:i]) for i in range(mnl+1) ] cs2 = [ cs1[i] + K[i] for i in range(mnl+1) ] ind = list(zip(range(mnl+1), cs1, cs2)) def Fgp(x = None, z = None): if x is None: return mnl, matrix(0.0, (n,1)) f = matrix(0.0, (mnl+1,1)) Df = matrix(0.0, (mnl+1,n)) # y = F*x+g blas.copy(g, y) base.gemv(F, x, y, beta=1.0) if z is not None: H = matrix(0.0, (n,n)) for i, start, stop in ind: # yi := exp(yi) = exp(Fi*x+gi) ymax = max(y[start:stop]) y[start:stop] = base.exp(y[start:stop] - ymax) # fi = log sum yi = log sum exp(Fi*x+gi) ysum = blas.asum(y, n=stop-start, offset=start) f[i] = ymax + math.log(ysum) # yi := yi / sum(yi) = exp(Fi*x+gi) / sum(exp(Fi*x+gi)) blas.scal(1.0/ysum, y, n=stop-start, offset=start) # gradfi := Fi' * yi # = Fi' * exp(Fi*x+gi) / sum(exp(Fi*x+gi)) base.gemv(F, y, Df, trans='T', m=stop-start, incy=mnl+1, offsetA=start, offsetx=start, offsety=i) if z is not None: # Hi = Fi' * (diag(yi) - yi*yi') * Fi # = Fisc' * Fisc # where # Fisc = diag(yi)^1/2 * (I - 1*yi') * Fi # = diag(yi)^1/2 * (Fi - 1*gradfi') Fsc[:K[i], :] = F[start:stop, :] for k in range(start,stop): blas.axpy(Df, Fsc, n=n, alpha=-1.0, incx=mnl+1, incy=Fsc.size[0], offsetx=i, offsety=k-start) blas.scal(math.sqrt(y[k]), Fsc, inc=Fsc.size[0], offset=k-start) # H += z[i]*Hi = z[i] * Fisc' * Fisc blas.syrk(Fsc, H, trans='T', k=stop-start, alpha=z[i], beta=1.0) if z is None: return f, Df else: return f, Df, H return cp(Fgp, G, h, dims, A, b) cvxopt-1.1.4/src/python/solvers.py0000644000175000017500000000276111674452555016271 0ustar sonnesonne""" Convex optimization solvers. conelp: solves linear cone programs. coneqp: solves quadratic cone programs. cp: solves nonlinear convex problem. cpl: solves nonlinear convex problems with linear objectives. gp: solves geometric programs. lp: solves linear programs. qp: solves quadratic programs. sdp: solves semidefinite programs. socp: solves second-order cone programs. options: dictionary with customizable algorithm parameters. """ # Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import cvxopt from cvxopt.cvxprog import cp, cpl, gp from cvxopt.coneprog import conelp, lp, sdp, socp, coneqp, qp options = {} cvxopt.cvxprog.options = options cvxopt.coneprog.options = options __all__ = ['conelp', 'coneqp', 'lp', 'socp', 'sdp', 'qp', 'cp', 'cpl', 'gp'] cvxopt-1.1.4/src/python/__init__.py0000644000175000017500000002000011674452555016315 0ustar sonnesonne""" Python package for convex optimization CVXOPT is a free software package for convex optimization based on the Python programming language. It can be used with the interactive Python interpreter, on the command line by executing Python scripts, or integrated in other software via Python extension modules. Its main purpose is to make the development of software for convex optimization applications straightforward by building on Python's extensive standard library and on the strengths of Python as a high-level programming language. """ # Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License import cvxopt.base def normal(nrows, ncols=1, mean=0.0, std=1.0): ''' Randomly generates a matrix with normally distributed entries. normal(nrows, ncols=1, mean=0, std=1) PURPOSE Returns a matrix with typecode 'd' and size nrows by ncols, with its entries randomly generated from a normal distribution with mean m and standard deviation std. ARGUMENTS nrows number of rows ncols number of columns mean approximate mean of the distribution std standard deviation of the distribution ''' try: from cvxopt import gsl except: from cvxopt.base import matrix from random import gauss return matrix([gauss(mean, std) for k in range(nrows*ncols)], (nrows,ncols), 'd' ) return gsl.normal(nrows, ncols, mean, std) def uniform(nrows, ncols=1, a=0, b=1): ''' Randomly generates a matrix with uniformly distributed entries. uniform(nrows, ncols=1, a=0, b=1) PURPOSE Returns a matrix with typecode 'd' and size nrows by ncols, with its entries randomly generated from a uniform distribution on the interval (a,b). ARGUMENTS nrows number of rows ncols number of columns a lower bound b upper bound ''' try: from cvxopt import gsl except: from cvxopt.base import matrix from random import uniform return matrix([uniform(a, b) for k in range(nrows*ncols)], (nrows,ncols), 'd' ) return gsl.uniform(nrows, ncols, a, b) def setseed(val = 0): ''' Sets the seed value for the random number generator. setseed(val = 0) ARGUMENTS value integer seed. If the value is 0, the current system time is used. ''' try: from cvxopt import gsl gsl.setseed(val) except: from random import seed if val is 0: val = None seed(val) def getseed(): ''' Returns the seed value for the random number generator. getseed() ''' try: from cvxopt import gsl return gsl.getseed() except: raise NotImplementedError("getseed() not installed (requires GSL)") import sys if sys.version_info.major < 3: import __builtin__ omax = __builtin__.max omin = __builtin__.min else: omax = max omin = min from functools import reduce def max(*args): ''' Elementwise max for matrices. PURPOSE max(a1, ..., an) computes the elementwise max for matrices. The arguments must be matrices of compatible dimensions, and scalars. The elementwise max of a matrix and a scalar is a new matrix where each element is defined as max of a matrix element and the scalar. max(iterable) where the iterator generates matrices and scalars computes the elementwise max between the objects in the iterator, using the same conventions as max(a1, ..., an). ''' if len(args) == 1 and type(args[0]).__name__ in \ ['list', 'tuple', 'xrange', 'range', 'generator']: return +reduce(base.emax, *args) elif len(args) == 1 and type(args[0]) is base.matrix: return omax(args[0]) elif len(args) == 1 and type(args[0]) is base.spmatrix: if len(args[0]) == mul(args[0].size): return omax(args[0]) else: return omax(omax(args[0]), 0.0) else: return +reduce(base.emax, args) def min(*args): ''' Elementwise min for matrices. PURPOSE min(a1, ..., an) computes the elementwise min for matrices. The arguments must be matrices of compatible dimensions, and scalars. The elementwise min of a matrix and a scalar is a new matrix where each element is defined as min of a matrix element and the scalar. min(iterable) where the iterator generates matrices and scalars computes the elementwise min between the objects in the iterator, using the same conventions as min(a1, ..., an). ''' if len(args) == 1 and type(args[0]).__name__ in \ ['list', 'tuple', 'xrange', 'range', 'generator']: return +reduce(base.emin, *args) elif len(args) == 1 and type(args[0]) is base.matrix: return omin(args[0]) elif len(args) == 1 and type(args[0]) is base.spmatrix: if len(args[0]) == mul(args[0].size): return omin(args[0]) else: return omin(omin(args[0]), 0.0) else: return +reduce(base.emin, args) def mul(*args): ''' Elementwise multiplication for matrices. PURPOSE mul(a1, ..., an) computes the elementwise multiplication for matrices. The arguments must be matrices of compatible dimensions, and scalars. The elementwise multiplication of a matrix and a scalar is a new matrix where each element is defined as the multiplication of a matrix element and the scalar. mul(iterable) where the iterator generates matrices and scalars computes the elementwise multiplication between the objects in the iterator, using the same conventions as mul(a1, ..., an). ''' if len(args) == 1 and type(args[0]).__name__ in \ ['list', 'tuple', 'xrange', 'range', 'generator']: return +reduce(base.emul, *args) else: return +reduce(base.emul, args) def div(*args): ''' Elementwise division for matrices. PURPOSE div(a1, ..., an) computes the elementwise division for matrices. The arguments must be matrices of compatible dimensions, and scalars. The elementwise division of a matrix and a scalar is a new matrix where each element is defined as the division between a matrix element and the scalar. div(iterable) where the iterator generates matrices and scalars computes the elementwise division between the objects in the iterator, using the same conventions as div(a1, ..., an). ''' if len(args) == 1 and type(args[0]).__name__ in \ ['list', 'tuple', 'xrange', 'range', 'generator']: return +reduce(base.ediv, *args) else: return +reduce(base.ediv, args) base.normal, base.uniform = normal, uniform base.setseed, base.getseed = setseed, getseed base.mul, base.div = mul, div from cvxopt import printing matrix_str = printing.matrix_str_default matrix_repr = printing.matrix_repr_default spmatrix_str = printing.spmatrix_str_default spmatrix_repr = printing.spmatrix_repr_default from cvxopt.base import matrix, spmatrix, sparse, spdiag, sqrt, sin, cos, \ exp, log __all__ = [ 'blas', 'lapack', 'amd', 'umfpack', 'cholmod', 'solvers', 'modeling', 'printing', 'info', 'matrix', 'spmatrix', 'sparse', 'spdiag', 'sqrt', 'sin', 'cos', 'exp', 'log', 'min', 'max', 'mul', 'div', 'normal', 'uniform', 'setseed', 'getseed' ] cvxopt-1.1.4/src/python/misc.py0000644000175000017500000015266311674452555015536 0ustar sonnesonne# Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import math from cvxopt import base, blas, lapack, cholmod, misc_solvers from cvxopt.base import matrix, spmatrix __all__ = [] use_C = True if use_C: scale = misc_solvers.scale else: def scale(x, W, trans = 'N', inverse = 'N'): """ Applies Nesterov-Todd scaling or its inverse. Computes x := W*x (trans is 'N', inverse = 'N') x := W^T*x (trans is 'T', inverse = 'N') x := W^{-1}*x (trans is 'N', inverse = 'I') x := W^{-T}*x (trans is 'T', inverse = 'I'). x is a dense 'd' matrix. W is a dictionary with entries: - W['dnl']: positive vector - W['dnli']: componentwise inverse of W['dnl'] - W['d']: positive vector - W['di']: componentwise inverse of W['d'] - W['v']: lists of 2nd order cone vectors with unit hyperbolic norms - W['beta']: list of positive numbers - W['r']: list of square matrices - W['rti']: list of square matrices. rti[k] is the inverse transpose of r[k]. The 'dnl' and 'dnli' entries are optional, and only present when the function is called from the nonlinear solver. """ ind = 0 # Scaling for nonlinear component xk is xk := dnl .* xk; inverse # scaling is xk ./ dnl = dnli .* xk, where dnl = W['dnl'], # dnli = W['dnli']. if 'dnl' in W: if inverse == 'N': w = W['dnl'] else: w = W['dnli'] for k in range(x.size[1]): blas.tbmv(w, x, n = w.size[0], k = 0, ldA = 1, offsetx = k*x.size[0]) ind += w.size[0] # Scaling for linear 'l' component xk is xk := d .* xk; inverse # scaling is xk ./ d = di .* xk, where d = W['d'], di = W['di']. if inverse == 'N': w = W['d'] else: w = W['di'] for k in range(x.size[1]): blas.tbmv(w, x, n = w.size[0], k = 0, ldA = 1, offsetx = k*x.size[0] + ind) ind += w.size[0] # Scaling for 'q' component is # # xk := beta * (2*v*v' - J) * xk # = beta * (2*v*(xk'*v)' - J*xk) # # where beta = W['beta'][k], v = W['v'][k], J = [1, 0; 0, -I]. # # Inverse scaling is # # xk := 1/beta * (2*J*v*v'*J - J) * xk # = 1/beta * (-J) * (2*v*((-J*xk)'*v)' + xk). w = matrix(0.0, (x.size[1], 1)) for k in range(len(W['v'])): v = W['v'][k] m = v.size[0] if inverse == 'I': blas.scal(-1.0, x, offset = ind, inc = x.size[0]) blas.gemv(x, v, w, trans = 'T', m = m, n = x.size[1], offsetA = ind, ldA = x.size[0]) blas.scal(-1.0, x, offset = ind, inc = x.size[0]) blas.ger(v, w, x, alpha = 2.0, m = m, n = x.size[1], ldA = x.size[0], offsetA = ind) if inverse == 'I': blas.scal(-1.0, x, offset = ind, inc = x.size[0]) a = 1.0 / W['beta'][k] else: a = W['beta'][k] for i in range(x.size[1]): blas.scal(a, x, n = m, offset = ind + i*x.size[0]) ind += m # Scaling for 's' component xk is # # xk := vec( r' * mat(xk) * r ) if trans = 'N' # xk := vec( r * mat(xk) * r' ) if trans = 'T'. # # r is kth element of W['r']. # # Inverse scaling is # # xk := vec( rti * mat(xk) * rti' ) if trans = 'N' # xk := vec( rti' * mat(xk) * rti ) if trans = 'T'. # # rti is kth element of W['rti']. maxn = max( [0] + [ r.size[0] for r in W['r'] ] ) a = matrix(0.0, (maxn, maxn)) for k in range(len(W['r'])): if inverse == 'N': r = W['r'][k] if trans == 'N': t = 'T' else: t = 'N' else: r = W['rti'][k] t = trans n = r.size[0] for i in range(x.size[1]): # scale diagonal of xk by 0.5 blas.scal(0.5, x, offset = ind + i*x.size[0], inc = n+1, n = n) # a = r*tril(x) (t is 'N') or a = tril(x)*r (t is 'T') blas.copy(r, a) if t == 'N': blas.trmm(x, a, side = 'R', m = n, n = n, ldA = n, ldB = n, offsetA = ind + i*x.size[0]) else: blas.trmm(x, a, side = 'L', m = n, n = n, ldA = n, ldB = n, offsetA = ind + i*x.size[0]) # x := (r*a' + a*r') if t is 'N' # x := (r'*a + a'*r) if t is 'T' blas.syr2k(r, a, x, trans = t, n = n, k = n, ldB = n, ldC = n, offsetC = ind + i*x.size[0]) ind += n**2 if use_C: scale2 = misc_solvers.scale2 else: def scale2(lmbda, x, dims, mnl = 0, inverse = 'N'): """ Evaluates x := H(lambda^{1/2}) * x (inverse is 'N') x := H(lambda^{-1/2}) * x (inverse is 'I'). H is the Hessian of the logarithmic barrier. """ # For the nonlinear and 'l' blocks, # # xk := xk ./ l (inverse is 'N') # xk := xk .* l (inverse is 'I') # # where l is lmbda[:mnl+dims['l']]. if inverse == 'N': blas.tbsv(lmbda, x, n = mnl + dims['l'], k = 0, ldA = 1) else: blas.tbmv(lmbda, x, n = mnl + dims['l'], k = 0, ldA = 1) # For 'q' blocks, if inverse is 'N', # # xk := 1/a * [ l'*J*xk; # xk[1:] - (xk[0] + l'*J*xk) / (l[0] + 1) * l[1:] ]. # # If inverse is 'I', # # xk := a * [ l'*xk; # xk[1:] + (xk[0] + l'*xk) / (l[0] + 1) * l[1:] ]. # # a = sqrt(lambda_k' * J * lambda_k), l = lambda_k / a. ind = mnl + dims['l'] for m in dims['q']: a = jnrm2(lmbda, n = m, offset = ind) if inverse == 'N': lx = jdot(lmbda, x, n = m, offsetx = ind, offsety = ind)/a else: lx = blas.dot(lmbda, x, n = m, offsetx = ind, offsety = ind)/a x0 = x[ind] x[ind] = lx c = (lx + x0) / (lmbda[ind]/a + 1) / a if inverse == 'N': c *= -1.0 blas.axpy(lmbda, x, alpha = c, n = m-1, offsetx = ind+1, offsety = ind+1) if inverse == 'N': a = 1.0/a blas.scal(a, x, offset = ind, n = m) ind += m # For the 's' blocks, if inverse is 'N', # # xk := vec( diag(l)^{-1/2} * mat(xk) * diag(k)^{-1/2}). # # If inverse is 'I', # # xk := vec( diag(l)^{1/2} * mat(xk) * diag(k)^{1/2}). # # where l is kth block of lambda. # # We scale upper and lower triangular part of mat(xk) because the # inverse operation will be applied to nonsymmetric matrices. ind2 = ind for k in range(len(dims['s'])): m = dims['s'][k] for j in range(m): c = math.sqrt(lmbda[ind2+j]) * base.sqrt(lmbda[ind2:ind2+m]) if inverse == 'N': blas.tbsv(c, x, n = m, k = 0, ldA = 1, offsetx = ind + j*m) else: blas.tbmv(c, x, n = m, k = 0, ldA = 1, offsetx = ind + j*m) ind += m*m ind2 += m def compute_scaling(s, z, lmbda, dims, mnl = None): """ Returns the Nesterov-Todd scaling W at points s and z, and stores the scaled variable in lmbda. W * z = W^{-T} * s = lmbda. """ W = {} # For the nonlinear block: # # W['dnl'] = sqrt( s[:mnl] ./ z[:mnl] ) # W['dnli'] = sqrt( z[:mnl] ./ s[:mnl] ) # lambda[:mnl] = sqrt( s[:mnl] .* z[:mnl] ) if mnl is None: mnl = 0 else: W['dnl'] = base.sqrt( base.div( s[:mnl], z[:mnl] )) W['dnli'] = W['dnl']**-1 lmbda[:mnl] = base.sqrt( base.mul( s[:mnl], z[:mnl] ) ) # For the 'l' block: # # W['d'] = sqrt( sk ./ zk ) # W['di'] = sqrt( zk ./ sk ) # lambdak = sqrt( sk .* zk ) # # where sk and zk are the first dims['l'] entries of s and z. # lambda_k is stored in the first dims['l'] positions of lmbda. m = dims['l'] W['d'] = base.sqrt( base.div( s[mnl:mnl+m], z[mnl:mnl+m] )) W['di'] = W['d']**-1 lmbda[mnl:mnl+m] = base.sqrt( base.mul( s[mnl:mnl+m], z[mnl:mnl+m] ) ) # For the 'q' blocks, compute lists 'v', 'beta'. # # The vector v[k] has unit hyperbolic norm: # # (sqrt( v[k]' * J * v[k] ) = 1 with J = [1, 0; 0, -I]). # # beta[k] is a positive scalar. # # The hyperbolic Householder matrix H = 2*v[k]*v[k]' - J # defined by v[k] satisfies # # (beta[k] * H) * zk = (beta[k] * H) \ sk = lambda_k # # where sk = s[indq[k]:indq[k+1]], zk = z[indq[k]:indq[k+1]]. # # lambda_k is stored in lmbda[indq[k]:indq[k+1]]. ind = mnl + dims['l'] W['v'] = [ matrix(0.0, (k,1)) for k in dims['q'] ] W['beta'] = len(dims['q']) * [ 0.0 ] for k in range(len(dims['q'])): m = dims['q'][k] v = W['v'][k] # a = sqrt( sk' * J * sk ) where J = [1, 0; 0, -I] aa = jnrm2(s, offset = ind, n = m) # b = sqrt( zk' * J * zk ) bb = jnrm2(z, offset = ind, n = m) # beta[k] = ( a / b )**1/2 W['beta'][k] = math.sqrt( aa / bb ) # c = sqrt( (sk/a)' * (zk/b) + 1 ) / sqrt(2) cc = math.sqrt( ( blas.dot(s, z, n = m, offsetx = ind, offsety = ind) / aa / bb + 1.0 ) / 2.0 ) # vk = 1/(2*c) * ( (sk/a) + J * (zk/b) ) blas.copy(z, v, offsetx = ind, n = m) blas.scal(-1.0/bb, v) v[0] *= -1.0 blas.axpy(s, v, 1.0/aa, offsetx = ind, n = m) blas.scal(1.0/2.0/cc, v) # v[k] = 1/sqrt(2*(vk0 + 1)) * ( vk + e ), e = [1; 0] v[0] += 1.0 blas.scal(1.0/math.sqrt(2.0 * v[0]), v) # To get the scaled variable lambda_k # # d = sk0/a + zk0/b + 2*c # lambda_k = [ c; # (c + zk0/b)/d * sk1/a + (c + sk0/a)/d * zk1/b ] # lambda_k *= sqrt(a * b) lmbda[ind] = cc dd = 2*cc + s[ind]/aa + z[ind]/bb blas.copy(s, lmbda, offsetx = ind+1, offsety = ind+1, n = m-1) blas.scal((cc + z[ind]/bb)/dd/aa, lmbda, n = m-1, offset = ind+1) blas.axpy(z, lmbda, (cc + s[ind]/aa)/dd/bb, n = m-1, offsetx = ind+1, offsety = ind+1) blas.scal(math.sqrt(aa*bb), lmbda, offset = ind, n = m) ind += m # For the 's' blocks: compute two lists 'r' and 'rti'. # # r[k]' * sk^{-1} * r[k] = diag(lambda_k)^{-1} # r[k]' * zk * r[k] = diag(lambda_k) # # where sk and zk are the entries inds[k] : inds[k+1] of # s and z, reshaped into symmetric matrices. # # rti[k] is the inverse of r[k]', so # # rti[k]' * sk * rti[k] = diag(lambda_k)^{-1} # rti[k]' * zk^{-1} * rti[k] = diag(lambda_k). # # The vectors lambda_k are stored in # # lmbda[ dims['l'] + sum(dims['q']) : -1 ] W['r'] = [ matrix(0.0, (m,m)) for m in dims['s'] ] W['rti'] = [ matrix(0.0, (m,m)) for m in dims['s'] ] work = matrix(0.0, (max( [0] + dims['s'] )**2, 1)) Ls = matrix(0.0, (max( [0] + dims['s'] )**2, 1)) Lz = matrix(0.0, (max( [0] + dims['s'] )**2, 1)) ind2 = ind for k in range(len(dims['s'])): m = dims['s'][k] r, rti = W['r'][k], W['rti'][k] # Factor sk = Ls*Ls'; store Ls in ds[inds[k]:inds[k+1]]. blas.copy(s, Ls, offsetx = ind2, n = m**2) lapack.potrf(Ls, n = m, ldA = m) # Factor zs[k] = Lz*Lz'; store Lz in dz[inds[k]:inds[k+1]]. blas.copy(z, Lz, offsetx = ind2, n = m**2) lapack.potrf(Lz, n = m, ldA = m) # SVD Lz'*Ls = U*diag(lambda_k)*V'. Keep U in work. for i in range(m): blas.scal(0.0, Ls, offset = i*m, n = i) blas.copy(Ls, work, n = m**2) blas.trmm(Lz, work, transA = 'T', ldA = m, ldB = m, n = m, m = m) lapack.gesvd(work, lmbda, jobu = 'O', ldA = m, m = m, n = m, offsetS = ind) # r = Lz^{-T} * U blas.copy(work, r, n = m*m) blas.trsm(Lz, r, transA = 'T', m = m, n = m, ldA = m) # rti = Lz * U blas.copy(work, rti, n = m*m) blas.trmm(Lz, rti, m = m, n = m, ldA = m) # r := r * diag(sqrt(lambda_k)) # rti := rti * diag(1 ./ sqrt(lambda_k)) for i in range(m): a = math.sqrt( lmbda[ind+i] ) blas.scal(a, r, offset = m*i, n = m) blas.scal(1.0/a, rti, offset = m*i, n = m) ind += m ind2 += m*m return W def update_scaling(W, lmbda, s, z): """ Updates the Nesterov-Todd scaling matrix W and the scaled variable lmbda so that on exit W * zt = W^{-T} * st = lmbda. On entry, the nonlinear, 'l' and 'q' components of the arguments s and z contain W^{-T}*st and W*zt, i.e, the new iterates in the current scaling. The 's' components contain the factors Ls, Lz in a factorization of the new iterates in the current scaling, W^{-T}*st = Ls*Ls', W*zt = Lz*Lz'. """ # Nonlinear and 'l' blocks # # d := d .* sqrt( s ./ z ) # lmbda := lmbda .* sqrt(s) .* sqrt(z) if 'dnl' in W: mnl = len(W['dnl']) else: mnl = 0 ml = len(W['d']) m = mnl + ml s[:m] = base.sqrt( s[:m] ) z[:m] = base.sqrt( z[:m] ) # d := d .* s .* z if 'dnl' in W: blas.tbmv(s, W['dnl'], n = mnl, k = 0, ldA = 1) blas.tbsv(z, W['dnl'], n = mnl, k = 0, ldA = 1) W['dnli'][:] = W['dnl'][:] ** -1 blas.tbmv(s, W['d'], n = ml, k = 0, ldA = 1, offsetA = mnl) blas.tbsv(z, W['d'], n = ml, k = 0, ldA = 1, offsetA = mnl) W['di'][:] = W['d'][:] ** -1 # lmbda := s .* z blas.copy(s, lmbda, n = m) blas.tbmv(z, lmbda, n = m, k = 0, ldA = 1) # 'q' blocks. # # Let st and zt be the new variables in the old scaling: # # st = s_k, zt = z_k # # and a = sqrt(st' * J * st), b = sqrt(zt' * J * zt). # # 1. Compute the hyperbolic Householder transformation 2*q*q' - J # that maps st/a to zt/b. # # c = sqrt( (1 + st'*zt/(a*b)) / 2 ) # q = (st/a + J*zt/b) / (2*c). # # The new scaling point is # # wk := betak * sqrt(a/b) * (2*v[k]*v[k]' - J) * q # # with betak = W['beta'][k]. # # 3. The scaled variable: # # lambda_k0 = sqrt(a*b) * c # lambda_k1 = sqrt(a*b) * ( (2vk*vk' - J) * (-d*q + u/2) )_1 # # where # # u = st/a - J*zt/b # d = ( vk0 * (vk'*u) + u0/2 ) / (2*vk0 *(vk'*q) - q0 + 1). # # 4. Update scaling # # v[k] := wk^1/2 # = 1 / sqrt(2*(wk0 + 1)) * (wk + e). # beta[k] *= sqrt(a/b) ind = m for k in range(len(W['v'])): v = W['v'][k] m = len(v) # ln = sqrt( lambda_k' * J * lambda_k ) ln = jnrm2(lmbda, n = m, offset = ind) # a = sqrt( sk' * J * sk ) = sqrt( st' * J * st ) # s := s / a = st / a aa = jnrm2(s, offset = ind, n = m) blas.scal(1.0/aa, s, offset = ind, n = m) # b = sqrt( zk' * J * zk ) = sqrt( zt' * J * zt ) # z := z / a = zt / b bb = jnrm2(z, offset = ind, n = m) blas.scal(1.0/bb, z, offset = ind, n = m) # c = sqrt( ( 1 + (st'*zt) / (a*b) ) / 2 ) cc = math.sqrt( ( 1.0 + blas.dot(s, z, offsetx = ind, offsety = ind, n = m) ) / 2.0 ) # vs = v' * st / a vs = blas.dot(v, s, offsety = ind, n = m) # vz = v' * J *zt / b vz = jdot(v, z, offsety = ind, n = m) # vq = v' * q where q = (st/a + J * zt/b) / (2 * c) vq = (vs + vz ) / 2.0 / cc # vu = v' * u where u = st/a - J * zt/b vu = vs - vz # lambda_k0 = c lmbda[ind] = cc # wk0 = 2 * vk0 * (vk' * q) - q0 wk0 = 2 * v[0] * vq - ( s[ind] + z[ind] ) / 2.0 / cc # d = (v[0] * (vk' * u) - u0/2) / (wk0 + 1) dd = (v[0] * vu - s[ind]/2.0 + z[ind]/2.0) / (wk0 + 1.0) # lambda_k1 = 2 * v_k1 * vk' * (-d*q + u/2) - d*q1 + u1/2 blas.copy(v, lmbda, offsetx = 1, offsety = ind+1, n = m-1) blas.scal(2.0 * (-dd * vq + 0.5 * vu), lmbda, offset = ind+1, n = m-1) blas.axpy(s, lmbda, 0.5 * (1.0 - dd/cc), offsetx = ind+1, offsety = ind+1, n = m-1) blas.axpy(z, lmbda, 0.5 * (1.0 + dd/cc), offsetx = ind+1, offsety = ind+1, n = m-1) # Scale so that sqrt(lambda_k' * J * lambda_k) = sqrt(aa*bb). blas.scal(math.sqrt(aa*bb), lmbda, offset = ind, n = m) # v := (2*v*v' - J) * q # = 2 * (v'*q) * v' - (J* st/a + zt/b) / (2*c) blas.scal(2.0 * vq, v) v[0] -= s[ind] / 2.0 / cc blas.axpy(s, v, 0.5/cc, offsetx = ind+1, offsety = 1, n = m-1) blas.axpy(z, v, -0.5/cc, offsetx = ind, n = m) # v := v^{1/2} = 1/sqrt(2 * (v0 + 1)) * (v + e) v[0] += 1.0 blas.scal(1.0 / math.sqrt(2.0 * v[0]), v) # beta[k] *= ( aa / bb )**1/2 W['beta'][k] *= math.sqrt( aa / bb ) ind += m # 's' blocks # # Let st, zt be the updated variables in the old scaling: # # st = Ls * Ls', zt = Lz * Lz'. # # where Ls and Lz are the 's' components of s, z. # # 1. SVD Lz'*Ls = Uk * lambda_k^+ * Vk'. # # 2. New scaling is # # r[k] := r[k] * Ls * Vk * diag(lambda_k^+)^{-1/2} # rti[k] := r[k] * Lz * Uk * diag(lambda_k^+)^{-1/2}. # work = matrix(0.0, (max( [0] + [r.size[0] for r in W['r']])**2, 1)) ind = mnl + ml + sum([ len(v) for v in W['v'] ]) ind2, ind3 = ind, 0 for k in range(len(W['r'])): r, rti = W['r'][k], W['rti'][k] m = r.size[0] # r := r*sk = r*Ls blas.gemm(r, s, work, m = m, n = m, k = m, ldB = m, ldC = m, offsetB = ind2) blas.copy(work, r, n = m**2) # rti := rti*zk = rti*Lz blas.gemm(rti, z, work, m = m, n = m, k = m, ldB = m, ldC = m, offsetB = ind2) blas.copy(work, rti, n = m**2) # SVD Lz'*Ls = U * lmbds^+ * V'; store U in sk and V' in zk. blas.gemm(z, s, work, transA = 'T', m = m, n = m, k = m, ldA = m, ldB = m, ldC = m, offsetA = ind2, offsetB = ind2) lapack.gesvd(work, lmbda, jobu = 'A', jobvt = 'A', m = m, n = m, ldA = m, U = s, Vt = z, ldU = m, ldVt = m, offsetS = ind, offsetU = ind2, offsetVt = ind2) # r := r*V blas.gemm(r, z, work, transB = 'T', m = m, n = m, k = m, ldB = m, ldC = m, offsetB = ind2) blas.copy(work, r, n = m**2) # rti := rti*U blas.gemm(rti, s, work, n = m, m = m, k = m, ldB = m, ldC = m, offsetB = ind2) blas.copy(work, rti, n = m**2) # r := r*lambda^{-1/2}; rti := rti*lambda^{-1/2} for i in range(m): a = 1.0 / math.sqrt(lmbda[ind+i]) blas.scal(a, r, offset = m*i, n = m) blas.scal(a, rti, offset = m*i, n = m) ind += m ind2 += m*m ind3 += m if use_C: pack = misc_solvers.pack else: def pack(x, y, dims, mnl = 0, offsetx = 0, offsety = 0): """ Copy x to y using packed storage. The vector x is an element of S, with the 's' components stored in unpacked storage. On return, x is copied to y with the 's' components stored in packed storage and the off-diagonal entries scaled by sqrt(2). """ nlq = mnl + dims['l'] + sum(dims['q']) blas.copy(x, y, n = nlq, offsetx = offsetx, offsety = offsety) iu, ip = offsetx + nlq, offsety + nlq for n in dims['s']: for k in range(n): blas.copy(x, y, n = n-k, offsetx = iu + k*(n+1), offsety = ip) y[ip] /= math.sqrt(2) ip += n-k iu += n**2 np = sum([ int(n*(n+1)/2) for n in dims['s'] ]) blas.scal(math.sqrt(2.0), y, n = np, offset = offsety+nlq) if use_C: pack2 = misc_solvers.pack2 else: def pack2(x, dims, mnl = 0): """ In-place version of pack(), which also accepts matrix arguments x. The columns of x are elements of S, with the 's' components stored in unpacked storage. On return, the 's' components are stored in packed storage and the off-diagonal entries are scaled by sqrt(2). """ if not dims['s']: return iu = mnl + dims['l'] + sum(dims['q']) ip = iu for n in dims['s']: for k in range(n): x[ip, :] = x[iu + (n+1)*k, :] x[ip + 1 : ip+n-k, :] = x[iu + (n+1)*k + 1: iu + n*(k+1), :] \ * math.sqrt(2.0) ip += n - k iu += n**2 np = sum([ int(n*(n+1)/2) for n in dims['s'] ]) if use_C: unpack = misc_solvers.unpack else: def unpack(x, y, dims, mnl = 0, offsetx = 0, offsety = 0): """ The vector x is an element of S, with the 's' components stored in unpacked storage and off-diagonal entries scaled by sqrt(2). On return, x is copied to y with the 's' components stored in unpacked storage. """ nlq = mnl + dims['l'] + sum(dims['q']) blas.copy(x, y, n = nlq, offsetx = offsetx, offsety = offsety) iu, ip = offsety+nlq, offsetx+nlq for n in dims['s']: for k in range(n): blas.copy(x, y, n = n-k, offsetx = ip, offsety = iu+k*(n+1)) y[iu+k*(n+1)] *= math.sqrt(2) ip += n-k iu += n**2 nu = sum([ n**2 for n in dims['s'] ]) blas.scal(1.0/math.sqrt(2.0), y, n = nu, offset = offsety+nlq) if use_C: sdot = misc_solvers.sdot else: def sdot(x, y, dims, mnl = 0): """ Inner product of two vectors in S. """ ind = mnl + dims['l'] + sum(dims['q']) a = blas.dot(x, y, n = ind) for m in dims['s']: a += blas.dot(x, y, offsetx = ind, offsety = ind, incx = m+1, incy = m+1, n = m) for j in range(1, m): a += 2.0 * blas.dot(x, y, incx = m+1, incy = m+1, offsetx = ind+j, offsety = ind+j, n = m-j) ind += m**2 return a def sdot2(x, y): """ Inner product of two block-diagonal symmetric dense 'd' matrices. x and y are square dense 'd' matrices, or lists of N square dense 'd' matrices. """ a = 0.0 if type(x) is matrix: n = x.size[0] a += blas.dot(x, y, incx=n+1, incy=n+1, n=n) for j in range(1,n): a += 2.0 * blas.dot(x, y, incx=n+1, incy=n+1, offsetx=j, offsety=j, n=n-j) else: for k in range(len(x)): n = x[k].size[0] a += blas.dot(x[k], y[k], incx=n+1, incy=n+1, n=n) for j in range(1,n): a += 2.0 * blas.dot(x[k], y[k], incx=n+1, incy=n+1, offsetx=j, offsety=j, n=n-j) return a def snrm2(x, dims, mnl = 0): """ Returns the norm of a vector in S """ return math.sqrt(sdot(x, x, dims, mnl)) if use_C: trisc = misc_solvers.trisc else: def trisc(x, dims, offset = 0): """ Sets upper triangular part of the 's' components of x equal to zero and scales the strictly lower triangular part by 2.0. """ m = dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) ind = offset + dims['l'] + sum(dims['q']) for mk in dims['s']: for j in range(1, mk): blas.scal(0.0, x, n = mk-j, inc = mk, offset = ind + j*(mk + 1) - 1) blas.scal(2.0, x, offset = ind + mk*(j-1) + j, n = mk-j) ind += mk**2 if use_C: triusc = misc_solvers.triusc else: def triusc(x, dims, offset = 0): """ Scales the strictly lower triangular part of the 's' components of x by 0.5. """ m = dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) ind = offset + dims['l'] + sum(dims['q']) for mk in dims['s']: for j in range(1, mk): blas.scal(0.5, x, offset = ind + mk*(j-1) + j, n = mk-j) ind += mk**2 def sgemv(A, x, y, dims, trans = 'N', alpha = 1.0, beta = 0.0, n = None, offsetA = 0, offsetx = 0, offsety = 0): """ Matrix-vector multiplication. A is a matrix or spmatrix of size (m, n) where N = dims['l'] + sum(dims['q']) + sum( k**2 for k in dims['s'] ) representing a mapping from R^n to S. If trans is 'N': y := alpha*A*x + beta * y (trans = 'N'). x is a vector of length n. y is a vector of length N. If trans is 'T': y := alpha*A'*x + beta * y (trans = 'T'). x is a vector of length N. y is a vector of length n. The 's' components in S are stored in unpacked 'L' storage. """ m = dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) if n is None: n = A.size[1] if trans == 'T' and alpha: trisc(x, dims, offsetx) base.gemv(A, x, y, trans = trans, alpha = alpha, beta = beta, m = m, n = n, offsetA = offsetA, offsetx = offsetx, offsety = offsety) if trans == 'T' and alpha: triusc(x, dims, offsetx) def jdot(x, y, n = None, offsetx = 0, offsety = 0): """ Returns x' * J * y, where J = [1, 0; 0, -I]. """ if n is None: if len(x) != len(y): raise ValueError("x and y must have the "\ "same length") n = len(x) return x[offsetx] * y[offsety] - blas.dot(x, y, n = n-1, offsetx = offsetx + 1, offsety = offsety + 1) def jnrm2(x, n = None, offset = 0): """ Returns sqrt(x' * J * x) where J = [1, 0; 0, -I], for a vector x in a second order cone. """ if n is None: n = len(x) a = blas.nrm2(x, n = n-1, offset = offset+1) return math.sqrt(x[offset] - a) * math.sqrt(x[offset] + a) if use_C: symm = misc_solvers.symm else: def symm(x, n, offset = 0): """ Converts lower triangular matrix to symmetric. Fills in the upper triangular part of the symmetric matrix stored in x[offset : offset+n*n] using 'L' storage. """ if n <= 1: return for i in range(n-1): blas.copy(x, x, offsetx = offset + i*(n+1) + 1, offsety = offset + (i+1)*(n+1) - 1, incy = n, n = n-i-1) if use_C: sprod = misc_solvers.sprod else: def sprod(x, y, dims, mnl = 0, diag = 'N'): """ The product x := (y o x). If diag is 'D', the 's' part of y is diagonal and only the diagonal is stored. """ # For the nonlinear and 'l' blocks: # # yk o xk = yk .* xk. blas.tbmv(y, x, n = mnl + dims['l'], k = 0, ldA = 1) # For 'q' blocks: # # [ l0 l1' ] # yk o xk = [ ] * xk # [ l1 l0*I ] # # where yk = (l0, l1). ind = mnl + dims['l'] for m in dims['q']: dd = blas.dot(x, y, offsetx = ind, offsety = ind, n = m) blas.scal(y[ind], x, offset = ind+1, n = m-1) blas.axpy(y, x, alpha = x[ind], n = m-1, offsetx = ind+1, offsety = ind+1) x[ind] = dd ind += m # For the 's' blocks: # # yk o sk = .5 * ( Yk * mat(xk) + mat(xk) * Yk ) # # where Yk = mat(yk) if diag is 'N' and Yk = diag(yk) if diag is 'D'. if diag is 'N': maxm = max([0] + dims['s']) A = matrix(0.0, (maxm, maxm)) for m in dims['s']: blas.copy(x, A, offsetx = ind, n = m*m) # Write upper triangular part of A and yk. for i in range(m-1): symm(A, m) symm(y, m, offset = ind) # xk = 0.5 * (A*yk + yk*A) blas.syr2k(A, y, x, alpha = 0.5, n = m, k = m, ldA = m, ldB = m, ldC = m, offsetB = ind, offsetC = ind) ind += m*m else: ind2 = ind for m in dims['s']: for j in range(m): u = 0.5 * ( y[ind2+j:ind2+m] + y[ind2+j] ) blas.tbmv(u, x, n = m-j, k = 0, ldA = 1, offsetx = ind + j*(m+1)) ind += m*m ind2 += m def ssqr(x, y, dims, mnl = 0): """ The product x := y o y. The 's' components of y are diagonal and only the diagonals of x and y are stored. """ blas.copy(y, x) blas.tbmv(y, x, n = mnl + dims['l'], k = 0, ldA = 1) ind = mnl + dims['l'] for m in dims['q']: x[ind] = blas.nrm2(y, offset = ind, n = m)**2 blas.scal(2.0*y[ind], x, n = m-1, offset = ind+1) ind += m blas.tbmv(y, x, n = sum(dims['s']), k = 0, ldA = 1, offsetA = ind, offsetx = ind) if use_C: sinv = misc_solvers.sinv else: def sinv(x, y, dims, mnl = 0): """ The inverse product x := (y o\ x), when the 's' components of y are diagonal. """ # For the nonlinear and 'l' blocks: # # yk o\ xk = yk .\ xk. blas.tbsv(y, x, n = mnl + dims['l'], k = 0, ldA = 1) # For the 'q' blocks: # # [ l0 -l1' ] # yk o\ xk = 1/a^2 * [ ] * xk # [ -l1 (a*I + l1*l1')/l0 ] # # where yk = (l0, l1) and a = l0^2 - l1'*l1. ind = mnl + dims['l'] for m in dims['q']: aa = jnrm2(y, n = m, offset = ind)**2 cc = x[ind] dd = blas.dot(y, x, offsetx = ind+1, offsety = ind+1, n = m-1) x[ind] = cc * y[ind] - dd blas.scal(aa / y[ind], x, n = m-1, offset = ind+1) blas.axpy(y, x, alpha = dd/y[ind] - cc, n = m-1, offsetx = ind+1, offsety = ind+1) blas.scal(1.0/aa, x, n = m, offset = ind) ind += m # For the 's' blocks: # # yk o\ xk = xk ./ gamma # # where gammaij = .5 * (yk_i + yk_j). ind2 = ind for m in dims['s']: for j in range(m): u = 0.5 * ( y[ind2+j:ind2+m] + y[ind2+j] ) blas.tbsv(u, x, n = m-j, k = 0, ldA = 1, offsetx = ind + j*(m+1)) ind += m*m ind2 += m if use_C: max_step = misc_solvers.max_step else: def max_step(x, dims, mnl = 0, sigma = None): """ Returns min {t | x + t*e >= 0}, where e is defined as follows - For the nonlinear and 'l' blocks: e is the vector of ones. - For the 'q' blocks: e is the first unit vector. - For the 's' blocks: e is the identity matrix. When called with the argument sigma, also returns the eigenvalues (in sigma) and the eigenvectors (in x) of the 's' components of x. """ t = [] ind = mnl + dims['l'] if ind: t += [ -min(x[:ind]) ] for m in dims['q']: if m: t += [ blas.nrm2(x, offset = ind + 1, n = m-1) - x[ind] ] ind += m if sigma is None and dims['s']: Q = matrix(0.0, (max(dims['s']), max(dims['s']))) w = matrix(0.0, (max(dims['s']),1)) ind2 = 0 for m in dims['s']: if sigma is None: blas.copy(x, Q, offsetx = ind, n = m**2) lapack.syevr(Q, w, range = 'I', il = 1, iu = 1, n = m, ldA = m) if m: t += [ -w[0] ] else: lapack.syevd(x, sigma, jobz = 'V', n = m, ldA = m, offsetA = ind, offsetW = ind2) if m: t += [ -sigma[ind2] ] ind += m*m ind2 += m if t: return max(t) else: return 0.0 def kkt_ldl(G, dims, A, mnl = 0): """ Solution of KKT equations by a dense LDL factorization of the 3 x 3 system. Returns a function that (1) computes the LDL factorization of [ H A' GG'*W^{-1} ] [ A 0 0 ], [ W^{-T}*GG 0 -I ] given H, Df, W, where GG = [Df; G], and (2) returns a function for solving [ H A' GG' ] [ ux ] [ bx ] [ A 0 0 ] * [ uy ] = [ by ]. [ GG 0 -W'*W ] [ uz ] [ bz ] H is n x n, A is p x n, Df is mnl x n, G is N x n where N = dims['l'] + sum(dims['q']) + sum( k**2 for k in dims['s'] ). """ p, n = A.size ldK = n + p + mnl + dims['l'] + sum(dims['q']) + sum([ int(k*(k+1)/2) for k in dims['s'] ]) K = matrix(0.0, (ldK, ldK)) ipiv = matrix(0, (ldK, 1)) u = matrix(0.0, (ldK, 1)) g = matrix(0.0, (mnl + G.size[0], 1)) def factor(W, H = None, Df = None): blas.scal(0.0, K) if H is not None: K[:n, :n] = H K[n:n+p, :n] = A for k in range(n): if mnl: g[:mnl] = Df[:,k] g[mnl:] = G[:,k] scale(g, W, trans = 'T', inverse = 'I') pack(g, K, dims, mnl, offsety = k*ldK + n + p) K[(ldK+1)*(p+n) :: ldK+1] = -1.0 lapack.sytrf(K, ipiv) def solve(x, y, z): # Solve # # [ H A' GG'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] * [ uy [ = [ by ] # [ W^{-T}*GG 0 -I ] [ W*uz ] [ W^{-T}*bz ] # # and return ux, uy, W*uz. # # On entry, x, y, z contain bx, by, bz. On exit, they contain # the solution ux, uy, W*uz. blas.copy(x, u) blas.copy(y, u, offsety = n) scale(z, W, trans = 'T', inverse = 'I') pack(z, u, dims, mnl, offsety = n + p) lapack.sytrs(K, ipiv, u) blas.copy(u, x, n = n) blas.copy(u, y, offsetx = n, n = p) unpack(u, z, dims, mnl, offsetx = n + p) return solve return factor def kkt_ldl2(G, dims, A, mnl = 0): """ Solution of KKT equations by a dense LDL factorization of the 2 x 2 system. Returns a function that (1) computes the LDL factorization of [ H + GG' * W^{-1} * W^{-T} * GG A' ] [ ] [ A 0 ] given H, Df, W, where GG = [Df; G], and (2) returns a function for solving [ H A' GG' ] [ ux ] [ bx ] [ A 0 0 ] * [ uy ] = [ by ]. [ GG 0 -W'*W ] [ uz ] [ bz ] H is n x n, A is p x n, Df is mnl x n, G is N x n where N = dims['l'] + sum(dims['q']) + sum( k**2 for k in dims['s'] ). """ p, n = A.size ldK = n + p K = matrix(0.0, (ldK, ldK)) if p: ipiv = matrix(0, (ldK, 1)) g = matrix(0.0, (mnl + G.size[0], 1)) u = matrix(0.0, (ldK, 1)) def factor(W, H = None, Df = None): blas.scal(0.0, K) if H is not None: K[:n, :n] = H K[n:,:n] = A for k in range(n): if mnl: g[:mnl] = Df[:,k] g[mnl:] = G[:,k] scale(g, W, trans = 'T', inverse = 'I') scale(g, W, inverse = 'I') if mnl: base.gemv(Df, g, K, trans = 'T', beta = 1.0, n = n-k, offsetA = mnl*k, offsety = (ldK + 1)*k) sgemv(G, g, K, dims, trans = 'T', beta = 1.0, n = n-k, offsetA = G.size[0]*k, offsetx = mnl, offsety = (ldK + 1)*k) if p: lapack.sytrf(K, ipiv) else: lapack.potrf(K) def solve(x, y, z): # Solve # # [ H + GG' * W^{-1} * W^{-T} * GG A' ] [ ux ] # [ ] * [ ] # [ A 0 ] [ uy ] # # [ bx + GG' * W^{-1} * W^{-T} * bz ] # = [ ] # [ by ] # # and return x, y, W*z = W^{-T} * (GG*x - bz). blas.copy(z, g) scale(g, W, trans = 'T', inverse = 'I') scale(g, W, inverse = 'I') if mnl: base.gemv(Df, g, u, trans = 'T') beta = 1.0 else: beta = 0.0 sgemv(G, g, u, dims, trans = 'T', offsetx = mnl, beta = beta) blas.axpy(x, u) blas.copy(y, u, offsety = n) if p: lapack.sytrs(K, ipiv, u) else: lapack.potrs(K, u) blas.copy(u, x, n = n) blas.copy(u, y, offsetx = n, n = p) if mnl: base.gemv(Df, x, z, alpha = 1.0, beta = -1.0) sgemv(G, x, z, dims, alpha = 1.0, beta = -1.0, offsety = mnl) scale(z, W, trans = 'T', inverse = 'I') return solve return factor def kkt_chol(G, dims, A, mnl = 0): """ Solution of KKT equations by reduction to a 2 x 2 system, a QR factorization to eliminate the equality constraints, and a dense Cholesky factorization of order n-p. Computes the QR factorization A' = [Q1, Q2] * [R; 0] and returns a function that (1) computes the Cholesky factorization Q_2^T * (H + GG^T * W^{-1} * W^{-T} * GG) * Q2 = L * L^T, given H, Df, W, where GG = [Df; G], and (2) returns a function for solving [ H A' GG' ] [ ux ] [ bx ] [ A 0 0 ] * [ uy ] = [ by ]. [ GG 0 -W'*W ] [ uz ] [ bz ] H is n x n, A is p x n, Df is mnl x n, G is N x n where N = dims['l'] + sum(dims['q']) + sum( k**2 for k in dims['s'] ). """ p, n = A.size cdim = mnl + dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) cdim_pckd = mnl + dims['l'] + sum(dims['q']) + sum([ int(k*(k+1)/2) for k in dims['s'] ]) # A' = [Q1, Q2] * [R; 0] (Q1 is n x p, Q2 is n x n-p). if type(A) is matrix: QA = A.T else: QA = matrix(A.T) tauA = matrix(0.0, (p,1)) lapack.geqrf(QA, tauA) Gs = matrix(0.0, (cdim, n)) K = matrix(0.0, (n,n)) bzp = matrix(0.0, (cdim_pckd, 1)) yy = matrix(0.0, (p,1)) def factor(W, H = None, Df = None): # Compute # # K = [Q1, Q2]' * (H + GG' * W^{-1} * W^{-T} * GG) * [Q1, Q2] # # and take the Cholesky factorization of the 2,2 block # # Q_2' * (H + GG^T * W^{-1} * W^{-T} * GG) * Q2. # Gs = W^{-T} * GG in packed storage. if mnl: Gs[:mnl, :] = Df Gs[mnl:, :] = G scale(Gs, W, trans = 'T', inverse = 'I') pack2(Gs, dims, mnl) # K = [Q1, Q2]' * (H + Gs' * Gs) * [Q1, Q2]. blas.syrk(Gs, K, k = cdim_pckd, trans = 'T') if H is not None: K[:,:] += H symm(K, n) lapack.ormqr(QA, tauA, K, side = 'L', trans = 'T') lapack.ormqr(QA, tauA, K, side = 'R') # Cholesky factorization of 2,2 block of K. lapack.potrf(K, n = n-p, offsetA = p*(n+1)) def solve(x, y, z): # Solve # # [ 0 A' GG'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] * [ uy ] = [ by ] # [ W^{-T}*GG 0 -I ] [ W*uz ] [ W^{-T}*bz ] # # and return ux, uy, W*uz. # # On entry, x, y, z contain bx, by, bz. On exit, they contain # the solution ux, uy, W*uz. # # If we change variables ux = Q1*v + Q2*w, the system becomes # # [ K11 K12 R ] [ v ] [Q1'*(bx+GG'*W^{-1}*W^{-T}*bz)] # [ K21 K22 0 ] * [ w ] = [Q2'*(bx+GG'*W^{-1}*W^{-T}*bz)] # [ R^T 0 0 ] [ uy ] [by ] # # W*uz = W^{-T} * ( GG*ux - bz ). # bzp := W^{-T} * bz in packed storage scale(z, W, trans = 'T', inverse = 'I') pack(z, bzp, dims, mnl) # x := [Q1, Q2]' * (x + Gs' * bzp) # = [Q1, Q2]' * (bx + Gs' * W^{-T} * bz) blas.gemv(Gs, bzp, x, beta = 1.0, trans = 'T', m = cdim_pckd) lapack.ormqr(QA, tauA, x, side = 'L', trans = 'T') # y := x[:p] # = Q1' * (bx + Gs' * W^{-T} * bz) blas.copy(y, yy) blas.copy(x, y, n = p) # x[:p] := v = R^{-T} * by blas.copy(yy, x) lapack.trtrs(QA, x, uplo = 'U', trans = 'T', n = p) # x[p:] := K22^{-1} * (x[p:] - K21*x[:p]) # = K22^{-1} * (Q2' * (bx + Gs' * W^{-T} * bz) - K21*v) blas.gemv(K, x, x, alpha = -1.0, beta = 1.0, m = n-p, n = p, offsetA = p, offsety = p) lapack.potrs(K, x, n = n-p, offsetA = p*(n+1), offsetB = p) # y := y - [K11, K12] * x # = Q1' * (bx + Gs' * W^{-T} * bz) - K11*v - K12*w blas.gemv(K, x, y, alpha = -1.0, beta = 1.0, m = p, n = n) # y := R^{-1}*y # = R^{-1} * (Q1' * (bx + Gs' * W^{-T} * bz) - K11*v # - K12*w) lapack.trtrs(QA, y, uplo = 'U', n = p) # x := [Q1, Q2] * x lapack.ormqr(QA, tauA, x, side = 'L') # bzp := Gs * x - bzp. # = W^{-T} * ( GG*ux - bz ) in packed storage. # Unpack and copy to z. blas.gemv(Gs, x, bzp, alpha = 1.0, beta = -1.0, m = cdim_pckd) unpack(bzp, z, dims, mnl) return solve return factor def kkt_chol2(G, dims, A, mnl = 0): """ Solution of KKT equations by reduction to a 2 x 2 system, a sparse or dense Cholesky factorization of order n to eliminate the 1,1 block, and a sparse or dense Cholesky factorization of order p. Implemented only for problems with no second-order or semidefinite cone constraints. Returns a function that (1) computes Cholesky factorizations of the matrices S = H + GG' * W^{-1} * W^{-T} * GG, K = A * S^{-1} *A' or (if K is singular in the first call to the function), the matrices S = H + GG' * W^{-1} * W^{-T} * GG + A' * A, K = A * S^{-1} * A', given H, Df, W, where GG = [Df; G], and (2) returns a function for solving [ H A' GG' ] [ ux ] [ bx ] [ A 0 0 ] * [ uy ] = [ by ]. [ GG 0 -W'*W ] [ uz ] [ bz ] H is n x n, A is p x n, Df is mnl x n, G is dims['l'] x n. """ if dims['q'] or dims['s']: raise ValueError("kktsolver option 'kkt_chol2' is implemented "\ "only for problems with no second-order or semidefinite cone "\ "constraints") p, n = A.size ml = dims['l'] F = {'firstcall': True, 'singular': False} def factor(W, H = None, Df = None): if F['firstcall']: if type(G) is matrix: F['Gs'] = matrix(0.0, G.size) else: F['Gs'] = spmatrix(0.0, G.I, G.J, G.size) if mnl: if type(Df) is matrix: F['Dfs'] = matrix(0.0, Df.size) else: F['Dfs'] = spmatrix(0.0, Df.I, Df.J, Df.size) if (mnl and type(Df) is matrix) or type(G) is matrix or \ type(H) is matrix: F['S'] = matrix(0.0, (n,n)) F['K'] = matrix(0.0, (p,p)) else: F['S'] = spmatrix([], [], [], (n,n), 'd') F['Sf'] = None if type(A) is matrix: F['K'] = matrix(0.0, (p,p)) else: F['K'] = spmatrix([], [], [], (p,p), 'd') # Dfs = Wnl^{-1} * Df if mnl: base.gemm(spmatrix(W['dnli'], list(range(mnl)), list(range(mnl))), Df, F['Dfs'], partial = True) # Gs = Wl^{-1} * G. base.gemm(spmatrix(W['di'], list(range(ml)), list(range(ml))), G, F['Gs'], partial = True) if F['firstcall']: base.syrk(F['Gs'], F['S'], trans = 'T') if mnl: base.syrk(F['Dfs'], F['S'], trans = 'T', beta = 1.0) if H is not None: F['S'] += H try: if type(F['S']) is matrix: lapack.potrf(F['S']) else: F['Sf'] = cholmod.symbolic(F['S']) cholmod.numeric(F['S'], F['Sf']) except ArithmeticError: F['singular'] = True if type(A) is matrix and type(F['S']) is spmatrix: F['S'] = matrix(0.0, (n,n)) base.syrk(F['Gs'], F['S'], trans = 'T') if mnl: base.syrk(F['Dfs'], F['S'], trans = 'T', beta = 1.0) base.syrk(A, F['S'], trans = 'T', beta = 1.0) if H is not None: F['S'] += H if type(F['S']) is matrix: lapack.potrf(F['S']) else: F['Sf'] = cholmod.symbolic(F['S']) cholmod.numeric(F['S'], F['Sf']) F['firstcall'] = False else: base.syrk(F['Gs'], F['S'], trans = 'T', partial = True) if mnl: base.syrk(F['Dfs'], F['S'], trans = 'T', beta = 1.0, partial = True) if H is not None: F['S'] += H if F['singular']: base.syrk(A, F['S'], trans = 'T', beta = 1.0, partial = True) if type(F['S']) is matrix: lapack.potrf(F['S']) else: cholmod.numeric(F['S'], F['Sf']) if type(F['S']) is matrix: # Asct := L^{-1}*A'. Factor K = Asct'*Asct. if type(A) is matrix: Asct = A.T else: Asct = matrix(A.T) blas.trsm(F['S'], Asct) blas.syrk(Asct, F['K'], trans = 'T') lapack.potrf(F['K']) else: # Asct := L^{-1}*P*A'. Factor K = Asct'*Asct. if type(A) is matrix: Asct = A.T cholmod.solve(F['Sf'], Asct, sys = 7) cholmod.solve(F['Sf'], Asct, sys = 4) blas.syrk(Asct, F['K'], trans = 'T') lapack.potrf(F['K']) else: Asct = cholmod.spsolve(F['Sf'], A.T, sys = 7) Asct = cholmod.spsolve(F['Sf'], Asct, sys = 4) base.syrk(Asct, F['K'], trans = 'T') Kf = cholmod.symbolic(F['K']) cholmod.numeric(F['K'], Kf) def solve(x, y, z): # Solve # # [ H A' GG'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] * [ uy ] = [ by ] # [ W^{-T}*GG 0 -I ] [ W*uz ] [ W^{-T}*bz ] # # and return ux, uy, W*uz. # # If not F['singular']: # # K*uy = A * S^{-1} * ( bx + GG'*W^{-1}*W^{-T}*bz ) - by # S*ux = bx + GG'*W^{-1}*W^{-T}*bz - A'*uy # W*uz = W^{-T} * ( GG*ux - bz ). # # If F['singular']: # # K*uy = A * S^{-1} * ( bx + GG'*W^{-1}*W^{-T}*bz + A'*by ) # - by # S*ux = bx + GG'*W^{-1}*W^{-T}*bz + A'*by - A'*y. # W*uz = W^{-T} * ( GG*ux - bz ). # z := W^{-1} * z = W^{-1} * bz scale(z, W, trans = 'T', inverse = 'I') # If not F['singular']: # x := L^{-1} * P * (x + GGs'*z) # = L^{-1} * P * (x + GG'*W^{-1}*W^{-T}*bz) # # If F['singular']: # x := L^{-1} * P * (x + GGs'*z + A'*y)) # = L^{-1} * P * (x + GG'*W^{-1}*W^{-T}*bz + A'*y) if mnl: base.gemv(F['Dfs'], z, x, trans = 'T', beta = 1.0) base.gemv(F['Gs'], z, x, offsetx = mnl, trans = 'T', beta = 1.0) if F['singular']: base.gemv(A, y, x, trans = 'T', beta = 1.0) if type(F['S']) is matrix: blas.trsv(F['S'], x) else: cholmod.solve(F['Sf'], x, sys = 7) cholmod.solve(F['Sf'], x, sys = 4) # y := K^{-1} * (Asc*x - y) # = K^{-1} * (A * S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz) - by) # (if not F['singular']) # = K^{-1} * (A * S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz + # A'*by) - by) # (if F['singular']). base.gemv(Asct, x, y, trans = 'T', beta = -1.0) if type(F['K']) is matrix: lapack.potrs(F['K'], y) else: cholmod.solve(Kf, y) # x := P' * L^{-T} * (x - Asc'*y) # = S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz - A'*y) # (if not F['singular']) # = S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz + A'*by - A'*y) # (if F['singular']) base.gemv(Asct, y, x, alpha = -1.0, beta = 1.0) if type(F['S']) is matrix: blas.trsv(F['S'], x, trans='T') else: cholmod.solve(F['Sf'], x, sys = 5) cholmod.solve(F['Sf'], x, sys = 8) # W*z := GGs*x - z = W^{-T} * (GG*x - bz) if mnl: base.gemv(F['Dfs'], x, z, beta = -1.0) base.gemv(F['Gs'], x, z, beta = -1.0, offsety = mnl) return solve return factor def kkt_qr(G, dims, A): """ Solution of KKT equations with zero 1,1 block, by eliminating the equality constraints via a QR factorization, and solving the reduced KKT system by another QR factorization. Computes the QR factorization A' = [Q1, Q2] * [R1; 0] and returns a function that (1) computes the QR factorization W^{-T} * G * Q2 = Q3 * R3 (with columns of W^{-T}*G in packed storage), and (2) returns a function for solving [ 0 A' G' ] [ ux ] [ bx ] [ A 0 0 ] * [ uy ] = [ by ]. [ G 0 -W'*W ] [ uz ] [ bz ] A is p x n and G is N x n where N = dims['l'] + sum(dims['q']) + sum( k**2 for k in dims['s'] ). """ p, n = A.size cdim = dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) cdim_pckd = dims['l'] + sum(dims['q']) + sum([ int(k*(k+1)/2) for k in dims['s'] ]) # A' = [Q1, Q2] * [R1; 0] if type(A) is matrix: QA = +A.T else: QA = matrix(A.T) tauA = matrix(0.0, (p,1)) lapack.geqrf(QA, tauA) Gs = matrix(0.0, (cdim, n)) tauG = matrix(0.0, (n-p,1)) u = matrix(0.0, (cdim_pckd, 1)) vv = matrix(0.0, (n,1)) w = matrix(0.0, (cdim_pckd, 1)) def factor(W): # Gs = W^{-T}*G, in packed storage. Gs[:,:] = G scale(Gs, W, trans = 'T', inverse = 'I') pack2(Gs, dims) # Gs := [ Gs1, Gs2 ] # = Gs * [ Q1, Q2 ] lapack.ormqr(QA, tauA, Gs, side = 'R', m = cdim_pckd) # QR factorization Gs2 := [ Q3, Q4 ] * [ R3; 0 ] lapack.geqrf(Gs, tauG, n = n-p, m = cdim_pckd, offsetA = Gs.size[0]*p) def solve(x, y, z): # On entry, x, y, z contain bx, by, bz. On exit, they # contain the solution x, y, W*z of # # [ 0 A' G'*W^{-1} ] [ x ] [bx ] # [ A 0 0 ] * [ y ] = [by ]. # [ W^{-T}*G 0 -I ] [ W*z ] [W^{-T}*bz] # # The system is solved in five steps: # # w := W^{-T}*bz - Gs1*R1^{-T}*by # u := R3^{-T}*Q2'*bx + Q3'*w # W*z := Q3*u - w # y := R1^{-1} * (Q1'*bx - Gs1'*(W*z)) # x := [ Q1, Q2 ] * [ R1^{-T}*by; R3^{-1}*u ] # w := W^{-T} * bz in packed storage scale(z, W, trans = 'T', inverse = 'I') pack(z, w, dims) # vv := [ Q1'*bx; R3^{-T}*Q2'*bx ] blas.copy(x, vv) lapack.ormqr(QA, tauA, vv, trans='T') lapack.trtrs(Gs, vv, uplo = 'U', trans = 'T', n = n-p, offsetA = Gs.size[0]*p, offsetB = p) # x[:p] := R1^{-T} * by blas.copy(y, x) lapack.trtrs(QA, x, uplo = 'U', trans = 'T', n = p) # w := w - Gs1 * x[:p] # = W^{-T}*bz - Gs1*by blas.gemv(Gs, x, w, alpha = -1.0, beta = 1.0, n = p, m = cdim_pckd) # u := [ Q3'*w + v[p:]; 0 ] # = [ Q3'*w + R3^{-T}*Q2'*bx; 0 ] blas.copy(w, u) lapack.ormqr(Gs, tauG, u, trans = 'T', k = n-p, offsetA = Gs.size[0]*p, m = cdim_pckd) blas.axpy(vv, u, offsetx = p, n = n-p) blas.scal(0.0, u, offset = n-p) # x[p:] := R3^{-1} * u[:n-p] blas.copy(u, x, offsety = p, n = n-p) lapack.trtrs(Gs, x, uplo='U', n = n-p, offsetA = Gs.size[0]*p, offsetB = p) # x is now [ R1^{-T}*by; R3^{-1}*u[:n-p] ] # x := [Q1 Q2]*x lapack.ormqr(QA, tauA, x) # u := [Q3, Q4] * u - w # = Q3 * u[:n-p] - w lapack.ormqr(Gs, tauG, u, k = n-p, m = cdim_pckd, offsetA = Gs.size[0]*p) blas.axpy(w, u, alpha = -1.0) # y := R1^{-1} * ( v[:p] - Gs1'*u ) # = R1^{-1} * ( Q1'*bx - Gs1'*u ) blas.copy(vv, y, n = p) blas.gemv(Gs, u, y, m = cdim_pckd, n = p, trans = 'T', alpha = -1.0, beta = 1.0) lapack.trtrs(QA, y, uplo = 'U', n=p) unpack(u, z, dims) return solve return factor cvxopt-1.1.4/src/python/msk.py0000644000175000017500000007313511674452555015371 0ustar sonnesonne""" CVXOPT interface for MOSEK 6.0 """ # Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import mosek from cvxopt import matrix, spmatrix, sparse from mosek.array import array, zeros env = mosek.Env() env.init() def streamprinter(text): print(text) env.set_Stream (mosek.streamtype.log, streamprinter) inf = 0.0 options = {} def lp(c, G, h, A=None, b=None): """ Solves a pair of primal and dual LPs minimize c'*x maximize -h'*z - b'*y subject to G*x + s = h subject to G'*z + A'*y + c = 0 A*x = b z >= 0. s >= 0 using MOSEK 6.0. (solsta, x, z, y) = lp(c, G, h, A=None, b=None). Input arguments G is m x n, h is m x 1, A is p x n, b is p x 1. G and A must be dense or sparse 'd' matrices. h and b are dense 'd' matrices with one column. The default values for A and b are empty matrices with zero rows. Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, y, z) contains the primal-dual solution. If solsta is mosek.solsta.prim_infeas_cer, then (x, y, z) is a certificate of primal infeasibility. If solsta is mosek.solsta.dual_infeas_cer, then (x, y, z) is a certificate of dual infeasibility. If solsta is mosek.solsta.unknown, then (x, y, z) are all None. Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined, c.f., section 17.48 of the MOSEK Python API manual. x, y, z the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary. For example, the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see chapter 15 of the MOSEK Python API manual. """ if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if (type(G) is not matrix and type(G) is not spmatrix) or \ G.typecode != 'd' or G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) m = G.size[0] if m is 0: raise ValueError("m cannot be 0") if type(h) is not matrix or h.typecode != 'd' or h.size != (m,1): raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %m) if A is None: A = spmatrix([], [], [], (0,n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): raise TypeError("'b' must be a dense matrix of size (%d,1)" %p) bkc = m*[ mosek.boundkey.up ] + p*[ mosek.boundkey.fx ] blc = m*[ -inf ] + [ bi for bi in b ] buc = matrix([h, b]) bkx = n*[mosek.boundkey.fr] blx = n*[ -inf ] bux = n*[ +inf ] colptr, asub, acof = sparse([G,A]).CCS aptrb, aptre = colptr[:-1], colptr[1:] task = env.Task(0,0) task.set_Stream (mosek.streamtype.log, streamprinter) # set MOSEK options for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: " + str(param)) task.inputdata (m+p, # number of constraints n, # number of variables array(c), # linear objective coefficients 0.0, # objective fixed value array(aptrb), array(aptre), array(asub), array(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.minimize) task.optimize() task.solutionsummary (mosek.streamtype.msg); prosta, solsta = task.getsolutionstatus(mosek.soltype.bas) x, z = zeros(n, float), zeros(m, float) task.getsolutionslice(mosek.soltype.bas, mosek.solitem.xx, 0, n, x) task.getsolutionslice(mosek.soltype.bas, mosek.solitem.suc, 0, m, z) x, z = matrix(x), matrix(z) if p is not 0: yu, yl = zeros(p, float), zeros(p, float) task.getsolutionslice(mosek.soltype.bas, mosek.solitem.suc, m, m+p, yu) task.getsolutionslice(mosek.soltype.bas, mosek.solitem.slc, m, m+p, yl) y = matrix(yu) - matrix(yl) else: y = matrix(0.0, (0,1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None, None) else: return (solsta, x, z, y) def conelp(c, G, h, dims = None): """ Solves a pair of primal and dual SOCPs minimize c'*x subject to G*x + s = h s >= 0 maximize -h'*z subject to G'*z + c = 0 z >= 0 using MOSEK 6.0. The inequalities are with respect to a cone C defined as the Cartesian product of N + 1 cones: C = C_0 x C_1 x .... x C_N x C_{N+1}. The first cone C_0 is the nonnegative orthant of dimension ml. The other cones are second order cones of dimension mq[0], ..., mq[N-1]. The second order cone of dimension m is defined as { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }. The formats of G and h are identical to that used in solvers.conelp(), except that only componentwise and second order cone inequalities are (dims['s'] must be zero, if defined). Input arguments. c is a dense 'd' matrix of size (n,1). dims is a dictionary with the dimensions of the components of C. It has three fields. - dims['l'] = ml, the dimension of the nonnegative orthant C_0. (ml >= 0.) - dims['q'] = mq = [ mq[0], mq[1], ..., mq[N-1] ], a list of N integers with the dimensions of the second order cones C_1, ..., C_N. (N >= 0 and mq[k] >= 1.) The default value of dims is {'l': G.size[0], 'q': []}. G is a dense or sparse 'd' matrix of size (K,n), where K = ml + mq[0] + ... + mq[N-1]. Each column of G describes a vector v = ( v_0, v_1, ..., v_N, vec(v_{N+1}) ) in V = R^ml x R^mq[0] x ... x R^mq[N-1] stored as a column vector. h is a dense 'd' matrix of size (K,1), representing a vector in V, in the same format as the columns of G. Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, zl, zq) contains the primal-dual solution. If solsta is moseksolsta.prim_infeas_cer, then (x, zl, zq) is a certificate of dual infeasibility. If solsta is moseksolsta.dual_infeas_cer, then (x, zl, zq) is a certificate of primal infeasibility. If solsta is mosek.solsta.unknown, then (x, zl, zq) are all None Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined, c.f., section 17.48 of the MOSEK Python API manual. x, z the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log:0} see chapter 15 of the MOSEK Python API manual. """ if dims is None: (solsta, x, y, z) = lp(c, G, h) return (solsta, x, z, None) try: if len(dims['s']) > 0: raise ValueError("dims['s'] must be zero") except: pass N, n = G.size ml, mq = dims['l'], dims['q'] cdim = ml + sum(mq) if cdim is 0: raise ValueError("ml+mq cannot be 0") # Data for kth 'q' constraint are found in rows indq[k]:indq[k+1] of G. indq = [ dims['l'] ] for k in dims['q']: indq = indq + [ indq[-1] + k ] if type(h) is not matrix or h.typecode != 'd' or h.size[1] != 1: raise TypeError("'h' must be a 'd' matrix with 1 column") if type(G) is matrix or type(G) is spmatrix: if G.typecode != 'd' or G.size[0] != cdim: raise TypeError("'G' must be a 'd' matrix with %d rows " %cdim) if h.size[0] != cdim: raise TypeError("'h' must have %d rows" %cdim) else: raise TypeError("'G' must be a matrix") if min(dims['q'])<1: raise TypeError( "dimensions of quadratic cones must be positive") bkc = n*[ mosek.boundkey.fx ] blc = array(-c) buc = array(-c) bkx = ml*[ mosek.boundkey.lo ] + sum(mq)*[ mosek.boundkey.fr ] blx = ml*[ 0.0 ] + sum(mq)*[ -inf ] bux = N*[ +inf ] c = array(-h) colptr, asub, acof = sparse([G.T]).CCS aptrb, aptre = colptr[:-1], colptr[1:] task = env.Task(0,0) task.set_Stream (mosek.streamtype.log, streamprinter) # set MOSEK options for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: "+str(param)) task.inputdata (n, # number of constraints N, # number of variables c, # linear objective coefficients 0.0, # objective fixed value array(aptrb), array(aptre), array(asub), array(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.maximize) for k in range(len(mq)): task.appendcone(mosek.conetype.quad, 0.0, array(range(ml+sum(mq[:k]),ml+sum(mq[:k+1])))) task.optimize() task.solutionsummary (mosek.streamtype.msg); prosta, solsta = task.getsolutionstatus(mosek.soltype.itr) xu, xl, zq = zeros(n, float), zeros(n, float), zeros(sum(mq), float) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.slc, 0, n, xl) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, 0, n, xu) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, ml, N, zq) x = matrix(xu-xl) zq = matrix(zq) if ml: zl = zeros(ml, float) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, 0, ml, zl) zl = matrix(zl) else: zl = matrix(0.0, (0,1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None) else: return (solsta, x, matrix([zl, zq])) def socp(c, Gl = None, hl = None, Gq = None, hq = None): """ Solves a pair of primal and dual SOCPs minimize c'*x subject to Gl*x + sl = hl Gq[k]*x + sq[k] = hq[k], k = 0, ..., N-1 sl >= 0, sq[k] >= 0, k = 0, ..., N-1 maximize -hl'*zl - sum_k hq[k]'*zq[k] subject to Gl'*zl + sum_k Gq[k]'*zq[k] + c = 0 zl >= 0, zq[k] >= 0, k = 0, ..., N-1. using MOSEK 6.0. solsta, x, zl, zq = socp(c, Gl = None, hl = None, Gq = None, hq = None) Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, zl, zq) contains the primal-dual solution. If solsta is mosek.solsta.prim_infeas_cer, then (x, zl, zq) is a certificate of dual infeasibility. If solsta is mosek.solsta.dual_infeas_cer, then (x, zl, zq) is a certificate of primal infeasibility. If solsta is mosek.solsta.unknown, then (x, zl, zq) are all None Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined, c.f., section 17.48 of the MOSEK Python API manual. x, zl, zq the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see chapter 15 of the MOSEK Python API manual. """ if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if Gl is None: Gl = spmatrix([], [], [], (0,n), tc='d') if (type(Gl) is not matrix and type(Gl) is not spmatrix) or \ Gl.typecode != 'd' or Gl.size[1] != n: raise TypeError("'Gl' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) ml = Gl.size[0] if hl is None: hl = matrix(0.0, (0,1)) if type(hl) is not matrix or hl.typecode != 'd' or \ hl.size != (ml,1): raise TypeError("'hl' must be a dense 'd' matrix of " \ "size (%d,1)" %ml) if Gq is None: Gq = [] if type(Gq) is not list or [ G for G in Gq if (type(G) is not matrix and type(G) is not spmatrix) or G.typecode != 'd' or G.size[1] != n ]: raise TypeError("'Gq' must be a list of sparse or dense 'd' "\ "matrices with %d columns" %n) mq = [ G.size[0] for G in Gq ] a = [ k for k in range(len(mq)) if mq[k] == 0 ] if a: raise TypeError("the number of rows of Gq[%d] is zero" %a[0]) if hq is None: hq = [] if type(hq) is not list or len(hq) != len(mq) or [ h for h in hq if (type(h) is not matrix and type(h) is not spmatrix) or h.typecode != 'd' ]: raise TypeError("'hq' must be a list of %d dense or sparse "\ "'d' matrices" %len(mq)) a = [ k for k in range(len(mq)) if hq[k].size != (mq[k], 1) ] if a: k = a[0] raise TypeError("'hq[%d]' has size (%d,%d). Expected size "\ "is (%d,1)." %(k, hq[k].size[0], hq[k].size[1], mq[k])) N = ml + sum(mq) h = matrix(0.0, (N,1)) if type(Gl) is matrix or [ Gk for Gk in Gq if type(Gk) is matrix ]: G = matrix(0.0, (N, n)) else: G = spmatrix([], [], [], (N, n), 'd') h[:ml] = hl G[:ml,:] = Gl ind = ml for k in range(len(mq)): h[ind : ind + mq[k]] = hq[k] G[ind : ind + mq[k], :] = Gq[k] ind += mq[k] bkc = n*[ mosek.boundkey.fx ] blc = array(-c) buc = array(-c) bkx = ml*[ mosek.boundkey.lo ] + sum(mq)*[ mosek.boundkey.fr ] blx = ml*[ 0.0 ] + sum(mq)*[ -inf ] bux = N*[ +inf ] c = -h colptr, asub, acof = sparse([G.T]).CCS aptrb, aptre = colptr[:-1], colptr[1:] task = env.Task(0,0) task.set_Stream (mosek.streamtype.log, streamprinter) # set MOSEK options for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: "+str(param)) task.inputdata (n, # number of constraints N, # number of variables array(c), # linear objective coefficients 0.0, # objective fixed value array(aptrb), array(aptre), array(asub), array(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.maximize) for k in range(len(mq)): task.appendcone(mosek.conetype.quad, 0.0, array(range(ml+sum(mq[:k]),ml+sum(mq[:k+1])))) task.optimize() task.solutionsummary (mosek.streamtype.msg); prosta, solsta = task.getsolutionstatus(mosek.soltype.itr) xu, xl, zq = zeros(n, float), zeros(n, float), zeros(sum(mq), float) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.slc, 0, n, xl) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, 0, n, xu) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, ml, N, zq) x = matrix(xu-xl) zq = [ matrix(zq[sum(mq[:k]):sum(mq[:k+1])]) for k in range(len(mq)) ] if ml: zl = zeros(ml, float) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, 0, ml, zl) zl = matrix(zl) else: zl = matrix(0.0, (0,1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None, None) else: return (solsta, x, zl, zq) def qp(P, q, G=None, h=None, A=None, b=None): """ Solves a quadratic program minimize (1/2)*x'*P*x + q'*x subject to G*x <= h A*x = b. using MOSEK 6.0. solsta, x, z, y = qp(P, q, G=None, h=None, A=None, b=None) Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.optimal, then (x, y, z) contains the primal-dual solution. If solsta is mosek.solsta.prim_infeas_cer, then (x, y, z) is a certificate of primal infeasibility. If solsta is mosek.solsta.dual_infeas_cer, then (x, y, z) is a certificate of dual infeasibility. If solsta is mosek.solsta.unknown, then (x, y, z) are all None. Other return values for solsta include: mosek.solsta.dual_feas mosek.solsta.near_dual_feas mosek.solsta.near_optimal mosek.solsta.near_prim_and_dual_feas mosek.solsta.near_prim_feas mosek.solsta.prim_and_dual_feas mosek.solsta.prim_feas in which case the (x,y,z) value may not be well-defined, c.f., section 17.48 of the MOSEK Python API manual. x, z, y the primal-dual solution. Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see chapter 15 of the MOSEK Python API manual. """ if (type(P) is not matrix and type(P) is not spmatrix) or \ P.typecode != 'd' or P.size[0] != P.size[1]: raise TypeError("'P' must be a square dense or sparse 'd' matrix ") n = P.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if type(q) is not matrix or q.typecode != 'd' or q.size != (n,1): raise TypeError("'q' must be a 'd' matrix of size (%d,1)" %n) if G is None: G = spmatrix([], [], [], (0,n), 'd') if (type(G) is not matrix and type(G) is not spmatrix) or \ G.typecode != 'd' or G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) m = G.size[0] if h is None: h = matrix(0.0, (0,1)) if type(h) is not matrix or h.typecode != 'd' or h.size != (m,1): raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %m) if A is None: A = spmatrix([], [], [], (0,n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): raise TypeError("'b' must be a dense matrix of size (%d,1)" %p) if m+p is 0: raise ValueError("m + p must be greater than 0") c = array(q) bkc = m*[ mosek.boundkey.up ] + p*[ mosek.boundkey.fx ] blc = m*[ -inf ] + [ bi for bi in b ] buc = matrix([h, b]) bkx = n*[mosek.boundkey.fr] blx = n*[ -inf ] bux = n*[ +inf ] colptr, asub, acof = sparse([G,A]).CCS aptrb, aptre = colptr[:-1], colptr[1:] task = env.Task(0,0) task.set_Stream (mosek.streamtype.log, streamprinter) # set MOSEK options for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: "+str(param)) task.inputdata (m+p, # number of constraints n, # number of variables array(c), # linear objective coefficients 0.0, # objective fixed value array(aptrb), array(aptre), array(asub), array(acof), bkc, blc, buc, bkx, blx, bux) Ps = sparse(P) I, J = Ps.I, Ps.J tril = [ k for k in range(len(I)) if I[k] >= J[k] ] task.putqobj(array(I[tril]), array(J[tril]), array(Ps.V[tril])) task.putobjsense(mosek.objsense.minimize) task.optimize() task.solutionsummary (mosek.streamtype.msg); prosta, solsta = task.getsolutionstatus(mosek.soltype.itr) x = zeros(n, float) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.xx, 0, n, x) x = matrix(x) if m is not 0: z = zeros(m, float) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, 0, m, z) z = matrix(z) else: z = matrix(0.0, (0,1)) if p is not 0: yu, yl = zeros(p, float), zeros(p, float) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.suc, m, m+p, yu) task.getsolutionslice(mosek.soltype.itr, mosek.solitem.slc, m, m+p, yl) y = matrix(yu) - matrix(yl) else: y = matrix(0.0, (0,1)) if (solsta is mosek.solsta.unknown): return (solsta, None, None, None) else: return (solsta, x, z, y) def ilp(c, G, h, A=None, b=None, I=None): """ Solves the mixed integer LP minimize c'*x subject to G*x + s = h A*x = b s >= 0 xi integer, forall i in I using MOSEK 6.0. solsta, x = ilp(c, G, h, A=None, b=None, I=None). Input arguments G is m x n, h is m x 1, A is p x n, b is p x 1. G and A must be dense or sparse 'd' matrices. h and b are dense 'd' matrices with one column. The default values for A and b are empty matrices with zero rows. I is a Python set with indices of integer elements of x. By default all elements in x are constrained to be integer, i.e., the default value of I is I = set(range(n)) Dual variables are not returned for MOSEK. Return values solsta is a MOSEK solution status key. If solsta is mosek.solsta.integer_optimal, then x contains the solution. If solsta is mosek.solsta.unknown, then x is None. Other return values for solsta include: mosek.solsta.near_integer_optimal in which case the x value may not be well-defined, c.f., section 17.48 of the MOSEK Python API manual. x is the solution Options are passed to MOSEK solvers via the msk.options dictionary, e.g., the following turns off output from the MOSEK solvers >>> msk.options = {mosek.iparam.log: 0} see chapter 15 of the MOSEK Python API manual. """ if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if (type(G) is not matrix and type(G) is not spmatrix) or \ G.typecode != 'd' or G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) m = G.size[0] if m is 0: raise ValueError("m cannot be 0") if type(h) is not matrix or h.typecode != 'd' or h.size != (m,1): raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %m) if A is None: A = spmatrix([], [], [], (0,n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): raise TypeError("'b' must be a dense matrix of size (%d,1)" %p) c = array(c) if I is None: I = set(range(n)) if type(I) is not set: raise TypeError("invalid argument for integer index set") for i in I: if type(i) is not int: raise TypeError("invalid integer index set I") if len(I) > 0 and min(I) < 0: raise IndexError( "negative element in integer index set I") if len(I) > 0 and max(I) > n-1: raise IndexError( "maximum element in in integer index set I is larger than n-1") bkc = m*[ mosek.boundkey.up ] + p*[ mosek.boundkey.fx ] blc = m*[ -inf ] + [ bi for bi in b ] buc = matrix([h, b]) bkx = n*[mosek.boundkey.fr] blx = n*[ -inf ] bux = n*[ +inf ] colptr, asub, acof = sparse([G,A]).CCS aptrb, aptre = colptr[:-1], colptr[1:] task = env.Task(0,0) task.set_Stream (mosek.streamtype.log, streamprinter) # set MOSEK options for (param, val) in options.items(): if str(param)[:6] == "iparam": task.putintparam(param, val) elif str(param)[:6] == "dparam": task.putdouparam(param, val) elif str(param)[:6] == "sparam": task.putstrparam(param, val) else: raise ValueError("invalid MOSEK parameter: "+str(param)) task.inputdata (m+p, # number of constraints n, # number of variables array(c), # linear objective coefficients 0.0, # objective fixed value array(aptrb), array(aptre), array(asub), array(acof), bkc, blc, buc, bkx, blx, bux) task.putobjsense(mosek.objsense.minimize) # Define integer variables if len(I) > 0: task.putvartypelist(list(I), len(I)*[ mosek.variabletype.type_int ]) task.putintparam (mosek.iparam.mio_mode, mosek.miomode.satisfied) task.optimize() task.solutionsummary (mosek.streamtype.msg); if len(I) > 0: prosta, solsta = task.getsolutionstatus(mosek.soltype.itg) else: prosta, solsta = task.getsolutionstatus(mosek.soltype.bas) x = zeros(n, float) if len(I) > 0: task.getsolutionslice(mosek.soltype.itg, mosek.solitem.xx, 0, n, x) else: task.getsolutionslice(mosek.soltype.bas, mosek.solitem.xx, 0, n, x) x = matrix(x) if (solsta is mosek.solsta.unknown): return (solsta, None) else: return (solsta, x) cvxopt-1.1.4/src/python/info.py0000644000175000017500000000321311674452555015520 0ustar sonnesonneversion = '1.1.4' def license(): print( """ CVXOPT version 1.1.4. Copyright (c) 2010-2011 L. Vandenberghe. Copyright (c) 2004-2009 J. Dahl and L. Vandenberghe. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ---- The CVXOPT distribution includes source code for part of the SuiteSparse suite of sparse matrix algorithms, including: - AMD Version 2.2. Copyright (c) 2007 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. - CHOLMOD Version 1.7.1. Copyright (c) 2005-2009 by University of Florida, Timothy A. Davis and W. Hager. - COLAMD version 2.7. Copyright (c) 1998-2007 by Timothy A. Davis. - UMFPACK Version 5.4.0. Copyright (c) 1994-2009 by Timothy A. Davis. These packages are licensed under the terms of the GNU General Public License, version 2 or higher (UMFPACK, the Supernodal module of CHOLMOD), and the GNU Lesser General Public License, version 2.1 or higher (the other CHOLMOD modules, AMD, COLAMD). For copyright and license details, consult the README files in the source directories or the website listed below. Availability: www.cise.ufl.edu/research/sparse. """ ) cvxopt-1.1.4/src/python/modeling.py0000644000175000017500000030523111674452555016370 0ustar sonnesonne""" Modeling tools for PWL convex optimization. Routines for specifying and solving convex optimization problems with piecewise-linear objective and constraint functions. """ # Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from cvxopt.base import matrix, spmatrix from cvxopt import blas, solvers import sys if sys.version_info.major < 3: import __builtin__ as builtins else: import builtins __all__ = ["variable", "constraint", "op", "min", "max", "sum", "dot"] class variable(object): """ Vector valued optimization variable. variable(size=1, name='') creates a variable of length size. Arguments: size length of the variable (positive integer) name name of the variable (string) Attributes: name the name of the variable value None or a 'd' matrix of size (len(self),1) _size the length of the variable """ def __init__(self, size=1, name=''): self.name = name self.value = None if type(size) is int and size > 0: self._size = size else: raise TypeError("size must be a positive integer") def __len__(self): return self._size def __repr__(self): return "variable(%d,'%s')" %(len(self),self.name) def __str__(self): s = self.name if self.name: s += ': ' s += 'variable of length %d\nvalue: ' %len(self) if self.value is None: s += 'None' else: s += '\n' + str(self.value) return s def __setattr__(self,name,value): if name == 'value': if value is None or (_isdmatrix(value) and value.size == (len(self),1)): object.__setattr__(self, name, value) elif type(value) is int or type(value) is float: object.__setattr__(self, name, matrix(value, (len(self),1), tc='d')) else: raise AttributeError("invalid type or size for "\ "attribute 'value'") elif name == 'name': if type(value) is str: object.__setattr__(self,name,value) else: raise AttributeError("invalid type for attribute "\ "'name'") elif name == '_size': object.__setattr__(self,name,value) else: raise AttributeError("'variable' object has no attribute "\ "'%s'" %name) def __pos__(self): f = _function() f._linear._coeff[self] = matrix(1.0) return f def __neg__(self): f = _function() f._linear._coeff[self] = matrix(-1.0) return f def __abs__(self): return max(self,-self) def __add__(self,other): return (+self).__add__(other) def __radd__(self,other): return (+self).__radd__(other) def __iadd__(self,other): raise NotImplementedError("in-place addition not implemented"\ " for 'variable' objects") def __sub__(self,other): return (+self).__sub__(other) def __rsub__(self,other): return (+self).__rsub__(other) def __isub__(self,other): raise NotImplementedError("in-place subtraction not "\ "implemented for 'variable' objects") def __mul__(self,other): return (+self).__mul__(other) def __rmul__(self,other): return (+self).__rmul__(other) def __imul__(self,other): raise NotImplementedError("in-place multiplication not "\ "implemented for 'variable' objects") if sys.version_info.major < 3: def __div__(self,other): return (+self).__div__(other) def __idiv__(self,other): raise NotImplementedError("in-place division not implemented "\ "for 'variable' objects") else: def __truediv__(self,other): return (+self).__truediv__(other) def __itruediv__(self,other): raise NotImplementedError("in-place division not implemented "\ "for 'variable' objects") def __eq__(self,other): return constraint(self-other, '=') def __le__(self,other): return constraint(self-other, '<') def __ge__(self,other): return constraint(other-self, '<') def __lt__(self,other): raise NotImplementedError def __gt__(self,other): raise NotImplementedError def __getitem__(self,key): return (+self).__getitem__(key) if sys.version_info.major >= 3: def __hash__(self): return id(self) class _function(object): """ Vector valued function. General form: f = constant + linear + sum of nonlinear convex terms + sum of nonlinear concave terms The length of f is the maximum of the lengths of the terms in the sum. Each term must have length 1 or length equal to len(f). _function() creates the constant function f=0 with length 1. Attributes: _constant constant term as a 1-column dense 'd' matrix of length 1 or length len(self) _linear linear term as a _lin object of length 1 or length len(self) _cvxterms nonlinear convex terms as a list [f1,f2,...] with each fi of type _minmax or _sum_minmax. Each fi has length 1 or length equal to len(self). _ccvterms nonlinear concave terms as a list [f1,f2,...] with each fi of type _minmax or _sum_minmax. Each fi has length 1 or length equal to len(self). Methods: value() returns the value of the function: None if one of the variables has value None; a dense 'd' matrix of size (len(self),1) if all the variables have values variables() returns a (copy of) the list of variables _iszero() True if self is identically zero _isconstant() True if there are no linear/convex/concave terms _islinear() True if there are no constant/convex/concave terms _isaffine() True if there are no nonlinear convex/concave terms _isconvex() True if there are no nonlinear concave terms _isconcave() True if there are no nonlinear convex terms """ def __init__(self): self._constant = matrix(0.0) self._linear = _lin() self._cvxterms = [] self._ccvterms = [] def __len__(self): if len(self._constant) > 1: return len(self._constant) lg = len(self._linear) if lg > 1: return lg for f in self._cvxterms: lg = len(f) if lg > 1: return lg for f in self._ccvterms: lg = len(f) if lg > 1: return lg return 1 def __repr__(self): if self._iszero(): return '' %len(self) elif self._isconstant(): return '' %len(self) elif self._islinear(): return '' %len(self) elif self._isaffine(): return '' %len(self) elif self._isconvex(): return '' %len(self) elif self._isconcave(): return '' %len(self) else: return '' %len(self) def __str__(self): s = repr(self)[1:-1] # print constant term if nonzero if not self._iszero() and (len(self._constant) != 1 or self._constant[0]): s += '\nconstant term:\n' + str(self._constant) else: s += '\n' # print linear term if nonzero if self._linear._coeff: s += 'linear term: ' + str(self._linear) # print nonlinear convex term if nonzero if self._cvxterms: s += '%d nonlinear convex term(s):' %len(self._cvxterms) for f in self._cvxterms: s += '\n' + str(f) # print nonlinear concave term if nonzero if self._ccvterms: s += '%d nonlinear concave term(s):' %len(self._ccvterms) for f in self._ccvterms: s += '\n' + str(f) return s def value(self): val = self._constant if self._linear._coeff: nval = self._linear.value() if nval is None: return None else: val = val + nval for f in self._cvxterms: nval = f.value() if nval is None: return None else: val = val + nval for f in self._ccvterms: nval = f.value() if nval is None: return None else: val = val + nval return val def variables(self): l = self._linear.variables() for f in self._cvxterms: l += [v for v in f.variables() if v not in l] for f in self._ccvterms: l += [v for v in f.variables() if v not in l] return l def _iszero(self): if not self._linear._coeff and not self._cvxterms and \ not self._ccvterms and not blas.nrm2(self._constant): return True else: return False def _isconstant(self): if not self._linear._coeff and not self._cvxterms and \ not self._ccvterms: return True else: return False def _islinear(self): if len(self._constant) == 1 and not self._constant[0] and \ not self._cvxterms and not self._ccvterms: return True else: return False def _isaffine(self): if not self._cvxterms and not self._ccvterms: return True else: return False def _isconvex(self): if not self._ccvterms: return True else: return False def _isconcave(self): if not self._cvxterms: return True else: return False def __pos__(self): f = _function() f._constant = +self._constant f._linear = +self._linear f._cvxterms = [+g for g in self._cvxterms] f._ccvterms = [+g for g in self._ccvterms] return f def __neg__(self): f = _function() f._constant = -self._constant f._linear = -self._linear f._ccvterms = [-g for g in self._cvxterms] f._cvxterms = [-g for g in self._ccvterms] return f def __add__(self,other): # convert other to matrix (dense 'd' or sparse) or _function if type(other) is int or type(other) is float: other = matrix(other, tc='d') elif _ismatrix(other): # ie, dense 'd' or sparse if other.size[1] != 1: raise ValueError('incompatible dimensions') elif type(other) is variable: other = +other elif type(other) is not _function: return NotImplemented if 1 != len(self) != len(other) != 1: raise ValueError('incompatible lengths') f = _function() if _ismatrix(other): # this converts sparse other to dense 'd' f._constant = self._constant + other f._linear = +self._linear f._cvxterms = [+fk for fk in self._cvxterms] f._ccvterms = [+fk for fk in self._ccvterms] else: #type(other) is _function: if not (self._isconvex() and other._isconvex()) and \ not (self._isconcave() and other._isconcave()): raise ValueError('operands must be both convex or '\ 'both concave') f._constant = self._constant + other._constant f._linear = self._linear + other._linear f._cvxterms = [+fk for fk in self._cvxterms] + \ [+fk for fk in other._cvxterms] f._ccvterms = [+fk for fk in self._ccvterms] + \ [+fk for fk in other._ccvterms] return f def __radd__(self,other): return self.__add__(other) def __iadd__(self,other): # convert other to matrix (dense 'd' or sparse) or _function if type(other) is int or type(other) is float: other = matrix(other, tc='d') elif _ismatrix(other): if other.size[1] != 1: raise ValueError('incompatible dimensions') elif type(other) is variable: other = +other elif type(other) is not _function: return NotImplemented if len(self) != len(other) != 1: raise ValueError('incompatible lengths') if _ismatrix(other): if 1 == len(self._constant) != len(other): self._constant = self._constant + other else: self._constant += other else: #type(other) is _function: if not (self._isconvex() and other._isconvex()) and \ not (self._isconcave() and other._isconcave()): raise ValueError('operands must be both convex or '\ 'both concave') if 1 == len(self._constant) != len(other._constant): self._constant = self._constant + other._constant else: self._constant += other._constant if 1 == len(self._linear) != len(other._linear): self._linear = self._linear + other._linear else: self._linear += other._linear self._cvxterms += [+fk for fk in other._cvxterms] self._ccvterms += [+fk for fk in other._ccvterms] return self def __sub__(self,other): # convert other to matrix (dense 'd' or sparse) or _function if type(other) is int or type(other) is float: other = matrix(other, tc='d') elif _ismatrix(other): if other.size[1] != 1: raise ValueError('incompatible dimensions') elif type(other) is variable: other = +other elif type(other) is not _function: return NotImplemented if 1 != len(self) != len(other) != 1: raise ValueError('incompatible lengths') f = _function() if _ismatrix(other): f._constant = self._constant - other f._linear = +self._linear f._cvxterms = [+fk for fk in self._cvxterms] f._ccvterms = [+fk for fk in self._ccvterms] else: #type(other) is _function: if not (self._isconvex() and other._isconcave()) and \ not (self._isconcave() and other._isconvex()): raise ValueError('operands must be convex and '\ 'concave or concave and convex') f._constant = self._constant - other._constant f._linear = self._linear - other._linear f._cvxterms = [+fk for fk in self._cvxterms] + \ [-fk for fk in other._ccvterms] f._ccvterms = [+fk for fk in self._ccvterms] + \ [-fk for fk in other._cvxterms] return f def __rsub__(self,other): # convert other to matrix (dense 'd' or sparse) or _function if type(other) is int or type(other) is float: other = matrix(other, tc='d') elif _isdmatrix(other): if other.size[1] != 1: raise ValueError('incompatible dimensions') elif type(other) is variable: other = +other elif type(other) is not _function: return NotImplemented if 1 != len(self) != len(other) != 1: raise ValueError('incompatible lengths') f = _function() if _ismatrix(other): f._constant = other - self._constant f._linear = -self._linear f._cvxterms = [-fk for fk in self._ccvterms] f._ccvterms = [-fk for fk in self._cvxterms] else: # type(other) is _function: if not (self._isconvex() and other._isconcave()) and \ not (self._isconcave() and other._isconvex()): raise ValueError('operands must be convex and '\ 'concave or concave and convex') f._constant = other._constant - self._constant f._linear = other._linear - self._linear f._cvxterms = [-fk for fk in self._ccvterms] + \ [fk for fk in other._cvxterms] f._ccvterms = [-fk for fk in self._cvxterms] + \ [fk for fk in other._ccvterms] return f def __isub__(self,other): # convert other to matrix (dense or sparse 'd') or _function if type(other) is int or type(other) is float: other = matrix(other, tc='d') elif _ismatrix(other): if other.size[1] != 1: raise ValueError('incompatible dimensions') elif type(other) is variable: other = +other elif type(other) is not _function: return NotImplemented if len(self) != len(other) != 1: raise ValueError('incompatible lengths') if _ismatrix(other): if 1 == len(self._constant) != len(other): self._constant = self._constant - other else: self._constant -= other else: #type(other) is _function: if not (self._isconvex() and other._isconcave()) and \ not (self._isconcave() and other._isconvex()): raise ValueError('operands must be convex and '\ 'concave or concave and convex') if 1 == len(self._constant) != len(other._constant): self._constant = self._constant - other._constant else: self._constant -= other._constant if 1 == len(self._linear) != len(other._linear): self._linear = self._linear - other._linear else: self._linear -= other._linear self._cvxterms += [-fk for fk in other._ccvterms] self._ccvterms += [-fk for fk in other._cvxterms] return self def __mul__(self,other): if type(other) is int or type(other) is float: other = matrix(other, tc='d') if (_ismatrix(other) and other.size == (1,1)) or \ (_isdmatrix(other) and other.size[1] == 1 == len(self)): f = _function() if other.size == (1,1) and other[0] == 0.0: # if other is zero, return constant zero function # of length len(self) f._constant = matrix(0.0, (len(self),1)) return f if len(self._constant) != 1 or self._constant[0]: # skip if self._constant is zero f._constant = self._constant*other if self._linear._coeff: # skip if self._linear is zero f._linear = self._linear*other if not self._isaffine(): # allow only multiplication with scalar if other.size == (1,1): if other[0] > 0.0: f._cvxterms = \ [fk*other[0] for fk in self._cvxterms] f._ccvterms = \ [fk*other[0] for fk in self._ccvterms] elif other[0] < 0.0: f._cvxterms = \ [fk*other[0] for fk in self._ccvterms] f._ccvterms = \ [fk*other[0] for fk in self._cvxterms] else: # already dealt with above pass else: raise ValueError('can only multiply with scalar') else: raise TypeError('incompatible dimensions or types') return f def __rmul__(self,other): if type(other) is int or type(other) is float: other = matrix(other, tc='d') lg = len(self) if (_ismatrix(other) and other.size[1] == lg) or \ (_isdmatrix(other) and other.size == (1,1)): f = _function() if other.size == (1,1) and other[0] == 0.0: # if other is zero, return constant zero function # of length len(self) f._constant = matrix(0.0, (len(self),1)) return f if len(self._constant) != 1 or self._constant[0]: if 1 == len(self._constant) != lg and \ not _isscalar(other): f._constant = other * self._constant[lg*[0]] else: f._constant = other * self._constant if self._linear._coeff: if 1 == len(self._linear) != lg and \ not _isscalar(other): f._linear = other * self._linear[lg*[0]] else: f._linear = other * self._linear if not self._isaffine(): # allow only scalar multiplication if other.size == (1,1): if other[0] > 0.0: f._cvxterms = [other[0] * fk for fk in self._cvxterms] f._ccvterms = [other[0] * fk for fk in self._ccvterms] elif other[0] < 0.0: f._cvxterms = [other[0] * fk for fk in self._ccvterms] f._ccvterms = [other[0] * fk for fk in self._cvxterms] else: pass else: raise ValueError('can only multiply with scalar') else: raise TypeError('incompatible dimensions or types') return f def __imul__(self,other): if type(other) is int or type(other) is float: other = matrix(other, tc='d') if _isdmatrix(other) and other.size == (1,1): if other[0] == 0.0: self._constant = matrix(0.0, (len(self),1)) return self if len(self._constant) != 1 or self._constant[0]: self._constant *= other[0] if self._linear._coeff: self._linear *= other[0] if not self._isaffine(): if other[0] > 0.0: for f in self._cvxterms: f *= other[0] for f in self._ccvterms: f *= other[0] elif other[0] < 0.0: cvxterms = [f*other[0] for f in self._ccvterms] self._ccvterms = [f*other[0] for f in self._cvxterms] self._cvxterms = cvxterms else: pass return self else: raise TypeError('incompatible dimensions or types') if sys.version_info.major < 3: def __div__(self,other): if type(other) is int or type(other) is float: return self.__mul__(1.0/other) elif _isdmatrix(other) and other.size == (1,1): return self.__mul__(1.0/other[0]) else: return NotImplemented else: def __truediv__(self,other): if type(other) is int or type(other) is float: return self.__mul__(1.0/other) elif _isdmatrix(other) and other.size == (1,1): return self.__mul__(1.0/other[0]) else: return NotImplemented def __rdiv__(self,other): return NotImplemented if sys.version_info.major < 3: def __idiv__(self,other): if type(other) is int or type(other) is float: return self.__imul__(1.0/other) elif _isdmatrix(other) and other.size == (1,1): return self.__imul__(1.0/other[0]) else: return NotImplemented else: def __itruediv__(self,other): if type(other) is int or type(other) is float: return self.__imul__(1.0/other) elif _isdmatrix(other) and other.size == (1,1): return self.__imul__(1.0/other[0]) else: return NotImplemented def __abs__(self): return max(self,-self) def __eq__(self,other): return constraint(self-other, '=') def __le__(self,other): return constraint(self-other, '<') def __ge__(self,other): return constraint(other-self, '<') def __lt__(self,other): raise NotImplementedError def __gt__(self,other): raise NotImplementedError def __getitem__(self,key): lg = len(self) l = _keytolist(key,lg) if not l: raise ValueError('empty index set') f = _function() if len(self._constant) != 1 or self._constant[0]: if 1 == len(self._constant) != lg: f._constant = +self._constant else: f._constant = self._constant[l] if self._linear: if 1 == len(self._linear) != lg: f._linear = +self._linear else: f._linear = self._linear[l] for fk in self._cvxterms: if 1 == len(fk) != lg: f._cvxterms += [+fk] elif type(fk) is _minmax: f._cvxterms += [fk[l]] else: # type(fk) is _sum_minmax # fk is defined as fk = sum(fmax) fmax = _minmax('max', *fk._flist) # take f += sum_j fk[j][l] = sum_{gk in fmax} gk[l] f._cvxterms += [gk[l] for gk in fmax] for fk in self._ccvterms: if 1 == len(fk) != lg: f._ccvterms += [+fk] elif type(fk) is _minmax: f._ccvterms += [fk[l]] else: # type(fk) is _sum_minmax # fk is defined as fk = sum(fmin) fmin = _minmax('min',*fk._flist) # take f += sum_j fk[j][l] = sum_{gk in fmin} gk[l] f._ccvterms += [gk[l] for gk in fmin] return f def sum(s): """ Built-in sum redefined to improve efficiency when s is a vector function. If type(s) is not _function object, this is the built-in sum without start argument. """ if type(s) is _function: lg = len(s) f = _function() if 1 == len(s._constant) != lg: f._constant = lg * s._constant else: f._constant = matrix(sum(s._constant), tc='d') if 1 == len(s._linear) != lg: f._linear = lg * s._linear else: f._linear = sum(s._linear) for c in s._cvxterms: if len(c) == 1: f._cvxterms += [lg*c] else: #type(c) must be _minmax if len(c) > 1 f._cvxterms += [_sum_minmax('max', *c._flist)] for c in s._ccvterms: if len(c) == 1: f._ccvterms += [lg*c] else: #type(c) must be _minmax if len(c) > 1 f._ccvterms += [_sum_minmax('min', *c._flist)] return f else: return builtins.sum(s) class _lin(object): """ Vector valued linear function. Attributes: _coeff dictionary {variable: coefficient}. The coefficients are dense or sparse matrices. Scalar coefficients are stored as 1x1 'd' matrices. Methods: value() returns the value of the function: None if one of the variables has value None; a dense 'd' matrix of size (len(self),1) if all the variables have values variables() returns a (copy of) the list of variables _addterm() adds a linear term a*v _mul() in-place multiplication _rmul() in-place right multiplication """ def __init__(self): self._coeff = {} def __len__(self): for v,c in iter(self._coeff.items()): if c.size[0] > 1: return c.size[0] elif _isscalar(c) and len(v) > 1: return len(v) return 1 def __repr__(self): return '' %len(self) def __str__(self): s = repr(self)[1:-1] + '\n' for v,c in iter(self._coeff.items()): s += 'coefficient of ' + repr(v) + ':\n' + str(c) return s def value(self): value = matrix(0.0, (len(self),1)) for v,c in iter(self._coeff.items()): if v.value is None: return None else: value += c*v.value return value def variables(self): return varlist(self._coeff.keys()) def _addterm(self,a,v): """ self += a*v with v variable and a int, float, 1x1 dense 'd' matrix, or sparse or dense 'd' matrix with len(v) columns. """ lg = len(self) if v in self._coeff: # self := self + a*v with v a variable of self # # Valid types/sizes: # # 1. a is a matrix (sparse or dense) with a.size[0]>1, # a.size[1]=len(v), and either lg=1 or lg=a.size[0]. # # 2. a is a matrix (sparse or dense), a.size = (1,len(v)), # lg arbitrary. # # 3. a is int or float or 1x1 dense matrix, and len(v)>1 # and either lg=1 or lg=len(v) # # 4. a is int or float or 1x1 dense matrix, and len(v)=1 c = self._coeff[v] if _ismatrix(a) and a.size[0] > 1 and a.size[1] == len(v)\ and (lg == 1 or lg == a.size[0]): newlg = a.size[0] if c.size == a.size: self._coeff[v] = c + a elif c.size == (1,len(v)): self._coeff[v] = c[newlg*[0],:] + a elif _isdmatrix(c) and c.size == (1,1): m = +a m[::newlg+1] += c[0] self._coeff[v] = m else: raise TypeError('incompatible dimensions') elif _ismatrix(a) and a.size == (1,len(v)): if c.size == (lg,len(v)): self._coeff[v] = c + a[lg*[0],:] elif c.size == (1,len(v)): self._coeff[v] = c + a elif _isdmatrix(c) and c.size == (1,1): m = a[lg*[0],:] m[::lg+1] += c[0] self._coeff[v] = m else: raise TypeError('incompatible dimensions') elif _isscalar(a) and len(v) > 1 and (lg == 1 or lg == len(v)): newlg = len(v) if c.size == (newlg,len(v)): self._coeff[v][::newlg+1] = c[::newlg+1] + a elif c.size == (1,len(v)): self._coeff[v] = c[newlg*[0],:] self._coeff[v][::newlg+1] = c[::newlg+1] + a elif _isscalar(c): self._coeff[v] = c + a else: raise TypeError('incompatible dimensions') elif _isscalar(a) and len(v) == 1: self._coeff[v] = c + a # add a to every elt of c else: raise TypeError('coefficient has invalid type or '\ 'incompatible dimensions ') elif type(v) is variable: # self := self + a*v with v not a variable of self # # 1. if a is a scalar and len(v)=lg or lg=1 or len(v)=1: # convert a to dense 1x1 matrix and add v:a pair to # dictionary # # 2. If a is a matrix (dense or sparse) and a.size[1]=len(v) # and a.size[0]=lg or lg=1 or a.size[0]=1: # make a copy of a and add v:a pair to dictionary if _isscalar(a) and (lg == 1 or len(v) == 1 or len(v) == lg): self._coeff[v] = matrix(a, tc='d') elif _ismatrix(a) and a.size[1] == len(v) and \ (lg == 1 or a.size[0] == 1 or a.size[0] == lg): self._coeff[v] = +a else: raise TypeError('coefficient has invalid type or '\ 'incompatible dimensions ') else: raise TypeError('second argument must be a variable') def _mul(self,a): ''' self := self*a where a is scalar or matrix ''' if type(a) is int or type(a) is float: for v in iter(self._coeff.keys()): self._coeff[v] *= a elif _ismatrix(a) and a.size == (1,1): for v in iter(self._coeff.keys()): self._coeff[v] *= a[0] elif len(self) == 1 and _isdmatrix(a) and a.size[1] == 1: for v,c in iter(self._coeff.items()): self._coeff[v] = a*c else: raise TypeError('incompatible dimensions') def _rmul(self,a): ''' self := a*self where a is scalar or matrix ''' lg = len(self) if _isscalar(a): for v in iter(self._coeff.keys()): self._coeff[v] *= a elif lg == 1 and _ismatrix(a) and a.size[1] == 1: for v,c in iter(self._coeff.items()): self._coeff[v] = a*c elif _ismatrix(a) and a.size[1] == lg: for v,c in iter(self._coeff.items()): if c.size == (1,len(v)): self._coeff[v] = a*c[lg*[0],:] else: self._coeff[v] = a*c else: raise TypeError('incompatible dimensions') def __pos__(self): f = _lin() for v,c in iter(self._coeff.items()): f._coeff[v] = +c return f def __neg__(self): f = _lin() for v,c in iter(self._coeff.items()): f._coeff[v] = -c return f def __add__(self,other): # self + other with other variable or _lin f = +self if type(other) is int or type(other) is float and not other: # Needed to make sum(f) work, because it defaults to # 0 + f[0] + ... + f[len(f)-1]. return f if type(other) is variable: f._addterm(1.0, other) elif type(other) is _lin: for v,c in iter(other._coeff.items()): f._addterm(c,v) else: return NotImplemented return f def __radd__(self,other): return self.__add__(other) def __iadd__(self,other): ''' self += other Only allowed if it does not change the length of self. ''' lg = len(self) if type(other) is variable and (len(other) == 1 or len(other) == lg): self._addterm(1.0,other) elif type(other) is _lin and (len(other) == 1 or len(other) == lg): for v,c in iter(other._coeff.items()): self._addterm(c,v) else: raise NotImplementedError('in-place addition must result '\ 'in a function of the same length') return self def __sub__(self,other): f = +self if type(other) is variable: f._addterm(-1.0, other) elif type(other) is _lin: for v,c in iter(other._coeff.items()): f._addterm(-c,v) else: return NotImplemented return f def __rsub__(self,other): f = -self if type(other) is variable: f._addterm(1.0, other) elif type(other) is _lin: for v,c in iter(other._coeff.items()): f._addterm(c,v) else: return NotImplemented return f def __isub__(self,other): ''' self -= other Only allowed if it does not change the length of self. ''' lg = len(self) if type(other) is variable and (len(other) == 1 or len(other) == lg): self._addterm(-1.0, other) elif type(other) is _lin and (len(other) == 1 or len(other) == lg): for v,c in iter(other._coeff.items()): self._addterm(-c,v) else: raise NotImplementedError('in-place subtraction must '\ 'result in a function of the same length') return self def __mul__(self,other): if _isscalar(other) or _ismatrix(other): f = +self f._mul(other) else: return NotImplemented return f def __rmul__(self,other): if _isscalar(other) or _ismatrix(other): f = +self f._rmul(other) else: return NotImplemented return f def __imul__(self,other): ''' self *= other Only allowed for scalar multiplication with a constant (int, float, 1x1 'd' matrix). ''' if _isscalar(other): self._mul(other) else: raise NotImplementedError('in-place multiplication ' \ 'only defined for scalar multiplication') return self def __getitem__(self,key): l = _keytolist(key,len(self)) if not l: raise ValueError('empty index set') f = _lin() for v,c in iter(self._coeff.items()): if c.size == (len(self), len(v)): f._coeff[v] = c[l,:] elif _isscalar(c) and len(v) == 1: f._coeff[v] = matrix(c, tc='d') elif c.size == (1,1) and len(v) > 1: # create a sparse matrix with 1.0 element in # position (k,l[k]) for k in range(len(l)) f._coeff[v] = spmatrix([], [], [], (len(l),len(v)), 'd') f._coeff[v][[l[k]*len(l)+k for k in range(len(l))]] \ = c[0] else: # c is 1 by len(v) f._coeff[v] = c[len(l)*[0],:] return f class _minmax(object): """ Componentwise maximum or minimum of functions. A function of the form f = max(f1,f2,...,fm) or f = max(f1) or f = min(f1,f2,...,fm) or f = min(f1) with each fi an object of type _function. If m>1, then len(f) = max(len(fi)) and f is the componentwise maximum/minimum of f1,f2,...,fm. Each fi has length 1 or length equal to len(f). If m=1, then len(f) = 1 and f is the maximum/minimum of the components of f1: f = max(f1[0],f1[1],...) or f = min(f1[0],f1[1],...). Attributes: _flist [f1,f2,...,fm] _ismax True for 'max', False for 'min' Methods: value() returns the value of the function variables() returns a copy of the list of variables """ def __init__(self,op,*s): self._flist = [] if op == 'max': self._ismax = True else: self._ismax = False if len(s) == 1: if type(s[0]) is variable or (type(s[0]) is _function and (s[0]._isconvex() and self._ismax) or (s[0]._isconcave() and not self._ismax)): self._flist += [+s[0]] else: raise TypeError('unsupported argument type') else: # cnst will be max/min of the constant arguments cnst = None lg = 1 for f in s: if type(f) is int or type(f) is float: f = matrix(f, tc='d') if _isdmatrix(f) and f.size[1] == 1: if cnst is None: cnst = +f elif self._ismax: cnst = _vecmax(cnst,f) else: cnst = _vecmin(cnst,f) elif type(f) is variable or type(f) is _function: self._flist += [+f] else: raise TypeError('unsupported argument type') lgf = len(f) if 1 != lg != lgf != 1: raise ValueError('incompatible dimensions') elif 1 == lg != lgf: lg = lgf if cnst is not None: self._flist += [_function()+cnst] def __len__(self): if len(self._flist) == 1: return 1 for f in self._flist: lg = len(f) if len(f) > 1: return lg return 1 def __repr__(self): if self._ismax: s = 'maximum' else: s = 'minimum' if len(self._flist) == 1: return '<' + s + ' component of a function of length %d>'\ %len(self._flist[0]) else: return "" %(len(self._flist),len(self)) def __str__(self): s = repr(self)[1:-1] + ':' if len(self._flist) == 1: s += '\n' + repr(self._flist[0])[1:-1] else: for k in range(len(self._flist)): s += "\nfunction %d: " %k + repr(self._flist[k])[1:-1] return s def value(self): if self._ismax: return _vecmax(*[f.value() for f in self._flist]) else: return _vecmin(*[f.value() for f in self._flist]) def variables(self): l = varlist() for f in self._flist: l += [v for v in f.variables() if v not in l] return l def __pos__(self): if self._ismax: f = _minmax('max', *[+fk for fk in self._flist]) else: f = _minmax('min', *[+fk for fk in self._flist]) return f def __neg__(self): if self._ismax: f = _minmax('min', *[-fk for fk in self._flist]) else: f = _minmax('max', *[-fk for fk in self._flist]) return f def __mul__(self,other): if type(other) is int or type(other) is float or \ (_ismatrix(other) and other.size == (1,1)): if _ismatrix(other): other = other[0] if other >= 0.0: if self._ismax: f = _minmax('max', *[other*fk for fk in self._flist]) else: f = _minmax('min', *[other*fk for fk in self._flist]) else: if self._ismax: f = _minmax('min', *[other*fk for fk in self._flist]) else: f = _minmax('max', *[other*fk for fk in self._flist]) return f else: return NotImplemented def __rmul__(self,other): return self.__mul__(other) def __imul__(self,other): if _isscalar(other): if type(other) is matrix: other = other[0] for f in self._flist: f *= other if other < 0.0: self._ismax = not self._ismax return self raise NotImplementedError('in-place multiplication is only '\ 'defined for scalars') def __getitem__(self,key): lg = len(self) l = _keytolist(key,lg) if not l: raise ValueError('empty index set') if len(self._flist) == 1: fl = list(self._flist[0]) else: fl = self._flist if self._ismax: f = _minmax('max') else: f = _minmax('min') for fk in fl: if 1 == len(fk) != lg: f._flist += [+fk] else: f._flist += [fk[l]] return f def max(*s): """ Identical to the built-in max except when some of the arguments are variables or functions. f = max(s1,s2,...) returns the componentwise maximum of s1,s2,.., as a convex function with len(f) = max(len(si)). The arguments si can be scalars, 1-column dense 'd' matrices, variables, or functions. At least one argument must be a function or a variable. The arguments can be scalars or vectors with length equal to len(f). f = max(s) with len(s) > 1 returns the maximum component of s as a function with len(f) = 1. The argument can be a variable or a function. f = max(s) with len(s) = 1 and s[0] a function returns s[0]. f = max(s) with s a list or tuple of variables, functions, constants, returns f = max(*s). Does not work with generators (Python 2.4). """ try: return builtins.max(*s) except NotImplementedError: f = _function() try: f._cvxterms = [_minmax('max',*s)] return f except: # maybe s[0] is a list or tuple of variables, functions # and constants try: return max(*s[0]) except: raise NotImplementedError def min(*s): """ Identical to the built-in min except when some of the arguments are variables or functions. f = min(s1,s2,...) returns the componentwise minimum of s1,s2,.., as function with len(f) = max(len(si)). The arguments si can be scalars, 1-column dense 'd' matrices, variables, or functions. At least one argument must be a function or a variable. The arguments can be scalars or vectors with length equal to len(f). f = min(s) with len(s) > 1 returns the minimum component of s as a function with len(f) = 1. The argument can be a variable or a function. f = min(s) with len(s) = 1 returns s[0]. f = min(s) with s a list or tuple of variables, functions, constants, returns f = min(*s). Does not work with generators (Python 2.4). """ try: return builtins.min(*s) except NotImplementedError: f = _function() try: f._ccvterms = [_minmax('min',*s)] return f except: # maybe s[0] is a list or tuple of variables, functions # and constants try: return min(*s[0]) except: raise NotImplementedError class _sum_minmax(_minmax): """ Sum of componentwise maximum or minimum of functions. A function of the form f = sum(max(f1,f2,...,fm)) or f = sum(min(f1,f2,...,fm)) with each fi an object of type _function. m must be greater than 1. len(f) = 1. Each fi has length 1 or length equal to max_i len(fi)). Attributes: _flist [f1,f2,...,fm] _ismax True for 'max', False for 'min' Methods: value() returns the value of the function variables() returns a copy of the list of variables _length() number of terms in the sum """ def __init__(self,op,*s): _minmax.__init__(self,op,*s) if len(self._flist) == 1: raise TypeError('expected more than 1 argument') def __len__(self): return 1 def _length(self): for f in self._flist: lg = len(f) if len(f) > 1: return lg return 1 def __repr__(self): if self._ismax: s = 'maximum' else: s = 'minimum' return "" %(len(self._flist),len(self)) def __str__(self): s = repr(self)[1:-1] for k in range(len(self._flist)): s += "\nfunction %d: " %k + repr(self._flist[k])[1:-1] return s def value(self): if self._ismax: return matrix(sum(_vecmax(*[f.value() for f in self._flist])), tc='d') else: return matrix(sum(_vecmin(*[f.value() for f in self._flist])), tc='d') def __pos__(self): if self._ismax: f = _sum_minmax('max', *[+fk for fk in self._flist]) else: f = _sum_minmax('min', *[+fk for fk in self._flist]) return f def __neg__(self): if self._ismax: f = _sum_minmax('min', *[-fk for fk in self._flist]) else: f = _sum_minmax('max', *[-fk for fk in self._flist]) return f def __mul__(self,other): if type(other) is int or type(other) is float or \ (_ismatrix(other) and other.size == (1,1)): if _ismatrix(other): other = other[0] if other >= 0.0: if self._ismax: f = _sum_minmax('max', *[other*fk for fk in self._flist]) else: f = _sum_minmax('min', *[other*fk for fk in self._flist]) else: if self._ismax: f = _sum_minmax('min', *[other*fk for fk in self._flist]) else: f = _sum_minmax('max', *[other*fk for fk in self._flist]) return f else: return NotImplemented def __rmul__(self,other): return self.__mul__(other) def __getitem__(self,key): l = _keytolist(key,1) if not l: raise ValueError('empty index set') # expand sum and convert to a _function if self._ismax: f = sum(_minmax('max',*self._flist)) else: f = sum(_minmax('min',*self._flist)) return f[l] class constraint(object): """ Equality or inequality constraint. constraint(f, ctype='=', name='') constructs a constraint f=0 (if ctype is '=') or f<=0 (if ctype is '<'). Arguments: f convex function if '<', affine function if '=' ctype '=' or '<' name string with the constraint name Attributes: multiplier a variable of length len(f). multiplier.name is the constraint name with '_mul' appended. name constraint name. Writing to .name also modifies the name of .multiplier. _f the constraint function (borrowed reference) _type '=' or '<' Methods: value() returns the value of the constraint function variables() returns the variables of the constraint function type() returns ._type _aslinearineq() converts convex piecewise-linear inequality into an equivalent set of linear inequalities """ def __init__(self, f, ctype='=', name=''): if ctype == '=' or ctype == '<': self._type = ctype else: raise TypeError("'ctype' argument must be '<' or '='") if type(f) is not _function: raise TypeError("'f' argument must be a function") if ctype == '=': if f._isaffine(): self._f = f else: raise TypeError("constraint function must be affine") else: if f._isconvex(): self._f = f else: raise TypeError("constraint function must be convex") self.name = name self.multiplier = variable(len(self), name + '_mul') def __len__(self): return len(self._f) def __repr__(self): lg = len(self) if self._type == '=': s = 'equality' else: s = 'inequality' if lg == 1: t = "" else: return t + ">" def __str__(self): return repr(self)[1:-1] + '\nconstraint function:\n' + \ str(self._f) def __setattr__(self,name,value): if name == 'name': if type(value) is str: object.__setattr__(self,name,value) if hasattr(self,'multiplier'): self.multiplier.name = value + '_mul' else: raise TypeError("invalid type for attribute 'name'") elif name == 'multiplier' or name == '_type' or name == '_f': object.__setattr__(self,name,value) else: raise AttributeError("'constraint' object has no "\ "attribute '%s'" %name) def type(self): """ Returns '=' for equality constraints, '<' for inequality.""" return self._type def value(self): """ Returns value of the constraint function.""" return self._f.value() def variables(self): """ Returns a list of variables of the constraint function.""" return self._f.variables() def _aslinearineq(self): """ Converts a convex PWL inequality into an equivalent set of linear inequalities. Returns a tuple (ineqs, aux_ineqs, aux_vars). If self is a linear inequailty, then ineqs = [self], aux_ineqs = [], aux_vars = []. If self is PWL then ineqs and aux_ineqs are two lists of linear inequalities that together are equivalent to self. They are separated in two sets so that the multiplier for self depends only on the multipliers of the constraints in ineqs: - if len(self) == max(len(ineqs[k])), then the multiplier of self is sum_k ineqs[k].multiplier - if len(self) == max(len(ineqs[k])), then the multiplier of self is sum(sum_k ineqs[k].multiplier) aux_vars is a varlist with new auxiliary variables. """ if self.type() != '<': raise TypeError('constraint must be an inequality') ineqs, aux_ineqs, aux_vars = [], [], varlist() # faff._constant and faff._linear are references to the # affine part of the constraint function faff = _function() faff._constant = self._f._constant faff._linear = self._f._linear cvxterms = self._f._cvxterms if not cvxterms: # inequality is linear ineqs += [self] elif len(cvxterms) == 1 and type(cvxterms[0]) is _minmax: # constraint is of the form f = faff + max() <= 0 if len(cvxterms[0]._flist) == 1: # constraint of the form f = faff + max(f0) <= 0 f0 = cvxterms[0]._flist[0] if len(faff) == 1: # write as scalar + f0 <= 0 with f0 possibly a # vector c = faff + f0 <= 0 c.name = self.name c, caux, newvars = c._aslinearineq() ineqs += c aux_ineqs += caux aux_vars += newvars else: # write as vector + f0[k] <= 0 for all k for k in range(len(f0)): c = faff + f0[k] <= 0 c.name = self.name + '(%d)' %k c, caux, newvars = c._aslinearineq() ineqs += c aux_ineqs += caux aux_vars += newvars else: # constraint of the form f = faff + max(f0,f1,...) <= 0 for k in range(len(cvxterms[0]._flist)): c = faff + cvxterms[0]._flist[k] <= 0 c.name = self.name + '(%d)' %k c, caux, newvars = c._aslinearineq() ineqs += c aux_ineqs += caux aux_vars += newvars else: # constraint is of the form f = faff + g1 + g2 .... <= 0 # with gi = max() or sum max() and the number of gi's can # be one. sumt = _function() for k in range(len(cvxterms)): if type(cvxterms[k]) is _minmax: # gk is max(f0,f1,...) tk = variable(len(cvxterms[k]), self.name + '_x' + str(k)) aux_vars += [tk] sumt = sumt + tk if len(cvxterms[k]._flist) == 1: # add constraint gk = max(f0) <= tk f0 = cvxterms[k]._flist[0] c = f0 <= tk c.name = self.name + '[%d]' %k c, caux, newvars = c._aslinearineq() aux_ineqs += c + caux aux_vars += newvars else: # add constraint gk = max(f0,f1, ... ) <= tk for j in range(len(cvxterms[k]._flist)): fj = cvxterms[k]._flist[j] c = fj <= tk c.name = self.name + '[%d](%d)' %(k,j) c, caux, newvars = c._aslinearineq() aux_ineqs += c + caux aux_vars += newvars else: # gk is sum(max(f0,f1,...) tk = variable(cvxterms[k]._length(), self.name + '_x' + str(k)) aux_vars += [tk] sumt = sumt + sum(tk) # add contraint max(f0,f1, ... ) <= tk for j in range(len(cvxterms[k]._flist)): fj = cvxterms[k]._flist[j] c = fj <= tk c.name = self.name + '[%d](%d)' %(k,j) c, caux, newvars = c._aslinearineq() aux_ineqs += c + caux aux_vars += newvars c = faff + sumt <= 0 c.name = self.name ineqs += [c] return (ineqs, aux_ineqs, aux_vars) class op(object): """ An optimization problem. op(objective=0.0, constraints=None, name '') constructs an optimization problem. Arguments: objective scalar (int, float, 1x1 dense 'd' matrix), scalar variable, scalar affine function or scalar convex piecewise-linear function. Scalars and variables are converted to affine functions. constraints None, a single constraint, or a list of constraints None means the same as an empty list. A single constraint means the same as a singleton list. name string with the name of the LP Attributes: objective the objective function (borrowed reference to the function passed as argument). name the name of the optimization problem status initially None. After solving the problem, summarizes the outcome. _inequalities list of inequality constraints _equalities list of equality constraints _variables a dictionary {v: dictionary with keys 'o','i','e'} The keys v are the variables in the problem. 'o': True/False depending on whether v appears in the objective or not; 'i': list of inequality constraints v appears in; 'e': list of equality constraints v appears in. Methods: variables() returns a list of variables. The list is a varlist (defined below), ie, a subclass of 'list'. constraints() returns a list of constraints inequalities() returns a list of inequality constraints equalities() returns a list of equality constraints delconstraint() deletes a constraint addconstraint() adds a constraint _inmatrixform() returns an equivalent LP in matrix form solve() solves the problem tofile() if the problem is an LP, writes it to an MPS file fromfile() reads an LP from an MPS file """ def __init__(self, objective=0.0, constraints=None, name=''): self._variables = dict() self.objective = objective for v in self.objective.variables(): self._variables[v] = {'o': True, 'i': [], 'e': []} self._inequalities, self._equalities = [], [] if constraints is None: pass elif type(constraints) is constraint: if constraints.type() == '<': self._inequalities += [constraints] else: self._equalities += [constraints] elif type(constraints) == list and not [c for c in constraints if type(c) is not constraint]: for c in constraints: if c.type() == '<': self._inequalities += [c] else: self._equalities += [c] else: raise TypeError('invalid argument for constraints') for c in self._inequalities: for v in c.variables(): if v in self._variables: self._variables[v]['i'] += [c] else: self._variables[v] = {'o': False, 'i': [c], 'e': []} for c in self._equalities: for v in c.variables(): if v in self._variables: self._variables[v]['e'] += [c] else: self._variables[v] = {'o': False, 'i': [], 'e': [c]} self.name = name self.status = None def __repr__(self): n = sum(map(len,self._variables)) m = sum(map(len,self._inequalities)) p = sum(map(len,self._equalities)) return "" %(n,m,p) def __setattr__(self,name,value): if name == 'objective': if _isscalar(value): value = _function() + value elif type(value) is variable and len(value) == 1: value = +value elif type(value) is _function and value._isconvex() and \ len(value) == 1: pass else: raise TypeError("attribute 'objective' must be a "\ "scalar affine or convex PWL function") # remove variables in _variables that only appear in current # objective for v in self.variables(): if not self._variables[v]['i'] and not \ self._variables[v]['e']: del self._variables[v] object.__setattr__(self,'objective',value) # update _variables for v in self.objective.variables(): if v not in self._variables: self._variables[v] = {'o': True, 'i': [], 'e': []} else: self._variables[v]['o'] = True elif name == 'name': if type(value) is str: object.__setattr__(self,name,value) else: raise TypeError("attribute 'name' must be string") elif name == '_inequalities' or name == '_equalities' or \ name == '_variables' or name == 'status': object.__setattr__(self,name,value) else: raise AttributeError("'op' object has no attribute "\ "'%s'" %name) def variables(self): """ Returns a list of variables of the LP. """ return varlist(self._variables.keys()) def constraints(self): """ Returns a list of constraints of the LP.""" return self._inequalities + self._equalities def equalities(self): """ Returns a list of equality constraints of the LP.""" return list(self._equalities) def inequalities(self): """ Returns a list of inequality constraints of the LP.""" return list(self._inequalities) def delconstraint(self,c): """ Deletes constraint c from the list of constrains """ if type(c) is not constraint: raise TypeError("argument must be of type 'constraint'") try: if c.type() == '<': self._inequalities.remove(c) for v in c.variables(): self._variables[v]['i'].remove(c) else: self._equalities.remove(c) for v in c.variables(): self._variables[v]['e'].remove(c) if not self._variables[v]['o'] and \ not self._variables[v]['i'] and \ not self._variables[v]['e']: del self._variables[v] except ValueError: # c is not a constraint pass def addconstraint(self,c): """ Adds constraint c to the list of constraints. """ if type(c) is not constraint: raise TypeError('argument must be of type constraint') if c.type() == '<': self._inequalities += [c] if c.type() == '=': self._equalities += [c] for v in c.variables(): if c.type() == '<': if v in self._variables: self._variables[v]['i'] += [c] else: self._variables[v] = {'o': False, 'i': [c], 'e': []} else: if v in self._variables: self._variables[v]['e'] += [c] else: self._variables[v] = {'o': False, 'i': [], 'e': [c]} def _islp(self): """ Returns True if self is an LP; False otherwise. """ if not self.objective._isaffine(): return False for c in self._inequalities: if not c._f._isaffine(): return False for c in self._equalities: if not c._f._isaffine(): return False return True def _inmatrixform(self, format='dense'): """ Converts self to an LP in matrix form minimize c'*x+d subject to G*x <= h A*x = b. c, h, b are dense column matrices; G and A sparse or dense matrices depending on format ('sparse' or 'dense'). If self is already an LP in matrix form with the correct matrix types, then _inmatrixform() returns None. Otherwise it returns a tuple (newlp, vmap, mmap). newlp is an LP in matrix form with the correct format and matrix types. vmap is a dictionary with the variables of self as keys and affine functions as values. For each variable v of self, vmap[v] is a function of the new variable x that can be evaluated to obtain the solution v from the solution x. mmap is a dictionary with the constraints of self as keys and affine functions as values. For each constraint c of self, mmap[c] is a function of the multipliers of the new lp that can be evaluated to obtain the optimal multiplier for c. """ variables, aux_variables = self.variables(), varlist() # lin_ineqs is a list of linear inequalities in the original # problem. pwl_ineqs is a dictionary {i: [c1,c2,...], ...} # where i is a PWL inequality in the original problem. # aux_ineqs are new auxiliary inequalities that together # with the ck constraints in pwl_ineqs are equivalent to the # original ones. The sum of the multipliers of the constraints # in pwl_ineqs[i] forms the multiplier of i. lin_ineqs, pwl_ineqs, aux_ineqs = [], dict(), [] for i in self._inequalities: if i._f._isaffine(): lin_ineqs += [i] else: pwl_ineqs[i] = [] equalities = self._equalities objective = +self.objective # return None if self is already an LP in the requested form if objective._isaffine() and len(variables) == 1 and \ not pwl_ineqs and len(lin_ineqs) <= 1 and \ len(equalities) <= 1: v = variables[0] if lin_ineqs: G = lin_ineqs[0]._f._linear._coeff[v] else: G = None if equalities: A = equalities[0]._f._linear._coeff[v] else: A = None if (format == 'dense' and (G is None or _isdmatrix(G)) and (A is None or _isdmatrix(A))) or \ (format == 'sparse' and (G is None or _isspmatrix(G)) and (A is None or _isspmatrix(A))): return None # convert PWL objective to linear if not objective._isaffine(): # f = affine + sum_k fk with each fk a maximum of convex # functions or a sum of a maximum of convex functions. # If fk is a maximum of convex functions we introduce a # new variable tk and replace fk in the objective with tk, # with a new constraint fk <= tk. # If fk is sum(gk) where gk is a maximum of convex # functions we introduce a new variable tk and replace fk # in the objective with sum(tk) with a new constraint # gk <= tk. newobj = _function() newobj._constant = +objective._constant newobj._linear = +objective._linear for k in range(len(objective._cvxterms)): fk = objective._cvxterms[k] if type(fk) is _minmax: tk = variable(1, self.name + '_x' + str(k)) newobj += tk else: tk = variable(fk._length(), self.name + '_x' + str(k)) newobj += sum(tk) aux_variables += [tk] for j in range(len(fk._flist)): c = fk._flist[j] <= tk if len(fk._flist) > 1: c.name = self.name + '[%d](%d)' %(k,j) else: c.name = self.name + '[%d]' %k c, caux, newvars = c._aslinearineq() aux_ineqs += c + caux aux_variables += newvars objective = newobj # convert PWL inequalities to linear for i in pwl_ineqs: pwl_ineqs[i], caux, newvars = i._aslinearineq() aux_ineqs += caux aux_variables += newvars # n is the length of x, c # The variables are available in variables and aux_variables. # variable v is stored in x[vslc[v]] vslc = dict() n = 0 for v in variables + aux_variables: vslc[v] = slice(n, n+len(v)) n += len(v) c = matrix(0.0, (1,n)) for v,cf in iter(objective._linear._coeff.items()): if _isscalar(cf): c[vslc[v]] = cf[0] elif _isdmatrix(cf): c[vslc[v]] = cf[:] else: c[vslc[v]] = matrix(cf[:], tc='d') if n > 0: x = variable(n) cost = c*x + objective._constant else: cost = _function() + objective._constant[0] vmap = dict() for v in variables: vmap[v] = x[vslc[v]] # m is the number of rows of G, h # The inequalities are available in lin_lineqs, pwl_ineqs, # aux_ineqs. # inequality i is stored in G[islc[i],:]*x <= h[islc[i]] islc = dict() for i in lin_ineqs + aux_ineqs: islc[i] = None for c in pwl_ineqs: for i in pwl_ineqs[c]: islc[i] = None m = 0 for i in islc: islc[i] = slice(m, m+len(i)) m += len(i) if format == 'sparse': G = spmatrix(0.0, [], [], (m,n)) else: G = matrix(0.0, (m,n)) h = matrix(0.0, (m,1)) for i in islc: lg = len(i) for v,cf in iter(i._f._linear._coeff.items()): if cf.size == (lg, len(v)): if _isspmatrix(cf) and _isdmatrix(G): G[islc[i], vslc[v]] = matrix(cf, tc='d') else: G[islc[i], vslc[v]] = cf elif cf.size == (1, len(v)): if _isspmatrix(cf) and _isdmatrix(G): G[islc[i], vslc[v]] = \ matrix(cf[lg*[0],:], tc='d') else: G[islc[i], vslc[v]] = cf[lg*[0],:] else: #cf.size[0] == (1,1): G[islc[i].start+m*vslc[v].start: islc[i].stop+m*vslc[v].stop:m+1] = cf[0] if _isscalar(i._f._constant): h[islc[i]] = -i._f._constant[0] else: h[islc[i]] = -i._f._constant[:] # p is the number of rows in A, b # equality e is stored A[eslc[e],:]*x == b[eslc[e]] eslc = dict() p = 0 for e in equalities: eslc[e] = slice(p, p+len(e)) p += len(e) if format == 'sparse': A = spmatrix(0.0, [], [], (p,n)) else: A = matrix(0.0, (p,n)) b = matrix(0.0, (p,1)) for e in equalities: lg = len(e) for v,cf in iter(e._f._linear._coeff.items()): if cf.size == (lg,len(v)): if _isspmatrix(cf) and _isdmatrix(A): A[eslc[e], vslc[v]] = matrix(cf, tc='d') else: A[eslc[e], vslc[v]] = cf elif cf.size == (1, len(v)): if _isspmatrix(cf) and _isdmatrix(A): A[eslc[e], vslc[v]] = \ matrix(cf[lg*[0],:], tc='d') else: A[eslc[e], vslc[v]] = cf[lg*[0],:] else: #cf.size[0] == (1,1): A[eslc[e].start+p*vslc[v].start: eslc[e].stop+p*vslc[v].stop:p+1] = cf[0] if _isscalar(e._f._constant): b[eslc[e]] = -e._f._constant[0] else: b[eslc[e]] = -e._f._constant[:] constraints = [] if n: if m: constraints += [G*x<=h] if p: constraints += [A*x==b] else: if m: constraints += [_function()-h <= 0] if p: constraints += [_function()-b == 0] mmap = dict() for i in lin_ineqs: mmap[i] = constraints[0].multiplier[islc[i]] for i in pwl_ineqs: mmap[i] = _function() for c in pwl_ineqs[i]: mmap[i] = mmap[i] + constraints[0].multiplier[islc[c]] if len(i) == 1 != len(mmap[i]): mmap[i] = sum(mmap[i]) for e in equalities: mmap[e] = constraints[1].multiplier[eslc[e]] return (op(cost, constraints), vmap, mmap) def solve(self, format='dense', solver = 'default'): """ Solves LP using dense or sparse solver. format is 'dense' or 'sparse' solver is 'default', 'glpk' or 'mosek' solve() sets self.status, and if status is 'optimal', also the value attributes of the variables and the constraint multipliers. If solver is 'python' then if status is 'primal infeasible', the constraint multipliers are set to a proof of infeasibility; if status is 'dual infeasible' the variables are set to a proof of dual infeasibility. """ t = self._inmatrixform(format) if t is None: lp1 = self else: lp1, vmap, mmap = t[0], t[1], t[2] variables = lp1.variables() if not variables: raise TypeError('lp must have at least one variable') x = variables[0] c = lp1.objective._linear._coeff[x] if _isspmatrix(c): c = matrix(c, tc='d') inequalities = lp1._inequalities if not inequalities: raise TypeError('lp must have at least one inequality') G = inequalities[0]._f._linear._coeff[x] h = -inequalities[0]._f._constant equalities = lp1._equalities if equalities: A = equalities[0]._f._linear._coeff[x] b = -equalities[0]._f._constant elif format == 'dense': A = matrix(0.0, (0,len(x))) b = matrix(0.0, (0,1)) else: A = spmatrix(0.0, [], [], (0,len(x))) b = matrix(0.0, (0,1)) sol = solvers.lp(c[:], G, h, A, b, solver=solver) x.value = sol['x'] inequalities[0].multiplier.value = sol['z'] if equalities: equalities[0].multiplier.value = sol['y'] self.status = sol['status'] if type(t) is tuple: for v,f in iter(vmap.items()): v.value = f.value() for c,f in iter(mmap.items()): c.multiplier.value = f.value() def tofile(self, filename): ''' writes LP to file 'filename' in MPS format. ''' if not self._islp(): raise TypeError('problem must be an LP') constraints = self.constraints() variables = self.variables() inequalities = self.inequalities() equalities = self.equalities() f = open(filename,'w') f.write('NAME') if self.name: f.write(10*' ' + self.name[:8].rjust(8)) f.write('\n') f.write('ROWS\n') f.write(' N %8s\n' %'cost') for k in range(len(constraints)): c = constraints[k] for i in range(len(c)): if c._type == '<': f.write(' L ') else: f.write(' E ') if c.name: name = c.name else: name = str(k) name = name[:(7-len(str(i)))] + '_' + str(i) f.write(name.rjust(8)) f.write('\n') f.write('COLUMNS\n') for k in range(len(variables)): v = variables[k] for i in range(len(v)): if v.name: varname = v.name else: varname = str(k) varname = varname[:(7-len(str(i)))] + '_' + str(i) if v in self.objective._linear._coeff: cf = self.objective._linear._coeff[v] if cf[i] != 0.0: f.write(4*' ' + varname[:8].rjust(8)) f.write(2*' ' + '%8s' %'cost') f.write(2*' ' + '% 7.5E\n' %cf[i]) for j in range(len(constraints)): c = constraints[j] if c.name: cname = c.name else: cname = str(j) if v in c._f._linear._coeff: cf = c._f._linear._coeff[v] if cf.size == (len(c),len(v)): nz = [k for k in range(cf.size[0]) if cf[k,i] != 0.0] for l in nz: conname = cname[:(7-len(str(l)))] \ + '_' + str(l) f.write(4*' ' + varname[:8].rjust(8)) f.write(2*' ' + conname[:8].rjust(8)) f.write(2*' ' + '% 7.5E\n' %cf[l,i]) elif cf.size == (1,len(v)): if cf[0,i] != 0.0: for l in range(len(c)): conname = cname[:(7-len(str(l)))] \ + '_' + str(l) f.write(4*' ' + varname[:8].rjust(8)) f.write(2*' ' + conname[:8].rjust(8)) f.write(2*' '+'% 7.5E\n' %cf[0,i]) elif _isscalar(cf): if cf[0,0] != 0.0: conname = cname[:(7-len(str(i)))] \ + '_' + str(i) f.write(4*' ' + varname[:8].rjust(8)) f.write(2*' ' + conname[:8].rjust(8)) f.write(2*' ' + '% 7.5E\n' %cf[0,0]) f.write('RHS\n') for j in range(len(constraints)): c = constraints[j] if c.name: cname = c.name else: cname = str(j) const = -c._f._constant for l in range(len(c)): conname = cname[:(7-len(str(l)))] + '_' + str(l) f.write(14*' ' + conname[:8].rjust(8)) if const.size[0] == len(c): f.write(2*' ' + '% 7.5E\n' %const[l]) else: f.write(2*' ' + '% 7.5E\n' %const[0]) f.write('RANGES\n') f.write('BOUNDS\n') for k in range(len(variables)): v = variables[k] for i in range(len(v)): if v.name: varname = v.name else: varname = str(k) varname = varname[:(7-len(str(i)))] + '_' + str(i) f.write(' FR ' + 10*' ' + varname[:8].rjust(8) + '\n') f.write('ENDATA\n') f.close() def fromfile(self, filename): ''' Reads LP from file 'filename' assuming it is a fixed format ascii MPS file. Does not include serious error checking. MPS features that are not allowed: comments preceded by dollar signs, linear combinations of rows, multiple righthand sides, ranges columns or bounds columns. ''' self._inequalities = [] self._equalities = [] self.objective = _function() self.name = '' f = open(filename,'r') s = f.readline() while s[:4] != 'NAME': s = f.readline() if not s: raise SyntaxError("EOF reached before 'NAME' section "\ "was found") self.name = s[14:22].strip() s = f.readline() while s[:4] != 'ROWS': if not s: raise SyntaxError("EOF reached before 'ROWS' section "\ "was found") s = f.readline() s = f.readline() # ROWS section functions = dict() # {MPS row label: affine function} rowtypes = dict() # {MPS row label: 'E', 'G' or 'L'} foundobj = False # first occurrence of 'N' counts while s[:7] != 'COLUMNS': if not s: raise SyntaxError("file has no 'COLUMNS' section") if len(s.strip()) == 0 or s[0] == '*': pass elif s[1:3].strip() in ['E','L','G']: rowlabel = s[4:12].strip() functions[rowlabel] = _function() rowtypes[rowlabel] = s[1:3].strip() elif s[1:3].strip() == 'N': rowlabel = s[4:12].strip() if not foundobj: functions[rowlabel] = self.objective foundobj = True else: raise ValueError("unknown row type '%s'" %s[1:3].strip()) s = f.readline() s = f.readline() # COLUMNS section variables = dict() # {MPS column label: variable} while s[:3] != 'RHS': if not s: raise SyntaxError("EOF reached before 'RHS' section "\ "was found") if len(s.strip()) == 0 or s[0] == '*': pass else: if s[4:12].strip(): collabel = s[4:12].strip() if collabel not in variables: variables[collabel] = variable(1,collabel) v = variables[collabel] rowlabel = s[14:22].strip() if rowlabel not in functions: raise KeyError("no row label '%s'" %rowlabel) functions[rowlabel]._linear._coeff[v] = \ matrix(float(s[24:36]), tc='d') rowlabel = s[39:47].strip() if rowlabel: if rowlabel not in functions: raise KeyError("no row label '%s'" %rowlabel) functions[rowlabel]._linear._coeff[v] = \ matrix(float(s[49:61]), tc='d') s = f.readline() s = f.readline() # RHS section # The RHS section may contain multiple right hand sides, # identified with different labels in s[4:12]. # We read in only one rhs, the one with the first rhs label # encountered. rhslabel = None while s[:6] != 'RANGES' and s[:6] != 'BOUNDS' and \ s[:6] != 'ENDATA': if not s: raise SyntaxError( \ "EOF reached before 'ENDATA' was found") if len(s.strip()) == 0 or s[0] == '*': pass else: if None != rhslabel != s[4:12].strip(): # skip if rhslabel is different from 1st rhs label # encountered pass else: if rhslabel is None: rhslabel = s[4:12].strip() rowlabel = s[14:22].strip() if rowlabel not in functions: raise KeyError("no row label '%s'" %rowlabel) functions[rowlabel]._constant = \ matrix(-float(s[24:36]), tc='d') rowlabel = s[39:47].strip() if rowlabel: if rowlabel not in functions: raise KeyError("no row label '%s'" \ %rowlabel) functions[rowlabel]._constant = \ matrix(-float(s[49:61]), tc='d') s = f.readline() # RANGES section # The RANGES section may contain multiple range vectors, # identified with different labels in s[4:12]. # We read in only one vector, the one with the first range label # encountered. ranges = dict() for l in iter(rowtypes.keys()): ranges[l] = None # {rowlabel: range value} rangeslabel = None if s[:6] == 'RANGES': s = f.readline() while s[:6] != 'BOUNDS' and s[:6] != 'ENDATA': if not s: raise SyntaxError( \ "EOF reached before 'ENDATA' was found") if len(s.strip()) == 0 or s[0] == '*': pass else: if None != rangeslabel != s[4:12].strip(): pass else: if rangeslabel == None: rangeslabel = s[4:12].strip() rowlabel = s[14:22].strip() if rowlabel not in rowtypes: raise KeyError("no row label '%s'"%rowlabel) ranges[rowlabel] = float(s[24:36]) rowlabel = s[39:47].strip() if rowlabel != '': if rowlabel not in functions: raise KeyError("no row label '%s'" \ %rowlabel) ranges[rowlabel] = float(s[49:61]) s = f.readline() # BOUNDS section # The BOUNDS section may contain bounds vectors, identified # with different labels in s[4:12]. # We read in only one bounds vector, the one with the first # label encountered. boundslabel = None bounds = dict() for v in iter(variables.keys()): bounds[v] = [0.0, None] #{column label: [l.bound, u. bound]} if s[:6] == 'BOUNDS': s = f.readline() while s[:6] != 'ENDATA': if not s: raise SyntaxError( \ "EOF reached before 'ENDATA' was found") if len(s.strip()) == 0 or s[0] == '*': pass else: if None != boundslabel != s[4:12].strip(): pass else: if boundslabel is None: boundslabel = s[4:12].strip() collabel = s[14:22].strip() if collabel not in variables: raise ValueError('unknown column label ' \ + "'%s'" %collabel) if s[1:3].strip() == 'LO': if bounds[collabel][0] != 0.0: raise ValueError("repeated lower "\ "bound for variable '%s'" %collabel) bounds[collabel][0] = float(s[24:36]) elif s[1:3].strip() == 'UP': if bounds[collabel][1] != None: raise ValueError("repeated upper "\ "bound for variable '%s'" %collabel) bounds[collabel][1] = float(s[24:36]) elif s[1:3].strip() == 'FX': if bounds[collabel] != [0, None]: raise ValueError("repeated bounds "\ "for variable '%s'" %collabel) bounds[collabel][0] = float(s[24:36]) bounds[collabel][1] = float(s[24:36]) elif s[1:3].strip() == 'FR': if bounds[collabel] != [0, None]: raise ValueError("repeated bounds "\ "for variable '%s'" %collabel) bounds[collabel][0] = None bounds[collabel][1] = None elif s[1:3].strip() == 'MI': if bounds[collabel][0] != 0.0: raise ValueError("repeated lower " \ "bound for variable '%s'" %collabel) bounds[collabel][0] = None elif s[1:3].strip() == 'PL': if bounds[collabel][1] != None: raise ValueError("repeated upper " \ "bound for variable '%s'" %collabel) else: raise ValueError("unknown bound type '%s'"\ %s[1:3].strip()) s = f.readline() for l, type in iter(rowtypes.items()): if type == 'L': c = functions[l] <= 0.0 c.name = l self._inequalities += [c] if ranges[l] != None: c = functions[l] >= -abs(ranges[l]) c.name = l + '_lb' self._inequalities += [c] if type == 'G': c = functions[l] >= 0.0 c.name = l self._inequalities += [c] if ranges[l] != None: c = functions[l] <= abs(ranges[l]) c.name = l + '_ub' self._inequalities += [c] if type == 'E': if ranges[l] is None or ranges[l] == 0.0: c = functions[l] == 0.0 c.name = l self._equalities += [c] elif ranges[l] > 0.0: c = functions[l] >= 0.0 c.name = l + '_lb' self._inequalities += [c] c = functions[l] <= ranges[l] c.name = l + '_ub' self._inequalities += [c] else: c = functions[l] <= 0.0 c.name = l + '_ub' self._inequalities += [c] c = functions[l] >= ranges[l] c.name = l + '_lb' self._inequalities += [c] for l,bnds in iter(bounds.items()): v = variables[l] if None != bnds[0] != bnds[1]: c = v >= bnds[0] self._inequalities += [c] if bnds[0] != bnds[1] != None: c = v <= bnds[1] self._inequalities += [c] if None != bnds[0] == bnds[1]: c = v == bnds[0] self._equalities += [c] # Eliminate constraints with no variables for c in self._inequalities + self._equalities: if len(c._f._linear._coeff) == 0: if c.type() == '=' and c._f._constant[0] != 0.0: raise ValueError("equality constraint '%s' "\ "has no variables and a nonzero righthand side"\ %c.name) elif c.type() == '<' and c._f._constant[0] > 0.0: raise ValueError("inequality constraint '%s' "\ "has no variables and a negative righthand side"\ %c.name) else: print("removing redundant constraint '%s'" %c.name) if c.type() == '<': self._inequalities.remove(c) if c.type() == '=': self._equalities.remove(c) self._variables = dict() for v in self.objective._linear._coeff.keys(): self._variables[v] = {'o': True, 'i': [], 'e': []} for c in self._inequalities: for v in c._f._linear._coeff.keys(): if v in self._variables: self._variables[v]['i'] += [c] else: self._variables[v] = {'o': False, 'i': [c], 'e': []} for c in self._equalities: for v in c._f._linear._coeff.keys(): if v in self._variables: self._variables[v]['e'] += [c] else: self._variables[v] = {'o': False, 'i': [], 'e': [c]} self.status = None f.close() def dot(x,y): """ Inner products of variable or affine function with constant vector. """ if _isdmatrix(x) and _isdmatrix(y): return blas.dot(x,y) elif _isdmatrix(x) and (type(y) is variable or (type(y) is _function and y._isaffine()) and x.size == (len(y),1)): return x.trans() * y elif _isdmatrix(y) and (type(x) is variable or (type(x) is _function and x._isaffine()) and y.size == (len(x),1)): return y.trans() * x else: raise TypeError('invalid argument types or incompatible '\ 'dimensions') def _isscalar(a): """ True if a is an int or float or 1x1 dense 'd' matrix. """ if type(a) is int or type(a) is float or (_isdmatrix(a) and a.size == (1,1)): return True else: return False def _isdmatrix(a): """ True if a is a nonempty dense 'd' matrix. """ if type(a) is matrix and a.typecode == 'd' and min(a.size) != 0: return True else: return False def _isspmatrix(a): """ True if a is a nonempty sparse 'd' matrix. """ if type(a) is spmatrix and a.typecode == 'd' and min(a.size) != 0: return True else: return False def _ismatrix(a): """ True if a is a nonempty 'd' matrix. """ if type(a) in (matrix, spmatrix) and a.typecode == 'd' and \ min(a.size) != 0: return True else: return False def _keytolist(key,n): """ Converts indices, index lists, index matrices, and slices of a length n sequence into lists of integers. key is the index passed to a call to __getitem__(). """ if type(key) is int: if -n <= key < 0: l = [key+n] elif 0 <= key < n: l = [key] else: raise IndexError('variable index out of range') elif (type(key) is list and not [k for k in key if type(k) is not int]) or (type(key) is matrix and key.typecode == 'i'): l = [k for k in key if -n <= k < n] if len(l) != len(key): raise IndexError('variable index out of range') for i in range(len(l)): if l[i] < 0: l[i] += n elif type(key) is slice: ind = key.indices(n) l = list(range(ind[0],ind[1],ind[2])) else: raise TypeError('invalid key') return l class varlist(list): """ Standard list with __contains__() redefined to use 'is' instead of '=='. """ def __contains__(self,item): for k in range(len(self)): if self[k] is item: return True return False def _vecmax(*s): """ _vecmax(s1,s2,...) returns the componentwise maximum of s1, s2,... _vecmax(s) returns the maximum component of s. The arguments can be None, scalars or 1-column dense 'd' vectors with lengths equal to 1 or equal to the maximum len(sk). Returns None if one of the arguments is None. """ if not s: raise TypeError("_vecmax expected at least 1 argument, got 0") val = None for c in s: if c is None: return None elif type(c) is int or type(c) is float: c = matrix(c, tc='d') elif not _isdmatrix(c) or c.size[1] != 1: raise TypeError("incompatible type or size") if val is None: if len(s) == 1: return matrix(max(c), tc='d') else: val = +c elif len(val) == 1 != len(c): val = matrix([max(val[0],x) for x in c], tc='d') elif len(val) != 1 == len(c): val = matrix([max(c[0],x) for x in val], tc='d') elif len(val) == len(c): val = matrix( [max(val[k],c[k]) for k in range(len(c))], tc='d' ) else: raise ValueError('incompatible dimensions') return val def _vecmin(*s): """ _vecmin(s1,s2,...) returns the componentwise minimum of s1, s2,... _vecmin(s) returns the minimum component of s. The arguments can be None, scalars or 1-column dense 'd' vectors with lengths equal to 1 or equal to the maximum len(sk). Returns None if one of the arguments is None. """ if not s: raise TypeError("_vecmin expected at least 1 argument, got 0") val = None for c in s: if c is None: return None elif type(c) is int or type(c) is float: c = matrix(c, tc='d') elif not _isdmatrix(c) or c.size[1] != 1: raise TypeError("incompatible type or size") if val is None: if len(s) == 1: return matrix(min(c), tc='d') else: val = +c elif len(val) == 1 != len(c): val = matrix( [min(val[0],x) for x in c], tc='d' ) elif len(val) != 1 == len(c): val = matrix( [min(c[0],x) for x in val], tc='d' ) elif len(val) == len(c): val = matrix( [min(val[k],c[k]) for k in range(len(c))], tc='d' ) else: raise ValueError('incompatible dimensions') return val cvxopt-1.1.4/src/python/coneprog.py0000644000175000017500000051111311674452555016404 0ustar sonnesonne""" Solver for linear and quadratic cone programs. """ # Copyright 2010-2011 L. Vandenberghe. # Copyright 2004-2009 J. Dahl and L. Vandenberghe. # # This file is part of CVXOPT version 1.1.4. # # CVXOPT is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # CVXOPT is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . __all__ = [] options = {} def conelp(c, G, h, dims = None, A = None, b = None, primalstart = None, dualstart = None, kktsolver = None, xnewcopy = None, xdot = None, xaxpy = None, xscal = None, ynewcopy = None, ydot = None, yaxpy = None, yscal = None): """ Solves a pair of primal and dual cone programs minimize c'*x subject to G*x + s = h A*x = b s >= 0 maximize -h'*z - b'*y subject to G'*z + A'*y + c = 0 z >= 0. The inequalities are with respect to a cone C defined as the Cartesian product of N + M + 1 cones: C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}. The first cone C_0 is the nonnegative orthant of dimension ml. The next N cones are second order cones of dimension mq[0], ..., mq[N-1]. The second order cone of dimension m is defined as { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }. The next M cones are positive semidefinite cones of order ms[0], ..., ms[M-1] >= 0. Input arguments (basic usage). c is a dense 'd' matrix of size (n,1). dims is a dictionary with the dimensions of the components of C. It has three fields. - dims['l'] = ml, the dimension of the nonnegative orthant C_0. (ml >= 0.) - dims['q'] = mq = [ mq[0], mq[1], ..., mq[N-1] ], a list of N integers with the dimensions of the second order cones C_1, ..., C_N. (N >= 0 and mq[k] >= 1.) - dims['s'] = ms = [ ms[0], ms[1], ..., ms[M-1] ], a list of M integers with the orders of the semidefinite cones C_{N+1}, ..., C_{N+M}. (M >= 0 and ms[k] >= 0.) The default value of dims is {'l': G.size[0], 'q': [], 's': []}. G is a dense or sparse 'd' matrix of size (K,n), where K = ml + mq[0] + ... + mq[N-1] + ms[0]**2 + ... + ms[M-1]**2. Each column of G describes a vector v = ( v_0, v_1, ..., v_N, vec(v_{N+1}), ..., vec(v_{N+M}) ) in V = R^ml x R^mq[0] x ... x R^mq[N-1] x S^ms[0] x ... x S^ms[M-1] stored as a column vector [ v_0; v_1; ...; v_N; vec(v_{N+1}); ...; vec(v_{N+M}) ]. Here, if u is a symmetric matrix of order m, then vec(u) is the matrix u stored in column major order as a vector of length m**2. We use BLAS unpacked 'L' storage, i.e., the entries in vec(u) corresponding to the strictly upper triangular entries of u are not referenced. h is a dense 'd' matrix of size (K,1), representing a vector in V, in the same format as the columns of G. A is a dense or sparse 'd' matrix of size (p,n). The default value is a sparse 'd' matrix of size (0,n). b is a dense 'd' matrix of size (p,1). The default value is a dense 'd' matrix of size (0,1). The argument primalstart is a dictionary with keys 'x', 's'. It specifies an optional primal starting point. - primalstart['x'] is a dense 'd' matrix of size (n,1). - primalstart['s'] is a dense 'd' matrix of size (K,1), representing a vector that is strictly positive with respect to the cone C. The argument dualstart is a dictionary with keys 'y', 'z'. It specifies an optional dual starting point. - dualstart['y'] is a dense 'd' matrix of size (p,1). - dualstart['z'] is a dense 'd' matrix of size (K,1), representing a vector that is strictly positive with respect to the cone C. It is assumed that rank(A) = p and rank([A; G]) = n. The other arguments are normally not needed. They make it possible to exploit certain types of structure, as described below. Output arguments. Returns a dictionary with keys 'status', 'x', 's', 'z', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack', 'residual as primal infeasibility certificate', 'residual as dual infeasibility certificate', 'iterations'. The 'status' field has values 'optimal', 'primal infeasible', 'dual infeasible', or 'unknown'. The 'iterations' field is the number of iterations taken. The values of the other fields depend on the exit status. Status 'optimal'. - 'x', 's', 'y', 'z' are an approximate solution of the primal and dual optimality conditions G*x + s = h, A*x = b G'*z + A'*y + c = 0 s >= 0, z >= 0 s'*z = 0. - 'primal objective': the primal objective c'*x. - 'dual objective': the dual objective -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal objective is negative, s'*z / -(h'*z + b'*y) if the dual objective is positive, and None otherwise. - 'primal infeasibility': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack, sup {t | s >= t*e }, where e = ( e_0, e_1, ..., e_N, e_{N+1}, ..., e_{M+N} ) is the identity vector in C. e_0 is an ml-vector of ones, e_k, k = 1,..., N, are unit vectors (1,0,...,0) of length mq[k], and e_k = vec(I) where I is the identity matrix of order ms[k]. - 'dual slack': the smallest dual slack, sup {t | z >= t*e }. - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate': None. The primal infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The dual infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The gap is less than solvers.options['abstol'] (default 1e-7) or the relative gap is less than solvers.options['reltol'] (default 1e-6). Status 'primal infeasible'. - 'x', 's': None. - 'y', 'z' are an approximate certificate of infeasibility -h'*z - b'*y = 1, G'*z + A'*y = 0, z >= 0. - 'primal objective': None. - 'dual objective': 1.0. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': None. - 'dual slack': the smallest dual slack, sup {t | z >= t*e }. - 'residual as primal infeasibility certificate': the residual in the condition of the infeasibility certificate, defined as || G'*z + A'*y || / max(1, ||c||). - 'residual as dual infeasibility certificate': None. The residual as primal infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). Status 'dual infeasible'. - 'x', 's' are an approximate proof of dual infeasibility c'*x = -1, G*x + s = 0, A*x = 0, s >= 0. - 'y', 'z': None. - 'primal objective': -1.0. - 'dual objective': None. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': the smallest primal slack, sup {t | s >= t*e}. - 'dual slack': None. - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate: the residual in the conditions of the infeasibility certificate, defined as the maximum of || G*x + s || / max(1, ||h||) and || A*x || / max(1, ||b||). The residual as dual infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). Status 'unknown'. - 'x', 'y', 's', 'z' are the last iterates before termination. These satisfy s > 0 and z > 0, but are not necessarily feasible. - 'primal objective': the primal cost c'*x. - 'dual objective': the dual cost -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal cost is negative, s'*z / -(h'*z + b'*y) if the dual cost is positive, and None otherwise. - 'primal infeasibility ': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack, sup {t | s >= t*e}. - 'dual slack': the smallest dual slack, sup {t | z >= t*e}. - 'residual as primal infeasibility certificate': None if h'*z + b'*y >= 0; the residual || G'*z + A'*y || / ( -(h'*z + b'*y) * max(1, ||c||) ) otherwise. - 'residual as dual infeasibility certificate': None if c'*x >= 0; the maximum of the residuals || G*x + s || / ( -c'*x * max(1, ||h||) ) and || A*x || / ( -c'*x * max(1, ||b||) ) otherwise. Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, s, z are close to optimal. If the residual as primal infeasibility certificate is small, then y / (-h'*z - b'*y), z / (-h'*z - b'*y) provide an approximate certificate of primal infeasibility. If the residual as certificate of dual infeasibility is small, then x / (-c'*x), s / (-c'*x) provide an approximate proof of dual infeasibility. Advanced usage. Three mechanisms are provided to express problem structure. 1. The user can provide a customized routine for solving linear equations (`KKT systems') [ 0 A' G' ] [ ux ] [ bx ] [ A 0 0 ] [ uy ] = [ by ]. [ G 0 -W'*W ] [ uz ] [ bz ] W is a scaling matrix, a block diagonal mapping W*z = ( W0*z_0, ..., W_{N+M}*z_{N+M} ) defined as follows. - For the 'l' block (W_0): W_0 = diag(d), with d a positive vector of length ml. - For the 'q' blocks (W_{k+1}, k = 0, ..., N-1): W_{k+1} = beta_k * ( 2 * v_k * v_k' - J ) where beta_k is a positive scalar, v_k is a vector in R^mq[k] with v_k[0] > 0 and v_k'*J*v_k = 1, and J = [1, 0; 0, -I]. - For the 's' blocks (W_{k+N}, k = 0, ..., M-1): W_k * x = vec(r_k' * mat(x) * r_k) where r_k is a nonsingular matrix of order ms[k], and mat(x) is the inverse of the vec operation. The optional argument kktsolver is a Python function that will be called as f = kktsolver(W), where W is a dictionary that contains the parameters of the scaling: - W['d'] is a positive 'd' matrix of size (ml,1). - W['di'] is a positive 'd' matrix with the elementwise inverse of W['d']. - W['beta'] is a list [ beta_0, ..., beta_{N-1} ] - W['v'] is a list [ v_0, ..., v_{N-1} ] - W['r'] is a list [ r_0, ..., r_{M-1} ] - W['rti'] is a list [ rti_0, ..., rti_{M-1} ], with rti_k the inverse of the transpose of r_k. The call f = kktsolver(W) should return a function f that solves the KKT system by f(x, y, z). On entry, x, y, z contain the righthand side bx, by, bz. On exit, they contain the solution, with uz scaled: the argument z contains W*uz. In other words, on exit, x, y, z are the solution of [ 0 A' G'*W^{-1} ] [ ux ] [ bx ] [ A 0 0 ] [ uy ] = [ by ]. [ G 0 -W' ] [ uz ] [ bz ] 2. The linear operators G*u and A*u can be specified by providing Python functions instead of matrices. This can only be done in combination with 1. above, i.e., it requires the kktsolver argument. If G is a function, the call G(u, v, alpha, beta, trans) should evaluate the matrix-vector products v := alpha * G * u + beta * v if trans is 'N' v := alpha * G' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. If A is a function, the call A(u, v, alpha, beta, trans) should evaluate the matrix-vectors products v := alpha * A * u + beta * v if trans is 'N' v := alpha * A' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. 3. Instead of using the default representation of the primal variable x and the dual variable y as one-column 'd' matrices, we can represent these variables and the corresponding parameters c and b by arbitrary Python objects (matrices, lists, dictionaries, etc.). This can only be done in combination with 1. and 2. above, i.e., it requires a user-provided KKT solver and an operator description of the linear mappings. It also requires the arguments xnewcopy, xdot, xscal, xaxpy, ynewcopy, ydot, yscal, yaxpy. These arguments are functions defined as follows. If X is the vector space of primal variables x, then: - xnewcopy(u) creates a new copy of the vector u in X. - xdot(u, v) returns the inner product of two vectors u and v in X. - xscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in X. - xaxpy(u, v, alpha = 1.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in X. If this option is used, the argument c must be in the same format as x, the argument G must be a Python function, the argument A must be a Python function or None, and the argument kktsolver is required. If Y is the vector space of primal variables y: - ynewcopy(u) creates a new copy of the vector u in Y. - ydot(u, v) returns the inner product of two vectors u and v in Y. - yscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in Y. - yaxpy(u, v, alpha = 1.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in Y. If this option is used, the argument b must be in the same format as y, the argument A must be a Python function or None, and the argument kktsolver is required. Control parameters. The following control parameters can be modified by adding an entry to the dictionary options. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] positive integer (default: 0 for problems with no second-order cone and matrix inequality constraints; 1 otherwise) options['abstol'] scalar (default: 1e-7 ) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). """ import math from cvxopt import base, blas, misc, matrix, spmatrix EXPON = 3 STEP = 0.99 try: DEBUG = options['debug'] except KeyError: DEBUG = False try: MAXITERS = options['maxiters'] except KeyError: MAXITERS = 100 else: if type(MAXITERS) is not int or MAXITERS < 1: raise ValueError("options['maxiters'] must be a positive "\ "integer") try: ABSTOL = options['abstol'] except KeyError: ABSTOL = 1e-7 else: if type(ABSTOL) is not float and type(ABSTOL) is not int: raise ValueError("options['abstol'] must be a scalar") try: RELTOL = options['reltol'] except KeyError: RELTOL = 1e-6 else: if type(RELTOL) is not float and type(RELTOL) is not int: raise ValueError("options['reltol'] must be a scalar") if RELTOL <= 0.0 and ABSTOL <= 0.0 : raise ValueError("at least one of options['reltol'] and " \ "options['abstol'] must be positive") try: FEASTOL = options['feastol'] except KeyError: FEASTOL = 1e-7 else: if (type(FEASTOL) is not float and type(FEASTOL) is not int) or \ FEASTOL <= 0.0: raise ValueError("options['feastol'] must be a positive "\ "scalar") try: show_progress = options['show_progress'] except KeyError: show_progress = True if kktsolver is None: if dims and (dims['q'] or dims['s']): kktsolver = 'qr' else: kktsolver = 'chol2' defaultsolvers = ('ldl', 'ldl2', 'qr', 'chol', 'chol2') if type(kktsolver) is str and kktsolver not in defaultsolvers: raise ValueError("'%s' is not a valid value for kktsolver" \ %kktsolver) # Argument error checking depends on level of customization. customkkt = type(kktsolver) is not str matrixG = type(G) in (matrix, spmatrix) matrixA = type(A) in (matrix, spmatrix) if (not matrixG or (not matrixA and A is not None)) and not customkkt: raise ValueError("use of function valued G, A requires a "\ "user-provided kktsolver") customx = (xnewcopy != None or xdot != None or xaxpy != None or xscal != None) if customx and (matrixG or matrixA or not customkkt): raise ValueError("use of non-vector type for x requires "\ "function valued G, A and user-provided kktsolver") customy = (ynewcopy != None or ydot != None or yaxpy != None or yscal != None) if customy and (matrixA or not customkkt): raise ValueError("use of non-vector type for y requires "\ "function valued A and user-provided kktsolver") if not customx and (type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1): raise TypeError("'c' must be a 'd' matrix with one column") if type(h) is not matrix or h.typecode != 'd' or h.size[1] != 1: raise TypeError("'h' must be a 'd' matrix with 1 column") if not dims: dims = {'l': h.size[0], 'q': [], 's': []} if type(dims['l']) is not int or dims['l'] < 0: raise TypeError("'dims['l']' must be a nonnegative integer") if [ k for k in dims['q'] if type(k) is not int or k < 1 ]: raise TypeError("'dims['q']' must be a list of positive integers") if [ k for k in dims['s'] if type(k) is not int or k < 0 ]: raise TypeError("'dims['s']' must be a list of nonnegative " \ "integers") try: refinement = options['refinement'] except KeyError: if dims['q'] or dims['s']: refinement = 1 else: refinement = 0 else: if type(refinement) is not int or refinement < 0: raise ValueError("options['refinement'] must be a "\ "nonnegative integer") cdim = dims['l'] + sum(dims['q']) + sum([k**2 for k in dims['s']]) cdim_pckd = dims['l'] + sum(dims['q']) + sum([k*(k+1)/2 for k in dims['s']]) cdim_diag = dims['l'] + sum(dims['q']) + sum(dims['s']) if h.size[0] != cdim: raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %cdim) # Data for kth 'q' constraint are found in rows indq[k]:indq[k+1] of G. indq = [ dims['l'] ] for k in dims['q']: indq = indq + [ indq[-1] + k ] # Data for kth 's' constraint are found in rows inds[k]:inds[k+1] of G. inds = [ indq[-1] ] for k in dims['s']: inds = inds + [ inds[-1] + k**2 ] if matrixG: if G.typecode != 'd' or G.size != (cdim, c.size[0]): raise TypeError("'G' must be a 'd' matrix of size (%d, %d)"\ %(cdim, c.size[0])) def Gf(x, y, trans = 'N', alpha = 1.0, beta = 0.0): misc.sgemv(G, x, y, dims, trans = trans, alpha = alpha, beta = beta) else: Gf = G if A is None: if customx or customy: def A(x, y, trans = 'N', alpha = 1.0, beta = 0.0): if trans == 'N': pass else: xscal(beta, y) else: A = spmatrix([], [], [], (0, c.size[0])) matrixA = True if matrixA: if A.typecode != 'd' or A.size[1] != c.size[0]: raise TypeError("'A' must be a 'd' matrix with %d columns "\ %c.size[0]) def Af(x, y, trans = 'N', alpha = 1.0, beta = 0.0): base.gemv(A, x, y, trans = trans, alpha = alpha, beta = beta) else: Af = A if not customy: if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size[1] != 1: raise TypeError("'b' must be a 'd' matrix with one column") if matrixA and b.size[0] != A.size[0]: raise TypeError("'b' must have length %d" %A.size[0]) else: if b is None: raise ValueError("use of non vector type for y requires b") # kktsolver(W) returns a routine for solving 3x3 block KKT system # # [ 0 A' G'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ]. # [ G 0 -W' ] [ uz ] [ bz ] if kktsolver in defaultsolvers: if b.size[0] > c.size[0] or b.size[0] + cdim_pckd < c.size[0]: raise ValueError("Rank(A) < p or Rank([G; A]) < n") if kktsolver == 'ldl': factor = misc.kkt_ldl(G, dims, A) elif kktsolver == 'ldl2': factor = misc.kkt_ldl2(G, dims, A) elif kktsolver == 'qr': factor = misc.kkt_qr(G, dims, A) elif kktsolver == 'chol': factor = misc.kkt_chol(G, dims, A) else: factor = misc.kkt_chol2(G, dims, A) def kktsolver(W): return factor(W) # res() evaluates residual in 5x5 block KKT system # # [ vx ] [ 0 ] [ 0 A' G' c ] [ ux ] # [ vy ] [ 0 ] [-A 0 0 b ] [ uy ] # [ vz ] += [ W'*us ] - [-G 0 0 h ] [ W^{-1}*uz ] # [ vtau ] [ dg*ukappa ] [-c' -b' -h' 0 ] [ utau/dg ] # # vs += lmbda o (dz + ds) # vkappa += lmbdg * (dtau + dkappa). ws3, wz3 = matrix(0.0, (cdim,1)), matrix(0.0, (cdim,1)) def res(ux, uy, uz, utau, us, ukappa, vx, vy, vz, vtau, vs, vkappa, W, dg, lmbda): # vx := vx - A'*uy - G'*W^{-1}*uz - c*utau/dg Af(uy, vx, alpha = -1.0, beta = 1.0, trans = 'T') blas.copy(uz, wz3) misc.scale(wz3, W, inverse = 'I') Gf(wz3, vx, alpha = -1.0, beta = 1.0, trans = 'T') xaxpy(c, vx, alpha = -utau[0]/dg) # vy := vy + A*ux - b*utau/dg Af(ux, vy, alpha = 1.0, beta = 1.0) yaxpy(b, vy, alpha = -utau[0]/dg) # vz := vz + G*ux - h*utau/dg + W'*us Gf(ux, vz, alpha = 1.0, beta = 1.0) blas.axpy(h, vz, alpha = -utau[0]/dg) blas.copy(us, ws3) misc.scale(ws3, W, trans = 'T') blas.axpy(ws3, vz) # vtau := vtau + c'*ux + b'*uy + h'*W^{-1}*uz + dg*ukappa vtau[0] += dg*ukappa[0] + xdot(c,ux) + ydot(b,uy) + \ misc.sdot(h, wz3, dims) # vs := vs + lmbda o (uz + us) blas.copy(us, ws3) blas.axpy(uz, ws3) misc.sprod(ws3, lmbda, dims, diag = 'D') blas.axpy(ws3, vs) # vkappa += vkappa + lmbdag * (utau + ukappa) vkappa[0] += lmbda[-1] * (utau[0] + ukappa[0]) if xnewcopy is None: xnewcopy = matrix if xdot is None: xdot = blas.dot if xaxpy is None: xaxpy = blas.axpy if xscal is None: xscal = blas.scal def xcopy(x, y): xscal(0.0, y) xaxpy(x, y) if ynewcopy is None: ynewcopy = matrix if ydot is None: ydot = blas.dot if yaxpy is None: yaxpy = blas.axpy if yscal is None: yscal = blas.scal def ycopy(x, y): yscal(0.0, y) yaxpy(x, y) resx0 = max(1.0, math.sqrt(xdot(c,c))) resy0 = max(1.0, math.sqrt(ydot(b,b))) resz0 = max(1.0, misc.snrm2(h, dims)) # Select initial points. x = xnewcopy(c); xscal(0.0, x) y = ynewcopy(b); yscal(0.0, y) s, z = matrix(0.0, (cdim,1)), matrix(0.0, (cdim,1)) dx, dy = xnewcopy(c), ynewcopy(b) ds, dz = matrix(0.0, (cdim,1)), matrix(0.0, (cdim,1)) dkappa, dtau = matrix(0.0, (1,1)), matrix(0.0, (1,1)) if primalstart is None or dualstart is None: # Factor # # [ 0 A' G' ] # [ A 0 0 ]. # [ G 0 -I ] W = {} W['d'] = matrix(1.0, (dims['l'], 1)) W['di'] = matrix(1.0, (dims['l'], 1)) W['v'] = [ matrix(0.0, (m,1)) for m in dims['q'] ] W['beta'] = len(dims['q']) * [ 1.0 ] for v in W['v']: v[0] = 1.0 W['r'] = [ matrix(0.0, (m,m)) for m in dims['s'] ] W['rti'] = [ matrix(0.0, (m,m)) for m in dims['s'] ] for r in W['r']: r[::r.size[0]+1 ] = 1.0 for rti in W['rti']: rti[::rti.size[0]+1 ] = 1.0 try: f = kktsolver(W) except ArithmeticError: raise ValueError("Rank(A) < p or Rank([G; A]) < n") if primalstart is None: # minimize || G * x - h ||^2 # subject to A * x = b # # by solving # # [ 0 A' G' ] [ x ] [ 0 ] # [ A 0 0 ] * [ dy ] = [ b ]. # [ G 0 -I ] [ -s ] [ h ] xscal(0.0, x) ycopy(b, dy) blas.copy(h, s) try: f(x, dy, s) except ArithmeticError: raise ValueError("Rank(A) < p or Rank([G; A]) < n") blas.scal(-1.0, s) else: xcopy(primalstart['x'], x) blas.copy(primalstart['s'], s) # ts = min{ t | s + t*e >= 0 } ts = misc.max_step(s, dims) if ts >= 0 and primalstart: raise ValueError("initial s is not positive") if dualstart is None: # minimize || z ||^2 # subject to G'*z + A'*y + c = 0 # # by solving # # [ 0 A' G' ] [ dx ] [ -c ] # [ A 0 0 ] [ y ] = [ 0 ]. # [ G 0 -I ] [ z ] [ 0 ] xcopy(c, dx); xscal(-1.0, dx) yscal(0.0, y) blas.scal(0.0, z) try: f(dx, y, z) except ArithmeticError: raise ValueError("Rank(A) < p or Rank([G; A]) < n") else: if 'y' in dualstart: ycopy(dualstart['y'], y) blas.copy(dualstart['z'], z) # tz = min{ t | z + t*e >= 0 } tz = misc.max_step(z, dims) if tz >= 0 and dualstart: raise ValueError("initial z is not positive") nrms = misc.snrm2(s, dims) nrmz = misc.snrm2(z, dims) if primalstart is None and dualstart is None: gap = misc.sdot(s, z, dims) pcost = xdot(c,x) dcost = -ydot(b,y) - misc.sdot(h, z, dims) if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None if ts <= 0 and tz <= 0 and (gap <= ABSTOL or ( relgap is not None and relgap <= RELTOL )): # The initial points we constructed happen to be feasible and # optimal. ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(s, m, ind) misc.symm(z, m, ind) ind += m**2 # rx = A'*y + G'*z + c rx = xnewcopy(c) Af(y, rx, beta = 1.0, trans = 'T') Gf(z, rx, beta = 1.0, trans = 'T') resx = math.sqrt( xdot(rx, rx) ) # ry = b - A*x ry = ynewcopy(b) Af(x, ry, alpha = -1.0, beta = 1.0) resy = math.sqrt( ydot(ry, ry) ) # rz = s + G*x - h rz = matrix(0.0, (cdim,1)) Gf(x, rz) blas.axpy(s, rz) blas.axpy(h, rz, alpha = -1.0) resz = misc.snrm2(rz, dims) pres = max(resy/resy0, resz/resz0) dres = resx/resx0 cx, by, hz = xdot(c,x), ydot(b,y), misc.sdot(h, z, dims) if show_progress: print("Optimal solution found.") return { 'x': x, 'y': y, 's': s, 'z': z, 'status': 'optimal', 'gap': gap, 'relative gap': relgap, 'primal objective': cx, 'dual objective': -(by + hz), 'primal infeasibility': pres, 'primal slack': -ts, 'dual slack': -tz, 'dual infeasibility': dres, 'residual as primal infeasibility certificate': None, 'residual as dual infeasibility certificate': None, 'iterations': 0 } if ts >= -1e-8 * max(nrms, 1.0): a = 1.0 + ts s[:dims['l']] += a s[indq[:-1]] += a ind = dims['l'] + sum(dims['q']) for m in dims['s']: s[ind : ind+m*m : m+1] += a ind += m**2 if tz >= -1e-8 * max(nrmz, 1.0): a = 1.0 + tz z[:dims['l']] += a z[indq[:-1]] += a ind = dims['l'] + sum(dims['q']) for m in dims['s']: z[ind : ind+m*m : m+1] += a ind += m**2 elif primalstart is None and dualstart is not None: if ts >= -1e-8 * max(nrms, 1.0): a = 1.0 + ts s[:dims['l']] += a s[indq[:-1]] += a ind = dims['l'] + sum(dims['q']) for m in dims['s']: s[ind : ind+m*m : m+1] += a ind += m**2 elif primalstart is not None and dualstart is None: if tz >= -1e-8 * max(nrmz, 1.0): a = 1.0 + tz z[:dims['l']] += a z[indq[:-1]] += a ind = dims['l'] + sum(dims['q']) for m in dims['s']: z[ind : ind+m*m : m+1] += a ind += m**2 tau, kappa = 1.0, 1.0 rx, hrx = xnewcopy(c), xnewcopy(c) ry, hry = ynewcopy(b), ynewcopy(b) rz, hrz = matrix(0.0, (cdim,1)), matrix(0.0, (cdim,1)) sigs = matrix(0.0, (sum(dims['s']), 1)) sigz = matrix(0.0, (sum(dims['s']), 1)) lmbda = matrix(0.0, (cdim_diag + 1, 1)) lmbdasq = matrix(0.0, (cdim_diag + 1, 1)) gap = misc.sdot(s, z, dims) for iters in range(MAXITERS+1): # hrx = -A'*y - G'*z Af(y, hrx, alpha = -1.0, trans = 'T') Gf(z, hrx, alpha = -1.0, beta = 1.0, trans = 'T') hresx = math.sqrt( xdot(hrx, hrx) ) # rx = hrx - c*tau # = -A'*y - G'*z - c*tau xcopy(hrx, rx) xaxpy(c, rx, alpha = -tau) resx = math.sqrt( xdot(rx, rx) ) / tau # hry = A*x Af(x, hry) hresy = math.sqrt( ydot(hry, hry) ) # ry = hry - b*tau # = A*x - b*tau ycopy(hry, ry) yaxpy(b, ry, alpha = -tau) resy = math.sqrt( ydot(ry, ry) ) / tau # hrz = s + G*x Gf(x, hrz) blas.axpy(s, hrz) hresz = misc.snrm2(hrz, dims) # rz = hrz - h*tau # = s + G*x - h*tau blas.scal(0, rz) blas.axpy(hrz, rz) blas.axpy(h, rz, alpha = -tau) resz = misc.snrm2(rz, dims) / tau # rt = kappa + c'*x + b'*y + h'*z cx, by, hz = xdot(c,x), ydot(b,y), misc.sdot(h, z, dims) rt = kappa + cx + by + hz # Statistics for stopping criteria. pcost, dcost = cx / tau, -(by + hz) / tau if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None pres = max(resy/resy0, resz/resz0) dres = resx/resx0 if hz + by < 0.0: pinfres = hresx / resx0 / (-hz - by) else: pinfres = None if cx < 0.0: dinfres = max(hresy / resy0, hresz/resz0) / (-cx) else: dinfres = None if show_progress: if iters == 0: print("% 10s% 12s% 10s% 8s% 7s % 5s" %("pcost", "dcost", "gap", "pres", "dres", "k/t")) print("%2d: % 8.4e % 8.4e % 4.0e% 7.0e% 7.0e% 7.0e" \ %(iters, pcost, dcost, gap, pres, dres, kappa/tau)) if ( pres <= FEASTOL and dres <= FEASTOL and ( gap <= ABSTOL or (relgap is not None and relgap <= RELTOL) ) ) or \ iters == MAXITERS: xscal(1.0/tau, x) yscal(1.0/tau, y) blas.scal(1.0/tau, s) blas.scal(1.0/tau, z) ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(s, m, ind) misc.symm(z, m, ind) ind += m**2 ts = misc.max_step(s, dims) tz = misc.max_step(z, dims) if iters == MAXITERS: if show_progress: print("Terminated (maximum number of iterations "\ "reached).") return { 'x': x, 'y': y, 's': s, 'z': z, 'status': 'unknown', 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective' : dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': dinfres, 'iterations': iters} else: if show_progress: print("Optimal solution found.") return { 'x': x, 'y': y, 's': s, 'z': z, 'status': 'optimal', 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective' : dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz, 'residual as primal infeasibility certificate': None, 'residual as dual infeasibility certificate': None, 'iterations': iters } elif pinfres is not None and pinfres <= FEASTOL: yscal(1.0/(-hz - by), y) blas.scal(1.0/(-hz - by), z) ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(z, m, ind) ind += m**2 tz = misc.max_step(z, dims) if show_progress: print("Certificate of primal infeasibility found.") return { 'x': None, 'y': y, 's': None, 'z': z, 'status': 'primal infeasible', 'gap': None, 'relative gap': None, 'primal objective': None, 'dual objective' : 1.0, 'primal infeasibility': None, 'dual infeasibility': None, 'primal slack': None, 'dual slack': -tz, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': None, 'iterations': iters } elif dinfres is not None and dinfres <= FEASTOL: xscal(1.0/(-cx), x) blas.scal(1.0/(-cx), s) ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(s, m, ind) ind += m**2 y, z = None, None ts = misc.max_step(s, dims) if show_progress: print("Certificate of dual infeasibility found.") return {'x': x, 'y': None, 's': s, 'z': None, 'status': 'dual infeasible', 'gap': None, 'relative gap': None, 'primal objective': -1.0, 'dual objective' : None, 'primal infeasibility': None, 'dual infeasibility': None, 'primal slack': -ts, 'dual slack': None, 'residual as primal infeasibility certificate': None, 'residual as dual infeasibility certificate': dinfres, 'iterations': iters } # Compute initial scaling W: # # W * z = W^{-T} * s = lambda # dg * tau = 1/dg * kappa = lambdag. if iters == 0: W = misc.compute_scaling(s, z, lmbda, dims, mnl = 0) # dg = sqrt( kappa / tau ) # dgi = sqrt( tau / kappa ) # lambda_g = sqrt( tau * kappa ) # # lambda_g is stored in the last position of lmbda. dg = math.sqrt( kappa / tau ) dgi = math.sqrt( tau / kappa ) lmbda[-1] = math.sqrt( tau * kappa ) # lmbdasq := lmbda o lmbda misc.ssqr(lmbdasq, lmbda, dims) lmbdasq[-1] = lmbda[-1]**2 # f3(x, y, z) solves # # [ 0 A' G' ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ]. # [ G 0 -W'*W ] [ W^{-1}*uz ] [ bz ] # # On entry, x, y, z contain bx, by, bz. # On exit, they contain ux, uy, uz. # # Also solve # # [ 0 A' G' ] [ x1 ] [ c ] # [-A 0 0 ]*[ y1 ] = -dgi * [ b ]. # [-G 0 W'*W ] [ W^{-1}*z1 ] [ h ] try: f3 = kktsolver(W) if iters == 0: x1, y1 = xnewcopy(c), ynewcopy(b) z1 = matrix(0.0, (cdim,1)) xcopy(c, x1); xscal(-1, x1) ycopy(b, y1) blas.copy(h, z1) f3(x1, y1, z1) xscal(dgi, x1) yscal(dgi, y1) blas.scal(dgi, z1) except ArithmeticError: if iters == 0 and primalstart and dualstart: raise ValueError("Rank(A) < p or Rank([G; A]) < n") else: xscal(1.0/tau, x) yscal(1.0/tau, y) blas.scal(1.0/tau, s) blas.scal(1.0/tau, z) ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(s, m, ind) misc.symm(z, m, ind) ind += m**2 ts = misc.max_step(s, dims) tz = misc.max_step(z, dims) if show_progress: print("Terminated (singular KKT matrix).") return { 'x': x, 'y': y, 's': s, 'z': z, 'status': 'unknown', 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective' : dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': dinfres, 'iterations': iters } # f6_no_ir(x, y, z, tau, s, kappa) solves # # [ 0 ] [ 0 A' G' c ] [ ux ] [ bx ] # [ 0 ] [ -A 0 0 b ] [ uy ] [ by ] # [ W'*us ] - [ -G 0 0 h ] [ W^{-1}*uz ] = -[ bz ] # [ dg*ukappa ] [ -c' -b' -h' 0 ] [ utau/dg ] [ btau ] # # lmbda o (uz + us) = -bs # lmbdag * (utau + ukappa) = -bkappa. # # On entry, x, y, z, tau, s, kappa contain bx, by, bz, btau, # bkappa. On exit, they contain ux, uy, uz, utau, ukappa. # th = W^{-T} * h if iters == 0: th = matrix(0.0, (cdim,1)) blas.copy(h, th) misc.scale(th, W, trans = 'T', inverse = 'I') def f6_no_ir(x, y, z, tau, s, kappa): # Solve # # [ 0 A' G' 0 ] [ ux ] # [ -A 0 0 b ] [ uy ] # [ -G 0 W'*W h ] [ W^{-1}*uz ] # [ -c' -b' -h' k/t ] [ utau/dg ] # # [ bx ] # [ by ] # = [ bz - W'*(lmbda o\ bs) ] # [ btau - bkappa/tau ] # # us = -lmbda o\ bs - uz # ukappa = -bkappa/lmbdag - utau. # First solve # # [ 0 A' G' ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ -by ] # [ G 0 -W'*W ] [ W^{-1}*uz ] [ -bz + W'*(lmbda o\ bs) ] # y := -y = -by yscal(-1.0, y) # s := -lmbda o\ s = -lmbda o\ bs misc.sinv(s, lmbda, dims) blas.scal(-1.0, s) # z := -(z + W'*s) = -bz + W'*(lambda o\ bs) blas.copy(s, ws3) misc.scale(ws3, W, trans = 'T') blas.axpy(ws3, z) blas.scal(-1.0, z) # Solve system. f3(x, y, z) # Combine with solution of # # [ 0 A' G' ] [ x1 ] [ c ] # [-A 0 0 ] [ y1 ] = -dgi * [ b ] # [-G 0 W'*W ] [ W^{-1}*dzl ] [ h ] # # to satisfy # # -c'*x - b'*y - h'*W^{-1}*z + dg*tau = btau - bkappa/tau. # kappa[0] := -kappa[0] / lmbd[-1] = -bkappa / lmbdag kappa[0] = -kappa[0] / lmbda[-1] # tau[0] = tau[0] + kappa[0] / dgi = btau[0] - bkappa / tau tau[0] += kappa[0] / dgi tau[0] = dgi * ( tau[0] + xdot(c,x) + ydot(b,y) + misc.sdot(th, z, dims) ) / (1.0 + misc.sdot(z1, z1, dims)) xaxpy(x1, x, alpha = tau[0]) yaxpy(y1, y, alpha = tau[0]) blas.axpy(z1, z, alpha = tau[0]) # s := s - z = - lambda o\ bs - z blas.axpy(z, s, alpha = -1) kappa[0] -= tau[0] # f6(x, y, z, tau, s, kappa) solves the same system as f6_no_ir, # but applies iterative refinement. if iters == 0: if refinement or DEBUG: wx, wy = xnewcopy(c), ynewcopy(b) wz, ws = matrix(0.0, (cdim, 1)), matrix(0.0, (cdim, 1)) wtau, wkappa = matrix(0.0), matrix(0.0) if refinement: wx2, wy2 = xnewcopy(c), ynewcopy(b) wz2, ws2 = matrix(0.0, (cdim, 1)), matrix(0.0, (cdim, 1)) wtau2, wkappa2 = matrix(0.0), matrix(0.0) def f6(x, y, z, tau, s, kappa): if refinement or DEBUG: xcopy(x, wx) ycopy(y, wy) blas.copy(z, wz) wtau[0] = tau[0] blas.copy(s, ws) wkappa[0] = kappa[0] f6_no_ir(x, y, z, tau, s, kappa) for i in range(refinement): xcopy(wx, wx2) ycopy(wy, wy2) blas.copy(wz, wz2) wtau2[0] = wtau[0] blas.copy(ws, ws2) wkappa2[0] = wkappa[0] res(x, y, z, tau, s, kappa, wx2, wy2, wz2, wtau2, ws2, wkappa2, W, dg, lmbda) f6_no_ir(wx2, wy2, wz2, wtau2, ws2, wkappa2) xaxpy(wx2, x) yaxpy(wy2, y) blas.axpy(wz2, z) tau[0] += wtau2[0] blas.axpy(ws2, s) kappa[0] += wkappa2[0] if DEBUG: res(x, y, z, tau, s, kappa, wx, wy, wz, wtau, ws, wkappa, W, dg, lmbda) print("KKT residuals") print(" 'x': %e" %math.sqrt(xdot(wx, wx))) print(" 'y': %e" %math.sqrt(ydot(wy, wy))) print(" 'z': %e" %misc.snrm2(wz, dims)) print(" 'tau': %e" %abs(wtau[0])) print(" 's': %e" %misc.snrm2(ws, dims)) print(" 'kappa': %e" %abs(wkappa[0])) mu = blas.nrm2(lmbda)**2 / (1 + cdim_diag) sigma = 0.0 for i in [0,1]: # Solve # # [ 0 ] [ 0 A' G' c ] [ dx ] # [ 0 ] [ -A 0 0 b ] [ dy ] # [ W'*ds ] - [ -G 0 0 h ] [ W^{-1}*dz ] # [ dg*dkappa ] [ -c' -b' -h' 0 ] [ dtau/dg ] # # [ rx ] # [ ry ] # = - (1-sigma) [ rz ] # [ rtau ] # # lmbda o (dz + ds) = -lmbda o lmbda + sigma*mu*e # lmbdag * (dtau + dkappa) = - kappa * tau + sigma*mu # ds = -lmbdasq if i is 0 # = -lmbdasq - dsa o dza + sigma*mu*e if i is 1 # dkappa = -lambdasq[-1] if i is 0 # = -lambdasq[-1] - dkappaa*dtaua + sigma*mu if i is 1. blas.copy(lmbdasq, ds, n = dims['l'] + sum(dims['q'])) ind = dims['l'] + sum(dims['q']) ind2 = ind blas.scal(0.0, ds, offset = ind) for m in dims['s']: blas.copy(lmbdasq, ds, n = m, offsetx = ind2, offsety = ind, incy = m+1) ind += m*m ind2 += m dkappa[0] = lmbdasq[-1] if i == 1: blas.axpy(ws3, ds) ds[:dims['l']] -= sigma*mu ds[indq[:-1]] -= sigma*mu ind = dims['l'] + sum(dims['q']) ind2 = ind for m in dims['s']: ds[ind : ind+m*m : m+1] -= sigma*mu ind += m*m dkappa[0] += wkappa3 - sigma*mu # (dx, dy, dz, dtau) = (1-sigma)*(rx, ry, rz, rt) xcopy(rx, dx); xscal(1.0 - sigma, dx) ycopy(ry, dy); yscal(1.0 - sigma, dy) blas.copy(rz, dz); blas.scal(1.0 - sigma, dz) dtau[0] = (1.0 - sigma) * rt f6(dx, dy, dz, dtau, ds, dkappa) # Save ds o dz and dkappa * dtau for Mehrotra correction if i == 0: blas.copy(ds, ws3) misc.sprod(ws3, dz, dims) wkappa3 = dtau[0] * dkappa[0] # Maximum step to boundary. # # If i is 1, also compute eigenvalue decomposition of the 's' # blocks in ds, dz. The eigenvectors Qs, Qz are stored in # dsk, dzk. The eigenvalues are stored in sigs, sigz. misc.scale2(lmbda, ds, dims) misc.scale2(lmbda, dz, dims) if i == 0: ts = misc.max_step(ds, dims) tz = misc.max_step(dz, dims) else: ts = misc.max_step(ds, dims, sigma = sigs) tz = misc.max_step(dz, dims, sigma = sigz) tt = -dtau[0] / lmbda[-1] tk = -dkappa[0] / lmbda[-1] t = max([ 0.0, ts, tz, tt, tk ]) if t == 0.0: step = 1.0 else: if i == 0: step = min(1.0, 1.0 / t) else: step = min(1.0, STEP / t) if i == 0: sigma = (1.0 - step)**EXPON # Update x, y. xaxpy(dx, x, alpha = step) yaxpy(dy, y, alpha = step) # Replace 'l' and 'q' blocks of ds and dz with the updated # variables in the current scaling. # Replace 's' blocks of ds and dz with the factors Ls, Lz in a # factorization Ls*Ls', Lz*Lz' of the updated variables in the # current scaling. # ds := e + step*ds for 'l' and 'q' blocks. # dz := e + step*dz for 'l' and 'q' blocks. blas.scal(step, ds, n = dims['l'] + sum(dims['q'])) blas.scal(step, dz, n = dims['l'] + sum(dims['q'])) ds[:dims['l']] += 1.0 dz[:dims['l']] += 1.0 ds[indq[:-1]] += 1.0 dz[indq[:-1]] += 1.0 # ds := H(lambda)^{-1/2} * ds and dz := H(lambda)^{-1/2} * dz. # # This replaces the 'l' and 'q' components of ds and dz with the # updated variables in the current scaling. # The 's' components of ds and dz are replaced with # # diag(lmbda_k)^{1/2} * Qs * diag(lmbda_k)^{1/2} # diag(lmbda_k)^{1/2} * Qz * diag(lmbda_k)^{1/2} # misc.scale2(lmbda, ds, dims, inverse = 'I') misc.scale2(lmbda, dz, dims, inverse = 'I') # sigs := ( e + step*sigs ) ./ lambda for 's' blocks. # sigz := ( e + step*sigz ) ./ lambda for 's' blocks. blas.scal(step, sigs) blas.scal(step, sigz) sigs += 1.0 sigz += 1.0 blas.tbsv(lmbda, sigs, n = sum(dims['s']), k = 0, ldA = 1, offsetA = dims['l'] + sum(dims['q'])) blas.tbsv(lmbda, sigz, n = sum(dims['s']), k = 0, ldA = 1, offsetA = dims['l'] + sum(dims['q'])) # dsk := Ls = dsk * sqrt(sigs). # dzk := Lz = dzk * sqrt(sigz). ind2, ind3 = dims['l'] + sum(dims['q']), 0 for k in range(len(dims['s'])): m = dims['s'][k] for i in range(m): blas.scal(math.sqrt(sigs[ind3+i]), ds, offset = ind2 + m*i, n = m) blas.scal(math.sqrt(sigz[ind3+i]), dz, offset = ind2 + m*i, n = m) ind2 += m*m ind3 += m # Update lambda and scaling. misc.update_scaling(W, lmbda, ds, dz) # For kappa, tau block: # # dg := sqrt( (kappa + step*dkappa) / (tau + step*dtau) ) # = dg * sqrt( (1 - step*tk) / (1 - step*tt) ) # # lmbda[-1] := sqrt((tau + step*dtau) * (kappa + step*dkappa)) # = lmbda[-1] * sqrt(( 1 - step*tt) * (1 - step*tk)) dg *= math.sqrt(1.0 - step*tk) / math.sqrt(1.0 - step*tt) dgi = 1.0 / dg lmbda[-1] *= math.sqrt(1.0 - step*tt) * math.sqrt(1.0 - step*tk) # Unscale s, z, tau, kappa (unscaled variables are used only to # compute feasibility residuals). blas.copy(lmbda, s, n = dims['l'] + sum(dims['q'])) ind = dims['l'] + sum(dims['q']) ind2 = ind for m in dims['s']: blas.scal(0.0, s, offset = ind2) blas.copy(lmbda, s, offsetx = ind, offsety = ind2, n = m, incy = m+1) ind += m ind2 += m*m misc.scale(s, W, trans = 'T') blas.copy(lmbda, z, n = dims['l'] + sum(dims['q'])) ind = dims['l'] + sum(dims['q']) ind2 = ind for m in dims['s']: blas.scal(0.0, z, offset = ind2) blas.copy(lmbda, z, offsetx = ind, offsety = ind2, n = m, incy = m+1) ind += m ind2 += m*m misc.scale(z, W, inverse = 'I') kappa, tau = lmbda[-1]/dgi, lmbda[-1]*dgi gap = ( blas.nrm2(lmbda, n = lmbda.size[0]-1) / tau )**2 def coneqp(P, q, G = None, h = None, dims = None, A = None, b = None, initvals = None, kktsolver = None, xnewcopy = None, xdot = None, xaxpy = None, xscal = None, ynewcopy = None, ydot = None, yaxpy = None, yscal = None): """ Solves a pair of primal and dual convex quadratic cone programs minimize (1/2)*x'*P*x + q'*x subject to G*x + s = h A*x = b s >= 0 maximize -(1/2)*(q + G'*z + A'*y)' * pinv(P) * (q + G'*z + A'*y) - h'*z - b'*y subject to q + G'*z + A'*y in range(P) z >= 0. The inequalities are with respect to a cone C defined as the Cartesian product of N + M + 1 cones: C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}. The first cone C_0 is the nonnegative orthant of dimension ml. The next N cones are 2nd order cones of dimension mq[0], ..., mq[N-1]. The second order cone of dimension m is defined as { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }. The next M cones are positive semidefinite cones of order ms[0], ..., ms[M-1] >= 0. Input arguments (basic usage). P is a dense or sparse 'd' matrix of size (n,n) with the lower triangular part of the Hessian of the objective stored in the lower triangle. Must be positive semidefinite. q is a dense 'd' matrix of size (n,1). dims is a dictionary with the dimensions of the components of C. It has three fields. - dims['l'] = ml, the dimension of the nonnegative orthant C_0. (ml >= 0.) - dims['q'] = mq = [ mq[0], mq[1], ..., mq[N-1] ], a list of N integers with the dimensions of the second order cones C_1, ..., C_N. (N >= 0 and mq[k] >= 1.) - dims['s'] = ms = [ ms[0], ms[1], ..., ms[M-1] ], a list of M integers with the orders of the semidefinite cones C_{N+1}, ..., C_{N+M}. (M >= 0 and ms[k] >= 0.) The default value of dims = {'l': G.size[0], 'q': [], 's': []}. G is a dense or sparse 'd' matrix of size (K,n), where K = ml + mq[0] + ... + mq[N-1] + ms[0]**2 + ... + ms[M-1]**2. Each column of G describes a vector v = ( v_0, v_1, ..., v_N, vec(v_{N+1}), ..., vec(v_{N+M}) ) in V = R^ml x R^mq[0] x ... x R^mq[N-1] x S^ms[0] x ... x S^ms[M-1] stored as a column vector [ v_0; v_1; ...; v_N; vec(v_{N+1}); ...; vec(v_{N+M}) ]. Here, if u is a symmetric matrix of order m, then vec(u) is the matrix u stored in column major order as a vector of length m**2. We use BLAS unpacked 'L' storage, i.e., the entries in vec(u) corresponding to the strictly upper triangular entries of u are not referenced. h is a dense 'd' matrix of size (K,1), representing a vector in V, in the same format as the columns of G. A is a dense or sparse 'd' matrix of size (p,n). The default value is a sparse 'd' matrix of size (0,n). b is a dense 'd' matrix of size (p,1). The default value is a dense 'd' matrix of size (0,1). initvals is a dictionary with optional primal and dual starting points initvals['x'], initvals['s'], initvals['y'], initvals['z']. - initvals['x'] is a dense 'd' matrix of size (n,1). - initvals['s'] is a dense 'd' matrix of size (K,1), representing a vector that is strictly positive with respect to the cone C. - initvals['y'] is a dense 'd' matrix of size (p,1). - initvals['z'] is a dense 'd' matrix of size (K,1), representing a vector that is strictly positive with respect to the cone C. A default initialization is used for the variables that are not specified in initvals. It is assumed that rank(A) = p and rank([P; A; G]) = n. The other arguments are normally not needed. They make it possible to exploit certain types of structure, as described below. Output arguments. Returns a dictionary with keys 'status', 'x', 's', 'z', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack', 'iterations'. The 'status' field has values 'optimal' or 'unknown'. 'iterations' is the number of iterations taken. If the status is 'optimal', 'x', 's', 'y', 'z' are an approximate solution of the primal and dual optimality conditions G*x + s = h, A*x = b P*x + G'*z + A'*y + q = 0 s >= 0, z >= 0 s'*z = 0. If the status is 'unknown', 'x', 'y', 's', 'z' are the last iterates before termination. These satisfy s > 0 and z > 0, but are not necessarily feasible. The values of the other fields are defined as follows. - 'primal objective': the primal objective (1/2)*x'*P*x + q'*x. - 'dual objective': the dual objective L(x,y,z) = (1/2)*x'*P*x + q'*x + z'*(G*x - h) + y'*(A*x-b). - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as gap / -primal objective if the primal objective is negative, gap / dual objective if the dual objective is positive, and None otherwise. - 'primal infeasibility': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || P*x + G'*z + A'*y + q || / max(1, ||q||). - 'primal slack': the smallest primal slack, sup {t | s >= t*e }, where e = ( e_0, e_1, ..., e_N, e_{N+1}, ..., e_{M+N} ) is the identity vector in C. e_0 is an ml-vector of ones, e_k, k = 1,..., N, is the unit vector (1,0,...,0) of length mq[k], and e_k = vec(I) where I is the identity matrix of order ms[k]. - 'dual slack': the smallest dual slack, sup {t | z >= t*e }. If the exit status is 'optimal', then the primal and dual infeasibilities are guaranteed to be less than solvers.options['feastol'] (default 1e-7). The gap is less than solvers.options['abstol'] (default 1e-7) or the relative gap is less than solvers.options['reltol'] (default 1e-6). Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, s, z are close to optimal. Advanced usage. Three mechanisms are provided to express problem structure. 1. The user can provide a customized routine for solving linear equations (`KKT systems') [ P A' G' ] [ ux ] [ bx ] [ A 0 0 ] [ uy ] = [ by ]. [ G 0 -W'*W ] [ uz ] [ bz ] W is a scaling matrix, a block diagonal mapping W*u = ( W0*u_0, ..., W_{N+M}*u_{N+M} ) defined as follows. - For the 'l' block (W_0): W_0 = diag(d), with d a positive vector of length ml. - For the 'q' blocks (W_{k+1}, k = 0, ..., N-1): W_{k+1} = beta_k * ( 2 * v_k * v_k' - J ) where beta_k is a positive scalar, v_k is a vector in R^mq[k] with v_k[0] > 0 and v_k'*J*v_k = 1, and J = [1, 0; 0, -I]. - For the 's' blocks (W_{k+N}, k = 0, ..., M-1): W_k * u = vec(r_k' * mat(u) * r_k) where r_k is a nonsingular matrix of order ms[k], and mat(x) is the inverse of the vec operation. The optional argument kktsolver is a Python function that will be called as g = kktsolver(W). W is a dictionary that contains the parameters of the scaling: - W['d'] is a positive 'd' matrix of size (ml,1). - W['di'] is a positive 'd' matrix with the elementwise inverse of W['d']. - W['beta'] is a list [ beta_0, ..., beta_{N-1} ] - W['v'] is a list [ v_0, ..., v_{N-1} ] - W['r'] is a list [ r_0, ..., r_{M-1} ] - W['rti'] is a list [ rti_0, ..., rti_{M-1} ], with rti_k the inverse of the transpose of r_k. The call g = kktsolver(W) should return a function g that solves the KKT system by g(x, y, z). On entry, x, y, z contain the righthand side bx, by, bz. On exit, they contain the solution, with uz scaled, the argument z contains W*uz. In other words, on exit x, y, z are the solution of [ P A' G'*W^{-1} ] [ ux ] [ bx ] [ A 0 0 ] [ uy ] = [ by ]. [ G 0 -W' ] [ uz ] [ bz ] 2. The linear operators P*u, G*u and A*u can be specified by providing Python functions instead of matrices. This can only be done in combination with 1. above, i.e., it requires the kktsolver argument. If P is a function, the call P(u, v, alpha, beta) should evaluate the matrix-vectors product v := alpha * P * u + beta * v. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0. If G is a function, the call G(u, v, alpha, beta, trans) should evaluate the matrix-vector products v := alpha * G * u + beta * v if trans is 'N' v := alpha * G' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. If A is a function, the call A(u, v, alpha, beta, trans) should evaluate the matrix-vectors products v := alpha * A * u + beta * v if trans is 'N' v := alpha * A' * u + beta * v if trans is 'T'. The arguments u and v are required. The other arguments have default values alpha = 1.0, beta = 0.0, trans = 'N'. 3. Instead of using the default representation of the primal variable x and the dual variable y as one-column 'd' matrices, we can represent these variables and the corresponding parameters q and b by arbitrary Python objects (matrices, lists, dictionaries, etc). This can only be done in combination with 1. and 2. above, i.e., it requires a user-provided KKT solver and an operator description of the linear mappings. It also requires the arguments xnewcopy, xdot, xscal, xaxpy, ynewcopy, ydot, yscal, yaxpy. These arguments are functions defined as follows. If X is the vector space of primal variables x, then: - xnewcopy(u) creates a new copy of the vector u in X. - xdot(u, v) returns the inner product of two vectors u and v in X. - xscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in X. - xaxpy(u, v, alpha = 1.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in X. If this option is used, the argument q must be in the same format as x, the argument P must be a Python function, the arguments A and G must be Python functions or None, and the argument kktsolver is required. If Y is the vector space of primal variables y: - ynewcopy(u) creates a new copy of the vector u in Y. - ydot(u, v) returns the inner product of two vectors u and v in Y. - yscal(alpha, u) computes u := alpha*u, where alpha is a scalar and u is a vector in Y. - yaxpy(u, v, alpha = 1.0) computes v := alpha*u + v for a scalar alpha and two vectors u and v in Y. If this option is used, the argument b must be in the same format as y, the argument A must be a Python function or None, and the argument kktsolver is required. Control parameters. The following control parameters can be modified by adding an entry to the dictionary options. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] nonnegative integer (default: 0 for problems with no second-order cone and matrix inequality constraints; 1 otherwise) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). """ import math from cvxopt import base, blas, misc from cvxopt.base import matrix, spmatrix STEP = 0.99 EXPON = 3 try: DEBUG = options['debug'] except KeyError: DEBUG = False # Use Mehrotra correction or not. try: correction = options['use_correction'] except KeyError: correction = True try: MAXITERS = options['maxiters'] except KeyError: MAXITERS = 100 else: if type(MAXITERS) is not int or MAXITERS < 1: raise ValueError("options['maxiters'] must be a positive "\ "integer") try: ABSTOL = options['abstol'] except KeyError: ABSTOL = 1e-7 else: if type(ABSTOL) is not float and type(ABSTOL) is not int: raise ValueError("options['abstol'] must be a scalar") try: RELTOL = options['reltol'] except KeyError: RELTOL = 1e-6 else: if type(RELTOL) is not float and type(RELTOL) is not int: raise ValueError("options['reltol'] must be a scalar") if RELTOL <= 0.0 and ABSTOL <= 0.0 : raise ValueError("at least one of options['reltol'] and " \ "options['abstol'] must be positive") try: FEASTOL = options['feastol'] except KeyError: FEASTOL = 1e-7 else: if (type(FEASTOL) is not float and type(FEASTOL) is not int) or \ FEASTOL <= 0.0: raise ValueError("options['feastol'] must be a positive "\ "scalar") try: show_progress = options['show_progress'] except KeyError: show_progress = True if kktsolver is None: if dims and (dims['q'] or dims['s']): kktsolver = 'chol' else: kktsolver = 'chol2' defaultsolvers = ('ldl', 'ldl2', 'chol', 'chol2') if type(kktsolver) is str and kktsolver not in defaultsolvers: raise ValueError("'%s' is not a valid value for kktsolver" \ %kktsolver) # Argument error checking depends on level of customization. customkkt = type(kktsolver) is not str matrixP = type(P) in (matrix, spmatrix) matrixG = type(G) in (matrix, spmatrix) matrixA = type(A) in (matrix, spmatrix) if (not matrixP or (not matrixG and G is not None) or (not matrixA and A is not None)) and not customkkt: raise ValueError("use of function valued P, G, A requires a "\ "user-provided kktsolver") customx = (xnewcopy != None or xdot != None or xaxpy != None or xscal != None) if customx and (matrixP or matrixG or matrixA or not customkkt): raise ValueError("use of non-vector type for x requires "\ "function valued P, G, A and user-provided kktsolver") customy = (ynewcopy != None or ydot != None or yaxpy != None or yscal != None) if customy and (matrixA or not customkkt): raise ValueError("use of non vector type for y requires "\ "function valued A and user-provided kktsolver") if not customx and (type(q) is not matrix or q.typecode != 'd' or q.size[1] != 1): raise TypeError("'q' must be a 'd' matrix with one column") if matrixP: if P.typecode != 'd' or P.size != (q.size[0], q.size[0]): raise TypeError("'P' must be a 'd' matrix of size (%d, %d)"\ %(q.size[0], q.size[0])) def fP(x, y, alpha = 1.0, beta = 0.0): base.symv(P, x, y, alpha = alpha, beta = beta) else: fP = P if h is None: h = matrix(0.0, (0,1)) if type(h) is not matrix or h.typecode != 'd' or h.size[1] != 1: raise TypeError("'h' must be a 'd' matrix with one column") if not dims: dims = {'l': h.size[0], 'q': [], 's': []} if type(dims['l']) is not int or dims['l'] < 0: raise TypeError("'dims['l']' must be a nonnegative integer") if [ k for k in dims['q'] if type(k) is not int or k < 1 ]: raise TypeError("'dims['q']' must be a list of positive integers") if [ k for k in dims['s'] if type(k) is not int or k < 0 ]: raise TypeError("'dims['s']' must be a list of nonnegative " \ "integers") try: refinement = options['refinement'] except KeyError: if dims['q'] or dims['s']: refinement = 1 else: refinement = 0 else: if type(refinement) is not int or refinement < 0: raise ValueError("options['refinement'] must be a "\ "nonnegative integer") cdim = dims['l'] + sum(dims['q']) + sum([ k**2 for k in dims['s'] ]) if h.size[0] != cdim: raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %cdim) # Data for kth 'q' constraint are found in rows indq[k]:indq[k+1] of G. indq = [ dims['l'] ] for k in dims['q']: indq = indq + [ indq[-1] + k ] # Data for kth 's' constraint are found in rows inds[k]:inds[k+1] of G. inds = [ indq[-1] ] for k in dims['s']: inds = inds + [ inds[-1] + k**2 ] if G is None: if customx: def G(x, y, trans = 'N', alpha = 1.0, beta = 0.0): if trans == 'N': pass else: xscal(beta, y) else: G = spmatrix([], [], [], (0, q.size[0])) matrixG = True if matrixG: if G.typecode != 'd' or G.size != (cdim, q.size[0]): raise TypeError("'G' must be a 'd' matrix of size (%d, %d)"\ %(cdim, q.size[0])) def fG(x, y, trans = 'N', alpha = 1.0, beta = 0.0): misc.sgemv(G, x, y, dims, trans = trans, alpha = alpha, beta = beta) else: fG = G if A is None: if customx or customy: def A(x, y, trans = 'N', alpha = 1.0, beta = 0.0): if trans == 'N': pass else: xscal(beta, y) else: A = spmatrix([], [], [], (0, q.size[0])) matrixA = True if matrixA: if A.typecode != 'd' or A.size[1] != q.size[0]: raise TypeError("'A' must be a 'd' matrix with %d columns" \ %q.size[0]) def fA(x, y, trans = 'N', alpha = 1.0, beta = 0.0): base.gemv(A, x, y, trans = trans, alpha = alpha, beta = beta) else: fA = A if not customy: if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size[1] != 1: raise TypeError("'b' must be a 'd' matrix with one column") if matrixA and b.size[0] != A.size[0]: raise TypeError("'b' must have length %d" %A.size[0]) if b is None and customy: raise ValueEror("use of non-vector type for y requires b") ws3, wz3 = matrix(0.0, (cdim,1 )), matrix(0.0, (cdim,1 )) def res(ux, uy, uz, us, vx, vy, vz, vs, W, lmbda): # Evaluates residual in Newton equations: # # [ vx ] [ vx ] [ 0 ] [ P A' G' ] [ ux ] # [ vy ] := [ vy ] - [ 0 ] - [ A 0 0 ] * [ uy ] # [ vz ] [ vz ] [ W'*us ] [ G 0 0 ] [ W^{-1}*uz ] # # vs := vs - lmbda o (uz + us). # vx := vx - P*ux - A'*uy - G'*W^{-1}*uz fP(ux, vx, alpha = -1.0, beta = 1.0) fA(uy, vx, alpha = -1.0, beta = 1.0, trans = 'T') blas.copy(uz, wz3) misc.scale(wz3, W, inverse = 'I') fG(wz3, vx, alpha = -1.0, beta = 1.0, trans = 'T') # vy := vy - A*ux fA(ux, vy, alpha = -1.0, beta = 1.0) # vz := vz - G*ux - W'*us fG(ux, vz, alpha = -1.0, beta = 1.0) blas.copy(us, ws3) misc.scale(ws3, W, trans = 'T') blas.axpy(ws3, vz, alpha = -1.0) # vs := vs - lmbda o (uz + us) blas.copy(us, ws3) blas.axpy(uz, ws3) misc.sprod(ws3, lmbda, dims, diag = 'D') blas.axpy(ws3, vs, alpha = -1.0) # kktsolver(W) returns a routine for solving # # [ P A' G'*W^{-1} ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ]. # [ G 0 -W' ] [ uz ] [ bz ] if kktsolver in defaultsolvers: if b.size[0] > q.size[0]: raise ValueError("Rank(A) < p or Rank([P; G; A]) < n") if kktsolver == 'ldl': factor = misc.kkt_ldl(G, dims, A) elif kktsolver == 'ldl2': factor = misc.kkt_ldl2(G, dims, A) elif kktsolver == 'chol': factor = misc.kkt_chol(G, dims, A) else: factor = misc.kkt_chol2(G, dims, A) def kktsolver(W): return factor(W, P) if xnewcopy is None: xnewcopy = matrix if xdot is None: xdot = blas.dot if xaxpy is None: xaxpy = blas.axpy if xscal is None: xscal = blas.scal def xcopy(x, y): xscal(0.0, y) xaxpy(x, y) if ynewcopy is None: ynewcopy = matrix if ydot is None: ydot = blas.dot if yaxpy is None: yaxpy = blas.axpy if yscal is None: yscal = blas.scal def ycopy(x, y): yscal(0.0, y) yaxpy(x, y) resx0 = max(1.0, math.sqrt(xdot(q,q))) resy0 = max(1.0, math.sqrt(ydot(b,b))) resz0 = max(1.0, misc.snrm2(h, dims)) if cdim == 0: # Solve # # [ P A' ] [ x ] [ -q ] # [ ] [ ] = [ ]. # [ A 0 ] [ y ] [ b ] try: f3 = kktsolver({'d': matrix(0.0, (0,1)), 'di': matrix(0.0, (0,1)), 'beta': [], 'v': [], 'r': [], 'rti': []}) except ArithmeticError: raise ValueError("Rank(A) < p or Rank([P; A; G]) < n") x = xnewcopy(q) xscal(-1.0, x) y = ynewcopy(b) f3(x, y, matrix(0.0, (0,1))) # dres = || P*x + q + A'*y || / resx0 rx = xnewcopy(q) fP(x, rx, beta = 1.0) pcost = 0.5 * (xdot(x, rx) + xdot(x, q)) fA(y, rx, beta = 1.0, trans = 'T') dres = math.sqrt(xdot(rx, rx)) / resx0 # pres = || A*x - b || / resy0 ry = ynewcopy(b) fA(x, ry, alpha = 1.0, beta = -1.0) pres = math.sqrt(ydot(ry, ry)) / resy0 if pcost == 0.0: relgap = None else: relgap = 0.0 return { 'status': 'optimal', 'x': x, 'y': y, 'z': matrix(0.0, (0,1)), 's': matrix(0.0, (0,1)), 'gap': 0.0, 'relgap': 0.0, 'primal objective': pcost, 'dual objective': pcost, 'primal slack': 0.0, 'dual slack': 0.0, 'primal infeasibility': pres, 'dual infeasibility': dres, 'iterations': 0 } x, y = xnewcopy(q), ynewcopy(b) s, z = matrix(0.0, (cdim, 1)), matrix(0.0, (cdim, 1)) if initvals is None: # Factor # # [ P A' G' ] # [ A 0 0 ]. # [ G 0 -I ] W = {} W['d'] = matrix(1.0, (dims['l'], 1)) W['di'] = matrix(1.0, (dims['l'], 1)) W['v'] = [ matrix(0.0, (m,1)) for m in dims['q'] ] W['beta'] = len(dims['q']) * [ 1.0 ] for v in W['v']: v[0] = 1.0 W['r'] = [ matrix(0.0, (m,m)) for m in dims['s'] ] W['rti'] = [ matrix(0.0, (m,m)) for m in dims['s'] ] for r in W['r']: r[::r.size[0]+1 ] = 1.0 for rti in W['rti']: rti[::rti.size[0]+1 ] = 1.0 try: f = kktsolver(W) except ArithmeticError: raise ValueError("Rank(A) < p or Rank([P; A; G]) < n") # Solve # # [ P A' G' ] [ x ] [ -q ] # [ A 0 0 ] * [ y ] = [ b ]. # [ G 0 -I ] [ z ] [ h ] xcopy(q, x) xscal(-1.0, x) ycopy(b, y) blas.copy(h, z) try: f(x, y, z) except ArithmeticError: raise ValueError("Rank(A) < p or Rank([P; G; A]) < n") blas.copy(z, s) blas.scal(-1.0, s) nrms = misc.snrm2(s, dims) ts = misc.max_step(s, dims) if ts >= -1e-8 * max(nrms, 1.0): a = 1.0 + ts s[:dims['l']] += a s[indq[:-1]] += a ind = dims['l'] + sum(dims['q']) for m in dims['s']: s[ind : ind+m*m : m+1] += a ind += m**2 nrmz = misc.snrm2(z, dims) tz = misc.max_step(z, dims) if tz >= -1e-8 * max(nrmz, 1.0): a = 1.0 + tz z[:dims['l']] += a z[indq[:-1]] += a ind = dims['l'] + sum(dims['q']) for m in dims['s']: z[ind : ind+m*m : m+1] += a ind += m**2 else: if 'x' in initvals: xcopy(initvals['x'], x) else: xscal(0.0, x) if 's' in initvals: blas.copy(initvals['s'], s) # ts = min{ t | s + t*e >= 0 } if misc.max_step(s, dims) >= 0: raise ValueError("initial s is not positive") else: s[: dims['l']] = 1.0 ind = dims['l'] for m in dims['q']: s[ind] = 1.0 ind += m for m in dims['s']: s[ind : ind + m*m : m+1] = 1.0 ind += m**2 if 'y' in initvals: ycopy(initvals['y'], y) else: yscal(0.0, y) if 'z' in initvals: blas.copy(initvals['z'], z) # tz = min{ t | z + t*e >= 0 } if misc.max_step(z, dims) >= 0: raise ValueError("initial z is not positive") else: z[: dims['l']] = 1.0 ind = dims['l'] for m in dims['q']: z[ind] = 1.0 ind += m for m in dims['s']: z[ind : ind + m*m : m+1] = 1.0 ind += m**2 rx, ry, rz = xnewcopy(q), ynewcopy(b), matrix(0.0, (cdim, 1)) dx, dy = xnewcopy(x), ynewcopy(y) dz, ds = matrix(0.0, (cdim, 1)), matrix(0.0, (cdim, 1)) lmbda = matrix(0.0, (dims['l'] + sum(dims['q']) + sum(dims['s']), 1)) lmbdasq = matrix(0.0, (dims['l'] + sum(dims['q']) + sum(dims['s']), 1)) sigs = matrix(0.0, (sum(dims['s']), 1)) sigz = matrix(0.0, (sum(dims['s']), 1)) if show_progress: print("% 10s% 12s% 10s% 8s% 7s" %("pcost", "dcost", "gap", "pres", "dres")) gap = misc.sdot(s, z, dims) for iters in range(MAXITERS + 1): # f0 = (1/2)*x'*P*x + q'*x + r and rx = P*x + q + A'*y + G'*z. xcopy(q, rx) fP(x, rx, beta = 1.0) f0 = 0.5 * (xdot(x, rx) + xdot(x, q)) fA(y, rx, beta = 1.0, trans = 'T') fG(z, rx, beta = 1.0, trans = 'T') resx = math.sqrt(xdot(rx, rx)) # ry = A*x - b ycopy(b, ry) fA(x, ry, alpha = 1.0, beta = -1.0) resy = math.sqrt(ydot(ry, ry)) # rz = s + G*x - h blas.copy(s, rz) blas.axpy(h, rz, alpha = -1.0) fG(x, rz, beta = 1.0) resz = misc.snrm2(rz, dims) # Statistics for stopping criteria. # pcost = (1/2)*x'*P*x + q'*x # dcost = (1/2)*x'*P*x + q'*x + y'*(A*x-b) + z'*(G*x-h) # = (1/2)*x'*P*x + q'*x + y'*(A*x-b) + z'*(G*x-h+s) - z'*s # = (1/2)*x'*P*x + q'*x + y'*ry + z'*rz - gap pcost = f0 dcost = f0 + ydot(y, ry) + misc.sdot(z, rz, dims) - gap if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None pres = max(resy/resy0, resz/resz0) dres = resx/resx0 if show_progress: print("%2d: % 8.4e % 8.4e % 4.0e% 7.0e% 7.0e" \ %(iters, pcost, dcost, gap, pres, dres)) if ( pres <= FEASTOL and dres <= FEASTOL and ( gap <= ABSTOL or (relgap is not None and relgap <= RELTOL) )) or \ iters == MAXITERS: ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(s, m, ind) misc.symm(z, m, ind) ind += m**2 ts = misc.max_step(s, dims) tz = misc.max_step(z, dims) if iters == MAXITERS: if show_progress: print("Terminated (maximum number of iterations "\ "reached).") status = 'unknown' else: if show_progress: print("Optimal solution found.") status = 'optimal' return { 'x': x, 'y': y, 's': s, 'z': z, 'status': status, 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective': dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz , 'iterations': iters } # Compute initial scaling W and scaled iterates: # # W * z = W^{-T} * s = lambda. # # lmbdasq = lambda o lambda. if iters == 0: W = misc.compute_scaling(s, z, lmbda, dims) misc.ssqr(lmbdasq, lmbda, dims) # f3(x, y, z) solves # # [ P A' G' ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ]. # [ G 0 -W'*W ] [ W^{-1}*uz ] [ bz ] # # On entry, x, y, z containg bx, by, bz. # On exit, they contain ux, uy, uz. try: f3 = kktsolver(W) except ArithmeticError: if iters == 0: raise ValueError("Rank(A) < p or Rank([P; A; G]) < n") else: ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(s, m, ind) misc.symm(z, m, ind) ind += m**2 ts = misc.max_step(s, dims) tz = misc.max_step(z, dims) print("Terminated (singular KKT matrix).") return { 'x': x, 'y': y, 's': s, 'z': z, 'status': 'unknown', 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective': dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz, 'iterations': iters } # f4_no_ir(x, y, z, s) solves # # [ 0 ] [ P A' G' ] [ ux ] [ bx ] # [ 0 ] + [ A 0 0 ] * [ uy ] = [ by ] # [ W'*us ] [ G 0 0 ] [ W^{-1}*uz ] [ bz ] # # lmbda o (uz + us) = bs. # # On entry, x, y, z, s contain bx, by, bz, bs. # On exit, they contain ux, uy, uz, us. def f4_no_ir(x, y, z, s): # Solve # # [ P A' G' ] [ ux ] [ bx ] # [ A 0 0 ] [ uy ] = [ by ] # [ G 0 -W'*W ] [ W^{-1}*uz ] [ bz - W'*(lmbda o\ bs) ] # # us = lmbda o\ bs - uz. # # On entry, x, y, z, s contains bx, by, bz, bs. # On exit they contain x, y, z, s. # s := lmbda o\ s # = lmbda o\ bs misc.sinv(s, lmbda, dims) # z := z - W'*s # = bz - W'*(lambda o\ bs) blas.copy(s, ws3) misc.scale(ws3, W, trans = 'T') blas.axpy(ws3, z, alpha = -1.0) # Solve for ux, uy, uz f3(x, y, z) # s := s - z # = lambda o\ bs - uz. blas.axpy(z, s, alpha = -1.0) # f4(x, y, z, s) solves the same system as f4_no_ir, but applies # iterative refinement. if iters == 0: if refinement or DEBUG: wx, wy = xnewcopy(q), ynewcopy(b) wz, ws = matrix(0.0, (cdim,1)), matrix(0.0, (cdim,1)) if refinement: wx2, wy2 = xnewcopy(q), ynewcopy(b) wz2, ws2 = matrix(0.0, (cdim,1)), matrix(0.0, (cdim,1)) def f4(x, y, z, s): if refinement or DEBUG: xcopy(x, wx) ycopy(y, wy) blas.copy(z, wz) blas.copy(s, ws) f4_no_ir(x, y, z, s) for i in range(refinement): xcopy(wx, wx2) ycopy(wy, wy2) blas.copy(wz, wz2) blas.copy(ws, ws2) res(x, y, z, s, wx2, wy2, wz2, ws2, W, lmbda) f4_no_ir(wx2, wy2, wz2, ws2) xaxpy(wx2, x) yaxpy(wy2, y) blas.axpy(wz2, z) blas.axpy(ws2, s) if DEBUG: res(x, y, z, s, wx, wy, wz, ws, W, lmbda) print("KKT residuals:") print(" 'x': %e" %math.sqrt(xdot(wx, wx))) print(" 'y': %e" %math.sqrt(ydot(wy, wy))) print(" 'z': %e" %misc.snrm2(wz, dims)) print(" 's': %e" %misc.snrm2(ws, dims)) mu = gap / (dims['l'] + len(dims['q']) + sum(dims['s'])) sigma, eta = 0.0, 0.0 for i in [0, 1]: # Solve # # [ 0 ] [ P A' G' ] [ dx ] # [ 0 ] + [ A 0 0 ] * [ dy ] = -(1 - eta) * r # [ W'*ds ] [ G 0 0 ] [ W^{-1}*dz ] # # lmbda o (dz + ds) = -lmbda o lmbda + sigma*mu*e (i=0) # lmbda o (dz + ds) = -lmbda o lmbda - dsa o dza # + sigma*mu*e (i=1) where dsa, dza # are the solution for i=0. # ds = -lmbdasq + sigma * mu * e (if i is 0) # = -lmbdasq - dsa o dza + sigma * mu * e (if i is 1), # where ds, dz are solution for i is 0. blas.scal(0.0, ds) if correction and i == 1: blas.axpy(ws3, ds, alpha = -1.0) blas.axpy(lmbdasq, ds, n = dims['l'] + sum(dims['q']), alpha = -1.0) ds[:dims['l']] += sigma*mu ind = dims['l'] for m in dims['q']: ds[ind] += sigma*mu ind += m ind2 = ind for m in dims['s']: blas.axpy(lmbdasq, ds, n = m, offsetx = ind2, offsety = ind, incy = m + 1, alpha = -1.0) ds[ind : ind + m*m : m+1] += sigma*mu ind += m*m ind2 += m # (dx, dy, dz) := -(1 - eta) * (rx, ry, rz) xscal(0.0, dx); xaxpy(rx, dx, alpha = -1.0 + eta) yscal(0.0, dy); yaxpy(ry, dy, alpha = -1.0 + eta) blas.scal(0.0, dz) blas.axpy(rz, dz, alpha = -1.0 + eta) try: f4(dx, dy, dz, ds) except ArithmeticError: if iters == 0: raise ValueError("Rank(A) < p or Rank([P; A; G]) < n") else: ind = dims['l'] + sum(dims['q']) for m in dims['s']: misc.symm(s, m, ind) misc.symm(z, m, ind) ind += m**2 ts = misc.max_step(s, dims) tz = misc.max_step(z, dims) print("Terminated (singular KKT matrix).") return { 'x': x, 'y': y, 's': s, 'z': z, 'status': 'unknown', 'gap': gap, 'relative gap': relgap, 'primal objective': pcost, 'dual objective': dcost, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': -ts, 'dual slack': -tz, 'iterations': iters } dsdz = misc.sdot(ds, dz, dims) # Save ds o dz for Mehrotra correction if correction and i == 0: blas.copy(ds, ws3) misc.sprod(ws3, dz, dims) # Maximum steps to boundary. # # If i is 1, also compute eigenvalue decomposition of the # 's' blocks in ds,dz. The eigenvectors Qs, Qz are stored in # dsk, dzk. The eigenvalues are stored in sigs, sigz. misc.scale2(lmbda, ds, dims) misc.scale2(lmbda, dz, dims) if i == 0: ts = misc.max_step(ds, dims) tz = misc.max_step(dz, dims) else: ts = misc.max_step(ds, dims, sigma = sigs) tz = misc.max_step(dz, dims, sigma = sigz) t = max([ 0.0, ts, tz ]) if t == 0: step = 1.0 else: if i == 0: step = min(1.0, 1.0 / t) else: step = min(1.0, STEP / t) if i == 0: sigma = min(1.0, max(0.0, 1.0 - step + dsdz/gap * step**2))**EXPON eta = 0.0 xaxpy(dx, x, alpha = step) yaxpy(dy, y, alpha = step) # We will now replace the 'l' and 'q' blocks of ds and dz with # the updated iterates in the current scaling. # We also replace the 's' blocks of ds and dz with the factors # Ls, Lz in a factorization Ls*Ls', Lz*Lz' of the updated variables # in the current scaling. # ds := e + step*ds for nonlinear, 'l' and 'q' blocks. # dz := e + step*dz for nonlinear, 'l' and 'q' blocks. blas.scal(step, ds, n = dims['l'] + sum(dims['q'])) blas.scal(step, dz, n = dims['l'] + sum(dims['q'])) ind = dims['l'] ds[:ind] += 1.0 dz[:ind] += 1.0 for m in dims['q']: ds[ind] += 1.0 dz[ind] += 1.0 ind += m # ds := H(lambda)^{-1/2} * ds and dz := H(lambda)^{-1/2} * dz. # # This replaced the 'l' and 'q' components of ds and dz with the # updated iterates in the current scaling. # The 's' components of ds and dz are replaced with # # diag(lmbda_k)^{1/2} * Qs * diag(lmbda_k)^{1/2} # diag(lmbda_k)^{1/2} * Qz * diag(lmbda_k)^{1/2} # misc.scale2(lmbda, ds, dims, inverse = 'I') misc.scale2(lmbda, dz, dims, inverse = 'I') # sigs := ( e + step*sigs ) ./ lambda for 's' blocks. # sigz := ( e + step*sigz ) ./ lmabda for 's' blocks. blas.scal(step, sigs) blas.scal(step, sigz) sigs += 1.0 sigz += 1.0 blas.tbsv(lmbda, sigs, n = sum(dims['s']), k = 0, ldA = 1, offsetA = dims['l'] + sum(dims['q'])) blas.tbsv(lmbda, sigz, n = sum(dims['s']), k = 0, ldA = 1, offsetA = dims['l'] + sum(dims['q'])) # dsk := Ls = dsk * sqrt(sigs). # dzk := Lz = dzk * sqrt(sigz). ind2, ind3 = dims['l'] + sum(dims['q']), 0 for k in range(len(dims['s'])): m = dims['s'][k] for i in range(m): blas.scal(math.sqrt(sigs[ind3+i]), ds, offset = ind2 + m*i, n = m) blas.scal(math.sqrt(sigz[ind3+i]), dz, offset = ind2 + m*i, n = m) ind2 += m*m ind3 += m # Update lambda and scaling. misc.update_scaling(W, lmbda, ds, dz) # Unscale s, z (unscaled variables are used only to compute # feasibility residuals). blas.copy(lmbda, s, n = dims['l'] + sum(dims['q'])) ind = dims['l'] + sum(dims['q']) ind2 = ind for m in dims['s']: blas.scal(0.0, s, offset = ind2) blas.copy(lmbda, s, offsetx = ind, offsety = ind2, n = m, incy = m+1) ind += m ind2 += m*m misc.scale(s, W, trans = 'T') blas.copy(lmbda, z, n = dims['l'] + sum(dims['q'])) ind = dims['l'] + sum(dims['q']) ind2 = ind for m in dims['s']: blas.scal(0.0, z, offset = ind2) blas.copy(lmbda, z, offsetx = ind, offsety = ind2, n = m, incy = m+1) ind += m ind2 += m*m misc.scale(z, W, inverse = 'I') gap = blas.dot(lmbda, lmbda) def lp(c, G, h, A = None, b = None, solver = None, primalstart = None, dualstart = None): """ Solves a pair of primal and dual LPs minimize c'*x subject to G*x + s = h A*x = b s >= 0 maximize -h'*z - b'*y subject to G'*z + A'*y + c = 0 z >= 0. Input arguments. G is m x n, h is m x 1, A is p x n, b is p x 1. G and A must be dense or sparse 'd' matrices. h and b are dense 'd' matrices with one column. The default values for A and b are empty matrices with zero rows. solver is None, 'glpk' or 'mosek'. The default solver (None) uses the cvxopt conelp() function. The 'glpk' solver is the simplex LP solver from GLPK. The 'mosek' solver is the LP solver from MOSEK. The arguments primalstart and dualstart are ignored when solver is 'glpk' or 'mosek', and are optional when solver is None. The argument primalstart is a dictionary with keys 'x' and 's', and specifies a primal starting point. primalstart['x'] must be a dense 'd' matrix of length n; primalstart['s'] must be a positive dense 'd' matrix of length m. The argument dualstart is a dictionary with keys 'z' and 'y', and specifies a dual starting point. dualstart['y'] must be a dense 'd' matrix of length p; dualstart['z'] must be a positive dense 'd' matrix of length m. When solver is None, we require n >= 1, Rank(A) = p and Rank([G; A]) = n Output arguments. Returns a dictionary with keys 'status', 'x', 's', 'z', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack', 'residual as primal infeasibility certificate', 'residual as dual infeasibility certificate'. The 'status' field has values 'optimal', 'primal infeasible', 'dual infeasible', or 'unknown'. The values of the other fields depend on the exit status and the solver used. Status 'optimal'. - 'x', 's', 'y', 'z' are an approximate solution of the primal and dual optimality conditions G*x + s = h, A*x = b G'*z + A'*y + c = 0 s >= 0, z >= 0 s'*z = 0. - 'primal objective': the primal objective c'*x. - 'dual objective': the dual objective -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal objective is negative, s'*z / -(h'*z + b'*y) if the dual objective is positive, and None otherwise. - 'primal infeasibility': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack min_k s_k. - 'dual slack': the smallest dual slack min_k z_k. - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate': None. If the default solver is used, the primal infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The dual infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The gap is less than solvers.options['abstol'] (default 1e-7) or the relative gap is less than solvers.options['reltol'] (default 1e-6). For the other solvers, the default GLPK or MOSEK exit criteria apply. Status 'primal infeasible'. If the GLPK solver is used, all the fields except the status field are None. For the default and the MOSEK solvers, the values are as follows. - 'x', 's': None. - 'y', 'z' are an approximate certificate of infeasibility -h'*z - b'*y = 1, G'*z + A'*y = 0, z >= 0. - 'primal objective': None. - 'dual objective': 1.0. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': None. - 'dual slack': the smallest dual slack min z_k. - 'residual as primal infeasibility certificate': the residual in the condition of the infeasibility certificate, defined as || G'*z + A'*y || / max(1, ||c||). - 'residual as dual infeasibility certificate': None. If the default solver is used, the residual as primal infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). For the other solvers, the default GLPK or MOSEK exit criteria apply. Status 'dual infeasible'. If the GLPK solver is used, all the fields except the status field are empty. For the default and the MOSEK solvers, the values are as follows. - 'x', 's' are an approximate proof of dual infeasibility c'*x = -1, G*x + s = 0, A*x = 0, s >= 0. - 'y', 'z': None. - 'primal objective': -1.0. - 'dual objective': None. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': the smallest primal slack min_k s_k . - 'dual slack': None. - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate: the residual in the conditions of the infeasibility certificate, defined as the maximum of || G*x + s || / max(1, ||h||) and || A*x || / max(1, ||b||). If the default solver is used, the residual as dual infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). For the other solvers, the default GLPK or MOSEK exit criteria apply. Status 'unknown'. If the GLPK or MOSEK solver is used, all the fields except the status field are None. If the default solver is used, the values are as follows. - 'x', 'y', 's', 'z' are the last iterates before termination. These satisfy s > 0 and z > 0, but are not necessarily feasible. - 'primal objective': the primal cost c'*x. - 'dual objective': the dual cost -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal cost is negative, s'*z / -(h'*z + b'*y) if the dual cost is positive, and None otherwise. - 'primal infeasibility ': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack min_k s_k. - 'dual slack': the smallest dual slack min_k z_k. - 'residual as primal infeasibility certificate': None if h'*z + b'*y >= 0; the residual || G'*z + A'*y || / (-(h'*z + b'*y) * max(1, ||c||) ) otherwise. - 'residual as dual infeasibility certificate': None if c'*x >= 0; the maximum of the residuals || G*x + s || / (-c'*x * max(1, ||h||)) and || A*x || / (-c'*x * max(1, ||b||)) otherwise. Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, s, z are close to optimal. If the residual as primal infeasibility certificate is small, then y / (-h'*z - b'*y), z / (-h'*z - b'*y) provide an approximate certificate of primal infeasibility. If the residual as certificate of dual infeasibility is small, then x / (-c'*x), s / (-c'*x) provide an approximate proof of dual infeasibility. Control parameters. The control parameters for the different solvers can be modified by adding an entry to the dictionary cvxopt.solvers.options. The following parameters control the execution of the default solver. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] positive integer (default: 0) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). The control parameter names for GLPK are strings with the name of the GLPK parameter, listed in the GLPK documentation. The MOSEK parameters can me modified by adding an entry options['MOSEK'], containing a dictionary with MOSEK parameter/value pairs, as described in the MOSEK documentation. Options that are not recognized are replaced by their default values. """ import math from cvxopt import base, blas, misc from cvxopt.base import matrix, spmatrix if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if (type(G) is not matrix and type(G) is not spmatrix) or \ G.typecode != 'd' or G.size[1] != n: raise TypeError("'G' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) m = G.size[0] if type(h) is not matrix or h.typecode != 'd' or h.size != (m,1): raise TypeError("'h' must be a 'd' matrix of size (%d,1)" %m) if A is None: A = spmatrix([], [], [], (0,n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): raise TypeError("'b' must be a dense matrix of size (%d,1)" %p) if solver == 'glpk': try: from cvxopt import glpk except ImportError: raise ValueError("invalid option "\ "(solver = 'glpk'): cvxopt.glpk is not installed") glpk.options = options status, x, z, y = glpk.lp(c, G, h, A, b) if status == 'optimal': resx0 = max(1.0, blas.nrm2(c)) resy0 = max(1.0, blas.nrm2(b)) resz0 = max(1.0, blas.nrm2(h)) pcost = blas.dot(c,x) dcost = -blas.dot(h,z) - blas.dot(b,y) s = matrix(h) base.gemv(G, x, s, alpha=-1.0, beta=1.0) gap = blas.dot(s, z) if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None # rx = c + G'*z + A'*y rx = matrix(c) base.gemv(G, z, rx, beta = 1.0, trans = 'T') base.gemv(A, y, rx, beta = 1.0, trans = 'T') resx = blas.nrm2(rx) / resx0 # ry = b - A*x ry = matrix(b) base.gemv(A, x, ry, alpha = -1.0, beta = 1.0) resy = blas.nrm2(ry) / resy0 # rz = G*x + s - h rz = matrix(0.0, (m,1)) base.gemv(G, x, rz) blas.axpy(s, rz) blas.axpy(h, rz, alpha = -1.0) resz = blas.nrm2(rz) / resz0 dims = {'l': m, 's': [], 'q': []} pslack = -misc.max_step(s, dims) dslack = -misc.max_step(z, dims) pres, dres = max(resy, resz), resx pinfres, dinfres = None, None else: s = None pcost, dcost = None, None gap, relgap = None, None pres, dres = None, None pslack, dslack = None, None pinfres, dinfres = None, None return {'status': status, 'x': x, 's': s, 'y': y, 'z': z, 'primal objective': pcost, 'dual objective': dcost, 'gap': gap, 'relative gap': relgap, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': pslack, 'dual slack': dslack, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': dinfres} if solver == 'mosek': try: from cvxopt import msk import mosek except ImportError: raise ValueError("invalid option (solver = 'mosek'): "\ "cvxopt.mosek is not installed") if 'MOSEK' in options: msk.options = options['MOSEK'] else: msk.options = {} solsta, x, z, y = msk.lp(c, G, h, A, b) resx0 = max(1.0, blas.nrm2(c)) resy0 = max(1.0, blas.nrm2(b)) resz0 = max(1.0, blas.nrm2(h)) if solsta is mosek.solsta.optimal: status = 'optimal' pcost = blas.dot(c,x) dcost = -blas.dot(h,z) - blas.dot(b,y) # s = h - G*x s = matrix(h) base.gemv(G, x, s, alpha = -1.0, beta = 1.0) gap = blas.dot(s, z) if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None # rx = c + G'*z + A'*y rx = matrix(c) base.gemv(G, z, rx, beta = 1.0, trans = 'T') base.gemv(A, y, rx, beta = 1.0, trans = 'T') resx = blas.nrm2(rx) / resx0 # ry = b - A*x ry = matrix(b) base.gemv(A, x, ry, alpha = -1.0, beta = 1.0) resy = blas.nrm2(ry) / resy0 # rz = G*x + s - h rz = matrix(0.0, (m,1)) base.gemv(G, x, rz) blas.axpy(s, rz) blas.axpy(h, rz, alpha = -1.0) resz = blas.nrm2(rz) / resz0 dims = {'l': m, 's': [], 'q': []} pslack = -misc.max_step(s, dims) dslack = -misc.max_step(z, dims) pres, dres = max(resy, resz), resx pinfres, dinfres = None, None elif solsta is mosek.solsta.prim_infeas_cer: status = 'primal infeasible' hz, by = blas.dot(h, z), blas.dot(b, y) blas.scal(1.0 / (-hz - by), y) blas.scal(1.0 / (-hz - by), z) # rx = -A'*y - G'*z rx = matrix(0.0, (n,1)) base.gemv(A, y, rx, alpha = -1.0, trans = 'T') base.gemv(G, z, rx, alpha = -1.0, beta = 1.0, trans = 'T') pinfres = blas.nrm2(rx) / resx0 dinfres = None x, s = None, None pres, dres = None, None pcost, dcost = None, 1.0 gap, relgap = None, None dims = {'l': m, 's': [], 'q': []} dslack = -misc.max_step(z, dims) pslack = None elif solsta == mosek.solsta.dual_infeas_cer: status = 'dual infeasible' cx = blas.dot(c,x) blas.scal(-1.0/cx, x) s = matrix(0.0, (m,1)) base.gemv(G, x, s, alpha = -1.0) # ry = A*x ry = matrix(0.0, (p,1)) base.gemv(A, x, ry) resy = blas.nrm2(ry) / resy0 # rz = s + G*x rz = matrix(s) base.gemv(G, x, rz, beta = 1.0) resz = blas.nrm2(rz) / resz0 pres, dres = None, None dinfres, pinfres = max(resy, resz), None z, y = None, None pcost, dcost = -1.0, None gap, relgap = None, None dims = {'l': m, 's': [], 'q': []} pslack = -misc.max_step(s, dims) dslack = None else: s = None pcost, dcost = None, None gap, relgap = None, None pres, dres = None, None pinfres, dinfres = None, None pslack, dslack = None, None return {'status': status, 'x': x, 's': s, 'y': y, 'z': z, 'primal objective': pcost, 'dual objective': dcost, 'gap': gap, 'relative gap': relgap, 'primal infeasibility': pres, 'dual infeasibility': dres, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': dinfres, 'primal slack': pslack, 'dual slack': dslack} return conelp(c, G, h, {'l': m, 'q': [], 's': []}, A, b, primalstart, dualstart) def socp(c, Gl = None, hl = None, Gq = None, hq = None, A = None, b = None, solver = None, primalstart = None, dualstart = None): """ Solves a pair of primal and dual SOCPs minimize c'*x subject to Gl*x + sl = hl Gq[k]*x + sq[k] = hq[k], k = 0, ..., N-1 A*x = b sl >= 0, sq[k] >= 0, k = 0, ..., N-1 maximize -hl'*z - sum_k hq[k]'*zq[k] - b'*y subject to Gl'*zl + sum_k Gq[k]'*zq[k] + A'*y + c = 0 zl >= 0, zq[k] >= 0, k = 0, ..., N-1. The inequalities sl >= 0 and zl >= 0 are elementwise vector inequalities. The inequalities sq[k] >= 0, zq[k] >= 0 are second order cone inequalities, i.e., equivalent to sq[k][0] >= || sq[k][1:] ||_2, zq[k][0] >= || zq[k][1:] ||_2. Input arguments. Gl is a dense or sparse 'd' matrix of size (ml, n). hl is a dense 'd' matrix of size (ml, 1). The default values of Gl and hl are matrices with zero rows. The argument Gq is a list of N dense or sparse 'd' matrices of size (m[k] n), k = 0, ..., N-1, where m[k] >= 1. hq is a list of N dense 'd' matrices of size (m[k], 1), k = 0, ..., N-1. The default values of Gq and hq are empty lists. A is a dense or sparse 'd' matrix of size (p,1). b is a dense 'd' matrix of size (p,1). The default values of A and b are matrices with zero rows. solver is None or 'mosek'. The default solver (None) uses the cvxopt conelp() function. The 'mosek' solver is the SOCP solver from MOSEK. The arguments primalstart and dualstart are ignored when solver is 'mosek', and are optional when solver is None. The argument primalstart is a dictionary with keys 'x', 'sl', 'sq', and specifies an optional primal starting point. primalstart['x'] is a dense 'd' matrix of size (n,1). primalstart['sl'] is a positive dense 'd' matrix of size (ml,1). primalstart['sq'] is a list of matrices of size (m[k],1), positive with respect to the second order cone of order m[k]. The argument dualstart is a dictionary with keys 'y', 'zl', 'zq', and specifies an optional dual starting point. dualstart['y'] is a dense 'd' matrix of size (p,1). dualstart['zl'] is a positive dense 'd' matrix of size (ml,1). dualstart['sq'] is a list of matrices of size (m[k],1), positive with respect to the second order cone of order m[k]. Output arguments. Returns a dictionary with keys 'status', 'x', 'sl', 'sq', 'zl', 'zq', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack', 'residual as primal infeasibility certificate', 'residual as dual infeasibility certificate'. The 'status' field has values 'optimal', 'primal infeasible', 'dual infeasible', or 'unknown'. The values of the other fields depend on the exit status and the solver used. Status 'optimal'. - 'x', 'sl', 'sq', 'y', 'zl', 'zq' are an approximate solution of the primal and dual optimality conditions G*x + s = h, A*x = b G'*z + A'*y + c = 0 s >= 0, z >= 0 s'*z = 0 where G = [ Gl; Gq[0]; ...; Gq[N-1] ] h = [ hl; hq[0]; ...; hq[N-1] ] s = [ sl; sq[0]; ...; sq[N-1] ] z = [ zl; zq[0]; ...; zq[N-1] ]. - 'primal objective': the primal objective c'*x. - 'dual objective': the dual objective -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal objective is negative, s'*z / -(h'*z + b'*y) if the dual objective is positive, and None otherwise. - 'primal infeasibility': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack, min( min_k sl_k, min_k (sq[k][0] - || sq[k][1:] ||) ). - 'dual slack': the smallest dual slack, min( min_k zl_k, min_k (zq[k][0] - || zq[k][1:] ||) ). - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate': None. If the default solver is used, the primal infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The dual infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The gap is less than solvers.options['abstol'] (default 1e-7) or the relative gap is less than solvers.options['reltol'] (default 1e-6). If the MOSEK solver is used, the default MOSEK exit criteria apply. Status 'primal infeasible'. - 'x', 'sl', 'sq': None. - 'y', 'zl', 'zq' are an approximate certificate of infeasibility -h'*z - b'*y = 1, G'*z + A'*y = 0, z >= 0. - 'primal objective': None. - 'dual objective': 1.0. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': None. - 'dual slack': the smallest dual slack, min( min_k zl_k, min_k (zq[k][0] - || zq[k][1:] ||) ). - 'residual as primal infeasibility certificate': the residual in the condition of the infeasibility certificate, defined as || G'*z + A'*y || / max(1, ||c||). - 'residual as dual infeasibility certificate': None. If the default solver is used, the residual as primal infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). If the MOSEK solver is used, the default MOSEK exit criteria apply. Status 'dual infeasible'. - 'x', 'sl', 'sq': an approximate proof of dual infeasibility c'*x = -1, G*x + s = 0, A*x = 0, s >= 0. - 'y', 'zl', 'zq': None. - 'primal objective': -1.0. - 'dual objective': None. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': the smallest primal slack, min( min_k sl_k, min_k (sq[k][0] - || sq[k][1:] ||) ). - 'dual slack': None. - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate: the residual in the conditions of the infeasibility certificate, defined as the maximum of || G*x + s || / max(1, ||h||) and || A*x || / max(1, ||b||). If the default solver is used, the residual as dual infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). If the MOSEK solver is used, the default MOSEK exit criteria apply. Status 'unknown'. If the MOSEK solver is used, all the fields except the status field are empty. If the default solver is used, the values are as follows. - 'x', 'y', 'sl', 'sq', 'zl', 'zq': the last iterates before termination. These satisfy s > 0 and z > 0, but are not necessarily feasible. - 'primal objective': the primal cost c'*x. - 'dual objective': the dual cost -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal cost is negative, s'*z / -(h'*z + b'*y) if the dual cost is positive, and None otherwise. - 'primal infeasibility ': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack, min( min_k sl_k, min_k (sq[k][0] - || sq[k][1:] ||) ). - 'dual slack': the smallest dual slack, min( min_k zl_k, min_k (zq[k][0] - || zq[k][1:] ||) ). - 'residual as primal infeasibility certificate': None if h'*z + b'*y >= 0; the residual || G'*z + A'*y || / (-(h'*z + b'*y) * max(1, ||c||) ) otherwise. - 'residual as dual infeasibility certificate': None if c'*x >= 0; the maximum of the residuals || G*x + s || / (-c'*x * max(1, ||h||)) and || A*x || / (-c'*x * max(1, ||b||)) otherwise. Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, s, z are close to optimal. If the residual as primal infeasibility certificate is small, then y / (-h'*z - b'*y), z / (-h'*z - b'*y) provide an approximate certificate of primal infeasibility. If the residual as certificate of dual infeasibility is small, then x / (-c'*x), s / (-c'*x) provide an approximate proof of dual infeasibility. Control parameters. The control parameters for the different solvers can be modified by adding an entry to the dictionary cvxopt.solvers.options. The following parameters control the execution of the default solver. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] positive integer (default: 1) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). The MOSEK parameters can me modified by adding an entry options['MOSEK'], containing a dictionary with MOSEK parameter/value pairs, as described in the MOSEK documentation. Options that are not recognized are replaced by their default values. """ from cvxopt import base, blas from cvxopt.base import matrix, spmatrix if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if Gl is None: Gl = spmatrix([], [], [], (0,n), tc='d') if (type(Gl) is not matrix and type(Gl) is not spmatrix) or \ Gl.typecode != 'd' or Gl.size[1] != n: raise TypeError("'Gl' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) ml = Gl.size[0] if hl is None: hl = matrix(0.0, (0,1)) if type(hl) is not matrix or hl.typecode != 'd' or \ hl.size != (ml,1): raise TypeError("'hl' must be a dense 'd' matrix of " \ "size (%d,1)" %ml) if Gq is None: Gq = [] if type(Gq) is not list or [ G for G in Gq if (type(G) is not matrix and type(G) is not spmatrix) or G.typecode != 'd' or G.size[1] != n ]: raise TypeError("'Gq' must be a list of sparse or dense 'd' "\ "matrices with %d columns" %n) mq = [ G.size[0] for G in Gq ] a = [ k for k in range(len(mq)) if mq[k] == 0 ] if a: raise TypeError("the number of rows of Gq[%d] is zero" %a[0]) if hq is None: hq = [] if type(hq) is not list or len(hq) != len(mq) or [ h for h in hq if (type(h) is not matrix and type(h) is not spmatrix) or h.typecode != 'd' ]: raise TypeError("'hq' must be a list of %d dense or sparse "\ "'d' matrices" %len(mq)) a = [ k for k in range(len(mq)) if hq[k].size != (mq[k], 1) ] if a: k = a[0] raise TypeError("'hq[%d]' has size (%d,%d). Expected size "\ "is (%d,1)." %(k, hq[k].size[0], hq[k].size[1], mq[k])) if A is None: A = spmatrix([], [], [], (0,n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): raise TypeError("'b' must be a dense matrix of size (%d,1)" %p) dims = {'l': ml, 'q': mq, 's': []} N = ml + sum(mq) if solver == 'mosek': from cvxopt import misc try: from cvxopt import msk import mosek except ImportError: raise ValueError("invalid option (solver = 'mosek'): "\ "cvxopt.mosek is not installed") if 'MOSEK' in options: msk.options = options['MOSEK'] else: msk.options = {} if p: raise ValueError("socp() with the solver = 'socp' option "\ "does not handle problems with equality constraints") solsta, x, zl, zq = msk.socp(c, Gl, hl, Gq, hq) resx0 = max(1.0, blas.nrm2(c)) rh = matrix([ blas.nrm2(hl) ] + [ blas.nrm2(hqk) for hqk in hq ]) resz0 = max(1.0, blas.nrm2(rh)) if solsta is mosek.solsta.optimal: status = 'optimal' y = matrix(0.0, (0,1)) pcost = blas.dot(c,x) dcost = -blas.dot(hl,zl) - \ sum([ blas.dot(hq[k],zq[k]) for k in range(len(mq))]) sl = matrix(hl) base.gemv(Gl, x, sl, alpha = -1.0, beta = 1.0) sq = [ +hqk for hqk in hq ] for k in range(len(Gq)): base.gemv(Gq[k], x, sq[k], alpha = -1.0, beta = 1.0) gap = blas.dot(sl, zl) + \ sum([blas.dot(zq[k],sq[k]) for k in range(len(mq))]) if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None # rx = c + G'*z rx = matrix(c) base.gemv(Gl, zl, rx, beta = 1.0, trans = 'T') for k in range(len(mq)): base.gemv(Gq[k], zq[k], rx, beta = 1.0, trans = 'T') resx = blas.nrm2(rx) / resx0 # rz = G*x + s - h rz = matrix(0.0, (ml + sum(mq),1)) base.gemv(Gl, x, rz) blas.axpy(sl, rz) blas.axpy(hl, rz, alpha = -1.0) ind = ml for k in range(len(mq)): base.gemv(Gq[k], x, rz, offsety = ind) blas.axpy(sq[k], rz, offsety = ind) blas.axpy(hq[k], rz, alpha = -1.0, offsety = ind) ind += mq[k] resz = blas.nrm2(rz) / resz0 s, z = matrix(0.0, (N,1)), matrix(0.0, (N,1)) blas.copy(sl, s) blas.copy(zl, z) ind = ml for k in range(len(mq)): blas.copy(zq[k], z, offsety = ind) blas.copy(sq[k], s, offsety = ind) ind += mq[k] pslack = -misc.max_step(s, dims) dslack = -misc.max_step(z, dims) pres, dres = resz, resx pinfres, dinfres = None, None elif solsta is mosek.solsta.dual_infeas_cer: status = 'primal infeasible' y = matrix(0.0, (0,1)) hz = blas.dot(hl, zl) + sum([blas.dot(hq[k],zq[k]) for k in range(len(mq))]) blas.scal(1.0 / -hz, zl) for k in range(len(mq)): blas.scal(1.0 / -hz, zq[k]) x, sl, sq = None, None, None # rx = - G'*z rx = matrix(0.0, (n,1)) base.gemv(Gl, zl, rx, alpha = -1.0, beta = 1.0, trans = 'T') for k in range(len(mq)): base.gemv(Gq[k], zq[k], rx, beta = 1.0, trans = 'T') pinfres = blas.nrm2(rx) / resx0 dinfres = None z = matrix(0.0, (N,1)) blas.copy(zl, z) ind = ml for k in range(len(mq)): blas.copy(zq[k], z, offsety = ind) ind += mq[k] dslack = -misc.max_step(z, dims) pslack = None x, s = None, None pres, dres = None, None pcost, dcost = None, 1.0 gap, relgap = None, None elif solsta == mosek.solsta.prim_infeas_cer: status = 'dual infeasible' cx = blas.dot(c,x) blas.scal(-1.0/cx, x) sl = matrix(0.0, (ml,1)) base.gemv(Gl, x, sl, alpha = -1.0) sq = [ matrix(0.0, (mqk,1)) for mqk in mq ] for k in range(len(mq)): base.gemv(Gq[k], x, sq[k], alpha = -1.0, beta = 1.0) # rz = s + G*x rz = matrix( [sl] + [sqk for sqk in sq]) base.gemv(Gl, x, rz, beta = 1.0) ind = ml for k in range(len(mq)): base.gemv(Gq[k], x, rz, beta = 1.0, offsety = ind) ind += mq[k] resz = blas.nrm2(rz) / resz0 dims = {'l': ml, 's': [], 'q': mq} s = matrix(0.0, (N,1)) blas.copy(sl, s) ind = ml for k in range(len(mq)): blas.copy(sq[k], s, offsety = ind) ind += mq[k] pslack = -misc.max_step(s, dims) dslack = None pres, dres = None, None dinfres, pinfres = resz, None z, y = None, None pcost, dcost = -1.0, None gap, relgap = None, None else: status = 'unknown' sl, sq = None, None zl, zq = None, None x, y = None, None pcost, dcost = None, None gap, relgap = None, None pres, dres = None, None pinfres, dinfres = None, None pslack, dslack = None, None print(status) return {'status': status, 'x': x, 'sl': sl, 'sq': sq, 'y': y, 'zl': zl, 'zq': zq, 'primal objective': pcost, 'dual objective': dcost, 'gap': gap, 'relative gap': relgap, 'primal infeasibility': pres, 'dual infeasibility': dres, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': dinfres, 'primal slack': pslack, 'dual slack': dslack} h = matrix(0.0, (N,1)) if type(Gl) is matrix or [ Gk for Gk in Gq if type(Gk) is matrix ]: G = matrix(0.0, (N, n)) else: G = spmatrix([], [], [], (N, n), 'd') h[:ml] = hl G[:ml,:] = Gl ind = ml for k in range(len(mq)): h[ind : ind + mq[k]] = hq[k] G[ind : ind + mq[k], :] = Gq[k] ind += mq[k] if primalstart: ps = {} ps['x'] = primalstart['x'] ps['s'] = matrix(0.0, (N,1)) if ml: ps['s'][:ml] = primalstart['sl'] if mq: ind = ml for k in range(len(mq)): ps['s'][ind : ind + mq[k]] = primalstart['sq'][k][:] ind += mq[k] else: ps = None if dualstart: ds = {} if p: ds['y'] = dualstart['y'] ds['z'] = matrix(0.0, (N,1)) if ml: ds['z'][:ml] = dualstart['zl'] if mq: ind = ml for k in range(len(mq)): ds['z'][ind : ind + mq[k]] = dualstart['zq'][k][:] ind += mq[k] else: ds = None sol = conelp(c, G, h, dims, A = A, b = b, primalstart = ps, dualstart = ds) if sol['s'] is None: sol['sl'] = None sol['sq'] = None else: sol['sl'] = sol['s'][:ml] sol['sq'] = [ matrix(0.0, (m,1)) for m in mq ] ind = ml for k in range(len(mq)): sol['sq'][k][:] = sol['s'][ind : ind+mq[k]] ind += mq[k] del sol['s'] if sol['z'] is None: sol['zl'] = None sol['zq'] = None else: sol['zl'] = sol['z'][:ml] sol['zq'] = [ matrix(0.0, (m,1)) for m in mq] ind = ml for k in range(len(mq)): sol['zq'][k][:] = sol['z'][ind : ind+mq[k]] ind += mq[k] del sol['z'] return sol def sdp(c, Gl = None, hl = None, Gs = None, hs = None, A = None, b = None, solver = None, primalstart = None, dualstart = None): """ Solves a pair of primal and dual SDPs minimize c'*x subject to Gl*x + sl = hl mat(Gs[k]*x) + ss[k] = hs[k], k = 0, ..., N-1 A*x = b sl >= 0, ss[k] >= 0, k = 0, ..., N-1 maximize -hl'*z - sum_k trace(hs[k]*zs[k]) - b'*y subject to Gl'*zl + sum_k Gs[k]'*vec(zs[k]) + A'*y + c = 0 zl >= 0, zs[k] >= 0, k = 0, ..., N-1. The inequalities sl >= 0 and zl >= 0 are elementwise vector inequalities. The inequalities ss[k] >= 0, zs[k] >= 0 are matrix inequalities, i.e., the symmetric matrices ss[k] and zs[k] must be positive semidefinite. mat(Gs[k]*x) is the symmetric matrix X with X[:] = Gs[k]*x. For a symmetric matrix, zs[k], vec(zs[k]) is the vector zs[k][:]. Input arguments. Gl is a dense or sparse 'd' matrix of size (ml, n). hl is a dense 'd' matrix of size (ml, 1). The default values of Gl and hl are matrices with zero rows. The argument Gs is a list of N dense or sparse 'd' matrices of size (m[k]**2, n), k = 0, ..., N-1. The columns of Gs[k] represent symmetric matrices stored as vectors in column major order. hs is a list of N dense 'd' matrices of size (m[k], m[k]), k = 0, ..., N-1. The columns of Gs[k] and the matrices hs[k] represent symmetric matrices in 'L' storage, i.e., only the lower triangular elements are accessed. The default values of Gs and hs are empty lists. A is a dense or sparse 'd' matrix of size (p,n). b is a dense 'd' matrix of size (p,1). The default values of A and b are matrices with zero rows. solver is None or 'dsdp'. The default solver (None) calls cvxopt.conelp(). The 'dsdp' solver uses an interface to DSDP5. The 'dsdp' solver does not accept problems with equality constraints (A and b must have zero rows, or be absent). The argument primalstart is a dictionary with keys 'x', 'sl', 'ss', and specifies an optional primal starting point. primalstart['x'] is a dense 'd' matrix of length n; primalstart['sl'] is a positive dense 'd' matrix of length ml; primalstart['ss'] is a list of positive definite matrices of size (ms[k], ms[k]). Only the lower triangular parts of these matrices will be accessed. The argument dualstart is a dictionary with keys 'zl', 'zs', 'y' and specifies an optional dual starting point. dualstart['y'] is a dense 'd' matrix of length p; dualstart['zl'] must be a positive dense 'd' matrix of length ml; dualstart['zs'] is a list of positive definite matrices of size (ms[k], ms[k]). Only the lower triangular parts of these matrices will be accessed. The arguments primalstart and dualstart are ignored when solver is 'dsdp'. Output arguments. Returns a dictionary with keys 'status', 'x', 'sl', 'ss', 'zl', 'zs', 'y', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility', 'dual infeasibility', 'primal slack', 'dual slack', 'residual as primal infeasibility certificate', 'residual as dual infeasibility certificate'. The 'status' field has values 'optimal', 'primal infeasible', 'dual infeasible', or 'unknown'. The values of the other fields depend on the exit status and the solver used. Status 'optimal'. - 'x', 'sl', 'ss', 'y', 'zl', 'zs' are an approximate solution of the primal and dual optimality conditions G*x + s = h, A*x = b G'*z + A'*y + c = 0 s >= 0, z >= 0 s'*z = 0 where G = [ Gl; Gs[0][:]; ...; Gs[N-1][:] ] h = [ hl; hs[0][:]; ...; hs[N-1][:] ] s = [ sl; ss[0][:]; ...; ss[N-1][:] ] z = [ zl; zs[0][:]; ...; zs[N-1][:] ]. - 'primal objective': the primal objective c'*x. - 'dual objective': the dual objective -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal objective is negative, s'*z / -(h'*z + b'*y) if the dual objective is positive, and None otherwise. - 'primal infeasibility': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack, min( min_k sl_k, min_k lambda_min(mat(ss[k])) ). - 'dual slack': the smallest dual slack, min( min_k zl_k, min_k lambda_min(mat(zs[k])) ). - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate': None. If the default solver is used, the primal infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The dual infeasibility is guaranteed to be less than solvers.options['feastol'] (default 1e-7). The gap is less than solvers.options['abstol'] (default 1e-7) or the relative gap is less than solvers.options['reltol'] (default 1e-6). If the DSDP solver is used, the default DSDP exit criteria apply. Status 'primal infeasible'. - 'x', 'sl', 'ss': None. - 'y', 'zl', 'zs' are an approximate certificate of infeasibility -h'*z - b'*y = 1, G'*z + A'*y = 0, z >= 0. - 'primal objective': None. - 'dual objective': 1.0. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': None - 'dual slack': the smallest dual slack, min( min_k zl_k, min_k lambda_min(mat(zs[k])) ). - 'residual as primal infeasibility certificate': the residual in the condition of the infeasibility certificate, defined as || G'*z + A'*y || / max(1, ||c||). - 'residual as dual infeasibility certificate': None. If the default solver is used, the residual as primal infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). If the DSDP solver is used, the default DSDP exit criteria apply. Status 'dual infeasible'. - 'x', 'sl', 'ss': an approximate proof of dual infeasibility c'*x = -1, G*x + s = 0, A*x = 0, s >= 0. - 'y', 'zl', 'zs': None. - 'primal objective': -1.0. - 'dual objective': None. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': the smallest primal slack, min( min_k sl_k, min_k lambda_min(mat(ss[k])) ). - 'dual slack': None. - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate: the residual in the conditions of the infeasibility certificate, defined as the maximum of || G*x + s || / max(1, ||h||) and || A*x || / max(1, ||b||). If the default solver is used, the residual as dual infeasiblity certificate is guaranteed to be less than solvers.options['feastol'] (default 1e-7). If the MOSEK solver is used, the default MOSEK exit criteria apply. Status 'unknown'. If the DSDP solver is used, all the fields except the status field are empty. If the default solver is used, the values are as follows. - 'x', 'y', 'sl', 'ss', 'zl', 'zs': the last iterates before termination. These satisfy s > 0 and z > 0, but are not necessarily feasible. - 'primal objective': the primal cost c'*x. - 'dual objective': the dual cost -h'*z - b'*y. - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as s'*z / -c'*x if the primal cost is negative, s'*z / -(h'*z + b'*y) if the dual cost is positive, and None otherwise. - 'primal infeasibility ': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || G'*z + A'*y + c || / max(1, ||c||). - 'primal slack': the smallest primal slack, min( min_k sl_k, min_k lambda_min(mat(ss[k])) ). - 'dual slack': the smallest dual slack, min( min_k zl_k, min_k lambda_min(mat(zs[k])) ). - 'residual as primal infeasibility certificate': None if h'*z + b'*y >= 0; the residual || G'*z + A'*y || / (-(h'*z + b'*y) * max(1, ||c||) ) otherwise. - 'residual as dual infeasibility certificate': None if c'*x >= 0; the maximum of the residuals || G*x + s || / (-c'*x * max(1, ||h||)) and || A*x || / (-c'*x * max(1, ||b||)) otherwise. Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, s, z are close to optimal. If the residual as primal infeasibility certificate is small, then y / (-h'*z - b'*y), z / (-h'*z - b'*y) provide an approximate certificate of primal infeasibility. If the residual as certificate of dual infeasibility is small, then x / (-c'*x), s / (-c'*x) provide an approximate proof of dual infeasibility. Control parameters. The following parameters control the execution of the default solver. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] positive integer (default: 1) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). The execution of the 'dsdp' solver is controlled by: options['DSDP_Monitor'] integer (default: 0) options['DSDP_MaxIts'] positive integer options['DSDP_GapTolerance'] scalar (default: 1e-5). """ import math from cvxopt import base, blas, misc from cvxopt.base import matrix, spmatrix if type(c) is not matrix or c.typecode != 'd' or c.size[1] != 1: raise TypeError("'c' must be a dense column matrix") n = c.size[0] if n < 1: raise ValueError("number of variables must be at least 1") if Gl is None: Gl = spmatrix([], [], [], (0,n), tc='d') if (type(Gl) is not matrix and type(Gl) is not spmatrix) or \ Gl.typecode != 'd' or Gl.size[1] != n: raise TypeError("'Gl' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) ml = Gl.size[0] if hl is None: hl = matrix(0.0, (0,1)) if type(hl) is not matrix or hl.typecode != 'd' or \ hl.size != (ml,1): raise TypeError("'hl' must be a 'd' matrix of size (%d,1)" %ml) if Gs is None: Gs = [] if type(Gs) is not list or [ G for G in Gs if (type(G) is not matrix and type(G) is not spmatrix) or G.typecode != 'd' or G.size[1] != n ]: raise TypeError("'Gs' must be a list of sparse or dense 'd' "\ "matrices with %d columns" %n) ms = [ int(math.sqrt(G.size[0])) for G in Gs ] a = [ k for k in range(len(ms)) if ms[k]**2 != Gs[k].size[0] ] if a: raise TypeError("the squareroot of the number of rows in "\ "'Gs[%d]' is not an integer" %k) if hs is None: hs = [] if type(hs) is not list or len(hs) != len(ms) or [ h for h in hs if (type(h) is not matrix and type(h) is not spmatrix) or h.typecode != 'd' ]: raise TypeError("'hs' must be a list of %d dense or sparse "\ "'d' matrices" %len(ms)) a = [ k for k in range(len(ms)) if hs[k].size != (ms[k],ms[k]) ] if a: k = a[0] raise TypeError("hs[%d] has size (%d,%d). Expected size is "\ "(%d,%d)." %(k,hs[k].size[0], hs[k].size[1], ms[k], ms[k])) if A is None: A = spmatrix([], [], [], (0,n), 'd') if (type(A) is not matrix and type(A) is not spmatrix) or \ A.typecode != 'd' or A.size[1] != n: raise TypeError("'A' must be a dense or sparse 'd' matrix "\ "with %d columns" %n) p = A.size[0] if b is None: b = matrix(0.0, (0,1)) if type(b) is not matrix or b.typecode != 'd' or b.size != (p,1): raise TypeError("'b' must be a dense matrix of size (%d,1)" %p) dims = {'l': ml, 'q': [], 's': ms} N = ml + sum([ m**2 for m in ms ]) if solver == 'dsdp': try: from cvxopt import dsdp except ImportError: raise ValueError("invalid option "\ "(solver = 'dsdp'): cvxopt.dsdp is not installed") dsdp.options = options if p: raise ValueError("sdp() with the solver = 'dsdp' option "\ "does not handle problems with equality constraints") dsdpstatus, x, r, zl, zs = dsdp.sdp(c, Gl, hl, Gs, hs) resx0 = max(1.0, blas.nrm2(c)) rh = matrix([ blas.nrm2(hl) ] + [ math.sqrt(misc.sdot2(hsk, hsk)) for hsk in hs ]) resz0 = max(1.0, blas.nrm2(rh)) if dsdpstatus == 'DSDP_UNBOUNDED': status = 'dual infeasible' cx = blas.dot(c,x) blas.scal(-1.0/cx, x) sl = -Gl*x ss = [ -matrix(Gs[k]*x, (ms[k], ms[k])) for k in range(len(ms)) ] for k in range(len(ms)): misc.symm(ss[k], ms[k]) # rz = s + G*x rz = matrix( [sl] + [ssk[:] for ssk in ss]) base.gemv(Gl, x, rz, beta = 1.0) ind = ml for k in range(len(ms)): base.gemv(Gs[k], x, rz, beta = 1.0, offsety = ind) ind += ms[k]**2 dims = {'l': ml, 's': ms, 'q': []} resz = misc.nrm2(rz, dims) / resz0 s = matrix(0.0, (N,1)) blas.copy(sl, s) ind = ml for k in range(len(ms)): blas.copy(ss[k], s, offsety = ind) ind += ms[k] pslack = -misc.max_step(s, dims) sslack = None pres, dres = None, None dinfres, pinfres = resz, None zl, zs, y = None, None, None pcost, dcost = -1.0, None gap, relgap = None, None elif dsdpstatus == 'DSDP_INFEASIBLE': status = 'primal infeasible' y = matrix(0.0, (0,1)) hz = blas.dot(hl, zl) + misc.sdot2(hs, zs) blas.scal(1.0 / -hz, zl) for k in range(len(ms)): blas.scal(1.0 / -hz, zs[k]) misc.symm(zs[k], ms[k]) # rx = -G'*z rx = matrix(0.0, (n,1)) base.gemv(Gl, zl, rx, alpha = -1.0, beta = 1.0, trans = 'T') ind = 0 for k in range(len(ms)): blas.scal(0.5, zs[k], inc=ms[k]+1) for j in range(ms[k]): blas.scal(0.0, zs[k], offset=j+ms[k]*(j+1), inc=ms[k]) base.gemv(Gs[k], zs[k], rx, alpha=2.0, beta=1.0, trans='T') blas.scal(2.0, zs[k], inc=ms[k]+1) ind += ms[k] pinfres = blas.nrm2(rx) / resx0 dinfres = None z = matrix(0.0, (N,1)) blas.copy(zl, z) ind = ml for k in range(len(ms)): blas.copy(zs[k], z, offsety = ind) ind += ms[k] dslack = -misc.max_step(z, dims) pslack = None x, sl, ss = None, None, None pres, dres = None, None pcost, dcost = None, 1.0 gap, relgap = None, None else: if dsdpstatus == 'DSDP_PDFEASIBLE': status = 'optimal' else: status = 'unknown' y = matrix(0.0, (0,1)) sl = hl - Gl*x ss = [ hs[k] - matrix(Gs[k]*x, (ms[k], ms[k])) for k in range(len(ms)) ] for k in range(len(ms)): misc.symm(ss[k], ms[k]) misc.symm(zs[k], ms[k]) pcost = blas.dot(c,x) dcost = -blas.dot(hl,zl) - misc.sdot2(hs, zs) gap = blas.dot(sl, zl) + misc.sdot2(ss, zs) if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None # rx = c + G'*z rx = matrix(c) base.gemv(Gl, zl, rx, beta = 1.0, trans = 'T') ind = 0 for k in range(len(ms)): blas.scal(0.5, zs[k], inc = ms[k]+1) for j in range(ms[k]): blas.scal(0.0, zs[k], offset=j+ms[k]*(j+1), inc=ms[k]) base.gemv(Gs[k], zs[k], rx, alpha=2.0, beta=1.0, trans='T') blas.scal(2.0, zs[k], inc=ms[k]+1) ind += ms[k] resx = blas.nrm2(rx) / resx0 # rz = G*x + s - h rz = matrix(0.0, (ml + sum([msk**2 for msk in ms]), 1)) base.gemv(Gl, x, rz) blas.axpy(sl, rz) blas.axpy(hl, rz, alpha = -1.0) ind = ml for k in range(len(ms)): base.gemv(Gs[k], x, rz, offsety = ind) blas.axpy(ss[k], rz, offsety = ind, n = ms[k]**2) blas.axpy(hs[k], rz, alpha = -1.0, offsety = ind, n = ms[k]**2) ind += ms[k]**2 resz = misc.snrm2(rz, dims) / resz0 pres, dres = resz, resx s, z = matrix(0.0, (N,1)), matrix(0.0, (N,1)) blas.copy(sl, s) blas.copy(zl, z) ind = ml for k in range(len(ms)): blas.copy(ss[k], s, offsety = ind) blas.copy(zs[k], z, offsety = ind) ind += ms[k] pslack = -misc.max_step(s, dims) dslack = -misc.max_step(z, dims) if status is 'optimal' or dcost <= 0.0: pinfres = None else: # rx = G'*z rx = matrix(0.0, (n,1)) base.gemv(Gl, zl, rx, beta = 1.0, trans = 'T') ind = 0 for k in range(len(ms)): blas.scal(0.5, zs[k], inc = ms[k]+1) for j in range(ms[k]): blas.scal(0.0, zs[k], offset=j+ms[k]*(j+1), inc=ms[k]) base.gemv(Gs[k], zs[k], rx, alpha=2.0, beta=1.0, trans='T') blas.scal(2.0, zs[k], inc=ms[k]+1) ind += ms[k] pinfres = blas.nrm2(rx) / resx0 / dcost if status is 'optimal' or pcost >= 0.0: dinfres = None else: # rz = G*x + s rz = matrix(0.0, (ml + sum([msk**2 for msk in ms]), 1)) base.gemv(Gl, x, rz) blas.axpy(sl, rz) ind = ml for k in range(len(ms)): base.gemv(Gs[k], x, rz, offsety = ind) blas.axpy(ss[k], rz, offsety = ind, n = ms[k]**2) ind += ms[k]**2 dims = {'l': ml, 's': ms, 'q': []} dinfres = misc.snrm2(rz, dims) / resz0 / -pcost return {'status': status, 'x': x, 'sl': sl, 'ss': ss, 'y': y, 'zl': zl, 'zs': zs, 'primal objective': pcost, 'dual objective': dcost, 'gap': gap, 'relative gap': relgap, 'primal infeasibility': pres, 'dual infeasibility': dres, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': dinfres, 'primal slack': pslack, 'dual slack': dslack} h = matrix(0.0, (N,1)) if type(Gl) is matrix or [ Gk for Gk in Gs if type(Gk) is matrix ]: G = matrix(0.0, (N, n)) else: G = spmatrix([], [], [], (N, n), 'd') h[:ml] = hl G[:ml,:] = Gl ind = ml for k in range(len(ms)): m = ms[k] h[ind : ind + m*m] = hs[k][:] G[ind : ind + m*m, :] = Gs[k] ind += m**2 if primalstart: ps = {} ps['x'] = primalstart['x'] ps['s'] = matrix(0.0, (N,1)) if ml: ps['s'][:ml] = primalstart['sl'] if ms: ind = ml for k in range(len(ms)): m = ms[k] ps['s'][ind : ind + m*m] = primalstart['ss'][k][:] ind += m**2 else: ps = None if dualstart: ds = {} if p: ds['y'] = dualstart['y'] ds['z'] = matrix(0.0, (N,1)) if ml: ds['z'][:ml] = dualstart['zl'] if ms: ind = ml for k in range(len(ms)): m = ms[k] ds['z'][ind : ind + m*m] = dualstart['zs'][k][:] ind += m**2 else: ds = None sol = conelp(c, G, h, dims, A = A, b = b, primalstart = ps, dualstart = ds) if sol['s'] is None: sol['sl'] = None sol['ss'] = None else: sol['sl'] = sol['s'][:ml] sol['ss'] = [ matrix(0.0, (mk, mk)) for mk in ms ] ind = ml for k in range(len(ms)): m = ms[k] sol['ss'][k][:] = sol['s'][ind:ind+m*m] ind += m**2 del sol['s'] if sol['z'] is None: sol['zl'] = None sol['zs'] = None else: sol['zl'] = sol['z'][:ml] sol['zs'] = [ matrix(0.0, (mk, mk)) for mk in ms ] ind = ml for k in range(len(ms)): m = ms[k] sol['zs'][k][:] = sol['z'][ind:ind+m*m] ind += m**2 del sol['z'] return sol def qp(P, q, G = None, h = None, A = None, b = None, solver = None, initvals = None): """ Solves a quadratic program minimize (1/2)*x'*P*x + q'*x subject to G*x <= h A*x = b. Input arguments. P is a n x n dense or sparse 'd' matrix with the lower triangular part of P stored in the lower triangle. Must be positive semidefinite. q is an n x 1 dense 'd' matrix. G is an m x n dense or sparse 'd' matrix. h is an m x 1 dense 'd' matrix. A is a p x n dense or sparse 'd' matrix. b is a p x 1 dense 'd' matrix or None. solver is None or 'mosek'. The default values for G, h, A and b are empty matrices with zero rows. Output arguments (default solver). Returns a dictionary with keys 'status', 'x', 's', 'y', 'z', 'primal objective', 'dual objective', 'gap', 'relative gap', 'primal infeasibility, 'dual infeasibility', 'primal slack', 'dual slack'. The 'status' field has values 'optimal' or 'unknown'. If the status is 'optimal', 'x', 's', 'y', 'z' are an approximate solution of the primal and dual optimal solutions G*x + s = h, A*x = b P*x + G'*z + A'*y + q = 0 s >= 0, z >= 0 s'*z = o. If the status is 'unknown', 'x', 's', 'y', 'z' are the last iterates before termination. These satisfy s > 0 and z > 0, but are not necessarily feasible. The values of the other fields are defined as follows. - 'primal objective': the primal objective (1/2)*x'*P*x + q'*x. - 'dual objective': the dual objective L(x,y,z) = (1/2)*x'*P*x + q'*x + z'*(G*x - h) + y'*(A*x-b). - 'gap': the duality gap s'*z. - 'relative gap': the relative gap, defined as gap / -primal objective if the primal objective is negative, gap / dual objective if the dual objective is positive, and None otherwise. - 'primal infeasibility': the residual in the primal constraints, defined as the maximum of the residual in the inequalities || G*x + s + h || / max(1, ||h||) and the residual in the equalities || A*x - b || / max(1, ||b||). - 'dual infeasibility': the residual in the dual constraints, defined as || P*x + G'*z + A'*y + q || / max(1, ||q||). - 'primal slack': the smallest primal slack, min_k s_k. - 'dual slack': the smallest dual slack, min_k z_k. If the exit status is 'optimal', then the primal and dual infeasibilities are guaranteed to be less than solvers.options['feastol'] (default 1e-7). The gap is less than solvers.options['abstol'] (default 1e-7) or the relative gap is less than solvers.options['reltol'] (default 1e-6). Termination with status 'unknown' indicates that the algorithm failed to find a solution that satisfies the specified tolerances. In some cases, the returned solution may be fairly accurate. If the primal and dual infeasibilities, the gap, and the relative gap are small, then x, y, s, z are close to optimal. Output arguments (MOSEK solver). The return dictionary has two additional fields 'residual as primal infeasibility certificate' and 'residual as dual infeasibility certificate', and 'status' field can also have the values 'primal infeasible' or 'dual infeasible'. If the exit status is 'optimal', the different fields have the same meaning as for the default solver, but the the magnitude of the residuals and duality gap is controlled by the MOSEK exit criteria. The 'residual as primal infeasibility certificate' and 'residual as dual infeasibility certificate' are None. Status 'primal infeasible'. - 'x', 's': None. - 'y', 'z' are an approximate certificate of infeasibility G'*z + A'*y = 0, h'*z + b'*y = -1, z >= 0. - 'primal objective': None. - 'dual objective': 1.0. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': None. - 'dual slack': the smallest dual slack min z_k. - 'residual as primal infeasibility certificate': the residual in the condition of the infeasibility certificate, defined as || G'*z + A'*y || / max(1, ||c||). - 'residual as dual infeasibility certificate': None. Status 'dual infeasible'. - 'x', 's' are an approximate proof of dual infeasibility P*x = 0, q'*x = -1, G*x + s = 0, A*x = 0, s >= 0. - 'y', 'z': None. - 'primal objective': -1.0. - 'dual objective': None. - 'gap', 'relative gap': None. - 'primal infeasibility' and 'dual infeasibility': None. - 'primal slack': the smallest primal slack min_k s_k . - 'dual slack': None. - 'residual as primal infeasibility certificate': None. - 'residual as dual infeasibility certificate: the residual in the conditions of the infeasibility certificate, defined as the maximum of || P*x || / max(1, ||q||), || G*x + s || / max(1, ||h||), || A*x || / max(1, ||b||). If status is 'unknown', all the other fields are None. Control parameters. The control parameters for the different solvers can be modified by adding an entry to the dictionary cvxopt.solvers.options. The following parameters control the execution of the default solver. options['show_progress'] True/False (default: True) options['maxiters'] positive integer (default: 100) options['refinement'] positive integer (default: 0) options['abstol'] scalar (default: 1e-7) options['reltol'] scalar (default: 1e-6) options['feastol'] scalar (default: 1e-7). The MOSEK parameters can me modified by adding an entry options['MOSEK'], containing a dictionary with MOSEK parameter/value pairs, as described in the MOSEK documentation. Options that are not recognized are replaced by their default values. """ from cvxopt import base, blas from cvxopt.base import matrix, spmatrix if solver == 'mosek': from cvxopt import misc try: from cvxopt import msk import mosek except ImportError: raise ValueError("invalid option "\ "(solver='mosek'): cvxopt.msk is not installed") if 'MOSEK' in options: msk.options = options['MOSEK'] else: msk.options = {} solsta, x, z, y = msk.qp(P, q, G, h, A, b) n = q.size[0] if G is None: G = spmatrix([], [], [], (0,n), 'd') if h is None: h = matrix(0.0, (0,1)) if A is None: A = spmatrix([], [], [], (0,n), 'd') if b is None: b = matrix(0.0, (0,1)) m = G.size[0] resx0 = max(1.0, blas.nrm2(q)) resy0 = max(1.0, blas.nrm2(b)) resz0 = max(1.0, blas.nrm2(h)) if solsta == mosek.solsta.optimal: status = 'optimal' s = matrix(h) base.gemv(G, x, s, alpha = -1.0, beta = 1.0) # rx = q + P*x + G'*z + A'*y # pcost = 0.5 * x'*P*x + q'*x rx = matrix(q) base.symv(P, x, rx, beta = 1.0) pcost = 0.5 * (blas.dot(x, rx) + blas.dot(x, q)) base.gemv(A, y, rx, beta = 1.0, trans = 'T') base.gemv(G, z, rx, beta = 1.0, trans = 'T') resx = blas.nrm2(rx) / resx0 # ry = A*x - b ry = matrix(b) base.gemv(A, x, ry, alpha = 1.0, beta = -1.0) resy = blas.nrm2(ry) / resy0 # rz = G*x + s - h rz = matrix(0.0, (m,1)) base.gemv(G, x, rz) blas.axpy(s, rz) blas.axpy(h, rz, alpha = -1.0) resz = blas.nrm2(rz) / resz0 gap = blas.dot(s, z) dcost = pcost + blas.dot(y, ry) + blas.dot(z, rz) - gap if pcost < 0.0: relgap = gap / -pcost elif dcost > 0.0: relgap = gap / dcost else: relgap = None dims = {'l': m, 's': [], 'q': []} pslack = -misc.max_step(s, dims) dslack = -misc.max_step(z, dims) pres, dres = max(resy, resz), resx pinfres, dinfres = None, None elif solsta == mosek.solsta.prim_infeas_cer: status = 'primal infeasible' hz, by = blas.dot(h, z), blas.dot(b, y) blas.scal(1.0 / (-hz - by), y) blas.scal(1.0 / (-hz - by), z) # rx = -A'*y - G'*z rx = matrix(0.0, (q.size[0],1)) base.gemv(A, y, rx, alpha = -1.0, trans = 'T') base.gemv(G, z, rx, alpha = -1.0, beta = 1.0, trans = 'T') pinfres = blas.nrm2(rx) / resx0 dinfres = None x, s = None, None pres, dres = None, None pcost, dcost = None, 1.0 gap, relgap = None, None dims = {'l': m, 's': [], 'q': []} dslack = -misc.max_step(z, dims) pslack = None elif solsta == mosek.solsta.dual_infeas_cer: status = 'dual infeasible' qx = blas.dot(q,x) blas.scal(-1.0/qx, x) s = matrix(0.0, (m,1)) base.gemv(G, x, s, alpha=-1.0) z, y = None, None # rz = P*x rx = matrix(0.0, (q.size[0],1)) base.symv(P, x, rx, beta = 1.0) resx = blas.nrm2(rx) / resx0 # ry = A*x ry = matrix(0.0, (b.size[0],1)) base.gemv(A, x, ry) resy = blas.nrm2(ry) / resy0 # rz = s + G*x rz = matrix(s) base.gemv(G, x, rz, beta = 1.0) resz = blas.nrm2(rz) / resz0 pres, dres = None, None dinfres, pinfres = max(resx, resy, resz), None z, y = None, None pcost, dcost = -1.0, None gap, relgap = None, None dims = {'l': m, 's': [], 'q': []} pslack = -misc.max_step(s, dims) dslack = None else: status = 'unknown' x, s, y, z = None, None, None, None pcost, dcost = None, None gap, relgap = None, None pres, dres = None, None pslack, dslack = None, None pinfres, dinfres = None, None return {'status': status, 'x': x, 's': s, 'y': y, 'z': z, 'primal objective': pcost, 'dual objective': dcost, 'gap': gap, 'relative gap': relgap, 'primal infeasibility': pres, 'dual infeasibility': dres, 'primal slack': pslack, 'dual slack': dslack, 'residual as primal infeasibility certificate': pinfres, 'residual as dual infeasibility certificate': dinfres} return coneqp(P, q, G, h, None, A, b, initvals) cvxopt-1.1.4/src/C/0000755000175000017500000000000011674452555013055 5ustar sonnesonnecvxopt-1.1.4/src/C/lapack.c0000644000175000017500000102503411674452733014457 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Python.h" #include "cvxopt.h" #include "misc.h" #define err_lapack { PyErr_SetObject( (info < 0) ? PyExc_ValueError :\ PyExc_ArithmeticError, Py_BuildValue("i",info) ); \ return NULL;} PyDoc_STRVAR(lapack__doc__, "Interface to the LAPACK library.\n\n" "Double-precision real and complex LAPACK routines for solving sets of\n" "linear equations, linear least-squares and least-norm problems,\n" "symmetric and Hermitian eigenvalue problems, singular value \n" "decomposition, and Schur factorization.\n\n" "For more details, see the LAPACK Users' Guide at \n" "www.netlib.org/lapack/lug/lapack_lug.html.\n\n" "Double and complex matrices and vectors are stored in CVXOPT matrices\n" "using the conventional BLAS storage schemes, with the CVXOPT matrix\n" "buffers interpreted as one-dimensional arrays. For each matrix \n" "argument X, an additional integer argument offsetX specifies the start\n" "of the array, i.e., the pointer X->buffer + offsetX is passed to the\n" "LAPACK function. The other arguments (dimensions and options) have the\n" "same meaning as in the LAPACK definition. Default values of the\n" "dimension arguments are derived from the CVXOPT matrix sizes.\n\n" "If a routine from the LAPACK library returns with a positive 'info'\n" "value, an ArithmeticError is raised. If it returns with a negative\n" "'info' value, a ValueError is raised. In both cases the value of \n" "'info' is returned as an argument to the exception."); /* LAPACK prototypes */ extern int ilaenv_(int *ispec, char **name, char **opts, int *n1, int *n2, int *n3, int *n4); extern void dlacpy_(char *uplo, int *m, int *n, double *A, int *lda, double *B, int *ldb); extern void zlacpy_(char *uplo, int *m, int *n, complex *A, int *lda, complex *B, int *ldb); extern void dgetrf_(int *m, int *n, double *A, int *lda, int *ipiv, int *info); extern void zgetrf_(int *m, int *n, complex *A, int *lda, int *ipiv, int *info); extern void dgetrs_(char *trans, int *n, int *nrhs, double *A, int *lda, int *ipiv, double *B, int *ldb, int *info); extern void zgetrs_(char *trans, int *n, int *nrhs, complex *A, int *lda, int *ipiv, complex *B, int *ldb, int *info); extern void dgetri_(int *n, double *A, int *lda, int *ipiv, double *work, int *lwork, int *info); extern void zgetri_(int *n, complex *A, int *lda, int *ipiv, complex *work, int *lwork, int *info); extern void dgesv_(int *n, int *nrhs, double *A, int *lda, int *ipiv, double *B, int *ldb, int *info); extern void zgesv_(int *n, int *nrhs, complex *A, int *lda, int *ipiv, complex *B, int *ldb, int *info); extern void dgbtrf_(int *m, int *n, int *kl, int *ku, double *AB, int *ldab, int *ipiv, int *info); extern void zgbtrf_(int *m, int *n, int *kl, int *ku, complex *AB, int *ldab, int *ipiv, int *info); extern void dgbtrs_(char *trans, int *n, int *kl, int *ku, int *nrhs, double *AB, int *ldab, int *ipiv, double *B, int *ldB, int *info); extern void zgbtrs_(char *trans, int *n, int *kl, int *ku, int *nrhs, complex *AB, int *ldab, int *ipiv, complex *B, int *ldB, int *info); extern void dgbsv_(int *n, int *kl, int *ku, int *nrhs, double *ab, int *ldab, int *ipiv, double *b, int *ldb, int *info); extern void zgbsv_(int *n, int *kl, int *ku, int *nrhs, complex *ab, int *ldab, int *ipiv, complex *b, int *ldb, int *info); extern void dgttrf_(int *n, double *dl, double *d, double *du, double *du2, int *ipiv, int *info); extern void zgttrf_(int *n, complex *dl, complex *d, complex *du, complex *du2, int *ipiv, int *info); extern void dgttrs_(char *trans, int *n, int *nrhs, double *dl, double *d, double *du, double *du2, int *ipiv, double *B, int *ldB, int *info); extern void zgttrs_(char *trans, int *n, int *nrhs, complex *dl, complex *d, complex *du, complex *du2, int *ipiv, complex *B, int *ldB, int *info); extern void dgtsv_(int *n, int *nrhs, double *dl, double *d, double *du, double *B, int *ldB, int *info); extern void zgtsv_(int *n, int *nrhs, complex *dl, complex *d, complex *du, complex *B, int *ldB, int *info); extern void dpotrf_(char *uplo, int *n, double *A, int *lda, int *info); extern void zpotrf_(char *uplo, int *n, complex *A, int *lda, int *info); extern void dpotrs_(char *uplo, int *n, int *nrhs, double *A, int *lda, double *B, int *ldb, int *info); extern void zpotrs_(char *uplo, int *n, int *nrhs, complex *A, int *lda, complex *B, int *ldb, int *info); extern void dpotri_(char *uplo, int *n, double *A, int *lda, int *info); extern void zpotri_(char *uplo, int *n, complex *A, int *lda, int *info); extern void dposv_(char *uplo, int *n, int *nrhs, double *A, int *lda, double *B, int *ldb, int *info); extern void zposv_(char *uplo, int *n, int *nrhs, complex *A, int *lda, complex *B, int *ldb, int *info); extern void dpbtrf_(char *uplo, int *n, int *kd, double *AB, int *ldab, int *info); extern void zpbtrf_(char *uplo, int *n, int *kd, complex *AB, int *ldab, int *info); extern void dpbtrs_(char *uplo, int *n, int *kd, int *nrhs, double *AB, int *ldab, double *B, int *ldb, int *info); extern void zpbtrs_(char *uplo, int *n, int *kd, int *nrhs, complex *AB, int *ldab, complex *B, int *ldb, int *info); extern void dpbsv_(char *uplo, int *n, int *kd, int *nrhs, double *A, int *lda, double *B, int *ldb, int *info); extern void zpbsv_(char *uplo, int *n, int *kd, int *nrhs, complex *A, int *lda, complex *B, int *ldb, int *info); extern void dpttrf_(int *n, double *d, double *e, int *info); extern void zpttrf_(int *n, double *d, complex *e, int *info); extern void dpttrs_(int *n, int *nrhs, double *d, double *e, double *B, int *ldB, int *info); extern void zpttrs_(char *uplo, int *n, int *nrhs, double *d, complex *e, complex *B, int *ldB, int *info); extern void dptsv_(int *n, int *nrhs, double *d, double *e, double *B, int *ldB, int *info); extern void zptsv_(int *n, int *nrhs, double *d, complex *e, complex *B, int *ldB, int *info); extern void dsytrf_(char *uplo, int *n, double *A, int *lda, int *ipiv, double *work, int *lwork, int *info); extern void zsytrf_(char *uplo, int *n, complex *A, int *lda, int *ipiv, complex *work, int *lwork, int *info); extern void zhetrf_(char *uplo, int *n, complex *A, int *lda, int *ipiv, complex *work, int *lwork, int *info); extern void dsytrs_(char *uplo, int *n, int *nrhs, double *A, int *lda, int *ipiv, double *B, int *ldb, int *info); extern void zsytrs_(char *uplo, int *n, int *nrhs, complex *A, int *lda, int *ipiv, complex *B, int *ldb, int *info); extern void zhetrs_(char *uplo, int *n, int *nrhs, complex *A, int *lda, int *ipiv, complex *B, int *ldb, int *info); extern void dsytri_(char *uplo, int *n, double *A, int *lda, int *ipiv, double *work, int *info); extern void zsytri_(char *uplo, int *n, complex *A, int *lda, int *ipiv, complex *work, int *info); extern void zhetri_(char *uplo, int *n, complex *A, int *lda, int *ipiv, complex *work, int *info); extern void dsysv_(char *uplo, int *n, int *nrhs, double *A, int *lda, int *ipiv, double *B, int *ldb, double *work, int *lwork, int *info); extern void zsysv_(char *uplo, int *n, int *nrhs, complex *A, int *lda, int *ipiv, complex *B, int *ldb, complex *work, int *lwork, int *info); extern void zhesv_(char *uplo, int *n, int *nrhs, complex *A, int *lda, int *ipiv, complex *B, int *ldb, complex *work, int *lwork, int *info); extern void dtrtrs_(char *uplo, char *trans, char *diag, int *n, int *nrhs, double *a, int *lda, double *b, int *ldb, int *info); extern void ztrtrs_(char *uplo, char *trans, char *diag, int *n, int *nrhs, complex *a, int *lda, complex *b, int *ldb, int *info); extern void dtrtri_(char *uplo, char *diag, int *n, double *a, int *lda, int *info); extern void ztrtri_(char *uplo, char *diag, int *n, complex *a, int *lda, int *info); extern void dtbtrs_(char *uplo, char *trans, char *diag, int *n, int *kd, int *nrhs, double *ab, int *ldab, double *b, int *ldb, int *info); extern void ztbtrs_(char *uplo, char *trans, char *diag, int *n, int *kd, int *nrhs, complex *ab, int *ldab, complex *b, int *ldb, int *info); extern void dgels_(char *trans, int *m, int *n, int *nrhs, double *a, int *lda, double *b, int *ldb, double *work, int *lwork, int *info); extern void zgels_(char *trans, int *m, int *n, int *nrhs, complex *a, int *lda, complex *b, int *ldb, complex *work, int *lwork, int *info); extern void dgeqrf_(int *m, int *n, double *a, int *lda, double *tau, double *work, int *lwork, int *info); extern void zgeqrf_(int *m, int *n, complex *a, int *lda, complex *tau, complex *work, int *lwork, int *info); extern void dormqr_(char *side, char *trans, int *m, int *n, int *k, double *a, int *lda, double *tau, double *c, int *ldc, double *work, int *lwork, int *info); extern void zunmqr_(char *side, char *trans, int *m, int *n, int *k, complex *a, int *lda, complex *tau, complex *c, int *ldc, complex *work, int *lwork, int *info); extern void dorgqr_(int *m, int *n, int *k, double *A, int *lda, double *tau, double *work, int *lwork, int *info); extern void zungqr_(int *m, int *n, int *k, complex *A, int *lda, complex *tau, complex *work, int *lwork, int *info); extern void dorglq_(int *m, int *n, int *k, double *A, int *lda, double *tau, double *work, int *lwork, int *info); extern void zunglq_(int *m, int *n, int *k, complex *A, int *lda, complex *tau, complex *work, int *lwork, int *info); extern void dgelqf_(int *m, int *n, double *a, int *lda, double *tau, double *work, int *lwork, int *info); extern void zgelqf_(int *m, int *n, complex *a, int *lda, complex *tau, complex *work, int *lwork, int *info); extern void dormlq_(char *side, char *trans, int *m, int *n, int *k, double *a, int *lda, double *tau, double *c, int *ldc, double *work, int *lwork, int *info); extern void zunmlq_(char *side, char *trans, int *m, int *n, int *k, complex *a, int *lda, complex *tau, complex *c, int *ldc, complex *work, int *lwork, int *info); extern void dgeqp3_(int *m, int *n, double *a, int *lda, int *jpvt, double *tau, double *work, int *lwork, int *info); extern void zgeqp3_(int *m, int *n, complex *a, int *lda, int *jpvt, complex *tau, complex *work, int *lwork, double *rwork, int *info); extern void dsyev_(char *jobz, char *uplo, int *n, double *A, int *lda, double *W, double *work, int *lwork, int *info); extern void zheev_(char *jobz, char *uplo, int *n, complex *A, int *lda, double *W, complex *work, int *lwork, double *rwork, int *info); extern void dsyevx_(char *jobz, char *range, char *uplo, int *n, double *A, int *lda, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *W, double *Z, int *ldz, double *work, int *lwork, int *iwork, int *ifail, int *info); extern void zheevx_(char *jobz, char *range, char *uplo, int *n, complex *A, int *lda, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *W, complex *Z, int *ldz, complex *work, int *lwork, double *rwork, int *iwork, int *ifail, int *info); extern void dsyevd_(char *jobz, char *uplo, int *n, double *A, int *ldA, double *W, double *work, int *lwork, int *iwork, int *liwork, int *info); extern void zheevd_(char *jobz, char *uplo, int *n, complex *A, int *ldA, double *W, complex *work, int *lwork, double *rwork, int *lrwork, int *iwork, int *liwork, int *info); extern void dsyevr_(char *jobz, char *range, char *uplo, int *n, double *A, int *ldA, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *W, double *Z, int *ldZ, int *isuppz, double *work, int *lwork, int *iwork, int *liwork, int *info); extern void zheevr_(char *jobz, char *range, char *uplo, int *n, complex *A, int *ldA, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *W, complex *Z, int *ldZ, int *isuppz, complex *work, int *lwork, double *rwork, int *lrwork, int *iwork, int *liwork, int *info); extern void dsygv_(int *itype, char *jobz, char *uplo, int *n, double *A, int *lda, double *B, int *ldb, double *W, double *work, int *lwork, int *info); extern void zhegv_(int *itype, char *jobz, char *uplo, int *n, complex *A, int *lda, complex *B, int *ldb, double *W, complex *work, int *lwork, double *rwork, int *info); extern void dgesvd_(char *jobu, char *jobvt, int *m, int *n, double *A, int *ldA, double *S, double *U, int *ldU, double *Vt, int *ldVt, double *work, int *lwork, int *info); extern void dgesdd_(char *jobz, int *m, int *n, double *A, int *ldA, double *S, double *U, int *ldU, double *Vt, int *ldVt, double *work, int *lwork, int *iwork, int *info); extern void zgesvd_(char *jobu, char *jobvt, int *m, int *n, complex *A, int *ldA, double *S, complex *U, int *ldU, complex *Vt, int *ldVt, complex *work, int *lwork, double *rwork, int *info); extern void zgesdd_(char *jobz, int *m, int *n, complex *A, int *ldA, double *S, complex *U, int *ldU, complex *Vt, int *ldVt, complex *work, int *lwork, double *rwork, int *iwork, int *info); extern void dgees_(char *jobvs, char *sort, void *select, int *n, double *A, int *ldA, int *sdim, double *wr, double *wi, double *vs, int *ldvs, double *work, int *lwork, int *bwork, int *info); extern void zgees_(char *jobvs, char *sort, void *select, int *n, complex *A, int *ldA, int *sdim, complex *w, complex *vs, int *ldvs, complex *work, int *lwork, complex *rwork, int *bwork, int *info); extern void dgges_(char *jobvsl, char *jobvsr, char *sort, void *delctg, int *n, double *A, int *ldA, double *B, int *ldB, int *sdim, double *alphar, double *alphai, double *beta, double *vsl, int *ldvsl, double *vsr, int *ldvsr, double *work, int *lwork, int *bwork, int *info); extern void zgges_(char *jobvsl, char *jobvsr, char *sort, void *delctg, int *n, complex *A, int *ldA, complex *B, int *ldB, int *sdim, complex *alpha, complex *beta, complex *vsl, int *ldvsl, complex *vsr, int *ldvsr, complex *work, int *lwork, double *rwork, int *bwork, int *info); static char doc_getrf[] = "LU factorization of a general real or complex m by n matrix.\n\n" "getrf(A, ipiv, m=A.size[0], n=A.size[1], ldA=max(1,A.size[0]),\n" " offsetA=0)\n\n" "PURPOSE\n" "On exit, A is replaced with L, U in the factorization P*A = L*U\n" "and ipiv contains the permutation:\n" "P = P_min{m,n} * ... * P2 * P1 where Pi interchanges rows i and\n" "ipiv[i] of A (using the Fortran convention, i.e., the first row\n" "is numbered 1).\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "ipiv 'i' matrix of length at least min(m,n)\n\n" "m nonnegative integer. If negative, the default value is\n" " used.\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= max(1,m). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* getrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *ipiv; int m=-1, n=-1, ldA=0, oA=0, info; char *kwlist[] = {"A", "ipiv", "m", "n", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, &A, &ipiv, &m, &n, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv ->id != INT) err_int_mtrx("ipiv"); if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (len(ipiv) < MIN(n,m)) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(MIN(m,n)*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); #else int *ipiv_ptr = MAT_BUFI(ipiv); #endif switch (MAT_ID(A)) { case DOUBLE: Py_BEGIN_ALLOW_THREADS dgetrf_(&m, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zgetrf_(&m, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, &info); Py_END_ALLOW_THREADS break; default: #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif err_invalid_id; } #if (SIZEOF_INT < SIZEOF_LONG) int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* getrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; #endif char trans = 'N'; char *kwlist[] = {"A", "ipiv", "B", "trans", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Ciiiiii", kwlist, &A, &ipiv, &B, &trans_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; trans = trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist, &A, &ipiv, &B, &trans, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* getri(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *ipiv; int n=-1, ldA=0, oA=0, info, lwork; void *work; number wl; char *kwlist[] = {"A", "ipiv", "n", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iii", kwlist, &A, &ipiv, &n, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetA nonnegative integer"; static PyObject* gesv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv=NULL; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, k; void *Ac=NULL; int *ipivc=NULL; static char *kwlist[] = {"A", "B", "ipiv", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Oiiiiii", kwlist, &A, &B, &ipiv, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) err_int_mtrx("ipiv"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (ipiv && len(ipiv) < n) err_buf_len("ipiv"); if (ipiv) { #if (SIZEOF_INT < SIZEOF_LONG) if (!(ipivc = (int *) calloc(n, sizeof(int)))) return PyErr_NoMemory(); #else ipivc = MAT_BUFI(ipiv); #endif } else if (!(ipivc = (int *) calloc(n, sizeof(int)))) return PyErr_NoMemory(); switch (MAT_ID(A)){ case DOUBLE: if (ipiv) Py_BEGIN_ALLOW_THREADS dgesv_(&n, &nrhs, MAT_BUFD(A)+oA, &ldA, ipivc, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS else { if (!(Ac = (void *) calloc(n*n, sizeof(double)))){ free(ipivc); return PyErr_NoMemory(); } for (k=0; k= 2*kl+ku+1. If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* gbtrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *ipiv; int m, kl, n=-1, ku=-1, ldA=0, oA=0, info; char *kwlist[] = {"A", "m", "kl", "ipiv", "n", "ku", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiiO|iiii", kwlist, &A, &m, &kl, &ipiv, &n, &ku, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (m < 0) err_nn_int("m"); if (kl < 0) err_nn_int("kl"); if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ku < 0) ku = A->nrows - 2*kl - 1; if (ku < 0) err_nn_int("kl"); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < 2*kl + ku + 1) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + 2*kl + ku + 1 > len(A)) err_buf_len("A"); if (!Matrix_Check(ipiv) || ipiv ->id != INT) err_int_mtrx("ipiv"); if (len(ipiv) < MIN(n,m)) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(MIN(m,n)*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); #else int *ipiv_ptr = MAT_BUFI(ipiv); #endif switch (MAT_ID(A)) { case DOUBLE: Py_BEGIN_ALLOW_THREADS dgbtrf_(&m, &n, &kl, &ku, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zgbtrf_(&m, &n, &kl, &ku, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, &info); Py_END_ALLOW_THREADS break; default: #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif err_invalid_id; } #if (SIZEOF_INT < SIZEOF_LONG) int i; for (i=0; i= 2*kl+ku+1. If zero, the\n" " default value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* gbtrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv; int kl, n=-1, ku=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; #endif char trans = 'N'; char *kwlist[] = {"A", "kl", "ipiv", "B", "trans", "n", "ku", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiOO|Ciiiiiii", kwlist, &A, &kl, &ipiv, &B, &trans_, &n, &ku, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiOO|ciiiiiii", kwlist, &A, &kl, &ipiv, &B, &trans, &n, &ku, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (kl < 0) err_nn_int("kl"); if (ku < 0) ku = A->nrows - 2*kl - 1; if (ku < 0) err_nn_int("kl"); if (n < 0) n = A->ncols; if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < 2*kl+ku+1) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + 2*kl + ku + 1 > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= kl+ku+1 if ipiv is not provided\n" " and ldA >= 2*kl+ku+1 if ipiv is provided. If zero, the\n" " default value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* gbsv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv=NULL; void *Ac; int kl, ku=-1, n=-1, nrhs=-1, ldA=0, oA=0, ldB=0, oB=0, info, k; int *ipivc=NULL; static char *kwlist[] = {"A", "kl", "B", "ipiv", "ku", "n", "nrhs", "ldA", "ldB", "oA", "oB", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiO|Oiiiiiii", kwlist, &A, &kl, &B, &ipiv, &ku, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) err_int_mtrx("ipiv"); if (n < 0) n = A->ncols; if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (kl < 0) err_nn_int("kl"); if (ku < 0) ku = A->nrows - kl - 1 - (ipiv ? kl : 0); if (ku < 0) err_nn_int("ku"); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < ( ipiv ? 2*kl+ku+1 : kl+ku+1)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + (ipiv ? 2*kl+ku+1 : kl+ku+1) > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (ipiv && len(ipiv) < n) err_buf_len("ipiv"); if (ipiv) { #if (SIZEOF_INT < SIZEOF_LONG) if (!(ipivc = (int *) calloc(n, sizeof(int)))) return PyErr_NoMemory(); #else ipivc = MAT_BUFI(ipiv); #endif } else if (!(ipivc = (int *) calloc(n, sizeof(int)))) return PyErr_NoMemory(); switch (MAT_ID(A)) { case DOUBLE: if (ipiv) Py_BEGIN_ALLOW_THREADS dgbsv_(&n, &kl, &ku, &nrhs, MAT_BUFD(A)+oA, &ldA, ipivc, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS else { if (!(Ac = (void *) calloc((2*kl+ku+1)*n, sizeof(double)))){ free(ipivc); return PyErr_NoMemory(); } for (k=0; kid != INT) err_int_mtrx("ipiv"); if (od < 0) err_nn_int("offsetd"); if (n < 0) n = len(d) - od; if (n < 0) err_buf_len("d"); if (n == 0) return Py_BuildValue(""); if (odl < 0) err_nn_int("offsetdl"); if (odl + n - 1 > len(dl)) err_buf_len("dl"); if (od + n > len(d)) err_buf_len("d"); if (odu < 0) err_nn_int("offsetdu"); if (odu + n - 1 > len(du)) err_buf_len("du"); if (n - 2 > len(du2)) err_buf_len("du2"); if (len(ipiv) < n) err_buf_len("ipiv"); if (n > len(ipiv)) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); #else int *ipiv_ptr = MAT_BUFI(ipiv); #endif switch (MAT_ID(dl)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dgttrf_(&n, MAT_BUFD(dl)+odl, MAT_BUFD(d)+od, MAT_BUFD(du)+odu, MAT_BUFD(du2), ipiv_ptr, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zgttrf_(&n, MAT_BUFZ(dl)+odl, MAT_BUFZ(d)+od, MAT_BUFZ(du)+odu, MAT_BUFZ(du2), ipiv_ptr, &info); Py_END_ALLOW_THREADS break; default: #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif err_invalid_id; } #if (SIZEOF_INT < SIZEOF_LONG) int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetdl nonnegative integer\n\n" "offsetd nonnegative integer\n\n" "offsetdu nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* gttrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *dl, *d, *du, *du2, *ipiv, *B; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; #endif char trans = 'N'; int n=-1, nrhs=-1, ldB=0, odl=0, od=0, odu=0, oB=0, info; static char *kwlist[] = {"dl", "d", "du", "du2", "ipiv", "B", "trans", "n", "nrhs", "ldB", "offsetdl", "offsetd", "offsetdu", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOOOOO|ciiiiiii", kwlist, &dl, &d, &du, &du2, &ipiv, &B, &trans, &n, &nrhs, &ldB, &odl, &od, &odu, &oB)) return NULL; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOOOOO|ciiiiiii", kwlist, &dl, &d, &du, &du2, &ipiv, &B, &trans, &n, &nrhs, &ldB, &odl, &od, &odu, &oB)) return NULL; #endif if (!Matrix_Check(dl)) err_mtrx("dl"); if (!Matrix_Check(d)) err_mtrx("d"); if (!Matrix_Check(du)) err_mtrx("du"); if (!Matrix_Check(du2)) err_mtrx("du"); if (!Matrix_Check(B)) err_mtrx("B"); if ((MAT_ID(dl) != MAT_ID(d)) || (MAT_ID(dl) != MAT_ID(du)) || (MAT_ID(dl) != MAT_ID(du2)) || (MAT_ID(dl) != MAT_ID(B))) err_conflicting_ids; if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (od < 0) err_nn_int("offsetd"); if (n < 0) n = len(d) - od; if (n < 0) err_buf_len("d"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (odl < 0) err_nn_int("offsetdl"); if (odl + n - 1 > len(dl)) err_buf_len("dl"); if (od + n > len(d)) err_buf_len("d"); if (odu < 0) err_nn_int("offsetdu"); if (odu + n - 1 > len(du)) err_buf_len("du"); if (n - 2 > len(du2)) err_buf_len("du2"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (n > len(ipiv)) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetdl nonnegative integer\n\n" "offsetd nonnegative integer\n\n" "offsetdu nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* gtsv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *dl, *d, *du, *B; int n=-1, nrhs=-1, ldB=0, odl=0, od=0, odu=0, oB=0, info; static char *kwlist[] = {"dl", "d", "du", "B", "n", "nrhs", "ldB", "offsetdl", "offsetd", "offsetdu", "offsetB", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOOO|iiiiiii", kwlist, &dl, &d, &du, &B, &n, &nrhs, &ldB, &odl, &od, &odu, &oB)) return NULL; if (!Matrix_Check(dl)) err_mtrx("dl"); if (!Matrix_Check(d)) err_mtrx("d"); if (!Matrix_Check(du)) err_mtrx("du"); if (!Matrix_Check(B)) err_mtrx("B"); if ((MAT_ID(dl) != MAT_ID(B)) || (MAT_ID(dl) != MAT_ID(d)) || (MAT_ID(dl) != MAT_ID(du)) || (MAT_ID(dl) != MAT_ID(B))) err_conflicting_ids; if (od < 0) err_nn_int("offsetd"); if (n < 0) n = len(d) - od; if (n < 0) err_buf_len("d"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (odl < 0) err_nn_int("offsetdl"); if (odl + n - 1 > len(dl)) err_buf_len("dl"); if (od + n > len(d)) err_buf_len("d"); if (odu < 0) err_nn_int("offsetdu"); if (odu + n - 1 > len(du)) err_buf_len("du"); if (oB < 0) err_nn_int("offsetB"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(dl)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dgtsv_(&n, &nrhs, MAT_BUFD(dl)+odl, MAT_BUFD(d)+od, MAT_BUFD(du)+odu, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zgtsv_(&n, &nrhs, MAT_BUFZ(dl)+odl, MAT_BUFZ(d)+od, MAT_BUFZ(du)+odu, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_potrf[] = "Cholesky factorization of a real symmetric or complex Hermitian\n" "positive definite matrix.\n\n" "potrf(A, uplo='L', n=A.size[0], ldA = max(1,A.size[0]), offsetA=0)" "\n\n" "PURPOSE\n" "Factors A as A=L*L^T or A = L*L^H, where A is n by n, real\n" "symmetric or complex Hermitian, and positive definite.\n" "On exit, if uplo='L', the lower triangular part of A is replaced\n" "by L. If uplo='U', the upper triangular part is replaced by L^T\n" "or L^H.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* potrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A; int n=-1, ldA=0, oA=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "uplo", "n", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|Ciii", kwlist, &A, &uplo_, &n, &ldA, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|ciii", kwlist, &A, &uplo, &n, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A is not square"); return NULL; } } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpotrf_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpotrf_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_potrs[] = "Solves a real symmetric or complex Hermitian positive definite set\n" "of linear equations, given the Cholesky factorization computed by\n" "potrf() or posv().\n\n" "potrs(A, B, uplo='L', n=A.size[0], nrhs=B.size[1],\n" " ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n" " offsetB=0)\n\n" "PURPOSE\n" "Solves A*X = B where A is n by n, real symmetric or complex\n" "Hermitian and positive definite, and B is n by nrhs.\n" "On entry, A contains the Cholesky factor, as returned by posv() or\n" "potrf(). On exit B is replaced by the solution X.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "nrhs nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* potrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "B", "uplo", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciiiiii", kwlist, &A, &B, &uplo_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiii", kwlist, &A, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0) n = A->nrows; if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpotrs_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpotrs_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_potri[] = "Inverse of a real symmetric or complex Hermitian positive definite\n" "matrix.\n\n" "potri(A, uplo='L', n=A.size[0], ldA=max(1,A.size[0]), offsetA=0)\n\n" "PURPOSE\n" "Computes the inverse of a real symmetric or complex Hermitian\n" "positive definite matrix of order n. On entry, A contains the\n" "Cholesky factor, as returned by posv() or potrf(). On exit it is\n" "replaced by the inverse.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n\n" " used.\n\n" "ldA positive integer. ldA >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* potri(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A; int n=-1, ldA=0, oA=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "uplo", "n", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|Ciii", kwlist, &A, &uplo_, &n, &ldA, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|ciii", kwlist, &A, &uplo, &n, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0) n = A->nrows; if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|ciii", kwlist, &A, &uplo, &n, &ldA, &oA)) return NULL; switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpotri_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpotri_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_posv[] = "Solves a real symmetric or complex Hermitian positive definite set\n" "of linear equations.\n\n" "posv(A, B, uplo='L', n=A.size[0], nrhs=B.size[1], \n" " ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0, \n" " offsetB=0)\n\n" "PURPOSE\n" "Solves A*X = B with A n by n, real symmetric or complex Hermitian,\n" "and positive definite, and B n by nrhs.\n" "On exit, if uplo is 'L', the lower triangular part of A is\n" "replaced by L. If uplo is 'U', the upper triangular part is\n" "replaced by L^H. B is replaced by the solution.\n\n" "ARGUMENTS.\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "nrhs nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* posv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "B", "uplo", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciiiiii", kwlist, &A, &B, &uplo_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiii", kwlist, &A, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0) n = A->nrows; if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dposv_(&uplo, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zposv_(&uplo, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_pbtrf[] = "Cholesky factorization of a real symmetric or complex Hermitian\n" "positive definite band matrix.\n\n" "pbtrf(A, uplo='L', n=A.size[1], kd=A.size[0]-1, ldA=max(1,A.size[0])," "\n" " offsetA=0)\n\n" "PURPOSE\n" "Factors A as A=L*L^T or A = L*L^H, where A is an n by n real\n" "symmetric or complex Hermitian positive definite band matrix with\n" "kd subdiagonals and kd superdiagonals. A is stored in the BLAS \n" "format for symmetric band matrices. On exit, A contains the\n" "Cholesky factor in the BLAS format for triangular band matrices.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix.\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "kd nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= kd+1. If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* pbtrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A; int n=-1, kd=-1, ldA=0, oA=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "uplo", "n", "kd", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|Ciiii", kwlist, &A, &uplo_, &n, &kd, &ldA, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|ciiii", kwlist, &A, &uplo, &n, &kd, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (n < 0) n = A->ncols; if (n == 0) return Py_BuildValue(""); if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (kd < 0) kd = A->nrows - 1; if (kd < 0) err_nn_int("kd"); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < kd+1) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A"); switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpbtrf_(&uplo, &n, &kd, MAT_BUFD(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpbtrf_(&uplo, &n, &kd, MAT_BUFZ(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_pbtrs[] = "Solves a real symmetric or complex Hermitian positive definite set\n" "of linear equations with a banded coefficient matrix, given the\n" "Cholesky factorization computed by pbtrf() or pbsv().\n\n" "pbtrs(A, B, uplo='L', n=A.size[1], kd=A.size[0]-1, nrhs=B.size[1],\n" " ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n" " offsetB=0)\n\n" "PURPOSE\n" "Solves A*X = B where A is an n by n real symmetric or complex \n" "Hermitian positive definite band matrix with kd subdiagonals and kd\n" "superdiagonals, and B is n by nrhs. A contains the Cholesky factor\n" "of A, as returned by pbtrf() or pbtrs(). On exit, B is replaced by\n" "the solution X.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix.\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "kd nonnegative integer. If negative, the default value is\n" " used.\n\n" "nrhs nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= kd+1. If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* pbtrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; int n=-1, kd=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "B", "uplo", "n", "kd", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciiiiiii", kwlist, &A, &B, &uplo_, &n, &kd, &nrhs, &ldA, &ldB, &oA, oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiiii", kwlist, &A, &B, &uplo, &n, &kd, &nrhs, &ldA, &ldB, &oA, oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (n < 0) n = A->ncols; if (kd < 0) kd = A->nrows - 1; if (kd < 0) err_nn_int("kd"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < kd+1) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpbtrs_(&uplo, &n, &kd, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpbtrs_(&uplo, &n, &kd, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_pbsv[] = "Solves a real symmetric or complex Hermitian positive definite set\n" "of linear equations with a banded coefficient matrix.\n\n" "pbsv(A, B, uplo='L', n=A.size[1], kd=A.size[0]-1, nrhs=B.size[1],\n" " ldA=MAX(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n" " offsetB=0)\n\n" "PURPOSE\n" "Solves A*X = B where A is an n by n real symmetric or complex\n" "Hermitian positive definite band matrix with kd subdiagonals and kd\n" "superdiagonals, and B is n by nrhs.\n" "On entry, A contains A in the BLAS format for symmetric band\n" "matrices. On exit, A is replaced with the Cholesky factors, stored\n" "in the BLAS format for triangular band matrices. B is replaced\n" "by the solution X.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix.\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "kd nonnegative integer. If negative, the default value is\n" " used.\n\n" "nrhs nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= kd+1. If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* pbsv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; int n=-1, kd=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "B", "uplo", "n", "kd", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciiiiiii", kwlist, &A, &B, &uplo_, &n, &kd, &nrhs, &ldA, &ldB, &oA, oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiiii", kwlist, &A, &B, &uplo, &n, &kd, &nrhs, &ldA, &ldB, &oA, oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (n < 0) n = A->ncols; if (kd < 0) kd = A->nrows - 1; if (kd < 0) err_nn_int("kd"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < kd+1) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpbsv_(&uplo, &n, &kd, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpbsv_(&uplo, &n, &kd, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_pttrf[] = "Cholesky factorization of a real symmetric or complex Hermitian\n" "positive definite tridiagonal matrix.\n\n" "pttrf(d, e, n=len(d)-offsetd, offsetd=0, offsete=0)\n\n" "PURPOSE\n" "Factors A as A = L*D*L^T or A = L*D*L^H where A is n by n, real\n" "symmetric or complex Hermitian, positive definite, and tridiagonal.\n" "On entry, d is the subdiagonal of A and e is the diagonal. On \n" "exit, d contains the diagonal of D and e contains the subdiagonal\n" "of the unit bidiagonal matrix L.\n\n" "ARGUMENTS.\n" "d 'd' matrix\n\n" "e 'd' or 'z' matrix.\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "offsetd nonnegative integer\n\n" "offsete nonnegative integer"; static PyObject* pttrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *d, *e; int n=-1, od=0, oe=0, info; static char *kwlist[] = {"d", "e", "n", "offsetd", "offsete", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iii", kwlist, &d, &e, &n, &od, &oe)) return NULL; if (!Matrix_Check(d)) err_mtrx("d"); if (MAT_ID(d) != DOUBLE) err_type("d"); if (!Matrix_Check(e)) err_mtrx("e"); if (od < 0) err_nn_int("offsetd"); if (n < 0) n = len(d) - od; if (n < 0) err_buf_len("d"); if (od + n > len(d)) err_buf_len("d"); if (n == 0) return Py_BuildValue(""); if (oe < 0) err_nn_int("offsete"); if (oe + n - 1 > len(e)) err_buf_len("e"); switch (MAT_ID(e)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpttrf_(&n, MAT_BUFD(d)+od, MAT_BUFD(e)+oe, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpttrf_(&n, MAT_BUFD(d)+od, MAT_BUFZ(e)+oe, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_pttrs[] = "Solves a real symmetric or complex Hermitian positive definite set\n" "of linear equations with a tridiagonal coefficient matrix, given \n" "the factorization computed by pttrf().\n\n" "pttrs(d, e, B, uplo='L', n=len(d)-offsetd, nrhs=B.size[1],\n" " ldB=max(1,B.size[0], offsetd=0, offsete=0, offsetB=0)\n\n" "PURPOSE\n" "Solves A*X=B with A n by n real or complex Hermitian positive\n" "definite and tridiagonal, and B n by nrhs. On entry, d and e\n" "contain the Cholesky factorization L*D*L^T or L*D*L^H, for example,\n" "as returned by pttrf(). The argument d is the diagonal of the \n" "diagonal matrix D. The argument uplo only matters in the complex\n" "case. If uplo = 'L', then e is the subdiagonal of L. If uplo='U',\n" "e is the superdiagonal of L^H. On exit B is overwritten with the\n" "solution X. \n\n" "ARGUMENTS.\n" "d 'd' matrix\n\n" "e 'd' or 'z' matrix.\n\n" "B 'd' or 'z' matrix. Must have the same type as e.\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "nrhs nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetd nonnegative integer\n\n" "offsete nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* pttrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *d, *e, *B; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; int n=-1, nrhs=-1, ldB=0, od=0, oe=0, oB=0, info; static char *kwlist[] = {"d", "e", "B", "uplo", "n", "nrhs", "ldB", "offsetd", "offsete", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Ciiiiii", kwlist, &d, &e, &B, &uplo_, &n, &nrhs, &ldB, &od, &oe, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist, &d, &e, &B, &uplo, &n, &nrhs, &ldB, &od, &oe, &oB)) return NULL; #endif if (!Matrix_Check(d)) err_mtrx("d"); if (MAT_ID(d) != DOUBLE) err_type("d"); if (!Matrix_Check(e)) err_mtrx("e"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(e) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (od < 0) err_nn_int("offsetd"); if (n < 0) n = len(d) - od; if (n < 0) err_buf_len("d"); if (od + n > len(d)) err_buf_len("d"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (oe < 0) err_nn_int("offsete"); if (oe + n - 1 > len(e)) err_buf_len("e"); if (oB < 0) err_nn_int("offsetB"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(e)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dpttrs_(&n, &nrhs, MAT_BUFD(d)+od, MAT_BUFD(e)+oe, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zpttrs_(&uplo, &n, &nrhs, MAT_BUFD(d)+od, MAT_BUFZ(e)+oe, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_ptsv[] = "Solves a real symmetric or complex Hermitian positive definite set\n" "of linear equations with a tridiagonal coefficient matrix.\n\n" "ptsv(d, e, B, n=len(d)-offsetd, nrhs=B.size[1], ldB=max(1,B.size[0]," "\n" " offsetd=0, offsete=0, offsetB=0)\n\n" "PURPOSE\n" "Solves A*X=B with A n by n real or complex Hermitian positive\n" "definite and tridiagonal. A is specified by its diagonal d and\n" "subdiagonal e. On exit B is overwritten with the solution, and d\n" "and e are overwritten with the elements of Cholesky factorization\n" "of A.\n\n" "ARGUMENTS.\n" "d 'd' matrix\n\n" "e 'd' or 'z' matrix.\n\n" "B 'd' or 'z' matrix. Must have the same type as e.\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "nrhs nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetd nonnegative integer\n\n" "offsete nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* ptsv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *d, *e, *B; int n=-1, nrhs=-1, ldB=0, od=0, oe=0, oB=0, info; static char *kwlist[] = {"d", "e", "B", "n", "nrhs", "ldB", "offsetd", "offsete", "offsetB", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iiiiii", kwlist, &d, &e, &B, &n, &nrhs, &ldB, &od, &oe, &oB)) return NULL; if (!Matrix_Check(d)) err_mtrx("d"); if (MAT_ID(d) != DOUBLE) err_type("d"); if (!Matrix_Check(e)) err_mtrx("e"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(e) != MAT_ID(B)) err_conflicting_ids; if (od < 0) err_nn_int("offsetd"); if (n < 0) n = len(d) - od; if (n < 0) err_buf_len("d"); if (od + n > len(d)) err_buf_len("d"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (oe < 0) err_nn_int("offsete"); if (oe + n - 1 > len(e)) err_buf_len("e"); if (oB < 0) err_nn_int("offsetB"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(e)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dptsv_(&n, &nrhs, MAT_BUFD(d)+od, MAT_BUFD(e)+oe, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zptsv_(&n, &nrhs, MAT_BUFD(d)+od, MAT_BUFZ(e)+oe, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_sytrf[] = "LDL^T factorization of a real or complex symmetric matrix.\n\n" "sytrf(A, ipiv, uplo='L', n=A.size[0], ldA=max(1,A.size[0]))\n\n" "PURPOSE\n" "Computes the LDL^T factorization of a real or complex symmetric\n" "n by n matrix A. On exit, A and ipiv contain the details of the\n" "factorization.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "ipiv 'i' matrix of length at least n\n\n" "uplo 'L' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* sytrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *ipiv; void *work; number wl; int n=-1, ldA=0, oA=0, info, lwork; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciii", kwlist, &A, &ipiv, &uplo_, &n, &ldA, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist, &A, &ipiv, &uplo, &n, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); #else int *ipiv_ptr = MAT_BUFI(ipiv); #endif switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))){ #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsytrf_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))){ #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zsytrf_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif err_invalid_id; } #if (SIZEOF_INT < SIZEOF_LONG) int i; for (i=0; i= max(1,n). If zero, the default\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* hetrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *ipiv; void *work; number wl; int n=-1, ldA=0, oA=0, info, lwork; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciii", kwlist, &A, &ipiv, &uplo_, &n, &ldA, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist, &A, &ipiv, &uplo, &n, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); #else int *ipiv_ptr = MAT_BUFI(ipiv); #endif switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))){ #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsytrf_(&uplo, &n, MAT_BUFD(A)+oA, &ldA, ipiv_ptr, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zhetrf_(&uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))){ #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zhetrf_(&uplo, &n, MAT_BUFZ(A)+oA, &ldA, ipiv_ptr, (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: #if (SIZEOF_INT < SIZEOF_LONG) free(ipiv_ptr); #endif err_invalid_id; } #if (SIZEOF_INT < SIZEOF_LONG) int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* sytrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "ipiv", "B", "uplo", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Ciiiiii", kwlist, &A, &ipiv, &B, &uplo_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist, &A, &ipiv, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* hetrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ ='L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "ipiv", "B", "uplo", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Ciiiiii", kwlist, &A, &ipiv, &B, &uplo_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciiiiii", kwlist, &A, &ipiv, &B, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* sytri(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *ipiv; int n=-1, ldA=0, oA=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; void *work; char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciii", kwlist, &A, &ipiv, &uplo_, &n, &ldA, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist, &A, &ipiv, &uplo, &n, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* hetri(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *ipiv; int n=-1, ldA=0, oA=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; void *work; char *kwlist[] = {"A", "ipiv", "uplo", "n", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciii", kwlist, &A, &ipiv, &uplo_, &n, &ldA, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist, &A, &ipiv, &uplo, &n, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(ipiv) || ipiv->id != INT) err_int_mtrx("ipiv"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (len(ipiv) < n) err_buf_len("ipiv"); #if (SIZEOF_INT < SIZEOF_LONG) int *ipiv_ptr = malloc(n*sizeof(int)); if (!ipiv_ptr) return PyErr_NoMemory(); int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* sysv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv=NULL; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, lwork, k, *ipivc=NULL; void *work=NULL, *Ac=NULL; number wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "B", "ipiv", "uplo", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OCiiiiii", kwlist, &A, &B, &ipiv, &uplo_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ociiiiii", kwlist, &A, &B, &ipiv, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) err_int_mtrx("ipiv"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (ipiv && len(ipiv) < n) err_buf_len("ipiv"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); if (ipiv) { #if (SIZEOF_INT < SIZEOF_LONG) if (!(ipivc = (int *) calloc(n, sizeof(int)))){ free(work); return PyErr_NoMemory(); } for (k=0; k= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* hesv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *ipiv=NULL; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, lwork, k, *ipivc=NULL; void *work=NULL, *Ac=NULL; number wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "B", "ipiv", "uplo", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OCiiiiii", kwlist, &A, &B, &ipiv, &uplo_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ociiiiii", kwlist, &A, &B, &ipiv, &uplo, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (ipiv && (!Matrix_Check(ipiv) || ipiv->id != INT)) err_int_mtrx("ipiv"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); if (ipiv && len(ipiv) < n) err_buf_len("ipiv"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dsytrf_(&uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); if (ipiv) { #if (SIZEOF_INT < SIZEOF_LONG) if (!(ipivc = (int *) calloc(n,sizeof(int)))){ free(work); return PyErr_NoMemory(); } int i; for (i=0; i= max(1,n). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* trtrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; int n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', trans_ = 'N', diag_ = 'N'; #endif char uplo = 'L', trans = 'N', diag = 'N'; char *kwlist[] = {"A", "B", "uplo", "trans", "diag", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCiiiiii", kwlist, &A, &B, &uplo_, &trans_, &diag_, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; trans = (char) trans_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiii", kwlist, &A, &B, &uplo, &trans, &diag, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'"); if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (n < 0){ n = A->nrows; if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: if (trans == 'C') trans = 'T'; Py_BEGIN_ALLOW_THREADS dtrtrs_(&uplo, &trans, &diag, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS ztrtrs_(&uplo, &trans, &diag, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_trtri[] = "Inverse of a triangular matrix.\n\n" "trtri(A, uplo='L', diag='N', n=A.size[0], ldA=max(1,A.size[0]),\n" " offsetA=0)\n\n" "PURPOSE\n" "Computes the inverse of a triangular matrix of order n.\n" "On exit, A is replaced with its inverse.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "uplo 'L' or 'U'\n\n" "diag 'N' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer"; static PyObject* trtri(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A; int n=-1, ldA=0, oA=0, info; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', diag_ = 'N'; #endif char uplo = 'L', diag = 'N'; char *kwlist[] = {"A", "uplo", "diag", "n", "ldA", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|CCiii", kwlist, &A, &uplo_, &diag_, &n, &ldA, &oA)) return NULL; uplo = (char) uplo_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|cciii", kwlist, &A, &uplo, &diag, &n, &ldA, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'"); if (n < 0){ n = A->nrows; if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dtrtri_(&uplo, &diag, &n, MAT_BUFD(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS ztrtri_(&uplo, &diag, &n, MAT_BUFZ(A)+oA, &ldA, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_tbtrs[] = "Solution of a triangular set of equations with banded coefficient\n" "matrix.\n\n" "tbtrs(A, B, uplo='L', trans='N', diag='N', n=A.size[1], \n" " kd=A.size[0]-1, nrhs=B.size[1], ldA=max(1,A.size[0]),\n" " ldB=max(1,B.size[0]), offsetA=0, offsetB=0)\n\n" "PURPOSE\n" "If trans is 'N', solves A*X = B.\n" "If trans is 'T', solves A^T*X = B.\n" "If trans is 'C', solves A^H*X = B.\n" "B is n by nrhs and A is a triangular band matrix of order n with kd\n" "subdiagonals (uplo is 'L') or superdiagonals (uplo is 'U').\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N', 'T' or 'C'\n\n" "diag 'N' or 'U'\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "kd nonnegative integer. If negative, the default value is\n" " used.\n\n" "nrhs nonnegative integer. If negative, the default value is\n" " used.\n\n" "ldA positive integer. ldA >= kd+1. If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,n). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* tbtrs(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', trans_ = 'N', diag_ = 'N'; #endif char uplo = 'L', trans = 'N', diag = 'N'; int n=-1, kd=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info; char *kwlist[] = {"A", "B", "uplo", "trans", "diag", "n", "kd", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCiiiiiii", kwlist, &A, &B, &uplo_, &trans_, &diag_, &n, &kd, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; trans = (char) trans_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiiii", kwlist, &A, &B, &uplo, &trans, &diag, &n, &kd, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'"); if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (n < 0) n = A->ncols; if (kd < 0) kd = A->nrows - 1; if (kd < 0) err_nn_int("kd"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < kd+1) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + kd + 1 > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: if (trans == 'C') trans = 'T'; Py_BEGIN_ALLOW_THREADS dtbtrs_(&uplo, &trans, &diag, &n, &kd, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS ztbtrs_(&uplo, &trans, &diag, &n, &kd, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &info); Py_END_ALLOW_THREADS break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_gels[] = "Solves least-squares and least-norm problems with full rank\n" "matrices.\n\n" "gels(A, B, trans='N', m=A.size[0], n=A.size[1], nrhs=B.size[1],\n" " ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), offsetA=0,\n" " offsetB=0)\n\n" "PURPOSE\n" "1. If trans is 'N' and A and B are real/complex:\n" "- if m >= n: minimizes ||A*X - B||_F.\n" "- if m < n: minimizes ||X||_F subject to A*X = B.\n\n" "2. If trans is 'N' or 'C' and A and B are real:\n" "- if m >= n: minimizes ||X||_F subject to A^T*X = B.\n" "- if m < n: minimizes ||X||_F subject to A^T*X = B.\n\n" "3. If trans is 'C' and A and B are complex:\n" "- if m >= n: minimizes ||X||_F subject to A^H*X = B.\n" "- if m < n: minimizes ||X||_F subject to A^H*X = B.\n\n" "A is an m by n matrix. B has nrhs columns. On exit, B is\n" "replaced with the solution, and A is replaced with the details\n" "of its QR or LQ factorization.\n\n" "Note that gels does not check whether A has full rank.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "trans 'N', 'T' or 'C' if A is real. 'N' or 'C' if A is\n" " complex.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "nrhs integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,m,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* gels(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; int m=-1, n=-1, nrhs=-1, ldA=0, ldB=0, oA=0, oB=0, info, lwork; void *work; number wl; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; #endif char trans = 'N'; char *kwlist[] = {"A", "B", "trans", "m", "n", "nrhs", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciiiiiii", kwlist, &A, &B, &trans_, &m, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiiii", kwlist, &A, &B, &trans, &m, &n, &nrhs, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (nrhs < 0) nrhs = B->ncols; if (m == 0 || n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(MAX(1,n),m)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + ((trans == 'N') ? n : m) > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: if (trans == 'C') trans = 'T'; lwork = -1; Py_BEGIN_ALLOW_THREADS dgels_(&trans, &m, &n, &nrhs, NULL, &ldA, NULL, &ldB, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dgels_(&trans, &m, &n, &nrhs, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: if (trans == 'T') err_char("trans", "'N', 'C'"); lwork = -1; Py_BEGIN_ALLOW_THREADS zgels_(&trans, &m, &n, &nrhs, NULL, &ldA, NULL, &ldB, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS zgels_(&trans, &m, &n, &nrhs, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_geqrf[] = "QR factorization.\n\n" "geqrf(A, tau, m=A.size[0], n=A.size[1], ldA=max(1,A.size[0]),\n" " offsetA=0)\n\n" "PURPOSE\n" "QR factorization of an m by n real or complex matrix A:\n\n" "A = Q*R = [Q1 Q2] * [R1; 0] if m >= n\n" "A = Q*R = Q * [R1 R2] if m <= n,\n\n" "where Q is m by m and orthogonal/unitary and R is m by n with R1\n" "upper triangular. On exit, R is stored in the upper triangular\n" "part of A. Q is stored as a product of k=min(m,n) elementary\n" "reflectors. The parameters of the reflectors are stored in the\n" "first k entries of tau and in the lower triangular part of the\n" "first k columns of A.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "tau 'd' or 'z' matrix of length at least min(m,n). Must\n" " have the same type as A.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* geqrf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau; int m=-1, n=-1, ldA=0, oA=0, info, lwork; void *work; number wl; char *kwlist[] = {"A", "tau", "m", "n", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, &A, &tau, &m, &n, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids; if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (len(tau) < MIN(m,n)) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dgeqrf_(&m, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dgeqrf_(&m, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(tau), (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zgeqrf_(&m, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS zgeqrf_(&m, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(tau), (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_ormqr[] = "Product with a real orthogonal matrix.\n\n" "ormqr(A, tau, C, side='L', trans='N', m=C.size[0], n=C.size[1],\n" " k=len(tau), ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n" " offsetA=0, offsetC=0)\n\n" "PURPOSE\n" "Computes\n" "C := Q*C if side = 'L' and trans = 'N'.\n" "C := Q^T*C if side = 'L' and trans = 'T'.\n" "C := C*Q if side = 'R' and trans = 'N'.\n" "C := C*Q^T if side = 'R' and trans = 'T'.\n" "C is m by n and Q is a square orthogonal matrix computed by geqrf." "\n" "Q is defined as a product of k elementary reflectors, stored as\n" "the first k columns of A and the first k entries of tau.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "tau 'd' matrix of length at least k\n\n" "C 'd' matrix\n\n" "side 'L' or 'R'\n\n" "trans 'N' or 'T'\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "k integer. k <= m if side = 'R' and k <= n if side = 'L'.\n" " If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m) if side = 'L'\n" " and ldA >= max(1,n) if side = 'R'. If zero, the\n" " default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* ormqr(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau, *C; int m=-1, n=-1, k=-1, ldA=0, ldC=0, oA=0, oC=0, info, lwork; void *work; number wl; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', trans_ = 'N'; #endif char side = 'L', trans = 'N'; char *kwlist[] = {"A", "tau", "C", "side", "trans", "m", "n", "k", "ldA", "ldC", "offsetA", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCiiiiiii", kwlist, &A, &tau, &C, &side_, &trans_, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; side = (char) side_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cciiiiiii", kwlist, &A, &tau, &C, &side, &trans, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(tau) || MAT_ID(A) != MAT_ID(C)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (trans != 'N' && trans != 'T') err_char("trans", "'N', 'T'"); if (m < 0) m = C->nrows; if (n < 0) n = C->ncols; if (k < 0) k = len(tau); if (m == 0 || n == 0 || k == 0) return Py_BuildValue(""); if (k > ((side == 'L') ? m : n)) err_ld("k"); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < ((side == 'L') ? MAX(1,m) : MAX(1,n))) err_ld("ldA"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,m)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (oA + k*ldA > len(A)) err_buf_len("A"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dormqr_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL, &ldC, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dormqr_(&side, &trans, &m, &n, &k, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(tau), MAT_BUFD(C)+oC, &ldC, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_unmqr[] = "Product with a real or complex orthogonal matrix.\n\n" "unmqr(A, tau, C, side='L', trans='N', m=C.size[0], n=C.size[1],\n" " k=len(tau), ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n" " offsetA=0, offsetC=0)\n\n" "PURPOSE\n" "Computes\n" "C := Q*C if side = 'L' and trans = 'N'.\n" "C := Q^T*C if side = 'L' and trans = 'T'.\n" "C := Q^H*C if side = 'L' and trans = 'C'.\n" "C := C*Q if side = 'R' and trans = 'N'.\n" "C := C*Q^T if side = 'R' and trans = 'T'.\n" "C := C*Q^H if side = 'R' and trans = 'C'.\n" "C is m by n and Q is a square orthogonal/unitary matrix computed\n" "by geqrf. Q is defined as a product of k elementary reflectors,\n" "stored as the first k columns of A and the first k entries of tau." "\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "tau 'd' or 'z' matrix of length at least k. Must have the\n" " same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "side 'L' or 'R'\n\n" "trans 'N', 'T', or 'C'n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "k integer. k <= m if side = 'R' and k <= n if side = 'L'.\n" " If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m) if side = 'L'\n" " and ldA >= max(1,n) if side = 'R'. If zero, the\n" " default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* unmqr(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau, *C; int m=-1, n=-1, k=-1, ldA=0, ldC=0, oA=0, oC=0, info, lwork; void *work; number wl; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', trans_ = 'N'; #endif char side = 'L', trans = 'N'; char *kwlist[] = {"A", "tau", "C", "side", "trans", "m", "n", "k", "ldA", "ldC", "offsetA", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCiiiiiii", kwlist, &A, &tau, &C, &side_, &trans_, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; side = (char) side_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cciiiiiii", kwlist, &A, &tau, &C, &side, &trans, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(tau) || MAT_ID(A) != MAT_ID(C)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (m < 0) m = C->nrows; if (n < 0) n = C->ncols; if (k < 0) k = len(tau); if (m == 0 || n == 0 || k == 0) return Py_BuildValue(""); if (k > ((side == 'L') ? m : n)) err_ld("k"); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < ((side == 'L') ? MAX(1,m) : MAX(1,n))) err_ld("ldA"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,m)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (oA + k*ldA > len(A)) err_buf_len("A"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: if (trans == 'C') trans = 'T'; lwork = -1; Py_BEGIN_ALLOW_THREADS dormqr_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL, &ldC, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dormqr_(&side, &trans, &m, &n, &k, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(tau), MAT_BUFD(C)+oC, &ldC, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: if (trans == 'T') err_char("trans", "'N', 'C'"); lwork = -1; Py_BEGIN_ALLOW_THREADS zunmqr_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL, &ldC, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS zunmqr_(&side, &trans, &m, &n, &k, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(tau), MAT_BUFZ(C)+oC, &ldC, (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_orgqr[] = "Generate the orthogonal matrix in a QR factorization.\n\n" "ormqr(A, tau, m=A.size[0], n=min(A.size), k=len(tau), \n" " ldA=max(1,A.size[0]), offsetA=0)\n\n" "PURPOSE\n" "On entry, A and tau contain an m by m orthogonal matrix Q.\n" "Q is defined as a product of k elementary reflectors, stored in the\n" "first k columns of A and in tau, as computed by geqrf(). On exit,\n" "the first n columns of Q are stored in the leading columns of A.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "tau 'd' matrix of length at least k\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. n <= m. If negative, the default value is used." "\n\n" "k integer. k <= n. If negative, the default value is \n" " used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* orgqr(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau; int m=-1, n=-1, k=-1, ldA=0, oA=0, info, lwork; void *work; number wl; char *kwlist[] = {"A", "tau", "m", "n", "k", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &A, &tau, &m, &n, &k, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids; if (m < 0) m = A->nrows; if (n < 0) n = MIN(A->nrows, A->ncols); if (n > m) err_ld("n"); if (k < 0) k = len(tau); if (k > n) err_ld("k"); if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < MAX(1, m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + n*ldA > len(A)) err_buf_len("A"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dorgqr_(&m, &n, &k, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dorgqr_(&m, &n, &k, MAT_BUFD(A) + oA, &ldA, MAT_BUFD(tau), (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_ungqr[] = "Generate the orthogonal or unitary matrix in a QR factorization.\n\n" "ungqr(A, tau, m=A.size[0], n=min(A.size), k=len(tau), \n" " ldA=max(1,A.size[0]), offsetA=0)\n\n" "PURPOSE\n" "On entry, A and tau contain an m by m orthogonal/unitary matrix Q.\n" "Q is defined as a product of k elementary reflectors, stored in the\n" "first k columns of A and in tau, as computed by geqrf(). On exit,\n" "the first n columns of Q are stored in the leading columns of A.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "tau 'd' or 'z' matrix of length at least k. Must have the\n" " same type as A.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. n <= m. If negative, the default value is used." "\n\n" "k integer. k <= n. If negative, the default value is \n" " used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* ungqr(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau; int m=-1, n=-1, k=-1, ldA=0, oA=0, info, lwork; void *work; number wl; char *kwlist[] = {"A", "tau", "m", "n", "k", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &A, &tau, &m, &n, &k, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids; if (m < 0) m = A->nrows; if (n < 0) n = MIN(A->nrows, A->ncols); if (n > m) err_ld("n"); if (k < 0) k = len(tau); if (k > n) err_ld("k"); if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < MAX(1, m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + n*ldA > len(A)) err_buf_len("A"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dorgqr_(&m, &n, &k, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dorgqr_(&m, &n, &k, MAT_BUFD(A) + oA, &ldA, MAT_BUFD(tau), (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zungqr_(&m, &n, &k, NULL, &ldA, NULL, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS zungqr_(&m, &n, &k, MAT_BUFZ(A) + oA, &ldA, MAT_BUFZ(tau), (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_gelqf[] = "LQ factorization.\n\n" "gelqf(A, tau, m=A.size[0], n=A.size[1], ldA=max(1,A.size[0]),\n" " offsetA=0)\n\n" "PURPOSE\n" "LQ factorization of an m by n real or complex matrix A:\n\n" "A = L*Q = [L1; 0] * [Q1; Q2] if m <= n\n" "A = L*Q = [L1; L2] * Q if m >= n,\n\n" "where Q is n by n and orthogonal/unitary and L is m by n with L1\n" "lower triangular. On exit, L is stored in the lower triangular\n" "part of A. Q is stored as a product of k=min(m,n) elementary\n" "reflectors. The parameters of the reflectors are stored in the\n" "first k entries of tau and in the upper triangular part of the\n" "first k rows of A.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "tau 'd' or 'z' matrix of length at least min(m,n). Must\n" " have the same type as A.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* gelqf(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau; int m=-1, n=-1, ldA=0, oA=0, info, lwork; void *work; number wl; char *kwlist[] = {"A", "tau", "m", "n", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, &A, &tau, &m, &n, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids; if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (len(tau) < MIN(m,n)) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dgelqf_(&m, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dgelqf_(&m, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(tau), (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zgelqf_(&m, &n, NULL, &ldA, NULL, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS zgelqf_(&m, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(tau), (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_ormlq[] = "Product with a real orthogonal matrix.\n\n" "ormlq(A, tau, C, side='L', trans='N', m=C.size[0], n=C.size[1],\n" " k=min(A.size), ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n" " offsetA=0, offsetC=0)\n\n" "PURPOSE\n" "Computes\n" "C := Q*C if side = 'L' and trans = 'N'.\n" "C := Q^T*C if side = 'L' and trans = 'T'.\n" "C := C*Q if side = 'R' and trans = 'N'.\n" "C := C*Q^T if side = 'R' and trans = 'T'.\n" "C is m by n and Q is a square orthogonal matrix computed by gelqf." "\n" "Q is defined as a product of k elementary reflectors, stored as\n" "the first k rows of A and the first k entries of tau.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "tau 'd' matrix of length at least k\n\n" "C 'd' matrix\n\n" "side 'L' or 'R'\n\n" "trans 'N' or 'T'\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "k integer. k <= m if side = 'L' and k <= n if side = 'R'.\n" " If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,k). If zero, the\n" " default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* ormlq(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau, *C; int m=-1, n=-1, k=-1, ldA=0, ldC=0, oA=0, oC=0, info, lwork; void *work; number wl; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', trans_ = 'N'; #endif char side = 'L', trans = 'N'; char *kwlist[] = {"A", "tau", "C", "side", "trans", "m", "n", "k", "ldA", "ldC", "offsetA", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCiiiiiii", kwlist, &A, &tau, &C, &side_, &trans_, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; side = (char) side_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cciiiiiii", kwlist, &A, &tau, &C, &side, &trans, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(tau) || MAT_ID(A) != MAT_ID(C)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (trans != 'N' && trans != 'T') err_char("trans", "'N', 'T'"); if (m < 0) m = C->nrows; if (n < 0) n = C->ncols; if (k < 0) k = MIN(A->nrows, A->ncols); if (m == 0 || n == 0 || k == 0) return Py_BuildValue(""); if (k > ((side == 'L') ? m : n)) err_ld("k"); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,k)) err_ld("ldA"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,m)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (oA + ldA * ((side == 'L') ? m : n) > len(A)) err_buf_len("A"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dormlq_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL, &ldC, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dormlq_(&side, &trans, &m, &n, &k, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(tau), MAT_BUFD(C)+oC, &ldC, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_unmlq[] = "Product with a real or complex orthogonal matrix.\n\n" "unmlq(A, tau, C, side='L', trans='N', m=C.size[0], n=C.size[1],\n" " k=min(A.size), ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n" " offsetA=0, offsetC=0)\n\n" "PURPOSE\n" "Computes\n" "C := Q*C if side = 'L' and trans = 'N'.\n" "C := Q^T*C if side = 'L' and trans = 'T'.\n" "C := Q^H*C if side = 'L' and trans = 'C'.\n" "C := C*Q if side = 'R' and trans = 'N'.\n" "C := C*Q^T if side = 'R' and trans = 'T'.\n" "C := C*Q^H if side = 'R' and trans = 'C'.\n" "C is m by n and Q is a square orthogonal/unitary matrix computed\n" "by gelqf. Q is defined as a product of k elementary reflectors,\n" "stored as the first k rows of A and the first k entries of tau." "\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "tau 'd' or 'z' matrix of length at least k. Must have the\n" " same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "side 'L' or 'R'\n\n" "trans 'N', 'T', or 'C'n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "k integer. k <= m if side = 'R' and k <= n if side = 'L'.\n" " If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,k). If zero, the\n" " default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* unmlq(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau, *C; int m=-1, n=-1, k=-1, ldA=0, ldC=0, oA=0, oC=0, info, lwork; void *work; number wl; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', trans_ = 'N'; #endif char side = 'L', trans = 'N'; char *kwlist[] = {"A", "tau", "C", "side", "trans", "m", "n", "k", "ldA", "ldC", "offsetA", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCiiiiiii", kwlist, &A, &tau, &C, &side_, &trans_, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; side = (char) side_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cciiiiiii", kwlist, &A, &tau, &C, &side, &trans, &m, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(tau) || MAT_ID(A) != MAT_ID(C)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (m < 0) m = C->nrows; if (n < 0) n = C->ncols; if (k < 0) k = MIN(A->nrows, A->ncols); if (m == 0 || n == 0 || k == 0) return Py_BuildValue(""); if (k > ((side == 'L') ? m : n)) err_ld("k"); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,k)) err_ld("ldA"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,m)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (oA + ldA * ((side == 'L') ? m : n) > len(A)) err_buf_len("A"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: if (trans == 'C') trans = 'T'; lwork = -1; Py_BEGIN_ALLOW_THREADS dormlq_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL, &ldC, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dormlq_(&side, &trans, &m, &n, &k, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(tau), MAT_BUFD(C)+oC, &ldC, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: if (trans == 'T') err_char("trans", "'N', 'C'"); lwork = -1; Py_BEGIN_ALLOW_THREADS zunmlq_(&side, &trans, &m, &n, &k, NULL, &ldA, NULL, NULL, &ldC, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS zunmlq_(&side, &trans, &m, &n, &k, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(tau), MAT_BUFZ(C)+oC, &ldC, (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_orglq[] = "Generate the orthogonal matrix in an LQ factorization.\n\n" "orglq(A, tau, m=min(A.size), n=A.size[1], k=len(tau), \n" " ldA=max(1,A.size[0]), offsetA=0)\n\n" "PURPOSE\n" "On entry, A and tau contain an n by n orthogonal matrix Q.\n" "Q is defined as a product of k elementary reflectors, stored in the\n" "first k rows of A and in tau, as computed by gelqf(). On exit,\n" "the first m rows of Q are stored in the leading rows of A.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "tau 'd' matrix of length at least k\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. n >= m. If negative, the default value is used." "\n\n" "k integer. k <= m. If negative, the default value is \n" " used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* orglq(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau; int m=-1, n=-1, k=-1, ldA=0, oA=0, info, lwork; void *work; number wl; char *kwlist[] = {"A", "tau", "m", "n", "k", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &A, &tau, &m, &n, &k, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids; if (m < 0) m = MIN(A->nrows, A->ncols); if (n < 0) n = A->ncols; if (m > n) err_ld("n"); if (k < 0) k = len(tau); if (k > m) err_ld("k"); if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < MAX(1, m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + n*ldA > len(A)) err_buf_len("A"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dorglq_(&m, &n, &k, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dorglq_(&m, &n, &k, MAT_BUFD(A) + oA, &ldA, MAT_BUFD(tau), (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_unglq[] = "Generate the orthogonal or unitary matrix in an LQ factorization.\n\n" "unglq(A, tau, m=min(A.size), n=A.size[1], k=len(tau), \n" " ldA=max(1,A.size[0]), offsetA=0)\n\n" "PURPOSE\n" "On entry, A and tau contain an n by n orthogonal/unitary matrix Q.\n" "Q is defined as a product of k elementary reflectors, stored in the\n" "first k rows of A and in tau, as computed by gelqf(). On exit,\n" "the first m rows of Q are stored in the leading rows of A.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "tau 'd' or 'z' matrix of length at least k. Must have the\n" " same type as A.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. n >= m. If negative, the default value is used." "\n\n" "k integer. k <= m. If negative, the default value is \n" " used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* unglq(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau; int m=-1, n=-1, k=-1, ldA=0, oA=0, info, lwork; void *work; number wl; char *kwlist[] = {"A", "tau", "m", "n", "k", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &A, &tau, &m, &n, &k, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids; if (m < 0) m = MIN(A->nrows, A->ncols); if (n < 0) n = A->ncols; if (m > n) err_ld("n"); if (k < 0) k = len(tau); if (k > m) err_ld("k"); if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < MAX(1, m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + n*ldA > len(A)) err_buf_len("A"); if (len(tau) < k) err_buf_len("tau"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dorglq_(&m, &n, &k, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dorglq_(&m, &n, &k, MAT_BUFD(A) + oA, &ldA, MAT_BUFD(tau), (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zunglq_(&m, &n, &k, NULL, &ldA, NULL, &wl.z, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); if (!(work = (void *) calloc(lwork, sizeof(complex)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS zunglq_(&m, &n, &k, MAT_BUFZ(A) + oA, &ldA, MAT_BUFZ(tau), (complex *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_geqp3[] = "QR factorization with column pivoting.\n\n" "geqp3(A, jpvt, tau, m=A.size[0], n=A.size[1], ldA=max(1,A.size[0]),\n" " offsetA=0)\n\n" "PURPOSE\n" "QR factorization with column pivoting of an m by n real or complex\n" "matrix A:\n\n" "A*P = Q*R = [Q1 Q2] * [R1; 0] if m >= n\n" "A*P = Q*R = Q * [R1 R2] if m <= n,\n\n" "where P is a permutation matrix, Q is m by m and orthogonal/unitary\n" "and R is m by n with R1 upper triangular. On exit, R is stored in\n" "the upper triangular part of A. Q is stored as a product of\n" "k=min(m,n) elementary reflectors. The parameters of the\n" "reflectors are stored in the first k entries of tau and in the\n" "lower triangular part of the first k columns of A. On entry, if\n" "jpvt[j] is nonzero, the jth column of A is permuted to the front of\n" "A*P. If jpvt[j] is zero, the jth column is a free column. On exit\n" "A*P = A[:, jpvt - 1].\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "jpvt 'i' matrix of length n\n\n" "tau 'd' or 'z' matrix of length min(m,n). Must have the same\n" " type as A.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer"; static PyObject* geqp3(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *tau, *jpvt; int m=-1, n=-1, ldA=0, oA=0, info, lwork; double *rwork = NULL; void *work = NULL; number wl; char *kwlist[] = {"A", "jpvt", "tau", "m", "n", "ldA", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iiii", kwlist, &A, &jpvt, &tau, &m, &n, &ldA, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(jpvt) || jpvt ->id != INT) err_int_mtrx("jpvt"); if (!Matrix_Check(tau)) err_mtrx("tau"); if (MAT_ID(A) != MAT_ID(tau)) err_conflicting_ids; if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (len(jpvt) < n) err_buf_len("jpvt"); if (len(tau) < MIN(m,n)) err_buf_len("tau"); int i; #if (SIZEOF_INT < SIZEOF_LONG) int *jpvt_ptr = malloc(n*sizeof(int)); if (!jpvt_ptr) return PyErr_NoMemory(); for (i=0; i= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* syev(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W; int n=-1, ldA=0, oA=0, oW=0, info, lwork; double *work; number wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N'; #endif char uplo = 'L', jobz = 'N'; char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", "offsetW", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCiiii", kwlist, &A, &W, &jobz_, &uplo_, &n, &ldA, &oA, &oW)) return NULL; jobz = (char) jobz_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist, &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue("i",0); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); switch (MAT_ID(A)){ case DOUBLE: lwork=-1; Py_BEGIN_ALLOW_THREADS dsyev_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dsyev_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(W)+oW, work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_heev[] = "Eigenvalue decomposition of a real symmetric or complex Hermitian" "\nmatrix.\n\n" "heev(A, W, jobz='N', uplo='L', n=A.size[0], " "ldA = max(1,A.size[0]),\n" " offsetA=0, offsetW=0)\n\n" "PURPOSE\n" "Returns eigenvalues/vectors of a real symmetric or complex\n" "Hermitian nxn matrix A. On exit, W contains the eigenvalues in\n" "ascending order. If jobz is 'V', the (normalized) eigenvectors\n" "are also computed and returned in A. If jobz is 'N', only the\n" "eigenvalues are computed, and the content of A is destroyed.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "W 'd' matrix of length at least n\n\n" "jobz 'N' or 'V'\n\n" "uplo 'L' or 'U'\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* heev(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W; int n=-1, ldA=0, oA=0, oW=0, info, lwork; double *rwork=NULL; void *work=NULL; number wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N'; #endif char uplo = 'L', jobz = 'N'; char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", "offsetW", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCiiii", kwlist, &A, &W, &jobz_, &uplo_, &n, &ldA, &oA, &oW)) return NULL; jobz = (char) jobz_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist, &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); switch (MAT_ID(A)){ case DOUBLE: lwork=-1; Py_BEGIN_ALLOW_THREADS dsyev_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dsyev_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(W)+oW, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork=-1; Py_BEGIN_ALLOW_THREADS zheev_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); work = (void *) calloc(lwork, sizeof(complex)); rwork = (double *) calloc(3*n-2, sizeof(double)); if (!work || !rwork){ free(work); free(rwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zheev_(&jobz, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFD(W)+oW, (complex *) work, &lwork, rwork, &info); Py_END_ALLOW_THREADS free(work); free(rwork); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_syevx[] = "Computes selected eigenvalues and eigenvectors of a real symmetric" "\nmatrix (expert driver).\n\n" "m = syevx(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n" " il=1, iu=1, Z=None, n=A.size[0], ldA=max(1,A.size[0]),\n" " ldZ=None, abstol=0.0, offsetA=0, offsetW=0,\n" " offsetZ=0)\n\n" "PURPOSE\n" "Computes selected eigenvalues/vectors of a real symmetric n by n\n" "matrix A.\n" "If range is 'A', all eigenvalues are computed.\n" "If range is 'V', all eigenvalues in the interval (vl,vu] are\n" "computed.\n" "If range is 'I', all eigenvalues il through iu are computed\n" "(sorted in ascending order with 1 <= il <= iu <= n).\n" "If jobz is 'N', only the eigenvalues are returned in W.\n" "If jobz is 'V', the eigenvectors are also returned in Z.\n" "On exit, the content of A is destroyed.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "W 'd' matrix of length at least n. On exit, contains\n" " the computed eigenvalues in ascending order.\n\n" "jobz 'N' or 'V'\n\n" "range 'A', 'V' or 'I'\n\n" "uplo 'L' or 'U'\n\n" "vl,vu doubles. Only required when range is 'V'.\n\n" "il,iu integers. Only required when range is 'I'.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n). If zero, the\n" " default value is used.\n\n" "Z 'd' matrix. Only required when jobz is 'V'. If range\n" " is 'A' or 'V', Z must have at least n columns. If\n" " range is 'I', Z must have at least iu-il+1 columns.\n" " On exit the first m columns of Z contain the computed\n" " (normalized) eigenvectors.\n\n" "abstol double. Absolute error tolerance for eigenvalues.\n" " If nonpositive, the LAPACK default value is used.\n\n" "ldZ nonnegative integer. ldZ >= 1 if jobz is 'N' and\n" " ldZ >= max(1,n) if jobz is 'V'. The default value\n" " is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetW nonnegative integer\n\n" "offsetZ nonnegative integer\n\n" "m the number of eigenvalues computed"; static PyObject* syevx(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W, *Z=NULL; int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, lwork, *iwork, m, *ifail=NULL; double *work, vl=0.0, vu=0.0, abstol=0.0; double wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N', range_ = 'A'; #endif char uplo = 'L', jobz = 'N', range = 'A'; char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu", "il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", "offsetW", "offsetZ", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCddiiOiiidiii", kwlist, &A, &W, &jobz_, &range_, &uplo_, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; jobz = (char) jobz_; range = (char) range_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii", kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (range != 'A' && range != 'V' && range != 'I') err_char("range", "'A', 'V', 'I'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue("i",0); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (range == 'V' && vl >= vu){ PyErr_SetString(PyExc_ValueError, "vl must be less than vu"); return NULL; } if (range == 'I' && (il < 1 || il > iu || iu > n)){ PyErr_SetString(PyExc_ValueError, "il and iu must satisfy " "1 <= il <= iu <= n"); return NULL; } if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); if (jobz == 'V'){ if (!Z || !Matrix_Check(Z) || MAT_ID(Z) != DOUBLE) err_dbl_mtrx("Z"); if (ldZ == 0) ldZ = MAX(1,Z->nrows); if (ldZ < MAX(1,n)) err_ld("ldZ"); if (oZ < 0) err_nn_int("offsetZ"); if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) err_buf_len("Z"); } else { if (ldZ == 0) ldZ = 1; if (ldZ < 1) err_ld("ldZ"); } switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dsyevx_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il, &iu, &abstol, &m, NULL, NULL, &ldZ, &wl, &lwork, NULL, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) wl; work = (double *) calloc(lwork, sizeof(double)); iwork = (int *) calloc(5*n, sizeof(int)); if (jobz == 'V') ifail = (int *) calloc(n, sizeof(int)); if (!work || !iwork || (jobz == 'V' && !ifail)){ free(work); free(iwork); free(ifail); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsyevx_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl, &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, (jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL, &ldZ, work, &lwork, iwork, ifail, &info); Py_END_ALLOW_THREADS free(work); free(iwork); free(ifail); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue("i", m); } static char doc_heevx[] = "Computes selected eigenvalues and eigenvectors of a real symmetric" "\nor complex Hermitian matrix (expert driver).\n\n" "m = syevx(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n" " il=1, iu=1, Z=None, n=A.size[0], \n" " ldA = max(1,A.size[0]), ldZ=None, abstol=0.0, \n" " offsetA=0, offsetW=0, offsetZ=0)\n\n" "PURPOSE\n" "Computes selected eigenvalues/vectors of a real symmetric or\n" "complex Hermitian n by n matrix A.\n" "If range is 'A', all eigenvalues are computed.\n" "If range is 'V', all eigenvalues in the interval (vl,vu] are\n" "computed.\n" "If range is 'I', all eigenvalues il through iu are computed\n" "(sorted in ascending order with 1 <= il <= iu <= n).\n" "If jobz is 'N', only the eigenvalues are returned in W.\n" "If jobz is 'V', the eigenvectors are also returned in Z.\n" "On exit, the content of A is destroyed.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "W 'd' matrix of length at least n. On exit, contains\n" " the computed eigenvalues in ascending order.\n\n" "jobz 'N' or 'V'\n\n" "range 'A', 'V' or 'I'\n\n" "uplo 'L' or 'U'\n\n" "vl,vu doubles. Only required when range is 'V'.\n\n" "il,iu integers. Only required when range is 'I'.\n\n" "Z 'd' or 'z' matrix. Must have the same type as A.\n" " Z is only required when jobz is 'V'. If range is 'A'\n" " or 'V', Z must have at least n columns. If range is\n" " 'I', Z must have at least iu-il+1 columns. On exit\n" " the first m columns of Z contain the computed\n" " (normalized) eigenvectors.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n). If zero, the\n" " default value is used.\n\n" "ldZ nonnegative integer. ldZ >= 1 if jobz is 'N' and\n" " ldZ >= max(1,n) if jobz is 'V'. The default value\n" " is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n" " If zero, the default value is used.\n\n" "abstol double. Absolute error tolerance for eigenvalues.\n" " If nonpositive, the LAPACK default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetW nonnegative integer\n\n" "offsetZ nonnegative integer\n\n" "m the number of eigenvalues computed"; static PyObject* heevx(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W, *Z=NULL; int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, lwork, *iwork, m, *ifail=NULL; double vl=0.0, vu=0.0, abstol=0.0, *rwork; number wl; void *work; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N', range_ = 'A'; #endif char uplo = 'L', jobz = 'N', range = 'A'; char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu", "il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", "offsetW", "offsetZ", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCddiiOiiidiii", kwlist, &A, &W, &jobz_, &range_, &uplo_, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; jobz = (char) jobz_; range = (char) range_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii", kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (range != 'A' && range != 'V' && range != 'I') err_char("range", "'A', 'V', 'I'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue("i",0); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (range == 'V' && vl >= vu){ PyErr_SetString(PyExc_ValueError, "vl must be less than vu"); return NULL; } if (range == 'I' && (il < 1 || il > iu || iu > n)){ PyErr_SetString(PyExc_ValueError, "il and iu must satisfy " "1 <= il <= iu <= n"); return NULL; } if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); if (jobz == 'V'){ if (!Z || !Matrix_Check(Z)) err_mtrx("Z"); if (MAT_ID(Z) != MAT_ID(A)) err_conflicting_ids; if (ldZ == 0) ldZ = MAX(1,Z->nrows); if (ldZ < MAX(1,n)) err_ld("ldZ"); if (oZ < 0) err_nn_int("offsetZ"); if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) err_buf_len("Z"); } else { if (ldZ == 0) ldZ = 1; if (ldZ < 1) err_ld("ldZ"); } switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dsyevx_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il, &iu, &abstol, &m, NULL, NULL, &ldZ, &wl.d, &lwork, NULL, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; work = (void *) calloc(lwork, sizeof(double)); iwork = (int *) calloc(5*n, sizeof(int)); if (jobz == 'V') ifail = (int *) calloc(n, sizeof(int)); if (!work || !iwork || (jobz == 'V' && !ifail)){ free(work); free(iwork); free(ifail); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsyevx_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl, &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, (jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL, &ldZ, (double *) work, &lwork, iwork, ifail, &info); Py_END_ALLOW_THREADS free(work); free(iwork); free(ifail); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zheevx_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il, &iu, &abstol, &m, NULL, NULL, &ldZ, &wl.z, &lwork, NULL, NULL, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); work = (void *) calloc(lwork, sizeof(complex)); rwork = (double *) calloc(7*n, sizeof(double)); iwork = (int *) calloc(5*n, sizeof(int)); if (jobz == 'V') ifail = (int *) calloc(n, sizeof(int)); if (!work || !rwork || !iwork || (jobz == 'V' && !ifail)){ free(work); free(rwork); free(iwork); free(ifail); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zheevx_(&jobz, &range, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, &vl, &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, (jobz == 'V') ? MAT_BUFZ(Z)+oZ : NULL, &ldZ, (complex *) work, &lwork, rwork, iwork, ifail, &info); Py_END_ALLOW_THREADS free(work); free(rwork); free(iwork); free(ifail); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue("i", m); } static char doc_syevd[] = "Eigenvalue decomposition of a real symmetric matrix\n" "(divide-and-conquer driver).\n\n" "syevd(A, W, jobz='N', uplo='L', n=A.size[0], " "ldA = max(1,A.size[0]),\n" " offsetA=0, offsetW=0)\n\n" "PURPOSE\n" "Returns eigenvalues/vectors of a real symmetric nxn matrix A.\n" "On exit, W contains the eigenvalues in ascending order.\n" "If jobz is 'V', the (normalized) eigenvectors are also computed\n" "and returned in A. If jobz is 'N', only the eigenvalues are\n" "computed, and the content of A is destroyed.\n" "\n\nARGUMENTS\n" "A 'd' matrix\n\n" "W 'd' matrix of length at least n. On exit, contains\n" " the computed eigenvalues in ascending order.\n\n" "jobz 'N' or 'V'\n\n" "uplo 'L' or 'U'\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* syevd(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W; int n=-1, ldA=0, oA=0, oW=0, info, lwork, liwork, *iwork, iwl; double *work=NULL, wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N'; #endif char uplo = 'L', jobz = 'N'; char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", "offsetW", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCiiii", kwlist, &A, &W, &jobz_, &uplo_, &n, &ldA, &oA, &oW)) return NULL; uplo = (char) uplo_; jobz = (char) jobz_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist, &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || W->id != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; liwork = -1; Py_BEGIN_ALLOW_THREADS dsyevd_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl, &lwork, &iwl, &liwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl; liwork = iwl; work = (double *) calloc(lwork, sizeof(double)); iwork = (int *) calloc(liwork, sizeof(int)); if (!work || !iwork){ free(work); free(iwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsyevd_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(W)+oW, work, &lwork, iwork, &liwork, &info); Py_END_ALLOW_THREADS free(work); free(iwork); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_heevd[] = "Eigenvalue decomposition of a real symmetric or complex Hermitian" "\nmatrix (divide-and-conquer driver).\n\n" "heevd(A, W, jobz='N', uplo='L', n=A.size[0], " "ldA = max(1,A.size[0]),\n" " offsetA=0, offsetW=0)\n\n" "PURPOSE\n" "Returns eigenvalues/vectors of a real symmetric or complex\n" "Hermitian n by n matrix A. On exit, W contains the eigenvalues\n" "in ascending order. If jobz is 'V', the (normalized) eigenvectors" "\nare also computed and returned in A. If jobz is 'N', only the\n" "eigenvalues are computed, and the content of A is destroyed.\n" "\n\nARGUMENTS\n" "A 'd' matrix\n\n" "W 'd' matrix of length at least n. On exit, contains\n" " the computed eigenvalues in ascending order.\n\n" "jobz 'N' or 'V'\n\n" "uplo 'L' or 'U'\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* heevd(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W; int n=-1, ldA=0, oA=0, oW=0, info, lwork, liwork, *iwork, iwl, lrwork; double *rwork, rwl; number wl; void *work; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N'; #endif char uplo = 'L', jobz = 'N'; char *kwlist[] = {"A", "W", "jobz", "uplo", "n", "ldA", "offsetA", "offsetW", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCiiii", kwlist, &A, &W, &jobz_, &uplo_, &n, &ldA, &oA, &oW)) return NULL; jobz = (char) jobz_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cciiii", kwlist, &A, &W, &jobz, &uplo, &n, &ldA, &oA, &oW)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || W->id != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); switch (MAT_ID(A)){ case DOUBLE: lwork = -1; liwork = -1; Py_BEGIN_ALLOW_THREADS dsyevd_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.d, &lwork, &iwl, &liwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; liwork = iwl; work = (void *) calloc(lwork, sizeof(double)); iwork = (int *) calloc(liwork, sizeof(int)); if (!work || !iwork){ free(work); free(iwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsyevd_(&jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(W)+oW, (double *) work, &lwork, iwork, &liwork, &info); Py_END_ALLOW_THREADS free(work); free(iwork); break; case COMPLEX: lwork = -1; liwork = -1; lrwork = -1; Py_BEGIN_ALLOW_THREADS zheevd_(&jobz, &uplo, &n, NULL, &ldA, NULL, &wl.z, &lwork, &rwl, &lrwork, &iwl, &liwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; lrwork = (int) rwl; liwork = iwl; work = (void *) calloc(lwork, sizeof(complex)); rwork = (double *) calloc(lrwork, sizeof(double)); iwork = (int *) calloc(liwork, sizeof(int)); if (!work || !rwork || !iwork){ free(work); free(rwork); free(iwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zheevd_(&jobz, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFD(W)+oW, (complex *) work, &lwork, rwork, &lrwork, iwork, &liwork, &info); Py_END_ALLOW_THREADS free(work); free(rwork); free(iwork); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_syevr[] = "Computes selected eigenvalues and eigenvectors of a real symmetric" "\n" "matrix (RRR driver).\n\n" "m = syevr(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n" " il=1, iu=1, Z=None, n=A.size[0], ldA=max(1,A.size[0]),\n" " ldZ=None, abstol=0.0, offsetA=0, offsetW=0, offsetZ=0)\n" "\n" "PURPOSE\n" "Computes selected eigenvalues/vectors of a real symmetric n by n\n" "matrix A.\n" "If range is 'A', all eigenvalues are computed.\n" "If range is 'V', all eigenvalues in the interval (vl,vu] are\n" "computed.\n" "If range is 'I', all eigenvalues il through iu are computed\n" "(sorted in ascending order with 1 <= il <= iu <= n).\n" "If jobz is 'N', only the eigenvalues are returned in W.\n" "If jobz is 'V', the eigenvectors are also returned in Z.\n" "On exit, the content of A is destroyed.\n" "syevr is usually the fastest of the four eigenvalue routines.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "W 'd' matrix of length at least n. On exit, contains\n" " the computed eigenvalues in ascending order.\n\n" "jobz 'N' or 'V'\n\n" "range 'A', 'V' or 'I'\n\n" "uplo 'L' or 'U'\n\n" "vl,vu doubles. Only required when range is 'V'.\n\n" "il,iu integers. Only required when range is 'I'.\n\n" "Z 'd' matrix. Only required when jobz = 'V'.\n" " If range is 'A' or 'V', Z must have at least n columns." "\n" " If range is 'I', Z must have at least iu-il+1 columns.\n" " On exit the first m columns of Z contain the computed\n" " (normalized) eigenvectors.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "ldZ nonnegative integer. ldZ >= 1 if jobz is 'N' and\n" " ldZ >= max(1,n) if jobz is 'V'. The default value\n" " is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n" " If zero, the default value is used.\n\n" "abstol double. Absolute error tolerance for eigenvalues.\n" " If nonpositive, the LAPACK default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetW nonnegative integer\n\n" "offsetZ nonnegative integer\n\n" "m the number of eigenvalues computed"; static PyObject* syevr(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W, *Z=NULL; int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, lwork, *iwork=NULL, liwork, m, *isuppz=NULL, iwl; double *work=NULL, vl=0.0, vu=0.0, abstol=0.0, wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N', range_ = 'A'; #endif char uplo = 'L', jobz = 'N', range = 'A'; char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu", "il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", "offsetW", "offsetZ", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCddiiOiiidiii", kwlist, &A, &W, &jobz_, &range_, &uplo_, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; jobz = (char) jobz_; range = (char) range_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii", kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (range != 'A' && range != 'V' && range != 'I') err_char("range", "'A', 'V', 'I'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue("i",0); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (range == 'V' && vl >= vu){ PyErr_SetString(PyExc_ValueError, "vl must be less than vu"); return NULL; } if (range == 'I' && (il < 1 || il > iu || iu > n)){ PyErr_SetString(PyExc_ValueError, "il and iu must satisfy " "1 <= il <= iu <= n"); return NULL; } if (jobz == 'V'){ if (!Z || !Matrix_Check(Z) || MAT_ID(Z) != DOUBLE) err_dbl_mtrx("Z"); if (ldZ == 0) ldZ = MAX(1,Z->nrows); if (ldZ < MAX(1,n)) err_ld("ldZ"); } else { if (ldZ == 0) ldZ = 1; if (ldZ < 1) err_ld("ldZ"); } if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); if (jobz == 'V'){ if (oZ < 0) err_nn_int("offsetZ"); if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) err_buf_len("Z"); } switch (MAT_ID(A)){ case DOUBLE: lwork = -1; liwork = -1; Py_BEGIN_ALLOW_THREADS dsyevr_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il, &iu, &abstol, &m, NULL, NULL, &ldZ, NULL, &wl, &lwork, &iwl, &liwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl; liwork = iwl; work = (void *) calloc(lwork, sizeof(double)); iwork = (int *) calloc(liwork, sizeof(int)); if (jobz == 'V') isuppz = (int *) calloc(2*MAX(1, (range == 'I') ? iu-il+1 : n), sizeof(int)); if (!work || !iwork || (jobz == 'V' && !isuppz)){ free(work); free(iwork); free(isuppz); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsyevr_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl, &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, (jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL, &ldZ, (jobz == 'V') ? isuppz : NULL, work, &lwork, iwork, &liwork, &info); Py_END_ALLOW_THREADS free(work); free(iwork); free(isuppz); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue("i",m); } static char doc_heevr[] = "Computes selected eigenvalues and eigenvectors of a real symmetric" "\nor complex Hermitian matrix (RRR driver).\n\n" "m = syevr(A, W, jobz='N', range='A', uplo='L', vl=0.0, vu=0.0, \n" " il=1, iu=1, Z=None, n=A.size[0], ldA=max(1,A.size[0]),\n" " ldZ=None, abstol=0.0, offsetA=0, offsetW=0, offsetZ=0)\n" "\n" "PURPOSE\n" "Computes selected eigenvalues/vectors of a real symmetric or\n" "complex Hermitian n by n matrix A.\n" "If range is 'A', all eigenvalues are computed.\n" "If range is 'V', all eigenvalues in the interval (vl,vu] are\n" "computed.\n" "If range is 'I', all eigenvalues il through iu are computed\n" "(sorted in ascending order with 1 <= il <= iu <= n).\n" "If jobz is 'N', only the eigenvalues are returned in W.\n" "If jobz is 'V', the eigenvectors are also returned in Z.\n" "On exit, the content of A is destroyed.\n" "syevr is usually the fastest of the four eigenvalue routines.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "W 'd' matrix of length at least n. On exit, contains\n" " the computed eigenvalues in ascending order.\n\n" "jobz 'N' or 'V'\n\n" "range 'A', 'V' or 'I'\n\n" "uplo 'L' or 'U'\n\n" "vl,vu doubles. Only required when range is 'V'.\n\n" "il,iu integers. Only required when range is 'I'.\n\n" "Z 'd' or 'z' matrix. Must have the same type as A.\n" " Only required when jobz = 'V'. If range is 'A' or\n" " 'V', Z must have at least n columns. If range is 'I',\n" " Z must have at least iu-il+1 columns. On exit the\n" " first m columns of Z contain the computed (normalized)\n" " eigenvectors.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "ldZ nonnegative integer. ldZ >= 1 if jobz is 'N' and\n" " ldZ >= max(1,n) if jobz is 'V'. The default value\n" " is 1 if jobz is 'N' and max(1,Z.size[0]) if jobz ='V'.\n" " If zero, the default value is used.\n\n" "abstol double. Absolute error tolerance for eigenvalues.\n" " If nonpositive, the LAPACK default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetW nonnegative integer\n\n" "offsetZ nonnegative integer\n\n" "m the number of eigenvalues computed"; static PyObject* heevr(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *W, *Z=NULL; int n=-1, ldA=0, ldZ=0, il=1, iu=1, oA=0, oW=0, oZ=0, info, lwork, *iwork, liwork, lrwork, m, *isuppz=NULL, iwl; double vl=0.0, vu=0.0, abstol=0.0, *rwork, rwl; void *work; number wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N', range_ = 'A'; #endif char uplo = 'L', jobz = 'N', range = 'A'; char *kwlist[] = {"A", "W", "jobz", "range", "uplo", "vl", "vu", "il", "iu", "Z", "n", "ldA", "ldZ", "abstol", "offsetA", "offsetW", "offsetZ", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCddiiOiiidiii", kwlist, &A, &W, &jobz_, &range_, &uplo_, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; jobz = (char) jobz_; range = (char) range_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cccddiiOiiidiii", kwlist, &A, &W, &jobz, &range, &uplo, &vl, &vu, &il, &iu, &Z, &n, &ldA, &ldZ, &abstol, &oA, &oW, &oZ)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (range != 'A' && range != 'V' && range != 'I') err_char("range", "'A', 'V', 'I'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0) return Py_BuildValue("i",0); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (range == 'V' && vl >= vu){ PyErr_SetString(PyExc_ValueError, "vl must be less than vu"); return NULL; } if (range == 'I' && (il < 1 || il > iu || iu > n)){ PyErr_SetString(PyExc_ValueError, "il and iu must satisfy " "1 <= il <= iu <= n"); return NULL; } if (jobz == 'V'){ if (!Z || !Matrix_Check(Z)) err_mtrx("Z"); if (MAT_ID(Z) != MAT_ID(A)) err_conflicting_ids; if (ldZ == 0) ldZ = MAX(1,Z->nrows); if (ldZ < MAX(1,n)) err_ld("ldZ"); } else { if (ldZ == 0) ldZ = 1; if (ldZ < 1) err_ld("ldZ"); } if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); if (jobz == 'V'){ if (oZ < 0) err_nn_int("offsetZ"); if (oZ + ((range == 'I') ? iu-il : n-1)*ldZ + n > len(Z)) err_buf_len("Z"); } switch (MAT_ID(A)){ case DOUBLE: lwork = -1; liwork = -1; Py_BEGIN_ALLOW_THREADS dsyevr_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il, &iu, &abstol, &m, NULL, NULL, &ldZ, NULL, &wl.d, &lwork, &iwl, &liwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; liwork = iwl; work = (void *) calloc(lwork, sizeof(double)); iwork = (int *) calloc(liwork, sizeof(int)); if (jobz == 'V') isuppz = (int *) calloc(2*MAX(1, (range == 'I') ? iu-il+1 : n), sizeof(int)); if (!work || !iwork || (jobz == 'V' && !isuppz)){ free(work); free(iwork); free(isuppz); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dsyevr_(&jobz, &range, &uplo, &n, MAT_BUFD(A)+oA, &ldA, &vl, &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, (jobz == 'V') ? MAT_BUFD(Z)+oZ : NULL, &ldZ, (jobz == 'V') ? isuppz : NULL, (double *) work, &lwork, iwork, &liwork, &info); Py_END_ALLOW_THREADS free(work); free(iwork); free(isuppz); break; case COMPLEX: lwork = -1; liwork = -1; lrwork = -1; Py_BEGIN_ALLOW_THREADS zheevr_(&jobz, &range, &uplo, &n, NULL, &ldA, &vl, &vu, &il, &iu, &abstol, &m, NULL, NULL, &ldZ, NULL, &wl.z, &lwork, &rwl, &lrwork, &iwl, &liwork, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); lrwork = (int) rwl; liwork = iwl; work = (void *) calloc(lwork, sizeof(complex)); rwork = (double *) calloc(lrwork, sizeof(double)); iwork = (int *) calloc(liwork, sizeof(int)); if (jobz == 'V') isuppz = (int *) calloc(2*MAX(1, (range == 'I') ? iu-il+1 : n), sizeof(int)); if (!work || !rwork || !iwork || (jobz == 'V' && !isuppz)){ free(work); free(rwork); free(iwork); free(isuppz); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zheevr_(&jobz, &range, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, &vl, &vu, &il, &iu, &abstol, &m, MAT_BUFD(W)+oW, (jobz == 'V') ? MAT_BUFZ(Z)+oZ : NULL, &ldZ, (jobz == 'V') ? isuppz : NULL, (complex *) work, &lwork, rwork, &lrwork, iwork, &liwork, &info); Py_END_ALLOW_THREADS free(work); free(rwork); free(iwork); free(isuppz); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue("i",m); } static char doc_sygv[] = "Generalized symmetric-definite eigenvalue decomposition with real" "\n" "matrices.\n\n" "sygv(A, B, W, itype=1, jobz='N', uplo='L', n=A.size[0], \n" " ldA = max(1,A.size[0]), ldB = max(1,B.size[0]), offsetA=0, \n" " offsetB=0, offsetW=0)\n\n" "PURPOSE\n" "Returns eigenvalues/vectors of a real generalized \n" "symmetric-definite eigenproblem of order n, with B positive \n" "definite. \n" "1. If itype is 1: A*x = lambda*B*x.\n" "2. If itype is 2: A*Bx = lambda*x.\n" "3. If itype is 3: B*Ax = lambda*x.\n\n" "On exit, W contains the eigenvalues in ascending order. If jobz\n" "is 'V', the matrix of eigenvectors Z is also computed and\n" "returned in A, normalized as follows: \n" "1. If itype is 1: Z^T*A*Z = diag(W), Z^T*B*Z = I\n" "2. If itype is 2: Z^T*A^{-1}*Z = diag(W)^{-1}, Z^T*B*Z = I\n" "3. If itype is 3: Z^T*A*Z = diag(W), Z^T*B^{-1}*Z = I.\n\n" "If jobz is 'N', only the eigenvalues are computed, and the\n" "contents of A is destroyed. On exit, the matrix B is replaced\n" "by its Cholesky factor.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "B 'd' matrix\n\n" "W 'd' matrix of length at least n\n\n" "itype integer 1, 2, or 3\n\n" "jobz 'N' or 'V'\n\n" "uplo 'L' or 'U'\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n). If zero, the\n" " default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* sygv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *W; int n=-1, itype=1, ldA=0, ldB=0, oA=0, oB=0, oW=0, info, lwork; double *work; number wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N'; #endif char uplo = 'L', jobz = 'N'; char *kwlist[] = {"A", "B", "W", "itype", "jobz", "uplo", "n", "ldA", "ldB", "offsetA", "offsetB", "offsetW", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iCCiiiiii", kwlist, &A, &B, &W, &itype, &jobz_, &uplo_, &n, &ldA, &ldB, &oA, &oB, &oW)) return NULL; jobz = (char) jobz_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|icciiiiii", kwlist, &A, &B, &W, &itype, &jobz, &uplo, &n, &ldA, &ldB, &oA, &oB, &oW)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B) || MAT_ID(B) != MAT_ID(A)) err_conflicting_ids; if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (itype != 1 && itype != 2 && itype != 3) err_char("itype", "1, 2, 3"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } if (A->nrows != n || A->ncols != n){ PyErr_SetString(PyExc_TypeError, "B must have the same " "dimension as A"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (n-1)*ldB + n > len(B)) err_buf_len("B"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); switch (MAT_ID(A)){ case DOUBLE: lwork=-1; Py_BEGIN_ALLOW_THREADS dsygv_(&itype, &jobz, &uplo, &n, NULL, &ldA, NULL, &ldB, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dsygv_(&itype, &jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, MAT_BUFD(W)+oW, work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_hegv[] = "Generalized symmetric-definite eigenvalue decomposition with\n" "real or complex matrices.\n\n" "hegv(A, B, W, itype=1, jobz='N', uplo='L', n=A.size[0], \n" " ldA = max(1,A.size[0]), ldB = max(1,B.size[0]), offsetA=0, \n" " offsetB=0, offsetW=0)\n\n" "PURPOSE\n" "Returns eigenvalues/vectors of a real or complex generalized\n" "symmetric-definite eigenproblem of order n, with B positive\n" "definite. \n" "1. If itype is 1: A*x = lambda*B*x.\n" "2. If itype is 2: A*Bx = lambda*x.\n" "3. If itype is 3: B*Ax = lambda*x.n\n\n" "On exit, W contains the eigenvalues in ascending order. If jobz\n" "is 'V', the matrix of eigenvectors Z is also computed and \n" "returned in A, normalized as follows: \n" "1. If itype is 1: Z^H*A*Z = diag(W), Z^H*B*Z = I\n" "2. If itype is 2: Z^H*A^{-1}*Z = diag(W), Z^H*B*Z = I\n" "3. If itype is 3: Z^H*A*Z = diag(W), Z^H*B^{-1}*Z = I.\n\n" "If jobz is 'N', only the eigenvalues are computed, and the \n" "contents of A is destroyed. On exit, the matrix B is replaced\n" "by its Cholesky factor.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "W 'd' matrix of length at least n\n\n" "itype integer 1, 2, or 3\n\n" "jobz 'N' or 'V'\n\n" "uplo 'L' or 'U'\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n). If zero, the\n" " default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* hegv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *W; int n=-1, itype=1, ldA=0, ldB=0, oA=0, oB=0, oW=0, info, lwork; double *rwork=NULL; void *work=NULL; number wl; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', jobz_ = 'N'; #endif char uplo = 'L', jobz = 'N'; char *kwlist[] = {"A", "B", "W", "itype", "jobz", "uplo", "n", "ldA", "offsetA", "offsetB", "offsetW", NULL}; #if 0 int ispec=1, n2=-1, n3=-1, n4=-1; char *name = "zhetrd", *uplol = "L", *uplou = "U"; #endif #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iCCiiiii", kwlist, &A, &B, &W, &itype, &jobz_, &uplo_, &n, &ldA, &ldB, &oA, &oB, &oW)) return NULL; uplo = (char) uplo_; jobz = (char) jobz_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|icciiiii", kwlist, &A, &B, &W, &itype, &jobz, &uplo, &n, &ldA, &ldB, &oA, &oB, &oW)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B) || MAT_ID(B) != MAT_ID(A)) err_conflicting_ids; if (!Matrix_Check(W) || MAT_ID(W) != DOUBLE) err_dbl_mtrx("W"); if (itype != 1 && itype != 2 && itype != 3) err_char("itype", "1, 2, 3"); if (jobz != 'N' && jobz != 'V') err_char("jobz", "'N', 'V'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } if (A->nrows != n || A->ncols != n){ PyErr_SetString(PyExc_TypeError, "B must have the same " "dimension as A"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (n-1)*ldB + n > len(B)) err_buf_len("B"); if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); switch (MAT_ID(A)){ case DOUBLE: lwork=-1; Py_BEGIN_ALLOW_THREADS dsygv_(&itype, &jobz, &uplo, &n, NULL, &ldA, NULL, &ldB, NULL, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = calloc(lwork, sizeof(double)))) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS dsygv_(&itype, &jobz, &uplo, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, MAT_BUFD(W)+oW, work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: #if 1 lwork=-1; Py_BEGIN_ALLOW_THREADS zhegv_(&itype, &jobz, &uplo, &n, NULL, &n, NULL, &n, NULL, &wl.z, &lwork, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); #endif #if 0 /* zhegv used to handle lwork=-1 incorrectly. The following replaces the call to zhegv with lwork=-1 */ lwork = n * (1 + ilaenv_(&ispec, &name, (uplo == 'L') ? &uplol : &uplou, &n, &n2, &n3, &n4)); #endif work = (void *) calloc(lwork, sizeof(complex)); rwork = (double *) calloc(3*n-2, sizeof(double)); if (!work || !rwork){ free(work); free(rwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zhegv_(&itype, &jobz, &uplo, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, MAT_BUFD(W)+oW, (complex *) work, &lwork, rwork, &info); Py_END_ALLOW_THREADS free(work); free(rwork); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_gesvd[] = "Singular value decomposition of a real or complex matrix.\n\n" "gesvd(A, S, jobu='N', jobvt='N', U=None, Vt=None, m=A.size[0],\n" " n=A.size[1], ldA=max(1,A.size[0]), ldU=None, ldVt=None,\n" " offsetA=0, offsetS=0, offsetU=0, offsetVt=0)\n\n" "PURPOSE\n" "Computes singular values and, optionally, singular vectors of a \n" "real or complex m by n matrix A.\n\n" "The argument jobu controls how many left singular vectors are\n" "computed: \n\n" "'N': no left singular vectors are computed.\n" "'A': all left singular vectors are computed and returned as\n" " columns of U.\n" "'S': the first min(m,n) left singular vectors are computed and\n" " returned as columns of U.\n" "'O': the first min(m,n) left singular vectors are computed and\n" " returned as columns of A.\n\n" "The argument jobvt controls how many right singular vectors are\n" "computed:\n\n" "'N': no right singular vectors are computed.\n" "'A': all right singular vectors are computed and returned as\n" " rows of Vt.\n" "'S': the first min(m,n) right singular vectors are computed and\n" " returned as rows of Vt.\n" "'O': the first min(m,n) right singular vectors are computed and\n" " returned as rows of A.\n" "Note that the (conjugate) transposes of the right singular \n" "vectors are returned in Vt or A.\n\n" "On exit (in all cases), the contents of A are destroyed.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "S 'd' matrix of length at least min(m,n). On exit, \n" " contains the computed singular values in descending\n" " order.\n\n" "jobu 'N', 'A', 'S' or 'O'\n\n" "jobvt 'N', 'A', 'S' or 'O'\n\n" "U 'd' or 'z' matrix. Must have the same type as A.\n" " Not referenced if jobu is 'N' or 'O'. If jobu is 'A',\n" " a matrix with at least m columns. If jobu is 'S', a\n" " matrix with at least min(m,n) columns.\n" " On exit (with jobu 'A' or 'S'), the columns of U\n" " contain the computed left singular vectors.\n\n" "Vt 'd' or 'z' matrix. Must have the same type as A.\n" " Not referenced if jobvt is 'N' or 'O'. If jobvt is \n" " 'A' or 'S', a matrix with at least n columns.\n" " On exit (with jobvt 'A' or 'S'), the rows of Vt\n" " contain the computed right singular vectors, or, in\n" " the complex case, their complex conjugates.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m).\n" " If zero, the default value is used.\n\n" "ldU nonnegative integer.\n" " ldU >= 1 if jobu is 'N' or 'O'.\n" " ldU >= max(1,m) if jobu is 'A' or 'S'.\n" " The default value is max(1,U.size[0]) if jobu is 'A' \n" " or 'S', and 1 otherwise.\n" " If zero, the default value is used.\n\n" "ldVt nonnegative integer.\n" " ldVt >= 1 if jobvt is 'N' or 'O'.\n" " ldVt >= max(1,n) if jobvt is 'A'. \n" " ldVt >= max(1,min(m,n)) if ldVt is 'S'.\n" " The default value is max(1,Vt.size[0]) if jobvt is 'A'\n" " or 'S', and 1 otherwise.\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetS nonnegative integer\n\n" "offsetU nonnegative integer\n\n" "offsetVt nonnegative integer"; static PyObject* gesvd(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *S, *U=NULL, *Vt=NULL; int m=-1, n=-1, ldA=0, ldU=0, ldVt=0, oA=0, oS=0, oU=0, oVt=0, info, lwork; double *rwork=NULL; void *work=NULL; number wl; #if PY_MAJOR_VERSION >= 3 int jobu_ = 'N', jobvt_ = 'N'; #endif char jobu = 'N', jobvt = 'N'; char *kwlist[] = {"A", "S", "jobu", "jobvt", "U", "Vt", "m", "n", "ldA", "ldU", "ldVt", "offsetA", "offsetS", "offsetU", "offsetVt", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCOOiiiiiiiii", kwlist, &A, &S, &jobu_, &jobvt_, &U, &Vt, &m, &n, &ldA, &ldU, &ldVt, &oA, &oS, &oU, &oVt)) return NULL; jobu = (char) jobu_; jobvt = (char) jobvt_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOiiiiiiiii", kwlist, &A, &S, &jobu, &jobvt, &U, &Vt, &m, &n, &ldA, &ldU, &ldVt, &oA, &oS, &oU, &oVt)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(S) || MAT_ID(S) != DOUBLE) err_dbl_mtrx("S"); if (jobu != 'N' && jobu != 'A' && jobu != 'O' && jobu != 'S') err_char("jobu", "'N', 'A', 'S', 'O'"); if (jobvt != 'N' && jobvt != 'A' && jobvt != 'O' && jobvt != 'S') err_char("jobvt", "'N', 'A', 'S', 'O'"); if (jobu == 'O' && jobvt == 'O') { PyErr_SetString(PyExc_ValueError, "'jobu' and 'jobvt' cannot " "both be 'O'"); return NULL; } if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (jobu == 'A' || jobu == 'S'){ if (!U || !Matrix_Check(U)) err_mtrx("U"); if (MAT_ID(U) != MAT_ID(A)) err_conflicting_ids; if (ldU == 0) ldU = MAX(1,U->nrows); if (ldU < MAX(1,m)) err_ld("ldU"); } else { if (ldU == 0) ldU = 1; if (ldU < 1) err_ld("ldU"); } if (jobvt == 'A' || jobvt == 'S'){ if (!Vt || !Matrix_Check(Vt)) err_mtrx("Vt"); if (MAT_ID(Vt) != MAT_ID(A)) err_conflicting_ids; if (ldVt == 0) ldVt = MAX(1,Vt->nrows); if (ldVt < ((jobvt == 'A') ? MAX(1,n) : MAX(1,MIN(m,n)))) err_ld("ldVt"); } else { if (ldVt == 0) ldVt = 1; if (ldVt < 1) err_ld("ldVt"); } if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (oS < 0) err_nn_int("offsetS"); if (oS + MIN(m,n) > len(S)) err_buf_len("S"); if (jobu == 'A' || jobu == 'S'){ if (oU < 0) err_nn_int("offsetU"); if (oU + ((jobu == 'A') ? m-1 : MIN(m,n)-1)*ldU + m > len(U)) err_buf_len("U"); } if (jobvt == 'A' || jobvt == 'S'){ if (oVt < 0) err_nn_int("offsetVt"); if (oVt + (n-1)*ldVt + ((jobvt == 'A') ? n : MIN(m,n)) > len(Vt)) err_buf_len("Vt"); } switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dgesvd_(&jobu, &jobvt, &m, &n, NULL, &ldA, NULL, NULL, &ldU, NULL, &ldVt, &wl.d, &lwork, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; if (!(work = (void *) calloc(lwork, sizeof(double)))){ free(work); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dgesvd_(&jobu, &jobvt, &m, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(S)+oS, (jobu == 'A' || jobu == 'S') ? MAT_BUFD(U)+oU : NULL, &ldU, (jobvt == 'A' || jobvt == 'S') ? MAT_BUFD(Vt)+oVt : NULL, &ldVt, (double *) work, &lwork, &info); Py_END_ALLOW_THREADS free(work); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zgesvd_(&jobu, &jobvt, &m, &n, NULL, &ldA, NULL, NULL, &ldU, NULL, &ldVt, &wl.z, &lwork, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); work = (void *) calloc(lwork, sizeof(complex)); rwork = (double *) calloc(5*MIN(m,n), sizeof(double)); if (!work || !rwork){ free(work); free(rwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zgesvd_(&jobu, &jobvt, &m, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFD(S)+oS, (jobu == 'A' || jobu == 'S') ? MAT_BUFZ(U)+oU : NULL, &ldU, (jobvt == 'A' || jobvt == 'S') ? MAT_BUFZ(Vt)+oVt : NULL, &ldVt, (complex *) work, &lwork, rwork, &info); Py_END_ALLOW_THREADS free(work); free(rwork); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_gesdd[] = "Singular value decomposition of a real or complex matrix\n" "(divide-and-conquer driver).\n\n" "gesdd(A, S, jobz='N', U=None, V=None, m=A.size[0], n=A.size[1], \n" " ldA=max(1,A.size[0]), ldU=None, ldVt=None, offsetA=0, \n" " offsetS=0, offsetU=0, offsetVt=0)\n\n" "PURPOSE\n" "Computes singular values and, optionally, singular vectors of a \n" "real or complex m by n matrix A. The argument jobz controls how\n" "many singular vectors are computed:\n\n" "'N': no singular vectors are computed.\n" "'A': all m left singular vectors are computed and returned as\n" " columns of U; all n right singular vectors are computed \n" " and returned as rows of Vt.\n" "'S': the first min(m,n) left and right singular vectors are\n" " computed and returned as columns of U and rows of Vt.\n" "'O': if m>=n, the first n left singular vectors are returned as\n" " columns of A and the n right singular vectors are returned\n" " as rows of Vt. If m=n.\n" " If jobz is 'A' or jobz is 'O' and m=n), contains the computed\n" " left singular vectors stored columnwise.\n\n" "Vt 'd' or 'z' matrix. Must have the same type as A.\n" " Not referenced if jobz is 'N' or jobz is 'O' and m=n, a\n" " matrix with at least n columns. On exit (except when\n" " jobz is 'N' or jobz is 'O' and m= max(1,m).\n" " If zero, the default value is used.\n\n" "ldU nonnegative integer.\n" " ldU >= 1 if jobz is 'N' or 'O'.\n" " ldU >= max(1,m) if jobz is 'S' or 'A' or jobz is 'O'\n" " and m= 1 if jobz is 'N'.\n" " ldVt >= max(1,n) if jobz is 'A' or jobz is 'O' and \n" " m>=n. \n" " ldVt >= max(1,min(m,n)) if ldVt is 'S'.\n" " The default value is max(1,Vt.size[0]) if jobvt is 'A'\n" " or 'S' or jobvt is 'O' and m>=n, and 1 otherwise.\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetS nonnegative integer\n\n" "offsetU nonnegative integer\n\n" "offsetVt nonnegative integer"; static PyObject* gesdd(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *S, *U=NULL, *Vt=NULL; int m=-1, n=-1, ldA=0, ldU=0, ldVt=0, oA=0, oS=0, oU=0, oVt=0, info, *iwork=NULL, lwork; double *rwork=NULL; void *work=NULL; number wl; #if PY_MAJOR_VERSION >= 3 int jobz_ = 'N'; #endif char jobz = 'N'; char *kwlist[] = {"A", "S", "jobz", "U", "Vt", "m", "n", "ldA", "ldU", "ldVt", "offsetA", "offsetS", "offsetU", "offsetVt", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|COOiiiiiiiii", kwlist, &A, &S, &jobz_, &U, &Vt, &m, &n, &ldA, &ldU, &ldVt, &oA, &oS, &oU, &oVt)) return NULL; jobz = (char) jobz_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cOOiiiiiiiii", kwlist, &A, &S, &jobz, &U, &Vt, &m, &n, &ldA, &ldU, &ldVt, &oA, &oS, &oU, &oVt)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(S) || MAT_ID(S) != DOUBLE) err_dbl_mtrx("S"); if (jobz != 'A' && jobz != 'S' && jobz != 'O' && jobz != 'N') err_char("jobz", "'A', 'S', 'O', 'N'"); if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && mnrows); if (ldU < MAX(1,m)) err_ld("ldU"); } else { if (ldU == 0) ldU = 1; if (ldU < 1) err_ld("ldU"); } if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m>=n)){ if (!Vt || !Matrix_Check(Vt)) err_mtrx("Vt"); if (MAT_ID(Vt) != MAT_ID(A)) err_conflicting_ids; if (ldVt == 0) ldVt = MAX(1,Vt->nrows); if (ldVt < ((jobz == 'A' || jobz == 'O') ? MAX(1,n) : MAX(1,MIN(m,n)))) err_ld("ldVt"); } else { if (ldVt == 0) ldVt = 1; if (ldVt < 1) err_ld("ldVt"); } if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (oS < 0) err_nn_int("offsetS"); if (oS + MIN(m,n) > len(S)) err_buf_len("S"); if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m len(U)) err_buf_len("U"); } if (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m>=n)){ if (oVt < 0) err_nn_int("offsetVt"); if (oVt + (n-1)*ldVt + ((jobz == 'A' || jobz == 'O') ? n : MIN(m,n)) > len(Vt)) err_buf_len("Vt"); } switch (MAT_ID(A)){ case DOUBLE: lwork = -1; Py_BEGIN_ALLOW_THREADS dgesdd_(&jobz, &m, &n, NULL, &ldA, NULL, NULL, &ldU, NULL, &ldVt, &wl.d, &lwork, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) wl.d; work = (void *) calloc(lwork, sizeof(double)); iwork = (int *) calloc(8*MIN(m,n), sizeof(int)); if (!work || !iwork){ free(work); free(iwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS dgesdd_(&jobz, &m, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(S)+oS, (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m=n)) ? MAT_BUFD(Vt)+oVt : NULL, &ldVt, (double *) work, &lwork, iwork, &info); Py_END_ALLOW_THREADS free(work); free(iwork); break; case COMPLEX: lwork = -1; Py_BEGIN_ALLOW_THREADS zgesdd_(&jobz, &m, &n, NULL, &ldA, NULL, NULL, &ldU, NULL, &ldVt, &wl.z, &lwork, NULL, NULL, &info); Py_END_ALLOW_THREADS lwork = (int) creal(wl.z); work = (void *) calloc(lwork, sizeof(complex)); iwork = (int *) calloc(8*MIN(m,n), sizeof(int)); rwork = (double *) calloc( (jobz == 'N') ? 7*MIN(m,n) : 5*MIN(m,n)*(MIN(m,n)+1), sizeof(double)); if (!work || !iwork || !rwork){ free(work); free(iwork); free(rwork); return PyErr_NoMemory(); } Py_BEGIN_ALLOW_THREADS zgesdd_(&jobz, &m, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFD(S)+oS, (jobz == 'A' || jobz == 'S' || (jobz == 'O' && m=n)) ? MAT_BUFZ(Vt)+oVt : NULL, &ldVt, (complex *) work, &lwork, rwork, iwork, &info); Py_END_ALLOW_THREADS free(work); free(iwork); free(rwork); break; default: err_invalid_id; } if (info) err_lapack else return Py_BuildValue(""); } static char doc_gees[] = "Schur factorization of a real of complex matrix.\n\n" "sdim = gees(A, w=None, V=None, select=None, n=A.size[0],\n" " ldA=max(1,A.size[0]), ldV=max(1,Vs.size[0]), offsetA=0,\n" " offsetw=0, offsetV=0)\n\n" "PURPOSE\n" "Computes the real Schur form A = V * S * V^T or the complex Schur\n" "form A = V * S * V^H, the eigenvalues, and, optionally, the matrix\n" "of Schur vectors of an n by n matrix A. The real Schur form is \n" "computed if A is real, and the conmplex Schur form is computed if \n" "A is complex. On exit, A is replaced with S. If the argument w is\n" "provided, the eigenvalues are returned in w. If V is provided, the\n" "Schur vectors are computed and returned in V. The argument select\n" "can be used to obtain an ordered Schur factorization. It must be a\n" "Python function that can be called as f(s) with s complex, and \n" "returns 0 or 1. The eigenvalues s for which f(s) is 1 will be \n" "placed first in the Schur factorization. For the real case, \n" "eigenvalues s for which f(s) or f(conj(s)) is 1, are placed first.\n" "If select is provided, gees() returns the number of eigenvalues \n" "that satisfy the selection criterion. Otherwise, it returns 0.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "w 'z' matrix of length at least n\n\n" "V 'd' or 'z' matrix. Must have the same type as A.\n\n" "select Python function that takes a complex number as argument\n" " and returns True or False.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "ldV nonnegative integer. ldV >= 1 and ldV >= n if V is\n" " present. If zero, the default value is used (with \n" " V.size[0] replaced by 0 if V is None).\n\n" "offsetA nonnegative integer\n\n" "offsetW nonnegative integer\n\n" "offsetV nonnegative integer\n\n" "sdim number of eigenvalues that satisfy the selection\n" " criterion specified by select."; static PyObject *py_select_r; static PyObject *py_select_c; extern int fselect_c(complex *w) { PyObject *wpy, *result; int a = 0; wpy = PyComplex_FromDoubles(creal(*w), cimag(*w)); if (!(result = PyObject_CallFunctionObjArgs(py_select_c, wpy, NULL))) { Py_XDECREF(wpy); return -1; } #if PY_MAJOR_VERSION >= 3 if PyLong_Check(result) a = (int) PyLong_AsLong(result); #else if PyInt_Check(result) a = (int) PyInt_AsLong(result); #endif else PyErr_SetString(PyExc_TypeError, "select() must return an integer " "argument"); Py_XDECREF(wpy); Py_XDECREF(result); return a; } extern int fselect_r(double *wr, double *wi) { PyObject *wpy, *result; int a = 0; wpy = PyComplex_FromDoubles(*wr, *wi); if (!(result = PyObject_CallFunctionObjArgs(py_select_r, wpy, NULL))) { Py_XDECREF(wpy); return -1; } #if PY_MAJOR_VERSION >= 3 if PyLong_Check(result) a = (int) PyLong_AsLong(result); #else if PyInt_Check(result) a = (int) PyInt_AsLong(result); #endif else PyErr_SetString(PyExc_TypeError, "select() must return an integer " "argument"); Py_XDECREF(wpy); Py_XDECREF(result); return a; } static PyObject* gees(PyObject *self, PyObject *args, PyObject *kwrds) { PyObject *F=NULL; matrix *A, *W=NULL, *Vs=NULL; int n=-1, ldA=0, ldVs=0, oA=0, oVs=0, oW=0, info, lwork, sdim, k, *bwork=NULL; double *wr=NULL, *wi=NULL, *rwork=NULL; complex *w=NULL; void *work=NULL; number wl; char *kwlist[] = {"A", "w", "V", "select", "n", "ldA", "ldV", "offsetA", "offsetw", "offsetV", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OOOiiiiii", kwlist, &A, &W, &Vs, &F, &n, &ldA, &ldVs, &oA, &oW, &oVs)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (W){ if (!Matrix_Check(W) || MAT_ID(W) != COMPLEX) PY_ERR_TYPE("W must be a matrix with typecode 'z'") if (oW < 0) err_nn_int("offsetW"); if (oW + n > len(W)) err_buf_len("W"); } if (Vs){ if (!Matrix_Check(Vs)) err_mtrx("Vs"); if (MAT_ID(Vs) != MAT_ID(A)) err_conflicting_ids; if (ldVs == 0) ldVs = MAX(1, Vs->nrows); if (ldVs < MAX(1,n)) err_ld("ldVs"); if (oVs < 0) err_nn_int("offsetVs"); if (oVs + (n-1)*ldVs + n > len(Vs)) err_buf_len("Vs"); } else { if (ldVs == 0) ldVs = 1; if (ldVs < 1) err_ld("ldVs"); } if (F && !PyFunction_Check(F)) PY_ERR_TYPE("select must be a Python function") switch (MAT_ID(A)){ case DOUBLE: lwork = -1; dgees_(Vs ? "V" : "N", F ? "S" : "N", NULL, &n, NULL, &ldA, &sdim, NULL, NULL, NULL, &ldVs, &wl.d, &lwork, NULL, &info); lwork = (int) wl.d; work = (void *) calloc(lwork, sizeof(double)); wr = (double *) calloc(n, sizeof(double)); wi = (double *) calloc(n, sizeof(double)); if (F) bwork = (int *) calloc(n, sizeof(int)); if (!work || !wr || !wi || (F && !bwork)){ free(work); free(wr); free(wi); free(bwork); return PyErr_NoMemory(); } py_select_r = F; dgees_(Vs ? "V": "N", F ? "S" : "N", F ? &fselect_r : NULL, &n, MAT_BUFD(A) + oA, &ldA, &sdim, wr, wi, Vs ? MAT_BUFD(Vs) + oVs : NULL, &ldVs, (double *) work, &lwork, bwork, &info); if (W) for (k=0; k= max(1,n).\n" " If zero, the default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n).\n" " If zero, the default value is used.\n\n" "ldVl nonnegative integer. ldVl >= 1 and ldVl >= n if Vl \n" " is present. If zero, the default value is used (with \n" " Vl.size[0] replaced by 0 if Vl is None).\n\n" "ldVr nonnegative integer. ldVr >= 1 and ldVr >= n if Vr \n" " is present. If zero, the default value is used (with \n" " Vr.size[0] replaced by 0 if Vr is None).\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer\n\n" "offseta nonnegative integer\n\n" "offsetb nonnegative integer\n\n" "offsetVl nonnegative integer\n\n" "offsetVr nonnegative integer\n\n" "sdim number of eigenvalues that satisfy the selection\n" " criterion specified by select."; static PyObject *py_select_gr; static PyObject *py_select_gc; extern int fselect_gc(complex *w, double *v) { PyObject *wpy, *vpy, *result; int a = 0; wpy = PyComplex_FromDoubles(creal(*w), cimag(*w)); vpy = PyFloat_FromDouble(*v); if (!(result = PyObject_CallFunctionObjArgs(py_select_gc, wpy, vpy, NULL))) { Py_XDECREF(wpy); Py_XDECREF(vpy); return -1; } #if PY_MAJOR_VERSION >= 3 if PyLong_Check(result) a = (int) PyLong_AsLong(result); #else if PyInt_Check(result) a = (int) PyInt_AsLong(result); #endif else PyErr_SetString(PyExc_TypeError, "select() must return an integer " "argument"); Py_XDECREF(wpy); Py_XDECREF(vpy); Py_XDECREF(result); return a; } extern int fselect_gr(double *wr, double *wi, double *v) { PyObject *wpy, *vpy, *result; int a = 0; wpy = PyComplex_FromDoubles(*wr, *wi); vpy = PyFloat_FromDouble(*v); if (!(result = PyObject_CallFunctionObjArgs(py_select_gr, wpy, vpy, NULL))) { Py_XDECREF(wpy); Py_XDECREF(vpy); return -1; } #if PY_MAJOR_VERSION >= 3 if PyLong_Check(result) a = (int) PyLong_AsLong(result); #else if PyInt_Check(result) a = (int) PyInt_AsLong(result); #endif else PyErr_SetString(PyExc_TypeError, "select() must return an integer " "argument"); Py_XDECREF(wpy); Py_XDECREF(vpy); Py_XDECREF(result); return a; } static PyObject* gges(PyObject *self, PyObject *args, PyObject *kwrds) { PyObject *F=NULL; matrix *A, *B, *a=NULL, *b=NULL, *Vsl=NULL, *Vsr=NULL; int n=-1, ldA=0, ldB=0, ldVsl=0, ldVsr=0, oA=0, oB=0, oa=0, ob=0, oVsl=0, oVsr=0, info, lwork, sdim, k, *bwork=NULL; double *ar=NULL, *ai=NULL, *rwork=NULL; complex *ac=NULL; void *work=NULL, *bc=NULL; number wl; char *kwlist[] = {"A", "B", "a", "b", "Vl", "Vr", "select", "n", "ldA", "ldB", "ldVl", "ldVr", "offsetA", "offsetB", "offseta", "offsetb", "offsetVl", "offsetVr", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OOOOOiiiiiiiiiii", kwlist, &A, &B, &a, &b, &Vsl, &Vsr, &F, &n, &ldA, &ldB, &ldVsl, &ldVsr, &oA, &oB, &oa, &ob, &oVsl, &oVsr)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(B) != MAT_ID(A)) err_conflicting_ids; if (n < 0){ n = A->nrows; if (n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } if (n != B->nrows || n != B->ncols){ PyErr_SetString(PyExc_TypeError, "B must be square and of the " "same order as A"); return NULL; } } if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ldB == 0) ldB = MAX(1, B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oB < 0) err_nn_int("offsetB"); if (oB + (n-1)*ldB + n > len(B)) err_buf_len("B"); if (a){ if (!Matrix_Check(a) || MAT_ID(a) != COMPLEX) PY_ERR_TYPE("a must be a matrix with typecode 'z'") if (oa < 0) err_nn_int("offseta"); if (oa + n > len(a)) err_buf_len("a"); if (!b){ PyErr_SetString(PyExc_ValueError, "'b' must be provided if " "'a' is provided"); return NULL; } } if (b){ if (!Matrix_Check(b) || MAT_ID(b) != DOUBLE) PY_ERR_TYPE("b must be a matrix with typecode 'd'") if (ob < 0) err_nn_int("offsetb"); if (ob + n > len(b)) err_buf_len("b"); if (!a){ PyErr_SetString(PyExc_ValueError, "'a' must be provided if " "'b' is provided"); return NULL; } } if (Vsl){ if (!Matrix_Check(Vsl)) err_mtrx("Vsl"); if (MAT_ID(Vsl) != MAT_ID(A)) err_conflicting_ids; if (ldVsl == 0) ldVsl = MAX(1, Vsl->nrows); if (ldVsl < MAX(1,n)) err_ld("ldVsl"); if (oVsl < 0) err_nn_int("offsetVsl"); if (oVsl + (n-1)*ldVsl + n > len(Vsl)) err_buf_len("Vsl"); } else { if (ldVsl == 0) ldVsl = 1; if (ldVsl < 1) err_ld("ldVsl"); } if (Vsr){ if (!Matrix_Check(Vsr)) err_mtrx("Vsr"); if (MAT_ID(Vsr) != MAT_ID(A)) err_conflicting_ids; if (ldVsr == 0) ldVsr = MAX(1, Vsr->nrows); if (ldVsr < MAX(1,n)) err_ld("ldVsr"); if (oVsr < 0) err_nn_int("offsetVsr"); if (oVsr + (n-1)*ldVsr + n > len(Vsr)) err_buf_len("Vsr"); } else { if (ldVsr == 0) ldVsr = 1; if (ldVsr < 1) err_ld("ldVsr"); } if (F && !PyFunction_Check(F)) PY_ERR_TYPE("select must be a Python function") switch (MAT_ID(A)){ case DOUBLE: lwork = -1; dgges_(Vsl ? "V" : "N", Vsr ? "V" : "N", F ? "S" : "N", NULL, &n, NULL, &ldA, NULL, &ldB, &sdim, NULL, NULL, NULL, NULL, &ldVsl, NULL, &ldVsr, &wl.d, &lwork, NULL, &info); lwork = (int) wl.d; work = (void *) calloc(lwork, sizeof(double)); ar = (double *) calloc(n, sizeof(double)); ai = (double *) calloc(n, sizeof(double)); if (!b) bc = (double *) calloc(n, sizeof(double)); if (F) bwork = (int *) calloc(n, sizeof(int)); if (!work || !ar || !ai || (!b && !bc) || (F && !bwork)){ free(work); free(ar); free(ai); free(b); free(bwork); return PyErr_NoMemory(); } py_select_gr = F; dgges_(Vsl ? "V" : "N", Vsr ? "V" : "N", F ? "S" : "N", F ? &fselect_gr : NULL, &n, MAT_BUFD(A) + oA, &ldA, MAT_BUFD(B) + oB, &ldB, &sdim, ar, ai, b ? MAT_BUFD(b) + ob : (double *) bc, Vsl ? MAT_BUFD(Vsl) + oVsl : NULL, &ldVsl, Vsr ? MAT_BUFD(Vsr) + oVsr : NULL, &ldVsr, (double *) work, &lwork, bwork, &info); if (a) for (k=0; k= max(1,m). If zero, the default\n" " value is used.\n\n" "ldB positive integer. ldB >= max(1,m). If zero, the default\n" " value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* lacpy(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; int m = -1, n = -1, ldA = 0, ldB = 0, oA = 0, oB = 0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'N'; #endif char uplo = 'N'; char *kwlist[] = {"A", "B", "uplo", "m", "n", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciiiiii", kwlist, &A, &B, &uplo_, &m, &n, &ldA, &ldB, &oA, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciiiiii", kwlist, &A, &B, &uplo, &m, &n, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (uplo != 'N' && uplo != 'L' && uplo != 'U') err_char("trans", "'N', 'L', 'U'"); if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (ldA == 0) ldA = MAX(1, A->nrows); if (ldA < MAX(1, m)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1, B->nrows); if (ldB < MAX(1, m)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (n-1)*ldB + m > len(B)) err_buf_len("B"); switch (MAT_ID(A)){ case DOUBLE: dlacpy_(&uplo, &m, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB); break; case COMPLEX: zlacpy_(&uplo, &m, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB); break; default: err_invalid_id; } return Py_BuildValue(""); } static PyMethodDef lapack_functions[] = { {"getrf", (PyCFunction) getrf, METH_VARARGS|METH_KEYWORDS, doc_getrf}, {"getrs", (PyCFunction) getrs, METH_VARARGS|METH_KEYWORDS, doc_getrs}, {"getri", (PyCFunction) getri, METH_VARARGS|METH_KEYWORDS, doc_getri}, {"gesv", (PyCFunction) gesv, METH_VARARGS|METH_KEYWORDS, doc_gesv}, {"gbtrf", (PyCFunction) gbtrf, METH_VARARGS|METH_KEYWORDS, doc_gbtrf}, {"gbtrs", (PyCFunction) gbtrs, METH_VARARGS|METH_KEYWORDS, doc_gbtrs}, {"gbsv", (PyCFunction) gbsv, METH_VARARGS|METH_KEYWORDS, doc_gbsv}, {"gttrf", (PyCFunction) gttrf, METH_VARARGS|METH_KEYWORDS, doc_gttrf}, {"gttrs", (PyCFunction) gttrs, METH_VARARGS|METH_KEYWORDS, doc_gttrs}, {"gtsv", (PyCFunction) gtsv, METH_VARARGS|METH_KEYWORDS, doc_gtsv}, {"potrf", (PyCFunction) potrf, METH_VARARGS|METH_KEYWORDS, doc_potrf}, {"potrs", (PyCFunction) potrs, METH_VARARGS|METH_KEYWORDS, doc_potrs}, {"potri", (PyCFunction) potri, METH_VARARGS|METH_KEYWORDS, doc_potri}, {"posv", (PyCFunction) posv, METH_VARARGS|METH_KEYWORDS, doc_posv}, {"pbtrf", (PyCFunction) pbtrf, METH_VARARGS|METH_KEYWORDS, doc_pbtrf}, {"pbtrs", (PyCFunction) pbtrs, METH_VARARGS|METH_KEYWORDS, doc_pbtrs}, {"pbsv", (PyCFunction) pbsv, METH_VARARGS|METH_KEYWORDS, doc_pbsv}, {"pttrf", (PyCFunction) pttrf, METH_VARARGS|METH_KEYWORDS, doc_pttrf}, {"pttrs", (PyCFunction) pttrs, METH_VARARGS|METH_KEYWORDS, doc_pttrs}, {"ptsv", (PyCFunction) ptsv, METH_VARARGS|METH_KEYWORDS, doc_ptsv}, {"sytrs", (PyCFunction) sytrs, METH_VARARGS|METH_KEYWORDS, doc_sytrs}, {"hetrs", (PyCFunction) hetrs, METH_VARARGS|METH_KEYWORDS, doc_hetrs}, {"sytrf", (PyCFunction) sytrf, METH_VARARGS|METH_KEYWORDS, doc_sytrf}, {"hetrf", (PyCFunction) hetrf, METH_VARARGS|METH_KEYWORDS, doc_hetrf}, {"sytri", (PyCFunction) sytri, METH_VARARGS|METH_KEYWORDS, doc_sytri}, {"sysv", (PyCFunction) sysv, METH_VARARGS|METH_KEYWORDS, doc_sysv}, {"hetri", (PyCFunction) hetri, METH_VARARGS|METH_KEYWORDS, doc_hetri}, {"hesv", (PyCFunction) hesv, METH_VARARGS|METH_KEYWORDS, doc_hesv}, {"trtrs", (PyCFunction) trtrs, METH_VARARGS|METH_KEYWORDS, doc_trtrs}, {"trtri", (PyCFunction) trtri, METH_VARARGS|METH_KEYWORDS, doc_trtri}, {"tbtrs", (PyCFunction) tbtrs, METH_VARARGS|METH_KEYWORDS, doc_tbtrs}, {"gels", (PyCFunction) gels, METH_VARARGS|METH_KEYWORDS, doc_gels}, {"geqrf", (PyCFunction) geqrf, METH_VARARGS|METH_KEYWORDS, doc_geqrf}, {"ormqr", (PyCFunction) ormqr, METH_VARARGS|METH_KEYWORDS, doc_ormqr}, {"unmqr", (PyCFunction) unmqr, METH_VARARGS|METH_KEYWORDS, doc_unmqr}, {"orgqr", (PyCFunction) orgqr, METH_VARARGS|METH_KEYWORDS, doc_orgqr}, {"ungqr", (PyCFunction) ungqr, METH_VARARGS|METH_KEYWORDS, doc_ungqr}, {"gelqf", (PyCFunction) gelqf, METH_VARARGS|METH_KEYWORDS, doc_gelqf}, {"ormlq", (PyCFunction) ormlq, METH_VARARGS|METH_KEYWORDS, doc_ormlq}, {"unmlq", (PyCFunction) unmlq, METH_VARARGS|METH_KEYWORDS, doc_unmlq}, {"orglq", (PyCFunction) orglq, METH_VARARGS|METH_KEYWORDS, doc_orglq}, {"unglq", (PyCFunction) unglq, METH_VARARGS|METH_KEYWORDS, doc_unglq}, {"syev", (PyCFunction) syev, METH_VARARGS|METH_KEYWORDS, doc_syev}, {"heev", (PyCFunction) heev, METH_VARARGS|METH_KEYWORDS, doc_heev}, {"syevx", (PyCFunction) syevx, METH_VARARGS|METH_KEYWORDS, doc_syevx}, {"heevx", (PyCFunction) heevx, METH_VARARGS|METH_KEYWORDS, doc_heevx}, {"sygv", (PyCFunction) sygv, METH_VARARGS|METH_KEYWORDS, doc_sygv}, {"hegv", (PyCFunction) hegv, METH_VARARGS|METH_KEYWORDS, doc_hegv}, {"syevd", (PyCFunction) syevd, METH_VARARGS|METH_KEYWORDS, doc_syevd}, {"heevd", (PyCFunction) heevd, METH_VARARGS|METH_KEYWORDS, doc_heevd}, {"syevr", (PyCFunction) syevr, METH_VARARGS|METH_KEYWORDS, doc_syevr}, {"heevr", (PyCFunction) heevr, METH_VARARGS|METH_KEYWORDS, doc_heevr}, {"gesvd", (PyCFunction) gesvd, METH_VARARGS|METH_KEYWORDS, doc_gesvd}, {"gesdd", (PyCFunction) gesdd, METH_VARARGS|METH_KEYWORDS, doc_gesdd}, {"gees", (PyCFunction) gees, METH_VARARGS|METH_KEYWORDS, doc_gees}, {"gges", (PyCFunction) gges, METH_VARARGS|METH_KEYWORDS, doc_gges}, {"lacpy", (PyCFunction) lacpy, METH_VARARGS|METH_KEYWORDS, doc_lacpy}, {"geqp3", (PyCFunction) geqp3, METH_VARARGS|METH_KEYWORDS, doc_geqp3}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef lapack_module = { PyModuleDef_HEAD_INIT, "lapack", lapack__doc__, -1, lapack_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_lapack(void) { PyObject *m; if (!(m = PyModule_Create(&lapack_module))) return NULL; if (import_cvxopt() < 0) return NULL; return m; } #else PyMODINIT_FUNC initlapack(void) { PyObject *m; m = Py_InitModule3("cvxopt.lapack", lapack_functions, lapack__doc__); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/fftw.c0000644000175000017500000010241011674452555014165 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cvxopt.h" #include "misc.h" #include PyDoc_STRVAR(fftw__doc__, "Interface to the FFTW3 library.\n"); extern void zscal_(int *n, complex *alpha, complex *x, int *incx); extern void dscal_(int *n, double *alpha, double *x, int *incx); static char doc_dft[] = "DFT of a matrix, X := dft(X)\n\n" "PURPOSE\n" "Computes the DFT of a dense matrix X column by column.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'z'."; static PyObject *dft(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; char *kwlist[] = {"X", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &X)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == COMPLEX)) PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'z'"); int m = X->nrows, n = X->ncols; if (m == 0) return Py_BuildValue(""); fftw_plan p = fftw_plan_many_dft(1, &m, n, X->buffer, &m, 1, m, X->buffer, &m, 1, m, FFTW_FORWARD, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); return Py_BuildValue(""); } static char doc_dftn[] = "N-dimensional DFT of a matrix.\n" "X := dftn(X, dims)\n\n" "PURPOSE\n" "Computes the DFT of an N-dimensional array represented by a dense\n" "matrix X. The shape of the matrix X does not matter, but the data\n" "must be arranged in row-major-order. The total dimension (defined\n" "as mul(dims)) must equal the length of the array X.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "dims a tuple with the dimensions of the array."; static PyObject *dftn(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; PyObject *dims = NULL; char *kwlist[] = {"X", "dims", NULL}; int *dimarr; int free_dims = 0; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|O:dftn", kwlist, &X, &dims)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == COMPLEX)) PY_ERR_TYPE("X must be a dense matrix with type 'z'"); if (!dims) { dims = PyTuple_New(2); if (!dims) return PyErr_NoMemory(); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(dims, 0, PyLong_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyLong_FromLong(MAT_NROWS(X))); #else PyTuple_SET_ITEM(dims, 0, PyInt_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyInt_FromLong(MAT_NROWS(X))); #endif free_dims = 1; } if (!PyTuple_Check(dims)) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("invalid dimension tuple"); } int len = PySequence_Size(dims); PyObject *seq = PySequence_Fast(dims, "list is not iterable"); if (!(dimarr = malloc(len*sizeof(int)))) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); return PyErr_NoMemory(); } int i, proddim = 1; for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); PY_ERR_TYPE("non-integer in dimension tuple"); } #if PY_MAJOR_VERSION >= 3 dimarr[len-i-1] = PyLong_AS_LONG(item); #else dimarr[len-i-1] = PyInt_AS_LONG(item); #endif if (dimarr[len-i-1] < 0) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); PY_ERR(PyExc_ValueError, "negative dimension"); } proddim *= dimarr[len-i-1]; } if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); if (proddim != MAT_LGT(X)) { free(dimarr); PY_ERR_TYPE("length of X does not match dimensions"); } if (proddim == 0) { free(dimarr); return Py_BuildValue(""); } fftw_plan p = fftw_plan_dft(len, dimarr, X->buffer, X->buffer, FFTW_FORWARD, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); free(dimarr); return Py_BuildValue(""); } static char doc_idft[] = "IDFT of a matrix, X := idft(X)\n\n" "PURPOSE\n" "Computes the inverse DFT of a dense matrix X column by column.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'z'."; static PyObject *idft(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; char *kwlist[] = {"X", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &X)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == COMPLEX)) PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'z'"); int m = X->nrows, n = X->ncols; if (m == 0) return Py_BuildValue(""); fftw_plan p = fftw_plan_many_dft(1, &m, n, X->buffer, &m, 1, m, X->buffer, &m, 1, m, FFTW_BACKWARD, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS number a; a.z = 1.0/m; int mn = m*n, ix = 1; zscal_(&mn, &a.z, MAT_BUFZ(X), &ix); fftw_destroy_plan(p); return Py_BuildValue(""); } static char doc_idftn[] = "Inverse N-dimensional DFT of a matrix.\n" "X := idftn(X, dims)\n\n" "PURPOSE\n" "Computes the IDFT of an N-dimensional array represented by a dense\n" "matrix X. The shape of the matrix X does not matter, but the data\n" "must be arranged in row-major-order. The total dimension (defined\n" "as mul(dims)) must equal the length of the array X.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "dims a tuple with the dimensions of the array."; static PyObject *idftn(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; PyObject *dims = NULL; char *kwlist[] = {"X", "dims", NULL}; int *dimarr; int free_dims = 0; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|O:idftn", kwlist, &X, &dims)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == COMPLEX)) PY_ERR_TYPE("X must be a dense matrix with type 'z'"); if (!dims) { dims = PyTuple_New(2); if (!dims) return PyErr_NoMemory(); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(dims, 0, PyLong_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyLong_FromLong(MAT_NROWS(X))); #else PyTuple_SET_ITEM(dims, 0, PyInt_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyInt_FromLong(MAT_NROWS(X))); #endif free_dims = 1; } if (!PyTuple_Check(dims)) PY_ERR_TYPE("invalid dimension tuple"); int len = PySequence_Size(dims); PyObject *seq = PySequence_Fast(dims, "list is not iterable"); if (!(dimarr = malloc(len*sizeof(int)))) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); return PyErr_NoMemory(); } int i, proddim = 1; for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); PY_ERR_TYPE("non-integer in dimension tuple"); } #if PY_MAJOR_VERSION >= 3 dimarr[len-i-1] = PyLong_AS_LONG(item); #else dimarr[len-i-1] = PyInt_AS_LONG(item); #endif if (dimarr[len-i-1] < 0) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); PY_ERR(PyExc_ValueError, "negative dimension"); } proddim *= dimarr[len-i-1]; } Py_DECREF(seq); if (free_dims) { Py_DECREF(dims); } if (proddim != MAT_LGT(X)) { free(dimarr); PY_ERR_TYPE("length of X does not match dimensions"); } if (proddim == 0) { free(dimarr); return Py_BuildValue(""); } number a; a.z = 1.0/proddim; int ix = 1; zscal_(&proddim, &a.z, MAT_BUFZ(X), &ix); fftw_plan p = fftw_plan_dft(len, dimarr, X->buffer, X->buffer, FFTW_BACKWARD, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); free(dimarr); return Py_BuildValue(""); } static char doc_dct[] = "DCT of a matrix.\n" "X := dct(X, type=2)\n\n" "PURPOSE\n" "Computes the DCT of a dense matrix X column by column.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "type integer from 1 to 4; chooses either DCT-I, DCT-II, \n" " DCT-III or DCT-IV."; static PyObject *dct(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; int type = 2; char *kwlist[] = {"X", "type", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'"); int m = X->nrows, n = X->ncols; if (m == 0) return Py_BuildValue(""); fftw_r2r_kind kind; switch(type) { case 1: kind = FFTW_REDFT00; if (m <= 1) PY_ERR(PyExc_ValueError, "m must be greater than 1 for DCT-I"); break; case 2: kind = FFTW_REDFT10; break; case 3: kind = FFTW_REDFT01; break; case 4: kind = FFTW_REDFT11; break; default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } fftw_plan p = fftw_plan_many_r2r(1, &m, n, X->buffer, &m, 1, m, X->buffer, &m, 1, m, &kind, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); return Py_BuildValue(""); } static char doc_dctn[] = "N-dimensional DCT of a matrix.\n" "X := dctn(X, dims, type=2)\n\n" "PURPOSE\n" "Computes the DCT of an N-dimensional array represented by a dense\n" "matrix X. The shape of the matrix X does not matter, but the data\n" "must be arranged in row-major-order. The total dimension (defined\n" "as mul(dims)) must equal the length of the array X.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "dims a tuple with the dimensions of the array.\n\n" "type integer from 1 to 4; chooses either DCT-I, DCT-II, \n" " DCT-III or DCT-IV."; static PyObject *dctn(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; PyObject *dims = NULL, *type = NULL; char *kwlist[] = {"X", "dims", "type", NULL}; int *dimarr; fftw_r2r_kind *kindarr; int free_dims = 0; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OO:dctn", kwlist, &X, &dims, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR_TYPE("X must be a dense matrix with type 'd'"); if (!dims) { dims = PyTuple_New(2); if (!dims) return PyErr_NoMemory(); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(dims, 0, PyLong_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyLong_FromLong(MAT_NROWS(X))); #else PyTuple_SET_ITEM(dims, 0, PyInt_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyInt_FromLong(MAT_NROWS(X))); #endif free_dims = 1; } if (!PyTuple_Check(dims)) PY_ERR_TYPE("invalid dimension tuple"); if (type && !PyTuple_Check(type)) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("invalid type tuple"); } int len = PySequence_Size(dims); if (type && PySequence_Size(type) != len) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("dimensions and type tuples must have same length"); } PyObject *seq = PySequence_Fast(dims, "list is not iterable"); if (!(dimarr = malloc(len*sizeof(int)))) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); return PyErr_NoMemory(); } if (!(kindarr = malloc(len*sizeof(fftw_r2r_kind)))) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); return PyErr_NoMemory(); } int i, proddim = 1; for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in dimension tuple"); } #if PY_MAJOR_VERSION >= 3 dimarr[len-i-1] = PyLong_AS_LONG(item); #else dimarr[len-i-1] = PyInt_AS_LONG(item); #endif if (dimarr[len-i-1] < 0) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "negative dimension"); } proddim *= dimarr[len-i-1]; } if (free_dims) { Py_DECREF(dims); } if (proddim != MAT_LGT(X)) { Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR_TYPE("length of X does not match dimensions"); } if (proddim == 0) { Py_DECREF(seq); free(dimarr); free(kindarr); return Py_BuildValue(""); } Py_DECREF(seq); if (type == NULL) { for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in type tuple"); } #if PY_MAJOR_VERSION >= 3 switch(PyLong_AS_LONG(item)) { #else switch(PyInt_AS_LONG(item)) { #endif case 1: kindarr[len-i-1] = FFTW_REDFT00; if (dimarr[len-i-1] <= 1) { Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "dimension must be greater than 1 for DCT-I"); } break; case 2: kindarr[len-i-1] = FFTW_REDFT10; break; case 3: kindarr[len-i-1] = FFTW_REDFT01; break; case 4: kindarr[len-i-1] = FFTW_REDFT11; break; default: Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } } Py_DECREF(seq); } fftw_plan p = fftw_plan_r2r(len, dimarr, X->buffer, X->buffer, kindarr, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); free(dimarr); free(kindarr); return Py_BuildValue(""); } static char doc_idct[] = "Inverse DCT of a matrix.\n" "X := idct(X, type=2)\n\n" "PURPOSE\n" "Computes the IDCT of a dense matrix X column by column.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "type integer from 1 to 4; chooses either DCT-I, DCT-II, \n" " DCT-III or DCT-IV."; static PyObject *idct(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; int type = 2; char *kwlist[] = {"X", "type", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'"); int m = X->nrows, n = X->ncols; if (m == 0) return Py_BuildValue(""); fftw_r2r_kind kind; switch(type) { case 1: kind = FFTW_REDFT00; if (m <= 1) PY_ERR(PyExc_ValueError, "m must be greater than 1 for DCT-I"); break; case 2: kind = FFTW_REDFT01; break; case 3: kind = FFTW_REDFT10; break; case 4: kind = FFTW_REDFT11; break; default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } fftw_plan p = fftw_plan_many_r2r(1, &m, n, X->buffer, &m, 1, m, X->buffer, &m, 1, m, &kind, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS double a = 1.0/(type == 1 ? MAX(1,2*(m-1)) : 2*m); int mn = m*n, ix = 1; dscal_(&mn, &a, MAT_BUFD(X), &ix); fftw_destroy_plan(p); return Py_BuildValue(""); } static char doc_idctn[] = "Inverse N-dimensional DCT of a matrix.\n" "X := idctn(X, dims, type=2)\n\n" "PURPOSE\n" "Computes the IDCT of an N-dimensional array represented by a dense\n" "matrix X. The shape of the matrix X does not matter, but the data\n" "must be arranged in row-major-order. The total dimension (defined\n" "as mul(dims)) must equal the length of the array X.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "dims a tuple with the dimensions of the array.\n\n" "type integer from 1 to 4; chooses either DCT-I, DCT-II, \n" " DCT-III or DCT-IV."; static PyObject *idctn(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; PyObject *dims = NULL, *type = NULL; char *kwlist[] = {"X", "dims", "type", NULL}; int *dimarr; fftw_r2r_kind *kindarr; int free_dims = 0; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OO:idctn", kwlist, &X, &dims, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR_TYPE("X must be a dense matrix with type 'd'"); if (!dims) { dims = PyTuple_New(2); if (!dims) return PyErr_NoMemory(); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(dims, 0, PyLong_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyLong_FromLong(MAT_NROWS(X))); #else PyTuple_SET_ITEM(dims, 0, PyInt_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyInt_FromLong(MAT_NROWS(X))); #endif free_dims = 1; } if (!PyTuple_Check(dims)) PY_ERR_TYPE("invalid dimension tuple"); if (type && !PyTuple_Check(type)) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("invalid type tuple"); } int len = PySequence_Size(dims); if (type && PySequence_Size(type) != len) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("dimensions and type tuples must have same length"); } PyObject *seq = PySequence_Fast(dims, "list is not iterable"); if (!(dimarr = malloc(len*sizeof(int)))) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); return PyErr_NoMemory(); } if (!(kindarr = malloc(len*sizeof(fftw_r2r_kind)))) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); return PyErr_NoMemory(); } int i, proddim = 1; for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in dimension tuple"); } #if PY_MAJOR_VERSION >= 3 dimarr[len-i-1] = PyLong_AS_LONG(item); #else dimarr[len-i-1] = PyInt_AS_LONG(item); #endif if (dimarr[len-i-1] < 0) { if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "negative dimension"); } proddim *= dimarr[len-i-1]; } if (free_dims) { Py_DECREF(dims); } Py_DECREF(seq); if (proddim != MAT_LGT(X)) { free(dimarr); free(kindarr); PY_ERR_TYPE("length of X does not match dimensions"); } if (proddim == 0) { free(dimarr); free(kindarr); return Py_BuildValue(""); } if (type == NULL) { for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in type tuple"); } #if PY_MAJOR_VERSION >= 3 switch(PyLong_AS_LONG(item)) { #else switch(PyInt_AS_LONG(item)) { #endif case 1: kindarr[len-i-1] = FFTW_REDFT00; if (dimarr[len-i-1] <= 1) { Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "dimension must be greater than 1 for DCT-I"); } break; case 2: kindarr[len-i-1] = FFTW_REDFT01; break; case 3: kindarr[len-i-1] = FFTW_REDFT10; break; case 4: kindarr[len-i-1] = FFTW_REDFT11; break; default: Py_DECREF(seq); free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } } Py_DECREF(seq); } double a = 1.0; for (i=0; ibuffer, X->buffer, kindarr, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); free(dimarr); free(kindarr); return Py_BuildValue(""); } static char doc_dst[] = "DST of a matrix.\n" "X := dst(X, type=1)\n\n" "PURPOSE\n" "Computes the DST of a dense matrix X column by column.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "type integer from 1 to 4; chooses either DST-I, DST-II, \n" " DST-III or DST-IV."; static PyObject *dst(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; int type = 1; char *kwlist[] = {"X", "type", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'"); int m = X->nrows, n = X->ncols; if (m == 0) return Py_BuildValue(""); fftw_r2r_kind kind; switch(type) { case 1: kind = FFTW_RODFT00; break; case 2: kind = FFTW_RODFT10; break; case 3: kind = FFTW_RODFT01; break; case 4: kind = FFTW_RODFT11; break; default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } fftw_plan p = fftw_plan_many_r2r(1, &m, n, X->buffer, &m, 1, m, X->buffer, &m, 1, m, &kind, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); return Py_BuildValue(""); } static char doc_dstn[] = "N-dimensional DST of a matrix.\n" "X := dstn(X, dims, type=1)\n\n" "PURPOSE\n" "Computes the DST of an N-dimensional array represented by a dense\n" "matrix X. The shape of the matrix X does not matter, but the data\n" "must be arranged in row-major-order. The total dimension (defined\n" "as mul(dims)) must equal the length of the array X.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "dims a tuple with the dimensions of the array.\n\n" "type integer from 1 to 4; chooses either DST-I, DST-II, \n" " DST-III or DST-IV."; static PyObject *dstn(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; PyObject *dims = NULL, *type = NULL; char *kwlist[] = {"X", "dims", "type", NULL}; int *dimarr; fftw_r2r_kind *kindarr; int free_dims = 0; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OO:dctn", kwlist, &X, &dims, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR_TYPE("X must be a dense matrix with type 'd'"); if (!dims) { dims = PyTuple_New(2); if (!dims) return PyErr_NoMemory(); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(dims, 0, PyLong_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyLong_FromLong(MAT_NROWS(X))); #else PyTuple_SET_ITEM(dims, 0, PyInt_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyInt_FromLong(MAT_NROWS(X))); #endif free_dims = 1; } if (!PyTuple_Check(dims)) PY_ERR_TYPE("invalid dimension tuple"); if (type && !PyTuple_Check(type)) PY_ERR_TYPE("invalid type tuple"); int len = PySequence_Size(dims); if (type && PySequence_Size(type) != len) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("dimensions and type tuples must have same length"); } PyObject *seq = PySequence_Fast(dims, "list is not iterable"); if (!(dimarr = malloc(len*sizeof(int)))) { if (free_dims) { Py_DECREF(dims); } return PyErr_NoMemory(); } if (!(kindarr = malloc(len*sizeof(fftw_r2r_kind)))) { if (free_dims) { Py_DECREF(dims); } free(dimarr); return PyErr_NoMemory(); } int i, proddim = 1; for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif if (free_dims) { Py_DECREF(dims); } free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in dimension tuple"); } #if PY_MAJOR_VERSION >= 3 dimarr[len-i-1] = PyLong_AS_LONG(item); #else dimarr[len-i-1] = PyInt_AS_LONG(item); #endif if (dimarr[len-i-1] < 0) { if (free_dims) { Py_DECREF(dims); } free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "negative dimension"); } proddim *= dimarr[len-i-1]; } if (free_dims) { Py_DECREF(dims); } if (proddim != MAT_LGT(X)) { free(dimarr); free(kindarr); PY_ERR_TYPE("length of X does not match dimensions"); } if (proddim == 0) { free(dimarr); free(kindarr); return Py_BuildValue(""); } if (type == NULL) { for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in type tuple"); } #if PY_MAJOR_VERSION >= 3 switch(PyLong_AS_LONG(item)) { #else switch(PyInt_AS_LONG(item)) { #endif case 1: kindarr[len-i-1] = FFTW_RODFT00; break; case 2: kindarr[len-i-1] = FFTW_RODFT10; break; case 3: kindarr[len-i-1] = FFTW_RODFT01; break; case 4: kindarr[len-i-1] = FFTW_RODFT11; break; default: free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } } } fftw_plan p = fftw_plan_r2r(len, dimarr, X->buffer, X->buffer, kindarr, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); free(dimarr); free(kindarr); return Py_BuildValue(""); } static char doc_idst[] = "IDST of a matrix.\n" "X := idst(X, type=1)\n\n" "PURPOSE\n" "Computes the IDST of a dense matrix X column by column.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "type integer from 1 to 4; chooses the inverse transform for\n" " either DST-I, DST-II, DST-III or DST-IV."; static PyObject *idst(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; int type = 1; char *kwlist[] = {"X", "type", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|i", kwlist, &X, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR(PyExc_ValueError, "X must be a dense matrix with type 'd'"); int m = X->nrows, n = X->ncols; if (m == 0) return Py_BuildValue(""); fftw_r2r_kind kind; switch(type) { case 1: kind = FFTW_RODFT00; break; case 2: kind = FFTW_RODFT01; break; case 3: kind = FFTW_RODFT10; break; case 4: kind = FFTW_RODFT11; break; default: PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } fftw_plan p = fftw_plan_many_r2r(1, &m, n, X->buffer, &m, 1, m, X->buffer, &m, 1, m, &kind, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS double a = 1.0/(type == 1 ? MAX(1,2*(m+1)) : 2*m); int mn = m*n, ix = 1; dscal_(&mn, &a, MAT_BUFD(X), &ix); fftw_destroy_plan(p); return Py_BuildValue(""); } static char doc_idstn[] = "Inverse N-dimensional DST of a matrix.\n" "X := idstn(X, dims, type=1)\n\n" "PURPOSE\n" "Computes the IDST of an N-dimensional array represented by a dense\n" "matrix X. The shape of the matrix X does not matter, but the data\n" "must be arranged in row-major-order. The total dimension (defined\n" "as mul(dims)) must equal the length of the array X.\n\n" "ARGUMENTS\n" "X A dense matrix of typecode 'd'.\n\n" "dims a tuple with the dimensions of the array.\n\n" "type integer from 1 to 4; chooses either DST-I, DST-II, \n" " DST-III or DST-IV."; static PyObject *idstn(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *X; PyObject *dims = NULL, *type = NULL; char *kwlist[] = {"X", "dims", "type", NULL}; int *dimarr; fftw_r2r_kind *kindarr; int free_dims = 0; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OO:dctn", kwlist, &X, &dims, &type)) return NULL; if (!(Matrix_Check(X) && MAT_ID(X) == DOUBLE)) PY_ERR_TYPE("X must be a dense matrix with type 'd'"); if (!dims) { dims = PyTuple_New(2); if (!dims) return PyErr_NoMemory(); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(dims, 0, PyLong_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyLong_FromLong(MAT_NROWS(X))); #else PyTuple_SET_ITEM(dims, 0, PyInt_FromLong(MAT_NCOLS(X))); PyTuple_SET_ITEM(dims, 1, PyInt_FromLong(MAT_NROWS(X))); #endif free_dims = 1; } if (!PyTuple_Check(dims)) PY_ERR_TYPE("invalid dimension tuple"); if (type && !PyTuple_Check(type)) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("invalid type tuple"); } int len = PySequence_Size(dims); if (type && PySequence_Size(type) != len) { if (free_dims) { Py_DECREF(dims); } PY_ERR_TYPE("dimensions and type tuples must have same length"); } PyObject *seq = PySequence_Fast(dims, "list is not iterable"); if (!(dimarr = malloc(len*sizeof(int)))) { if (free_dims) { Py_DECREF(dims); } return PyErr_NoMemory(); } if (!(kindarr = malloc(len*sizeof(fftw_r2r_kind)))) { if (free_dims) { Py_DECREF(dims); } free(dimarr); return PyErr_NoMemory(); } int i, proddim = 1; for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif if (free_dims) { Py_DECREF(dims); } free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in dimension tuple"); } #if PY_MAJOR_VERSION >= 3 dimarr[len-i-1] = PyLong_AS_LONG(item); #else dimarr[len-i-1] = PyInt_AS_LONG(item); #endif if (dimarr[len-i-1] < 0) { if (free_dims) { Py_DECREF(dims); } free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "negative dimension"); } proddim *= dimarr[len-i-1]; } if (free_dims) { Py_DECREF(dims); } if (proddim != MAT_LGT(X)) { free(dimarr); free(kindarr); PY_ERR_TYPE("length of X does not match dimensions"); } if (proddim == 0) { free(dimarr); free(kindarr); return Py_BuildValue(""); } if (type == NULL) { for (i=0; i= 3 if (!PyLong_Check(item)) { #else if (!PyInt_Check(item)) { #endif free(dimarr); free(kindarr); PY_ERR_TYPE("non-integer in type tuple"); } #if PY_MAJOR_VERSION >= 3 switch(PyLong_AS_LONG(item)) { #else switch(PyInt_AS_LONG(item)) { #endif case 1: kindarr[len-i-1] = FFTW_RODFT00; break; case 2: kindarr[len-i-1] = FFTW_RODFT10; break; case 3: kindarr[len-i-1] = FFTW_RODFT01; break; case 4: kindarr[len-i-1] = FFTW_RODFT11; break; default: free(dimarr); free(kindarr); PY_ERR(PyExc_ValueError, "type must be between 1 and 4"); } } } double a = 1.0; for (i=0; ibuffer, X->buffer, kindarr, FFTW_ESTIMATE); Py_BEGIN_ALLOW_THREADS fftw_execute(p); Py_END_ALLOW_THREADS fftw_destroy_plan(p); free(dimarr); free(kindarr); return Py_BuildValue(""); } static PyMethodDef fftw_functions[] = { {"dft", (PyCFunction) dft, METH_VARARGS|METH_KEYWORDS, doc_dft}, {"dftn", (PyCFunction) dftn, METH_VARARGS|METH_KEYWORDS, doc_dftn}, {"idft", (PyCFunction) idft, METH_VARARGS|METH_KEYWORDS, doc_idft}, {"idftn", (PyCFunction) idftn, METH_VARARGS|METH_KEYWORDS, doc_idftn}, {"dct", (PyCFunction) dct, METH_VARARGS|METH_KEYWORDS, doc_dct}, {"dctn", (PyCFunction) dctn, METH_VARARGS|METH_KEYWORDS, doc_dctn}, {"idct", (PyCFunction) idct, METH_VARARGS|METH_KEYWORDS, doc_idct}, {"idctn", (PyCFunction) idctn, METH_VARARGS|METH_KEYWORDS, doc_idctn}, {"dst", (PyCFunction) dst, METH_VARARGS|METH_KEYWORDS, doc_dst}, {"dstn", (PyCFunction) dstn, METH_VARARGS|METH_KEYWORDS, doc_dstn}, {"idst", (PyCFunction) idst, METH_VARARGS|METH_KEYWORDS, doc_idst}, {"idstn", (PyCFunction) idstn, METH_VARARGS|METH_KEYWORDS, doc_idstn}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef fftw_module = { PyModuleDef_HEAD_INIT, "fftw", fftw__doc__, -1, fftw_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_fftw(void) { PyObject *m; if (!(m = PyModule_Create(&fftw_module))) return NULL; if (import_cvxopt() < 0) return NULL; return m; } #else PyMODINIT_FUNC initfftw(void) { PyObject *m; m = Py_InitModule3("cvxopt.fftw", fftw_functions, fftw__doc__); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/misc_solvers.c0000644000175000017500000011225311674452555015735 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Python.h" #include "cvxopt.h" #include "misc.h" #include "math.h" #include "float.h" PyDoc_STRVAR(misc_solvers__doc__, "Miscellaneous functions used by the " "CVXOPT solvers."); extern void dcopy_(int *n, double *x, int *incx, double *y, int *incy); extern double dnrm2_(int *n, double *x, int *incx); extern double ddot_(int *n, double *x, int *incx, double *y, int *incy); extern void dscal_(int *n, double *alpha, double *x, int *incx); extern void daxpy_(int *n, double *alpha, double *x, int *incx, double *y, int *incy); extern void dtbmv_(char *uplo, char *trans, char *diag, int *n, int *k, double *A, int *lda, double *x, int *incx); extern void dtbsv_(char *uplo, char *trans, char *diag, int *n, int *k, double *A, int *lda, double *x, int *incx); extern void dgemv_(char* trans, int *m, int *n, double *alpha, double *A, int *lda, double *x, int *incx, double *beta, double *y, int *incy); extern void dger_(int *m, int *n, double *alpha, double *x, int *incx, double *y, int *incy, double *A, int *lda); extern void dtrmm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n, double *alpha, double *A, int *lda, double *B, int *ldb); extern void dsyr2k_(char *uplo, char *trans, int *n, int *k, double *alpha, double *A, int *lda, double *B, int *ldb, double *beta, double *C, int *ldc); extern void dlacpy_(char *uplo, int *m, int *n, double *A, int *lda, double *B, int *ldb); extern void dsyevr_(char *jobz, char *range, char *uplo, int *n, double *A, int *ldA, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *W, double *Z, int *ldZ, int *isuppz, double *work, int *lwork, int *iwork, int *liwork, int *info); extern void dsyevd_(char *jobz, char *uplo, int *n, double *A, int *ldA, double *W, double *work, int *lwork, int *iwork, int *liwork, int *info); static char doc_scale[] = "Applies Nesterov-Todd scaling or its inverse.\n\n" "scale(x, W, trans = 'N', inverse = 'N')\n\n" "Computes\n\n" " x := W*x (trans is 'N', inverse = 'N')\n" " x := W^T*x (trans is 'T', inverse = 'N')\n" " x := W^{-1}*x (trans is 'N', inverse = 'I')\n" " x := W^{-T}*x (trans is 'T', inverse = 'I').\n\n" "x is a dense 'd' matrix.\n\n" "W is a dictionary with entries:\n\n" "- W['dnl']: positive vector\n" "- W['dnli']: componentwise inverse of W['dnl']\n" "- W['d']: positive vector\n" "- W['di']: componentwise inverse of W['d']\n" "- W['v']: lists of 2nd order cone vectors with unit hyperbolic \n" " norms\n" "- W['beta']: list of positive numbers\n" "- W['r']: list of square matrices\n" "- W['rti']: list of square matrices. rti[k] is the inverse\n" " transpose of r[k]. \n\n" "The 'dnl' and 'dnli' entries are optional, and only present when \n" "the function is called from the nonlinear solver."; static PyObject* scale(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *d, *vk, *rk; PyObject *W, *v, *beta, *r, *betak; #if PY_MAJOR_VERSION >= 3 int trans = 'N', inverse = 'N'; #else char trans = 'N', inverse = 'N'; #endif int m, n, xr, xc, ind = 0, int0 = 0, int1 = 1, i, k, inc, len, ld, maxn, N; double b, dbl0 = 0.0, dbl1 = 1.0, dblm1 = -1.0, dbl2 = 2.0, dbl5 = 0.5, *wrk; char *kwlist[] = {"x", "W", "trans", "inverse", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CC", kwlist, &x, &W, &trans, &inverse)) return NULL; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cc", kwlist, &x, &W, &trans, &inverse)) return NULL; #endif xr = x->nrows; xc = x->ncols; /* * Scaling for nonlinear component xk is xk := dnl .* xk; inverse is * xk ./ dnl = dnli .* xk, where dnl = W['dnl'], dnli = W['dnli']. */ if ((d = (inverse == 'N') ? (matrix *) PyDict_GetItemString(W, "dnl") : (matrix *) PyDict_GetItemString(W, "dnli"))){ m = len(d); for (i = 0; i < xc; i++) dtbmv_("L", "N", "N", &m, &int0, MAT_BUFD(d), &int1, MAT_BUFD(x) + i*xr, &int1); ind += m; } /* * Scaling for 'l' component xk is xk := d .* xk; inverse scaling is * xk ./ d = di .* xk, where d = W['d'], di = W['di']. */ if (!(d = (inverse == 'N') ? (matrix *) PyDict_GetItemString(W, "d") : (matrix *) PyDict_GetItemString(W, "di"))){ PyErr_SetString(PyExc_KeyError, "missing item W['d'] or W['di']"); return NULL; } m = len(d); for (i = 0; i < xc; i++) dtbmv_("L", "N", "N", &m, &int0, MAT_BUFD(d), &int1, MAT_BUFD(x) + i*xr + ind, &int1); ind += m; /* * Scaling for 'q' component is * * xk := beta * (2*v*v' - J) * xk * = beta * (2*v*(xk'*v)' - J*xk) * * where beta = W['beta'][k], v = W['v'][k], J = [1, 0; 0, -I]. * * Inverse scaling is * * xk := 1/beta * (2*J*v*v'*J - J) * xk * = 1/beta * (-J) * (2*v*((-J*xk)'*v)' + xk). */ v = PyDict_GetItemString(W, "v"); beta = PyDict_GetItemString(W, "beta"); N = (int) PyList_Size(v); if (!(wrk = (double *) calloc(xc, sizeof(double)))) return PyErr_NoMemory(); for (k = 0; k < N; k++){ vk = (matrix *) PyList_GetItem(v, (Py_ssize_t) k); m = vk->nrows; if (inverse == 'I') dscal_(&xc, &dblm1, MAT_BUFD(x) + ind, &xr); ld = MAX(xr, 1); dgemv_("T", &m, &xc, &dbl1, MAT_BUFD(x) + ind, &ld, MAT_BUFD(vk), &int1, &dbl0, wrk, &int1); dscal_(&xc, &dblm1, MAT_BUFD(x) + ind, &xr); dger_(&m, &xc, &dbl2, MAT_BUFD(vk), &int1, wrk, &int1, MAT_BUFD(x) + ind, &ld); if (inverse == 'I') dscal_(&xc, &dblm1, MAT_BUFD(x) + ind, &xr); betak = PyList_GetItem(beta, (Py_ssize_t) k); b = PyFloat_AS_DOUBLE(betak); if (inverse == 'I') b = 1.0 / b; for (i = 0; i < xc; i++) dscal_(&m, &b, MAT_BUFD(x) + ind + i*xr, &int1); ind += m; } free(wrk); /* * Scaling for 's' component xk is * * xk := vec( r' * mat(xk) * r ) if trans = 'N' * xk := vec( r * mat(xk) * r' ) if trans = 'T'. * * r is kth element of W['r']. * * Inverse scaling is * * xk := vec( rti * mat(xk) * rti' ) if trans = 'N' * xk := vec( rti' * mat(xk) * rti ) if trans = 'T'. * * rti is kth element of W['rti']. */ r = (inverse == 'N') ? PyDict_GetItemString(W, "r") : PyDict_GetItemString(W, "rti"); N = (int) PyList_Size(r); for (k = 0, maxn = 0; k < N; k++){ rk = (matrix *) PyList_GetItem(r, (Py_ssize_t) k); maxn = MAX(maxn, rk->nrows); } if (!(wrk = (double *) calloc(maxn*maxn, sizeof(double)))) return PyErr_NoMemory(); for (k = 0; k < N; k++){ rk = (matrix *) PyList_GetItem(r, (Py_ssize_t) k); n = rk->nrows; for (i = 0; i < xc; i++){ /* scale diagonal of rk by 0.5 */ inc = n + 1; dscal_(&n, &dbl5, MAT_BUFD(x) + ind + i*xr, &inc); /* wrk = r*tril(x) if inverse is 'N' and trans is 'T' or * inverse is 'I' and trans is 'N' * wrk = tril(x)*r otherwise. */ len = n*n; dcopy_(&len, MAT_BUFD(rk), &int1, wrk, &int1); ld = MAX(1, n); dtrmm_( (( inverse == 'N' && trans == 'T') || ( inverse == 'I' && trans == 'N')) ? "R" : "L", "L", "N", "N", &n, &n, &dbl1, MAT_BUFD(x) + ind + i*xr, &ld, wrk, &ld); /* x := (r*wrk' + wrk*r') if inverse is 'N' and trans is 'T' * or inverse is 'I' and trans is 'N' * x := (r'*wrk + wrk'*r) otherwise. */ dsyr2k_("L", ((inverse == 'N' && trans == 'T') || (inverse == 'I' && trans == 'N')) ? "N" : "T", &n, &n, &dbl1, MAT_BUFD(rk), &ld, wrk, &ld, &dbl0, MAT_BUFD(x) + ind + i*xr, &ld); } ind += n*n; } free(wrk); return Py_BuildValue(""); } static char doc_scale2[] = "Multiplication with square root of the Hessian.\n\n" "scale2(lmbda, x, dims, mnl = 0, inverse = 'N')\n\n" "Computes\n\n" "Evaluates\n\n" " x := H(lambda^{1/2}) * x (inverse is 'N')\n" " x := H(lambda^{-1/2}) * x (inverse is 'I').\n\n" "H is the Hessian of the logarithmic barrier."; static PyObject* scale2(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *lmbda, *x; PyObject *dims, *O, *Ok; #if PY_MAJOR_VERSION >= 3 int inverse = 'N'; #else char inverse = 'N'; #endif double a, lx, x0, b, *c = NULL, *sql = NULL; int m = 0, mk, i, j, len, int0 = 0, int1 = 1, maxn = 0, ind2; char *kwlist[] = {"lmbda", "x", "dims", "mnl", "inverse", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iC", kwlist, &lmbda, &x, &dims, &m, &inverse)) return NULL; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ic", kwlist, &lmbda, &x, &dims, &m, &inverse)) return NULL; #endif /* * For nonlinear and 'l' blocks: * * xk := xk ./ l (invers is 'N') * xk := xk .* l (invers is 'I') * * where l is the first mnl + dims['l'] components of lmbda. */ O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 m += (int) PyLong_AsLong(O); #else m += (int) PyInt_AsLong(O); #endif if (inverse == 'N') dtbsv_("L", "N", "N", &m, &int0, MAT_BUFD(lmbda), &int1, MAT_BUFD(x), &int1); else dtbmv_("L", "N", "N", &m, &int0, MAT_BUFD(lmbda), &int1, MAT_BUFD(x), &int1); /* * For 'q' blocks, if inverse is 'N', * * xk := 1/a * [ l'*J*xk; * xk[1:] - (xk[0] + l'*J*xk) / (l[0] + 1) * l[1:] ]. * * If inverse is 'I', * * xk := a * [ l'*xk; * xk[1:] + (xk[0] + l'*xk) / (l[0] + 1) * l[1:] ]. * * a = sqrt(lambda_k' * J * lambda_k), l = lambda_k / a. */ O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif len = mk - 1; a = dnrm2_(&len, MAT_BUFD(lmbda) + m + 1, &int1); a = sqrt(MAT_BUFD(lmbda)[m] + a) * sqrt(MAT_BUFD(lmbda)[m] - a); if (inverse == 'N') lx = ( MAT_BUFD(lmbda)[m] * MAT_BUFD(x)[m] - ddot_(&len, MAT_BUFD(lmbda) + m + 1, &int1, MAT_BUFD(x) + m + 1, &int1) ) / a; else lx = ddot_(&mk, MAT_BUFD(lmbda) + m, &int1, MAT_BUFD(x) + m, &int1) / a; x0 = MAT_BUFD(x)[m]; MAT_BUFD(x)[m] = lx; b = (x0 + lx) / (MAT_BUFD(lmbda)[m]/a + 1.0) / a; if (inverse == 'N') b *= -1.0; daxpy_(&len, &b, MAT_BUFD(lmbda) + m + 1, &int1, MAT_BUFD(x) + m + 1, &int1); if (inverse == 'N') a = 1.0 / a; dscal_(&mk, &a, MAT_BUFD(x) + m, &int1); m += mk; } /* * For the 's' blocks, if inverse is 'N', * * xk := vec( diag(l)^{-1/2} * mat(xk) * diag(k)^{-1/2}). * * If inverse is 'I', * * xk := vec( diag(l)^{1/2} * mat(xk) * diag(k)^{1/2}). * * where l is kth block of lambda. * * We scale upper and lower triangular part of mat(xk) because the * inverse operation will be applied to nonsymmetric matrices. */ O = PyDict_GetItemString(dims, "s"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 maxn = MAX(maxn, (int) PyLong_AsLong(Ok)); #else maxn = MAX(maxn, (int) PyInt_AsLong(Ok)); #endif } if (!(c = (double *) calloc(maxn, sizeof(double))) || !(sql = (double *) calloc(maxn, sizeof(double)))){ free(c); free(sql); return PyErr_NoMemory(); } ind2 = m; for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif for (j = 0; j < mk; j++) sql[j] = sqrt(MAT_BUFD(lmbda)[ind2 + j]); for (j = 0; j < mk; j++){ dcopy_(&mk, sql, &int1, c, &int1); b = sqrt(MAT_BUFD(lmbda)[ind2 + j]); dscal_(&mk, &b, c, &int1); if (inverse == 'N') dtbsv_("L", "N", "N", &mk, &int0, c, &int1, MAT_BUFD(x) + m + j*mk, &int1); else dtbmv_("L", "N", "N", &mk, &int0, c, &int1, MAT_BUFD(x) + m + j*mk, &int1); } m += mk*mk; ind2 += mk; } free(c); free(sql); return Py_BuildValue(""); } static char doc_pack[] = "Copy x to y using packed storage.\n\n" "pack(x, y, dims, mnl = 0, offsetx = 0, offsety = 0)\n\n" "The vector x is an element of S, with the 's' components stored in\n" "unpacked storage. On return, x is copied to y with the 's' \n" "components stored in packed storage and the off-diagonal entries \n" "scaled by sqrt(2)."; static PyObject* pack(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; PyObject *O, *Ok, *dims; double a; int i, k, nlq = 0, ox = 0, oy = 0, np, iu, ip, int1 = 1, len, n; char *kwlist[] = {"x", "y", "dims", "mnl", "offsetx", "offsety", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iii", kwlist, &x, &y, &dims, &nlq, &ox, &oy)) return NULL; O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 nlq += (int) PyLong_AsLong(O); #else nlq += (int) PyInt_AsLong(O); #endif O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 nlq += (int) PyLong_AsLong(Ok); #else nlq += (int) PyInt_AsLong(Ok); #endif } dcopy_(&nlq, MAT_BUFD(x) + ox, &int1, MAT_BUFD(y) + oy, &int1); O = PyDict_GetItemString(dims, "s"); for (i = 0, np = 0, iu = ox + nlq, ip = oy + nlq; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 n = (int) PyLong_AsLong(Ok); #else n = (int) PyInt_AsLong(Ok); #endif for (k = 0; k < n; k++){ len = n-k; dcopy_(&len, MAT_BUFD(x) + iu + k*(n+1), &int1, MAT_BUFD(y) + ip, &int1); MAT_BUFD(y)[ip] /= sqrt(2.0); ip += len; } np += n*(n+1)/2; iu += n*n; } a = sqrt(2.0); dscal_(&np, &a, MAT_BUFD(y) + oy + nlq, &int1); return Py_BuildValue(""); } static char doc_pack2[] = "In-place version of pack().\n\n" "pack2(x, dims, mnl = 0)\n\n" "In-place version of pack(), which also accepts matrix arguments x.\n" "The columns of x are elements of S, with the 's' components stored\n" "in unpacked storage. On return, the 's' components are stored in\n" "packed storage and the off-diagonal entries are scaled by sqrt(2)."; static PyObject* pack2(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; PyObject *O, *Ok, *dims; double a = sqrt(2.0), *wrk; int i, j, k, nlq = 0, iu, ip, len, n, maxn, xr, xc; char *kwlist[] = {"x", "dims", "mnl", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|i", kwlist, &x, &dims, &nlq)) return NULL; xr = x->nrows; xc = x->ncols; O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 nlq += (int) PyLong_AsLong(O); #else nlq += (int) PyInt_AsLong(O); #endif O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 nlq += (int) PyLong_AsLong(Ok); #else nlq += (int) PyInt_AsLong(Ok); #endif } O = PyDict_GetItemString(dims, "s"); for (i = 0, maxn = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 maxn = MAX(maxn, (int) PyLong_AsLong(Ok)); #else maxn = MAX(maxn, (int) PyInt_AsLong(Ok)); #endif } if (!maxn) return Py_BuildValue(""); if (!(wrk = (double *) calloc(maxn * xc, sizeof(double)))) return PyErr_NoMemory(); for (i = 0, iu = nlq, ip = nlq; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 n = (int) PyLong_AsLong(Ok); #else n = (int) PyInt_AsLong(Ok); #endif for (k = 0; k < n; k++){ len = n-k; dlacpy_(" ", &len, &xc, MAT_BUFD(x) + iu + k*(n+1), &xr, wrk, &maxn); for (j = 1; j < len; j++) dscal_(&xc, &a, wrk + j, &maxn); dlacpy_(" ", &len, &xc, wrk, &maxn, MAT_BUFD(x) + ip, &xr); ip += len; } iu += n*n; } free(wrk); return Py_BuildValue(""); } static char doc_unpack[] = "Unpacks x into y.\n\n" "unpack(x, y, dims, mnl = 0, offsetx = 0, offsety = 0)\n\n" "The vector x is an element of S, with the 's' components stored in\n" "unpacked storage and off-diagonal entries scaled by sqrt(2).\n" "On return, x is copied to y with the 's' components stored in\n" "unpacked storage."; static PyObject* unpack(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; PyObject *O, *Ok, *dims; double a = 1.0 / sqrt(2.0); int m = 0, ox = 0, oy = 0, int1 = 1, iu, ip, len, i, k, n; char *kwlist[] = {"x", "y", "dims", "mnl", "offsetx", "offsety", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iii", kwlist, &x, &y, &dims, &m, &ox, &oy)) return NULL; O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 m += (int) PyLong_AsLong(O); #else m += (int) PyInt_AsLong(O); #endif O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 m += (int) PyLong_AsLong(Ok); #else m += (int) PyInt_AsLong(Ok); #endif } dcopy_(&m, MAT_BUFD(x) + ox, &int1, MAT_BUFD(y) + oy, &int1); O = PyDict_GetItemString(dims, "s"); for (i = 0, ip = ox + m, iu = oy + m; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 n = (int) PyLong_AsLong(Ok); #else n = (int) PyInt_AsLong(Ok); #endif for (k = 0; k < n; k++){ len = n-k; dcopy_(&len, MAT_BUFD(x) + ip, &int1, MAT_BUFD(y) + iu + k*(n+1), &int1); ip += len; len -= 1; dscal_(&len, &a, MAT_BUFD(y) + iu + k*(n+1) + 1, &int1); } iu += n*n; } return Py_BuildValue(""); } static char doc_symm[] = "Converts lower triangular matrix to symmetric.\n\n" "symm(x, n, offset = 0)\n\n" "Fills in the upper triangular part of the symmetric matrix stored\n" "in x[offset : offset+n*n] using 'L' storage."; static PyObject* symm(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; int n, ox = 0, k, len, int1 = 1; char *kwlist[] = {"x", "n", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "Oi|i", kwlist, &x, &n, &ox)) return NULL; if (n > 1) for (k = 0; k < n; k++){ len = n-k-1; dcopy_(&len, MAT_BUFD(x) + ox + k*(n+1) + 1, &int1, MAT_BUFD(x) + ox + (k+1)*(n+1)-1, &n); } return Py_BuildValue(""); } static char doc_sprod[] = "The product x := (y o x).\n\n" "sprod(x, y, dims, mnl = 0, diag = 'N')\n\n" "If diag is 'D', the 's' part of y is diagonal and only the diagonal\n" "is stored."; static PyObject* sprod(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; PyObject *dims, *O, *Ok; int i, j, k, mk, len, maxn, ind = 0, ind2, int0 = 0, int1 = 1, ld; double a, *A = NULL, dbl2 = 0.5, dbl0 = 0.0; #if PY_MAJOR_VERSION >= 3 int diag = 'N'; #else char diag = 'N'; #endif char *kwlist[] = {"x", "y", "dims", "mnl", "diag", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|iC", kwlist, &x, &y, &dims, &ind, &diag)) return NULL; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ic", kwlist, &x, &y, &dims, &ind, &diag)) return NULL; #endif /* * For nonlinear and 'l' blocks: * * yk o xk = yk .* xk */ O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 ind += (int) PyLong_AsLong(O); #else ind += (int) PyInt_AsLong(O); #endif dtbmv_("L", "N", "N", &ind, &int0, MAT_BUFD(y), &int1, MAT_BUFD(x), &int1); /* * For 'q' blocks: * * [ l0 l1' ] * yk o xk = [ ] * xk * [ l1 l0*I ] * * where yk = (l0, l1). */ O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif a = ddot_(&mk, MAT_BUFD(y) + ind, &int1, MAT_BUFD(x) + ind, &int1); len = mk - 1; dscal_(&len, MAT_BUFD(y) + ind, MAT_BUFD(x) + ind + 1, &int1); daxpy_(&len, MAT_BUFD(x) + ind, MAT_BUFD(y) + ind + 1, &int1, MAT_BUFD(x) + ind + 1, &int1); MAT_BUFD(x)[ind] = a; ind += mk; } /* * For the 's' blocks: * * yk o sk = .5 * ( Yk * mat(xk) + mat(xk) * Yk ) * * where Yk = mat(yk) if diag is 'N' and Yk = diag(yk) if diag is 'D'. */ O = PyDict_GetItemString(dims, "s"); for (i = 0, maxn = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 maxn = MAX(maxn, (int) PyLong_AsLong(Ok)); #else maxn = MAX(maxn, (int) PyInt_AsLong(Ok)); #endif } if (diag == 'N'){ if (!(A = (double *) calloc(maxn * maxn, sizeof(double)))) return PyErr_NoMemory(); for (i = 0; i < (int) PyList_Size(O); ind += mk*mk, i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif len = mk*mk; dcopy_(&len, MAT_BUFD(x) + ind, &int1, A, &int1); if (mk > 1) for (k = 0; k < mk; k++){ len = mk - k - 1; dcopy_(&len, A + k*(mk+1) + 1, &int1, A + (k+1)*(mk+1)-1, &mk); dcopy_(&len, MAT_BUFD(y) + ind + k*(mk+1) + 1, &int1, MAT_BUFD(y) + ind + (k+1)*(mk+1)-1, &mk); } ld = MAX(1, mk); dsyr2k_("L", "N", &mk, &mk, &dbl2, A, &ld, MAT_BUFD(y) + ind, &ld, &dbl0, MAT_BUFD(x) + ind, &ld); } } else { if (!(A = (double *) calloc(maxn, sizeof(double)))) return PyErr_NoMemory(); for (i = 0, ind2 = ind; i < (int) PyList_Size(O); ind += mk*mk, ind2 += mk, i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif for (k = 0; k < mk; k++){ len = mk - k; dcopy_(&len, MAT_BUFD(y) + ind2 + k, &int1, A, &int1); for (j = 0; j < len; j++) A[j] += MAT_BUFD(y)[ind2 + k]; dscal_(&len, &dbl2, A, &int1); dtbmv_("L", "N", "N", &len, &int0, A, &int1, MAT_BUFD(x) + ind + k * (mk+1), &int1); } } } free(A); return Py_BuildValue(""); } static char doc_sinv[] = "The inverse of the product x := (y o x) when the 's' components of \n" "y are diagonal.\n\n" "sinv(x, y, dims, mnl = 0)"; static PyObject* sinv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; PyObject *dims, *O, *Ok; int i, j, k, mk, len, maxn, ind = 0, ind2, int0 = 0, int1 = 1; double a, c, d, alpha, *A = NULL, dbl2 = 0.5; char *kwlist[] = {"x", "y", "dims", "mnl", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|i", kwlist, &x, &y, &dims, &ind)) return NULL; /* * For nonlinear and 'l' blocks: * * yk o\ xk = yk .\ xk */ O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 ind += (int) PyLong_AsLong(O); #else ind += (int) PyInt_AsLong(O); #endif dtbsv_("L", "N", "N", &ind, &int0, MAT_BUFD(y), &int1, MAT_BUFD(x), &int1); /* * For 'q' blocks: * * [ l0 -l1' ] * yk o\ xk = 1/a^2 * [ ] * xk * [ -l1 (a*I + l1*l1')/l0 ] * * where yk = (l0, l1) and a = l0^2 - l1'*l1. */ O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif len = mk - 1; a = dnrm2_(&len, MAT_BUFD(y) + ind + 1, &int1); a = (MAT_BUFD(y)[ind] + a) * (MAT_BUFD(y)[ind] - a); c = MAT_BUFD(x)[ind]; d = ddot_(&len, MAT_BUFD(x) + ind + 1, &int1, MAT_BUFD(y) + ind + 1, &int1); MAT_BUFD(x)[ind] = c * MAT_BUFD(y)[ind] - d; alpha = a / MAT_BUFD(y)[ind]; dscal_(&len, &alpha, MAT_BUFD(x) + ind + 1, &int1); alpha = d / MAT_BUFD(y)[ind] - c; daxpy_(&len, &alpha, MAT_BUFD(y) + ind + 1, &int1, MAT_BUFD(x) + ind + 1, &int1); alpha = 1.0 / a; dscal_(&mk, &alpha, MAT_BUFD(x) + ind, &int1); ind += mk; } /* * For the 's' blocks: * * yk o\ sk = xk ./ gamma * * where gammaij = .5 * (yk_i + yk_j). */ O = PyDict_GetItemString(dims, "s"); for (i = 0, maxn = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 maxn = MAX(maxn, (int) PyLong_AsLong(Ok)); #else maxn = MAX(maxn, (int) PyInt_AsLong(Ok)); #endif } if (!(A = (double *) calloc(maxn, sizeof(double)))) return PyErr_NoMemory(); for (i = 0, ind2 = ind; i < (int) PyList_Size(O); ind += mk*mk, ind2 += mk, i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif for (k = 0; k < mk; k++){ len = mk - k; dcopy_(&len, MAT_BUFD(y) + ind2 + k, &int1, A, &int1); for (j = 0; j < len; j++) A[j] += MAT_BUFD(y)[ind2 + k]; dscal_(&len, &dbl2, A, &int1); dtbsv_("L", "N", "N", &len, &int0, A, &int1, MAT_BUFD(x) + ind + k * (mk+1), &int1); } } free(A); return Py_BuildValue(""); } static char doc_trisc[] = "Sets the upper triangular part of the 's' components of x equal to\n" "zero and scales the strictly lower triangular part\n\n" "trisc(x, dims, offset = 0)"; static PyObject* trisc(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; double dbl0 = 0.0, dbl2 = 2.0; int ox = 0, i, k, nk, len, int1 = 1; PyObject *dims, *O, *Ok; char *kwlist[] = {"x", "dims", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|i", kwlist, &x, &dims, &ox)) return NULL; O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 ox += (int) PyLong_AsLong(O); #else ox += (int) PyInt_AsLong(O); #endif O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 ox += (int) PyLong_AsLong(Ok); #else ox += (int) PyInt_AsLong(Ok); #endif } O = PyDict_GetItemString(dims, "s"); for (k = 0; k < (int) PyList_Size(O); k++){ Ok = PyList_GetItem(O, (Py_ssize_t) k); #if PY_MAJOR_VERSION >= 3 nk = (int) PyLong_AsLong(Ok); #else nk = (int) PyInt_AsLong(Ok); #endif for (i = 1; i < nk; i++){ len = nk - i; dscal_(&len, &dbl0, MAT_BUFD(x) + ox + i*(nk+1) - 1, &nk); dscal_(&len, &dbl2, MAT_BUFD(x) + ox + nk*(i-1) + i, &int1); } ox += nk*nk; } return Py_BuildValue(""); } static char doc_triusc[] = "Scales the strictly lower triangular part of the 's' components of\n" "x by 0.5.\n\n" "triusc(x, dims, offset = 0)"; static PyObject* triusc(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; double dbl5 = 0.5; int ox = 0, i, k, nk, len, int1 = 1; PyObject *dims, *O, *Ok; char *kwlist[] = {"x", "dims", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|i", kwlist, &x, &dims, &ox)) return NULL; O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 ox += (int) PyLong_AsLong(O); #else ox += (int) PyInt_AsLong(O); #endif O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 ox += (int) PyLong_AsLong(Ok); #else ox += (int) PyInt_AsLong(Ok); #endif } O = PyDict_GetItemString(dims, "s"); for (k = 0; k < (int) PyList_Size(O); k++){ Ok = PyList_GetItem(O, (Py_ssize_t) k); #if PY_MAJOR_VERSION >= 3 nk = (int) PyLong_AsLong(Ok); #else nk = (int) PyInt_AsLong(Ok); #endif for (i = 1; i < nk; i++){ len = nk - i; dscal_(&len, &dbl5, MAT_BUFD(x) + ox + nk*(i-1) + i, &int1); } ox += nk*nk; } return Py_BuildValue(""); } static char doc_sdot[] = "Inner product of two vectors in S.\n\n" "sdot(x, y, dims, mnl= 0)"; static PyObject* sdot(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; int m = 0, int1 = 1, i, k, nk, inc, len; double a; PyObject *dims, *O, *Ok; char *kwlist[] = {"x", "y", "dims", "mnl", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|i", kwlist, &x, &y, &dims, &m)) return NULL; O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 m += (int) PyLong_AsLong(O); #else m += (int) PyInt_AsLong(O); #endif O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 m += (int) PyLong_AsLong(Ok); #else m += (int) PyInt_AsLong(Ok); #endif } a = ddot_(&m, MAT_BUFD(x), &int1, MAT_BUFD(y), &int1); O = PyDict_GetItemString(dims, "s"); for (k = 0; k < (int) PyList_Size(O); k++){ Ok = PyList_GetItem(O, (Py_ssize_t) k); #if PY_MAJOR_VERSION >= 3 nk = (int) PyLong_AsLong(Ok); #else nk = (int) PyInt_AsLong(Ok); #endif inc = nk+1; a += ddot_(&nk, MAT_BUFD(x) + m, &inc, MAT_BUFD(y) + m, &inc); for (i = 1; i < nk; i++){ len = nk - i; a += 2.0 * ddot_(&len, MAT_BUFD(x) + m + i, &inc, MAT_BUFD(y) + m + i, &inc); } m += nk*nk; } return Py_BuildValue("d", a); } static char doc_max_step[] = "Returns min {t | x + t*e >= 0}\n\n." "max_step(x, dims, mnl = 0, sigma = None)\n\n" "e is defined as follows\n\n" "- For the nonlinear and 'l' blocks: e is the vector of ones.\n" "- For the 'q' blocks: e is the first unit vector.\n" "- For the 's' blocks: e is the identity matrix.\n\n" "When called with the argument sigma, also returns the eigenvalues\n" "(in sigma) and the eigenvectors (in x) of the 's' components of x.\n"; static PyObject* max_step(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *sigma = NULL; PyObject *dims, *O, *Ok; int i, mk, len, maxn, ind = 0, ind2, int1 = 1, ld, Ns = 0, info, lwork, *iwork = NULL, liwork, iwl, m; double t = -FLT_MAX, dbl0 = 0.0, *work = NULL, wl, *Q = NULL, *w = NULL; char *kwlist[] = {"x", "dims", "mnl", "sigma", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iO", kwlist, &x, &dims, &ind, &sigma)) return NULL; O = PyDict_GetItemString(dims, "l"); #if PY_MAJOR_VERSION >= 3 ind += (int) PyLong_AsLong(O); #else ind += (int) PyInt_AsLong(O); #endif for (i = 0; i < ind; i++) t = MAX(t, -MAT_BUFD(x)[i]); O = PyDict_GetItemString(dims, "q"); for (i = 0; i < (int) PyList_Size(O); i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif len = mk - 1; t = MAX(t, dnrm2_(&len, MAT_BUFD(x) + ind + 1, &int1) - MAT_BUFD(x)[ind]); ind += mk; } O = PyDict_GetItemString(dims, "s"); Ns = (int) PyList_Size(O); for (i = 0, maxn = 0; i < Ns; i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 maxn = MAX(maxn, (int) PyLong_AsLong(Ok)); #else maxn = MAX(maxn, (int) PyInt_AsLong(Ok)); #endif } if (!maxn) return Py_BuildValue("d", (ind) ? t : 0.0); lwork = -1; liwork = -1; ld = MAX(1, maxn); if (sigma){ dsyevd_("V", "L", &maxn, NULL, &ld, NULL, &wl, &lwork, &iwl, &liwork, &info); } else { if (!(Q = (double *) calloc(maxn * maxn, sizeof(double))) || !(w = (double *) calloc(maxn, sizeof(double)))){ free(Q); free(w); return PyErr_NoMemory(); } dsyevr_("N", "I", "L", &maxn, NULL, &ld, &dbl0, &dbl0, &int1, &int1, &dbl0, &maxn, NULL, NULL, &int1, NULL, &wl, &lwork, &iwl, &liwork, &info); } lwork = (int) wl; liwork = iwl; if (!(work = (double *) calloc(lwork, sizeof(double))) || (!(iwork = (int *) calloc(liwork, sizeof(int))))){ free(Q); free(w); free(work); free(iwork); return PyErr_NoMemory(); } for (i = 0, ind2 = 0; i < Ns; i++){ Ok = PyList_GetItem(O, (Py_ssize_t) i); #if PY_MAJOR_VERSION >= 3 mk = (int) PyLong_AsLong(Ok); #else mk = (int) PyInt_AsLong(Ok); #endif if (mk){ if (sigma){ dsyevd_("V", "L", &mk, MAT_BUFD(x) + ind, &mk, MAT_BUFD(sigma) + ind2, work, &lwork, iwork, &liwork, &info); t = MAX(t, -MAT_BUFD(sigma)[ind2]); } else { len = mk*mk; dcopy_(&len, MAT_BUFD(x) + ind, &int1, Q, &int1); ld = MAX(1, mk); dsyevr_("N", "I", "L", &mk, Q, &mk, &dbl0, &dbl0, &int1, &int1, &dbl0, &m, w, NULL, &int1, NULL, work, &lwork, iwork, &liwork, &info); t = MAX(t, -w[0]); } } ind += mk*mk; ind2 += mk; } free(work); free(iwork); free(Q); free(w); return Py_BuildValue("d", (ind) ? t : 0.0); } static PyMethodDef misc_solvers_functions[] = { {"scale", (PyCFunction) scale, METH_VARARGS|METH_KEYWORDS, doc_scale}, {"scale2", (PyCFunction) scale2, METH_VARARGS|METH_KEYWORDS, doc_scale2}, {"pack", (PyCFunction) pack, METH_VARARGS|METH_KEYWORDS, doc_pack}, {"pack2", (PyCFunction) pack2, METH_VARARGS|METH_KEYWORDS, doc_pack2}, {"unpack", (PyCFunction) unpack, METH_VARARGS|METH_KEYWORDS, doc_unpack}, {"symm", (PyCFunction) symm, METH_VARARGS|METH_KEYWORDS, doc_symm}, {"trisc", (PyCFunction) trisc, METH_VARARGS|METH_KEYWORDS, doc_trisc}, {"triusc", (PyCFunction) triusc, METH_VARARGS|METH_KEYWORDS, doc_triusc}, {"sdot", (PyCFunction) sdot, METH_VARARGS|METH_KEYWORDS, doc_sdot}, {"sprod", (PyCFunction) sprod, METH_VARARGS|METH_KEYWORDS, doc_sprod}, {"sinv", (PyCFunction) sinv, METH_VARARGS|METH_KEYWORDS, doc_sinv}, {"max_step", (PyCFunction) max_step, METH_VARARGS|METH_KEYWORDS, doc_max_step}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef misc_solvers_module = { PyModuleDef_HEAD_INIT, "misc_solvers", misc_solvers__doc__, -1, misc_solvers_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_misc_solvers(void) { PyObject *m; if (!(m = PyModule_Create(&misc_solvers_module))) return NULL; if (import_cvxopt() < 0) return NULL; return m; } #else PyMODINIT_FUNC initmisc_solvers(void) { PyObject *m; m = Py_InitModule3("cvxopt.misc_solvers", misc_solvers_functions, misc_solvers__doc__); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/blas.c0000644000175000017500000041244211674452555014151 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Python.h" #include "cvxopt.h" #include "misc.h" #define USE_CBLAS_ZDOT 0 PyDoc_STRVAR(blas__doc__,"Interface to the double-precision real and " "complex BLAS.\n\n" "Double and complex matrices and vectors are stored in CVXOPT \n" "matrices using the conventional BLAS storage schemes, with the\n" "CVXOPT matrix buffers interpreted as one-dimensional arrays.\n" "For each matrix argument X, an additional integer argument\n" "offsetX specifies the start of the array, i.e., the pointer\n" "X->buffer + offsetX is passed to the BLAS function. The other \n" "arguments (dimensions and options) have the same meaning as in\n" "the BLAS definition. Default values of the dimension arguments\n" "are derived from the CVXOPT matrix sizes."); /* BLAS 1 prototypes */ extern void dswap_(int *n, double *x, int *incx, double *y, int *incy); extern void zswap_(int *n, complex *x, int *incx, complex *y, int *incy); extern void dscal_(int *n, double *alpha, double *x, int *incx); extern void zscal_(int *n, complex *alpha, complex *x, int *incx); extern void zdscal_(int *n, double *alpha, complex *x, int *incx); extern void dcopy_(int *n, double *x, int *incx, double *y, int *incy); extern void zcopy_(int *n, complex *x, int *incx, complex *y, int *incy); extern void daxpy_(int *n, double *alpha, double *x, int *incx, double *y, int *incy); extern void zaxpy_(int *n, complex *alpha, complex *x, int *incx, complex *y, int *incy); extern double ddot_(int *n, double *x, int *incx, double *y, int *incy); #if USE_CBLAS_ZDOT extern void cblas_zdotc_sub(int n, void *x, int incx, void *y, int incy, void *result); extern void cblas_zdotu_sub(int n, void *x, int incx, void *y, int incy, void *result); #endif extern double dnrm2_(int *n, double *x, int *incx); extern double dznrm2_(int *n, complex *x, int *incx); extern double dasum_(int *n, double *x, int *incx); extern double dzasum_(int *n, complex *x, int *incx); extern int idamax_(int *n, double *x, int *incx); extern int izamax_(int *n, complex *x, int *incx); /* BLAS 2 prototypes */ extern void dgemv_(char* trans, int *m, int *n, double *alpha, double *A, int *lda, double *x, int *incx, double *beta, double *y, int *incy); extern void zgemv_(char* trans, int *m, int *n, complex *alpha, complex *A, int *lda, complex *x, int *incx, complex *beta, complex *y, int *incy); extern void dgbmv_(char* trans, int *m, int *n, int *kl, int *ku, double *alpha, double *A, int *lda, double *x, int *incx, double *beta, double *y, int *incy); extern void zgbmv_(char* trans, int *m, int *n, int *kl, int *ku, complex *alpha, complex *A, int *lda, complex *x, int *incx, complex *beta, complex *y, int *incy); extern void dsymv_(char *uplo, int *n, double *alpha, double *A, int *lda, double *x, int *incx, double *beta, double *y, int *incy); extern void zhemv_(char *uplo, int *n, complex *alpha, complex *A, int *lda, complex *x, int *incx, complex *beta, complex *y, int *incy); extern void dsbmv_(char *uplo, int *n, int *k, double *alpha, double *A, int *lda, double *x, int *incx, double *beta, double *y, int *incy); extern void zhbmv_(char *uplo, int *n, int *k, complex *alpha, complex *A, int *lda, complex *x, int *incx, complex *beta, complex *y, int *incy); extern void dtrmv_(char *uplo, char *trans, char *diag, int *n, double *A, int *lda, double *x, int *incx); extern void ztrmv_(char *uplo, char *trans, char *diag, int *n, complex *A, int *lda, complex *x, int *incx); extern void dtbmv_(char *uplo, char *trans, char *diag, int *n, int *k, double *A, int *lda, double *x, int *incx); extern void ztbmv_(char *uplo, char *trans, char *diag, int *n, int *k, complex *A, int *lda, complex *x, int *incx); extern void dtrsv_(char *uplo, char *trans, char *diag, int *n, double *A, int *lda, double *x, int *incx); extern void ztrsv_(char *uplo, char *trans, char *diag, int *n, complex *A, int *lda, complex *x, int *incx); extern void dtbsv_(char *uplo, char *trans, char *diag, int *n, int *k, double *A, int *lda, double *x, int *incx); extern void ztbsv_(char *uplo, char *trans, char *diag, int *n, int *k, complex *A, int *lda, complex *x, int *incx); extern void dger_(int *m, int *n, double *alpha, double *x, int *incx, double *y, int *incy, double *A, int *lda); extern void zgerc_(int *m, int *n, complex *alpha, complex *x, int *incx, complex *y, int *incy, complex *A, int *lda); extern void zgeru_(int *m, int *n, complex *alpha, complex *x, int *incx, complex *y, int *incy, complex *A, int *lda); extern void dsyr_(char *uplo, int *n, double *alpha, double *x, int *incx, double *A, int *lda); extern void zher_(char *uplo, int *n, double *alpha, complex *x, int *incx, complex *A, int *lda); extern void dsyr2_(char *uplo, int *n, double *alpha, double *x, int *incx, double *y, int *incy, double *A, int *lda); extern void zher2_(char *uplo, int *n, complex *alpha, complex *x, int *incx, complex *y, int *incy, complex *A, int *lda); /* BLAS 3 prototypes */ extern void dgemm_(char *transa, char *transb, int *m, int *n, int *k, double *alpha, double *A, int *lda, double *B, int *ldb, double *beta, double *C, int *ldc); extern void zgemm_(char *transa, char *transb, int *m, int *n, int *k, complex *alpha, complex *A, int *lda, complex *B, int *ldb, complex *beta, complex *C, int *ldc); extern void dsymm_(char *side, char *uplo, int *m, int *n, double *alpha, double *A, int *lda, double *B, int *ldb, double *beta, double *C, int *ldc); extern void zsymm_(char *side, char *uplo, int *m, int *n, complex *alpha, complex *A, int *lda, complex *B, int *ldb, complex *beta, complex *C, int *ldc); extern void zhemm_(char *side, char *uplo, int *m, int *n, complex *alpha, complex *A, int *lda, complex *B, int *ldb, complex *beta, complex *C, int *ldc); extern void dsyrk_(char *uplo, char *trans, int *n, int *k, double *alpha, double *A, int *lda, double *beta, double *B, int *ldb); extern void zsyrk_(char *uplo, char *trans, int *n, int *k, complex *alpha, complex *A, int *lda, complex *beta, complex *B, int *ldb); extern void zherk_(char *uplo, char *trans, int *n, int *k, double *alpha, complex *A, int *lda, double *beta, complex *B, int *ldb); extern void dsyr2k_(char *uplo, char *trans, int *n, int *k, double *alpha, double *A, int *lda, double *B, int *ldb, double *beta, double *C, int *ldc); extern void zsyr2k_(char *uplo, char *trans, int *n, int *k, complex *alpha, complex *A, int *lda, complex *B, int *ldb, complex *beta, complex *C, int *ldc); extern void zher2k_(char *uplo, char *trans, int *n, int *k, complex *alpha, complex *A, int *lda, complex *B, int *ldb, double *beta, complex *C, int *ldc); extern void dtrmm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n, double *alpha, double *A, int *lda, double *B, int *ldb); extern void ztrmm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n, complex *alpha, complex *A, int *lda, complex *B, int *ldb); extern void dtrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n, double *alpha, double *A, int *lda, double *B, int *ldb); extern void ztrsm_(char *side, char *uplo, char *transa, char *diag, int *m, int *n, complex *alpha, complex *A, int *lda, complex *B, int *ldb); static int number_from_pyobject(PyObject *o, number *a, int id) { switch (id){ case DOUBLE: #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(o) && !PyLong_Check(o) && !PyFloat_Check(o)) return -1; #else if (!PyInt_Check(o) && !PyLong_Check(o) && !PyFloat_Check(o)) return -1; #endif (*a).d = PyFloat_AsDouble(o); return 0; case COMPLEX: #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(o) && !PyLong_Check(o) && !PyFloat_Check(o) && !PyComplex_Check(o)) return -1; #else if (!PyInt_Check(o) && !PyLong_Check(o) && !PyFloat_Check(o) && !PyComplex_Check(o)) return -1; #endif (*a).z = PyComplex_RealAsDouble(o) + I*PyComplex_ImagAsDouble(o); return 0; } return -1; } static char doc_swap[] = "Interchanges two vectors (x <-> y).\n\n" "swap(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " len(x)>=offsetx+1 ? 1+(len(x)-offsetx-1)/|incx| : 0.\n" " If the default value is used, it must be equal to\n" " len(y)>=offsety+1 ? 1+(len(y)-offsetx-1)/|incy| : 0.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer"; static PyObject* swap(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; int n=-1, ix=1, iy=1, ox=0, oy=0; char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx", "offsety", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &x, &y, &n, &ix, &iy, &ox, &oy)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (ox < 0) err_nn_int("offsetx"); if (oy < 0) err_nn_int("offsety"); if (n<0){ n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0; if (n != ((len(y) >= oy+1) ? 1+(len(y)-oy-1)/abs(iy) : 0)){ PyErr_SetString(PyExc_ValueError, "arrays have unequal " "default lengths"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (len(x) < ox+1+(n-1)*abs(ix)) err_buf_len("x"); if (len(y) < oy+1+(n-1)*abs(iy)) err_buf_len("y"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dswap_(&n, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zswap_(&n, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_scal[] = "Scales a vector by a constant (x := alpha*x).\n\n" "scal(alpha, x, n=None, inc=1, offset=0)\n\n" "ARGUMENTS\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if x is complex.\n\n" "x 'd' or 'z' matrix\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " (len(x)>=offset+1) ? 1+(len-offset-1)/inc : 0.\n\n" "inc positive integer\n\n" "offset nonnegative integer"; static PyObject* scal(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; PyObject *ao; number a; int n=-1, ix=1, ox=0; char *kwlist[] = {"alpha", "x", "n", "inc", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iii", kwlist, &ao, &x, &n, &ix, &ox)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (ix <= 0) err_p_int("inc"); if (ox < 0) err_nn_int("offset"); if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0; if (n == 0) return Py_BuildValue(""); if (len(x) < ox+1+(n-1)*ix) err_buf_len("x"); switch (MAT_ID(x)){ case DOUBLE: if (number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); Py_BEGIN_ALLOW_THREADS dscal_(&n, &a.d, MAT_BUFD(x)+ox, &ix); Py_END_ALLOW_THREADS break; case COMPLEX: if (!number_from_pyobject(ao, &a, DOUBLE)) Py_BEGIN_ALLOW_THREADS zdscal_(&n, &a.d, MAT_BUFZ(x)+ox, &ix); Py_END_ALLOW_THREADS else if (!number_from_pyobject(ao, &a, COMPLEX)) Py_BEGIN_ALLOW_THREADS zscal_(&n, &a.z, MAT_BUFZ(x)+ox, &ix); Py_END_ALLOW_THREADS else err_type("alpha"); break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_copy[] = "Copies a vector x to a vector y (y := x).\n\n" "copy(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is given by\n" " (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer"; static PyObject* copy(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; int n=-1, ix=1, iy=1, ox=0, oy=0; char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx", "offsety", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &x, &y, &n, &ix, &iy, &ox, &oy)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (ox < 0 ) err_nn_int("offsetx"); if (oy < 0 ) err_nn_int("offsety"); if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0; if (n == 0) return Py_BuildValue(""); if (len(x) < ox+1+(n-1)*abs(ix)) err_buf_len("x"); if (len(y) < oy+1+(n-1)*abs(iy)) err_buf_len("y"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dcopy_(&n, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zcopy_(&n, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_axpy[] = "Constant times a vector plus a vector (y := alpha*x+y).\n\n" "axpy(x, y, alpha=1.0, n=None, incx=1, incy=1, offsetx=0, " "offsety=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if x is complex.\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer"; static PyObject* axpy(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; PyObject *ao=NULL; number a; int n=-1, ix=1, iy=1, ox=0, oy=0; char *kwlist[] = {"x", "y", "alpha", "n", "incx", "incy", "offsetx", "offsety", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Oiiiii", kwlist, &x, &y, &ao, &n, &ix, &iy, &ox, &oy)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (ox < 0) err_nn_int("offsetx"); if (oy < 0) err_nn_int("offsety"); if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0; if (n == 0) return Py_BuildValue(""); if (len(x) < ox + 1+(n-1)*abs(ix)) err_buf_len("x"); if (len(y) < oy + 1+(n-1)*abs(iy)) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d=1.0; Py_BEGIN_ALLOW_THREADS daxpy_(&n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z=1.0; Py_BEGIN_ALLOW_THREADS zaxpy_(&n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_dot[] = "Returns x^H*y for real or complex x, y.\n\n" "dot(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n" " If the default value is used, it must be equal to\n" " len(y)>=offsety+1 ? 1+(len(y)-offsetx-1)/|incy| : 0.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "Returns 0 if n=0."; static PyObject* dot(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; number val; int n=-1, ix=1, iy=1, ox=0, oy=0; char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx", "offsety", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &x, &y, &n, &ix, &iy, &ox, &oy)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (ox < 0) err_nn_int("offsetx"); if (oy < 0) err_nn_int("offsety"); if (n<0){ n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0; if (n != ((len(y) >= oy+1) ? 1+(len(y)-oy-1)/abs(iy) : 0)){ PyErr_SetString(PyExc_ValueError, "arrays have unequal " "default lengths"); return NULL; } } if (n && len(x) < ox + 1 + (n-1)*abs(ix)) err_buf_len("x"); if (n && len(y) < oy + 1 + (n-1)*abs(iy)) err_buf_len("y"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS val.d = (n==0) ? 0.0 : ddot_(&n, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS return Py_BuildValue("d", val.d); case COMPLEX: if (n==0) val.z = 0.0; else #if USE_CBLAS_ZDOT cblas_zdotc_sub(n, MAT_BUFZ(x)+ox, ix, MAT_BUFZ(y)+oy, iy, &val.z); #else ix *= 2; iy *= 2; Py_BEGIN_ALLOW_THREADS val.z = (ddot_(&n, MAT_BUFD(x)+2*ox, &ix, MAT_BUFD(y)+2*oy, &iy) + ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, MAT_BUFD(y)+2*oy + 1, &iy)) + I*(ddot_(&n, MAT_BUFD(x)+2*ox, &ix, MAT_BUFD(y)+2*oy + 1, &iy) - ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, MAT_BUFD(y)+2*oy, &iy)); Py_END_ALLOW_THREADS #endif return PyComplex_FromDoubles(creal(val.z),cimag(val.z)); default: err_invalid_id; } } static char doc_dotu[] = "Returns x^T*y for real or complex x, y.\n\n" "dotu(x, y, n=None, incx=1, incy=1, offsetx=0, offsety=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n" " If the default value is used, it must be equal to\n" " len(y)>=offsety+1 ? 1+(len(y)-offsetx-1)/|incy| : 0.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "Returns 0 if n=0."; static PyObject* dotu(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; number val; int n=-1, ix=1, iy=1, ox=0, oy=0; char *kwlist[] = {"x", "y", "n", "incx", "incy", "offsetx", "offsety", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiiii", kwlist, &x, &y, &n, &ix, &iy, &ox, &oy)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (ox < 0) err_nn_int("offsetx"); if (oy < 0) err_nn_int("offsety"); if (n<0){ n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/abs(ix) : 0; if (n != ((len(y) >= oy+1) ? 1+(len(y)-oy-1)/abs(iy) : 0)){ PyErr_SetString(PyExc_ValueError, "arrays have unequal " "default lengths"); return NULL; } } if (n && len(x) < ox + 1 + (n-1)*abs(ix)) err_buf_len("x"); if (n && len(y) < oy + 1 + (n-1)*abs(iy)) err_buf_len("y"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS val.d = (n==0) ? 0.0 : ddot_(&n, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS return Py_BuildValue("d", val.d); case COMPLEX: if (n==0) val.z = 0.0; else #if USE_CBLAS_ZDOT Py_BEGIN_ALLOW_THREADS cblas_zdotu_sub(n, MAT_BUFZ(x)+ox, ix, MAT_BUFZ(y)+oy, iy, &val.z); Py_END_ALLOW_THREADS #else ix *= 2; iy *= 2; Py_BEGIN_ALLOW_THREADS val.z = (ddot_(&n, MAT_BUFD(x)+2*ox, &ix, MAT_BUFD(y)+2*oy, &iy) - ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, MAT_BUFD(y)+2*oy + 1, &iy)) + I*(ddot_(&n, MAT_BUFD(x)+2*ox, &ix, MAT_BUFD(y)+2*oy + 1, &iy) + ddot_(&n, MAT_BUFD(x)+2*ox + 1, &ix, MAT_BUFD(y)+2*oy, &iy)); Py_END_ALLOW_THREADS #endif return PyComplex_FromDoubles(creal(val.z),cimag(val.z)); default: err_invalid_id; } } static char doc_nrm2[] = "Returns the Euclidean norm of a vector (returns ||x||_2).\n\n" "nrm2(x, n=None, inc=1, offset=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n\n" "inc positive integer\n\n" "offset nonnegative integer\n\n" "Returns 0 if n=0."; static PyObject* nrm2(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; int n=-1, ix=1, ox=0; char *kwlist[] = {"x", "n", "inc", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|iii", kwlist, &x, &n, &ix, &ox)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (ix <= 0) err_p_int("incx"); if (ox < 0) err_nn_int("offsetx"); if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0; if (n == 0) return Py_BuildValue("d", 0.0); if (len(x) < ox + 1+(n-1)*ix) err_buf_len("x"); switch (MAT_ID(x)){ case DOUBLE: return Py_BuildValue("d", dnrm2_(&n, MAT_BUFD(x)+ox, &ix)); case COMPLEX: return Py_BuildValue("d", dznrm2_(&n, MAT_BUFZ(x)+ox, &ix)); default: err_invalid_id; } } static char doc_asum[] = "Returns ||Re x||_1 + ||Im x||_1.\n\n" "asum(x, n=None, inc=1, offset=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " n = (len(x)>=offset+1) ? 1+(len(x)-offset-1)/inc : 0.\n" "\n" "inc positive integer\n\n" "offset nonnegative integer\n\n" "Returns 0 if n=0."; static PyObject* asum(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; int n=-1, ix=1, ox=0; char *kwlist[] = {"x", "n", "inc", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|iii", kwlist, &x, &n, &ix, &ox)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (ix <= 0) err_p_int("inc"); if (ox < 0) err_nn_int("offset"); if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0; if (n == 0) return Py_BuildValue("d", 0.0); if (len(x) < ox + 1+(n-1)*ix) err_buf_len("x"); double val; switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS val = dasum_(&n, MAT_BUFD(x)+ox, &ix); Py_END_ALLOW_THREADS return Py_BuildValue("d", val); case COMPLEX: Py_BEGIN_ALLOW_THREADS val = dzasum_(&n, MAT_BUFZ(x)+ox, &ix); Py_END_ALLOW_THREADS return Py_BuildValue("d", val); default: err_invalid_id; } } static char doc_iamax[] = "Returns the index (in {0,...,n-1}) of the coefficient with \n" "maximum value of |Re x_k| + |Im x_k|.\n\n" "iamax(x, n=None, inc=1, offset=0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " (len(x)>=offset+1) ? 1+(len(x)-offset-1)/inc : 0.\n\n" "inc positive integer\n\n" "offset nonnegative integer\n\n" "In the case of ties, the index of the first maximizer is \n" "returned. If n=0, iamax returns 0."; static PyObject* iamax(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x; int n=-1, ix=1, ox=0; char *kwlist[] = {"x", "n", "inc", "offset", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|iii", kwlist, &x, &n, &ix, &ox)) return NULL; if (!Matrix_Check(x)) err_mtrx("x"); if (ix <= 0) err_p_int("inc"); if (ox < 0) err_nn_int("offset"); if (n < 0) n = (len(x) >= ox+1) ? 1+(len(x)-ox-1)/ix : 0; if (n == 0) return Py_BuildValue("i", 0); if (len(x) < ox + 1+(n-1)*ix) err_buf_len("x"); #if PY_MAJOR_VERSION >= 3 double val; #endif switch (MAT_ID(x)){ case DOUBLE: #if PY_MAJOR_VERSION >= 3 Py_BEGIN_ALLOW_THREADS val = idamax_(&n, MAT_BUFD(x)+ox, &ix)-1; Py_END_ALLOW_THREADS return Py_BuildValue("i", val); #else return Py_BuildValue("i", idamax_(&n, MAT_BUFD(x)+ox, &ix)-1); #endif case COMPLEX: #if PY_MAJOR_VERSION >= 3 Py_BEGIN_ALLOW_THREADS val = izamax_(&n, MAT_BUFZ(x)+ox, &ix)-1; Py_END_ALLOW_THREADS return Py_BuildValue("i", val); #else return Py_BuildValue("i", izamax_(&n, MAT_BUFZ(x)+ox, &ix)-1); #endif default: err_invalid_id; } } static char doc_gemv[] = "General matrix-vector product. \n\n" "gemv(A, x, y, trans='N', alpha=1.0, beta=0.0, m=A.size[0],\n" " n=A.size[1], ldA=max(1,A.size[0]), incx=1, incy=1, \n" " offsetA=0, offsetx=0, offsety=0)\n\n" "PURPOSE\n" "If trans is 'N', computes y := alpha*A*x + beta*y.\n" "If trans is 'T', computes y := alpha*A^T*x + beta*y.\n" "If trans is 'C', computes y := alpha*A^H*x + beta*y.\n" "The matrix A is m by n.\n" "Returns immediately if n=0 and trans is 'T' or 'C', or if m=0 \n" "and trans is 'N'.\n" "Computes y := beta*y if n=0, m>0 and trans is 'N', or if m=0, \n" "n>0 and trans is 'T' or 'C'.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "y 'd' or 'z' matrix. Must have the same type as A.\n\n" "trans 'N', 'T' or 'C'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "ldA nonnegative integer. ldA >= max(1,m).\n" " If zero, the default value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer"; static PyObject* gemv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL, *bo=NULL; number a, b; int m=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; #endif char trans='N'; char *kwlist[] = {"A", "x", "y", "trans", "alpha", "beta", "m", "n", "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COOiiiiiiii", kwlist, &A, &x, &y, &trans_, &ao, &bo, &m, &n, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiiii", kwlist, &A, &x, &y, &trans, &ao, &bo, &m, &n, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N','T','C'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if ((!m && trans == 'N') || (!n && (trans == 'T' || trans == 'C'))) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (n > 0 && m > 0 && oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if ((trans == 'N' && n > 0 && ox + (n-1)*abs(ix) + 1 > len(x)) || ((trans == 'T' || trans == 'C') && m > 0 && ox + (m-1)*abs(ix) + 1 > len(x))) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if ((trans == 'N' && oy + (m-1)*abs(iy) + 1 > len(y)) || ((trans == 'T' || trans == 'C') && oy + (n-1)*abs(iy) + 1 > len(y))) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) err_type("beta"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d=1.0; if (!bo) b.d=0.0; if (trans == 'N' && n == 0) Py_BEGIN_ALLOW_THREADS dscal_(&m, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS else if ((trans == 'T' || trans == 'C') && m == 0) Py_BEGIN_ALLOW_THREADS dscal_(&n, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS else Py_BEGIN_ALLOW_THREADS dgemv_(&trans, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z=1.0; if (!bo) b.z=0.0; if (trans == 'N' && n == 0) Py_BEGIN_ALLOW_THREADS zscal_(&m, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS else if ((trans == 'T' || trans == 'C') && m == 0) Py_BEGIN_ALLOW_THREADS zscal_(&n, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS else Py_BEGIN_ALLOW_THREADS zgemv_(&trans, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_gbmv[] = "Matrix-vector product with a general banded matrix.\n\n" "gbmv(A, m, kl, x, y, trans='N', alpha=1.0, beta=0.0, n=A.size[1],\n" " ku=A.size[0]-kl-1, ldA=max(1,A.size[0]), incx=1, incy=1, \n" " offsetA=0, offsetx=0, offsety=0)\n\n" "PURPOSE\n" "If trans is 'N', computes y := alpha*A*x + beta*y.\n" "If trans is 'T', computes y := alpha*A^T*x + beta*y.\n" "If trans is 'C', computes y := alpha*A^H*x + beta*y.\n" "The matrix A is m by n with upper bandwidth ku and lower\n" "bandwidth kl.\n" "Returns immediately if n=0 and trans is 'T' or 'C', or if m=0 \n" "and trans is 'N'.\n" "Computes y := beta*y if n=0, m>0, and trans is 'N', or if m=0, n>0,\n" "and trans is 'T' or 'C'.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix. Must have the same type as A.\n\n" "m nonnegative integer\n\n" "kl nonnegative integer\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "y 'd' or 'z' matrix. Must have the same type as A.\n\n" "trans 'N', 'T' or 'C'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "n nonnegative integer. If negative, the default value is\n" " used.\n\n" "ku nonnegative integer. If negative, the default value is\n" " used.\n" "ldA positive integer. ldA >= kl+ku+1. If zero, the default\n" " value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer"; static PyObject* gbmv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL, *bo=NULL; number a, b; int m, kl, ku=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; #endif char trans = 'N'; char *kwlist[] = {"A", "m", "kl", "x", "y", "trans", "alpha", "beta", "n", "ku", "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiiOO|COOiiiiiiii", kwlist, &A, &m, &kl, &x, &y, &trans_, &ao, &bo, &n, &ku, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OiiOO|cOOiiiiiiii", kwlist, &A, &m, &kl, &x, &y, &trans, &ao, &bo, &n, &ku, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0) n = A->ncols; if ((!m && trans == 'N') || (!n && (trans == 'T' || trans == 'C'))) return Py_BuildValue(""); if (kl < 0) err_nn_int("kl"); if (ku < 0) ku = A->nrows - 1 - kl; if (ku < 0) err_nn_int("ku"); if (ldA == 0) ldA = A->nrows; if (ldA < kl+ku+1) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (m>0 && n>0 && oA + (n-1)*ldA + kl + ku + 1 > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if ((trans == 'N' && n > 0 && ox + (n-1)*abs(ix) + 1 > len(x)) || ((trans == 'T' || trans == 'C') && m > 0 && ox + (m-1)*abs(ix) + 1 > len(x))) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if ((trans == 'N' && oy + (m-1)*abs(iy) + 1 > len(y)) || ((trans == 'T' || trans == 'C') && oy + (n-1)*abs(iy) + 1 > len(y))) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) err_type("beta"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d=1.0; if (!bo) b.d=0.0; if (trans == 'N' && n == 0) Py_BEGIN_ALLOW_THREADS dscal_(&m, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS else if ((trans == 'T' || trans == 'C') && m == 0) Py_BEGIN_ALLOW_THREADS dscal_(&n, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS else Py_BEGIN_ALLOW_THREADS dgbmv_(&trans, &m, &n, &kl, &ku, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z=1.0; if (!bo) b.z=0.0; if (trans == 'N' && n == 0) Py_BEGIN_ALLOW_THREADS zscal_(&m, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS else if ((trans == 'T' || trans == 'C') && m == 0) Py_BEGIN_ALLOW_THREADS zscal_(&n, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS else Py_BEGIN_ALLOW_THREADS zgbmv_(&trans, &m, &n, &kl, &ku, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_symv[] = "Matrix-vector product with a real symmetric matrix.\n\n" "symv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[0], \n" " ldA=max(1,A.size[0]), incx=1, incy=1, offsetA=0, offsetx=0,\n" " offsety=0)\n\n" "PURPOSE\n" "Computes y := alpha*A*x + beta*y with A real symmetric of order n." "\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "x 'd' matrix\n\n" "y 'd' matrix\n\n" "uplo 'L' or 'U'\n\n" "alpha real number (int or float)\n\n" "beta real number (int or float)\n\n" "n integer. If negative, the default value is used.\n" " If the default value is used, we require that\n" " A.size[0]=A.size[1].\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer"; static PyObject* symv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COOiiiiiii", kwlist, &A, &x, &y, &uplo_, &ao, &bo, &n, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiii", kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_ValueError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) err_type("beta"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d=1.0; if (!bo) b.d=0.0; Py_BEGIN_ALLOW_THREADS dsymv_(&uplo, &n, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_hemv[] = "Matrix-vector product with a real symmetric or complex Hermitian\n" "matrix.\n\n" "hemv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[0],\n" " ldA=max(1,A.size[0]), incx=1, incy=1, offsetA=0, offsetx=0,\n" " offsety=0)\n\n" "PURPOSE\n" "Computes y := alpha*A*x + beta*y, with A real symmetric or\n" "complex Hermitian of order n.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "y 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "n integer. If negative, the default value is used.\n" " If the default value is used, we require that\n" " A.size[0]=A.size[1].\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "incx nonzero integer\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer"; static PyObject* hemv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COOiiiiiii", kwlist, &A, &x, &y, &uplo_, &ao, &bo, &n, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiii", kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_ValueError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) err_type("beta"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d=1.0; if (!bo) b.d=0.0; Py_BEGIN_ALLOW_THREADS dsymv_(&uplo, &n, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z=1.0; if (!bo) b.z=0.0; Py_BEGIN_ALLOW_THREADS zhemv_(&uplo, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_sbmv[] = "Matrix-vector product with a real symmetric band matrix.\n\n" "sbmv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[1], \n" " k=None, ldA=A.size[0], incx=1, incy=1, offsetA=0,\n" " offsetx=0, offsety=0)\n\n" "PURPOSE\n" "Computes y := alpha*A*x + beta*y with A real symmetric and \n" "banded of order n and with bandwidth k.\n\n" "ARGUMENTS\n" "A 'd' matrix\n\n" "x 'd' matrix\n\n" "y 'd' matrix\n\n" "uplo 'L' or 'U'\n\n" "alpha real number (int or float)\n\n" "beta real number (int or float)\n\n" "n integer. If negative, the default value is used.\n\n" "k integer. If negative, the default value is used.\n" " The default value is k = max(0,A.size[0]-1).\n\n" "ldA nonnegative integer. ldA >= k+1.\n" " If zero, the default vaule is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n"; static PyObject* sbmv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, k=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", "k", "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COOiiiiiiii", kwlist, &A, &x, &y, &uplo_, &ao, &bo, &n, &k, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiiii", kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &k, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0) n = A->ncols; if (n == 0) return Py_BuildValue(""); if (k < 0) k = MAX(0, A->nrows-1); if (ldA == 0) ldA = A->nrows; if (ldA < 1+k) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + k+1 > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) err_type("beta"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d=1.0; if (!bo) b.d=0.0; Py_BEGIN_ALLOW_THREADS dsbmv_(&uplo, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_hbmv[] = "Matrix-vector product with a real symmetric or complex Hermitian\n" "band matrix.\n\n" "hbmv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[1], \n" " k=None, ldA=A.size[0], incx=1, incy=1, offsetA=0, \n" " offsetx=0, offsety=0)\n\n" "PURPOSE\n" "Computes y := alpha*A*x + beta*y with A real symmetric or \n" "complex Hermitian and banded of order n and with bandwidth k.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "y 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "n integer. If negative, the default value is used.\n\n" "k integer. If negative, the default value is used.\n" " The default value is k = max(0,A.size[0]-1).\n\n" "ldA nonnegative integer. ldA >= k+1.\n" " If zero, the default vaule is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer.\n\n" "offsetx nonnegative integer.\n\n" "offsety nonnegative integer.\n\n"; static PyObject* hbmv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, k=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", "k", "ldA", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COOiiiiiiii", kwlist, &A, &x, &y, &uplo_, &ao, &bo, &n, &k, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiiii", kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &k, &ldA, &ix, &iy, &oA, &ox, &oy)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0) n = A->ncols; if (n == 0) return Py_BuildValue(""); if (k < 0) k = MAX(0, A->nrows-1); if (ldA == 0) ldA = A->nrows; if (ldA < 1+k) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + k+1 > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(x))) err_type("beta"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d=1.0; if (!bo) b.d=0.0; Py_BEGIN_ALLOW_THREADS dsbmv_(&uplo, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix, &b.d, MAT_BUFD(y)+oy, &iy); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z=1.0; if (!bo) b.z=0.0; Py_BEGIN_ALLOW_THREADS zhbmv_(&uplo, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix, &b.z, MAT_BUFZ(y)+oy, &iy); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_trmv[] = "Matrix-vector product with a triangular matrix.\n\n" "trmv(A, x, uplo='L', trans='N', diag='N', n=A.size[0],\n" " ldA=max(1,A.size[0]), incx=1, offsetA=0, offsetx=0)\n\n" "PURPOSE\n" "If trans is 'N', computes x := A*x.\n" "If trans is 'T', computes x := A^T*x.\n" "If trans is 'C', computes x := A^H*x.\n" "A is triangular of order n.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N' or 'T'\n\n" "diag 'N' or 'U'\n\n" "n integer. If negative, the default value is used.\n" " If the default value is used, we require that\n" " A.size[0] = A.size[1].\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero the default value is used.\n\n" "incx nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer"; static PyObject* trmv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x; int n=-1, ldA=0, ix=1, oA=0, ox=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', trans_ = 'N', diag_ = 'N'; #endif char uplo = 'L', trans = 'N', diag = 'N'; char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "ldA", "incx", "offsetA", "offsetx", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCiiiii", kwlist, &A, &x, &uplo_, &trans_, &diag_, &n, &ldA, &ix, &oA, &ox)) return NULL; uplo = (char) uplo_; trans = (char) trans_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiii", kwlist, &A, &x, &uplo, &trans, &diag, &n, &ldA, &ix, &oA, &ox)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'U', 'N'"); if (ix == 0) err_nz_int("incx"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("offsetx"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dtrmv_(&uplo, &trans, &diag, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS ztrmv_(&uplo, &trans, &diag, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_tbmv[] = "Matrix-vector product with a triangular band matrix.\n\n" "tbmv(A, x, uplo='L', trans='N', diag='N', n=A.size[1],\n" " k=max(0,A.size[0]-1), ldA=A.size[0], incx=1, offsetA=0,\n" " offsetx=0)\n\n" "PURPOSE\n" "If trans is 'N', computes x := A*x.\n" "If trans is 'T', computes x := A^T*x.\n" "If trans is 'C', computes x := A^H*x.\n" "A is banded triangular of order n and with bandwith k.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N', 'T' or 'C'\n\n" "diag 'N' or 'U'\n\n" "n nonnegative integer. If negative, the default value\n" " is used.\n\n" "k nonnegative integer. If negative, the default value\n" " is used.\n\n" "ldA nonnegative integer. lda >= 1+k.\n" " If zero the default value is used.\n\n" "incx nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer"; static PyObject* tbmv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x; int n=-1, k=-1, ldA=0, ix=1, oA=0, ox=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', trans_ = 'N', diag_ = 'N'; #endif char uplo = 'L', trans = 'N', diag = 'N'; char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "k", "ldA", "incx", "offsetA", "offsetx", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCiiiiii", kwlist, &A, &x, &uplo_, &trans_, &diag_, &n, &k, &ldA, &ix, &oA, &ox)) return NULL; uplo = (char) uplo_; trans = (char) trans_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiii", kwlist, &A, &x, &uplo, &trans, &diag, &n, &k, &ldA, &ix, &oA, &ox)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'U', 'N'"); if (ix == 0) err_nz_int("incx"); if (n < 0) n = A->ncols; if (n == 0) return Py_BuildValue(""); if (k < 0) k = MAX(0,A->nrows-1); if (ldA == 0) ldA = A->nrows; if (ldA < k+1) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + k + 1 > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dtbmv_(&uplo, &trans, &diag, &n, &k, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS ztbmv_(&uplo, &trans, &diag, &n, &k, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_trsv[] = "Solution of a triangular set of equations with one righthand side." "\n\n" "trsv(A, x, uplo='L', trans='N', diag='N', n=A.size[0],\n" " ldA=max(1,A.size[0]), incx=1, offsetA=0, offsetx=0)\n\n" "PURPOSE\n" "If trans is 'N', computes x := A^{-1}*x.\n" "If trans is 'T', computes x := A^{-T}*x.\n" "If trans is 'C', computes x := A^{-H}*x.\n" "A is triangular of order n. The code does not verify whether A\n" "is nonsingular.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N', 'T' or 'C'\n\n" "diag 'N' or 'U'\n\n" "n integer. If negative, the default value is used.\n" " If the default value is used, we require that\n" " A.size[0] = A.size[1].\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "incx nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer"; static PyObject* trsv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x; int n=-1, ldA=0, ix=1, oA=0, ox=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', trans_ = 'N', diag_ = 'N'; #endif char uplo = 'L', trans = 'N', diag = 'N'; char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "ldA", "incx", "offsetA", "offsetx", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCiiiii", kwlist, &A, &x, &uplo_, &trans_, &diag_, &n, &ldA, &ix, &oA, &ox)) return NULL; uplo = (char) uplo_; trans = (char) trans_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiii", kwlist, &A, &x, &uplo, &trans, &diag, &n, &ldA, &ix, &oA, &ox)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'"); if (ix == 0) err_nz_int("incx"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dtrsv_(&uplo, &trans, &diag, &n, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS ztrsv_(&uplo, &trans, &diag, &n, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_tbsv[] = "Solution of a triangular and banded set of equations.\n\n" "tbsv(A, x, uplo='L', trans='N', diag='N', n=A.size[1],\n" " k=max(0,A.size[0]-1), ldA=A.size[0], incx=1, offsetA=0,\n" " offsetx=0)\n\n" "PURPOSE\n" "If trans is 'N', computes x := A^{-1}*x.\n" "If trans is 'T', computes x := A^{-T}*x.\n" "If trans is 'C', computes x := A^{-H}*x.\n" "A is banded triangular of order n and with bandwidth k.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N', 'T' or 'C'\n\n" "diag 'N' or 'U'\n\n" "n nonnegative integer. If negative, the default value\n" " is used.\n\n" "k nonnegative integer. If negative, the default value\n" " is used.\n\n" "ldA nonnegative integer. ldA >= 1+k.\n" " If zero the default value is used.\n\n" "incx nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer"; static PyObject* tbsv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x; int n=-1, k=-1, ldA=0, ix=1, oA=0, ox=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L', trans_ = 'N', diag_ = 'N'; #endif char uplo='L', trans='N', diag='N'; char *kwlist[] = {"A", "x", "uplo", "trans", "diag", "n", "k", "ldA", "incx", "offsetA", "offsetx", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCiiiiii", kwlist, &A, &x, &uplo_, &trans_, &diag_, &n, &k, &ldA, &ix, &oA, &ox)) return NULL; uplo = (char) uplo_; trans = (char) trans_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccciiiiii", kwlist, &A, &x, &uplo, &trans, &diag, &n, &k, &ldA, &ix, &oA, &ox)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'"); if (ix == 0) err_nz_int("incx"); if (n < 0) n = A->ncols; if (n == 0) return Py_BuildValue(""); if (k < 0) k = MAX(0, A->nrows-1); if (ldA == 0) ldA = A->nrows; if (ldA < k+1) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + k + 1 > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dtbsv_(&uplo, &trans, &diag, &n, &k, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(x)+ox, &ix); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS ztbsv_(&uplo, &trans, &diag, &n, &k, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(x)+ox, &ix); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_ger[] = "General rank-1 update.\n\n" "ger(x, y, A, alpha=1.0, m=A.size[0], n=A.size[1], incx=1,\n" " incy=1, ldA=max(1,A.size[0]), offsetx=0, offsety=0,\n" " offsetA=0)\n\n" "PURPOSE\n" "Computes A := A + alpha*x*y^H with A m by n, real or complex.\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "A 'd' or 'z' matrix. Must have the same type as x.\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "ldA nonnegative integer. ldA >= max(1,m).\n" " If zero, the default value is used.\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "offsetA nonnegative integer"; static PyObject* ger(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL; number a; int m=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; char *kwlist[] = {"x", "y", "A", "alpha", "m", "n", "incx", "incy", "ldA", "offsetx", "offsety", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Oiiiiiiii", kwlist, &x, &y, &A, &ao, &m, &n, &ix, &iy, &ldA, &ox, &oy, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (m-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d = 1.0; Py_BEGIN_ALLOW_THREADS dger_(&m, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy, MAT_BUFD(A)+oA, &ldA); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; Py_BEGIN_ALLOW_THREADS zgerc_(&m, &n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy, MAT_BUFZ(A)+oA, &ldA); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_geru[] = "General rank-1 update.\n\n" "geru(x, y, A, m=A.size[0], n=A.size[1], alpha=1.0, incx=1,\n" " incy=1, ldA=max(1,A.size[0]), offsetx=0, offsety=0,\n" " offsetA=0)\n\n" "PURPOSE\n" "Computes A := A + alpha*x*y^T with A m by n, real or complex.\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "A 'd' or 'z' matrix. Must have the same type as x.\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "ldA nonnegative integer. ldA >= max(1,m).\n" " If zero, the default value is used.\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "offsetA nonnegative integer"; static PyObject* geru(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL; number a; int m=-1, n=-1, ldA=0, ix=1, iy=1, oA=0, ox=0, oy=0; char *kwlist[] = {"x", "y", "A", "alpha", "m", "n", "incx", "incy", "ldA", "offsetx", "offsety", "offsetA", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Oiiiiiiii", kwlist, &x, &y, &A, &ao, &m, &n, &ix, &iy, &ldA, &ox, &oy, &oA)) return NULL; if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (m < 0) m = A->nrows; if (n < 0) n = A->ncols; if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,m)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + m > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (m-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d = 1.0; Py_BEGIN_ALLOW_THREADS dger_(&m, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy, MAT_BUFD(A)+oA, &ldA); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; Py_BEGIN_ALLOW_THREADS zgeru_(&m, &n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy, MAT_BUFZ(A)+oA, &ldA); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_syr[] = "Symmetric rank-1 update.\n\n" "syr(x, A, uplo='L', alpha=1.0, n=A.size[0], incx=1,\n" " ldA=max(1,A.size[0]), offsetx=0, offsetA=0)\n\n" "PURPOSE\n" "Computes A := A + alpha*x*x^T with A real symmetric of order n." "\n\n" "ARGUMENTS\n" "x 'd' matrix\n\n" "A 'd' matrix\n\n" "uplo 'L' or 'U'\n\n" "alpha real number (int or float)\n\n" "n integer. If negative, the default value is used.\n\n" "incx nonzero integer\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "offsetx nonnegative integer\n\n" "offsetA nonnegative integer"; static PyObject* syr(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x; PyObject *ao=NULL; number a; int n=-1, ldA=0, ix=1, oA=0, ox=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo='L'; char *kwlist[] = {"x", "A", "uplo", "alpha", "n", "incx", "ldA", "offsetx", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|COiiiii", kwlist, &x, &A, &uplo_, &ao, &n, &ix, &ldA, &ox, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cOiiiii", kwlist, &x, &A, &uplo, &ao, &n, &ix, &ldA, &ox, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (ao && number_from_pyobject(ao, &a, DOUBLE)) err_type("alpha"); if (!ao) a.d = 1.0; switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dsyr_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(A)+oA, &ldA); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_her[] = "Hermitian rank-1 update.\n\n" "her(x, A, uplo='L', alpha=1.0, n=A.size[0], incx=1,\n" " ldA=max(1,A.size[0]), offsetx=0, offsetA=0)\n\n" "PURPOSE\n" "Computes A := A + alpha*x*x^H with A real symmetric or complex\n" "Hermitian of order n.\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "A 'd' or 'z' matrix. Must have the same type as x.\n\n" "uplo 'L' or 'U'\n\n" "alpha real number (int or float)\n\n" "n integer. If negative, the default value is used.\n\n" "incx nonzero integer\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero, the default value is used.\n\n" "offsetx nonnegative integer\n\n" "offsetA nonnegative integer"; static PyObject* her(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x; PyObject *ao=NULL; number a; int n=-1, ldA=0, ix=1, oA=0, ox=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"x", "A", "uplo", "alpha", "n", "incx", "ldA", "offsetx", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|COiiiii", kwlist, &x, &A, &uplo_, &ao, &n, &ix, &ldA, &ox, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|cOiiiii", kwlist, &x, &A, &uplo, &ao, &n, &ix, &ldA, &ox, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (MAT_ID(A) != MAT_ID(x)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (ao && number_from_pyobject(ao, &a, DOUBLE)) err_type("alpha"); if (!ao) a.d = 1.0; switch (MAT_ID(x)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dsyr_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(A)+oA, &ldA); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zher_(&uplo, &n, &a.d, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(A)+oA, &ldA); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_syr2[] = "Symmetric rank-2 update.\n\n" "syr2(x, y, A, uplo='L', alpha=1.0, n=A.size[0], incx=1, incy=1,\n" " ldA=max(1,A.size[0]), offsetx=0, offsety=0, offsetA=0)\n\n" "PURPOSE\n" "Computes A := A + alpha*(x*y^T + y*x^T) with A real symmetric.\n\n" "ARGUMENTS\n" "x 'd' matrix\n\n" "y 'd' matrix\n\n" "A 'd' matrix\n\n" "uplo 'L' or 'U'\n\n" "alpha real number (int or float)\n\n" "n integer. If negative, the default value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero the default value is used.\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "offsetA nonnegative integer"; static PyObject* syr2(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL; number a; int n=-1, ldA=0, ix=1, iy=1, ox=0, oy=0, oA=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"x", "y", "A", "uplo", "alpha", "n", "incx", "incy", "ldA", "offsetx", "offsety", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COiiiiiii", kwlist, &x, &y, &A, &uplo_, &ao, &n, &ix, &iy, &ldA, &ox, &oy, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOiiiiiii", kwlist, &x, &y, &A, &uplo, &ao, &n, &ix, &iy, &ldA, &ox, &oy, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L','U'"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d = 1.0; Py_BEGIN_ALLOW_THREADS dsyr2_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy, MAT_BUFD(A)+oA, &ldA); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_her2[] = "Hermitian rank-2 update.\n\n" "her2(x, y, A, uplo='L', alpha=1.0, n=A.size[0], incx=1, incy=1,\n" " ldA=max(1,A.size[0]), offsetx=0, offsety=0, offsetA=0)\n\n" "PURPOSE\n" "Computes A := A + alpha*x*y^H + conj(alpha)*y*x^H with A \n" "real symmetric or complex Hermitian of order n.\n\n" "ARGUMENTS\n" "x 'd' or 'z' matrix\n\n" "y 'd' or 'z' matrix. Must have the same type as x.\n\n" "A 'd' or 'z' matrix. Must have the same type as x.\n\n" "uplo 'L' or 'U'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "n integer. If negative, the default value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "ldA nonnegative integer. ldA >= max(1,n).\n" " If zero the default value is used.\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "offsetA nonnegative integer"; static PyObject* her2(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *x, *y; PyObject *ao=NULL; number a; int n=-1, ldA=0, ix=1, iy=1, ox=0, oy=0, oA=0; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; char *kwlist[] = {"x", "y", "A", "uplo", "alpha", "n", "incx", "incy", "ldA", "offsetx", "offsety", "offsetA", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COiiiiiii", kwlist, &x, &y, &A, &uplo_, &ao, &n, &ix, &iy, &ldA, &ox, &oy, &oA)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOiiiiiii", kwlist, &x, &y, &A, &uplo, &ao, &n, &ix, &iy, &ldA, &ox, &oy, &oA)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(A) != MAT_ID(x) || MAT_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0){ if (A->nrows != A->ncols){ PyErr_SetString(PyExc_TypeError, "A is not square"); return NULL; } n = A->nrows; } if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1,n)) err_ld("ldA"); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L','U'"); if (ao && number_from_pyobject(ao, &a, MAT_ID(x))) err_type("alpha"); switch (MAT_ID(x)){ case DOUBLE: if (!ao) a.d = 1.0; Py_BEGIN_ALLOW_THREADS dsyr2_(&uplo, &n, &a.d, MAT_BUFD(x)+ox, &ix, MAT_BUFD(y)+oy, &iy, MAT_BUFD(A)+oA, &ldA); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; Py_BEGIN_ALLOW_THREADS zher2_(&uplo, &n, &a.z, MAT_BUFZ(x)+ox, &ix, MAT_BUFZ(y)+oy, &iy, MAT_BUFZ(A)+oA, &ldA); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_gemm[] = "General matrix-matrix product.\n\n" "gemm(A, B, C, transA='N', transB='N', alpha=1.0, beta=0.0, \n" " m=None, n=None, k=None, ldA=max(1,A.size[0]), \n" " ldB=max(1,B.size[0]), ldC=max(1,C.size[0]), offsetA=0, \n" " offsetB=0, offsetC=0) \n\n" "PURPOSE\n" "Computes \n" "C := alpha*A*B + beta*C if transA = 'N' and transB = 'N'.\n" "C := alpha*A^T*B + beta*C if transA = 'T' and transB = 'N'.\n" "C := alpha*A^H*B + beta*C if transA = 'C' and transB = 'N'.\n" "C := alpha*A*B^T + beta*C if transA = 'N' and transB = 'T'.\n" "C := alpha*A^T*B^T + beta*C if transA = 'T' and transB = 'T'.\n" "C := alpha*A^H*B^T + beta*C if transA = 'C' and transB = 'T'.\n" "C := alpha*A*B^H + beta*C if transA = 'N' and transB = 'C'.\n" "C := alpha*A^T*B^H + beta*C if transA = 'T' and transB = 'C'.\n" "C := alpha*A^H*B^H + beta*C if transA = 'C' and transB = 'C'.\n" "The number of rows of the matrix product is m. The number of \n" "columns is n. The inner dimension is k. If k=0, this reduces \n" "to C := beta*C.\n\n" "ARGUMENTS\n\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "transA 'N', 'T' or 'C'\n\n" "transB 'N', 'T' or 'C'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n" " The default value is\n" " m = (transA == 'N') ? A.size[0] : A.size[1].\n\n" "n integer. If negative, the default value is used.\n" " The default value is\n" " n = (transB == 'N') ? B.size[1] : B.size[0].\n\n" "k integer. If negative, the default value is used.\n" " The default value is\n" " (transA == 'N') ? A.size[1] : A.size[0], transA='N'.\n" " If the default value is used it should also be equal to\n" " (transB == 'N') ? B.size[0] : B.size[1].\n\n" "ldA nonnegative integer. ldA >= max(1,(transA == 'N') ? m : k).\n" " If zero, the default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,(transB == 'N') ? k : n).\n" " If zero, the default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,m).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer\n\n" "offsetC nonnegative integer"; static PyObject* gemm(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *C; PyObject *ao=NULL, *bo=NULL; number a, b; int m=-1, n=-1, k=-1, ldA=0, ldB=0, ldC=0, oA=0, oB=0, oC=0; #if PY_MAJOR_VERSION >= 3 int transA_ = 'N', transB_ = 'N'; #endif char transA = 'N', transB = 'N'; char *kwlist[] = {"A", "B", "C", "transA", "transB", "alpha", "beta", "m", "n", "k", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCOOiiiiiiiii", kwlist, &A, &B, &C, &transA_, &transB_, &ao, &bo, &m, &n, &k, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; transA = (char) transA_; transB = (char) transB_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiiii", kwlist, &A, &B, &C, &transA, &transB, &ao, &bo, &m, &n, &k, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) || MAT_ID(B) != MAT_ID(C)) err_conflicting_ids; if (transA != 'N' && transA != 'T' && transA != 'C') err_char("transA", "'N', 'T', 'C'"); if (transB != 'N' && transB != 'T' && transB != 'C') err_char("transB", "'N', 'T', 'C'"); if (m < 0) m = (transA == 'N') ? A->nrows : A->ncols; if (n < 0) n = (transB == 'N') ? B->ncols : B->nrows; if (k < 0){ k = (transA == 'N') ? A->ncols : A->nrows; if (k != ((transB == 'N') ? B->nrows : B->ncols)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (k > 0 && ldA < MAX(1, (transA == 'N') ? m : k)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (k > 0 && ldB < MAX(1, (transB == 'N') ? k : n)) err_ld("ldB"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,m)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if (k > 0 && ((transA == 'N' && oA + (k-1)*ldA + m > len(A)) || ((transA == 'T' || transA == 'C') && oA + (m-1)*ldA + k > len(A)))) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (k > 0 && ((transB == 'N' && oB + (n-1)*ldB + k > len(B)) || ((transB == 'T' || transB == 'C') && oB + (k-1)*ldB + n > len(B)))) err_buf_len("B"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) err_type("beta"); switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; if (!bo) b.d = 0.0; Py_BEGIN_ALLOW_THREADS dgemm_(&transA, &transB, &m, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; if (!bo) b.z = 0.0; Py_BEGIN_ALLOW_THREADS zgemm_(&transA, &transB, &m, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &b.z, MAT_BUFZ(C)+oC, &ldC); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_symm[] = "Matrix-matrix product where one matrix is symmetric." "\n\n" "symm(A, B, C, side='L', uplo='L', alpha=1.0, beta=0.0, \n" " m=B.size[0], n=B.size[1], ldA=max(1,A.size[0]), \n" " ldB=max(1,B.size[0]), ldC=max(1,C.size[0]), offsetA=0, \n" " offsetB=0, offsetC=0)\n\n" "PURPOSE\n" "If side is 'L', computes C := alpha*A*B + beta*C.\n" "If side is 'R', computes C := alpha*B*A + beta*C.\n" "C is m by n and A is real or complex symmetric. (Use hemm for\n" "Hermitian A).\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "side 'L' or 'R'\n\n" "uplo 'L' or 'U'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n" " If the default value is used and side = 'L', then m\n" " must be equal to A.size[0] and A.size[1].\n\n" "n integer. If negative, the default value is used.\n" " If the default value is used and side = 'R', then \n\n" " must be equal to A.size[0] and A.size[1].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (side == 'L') ? m : n). If zero, the\n" " default value is used.\n\n" "ldB nonnegative integer.\n" " ldB >= max(1, (side == 'L') ? n : m). If zero, the\n" " default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,m).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer\n\n" "offsetC nonnegative integer"; static PyObject* symm(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *C; PyObject *ao=NULL, *bo=NULL; number a, b; int m=-1, n=-1, ldA=0, ldB=0, ldC=0, oA=0, oB=0, oC = 0; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', uplo_ = 'L'; #endif char side = 'L', uplo = 'L'; char *kwlist[] = {"A", "B", "C", "side", "uplo", "alpha", "beta", "m", "n", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCOOiiiiiiii", kwlist, &A, &B, &C, &side_, &uplo_, &ao, &bo, &m, &n, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; side = (char) side_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", kwlist, &A, &B, &C, &side, &uplo, &ao, &bo, &m, &n, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) || MAT_ID(B) != MAT_ID(C)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (m < 0){ m = B->nrows; if (side == 'L' && (m != A->nrows || m != A->ncols)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (n < 0){ n = B->ncols; if (side == 'R' && (n != A->nrows || n != A->ncols)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,m)) err_ld("ldB"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,m)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) || (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (n-1)*ldB + m > len(B)) err_buf_len("B"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) err_type("beta"); switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; if (!bo) b.d = 0.0; Py_BEGIN_ALLOW_THREADS dsymm_(&side, &uplo, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; if (!bo) b.z = 0.0; Py_BEGIN_ALLOW_THREADS zsymm_(&side, &uplo, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &b.z, MAT_BUFZ(C)+oC, &ldC); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_hemm[] = "Matrix-matrix product where one matrix is real symmetric or\n" "complex Hermitian." "\n\n" "hemm(A, B, C, side='L', uplo='L', alpha=1.0, beta=0.0, \n" " m=B.size[0], n=B.size[1], ldA=max(1,A.size[0]), \n" " ldB=max(1,B.size[0]), ldC=max(1,C.size[0]), offsetA=0, \n" " offsetB=0, offsetC=0)\n\n" "PURPOSE\n" "If side is 'L', computes C := alpha*A*B + beta*C.\n" "If side is 'R', computes C := alpha*B*A + beta*C.\n" "C is m by n and A is real symmetric or complex Hermitian.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "side 'L' or 'R'\n\n" "uplo 'L' or 'U'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n" " If the default value is used and side = 'L', then m\n" " must be equal to A.size[0] and A.size[1].\n\n" "n integer. If negative, the default value is used.\n" " If the default value is used and side = 'R', then \n\n" " must be equal to A.size[0] and A.size[1].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (side == 'L') ? m : n). If zero, the\n" " default value is used.\n\n" "ldB nonnegative integer.\n" " ldB >= max(1, (side == 'L') ? n : m). If zero, the\n" " default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,m).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer\n\n" "offsetC nonnegative integer"; static PyObject* hemm(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *C; PyObject *ao=NULL, *bo=NULL; number a, b; int m=-1, n=-1, ldA=0, ldB=0, ldC=0, oA=0, oB=0, oC = 0; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', uplo_ = 'L'; #endif char side = 'L', uplo = 'L'; char *kwlist[] = {"A", "B", "C", "side", "uplo", "alpha", "beta", "m", "n", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCOOiiiiiiii", kwlist, &A, &B, &C, &side_, &uplo_, &ao, &bo, &m, &n, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; side = (char) side_; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", kwlist, &A, &B, &C, &side, &uplo, &ao, &bo, &m, &n, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) || MAT_ID(B) != MAT_ID(C)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (m < 0){ m = B->nrows; if (side == 'L' && (m != A->nrows || m != A->ncols)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (n < 0){ n = B->ncols; if (side == 'R' && (n != A->nrows || n != A->ncols)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,m)) err_ld("ldB"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,m)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) || (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (n-1)*ldB + m > len(B)) err_buf_len("B"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + m > len(C)) err_buf_len("C"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) err_type("beta"); switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; if (!bo) b.d = 0.0; Py_BEGIN_ALLOW_THREADS dsymm_(&side, &uplo, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; if (!bo) b.z = 0.0; Py_BEGIN_ALLOW_THREADS zhemm_(&side, &uplo, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &b.z, MAT_BUFZ(C)+oC, &ldC); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_syrk[] = "Rank-k update of symmetric matrix.\n\n" "syrk(A, C, uplo='L', trans='N', alpha=1.0, beta=0.0, n=None, \n" " k=None, ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n" " offsetA=0, offsetB=0)\n\n" "PURPOSE \n" "If trans is 'N', computes C := alpha*A*A^T + beta*C.\n" "If trans is 'T', computes C := alpha*A^T*A + beta*C.\n" "C is symmetric (real or complex) of order n. \n" "The inner dimension of the matrix product is k. If k=0 this is\n" "interpreted as C := beta*C.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N' or 'T'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "n integer. If negative, the default value is used.\n" " The default value is\n" " n = (trans == N) ? A.size[0] : A.size[1].\n\n" "k integer. If negative, the default value is used.\n" " The default value is\n" " k = (trans == 'N') ? A.size[1] : A.size[0].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (trans == 'N') ? n : k). If zero,\n" " the default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,n).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetC nonnegative integer"; static PyObject* syrk(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *C; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, k=-1, ldA=0, ldC=0, oA = 0, oC = 0; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N', uplo_ = 'L'; #endif char trans = 'N', uplo = 'L'; char *kwlist[] = {"A", "C", "uplo", "trans", "alpha", "beta", "n", "k", "ldA", "ldC", "offsetA", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCOOiiiiii", kwlist, &A, &C, &uplo_, &trans_, &ao, &bo, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; uplo = (char) uplo_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOiiiiii", kwlist, &A, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(C)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'T') err_char("trans", "'N', 'T'"); if (n < 0) n = (trans == 'N') ? A->nrows : A->ncols; if (k < 0) k = (trans == 'N') ? A->ncols : A->nrows; if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,n)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) || ((trans == 'T' || trans == 'C') && oA + (n-1)*ldA + k > len(A)))) err_buf_len("A"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + n > len(C)) err_buf_len("C"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) err_type("beta"); switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; if (!bo) b.d = 0.0; Py_BEGIN_ALLOW_THREADS dsyrk_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, &b.d, MAT_BUFD(C)+oC, &ldC); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; if (!bo) b.z = 0.0; Py_BEGIN_ALLOW_THREADS zsyrk_(&uplo, &trans, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA, &b.z, MAT_BUFZ(C)+oC, &ldC); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_herk[] = "Rank-k update of Hermitian matrix.\n\n" "herk(A, C, uplo='L', trans='N', alpha=1.0, beta=0.0, n=None, \n" " k=None, ldA=max(1,A.size[0]), ldC=max(1,C.size[0]),\n" " offsetA=0, offsetB=0)\n\n" "PURPOSE \n" "If trans is 'N', computes C := alpha*A*A^H + beta*C.\n" "If trans is 'C', computes C := alpha*A^H*A + beta*C.\n" "C is real symmetric or Hermitian of order n. The inner \n" "dimension of the matrix product is k.\n" "If k=0 this is interpreted as C := beta*C.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N' or 'C'\n\n" "alpha real number (int or float)\n\n" "beta number (int, float or complex)\n\n" "n integer. If negative, the default value is used.\n" " The default value is\n" " n = (trans == N) ? A.size[0] : A.size[1].\n\n" "k integer. If negative, the default value is used.\n" " The default value is\n" " k = (trans == 'N') ? A.size[1] : A.size[0].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (trans == 'N') ? n : k). If zero,\n" " the default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,n).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetC nonnegative integer"; static PyObject* herk(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *C; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, k=-1, ldA=0, ldC=0, oA = 0, oC = 0; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N', uplo_ = 'L'; #endif char trans = 'N', uplo = 'L'; char *kwlist[] = {"A", "C", "uplo", "trans", "alpha", "beta", "n", "k", "ldA", "ldC", "offsetA", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCOOiiiiii", kwlist, &A, &C, &uplo_, &trans_, &ao, &bo, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; uplo = (char) uplo_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOiiiiii", kwlist, &A, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldC, &oA, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(C)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'C') err_char("trans", "'N', 'C'"); if (n < 0) n = (trans == 'N') ? A->nrows : A->ncols; if (k < 0) k = (trans == 'N') ? A->ncols : A->nrows; if (n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,n)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) || ((trans == 'T' || trans == 'C') && oA + (n-1)*ldA + k > len(A)))) err_buf_len("A"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + n > len(C)) err_buf_len("C"); if (ao && number_from_pyobject(ao, &a, DOUBLE)) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, DOUBLE)) err_type("beta"); if (!ao) a.d = 1.0; if (!bo) b.d = 0.0; switch (MAT_ID(A)){ case DOUBLE: Py_BEGIN_ALLOW_THREADS dsyrk_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, &b.d, MAT_BUFD(C)+oC, &ldC); Py_END_ALLOW_THREADS break; case COMPLEX: Py_BEGIN_ALLOW_THREADS zherk_(&uplo, &trans, &n, &k, &a.d, MAT_BUFZ(A)+oA, &ldA, &b.d, MAT_BUFZ(C)+oC, &ldC); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_syr2k[] = "Rank-2k update of symmetric matrix.\n\n" "syr2k(A, B, C, uplo='L', trans='N', alpha=1.0, beta=0.0, n=None,\n" " k=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]), \n" " ldC=max(1,C.size[0])), offsetA=0, offsetB=0, offsetC=0)\n\n" "PURPOSE\n" "If trans is 'N', computes C := alpha*(A*B^T + B*A^T) + beta*C.\n" "If trans is 'T', computes C := alpha*(A^T*B + B^T*A) + beta*C.\n" "C is symmetric (real or complex) of order n.\n" "The inner dimension of the matrix product is k. If k=0 this is\n" "interpreted as C := beta*C.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N', 'T' or 'C' ('C' is only allowed when in the real\n" " case and means the same as 'T')\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "n integer. If negative, the default value is used.\n" " The default value is\n" " n = (trans == 'N') ? A.size[0] : A.size[1].\n" " If the default value is used, it should be equal to\n" " (trans == 'N') ? B.size[0] : B.size[1].\n\n" "k integer. If negative, the default value is used.\n" " The default value is\n" " k = (trans == 'N') ? A.size[1] : A.size[0].\n" " If the default value is used, it should be equal to\n" " (trans == 'N') ? B.size[1] : B.size[0].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (trans=='N') ? n : k).\n" " If zero, the default value is used.\n\n" "ldB nonnegative integer.\n" " ldB >= max(1, (trans=='N') ? n : k).\n" " If zero, the default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,n).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer\n\n" "offsetC nonnegative integer"; static PyObject* syr2k(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *C; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, k=-1, ldA=0, ldB=0, ldC=0, oA = 0, oB = 0, oC = 0; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N', uplo_ = 'L'; #endif char trans = 'N', uplo = 'L'; char *kwlist[] = {"A", "B", "C", "uplo", "trans", "alpha", "beta", "n", "k", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCOOiiiiiiii", kwlist, &A, &B, &C, &uplo_, &trans_, &ao, &bo, &n, &k, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; uplo = (char) uplo_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", kwlist, &A, &B, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) || MAT_ID(B) != MAT_ID(C)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'T') err_char("trans", "'N', 'T'"); if (n < 0){ n = (trans == 'N') ? A->nrows : A->ncols; if (n != ((trans == 'N') ? B->nrows : B->ncols)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (k < 0){ k = (trans == 'N') ? A->ncols : A->nrows; if (k != ((trans == 'N') ? B->ncols : B->nrows)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (ldA == 0) ldA = MAX(1,A->nrows); if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (k > 0 && ldB < MAX(1, (trans == 'N') ? n : k)) err_ld("ldB"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,n)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) || ((trans == 'T' || trans == 'C') && oA + (n-1)*ldA + k > len(A)))) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (k > 0 && ((trans == 'N' && oB + (k-1)*ldB + n > len(B)) || ((trans == 'T' || trans == 'C') && oB + (n-1)*ldB + k > len(B)))) err_buf_len("B"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + n > len(C)) err_buf_len("C"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) err_type("beta"); switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; if (!bo) b.d = 0.0; Py_BEGIN_ALLOW_THREADS dsyr2k_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; if (!bo) b.z = 0.0; Py_BEGIN_ALLOW_THREADS zsyr2k_(&uplo, &trans, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &b.z, MAT_BUFZ(C)+oC, &ldC); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_her2k[] = "Rank-2k update of Hermitian matrix.\n\n" "her2k(A, B, C, alpha=1.0, beta=0.0, uplo='L', trans='N', n=None,\n" " k=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]),\n" " ldC=max(1,C.size[0])), offsetA=0, offsetB=0, offsetC=0)\n\n" "PURPOSE\n" "Computes\n" "C := alpha*A*B^H + conj(alpha)*B*A^H + beta*C (trans=='N')\n" "C := alpha*A^H*B + conj(alpha)*B^H*A + beta*C (trans=='C')\n" "C is real symmetric or complex Hermitian of order n. The inner\n" "dimension of the matrix product is k. If k=0 this is interpreted\n" "as C := beta*C.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N' or 'C'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta real number (int or float)\n\n" "n integer. If negative, the default value is used.\n" " The default value is\n" " n = (trans == 'N') ? A.size[0] : A.size[1].\n" " If the default value is used, it should be equal to\n" " (trans == 'N') ? B.size[0] : B.size[1].\n\n" "k integer. If negative, the default value is used.\n" " The default value is\n" " k = (trans == 'N') ? A.size[1] : A.size[0].\n" " If the default value is used, it should be equal to\n" " (trans == 'N') ? B.size[1] : B.size[0].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (trans=='N') ? n : k).\n" " If zero, the default value is used.\n\n" "ldB nonnegative integer.\n" " ldB >= max(1, (trans=='N') ? n : k).\n" " If zero, the default value is used.\n\n" "ldC nonnegative integer. ldC >= max(1,n).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer\n\n" "offsetC nonnegative integer"; static PyObject* her2k(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B, *C; PyObject *ao=NULL, *bo=NULL; number a, b; int n=-1, k=-1, ldA=0, ldB=0, ldC=0, oA = 0, oB = 0, oC = 0; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N', uplo_ = 'L'; #endif char trans = 'N', uplo = 'L'; char *kwlist[] = {"A", "B", "C", "uplo", "trans", "alpha", "beta", "n", "k", "ldA", "ldB", "ldC", "offsetA", "offsetB", "offsetC", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCOOiiiiiiii", kwlist, &A, &B, &C, &uplo_, &trans_, &ao, &bo, &n, &k, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; uplo = (char) uplo_; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOiiiiiiii", kwlist, &A, &B, &C, &uplo, &trans, &ao, &bo, &n, &k, &ldA, &ldB, &ldC, &oA, &oB, &oC)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (!Matrix_Check(C)) err_mtrx("C"); if (MAT_ID(A) != MAT_ID(B) || MAT_ID(A) != MAT_ID(C) || MAT_ID(B) != MAT_ID(C)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (MAT_ID(A) == DOUBLE && trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (MAT_ID(A) == COMPLEX && trans != 'N' && trans != 'C') err_char("trans", "'N', 'C'"); if (n < 0){ n = (trans == 'N') ? A->nrows : A->ncols; if (n != ((trans == 'N') ? B->nrows : B->ncols)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (n == 0) return Py_BuildValue(""); if (k < 0){ k = (trans == 'N') ? A->ncols : A->nrows; if (k != ((trans == 'N') ? B->ncols : B->nrows)){ PyErr_SetString(PyExc_TypeError, "dimensions of A and B " "do not match"); return NULL; } } if (ldA == 0) ldA = MAX(1,A->nrows); if (k > 0 && ldA < MAX(1, (trans == 'N') ? n : k)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (k > 0 && ldB < MAX(1, (trans == 'N') ? n : k)) err_ld("ldB"); if (ldC == 0) ldC = MAX(1,C->nrows); if (ldC < MAX(1,n)) err_ld("ldC"); if (oA < 0) err_nn_int("offsetA"); if (k > 0 && ((trans == 'N' && oA + (k-1)*ldA + n > len(A)) || ((trans == 'T' || trans == 'C') && oA + (n-1)*ldA + k > len(A)))) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (k > 0 && ((trans == 'N' && oB + (k-1)*ldB + n > len(B)) || ((trans == 'T' || trans == 'C') && oB + (n-1)*ldB + k > len(B)))) err_buf_len("B"); if (oC < 0) err_nn_int("offsetC"); if (oC + (n-1)*ldC + n > len(C)) err_buf_len("C"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); if (bo && number_from_pyobject(bo, &b, MAT_ID(A))) err_type("beta"); if (!bo) b.d = 0.0; switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; Py_BEGIN_ALLOW_THREADS dsyr2k_(&uplo, &trans, &n, &k, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB, &b.d, MAT_BUFD(C)+oC, &ldC); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; Py_BEGIN_ALLOW_THREADS zher2k_(&uplo, &trans, &n, &k, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB, &b.d, MAT_BUFZ(C)+oC, &ldC); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_trmm[] = "Matrix-matrix product where one matrix is triangular.\n\n" "trmm(A, B, side='L', uplo='L', transA='N', diag='N', alpha=1.0,\n" " m=None, n=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]),\n" " offsetA=0, offsetB=0)\n\n" "PURPOSE\n" "Computes\n" "B := alpha*A*B if transA is 'N' and side = 'L'.\n" "B := alpha*B*A if transA is 'N' and side = 'R'.\n" "B := alpha*A^T*B if transA is 'T' and side = 'L'.\n" "B := alpha*B*A^T if transA is 'T' and side = 'R'.\n" "B := alpha*A^H*B if transA is 'C' and side = 'L'.\n" "B := alpha*B*A^H if transA is 'C' and side = 'R'.\n" "B is m by n and A is triangular.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "side 'L' or 'R'\n\n" "uplo 'L' or 'U'\n\n" "transA 'N' or 'T'\n\n" "diag 'N' or 'U'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n" " The default value is\n" " m = (side == 'L') ? A.size[0] : B.size[0].\n" " If the default value is used and side is 'L', m must\n" " be equal to A.size[1].\n\n" "n integer. If negative, the default value is used.\n" " The default value is\n" " n = (side == 'L') ? B.size[1] : A.size[0].\n" " If the default value is used and side is 'R', n must\n" " be equal to A.size[1].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (side == 'L') ? m : n).\n" " If zero, the default value is used. \n\n" "ldB nonnegative integer. ldB >= max(1,m).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* trmm(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; PyObject *ao=NULL; number a; int m=-1, n=-1, ldA=0, ldB=0, oA=0, oB=0; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', uplo_ = 'L', transA_ = 'N', diag_ = 'N'; #endif char side = 'L', uplo = 'L', transA = 'N', diag = 'N'; char *kwlist[] = {"A", "B", "side", "uplo", "transA", "diag", "alpha", "m", "n", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCCOiiiiii", kwlist, &A, &B, &side_, &uplo_, &transA_, &diag_, &ao, &m, &n, &ldA, &ldB, &oA, &oB)) return NULL; side = (char) side_; uplo = (char) uplo_; transA = (char) transA_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccccOiiiiii", kwlist, &A, &B, &side, &uplo, &transA, &diag, &ao, &m, &n, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'"); if (transA != 'N' && transA != 'T' && transA != 'C') err_char("transA", "'N', 'T', 'C'"); if (n < 0){ n = (side == 'L') ? B->ncols : A->nrows; if (side != 'L' && n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (m < 0){ m = (side == 'L') ? A->nrows: B->nrows; if (side == 'L' && m != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (m == 0 || n == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1, m)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) || (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB + (n-1)*ldB + m > len(B)) err_buf_len("B"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; Py_BEGIN_ALLOW_THREADS dtrmm_(&side, &uplo, &transA, &diag, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; Py_BEGIN_ALLOW_THREADS ztrmm_(&side, &uplo, &transA, &diag, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static char doc_trsm[] = "Solution of a triangular system of equations with multiple \n" "righthand sides.\n\n" "trsm(A, B, side='L', uplo='L', transA='N', diag='N', alpha=1.0,\n" " m=None, n=None, ldA=max(1,A.size[0]), ldB=max(1,B.size[0]),\n" " offsetA=0, offsetB=0)\n\n" "PURPOSE\n" "Computes\n" "B := alpha*A^{-1}*B if transA is 'N' and side = 'L'.\n" "B := alpha*B*A^{-1} if transA is 'N' and side = 'R'.\n" "B := alpha*A^{-T}*B if transA is 'T' and side = 'L'.\n" "B := alpha*B*A^{-T} if transA is 'T' and side = 'R'.\n" "B := alpha*A^{-H}*B if transA is 'C' and side = 'L'.\n" "B := alpha*B*A^{-H} if transA is 'C' and side = 'R'.\n" "B is m by n and A is triangular. The code does not verify \n" "whether A is nonsingular.\n\n" "ARGUMENTS\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "side 'L' or 'R'\n\n" "uplo 'L' or 'U'\n\n" "transA 'N' or 'T'\n\n" "diag 'N' or 'U'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n" " The default value is\n" " m = (side == 'L') ? A.size[0] : B.size[0].\n" " If the default value is used and side is 'L', m must\n" " be equal to A.size[1].\n\n" "n integer. If negative, the default value is used.\n" " The default value is\n" " n = (side == 'L') ? B.size[1] : A.size[0].\n" " If the default value is used and side is 'R', n must\n" " be equal to A.size[1].\n\n" "ldA nonnegative integer.\n" " ldA >= max(1, (side == 'L') ? m : n).\n" " If zero, the default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,m).\n" " If zero, the default value is used.\n\n" "offsetA nonnegative integer\n\n" "offsetB nonnegative integer"; static PyObject* trsm(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *A, *B; PyObject *ao=NULL; number a; int m=-1, n=-1, ldA=0, ldB=0, oA=0, oB=0; #if PY_MAJOR_VERSION >= 3 int side_ = 'L', uplo_ = 'L', transA_ = 'N', diag_ = 'N'; #endif char side = 'L', uplo = 'L', transA = 'N', diag = 'N'; char *kwlist[] = {"A", "B", "side", "uplo", "transA", "diag", "alpha", "m", "n", "ldA", "ldB", "offsetA", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCCCOiiiiii", kwlist, &A, &B, &side_, &uplo_, &transA_, &diag_, &ao, &m, &n, &ldA, &ldB, &oA, &oB)) return NULL; side = (char) side_; uplo = (char) uplo_; transA = (char) transA_; diag = (char) diag_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccccOiiiiii", kwlist, &A, &B, &side, &uplo, &transA, &diag, &ao, &m, &n, &ldA, &ldB, &oA, &oB)) return NULL; #endif if (!Matrix_Check(A)) err_mtrx("A"); if (!Matrix_Check(B)) err_mtrx("B"); if (MAT_ID(A) != MAT_ID(B)) err_conflicting_ids; if (side != 'L' && side != 'R') err_char("side", "'L', 'R'"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (diag != 'N' && diag != 'U') err_char("diag", "'N', 'U'"); if (transA != 'N' && transA != 'T' && transA != 'C') err_char("transA", "'N', 'T', 'C'"); if (n < 0){ n = (side == 'L') ? B->ncols : A->nrows; if (side != 'L' && n != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (m < 0){ m = (side == 'L') ? A->nrows: B->nrows; if (side == 'L' && m != A->ncols){ PyErr_SetString(PyExc_TypeError, "A must be square"); return NULL; } } if (n == 0 || m == 0) return Py_BuildValue(""); if (ldA == 0) ldA = MAX(1,A->nrows); if (ldA < MAX(1, (side == 'L') ? m : n)) err_ld("ldA"); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,m)) err_ld("ldB"); if (oA < 0) err_nn_int("offsetA"); if ((side == 'L' && oA + (m-1)*ldA + m > len(A)) || (side == 'R' && oA + (n-1)*ldA + n > len(A))) err_buf_len("A"); if (oB < 0) err_nn_int("offsetB"); if (oB < 0 || oB + (n-1)*ldB + m > len(B)) err_buf_len("B"); if (ao && number_from_pyobject(ao, &a, MAT_ID(A))) err_type("alpha"); switch (MAT_ID(A)){ case DOUBLE: if (!ao) a.d = 1.0; Py_BEGIN_ALLOW_THREADS dtrsm_(&side, &uplo, &transA, &diag, &m, &n, &a.d, MAT_BUFD(A)+oA, &ldA, MAT_BUFD(B)+oB, &ldB); Py_END_ALLOW_THREADS break; case COMPLEX: if (!ao) a.z = 1.0; Py_BEGIN_ALLOW_THREADS ztrsm_(&side, &uplo, &transA, &diag, &m, &n, &a.z, MAT_BUFZ(A)+oA, &ldA, MAT_BUFZ(B)+oB, &ldB); Py_END_ALLOW_THREADS break; default: err_invalid_id; } return Py_BuildValue(""); } static PyMethodDef blas_functions[] = { {"swap", (PyCFunction) swap, METH_VARARGS|METH_KEYWORDS, doc_swap}, {"scal", (PyCFunction) scal, METH_VARARGS|METH_KEYWORDS, doc_scal}, {"copy", (PyCFunction) copy, METH_VARARGS|METH_KEYWORDS, doc_copy}, {"axpy", (PyCFunction) axpy, METH_VARARGS|METH_KEYWORDS, doc_axpy}, {"dot", (PyCFunction) dot, METH_VARARGS|METH_KEYWORDS, doc_dot}, {"dotu", (PyCFunction) dotu, METH_VARARGS|METH_KEYWORDS, doc_dotu}, {"nrm2", (PyCFunction) nrm2, METH_VARARGS|METH_KEYWORDS, doc_nrm2}, {"asum", (PyCFunction) asum, METH_VARARGS|METH_KEYWORDS, doc_asum}, {"iamax",(PyCFunction) iamax, METH_VARARGS|METH_KEYWORDS, doc_iamax}, {"gemv", (PyCFunction) gemv, METH_VARARGS|METH_KEYWORDS, doc_gemv}, {"gbmv", (PyCFunction) gbmv, METH_VARARGS|METH_KEYWORDS, doc_gbmv}, {"symv", (PyCFunction) symv, METH_VARARGS|METH_KEYWORDS, doc_symv}, {"hemv", (PyCFunction) hemv, METH_VARARGS|METH_KEYWORDS, doc_hemv}, {"sbmv", (PyCFunction) sbmv, METH_VARARGS|METH_KEYWORDS, doc_sbmv}, {"hbmv", (PyCFunction) hbmv, METH_VARARGS|METH_KEYWORDS, doc_hbmv}, {"trmv", (PyCFunction) trmv, METH_VARARGS|METH_KEYWORDS, doc_trmv}, {"tbmv", (PyCFunction) tbmv, METH_VARARGS|METH_KEYWORDS, doc_tbmv}, {"trsv", (PyCFunction) trsv, METH_VARARGS|METH_KEYWORDS, doc_trsv}, {"tbsv", (PyCFunction) tbsv, METH_VARARGS|METH_KEYWORDS, doc_tbsv}, {"ger", (PyCFunction) ger, METH_VARARGS|METH_KEYWORDS, doc_ger}, {"geru", (PyCFunction) geru, METH_VARARGS|METH_KEYWORDS, doc_geru}, {"syr", (PyCFunction) syr, METH_VARARGS|METH_KEYWORDS, doc_syr}, {"her", (PyCFunction) her, METH_VARARGS|METH_KEYWORDS, doc_her}, {"syr2", (PyCFunction) syr2, METH_VARARGS|METH_KEYWORDS, doc_syr2}, {"her2", (PyCFunction) her2, METH_VARARGS|METH_KEYWORDS, doc_her2}, {"gemm", (PyCFunction) gemm, METH_VARARGS|METH_KEYWORDS, doc_gemm}, {"symm", (PyCFunction) symm, METH_VARARGS|METH_KEYWORDS, doc_symm}, {"hemm", (PyCFunction) hemm, METH_VARARGS|METH_KEYWORDS, doc_hemm}, {"syrk", (PyCFunction) syrk, METH_VARARGS|METH_KEYWORDS, doc_syrk}, {"herk", (PyCFunction) herk, METH_VARARGS|METH_KEYWORDS, doc_herk}, {"syr2k",(PyCFunction) syr2k, METH_VARARGS|METH_KEYWORDS, doc_syr2k}, {"her2k",(PyCFunction) her2k, METH_VARARGS|METH_KEYWORDS, doc_her2k}, {"trmm", (PyCFunction) trmm, METH_VARARGS|METH_KEYWORDS, doc_trmm}, {"trsm", (PyCFunction) trsm, METH_VARARGS|METH_KEYWORDS, doc_trsm}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef blas_module = { PyModuleDef_HEAD_INIT, "blas", blas__doc__, -1, blas_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_blas(void) { PyObject *m; if (!(m = PyModule_Create(&blas_module))) return NULL; if (import_cvxopt() < 0) return NULL; return m; } #else PyMODINIT_FUNC initblas(void) { PyObject *m; m = Py_InitModule3("cvxopt.blas", blas_functions, blas__doc__); if (import_cvxopt() < 0) return ; } #endif cvxopt-1.1.4/src/C/amd.c0000644000175000017500000001701411674452555013765 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cvxopt.h" #include "amd.h" #include "misc.h" /* defined in pyconfig.h */ #if (SIZEOF_INT < SIZEOF_LONG) #define amd_order amd_l_order #define amd_defaults amd_l_defaults #endif PyDoc_STRVAR(amd__doc__,"Interface to the AMD library.\n\n" "Approximate minimum degree ordering of sparse matrices.\n\n" "The default values of the control parameterse in the AMD 'Control' " "array\n" "described in the AMD User Guide are used. The values can be modified " "by\n" "making an entry in the dictionary amd.options, with possible key " "values\n" "'AMD_DENSE' and 'AMD_AGGRESSIVE'.\n\n" "AMD is available from http://www.cise.ufl.edu/research/sparse/amd."); static PyObject *amd_module; typedef struct { char name[20]; int idx; } param_tuple; static const param_tuple AMD_PARAM_LIST[] = { {"AMD_DENSE", AMD_DENSE}, {"AMD_AGGRESSIVE", AMD_AGGRESSIVE} }; /* 2 parameters */ #if PY_MAJOR_VERSION >= 3 static int get_param_idx(const char *str, int *idx) #else static int get_param_idx(char *str, int *idx) #endif { int i; for (i=0; i<2; i++) if (!strcmp(AMD_PARAM_LIST[i].name, str)) { *idx = AMD_PARAM_LIST[i].idx; return 1; } return 0; } static int set_defaults(double *control) { int_t pos=0; int param_id; PyObject *param, *key, *value; #if PY_MAJOR_VERSION < 3 char *keystr; #endif char err_str[100]; amd_defaults(control); if (!(param = PyObject_GetAttrString(amd_module, "options")) || !PyDict_Check(param)){ PyErr_SetString(PyExc_AttributeError, "missing amd.options" "dictionary"); return 0; } while (PyDict_Next(param, &pos, &key, &value)) #if PY_MAJOR_VERSION >= 3 if ((PyUnicode_Check(key)) && get_param_idx(_PyUnicode_AsString(key),¶m_id)) { if (!PyLong_Check(value) && !PyFloat_Check(value)){ sprintf(err_str, "invalid value for AMD parameter: %-.20s", _PyUnicode_AsString(key)); #else if ((keystr = PyString_AsString(key)) && get_param_idx(keystr, ¶m_id)) { if (!PyInt_Check(value) && !PyFloat_Check(value)){ sprintf(err_str, "invalid value for AMD parameter: " "%-.20s", keystr); #endif PyErr_SetString(PyExc_ValueError, err_str); Py_DECREF(param); return 0; } control[param_id] = PyFloat_AsDouble(value); } Py_DECREF(param); return 1; } static char doc_order[] = "Computes the approximate minimum degree ordering of a square " "matrix.\n\n" "p = order(A, uplo='L')\n\n" "PURPOSE\n" "Computes a permutation p that reduces fill-in in the Cholesky\n" "factorization of A[p,p].\n\n" "ARGUMENTS\n" "A square sparse matrix\n\n" "uplo 'L' or 'U'. If uplo is 'L', the lower triangular part\n" " of A is used and the upper triangular is ignored. If\n" " uplo is 'U', the upper triangular part is used and the\n" " lower triangular part is ignored.\n\n" "p 'i' matrix of length equal to the order of A"; static PyObject* order_c(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A; matrix *perm; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo = 'L'; int j, k, n, nnz, alloc=0, info; int_t *rowind=NULL, *colptr=NULL; double control[AMD_CONTROL]; char *kwlist[] = {"A", "uplo", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|C", kwlist, &A, &uplo_)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|c", kwlist, &A, &uplo)) return NULL; #endif if (!set_defaults(control)) return NULL; if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)){ PyErr_SetString(PyExc_TypeError, "A must be a square sparse " "matrix"); return NULL; } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (!(perm = (matrix *) Matrix_New(SP_NROWS(A),1,INT))) return PyErr_NoMemory(); n = SP_NROWS(A); for (nnz=0, j=0; j= 3 static PyModuleDef amd_module_def = { PyModuleDef_HEAD_INIT, "amd", amd__doc__, -1, amd_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_amd(void) { if (!(amd_module = PyModule_Create(&amd_module_def))) return NULL; PyModule_AddObject(amd_module, "options", PyDict_New()); if (import_cvxopt() < 0) return NULL; return amd_module; } #else PyMODINIT_FUNC initamd(void) { amd_module = Py_InitModule3("cvxopt.amd", amd_functions, amd__doc__); PyModule_AddObject(amd_module, "options", PyDict_New()); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/gsl.c0000644000175000017500000001234511674452555014013 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cvxopt.h" #include #include "misc.h" #include #include #include PyDoc_STRVAR(gsl__doc__,"Random Module."); static unsigned long seed = 0; static const gsl_rng_type *rng_type; static gsl_rng *rng; static char doc_getseed[] = "Returns the seed value for the random number generator.\n\n" "getseed()"; static PyObject * getseed(PyObject *self) { return Py_BuildValue("l",seed); } static char doc_setseed[] = "Sets the seed value for the random number generator.\n\n" "setseed(value = 0)\n\n" "ARGUMENTS\n" "value integer seed. If the value is 0, then the system clock\n" " measured in seconds is used instead"; static PyObject * setseed(PyObject *self, PyObject *args) { unsigned long seed_ = 0; time_t seconds; if (!PyArg_ParseTuple(args, "|l", &seed_)) return NULL; if (!seed_) { time(&seconds); seed = (unsigned long)seconds; } else seed = seed_; return Py_BuildValue(""); } static char doc_normal[] = "Randomly generates a matrix with normally distributed entries.\n\n" "normal(nrows, ncols=1, mean=0, std=1)\n\n" "PURPOSE\n" "Returns a matrix with typecode 'd' and size nrows by ncols, with\n" "its entries randomly generated from a normal distribution with mean\n" "m and standard deviation std.\n\n" "ARGUMENTS\n" "nrows number of rows\n\n" "ncols number of columns\n\n" "mean approximate mean of the distribution\n\n" "std standard deviation of the distribution"; static PyObject * normal(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *obj; int i, nrows, ncols = 1; double m = 0, s = 1; char *kwlist[] = {"nrows", "ncols", "mean", "std", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist, &nrows, &ncols, &m, &s)) return NULL; if (s < 0.0) PY_ERR(PyExc_ValueError, "std must be non-negative"); if ((nrows<0) || (ncols<0)) { PyErr_SetString(PyExc_TypeError, "dimensions must be non-negative"); return NULL; } if (!(obj = Matrix_New(nrows, ncols, DOUBLE))) return PyErr_NoMemory(); gsl_rng_env_setup(); rng_type = gsl_rng_default; rng = gsl_rng_alloc (rng_type); gsl_rng_set(rng, seed); for (i = 0; i < nrows*ncols; i++) MAT_BUFD(obj)[i] = gsl_ran_gaussian (rng, s) + m; seed = gsl_rng_get (rng); gsl_rng_free(rng); return (PyObject *)obj; } static char doc_uniform[] = "Randomly generates a matrix with uniformly distributed entries.\n\n" "uniform(nrows, ncols=1, a=0, b=1)\n\n" "PURPOSE\n" "Returns a matrix with typecode 'd' and size nrows by ncols, with\n" "its entries randomly generated from a uniform distribution on the\n" "interval (a,b).\n\n" "ARGUMENTS\n" "nrows number of rows\n\n" "ncols number of columns\n\n" "a lower bound\n\n" "b upper bound"; static PyObject * uniform(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *obj; int i, nrows, ncols = 1; double a = 0, b = 1; char *kwlist[] = {"nrows", "ncols", "a", "b", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "i|idd", kwlist, &nrows, &ncols, &a, &b)) return NULL; if (a>b) PY_ERR(PyExc_ValueError, "a must be less than b"); if ((nrows<0) || (ncols<0)) PY_ERR_TYPE("dimensions must be non-negative"); if (!(obj = (matrix *)Matrix_New(nrows, ncols, DOUBLE))) return PyErr_NoMemory(); gsl_rng_env_setup(); rng_type = gsl_rng_default; rng = gsl_rng_alloc (rng_type); gsl_rng_set(rng, seed); for (i= 0; i < nrows*ncols; i++) MAT_BUFD(obj)[i] = gsl_ran_flat (rng, a, b); seed = gsl_rng_get (rng); gsl_rng_free(rng); return (PyObject *)obj; } static PyMethodDef gsl_functions[] = { {"getseed", (PyCFunction)getseed, METH_VARARGS|METH_KEYWORDS, doc_getseed}, {"setseed", (PyCFunction)setseed, METH_VARARGS|METH_KEYWORDS, doc_setseed}, {"normal", (PyCFunction)normal, METH_VARARGS|METH_KEYWORDS, doc_normal}, {"uniform", (PyCFunction)uniform, METH_VARARGS|METH_KEYWORDS, doc_uniform}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef gsl_module = { PyModuleDef_HEAD_INIT, "gsl", gsl__doc__, -1, gsl_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_gsl(void) { PyObject *m; if (!(m = PyModule_Create(&gsl_module))) return NULL; if (import_cvxopt() < 0) return NULL; return m; } #else PyMODINIT_FUNC initgsl(void) { PyObject *m; m = Py_InitModule3("cvxopt.gsl", gsl_functions, gsl__doc__); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/blas_redefines.h0000644000175000017500000000647311674452555016205 0ustar sonnesonne#ifdef BLAS_NO_UNDERSCORE #define dswap_ dswap #define zswap_ zswap #define dscal_ dscal #define zscal_ zscal #define zdscal_ zdscal #define dcopy_ dcopy #define zcopy_ zcopy #define daxpy_ daxpy #define zaxpy_ zaxpy #define ddot_ ddot #define dnrm2_ dnrm2 #define dznrm2_ dznrm2 #define dasum_ dasum #define dzasum_ dzasum #define idamax_ idamax #define izamax_ izamax #define dgemv_ dgemv #define zgemv_ zgemv #define dgbmv_ dgbmv #define zgbmv_ zgbmv #define dsymv_ dsymv #define zsymv_ zsymv #define zhemv_ zhemv #define dsbmv_ dsbmv #define zhbmv_ zhbmv #define dtrmv_ dtrmv #define ztrmv_ ztrmv #define dtbmv_ dtbmv #define ztbmv_ ztbmv #define dtrsv_ dtrsv #define ztrsv_ ztrsv #define dtbsv_ dtbsv #define ztbsv_ ztbsv #define dger_ dger #define zgerc_ zgerc #define zgeru_ zgeru #define dsyr_ dsyr #define zher_ zher #define dsyr2_ dsyr2 #define zher2_ zher2 #define dgemm_ dgemm #define zgemm_ zgemm #define dsymm_ dsymm #define zsymm_ zsymm #define zhemm_ zhemm #define dsyrk_ dsyrk #define zsyrk_ zsyrk #define zherk_ zherk #define dsyr2k_ dsyr2k #define zsyr2k_ zsyr2k #define zher2k_ zher2k #define dtrmm_ dtrmm #define ztrmm_ ztrmm #define dtrsm_ dtrsm #define ztrsm_ ztrsm #define dgetrf_ dgetrf #define zgetrf_ zgetrf #define dgetrs_ dgetrs #define zgetrs_ zgetrs #define dgetri_ dgetri #define zgetri_ zgetri #define dgesv_ dgesv #define zgesv_ zgesv #define dpotrf_ dpotrf #define dpotri_ dpotri #define zpotri_ zpotri #define zpotrf_ zpotrf #define dpotrs_ dpotrs #define zpotrs_ zpotrs #define dposv_ dposv #define zposv_ zposv #define dsytrf_ dsytrf #define zsytrf_ zsytrf #define zhetrf_ zhetrf #define dsytri_ dsytri #define zsytri_ zsytri #define dsytrs_ dsytrs #define zsytrs_ zsytrs #define zhetrs_ zhetrs #define zhetri_ zhetri #define dsysv_ dsysv #define zsysv_ zsysv #define dsygv_ dsygv #define zhesv_ zhesv #define dgels_ dgels #define zgels_ zgels #define dsyev_ dsyev #define zheev_ zheev #define dsyevx_ dsyevx #define zheevx_ zheevx #define dsyevd_ dsyevd #define zheevd_ zheevd #define dsyevr_ dsyevr #define zheevr_ zheevr #define ilaenv_ ilaenv #define zhegv_ zhegv #define dgesvd_ dgesvd #define zgesvd_ zgesvd #define dgesdd_ dgesdd #define zgesdd_ zgesdd #define dgeqrf_ dgeqrf #define zgeqrf_ zgeqrf #define dormqr_ dormqr #define zunmqr_ zunmqr #define dorgqr_ dorgqr #define zungqr_ zungqr #define dgelqf_ dgelqf #define zgelqf_ zgelqf #define dormlq_ dormlq #define zunmlq_ zunmlq #define dorglq_ dorglq #define zunglq_ zunglq #define dtrtrs_ dtrtrs #define ztrtrs_ ztrtrs #define dgbtrf_ dgbtrf #define zgbtrf_ zgbtrf #define dgbtrs_ dgbtrs #define zgbtrs_ zgbtrs #define dgbsv_ dgbsv #define zgbsv_ zgbsv #define dgtsv_ dgtsv #define zgtsv_ zgtsv #define dpbsv_ dpbsv #define zpbsv_ zpbsv #define dptsv_ dptsv #define zptsv_ zptsv #define dgttrf_ dgttrf #define zgttrf_ zgttrf #define dgttrs_ dgttrs #define zgttrs_ zgttrs #define dtrtri_ dtrtri #define ztrtri_ ztrtri #define dpbtrf_ dpbtrf #define zpbtrf_ zpbtrf #define dtbtrs_ dtbtrs #define ztbtrs_ ztbtrs #define dtbtrf_ dtbtrf #define ztbtrf_ ztbtrf #define dpttrf_ dpttrf #define zpttrf_ zpttrf #define dpbtrs_ dpbtrs #define zpbtrs_ zpbtrs #define dpttrs_ dpttrs #define zpttrs_ zpttrs #define dlacpy_ dlacpy #define zlacpy_ zlacpy #define dgees_ dgees #define zgees_ zgees #define dgges_ dgges #define zgges_ zgges #define dgeqp3_ dgeqp3 #define zgeqp3_ zgeqp3 #endif cvxopt-1.1.4/src/C/dense.c0000644000175000017500000020145611674452555014327 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define BASE_MODULE #include "Python.h" #include "cvxopt.h" #include "misc.h" #include #if PY_MAJOR_VERSION < 3 /* NumPy array protocol */ typedef struct { int version; int nd; char typekind; int itemsize; int flags; int_t *shape; int_t *strides; void *data; } PyArrayInterface; #endif static const char PY_ARRAY_TC[3] = { 'i', 'f', 'c' }; /* prototyping and forward declarations */ extern void (*axpy[])(int *, number *, void *, int *, void *, int *) ; extern void (*scal[])(int *, number *, void *, int *) ; extern void (*gemm[])(char *, char *, int *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *) ; extern void (*mtx_abs[])(void *, void *, int) ; extern int (*div_array[])(void *, number, int) ; extern int (*mtx_rem[])(void *, number, int) ; extern void (*write_num[])(void *, int, void *, int) ; extern int (*convert_num[])(void *, void *, int, int_t) ; extern PyObject * (*num2PyObject[])(void *, int) ; int get_id(void *, int ) ; extern const int E_SIZE[]; extern const char TC_CHAR[][2]; extern number One[3], MinusOne[3], Zero[3]; extern PyObject *base_mod; extern PyTypeObject spmatrix_tp ; PyTypeObject matrix_tp ; matrix * Matrix_NewFromNumber(int_t , int_t , int_t , void *, int ) ; static PyNumberMethods matrix_as_number ; static PyObject * matrix_iter(matrix *) ; void dscal_(int *, double *, double *, int *) ; void zscal_(int *, complex *, complex *, int *) ; void daxpy_(int *, double *, double *, int *, double *, int *) ; void zaxpy_(int *, complex *, complex *, int *, complex *, int *) ; void dgemm_(char *, char *, int *, int *, int *, double *, double *, int *, double *, int *, double *, double *, int *) ; void zgemm_(char *, char *, int *, int *, int *, complex *, complex *, int *, complex *, int *, complex *, complex *, int *) ; static const char err_mtx_list2matrix[][35] = {"not an integer list", "not a floating point list", "not a complex floating point list" }; #define free_convert_mtx_alloc(O1, O2, id) { \ if (MAT_BUF(O1) != O2) { \ free(MAT_BUF(O1)); MAT_BUF(O1) = O2; MAT_ID(O1) = id; \ } \ } #define free_lists_exit(argI,argJ,I,J,ret) { \ if (argI && !Matrix_Check(argI)) { Py_XDECREF(I); } \ if (argJ && !Matrix_Check(argJ)) { Py_XDECREF(J); } \ return ret; } static int convert_mtx(matrix *src, void *dest, int id) { if (PY_NUMBER((PyObject *)src)) return convert_num[id](dest, src, 1, 0); if (MAT_ID(src) == id) { memcpy(dest, src->buffer, E_SIZE[src->id]*MAT_LGT(src) ); return 0; } int_t i; for (i=0; i COMPLEX)) { PyErr_BadInternalCall(); return NULL; } if (!(a = (matrix *)matrix_tp.tp_alloc(&matrix_tp, 0))) return NULL; a->id = id; a->nrows = nrows; a->ncols = ncols; if (!(a->buffer = calloc(nrows*ncols,E_SIZE[id]))) { #if PY_MAJOR_VERSION >= 3 Py_TYPE(a)->tp_free((PyObject*)a); #else a->ob_type->tp_free((PyObject*)a); #endif return (matrix *)PyErr_NoMemory(); } return a; } /* Creates a copy of matrix as a new object. In API. */ matrix *Matrix_NewFromMatrix(matrix *src, int id) { matrix *a; if (PY_NUMBER((PyObject *)src)) return Matrix_NewFromNumber(1, 1, id, src, 1); if (!(a = Matrix_New(src->nrows, src->ncols, id))) return (matrix *)PyErr_NoMemory(); if (convert_mtx(src, a->buffer, id)) { Py_DECREF(a); PY_ERR_TYPE("illegal type conversion"); } return a; } #if PY_MAJOR_VERSION < 3 /* Creates a matrix from a PyArrayInterface. */ matrix *Matrix_NewFromArrayStruct(PyObject *obj, int id, int_t *ndim) { PyObject *cobj = PyObject_GetAttrString(obj, "__array_struct__"); PyArrayInterface *src = (PyArrayInterface *)PyCObject_AsVoidPtr(cobj); if (src->version != 2) PY_ERR(PyExc_AssertionError, "unexpected format in array structure"); if (src->nd != 1 && src->nd != 2) PY_ERR(PyExc_TypeError, "imported array must have 1 or 2 dimensions"); int src_id; switch (src->typekind) { case 'i' : src_id = INT; break; case 'f' : src_id = DOUBLE; break; case 'c' : src_id = COMPLEX; break; default: Py_DECREF(cobj); PY_ERR_TYPE("invalid array type"); } if (id == -1) id = src_id; if ((src_id > id) || (src->itemsize != E_SIZE[src_id])) { Py_DECREF(cobj); PY_ERR_TYPE("invalid array type"); } /* XXX: revise flags check */ if (!(src->flags & 0x001) && !(src->flags & 0x002)) { Py_DECREF(cobj); PY_ERR_TYPE("error converting array"); } *ndim = src->nd; matrix *a = Matrix_New(src->shape[0], src->nd == 2 ? src->shape[1] : 1, id); if (!a) { Py_DECREF(cobj); return (matrix *)PyErr_NoMemory(); } int_t i, j, cnt; for (j=0, cnt=0; jshape[0]; i++, cnt++) { number n; switch (id) { case INT : MAT_BUFI(a)[cnt] = *(int_t *)(src->data+i*src->strides[0]+j*src->strides[1]); break; case DOUBLE: switch (src_id) { case INT: n.d = *(int_t *)(src->data + i*src->strides[0]+j*src->strides[1]); break; case DOUBLE: n.d = *(double *)(src->data + i*src->strides[0]+j*src->strides[1]); break; } MAT_BUFD(a)[cnt] = n.d; break; case COMPLEX: switch (src_id) { case INT: n.z = *(int_t *)(src->data+i*src->strides[0]+j*src->strides[1]); break; case DOUBLE: n.z = *(double *)(src->data+i*src->strides[0]+j*src->strides[1]); break; case COMPLEX: n.z = *(complex *)(src->data+i*src->strides[0]+j*src->strides[1]); break; } MAT_BUFZ(a)[cnt] = n.z; break; } } } Py_DECREF(cobj); return a; } #endif /* Generates a matrix with all entries equal. */ matrix * Matrix_NewFromNumber(int_t nrows, int_t ncols, int_t id, void *val, int val_id) { int_t i; matrix *a = Matrix_New(nrows, ncols, id); if (!a) return (matrix *)PyErr_NoMemory(); number n; if (convert_num[id](&n, val, val_id, 0)) { Py_DECREF(a); return NULL; } for (i=0; ibuffer, i, &n, 0); } Py_DECREF(seq); return L; } matrix * dense(spmatrix *self) { matrix *A; int_t j, k; if (!(A = Matrix_New(SP_NROWS(self),SP_NCOLS(self),SP_ID(self)))) return (matrix *)PyErr_NoMemory(); if (SP_ID(self) == DOUBLE) { for (j=0; j 0 && !PyList_Check(PyList_GET_ITEM(L, 0))); for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) { col = (single_col ? L : PyList_GET_ITEM(L, j)); if (!PyList_Check(col)) PY_ERR_TYPE("invalid type in list"); mk = 0; for (i=0; i= 0) && (id_arg < id)) PY_ERR_TYPE("illegal type conversion"); id = MAX(id, id_arg); matrix *A = Matrix_New(m, n, id); if (!A) return (matrix *)PyErr_NoMemory(); nk = 0; for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) { col = (single_col ? L : PyList_GET_ITEM(L, j)); mk = 0; int blk_nrows = 0, blk_ncols = 0; for (i=0; ibuffer); #if PY_MAJOR_VERSION >= 3 Py_TYPE(self)->tp_free((PyObject*)self); #else self->ob_type->tp_free((PyObject*)self); #endif } static PyObject * matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *Objx = NULL, *size = NULL; static char *kwlist[] = { "x", "size", "tc", NULL}; int_t nrows=0, ncols=0; char tc = 0; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOC:matrix", kwlist, &Objx, &size, &tc)) #else if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOc:matrix", kwlist, &Objx, &size, &tc)) #endif return NULL; if (size && !PyArg_ParseTuple(size, "ll", &nrows, &ncols)) PY_ERR_TYPE("invalid dimension tuple") ; if (nrows < 0 || ncols < 0) PY_ERR_TYPE("dimensions must be non-negative"); if (tc && !(VALID_TC_MAT(tc))) PY_ERR_TYPE("tc must be 'i', 'd' or 'z'"); int id = (tc ? TC2ID(tc) : -1); if (!Objx && size) PY_ERR_TYPE("invalid arguments"); if (!Objx) return (PyObject *)Matrix_New(0, 0, (id == -1 ? INT : id)); matrix *ret = NULL; /* x is a number */ if (PY_NUMBER(Objx)) return (PyObject *) Matrix_NewFromNumber(MAX(nrows, size ? 0 : 1), MAX(ncols, size ? 0 : 1), (id == -1 ? get_id(Objx,1):id),Objx,1); /* a matrix */ else if (Matrix_Check(Objx)) ret = Matrix_NewFromMatrix((matrix *)Objx, (id == -1 ?MAT_ID(Objx):id)); /* sparse matrix */ else if (SpMatrix_Check(Objx)) { matrix *tmp = dense((spmatrix *)Objx); if (!tmp) return PyErr_NoMemory(); if (tmp->id != id) { ret = Matrix_NewFromMatrix(tmp, (id == -1 ? SP_ID(Objx) : id)); Py_DECREF(tmp); } else { ret = tmp; } } #if PY_MAJOR_VERSION < 3 /* PyArrayStructure */ else if (PyObject_HasAttrString(Objx,"__array_struct__")) { int_t ndim = 0; ret = Matrix_NewFromArrayStruct(Objx, id, &ndim); } #endif /* x is a list */ else if (PyList_Check(Objx)) { /* first try a regular list */ if (!(ret = Matrix_NewFromSequence(Objx, id))) { PyErr_Clear(); /* try concatenation */ ret = dense_concat(Objx, id); } } /* x is a sequence */ else if (PySequence_Check(Objx)) { ret = Matrix_NewFromSequence(Objx, id); } else PY_ERR_TYPE("invalid matrix initialization"); if (ret && size) { if (nrows*ncols == MAT_LGT(ret)) { ret->nrows=nrows; ret->ncols=ncols; } else { Py_DECREF(ret); PY_ERR_TYPE("wrong matrix dimensions"); } } return (PyObject *)ret; } PyObject *matrix_sub(PyObject *, PyObject *); static PyObject * matrix_richcompare(PyObject *self, PyObject *other, int op) { PY_ERR(PyExc_NotImplementedError, "matrix comparison not implemented"); } static PyObject * matrix_str(matrix *self) { PyObject *cvxopt = PyImport_ImportModule("cvxopt"); PyObject *str, *ret; if (!(str = PyObject_GetAttrString(cvxopt, "matrix_str"))) { Py_DECREF(cvxopt); PY_ERR(PyExc_KeyError, "missing 'matrix_str' in 'cvxopt'"); } Py_DECREF(cvxopt); if (!PyCallable_Check(str)) PY_ERR_TYPE("'matrix_str' is not callable"); ret = PyObject_CallFunctionObjArgs(str, (PyObject *)self, NULL); Py_DECREF(str); return ret; } static PyObject * matrix_repr(matrix *self) { PyObject *cvxopt = PyImport_ImportModule("cvxopt"); PyObject *repr, *ret; if (!(repr = PyObject_GetAttrString(cvxopt, "matrix_repr"))) { Py_DECREF(cvxopt); PY_ERR(PyExc_KeyError, "missing 'matrix_repr' in 'cvxopt'"); } Py_DECREF(cvxopt); if (!PyCallable_Check(repr)) PY_ERR_TYPE("'matrix_repr' is not callable"); ret = PyObject_CallFunctionObjArgs(repr, (PyObject *)self, NULL); Py_DECREF(repr); return ret; } /* * This method converts different index sets into a matrix indexlist */ matrix * create_indexlist(int_t dim, PyObject *A) { matrix *x; int_t i, j; /* integer */ #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(A)) { i = PyLong_AS_LONG(A); #else if (PyInt_Check(A)) { i = PyInt_AS_LONG(A); #endif if (OUT_RNG(i,dim)) PY_ERR(PyExc_IndexError, "index out of range"); if ((x = Matrix_New(1,1,INT))) MAT_BUFI(x)[0] = i; return x; } /* slice */ else if (PySlice_Check(A)) { int_t start, stop, step, lgt; #if PY_MAJOR_VERSION >= 3 if (PySlice_GetIndicesEx(A, dim, &start, &stop, &step, &lgt) < 0) return NULL; #else if (PySlice_GetIndicesEx((PySliceObject*)A, dim, &start, &stop, &step, &lgt) < 0) return NULL; #endif if ((x = Matrix_New(lgt, 1, INT))) for (i=start, j=0; j= 3 if (PyLong_Check(args)) { int_t i = PyLong_AS_LONG(args); #else if (PyInt_Check(args)) { int_t i = PyInt_AS_LONG(args); #endif if (OUT_RNG(i,MAT_LGT(self))) PY_ERR(PyExc_IndexError, "index out of range"); return num2PyObject[self->id](self->buffer, CWRAP(i,MAT_LGT(self))); } else if (PyList_Check(args) || Matrix_Check(args) || PySlice_Check(args)) { if (!(Il = create_indexlist(MAT_LGT(self), args))) return NULL; int i; if (!(ret = Matrix_New(MAT_LGT(Il), 1, self->id) )) free_lists_exit(args,(PyObject *)NULL,Il,(PyObject *)NULL, PyErr_NoMemory()); for (i=0; iid](ret->buffer, i, self->buffer, CWRAP(MAT_BUFI(Il)[i],MAT_LGT(self))); free_lists_exit(args,(PyObject *)NULL,Il,(PyObject *)NULL,(PyObject *)ret); } /* remaining cases are different two argument indexing */ PyObject *argI = NULL, *argJ = NULL; if (!PyArg_ParseTuple(args, "OO", &argI,&argJ)) PY_ERR_TYPE("invalid index arguments"); /* handle normal subscripts (two integers) separately */ #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(argI) && PyLong_Check(argJ)) { int i = PyLong_AS_LONG(argI), j = PyLong_AS_LONG(argJ); #else if (PyInt_Check(argI) && PyInt_Check(argJ)) { int i = PyInt_AS_LONG(argI), j = PyInt_AS_LONG(argJ); #endif if ( OUT_RNG(i, self->nrows) || OUT_RNG(j, self->ncols)) PY_ERR(PyExc_IndexError, "index out of range"); return num2PyObject[self->id](self->buffer, CWRAP(i,self->nrows) + CWRAP(j,self->ncols)*self->nrows); } /* two slices, handled separately for speed */ if (PySlice_Check(argI) && PySlice_Check(argJ)) { int_t rowstart, rowstop, rowstep, rowlgt; int_t colstart, colstop, colstep, collgt; #if PY_MAJOR_VERSION >= 3 if ( (PySlice_GetIndicesEx(argI, MAT_NROWS(self), &rowstart, &rowstop, &rowstep, &rowlgt) < 0) || (PySlice_GetIndicesEx(argJ, MAT_NCOLS(self), &colstart, &colstop, &colstep, &collgt) < 0)) return NULL; #else if ( (PySlice_GetIndicesEx((PySliceObject*)argI, MAT_NROWS(self), &rowstart, &rowstop, &rowstep, &rowlgt) < 0) || (PySlice_GetIndicesEx((PySliceObject*)argJ, MAT_NCOLS(self), &colstart, &colstop, &colstep, &collgt) < 0)) return NULL; #endif if (!(ret = Matrix_New(rowlgt, collgt, self->id))) return PyErr_NoMemory(); int i, j, icnt, jcnt, cnt=0; for (j=colstart, jcnt=0; jcntid) { case INT: MAT_BUFI(ret)[cnt++] = MAT_BUFI(self)[j*self->nrows+i]; break; case DOUBLE: MAT_BUFD(ret)[cnt++] = MAT_BUFD(self)[j*self->nrows+i]; break; case COMPLEX: MAT_BUFZ(ret)[cnt++] = MAT_BUFZ(self)[j*self->nrows+i]; break; } } return (PyObject *)ret; } /* remaining two indexing cases */ if (!(Il = create_indexlist(self->nrows, argI)) || !(Jl = create_indexlist(self->ncols, argJ))) free_lists_exit(argI, argJ, Il, Jl, (PyObject *)NULL); int i, j, cnt; if (!(ret = Matrix_New(MAT_LGT(Il), MAT_LGT(Jl), self->id))) free_lists_exit(argI, argJ, Il, Jl, PyErr_NoMemory()); for (j=0, cnt=0; j < MAT_LGT(Jl); j++) for (i=0; i < MAT_LGT(Il); i++) { write_num[self->id](ret->buffer, cnt++, self->buffer, CWRAP(MAT_BUFI(Il)[i],self->nrows) + CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows); } free_lists_exit(argI, argJ, Il, Jl, (PyObject *)ret); } #define spmatrix_getitem_i(O,i,v) \ spmatrix_getitem_ij(O,i%SP_NROWS(O),i/SP_NROWS(O),v) int spmatrix_getitem_ij(spmatrix *, int_t, int_t, number *) ; static int matrix_ass_subscr(matrix* self, PyObject* args, PyObject* val) { matrix *Il = NULL, *Jl = NULL; int_t i, j, id = self->id, decref_val = 0, arraystruct_nd = 0; if (!val) PY_ERR_INT(PyExc_NotImplementedError, "cannot delete matrix entries"); if (!(PY_NUMBER(val) || Matrix_Check(val) || SpMatrix_Check(val))) { #if PY_MAJOR_VERSION >= 3 val = (PyObject *)Matrix_NewFromSequence(val, MAT_ID(self)); #else if (PyObject_HasAttrString(val,"__array_struct__")) val = (PyObject *)Matrix_NewFromArrayStruct(val, -1, &arraystruct_nd); else val = (PyObject *)Matrix_NewFromSequence(val, MAT_ID(self)); #endif if (!val) PY_ERR_INT(PyExc_NotImplementedError, "invalid type in assignment"); decref_val = 1; } if (get_id(val, (PY_NUMBER(val) ? 1 : 0)) > id) PY_ERR_INT(PyExc_TypeError, "invalid type in assignment"); #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(args) || PyList_Check(args) || #else if (PyInt_Check(args) || PyList_Check(args) || #endif Matrix_Check(args) || PySlice_Check(args)) { if (!(Il = create_indexlist(MAT_LGT(self), args))) { if (decref_val) { Py_DECREF(val); } return -1; } number n; if (PY_NUMBER(val) || (Matrix_Check(val) && MAT_LGT(val)==1)) { convert_num[id](&n, val, (Matrix_Check(val) ? 0 : 1), 0); for (i=0; ibuffer,CWRAP(MAT_BUFI(Il)[i],MAT_LGT(self)),&n,0); } else { if (Matrix_Check(val)) { if (MAT_LGT(val) != MAT_LGT(Il) || MAT_NCOLS(val) > 1) { if (!Matrix_Check(args)) { Py_DECREF(Il); } if (decref_val) { Py_DECREF(val); } PY_ERR_INT(PyExc_TypeError, "argument has wrong size"); } for (i=0; i < MAT_LGT(Il); i++) { convert_num[id](&n, val, 0, i); write_num[id](self->buffer, CWRAP(MAT_BUFI(Il)[i], MAT_LGT(self)), &n, 0); } } else { /* spmatrix */ if (SP_NROWS(val) != MAT_LGT(Il) || SP_NCOLS(val) > 1) { if (!Matrix_Check(args)) { Py_DECREF(Il); } if (decref_val) { Py_DECREF(val); } PY_ERR_INT(PyExc_TypeError, "argument has wrong size"); } for (i=0; i < MAT_LGT(Il); i++) { spmatrix_getitem_i((spmatrix *)val, i, &n); write_num[id](self->buffer, CWRAP(MAT_BUFI(Il)[i], MAT_LGT(self)), &n, 0); } } } if (decref_val) { Py_DECREF(val); } free_lists_exit(args,(PyObject *)NULL,Il,(PyObject *)NULL,0); } /* remaining cases are different two argument indexing */ PyObject *argI = NULL, *argJ = NULL; if (!PyArg_ParseTuple(args, "OO", &argI,&argJ)) PY_ERR_INT(PyExc_TypeError, "invalid index arguments"); /* two slices, RHS of same type, handled separately for speed */ if (PySlice_Check(argI) && PySlice_Check(argJ) && Matrix_Check(val) && MAT_ID(val) == MAT_ID(self)) { int_t rowstart, rowstop, rowstep, rowlgt; int_t colstart, colstop, colstep, collgt; #if PY_MAJOR_VERSION >= 3 if ( (PySlice_GetIndicesEx(argI, MAT_NROWS(self), &rowstart, &rowstop, &rowstep, &rowlgt) < 0) || (PySlice_GetIndicesEx(argJ, MAT_NCOLS(self), &colstart, &colstop, &colstep, &collgt) < 0)) return -1; #else if ( (PySlice_GetIndicesEx((PySliceObject*)argI, MAT_NROWS(self), &rowstart, &rowstop, &rowstep, &rowlgt) < 0) || (PySlice_GetIndicesEx((PySliceObject*)argJ, MAT_NCOLS(self), &colstart, &colstop, &colstep, &collgt) < 0)) return -1; #endif if (decref_val && MAT_LGT(val) == rowlgt*collgt) { MAT_NROWS(val) = rowlgt; MAT_NCOLS(val) = collgt; } if (MAT_NROWS(val)!=rowlgt || MAT_NCOLS(val)!=collgt) PY_ERR_INT(PyExc_TypeError, "argument has wrong size"); int i, j, icnt, jcnt, cnt=0; for (j=colstart, jcnt=0; jcntid) { case INT: MAT_BUFI(self)[j*self->nrows+i] = MAT_BUFI(val)[cnt++]; break; case DOUBLE: MAT_BUFD(self)[j*self->nrows+i] = MAT_BUFD(val)[cnt++]; break; case COMPLEX: MAT_BUFZ(self)[j*self->nrows+i] = MAT_BUFZ(val)[cnt++]; break; } } if (decref_val) { Py_DECREF(val); } return 0; } if (!(Il = create_indexlist(self->nrows, argI)) || !(Jl = create_indexlist(self->ncols, argJ))) { if (decref_val) { Py_DECREF(val); } free_lists_exit(argI,argJ,Il,Jl,-1); } if (decref_val && arraystruct_nd < 2 && MAT_LGT(val) == MAT_LGT(Il)*MAT_LGT(Jl)) { MAT_NROWS(val) = MAT_LGT(Il); MAT_NCOLS(val) = MAT_LGT(Jl); } number n; if (PY_NUMBER(val) || (Matrix_Check(val) && MAT_LGT(val)==1)) { if (convert_num[id](&n, val, (Matrix_Check(val) ? 0 : 1), 0)) { if (decref_val) { Py_DECREF(val); } free_lists_exit(Il,Jl,argI,argJ,-1); } for (j=0; j < MAT_LGT(Jl); j++) for (i=0; i < MAT_LGT(Il); i++) { write_num[id](self->buffer,CWRAP(MAT_BUFI(Il)[i],self->nrows) + CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows, &n, 0); } } else if (Matrix_Check(val)) { if (MAT_LGT(Il) != MAT_NROWS(val) || MAT_LGT(Jl) != MAT_NCOLS(val) ) { if (!Matrix_Check(argI)) { Py_DECREF(Il); } if (!Matrix_Check(argJ)) { Py_DECREF(Jl); } if (decref_val) { Py_DECREF(val); } PY_ERR_INT(PyExc_TypeError, "argument has wrong size"); } int cnt = 0; for (j=0; j < MAT_LGT(Jl); j++) for (i=0; i < MAT_LGT(Il); i++, cnt++) { if (convert_num[id](&n, val, 0, cnt)) free_lists_exit(argI,argJ,Il,Jl,-1); write_num[id](self->buffer,CWRAP(MAT_BUFI(Il)[i],self->nrows) + CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows, &n, 0); } } else { /* spmatrix */ if (MAT_LGT(Il) != SP_NROWS(val) || MAT_LGT(Jl) != SP_NCOLS(val) ) { if (!Matrix_Check(argI)) { Py_DECREF(Il); } if (!Matrix_Check(argJ)) { Py_DECREF(Jl); } if (decref_val) { Py_DECREF(val); } PY_ERR_INT(PyExc_TypeError, "argument has wrong size"); } int cnt = 0; for (j=0; j < MAT_LGT(Jl); j++) for (i=0; i < MAT_LGT(Il); i++, cnt++) { spmatrix_getitem_i((spmatrix *)val, cnt, &n); write_num[id](self->buffer,CWRAP(MAT_BUFI(Il)[i],self->nrows) + CWRAP(MAT_BUFI(Jl)[j],self->ncols)*self->nrows, &n, 0); } } if (decref_val) { Py_DECREF(val); } free_lists_exit(argI,argJ,Il,Jl,0); } static PyMappingMethods matrix_as_mapping = { (lenfunc)matrix_length, (binaryfunc)matrix_subscr, (objobjargproc)matrix_ass_subscr }; static PyObject * matrix_transpose(matrix *self) { matrix *ret = Matrix_New(self->ncols, self->nrows, self->id); if (!ret) return PyErr_NoMemory(); int i, j, cnt = 0; for (i=0; i < ret->nrows; i++) for (j=0; j < ret->ncols; j++) write_num[self->id](ret->buffer, i + j*ret->nrows, self->buffer, cnt++); return (PyObject *)ret; } static PyObject * matrix_ctranspose(matrix *self) { if (self->id != COMPLEX) return matrix_transpose(self); matrix *ret = Matrix_New(self->ncols, self->nrows, self->id); if (!ret) return PyErr_NoMemory(); int i, j, cnt = 0; for (i=0; i < ret->nrows; i++) for (j=0; j < ret->ncols; j++) MAT_BUFZ(ret)[i + j*ret->nrows] = conj(MAT_BUFZ(self)[cnt++]); return (PyObject *)ret; } static PyObject * matrix_real(matrix *self) { if (self->id != COMPLEX) return (PyObject *)Matrix_NewFromMatrix(self,self->id); matrix *ret = Matrix_New(self->nrows, self->ncols, DOUBLE); if (!ret) return PyErr_NoMemory(); int i; for (i=0; i < MAT_LGT(self); i++) MAT_BUFD(ret)[i] = creal(MAT_BUFZ(self)[i]); return (PyObject *)ret; } static PyObject * matrix_imag(matrix *self) { matrix *ret; if (self->id != COMPLEX) { PyObject *a = PyFloat_FromDouble(0); ret = Matrix_NewFromNumber(self->nrows, self->ncols, self->id, a, 2); Py_DECREF(a); if (!ret) return PyErr_NoMemory(); return (PyObject *)ret; } if (!(ret = Matrix_New(self->nrows, self->ncols, DOUBLE))) return PyErr_NoMemory(); int i; for (i=0; i < MAT_LGT(self); i++) MAT_BUFD(ret)[i] = cimag(MAT_BUFZ(self)[i]); return (PyObject *)ret; } #if PY_MAJOR_VERSION >= 3 static char doc_tofile[] = "Writes a matrix to file\n\n" "ARGUMENTS\n" "s a Python stream object, for example obtained by open()\n\n"; static PyObject * matrix_tofile(matrix *self, PyObject *args, PyObject *kwrds) { PyObject *f, *bytes, *res; char *kwlist[] = {"s", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O:fromfile", kwlist, &f)) return NULL; bytes = PyBytes_FromStringAndSize(self->buffer, E_SIZE[MAT_ID(self)]*MAT_LGT(self)); if (bytes == NULL) return NULL; res = PyObject_CallMethod(f, "write", "O", bytes); Py_DECREF(bytes); if (res == NULL) return NULL; Py_DECREF(res); return Py_BuildValue(""); } #else static char doc_tofile[] = "Writes a matrix to file\n\n" "ARGUMENTS\n" "fo a Python file object previously obtained by open()\n\n"; static PyObject * matrix_tofile(matrix *self, PyObject *args, PyObject *kwrds) { PyObject *file_obj; FILE *fp; char *kwlist[] = {"fo", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &file_obj)) return NULL; if (!PyFile_Check(file_obj)) PY_ERR_TYPE("argument must a file object"); if (!(fp = PyFile_AsFile(file_obj))) PY_ERR(PyExc_IOError,"file not open for writing"); if (fwrite(self->buffer, E_SIZE[self->id], MAT_LGT(self), fp)) ; return Py_BuildValue(""); } #endif #if PY_MAJOR_VERSION >= 3 static char doc_fromfile[] = "Reads a matrix from file\n\n" "ARGUMENTS\n" "s a Python stream object, for example obtained by open()\n\n"; static PyObject * matrix_fromfile(matrix *self, PyObject *args, PyObject *kwrds) { PyObject *f, *b; char *kwlist[] = {"s", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O:fromfile", kwlist, &f)) return NULL; b = PyObject_CallMethod(f, "read", "n", E_SIZE[self->id]*MAT_LGT(self)); if (b == NULL) return NULL; if (!PyBytes_Check(b)) { PyErr_SetString(PyExc_TypeError, "read() didn't return bytes"); Py_DECREF(b); return NULL; } if (PyBytes_GET_SIZE(b) != E_SIZE[self->id]*MAT_LGT(self)) { PyErr_SetString(PyExc_EOFError, "read() didn't return enough bytes"); Py_DECREF(b); return NULL; } Py_buffer view; PyObject_GetBuffer(b, &view, PyBUF_SIMPLE); memcpy(self->buffer, view.buf, E_SIZE[self->id]*MAT_LGT(self)); PyBuffer_Release(&view); Py_DECREF(b); return Py_BuildValue(""); } #else static char doc_fromfile[] = "Reads a matrix from file\n\n" "ARGUMENTS\n" "fo a Python file object prevously obtained by open()\n\n"; static PyObject * matrix_fromfile(matrix *self, PyObject *args, PyObject *kwrds) { PyObject *file_obj; FILE *fp; char *kwlist[] = {"fo", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O", kwlist, &file_obj)) return NULL; if (!PyFile_Check(file_obj)) PY_ERR_TYPE("argument must a file object"); if (!(fp = PyFile_AsFile(file_obj))) PY_ERR(PyExc_IOError,"file not open for reading"); int n = fread(self->buffer, E_SIZE[self->id], MAT_LGT(self), fp); if (n < MAT_LGT(self)) PY_ERR(PyExc_IOError, "could not read entire matrix"); return Py_BuildValue(""); } #endif static PyObject * matrix_getstate(matrix *self) { PyObject *list = PyList_New(MAT_LGT(self)); PyObject *size = PyTuple_New(2); if (!list || !size) { Py_XDECREF(list); Py_XDECREF(size); return NULL; } #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(size, 0, PyLong_FromLong(MAT_NROWS(self))); PyTuple_SET_ITEM(size, 1, PyLong_FromLong(MAT_NCOLS(self))); #else PyTuple_SET_ITEM(size, 0, PyInt_FromLong(MAT_NROWS(self))); PyTuple_SET_ITEM(size, 1, PyInt_FromLong(MAT_NCOLS(self))); #endif int i; for (i=0; i= 3 return Py_BuildValue("ON", Py_TYPE(self), matrix_getstate(self)); #else return Py_BuildValue("ON", self->ob_type, matrix_getstate(self)); #endif } static PyMethodDef matrix_methods[] = { {"trans", (PyCFunction)matrix_transpose, METH_NOARGS, "Returns the matrix transpose"}, {"ctrans", (PyCFunction)matrix_ctranspose, METH_NOARGS, "Returns the matrix conjugate transpose"}, {"real", (PyCFunction)matrix_real, METH_NOARGS, "Returns real part of matrix"}, {"imag", (PyCFunction)matrix_imag, METH_NOARGS, "Returns imaginary part of matrix"}, {"tofile", (PyCFunction)matrix_tofile, METH_VARARGS|METH_KEYWORDS, doc_tofile}, {"fromfile", (PyCFunction)matrix_fromfile, METH_VARARGS|METH_KEYWORDS, doc_fromfile}, {"__reduce__", (PyCFunction)matrix_reduce, METH_NOARGS, "__reduce__() -> (cls, state)"}, {NULL} /* Sentinel */ }; static PyObject * matrix_get_size(matrix *self, void *closure) { PyObject *t = PyTuple_New(2); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(t, 0, PyLong_FromLong(self->nrows)); PyTuple_SET_ITEM(t, 1, PyLong_FromLong(self->ncols)); #else PyTuple_SET_ITEM(t, 0, PyInt_FromLong(self->nrows)); PyTuple_SET_ITEM(t, 1, PyInt_FromLong(self->ncols)); #endif return t; } static int matrix_set_size(matrix *self, PyObject *value, void *closure) { if (value == NULL) PY_ERR_INT(PyExc_TypeError, "size attribute cannot be deleted"); if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) PY_ERR_INT(PyExc_TypeError, "can only assign a 2-tuple to size"); #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(PyTuple_GET_ITEM(value, 0)) || !PyLong_Check(PyTuple_GET_ITEM(value, 1))) PY_ERR_INT(PyExc_TypeError, "invalid size tuple"); int m = PyLong_AS_LONG(PyTuple_GET_ITEM(value, 0)); int n = PyLong_AS_LONG(PyTuple_GET_ITEM(value, 1)); #else if (!PyInt_Check(PyTuple_GET_ITEM(value, 0)) || !PyInt_Check(PyTuple_GET_ITEM(value, 1))) PY_ERR_INT(PyExc_TypeError, "invalid size tuple"); int m = PyInt_AS_LONG(PyTuple_GET_ITEM(value, 0)); int n = PyInt_AS_LONG(PyTuple_GET_ITEM(value, 1)); #endif if (m<0 || n<0) PY_ERR_INT(PyExc_TypeError, "dimensions must be non-negative"); if (m*n != MAT_LGT(self)) PY_ERR_INT(PyExc_TypeError, "number of elements in matrix cannot change"); MAT_NROWS(self) = m; MAT_NCOLS(self) = n; return 0; } static PyObject * matrix_get_typecode(matrix *self, void *closure) { #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromStringAndSize(TC_CHAR[self->id], 1); #else return PyString_FromStringAndSize(TC_CHAR[self->id], 1); #endif } #if PY_MAJOR_VERSION >= 3 static int matrix_buffer_getbuf(matrix *self, Py_buffer *view, int flags) { if (view==NULL) return 0; view->buf = self->buffer; view->len = MAT_LGT(self)*E_SIZE[self->id]; view->readonly = 0; view->format = NULL; //FIXME view->ndim = 2; view->obj = (PyObject*)self; Py_INCREF(self); view->itemsize = E_SIZE[self->id]; view->suboffsets = NULL; self->shape[0] = self->nrows; self->shape[1] = self->ncols; view->shape = self->shape; self->strides[0] = view->itemsize; self->strides[1] = self->nrows*view->itemsize; view->strides = self->strides; view->internal = NULL; self->ob_exports++; return 0; } static void matrix_buffer_relbuf(matrix *self, Py_buffer *view) { self->ob_exports--; } static PyBufferProcs matrix_as_buffer = { (getbufferproc)matrix_buffer_getbuf, (releasebufferproc)matrix_buffer_relbuf }; #else static void matrix_free_array_struct(void *a_struct, void *descr) { free(((PyArrayInterface *)a_struct)->shape); free(((PyArrayInterface *)a_struct)->strides); free(a_struct); } static PyObject * matrix_array_struct(matrix *self, void *closure) { PyArrayInterface *a = malloc(sizeof(PyArrayInterface)); if (!a) return PyErr_NoMemory(); a->shape = malloc(2*sizeof(int_t)); a->strides = malloc(2*sizeof(int_t)); if (!a->shape || !a->strides) { free(a->shape); free(a->strides); free(a); return PyErr_NoMemory(); } a->version = 2; a->nd = 2; a->typekind = PY_ARRAY_TC[self->id]; a->itemsize = E_SIZE[self->id]; a->flags = 0x001 + 0x002 + 0x100 + 0x200 + 0x400; a->shape[0] = self->nrows; a->shape[1] = self->ncols; a->strides[0] = E_SIZE[self->id]; a->strides[1] = self->nrows*E_SIZE[self->id]; a->data = self->buffer; return (PyObject *) PyCObject_FromVoidPtrAndDesc((void *) a, "CVXOPT ARRAY STRUCT", matrix_free_array_struct); } #endif static PyObject * matrix_get_T(matrix *self, void *closure) { return matrix_transpose(self); } static PyObject * matrix_get_H(matrix *self, void *closure) { return matrix_ctranspose(self); } static PyGetSetDef matrix_getsets[] = { {"size", (getter) matrix_get_size, (setter) matrix_set_size, "matrix dimensions"}, {"typecode", (getter) matrix_get_typecode, NULL, "typecode character"}, #if PY_MAJOR_VERSION <3 {"__array_struct__", (getter) matrix_array_struct, NULL, "C object implementing the NumPy array protocol"}, #endif {"T", (getter) matrix_get_T, NULL, "transpose"}, {"H", (getter) matrix_get_H, NULL, "conjugate transpose"}, {NULL} /* Sentinel */ }; PyTypeObject matrix_tp = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, #endif "cvxopt.base.matrix", sizeof(matrix), 0, (destructor)matrix_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)matrix_repr, /* tp_repr */ &matrix_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ &matrix_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ (reprfunc)matrix_str, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ #if PY_MAJOR_VERSION >= 3 &matrix_as_buffer, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ #else 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ #endif 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ (richcmpfunc)matrix_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)matrix_iter, /* tp_iter */ 0, /* tp_iternext */ matrix_methods, /* tp_methods */ 0, /* tp_members */ matrix_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ matrix_new, /* tp_new */ 0, /* tp_free */ }; /**************************************************************************/ static PyObject * matrix_add_generic(PyObject *self, PyObject *other, int inplace) { if (!(Matrix_Check(self) || PY_NUMBER(self)) || !(Matrix_Check(other) || PY_NUMBER(other))) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1)); int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1)); int id = MAX(id_self,id_other); if (inplace && (id != id_self || (MAT_LGT(self)==1 && (Matrix_Check(other) && MAT_LGT(other)!=1)))) PY_ERR_TYPE("invalid inplace operation"); /* first operand is a scalar */ if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) { number n; if (!inplace) { convert_num[id](&n,self,(Matrix_Check(self) ? 0 : 1),0); matrix *ret = Matrix_NewFromMatrix((matrix *)other, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(ret), int1 = 1, int0 = 0; axpy[id](&lgt, &One[id], &n, &int0, ret->buffer, &int1); return (PyObject *)ret; } else { convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); int int1 = 1, int0 = 0; axpy[id](&int1, &One[id], &n, &int0, MAT_BUF(self), &int1); Py_INCREF(self); return self; } } /* second operand is a scalar */ else if (PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other)==1)) { number n; convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); if (!inplace) { matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(self), int1 = 1, int0 = 0; axpy[id](&lgt, &One[id], &n, &int0, ret->buffer, &int1); return (PyObject *)ret; } else { int lgt = MAT_LGT(self), int1 = 1, int0 = 0; axpy[id](&lgt, &One[id], &n, &int0, MAT_BUF(self), &int1); Py_INCREF(self); return self; } } else { /* adding two matrices */ if (MAT_NROWS(self) != MAT_NROWS(other) || MAT_NCOLS(self) != MAT_NCOLS(other)) PY_ERR_TYPE("incompatible dimensions"); void *other_coerce = convert_mtx_alloc((matrix *)other, id); if (!other_coerce) return PyErr_NoMemory(); if (!inplace) { matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(self), int1 = 1; axpy[id](&lgt, &One[id], other_coerce, &int1, MAT_BUF(ret), &int1); if (MAT_BUF(other) != other_coerce) { free(other_coerce); } return (PyObject *)ret; } else { int lgt = MAT_LGT(self), int1 = 1; axpy[id](&lgt, &One[id], other_coerce, &int1, MAT_BUF(self), &int1); if (MAT_BUF(other) != other_coerce) { free(other_coerce); } Py_INCREF(self); return self; } } } PyObject * matrix_add(PyObject *self, PyObject *other) { return matrix_add_generic(self, other, 0); } static PyObject * matrix_iadd(PyObject *self,PyObject *other) { return matrix_add_generic(self, other, 1); } static PyObject * matrix_sub_generic(PyObject *self, PyObject *other, int inplace) { if (!(Matrix_Check(self) || PY_NUMBER(self)) || !(Matrix_Check(other) || PY_NUMBER(other))) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1)); int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1)); int id = MAX(id_self,id_other); if (inplace && (id != id_self || (MAT_LGT(self)==1 && (Matrix_Check(other) && MAT_LGT(other)!=1)))) PY_ERR_TYPE("invalid inplace operation"); /* first operand is a scalar */ if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) { number n; if (!inplace) { convert_num[id](&n,self,(Matrix_Check(self) ? 0 : 1),0); matrix *ret = Matrix_NewFromMatrix((matrix *)other, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(ret), int1 = 1, int0 = 0; scal[id](&lgt, &MinusOne[id], ret->buffer, &int1); axpy[id](&lgt, &One[id], &n, &int0, ret->buffer, &int1); return (PyObject *)ret; } else { convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); int int1 = 1, int0 = 0; axpy[id](&int1, &MinusOne[id], &n, &int0, MAT_BUF(self), &int1); Py_INCREF(self); return self; } } /* second operand is a scalar */ else if (PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other)==1)) { number n; convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); if (!inplace) { matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(self), int1 = 1, int0 = 0; axpy[id](&lgt, &MinusOne[id], &n, &int0, ret->buffer, &int1); return (PyObject *)ret; } else { int lgt = MAT_LGT(self), int1 = 1, int0 = 0; axpy[id](&lgt, &MinusOne[id], &n, &int0, MAT_BUF(self), &int1); Py_INCREF(self); return self; } } else { /* subtracting two matrices */ if (MAT_NROWS(self) != MAT_NROWS(other) || MAT_NCOLS(self) != MAT_NCOLS(other)) PY_ERR_TYPE("incompatible dimensions"); void *other_coerce = convert_mtx_alloc((matrix *)other, id); if (!other_coerce) return PyErr_NoMemory(); if (!inplace) { matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(self), int1 = 1; axpy[id](&lgt, &MinusOne[id], other_coerce, &int1, MAT_BUF(ret), &int1); if (MAT_BUF(other) != other_coerce) { free(other_coerce); } return (PyObject *)ret; } else { int lgt = MAT_LGT(self), int1 = 1; axpy[id](&lgt,&MinusOne[id],other_coerce,&int1,MAT_BUF(self),&int1); if (MAT_BUF(other) != other_coerce) { free(other_coerce); } Py_INCREF(self); return self; } } } PyObject * matrix_sub(PyObject *self, PyObject *other) { return matrix_sub_generic(self, other, 0); } static PyObject * matrix_isub(PyObject *self,PyObject *other) { return matrix_sub_generic(self, other, 1); } static PyObject * matrix_mul_generic(PyObject *self, PyObject *other, int inplace) { if (!(Matrix_Check(self) || PY_NUMBER(self)) || !(Matrix_Check(other) || PY_NUMBER(other))) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1)); int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1)); int id = MAX(id_self,id_other); if (inplace && (id != id_self || (MAT_LGT(self)==1 && (Matrix_Check(other) && MAT_LGT(other)!=1)) || (MAT_LGT(self)>1 && (Matrix_Check(other) && MAT_LGT(other)>1))) ) PY_ERR_TYPE("invalid inplace operation"); /* first operand is a scalar */ if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) { number n; if (!inplace) { convert_num[id](&n,self,(Matrix_Check(self) ? 0 : 1),0); matrix *ret = Matrix_NewFromMatrix((matrix *)other, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(ret), int1 = 1; scal[id](&lgt, &n, ret->buffer, &int1); return (PyObject *)ret; } else { convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); int int1 = 1; scal[id](&int1, &n, MAT_BUF(self), &int1); Py_INCREF(self); return self; } } /* second operand is a scalar */ else if (PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other)==1)) { number n; convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); if (!inplace) { matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(self), int1 = 1; scal[id](&lgt, &n, ret->buffer, &int1); return (PyObject *)ret; } else { int lgt = MAT_LGT(self), int1 = 1; scal[id](&lgt, &n, MAT_BUF(self), &int1); Py_INCREF(self); return self; } } else { /* multiplying two matrices */ if (MAT_NCOLS(self) != MAT_NROWS(other)) PY_ERR_TYPE("incompatible dimensions"); int m = MAT_NROWS(self), n = MAT_NCOLS(other), k = MAT_NCOLS(self); int ldA = MAX(1,MAT_NROWS(self)); int ldB = MAX(1,MAT_NROWS(other)); int ldC = MAX(1,MAT_NROWS(self)); char transA='N', transB='N'; void *self_coerce = convert_mtx_alloc((matrix *)self, id); if (!self_coerce) return PyErr_NoMemory(); void *other_coerce = convert_mtx_alloc((matrix *)other, id); if (!other_coerce) { if (MAT_ID(self) != id) { free(self_coerce); } return PyErr_NoMemory(); } matrix *c = Matrix_New(m, n, id); if (!c) { if (MAT_ID(self) != id) { free(self_coerce); } if (MAT_ID(other) != id) { free(other_coerce); } return PyErr_NoMemory(); } gemm[id](&transA, &transB, &m, &n, &k, &One[id], self_coerce, &ldA, other_coerce, &ldB, &Zero[id], MAT_BUF(c), &ldC); if (MAT_ID(self) != id) { free(self_coerce); } if (MAT_ID(other) != id) { free(other_coerce); } return (PyObject *)c; } } static PyObject * matrix_mul(PyObject *self, PyObject *other) { return matrix_mul_generic(self, other, 0); } static PyObject * matrix_imul(PyObject *self,PyObject *other) { return matrix_mul_generic(self, other, 1); } static PyObject * matrix_div_generic(PyObject *self, PyObject *other, int inplace) { if (!((Matrix_Check(other) && MAT_LGT(other)==1) || PY_NUMBER(other))) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1)); int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1)); #if PY_MAJOR_VERSION >= 3 int id = MAX(DOUBLE, MAX(id_self,id_other)); #else int id = MAX(id_self,id_other); #endif number n; convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); if (!inplace) { matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(ret); if (div_array[id](ret->buffer, n, lgt)) { Py_DECREF(ret); return NULL; } return (PyObject *)ret; } else { if (id != id_self) PY_ERR_TYPE("invalid inplace operation"); if (div_array[id](MAT_BUF(self), n, MAT_LGT(self))) return NULL; Py_INCREF(self); return self; } } static PyObject * matrix_div(PyObject *self, PyObject *other) { return matrix_div_generic(self, other, 0); } static PyObject * matrix_idiv(PyObject *self,PyObject *other) { return matrix_div_generic(self, other, 1); } static PyObject * matrix_rem_generic(PyObject *self, PyObject *other, int inplace) { if (!((Matrix_Check(other) && MAT_LGT(other)==1) || PY_NUMBER(other))) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } int id_self = get_id(self, (Matrix_Check(self) ? 0 : 1)); int id_other = get_id(other, (Matrix_Check(other) ? 0 : 1)); int id = MAX(id_self,id_other); if (id == COMPLEX) PY_ERR(PyExc_NotImplementedError, "complex modulo"); number n; convert_num[id](&n,other,(Matrix_Check(other) ? 0 : 1),0); if (!inplace) { matrix *ret = Matrix_NewFromMatrix((matrix *)self, id); if (!ret) return PyErr_NoMemory(); int lgt = MAT_LGT(ret); if (mtx_rem[id](ret->buffer, n, lgt)) { Py_DECREF(ret); return NULL; } return (PyObject *)ret; } else { void *ptr = convert_mtx_alloc((matrix *)self, id); if (!ptr) return PyErr_NoMemory(); int lgt = MAT_LGT(self); if (mtx_rem[id](ptr,n,lgt)) { free(ptr); return NULL; } free_convert_mtx_alloc(self, ptr, id); Py_INCREF(self); return self; } } static PyObject * matrix_rem(PyObject *self, PyObject *other) { return matrix_rem_generic(self, other, 0); } static PyObject * matrix_irem(PyObject *self, PyObject *other) { return matrix_rem_generic(self, other, 1); } static PyObject * matrix_neg(matrix *self) { matrix *x = Matrix_NewFromMatrix(self,self->id); if (!x) return PyErr_NoMemory(); int n = MAT_LGT(x), int1 = 1; scal[x->id](&n, &MinusOne[x->id], x->buffer, &int1); return (PyObject *)x; } static PyObject * matrix_pos(matrix *self) { matrix *x = Matrix_NewFromMatrix(self, self->id); if (!x) return PyErr_NoMemory(); return (PyObject *)x; } static PyObject * matrix_abs(matrix *self) { matrix *ret = Matrix_New(self->nrows, self->ncols, (self->id == COMPLEX ? DOUBLE : self->id)); if (!ret) return PyErr_NoMemory(); mtx_abs[self->id](MAT_BUF(self), MAT_BUF(ret), MAT_LGT(self)); return (PyObject *)ret; } static PyObject * matrix_pow(PyObject *self, PyObject *other) { if (!PY_NUMBER(other)) PY_ERR_TYPE("exponent must be a number"); number val; int id = MAX(DOUBLE, MAX(MAT_ID(self), get_id(other, 1))); convert_num[id](&val, other, 1, 0); matrix *Y = Matrix_NewFromMatrix((matrix *)self, id); if (!Y) return PyErr_NoMemory(); int i; for (i=0; i 0.0)) { Py_DECREF(Y); PY_ERR(PyExc_ValueError, "domain error"); } MAT_BUFD(Y)[i] = pow(MAT_BUFD(Y)[i], val.d); } else { if (MAT_BUFZ(Y)[i] == 0.0 && (cimag(val.z) != 0.0 || creal(val.z)<0.0)) { Py_DECREF(Y); PY_ERR(PyExc_ValueError, "domain error"); } MAT_BUFZ(Y)[i] = cpow(MAT_BUFZ(Y)[i], val.z); } } return (PyObject *)Y; } static int matrix_nonzero(matrix *self) { int i, res = 0; for (i=0; iindex = 0; it->mObj = obj; PyObject_GC_Track(it); return (PyObject *)it; } static void matrixiter_dealloc(matrixiter *it) { PyObject_GC_UnTrack(it); Py_XDECREF(it->mObj); PyObject_GC_Del(it); } static int matrixiter_traverse(matrixiter *it, visitproc visit, void *arg) { if (it->mObj == NULL) return 0; return visit((PyObject *)(it->mObj), arg); } static PyObject * matrixiter_next(matrixiter *it) { assert(MatrixIter_Check(it)); if (it->index >= MAT_LGT(it->mObj)) return NULL; return num2PyObject[it->mObj->id](it->mObj->buffer, it->index++); } static PyTypeObject matrixiter_tp = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, /* ob_size */ #endif "matrixiter", /* tp_name */ sizeof(matrixiter), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)matrixiter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ 0, /* tp_doc */ (traverseproc)matrixiter_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ (iternextfunc)matrixiter_next, /* tp_iternext */ 0, /* tp_methods */ }; PyObject * matrix_log(matrix *self, PyObject *args, PyObject *kwrds) { PyObject *A; if (!PyArg_ParseTuple(args, "O", &A)) return NULL; #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(A) || PyFloat_Check(A)) { #else if (PyInt_Check(A) || PyFloat_Check(A)) { #endif double f = PyFloat_AsDouble(A); if (f>0.0) return Py_BuildValue("d",log(f)); else PY_ERR(PyExc_ValueError, "domain error"); } else if (PyComplex_Check(A)) { number n; convert_num[COMPLEX](&n, A, 1, 0); if (n.z == 0) PY_ERR(PyExc_ValueError, "domain error"); n.z = clog(n.z); return num2PyObject[COMPLEX](&n, 0); } else if (Matrix_Check(A) && (MAT_ID(A) == INT || MAT_ID(A) == DOUBLE)) { if (MAT_LGT(A) == 0) return (PyObject *)Matrix_New(MAT_NROWS(A),MAT_NCOLS(A),DOUBLE); double val = (MAT_ID(A) == INT ? MAT_BUFI(A)[0] : MAT_BUFD(A)[0]); int i; for (i=1; i 0.0) { matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), DOUBLE); if (!ret) return PyErr_NoMemory(); for (i=0; i= 3 if (PyLong_Check(A) || PyFloat_Check(A)) #else if (PyInt_Check(A) || PyFloat_Check(A)) #endif return Py_BuildValue("d",exp(PyFloat_AsDouble(A))); else if (PyComplex_Check(A)) { number n; convert_num[COMPLEX](&n, A, 1, 0); n.z = cexp(n.z); return num2PyObject[COMPLEX](&n, 0); } else if (Matrix_Check(A)) { matrix *ret = Matrix_New(MAT_NROWS(A),MAT_NCOLS(A), (MAT_ID(A) == COMPLEX ? COMPLEX : DOUBLE)); if (!ret) return PyErr_NoMemory(); int i; if (MAT_ID(ret) == DOUBLE) for (i=0; i= 3 if (PyLong_Check(A) || PyFloat_Check(A)) { #else if (PyInt_Check(A) || PyFloat_Check(A)) { #endif double f = PyFloat_AsDouble(A); if (f >= 0.0) return Py_BuildValue("d",sqrt(f)); else PY_ERR(PyExc_ValueError, "domain error"); } else if (PyComplex_Check(A)) { number n; convert_num[COMPLEX](&n, A, 1, 0); n.z = csqrt(n.z); return num2PyObject[COMPLEX](&n, 0); } else if (Matrix_Check(A) && (MAT_ID(A) == INT || MAT_ID(A) == DOUBLE)) { if (MAT_LGT(A) == 0) return (PyObject *)Matrix_New(MAT_NROWS(A),MAT_NCOLS(A),DOUBLE); double val = (MAT_ID(A) == INT ? MAT_BUFI(A)[0] : MAT_BUFD(A)[0]); int i; for (i=1; i= 0.0) { matrix *ret = Matrix_New(MAT_NROWS(A), MAT_NCOLS(A), DOUBLE); if (!ret) return PyErr_NoMemory(); for (i=0; i= 3 if (PyLong_Check(A) || PyFloat_Check(A)) #else if (PyInt_Check(A) || PyFloat_Check(A)) #endif return Py_BuildValue("d",cos(PyFloat_AsDouble(A))); else if (PyComplex_Check(A)) { number n; convert_num[COMPLEX](&n, A, 1, 0); n.z = ccos(n.z); return num2PyObject[COMPLEX](&n, 0); } else if (Matrix_Check(A)) { matrix *ret = Matrix_New(MAT_NROWS(A),MAT_NCOLS(A), (MAT_ID(A) == COMPLEX ? COMPLEX : DOUBLE)); if (!ret) return PyErr_NoMemory(); int_t i; if (MAT_ID(ret) == DOUBLE) for (i=0; i= 3 if (PyLong_Check(A) || PyFloat_Check(A)) #else if (PyInt_Check(A) || PyFloat_Check(A)) #endif return Py_BuildValue("d",sin(PyFloat_AsDouble(A))); else if (PyComplex_Check(A)) { number n; convert_num[COMPLEX](&n, A, 1, 0); n.z = csin(n.z); return num2PyObject[COMPLEX](&n, 0); } else if (Matrix_Check(A)) { matrix *ret = Matrix_New(MAT_NROWS(A),MAT_NCOLS(A), (MAT_ID(A) == COMPLEX ? COMPLEX : DOUBLE)); if (!ret) return PyErr_NoMemory(); int_t i; if (MAT_ID(ret) == DOUBLE) for (i=0; i. */ #define BASE_MODULE #include "Python.h" #include "cvxopt.h" #include "misc.h" #include PyDoc_STRVAR(base__doc__,"Convex optimization package"); extern PyTypeObject matrix_tp ; matrix * Matrix_New(int, int, int) ; matrix * Matrix_NewFromMatrix(matrix *, int) ; matrix * Matrix_NewFromSequence(PyObject *, int) ; #if PY_MAJOR_VERSION < 3 matrix * Matrix_NewFromArrayStruct(PyObject *, int, int *) ; #endif extern PyTypeObject spmatrix_tp ; spmatrix * SpMatrix_New(int_t, int_t, int, int ) ; spmatrix * SpMatrix_NewFromMatrix(matrix *, int) ; spmatrix * SpMatrix_NewFromSpMatrix(spmatrix *, int) ; spmatrix * SpMatrix_NewFromIJV(matrix *, matrix *, matrix *, int_t, int_t, int, int) ; void free_ccs(ccs *) ; extern int (*sp_axpy[])(number, void *, void *, int, int, int, void **) ; extern int (*sp_gemm[])(char, char, number, void *, void *, number, void *, int, int, int, int, void **, int, int, int); extern int (*sp_gemv[])(char, int, int, number, void *, int, void *, int, number, void *, int) ; extern int (*sp_symv[])(char, int, number, ccs *, int, void *, int, number, void *, int) ; extern int (*sp_syrk[])(char, char, number, void *, number, void *, int, int, int, int, void **) ; const int E_SIZE[] = { sizeof(int_t), sizeof(double), sizeof(complex) }; const char TC_CHAR[][2] = {"i","d","z"} ; /* * Helper routines and definitions to implement type transparency. */ number One[3], MinusOne[3], Zero[3]; static void write_inum(void *dest, int i, void *src, int j) { ((int_t *)dest)[i] = ((int_t *)src)[j]; } static void write_dnum(void *dest, int i, void *src, int j) { ((double *)dest)[i] = ((double *)src)[j]; } static void write_znum(void *dest, int i, void *src, int j) { ((complex *)dest)[i] = ((complex *)src)[j]; } void (*write_num[])(void *, int, void *, int) = { write_inum, write_dnum, write_znum }; static PyObject * inum2PyObject(void *src, int i) { return Py_BuildValue("l", ((int_t *)src)[i]); } static PyObject * dnum2PyObject(void *src, int i) { return Py_BuildValue("d", ((double *)src)[i]); } static PyObject * znum2PyObject(void *src, int i) { Py_complex z; z.real = creal (((complex *)src)[i]); z.imag = cimag (((complex *)src)[i]); return Py_BuildValue("D", &z); } PyObject * (*num2PyObject[])(void *, int) = { inum2PyObject, dnum2PyObject, znum2PyObject }; /* val_id: 0 = matrix, 1 = PyNumber */ static int convert_inum(void *dest, void *val, int val_id, int offset) { if (val_id==0) { /* 1x1 matrix */ switch (MAT_ID(val)) { case INT: *(int_t *)dest = MAT_BUFI(val)[offset]; return 0; //case DOUBLE: //*(int_t *)dest = (int_t)round(MAT_BUFD(val)[offset]); return 0; default: PY_ERR_INT(PyExc_TypeError,"cannot cast argument as integer"); } } else { /* PyNumber */ #if PY_MAJOR_VERSION >= 3 if (PyLong_Check((PyObject *)val)) { *(int_t *)dest = PyLong_AS_LONG((PyObject *)val); return 0; } #else if (PyInt_Check((PyObject *)val)) { *(int_t *)dest = PyInt_AS_LONG((PyObject *)val); return 0; } #endif else PY_ERR_INT(PyExc_TypeError,"cannot cast argument as integer"); } } static int convert_dnum(void *dest, void *val, int val_id, int offset) { if (val_id==0) { /* matrix */ switch (MAT_ID(val)) { case INT: *(double *)dest = MAT_BUFI(val)[offset]; return 0; case DOUBLE: *(double *)dest = MAT_BUFD(val)[offset]; return 0; default: PY_ERR_INT(PyExc_TypeError, "cannot cast argument as double"); } } else { /* PyNumber */ #if PY_MAJOR_VERSION >= 3 if (PyLong_Check((PyObject *)val) || PyFloat_Check((PyObject *)val)) { #else if (PyInt_Check((PyObject *)val) || PyFloat_Check((PyObject *)val)) { #endif *(double *)dest = PyFloat_AsDouble((PyObject *)val); return 0; } else PY_ERR_INT(PyExc_TypeError,"cannot cast argument as double"); } } static int convert_znum(void *dest, void *val, int val_id, int offset) { if (val_id==0) { /* 1x1 matrix */ switch (MAT_ID(val)) { case INT: *(complex *)dest = MAT_BUFI(val)[offset]; return 0; case DOUBLE: *(complex *)dest = MAT_BUFD(val)[offset]; return 0; case COMPLEX: *(complex *)dest = MAT_BUFZ(val)[offset]; return 0; default: return -1; } } else { /* PyNumber */ Py_complex c = PyComplex_AsCComplex((PyObject *)val); *(complex *)dest = c.real + I*c.imag; return 0; } } int (*convert_num[])(void *, void *, int, int) = { convert_inum, convert_dnum, convert_znum }; extern void daxpy_(int *, void *, void *, int *, void *, int *) ; extern void zaxpy_(int *, void *, void *, int *, void *, int *) ; static void i_axpy(int *n, void *a, void *x, int *incx, void *y, int *incy) { int i; for (i=0; i < *n; i++) { ((int_t *)y)[i*(*incy)] += *((int_t *)a)*((int_t *)x)[i*(*incx)]; } } void (*axpy[])(int *, void *, void *, int *, void *, int *) = { i_axpy, daxpy_, zaxpy_ }; extern void dscal_(int *, void *, void *, int *) ; extern void zscal_(int *, void *, void *, int *) ; /* we dont implement a BLAS iscal */ static void i_scal(int *n, void *a, void *x, int *incx) { int i; for (i=0; i < *n; i++) { ((int_t *)x)[i*(*incx)] *= *((int_t *)a); } } void (*scal[])(int *, void *, void *, int *) = { i_scal, dscal_, zscal_ }; extern void dgemm_(char *, char *, int *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *) ; extern void zgemm_(char *, char *, int *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *) ; /* we dont implement a BLAS igemm */ static void i_gemm(char *transA, char *transB, int *m, int *n, int *k, void *alpha, void *A, int *ldA, void *B, int *ldB, void *beta, void *C, int *ldC) { int i, j, l; for (j=0; j<*n; j++) { for (i=0; i<*m; i++) { ((int_t *)C)[i+j*(*m)] = 0; for (l=0; l<*k; l++) ((int_t *)C)[i+j*(*m)]+=((int_t *)A)[i+l*(*m)]*((int_t *)B)[j*(*k)+l]; } } } void (*gemm[])(char *, char *, int *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *) = { i_gemm, dgemm_, zgemm_ }; extern void dgemv_(char *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *); extern void zgemv_(char *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *); static void (*gemv[])(char *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *) = { NULL, dgemv_, zgemv_ }; extern void dsyrk_(char *, char *, int *, int *, void *, void *, int *, void *, void *, int *); extern void zsyrk_(char *, char *, int *, int *, void *, void *, int *, void *, void *, int *); void (*syrk[])(char *, char *, int *, int *, void *, void *, int *, void *, void *, int *) = { NULL, dsyrk_, zsyrk_ }; extern void dsymv_(char *, int *, void *, void *, int *, void *, int *, void *, void *, int *); extern void zsymv_(char *, int *, void *, void *, int *, void *, int *, void *, void *, int *); void (*symv[])(char *, int *, void *, void *, int *, void *, int *, void *, void *, int *) = { NULL, dsymv_, zsymv_ }; static void mtx_iabs(void *src, void *dest, int n) { int i; for (i=0; i= 3 else if (PyLong_Check((PyObject *)val)) #else else if (PyInt_Check((PyObject *)val)) #endif return INT; else if (PyFloat_Check((PyObject *)val)) return DOUBLE; else return COMPLEX; } static int Matrix_Check_func(void *o) { return Matrix_Check((PyObject*)o); } static int SpMatrix_Check_func(void *o) { return SpMatrix_Check((PyObject *)o); } static char doc_axpy[] = "Constant times a vector plus a vector (y := alpha*x+y).\n\n" "axpy(x, y, n=None, alpha=1.0)\n\n" "ARGUMENTS\n" "x 'd' or 'z' (sp)matrix\n\n" "y 'd' or 'z' (sp)matrix. Must have the same type as x.\n\n" "n integer. If n<0, the default value of n is used.\n" " The default value is equal to\n" " (len(x)>=offsetx+1) ? 1+(len(x)-offsetx-1)/incx : 0.\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if x is complex"; PyObject * base_axpy(PyObject *self, PyObject *args, PyObject *kwrds) { PyObject *x, *y, *partial = NULL; PyObject *ao=NULL; number a; char *kwlist[] = {"x", "y", "alpha", "partial", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OO:axpy", kwlist, &x, &y, &ao, &partial)) return NULL; if (!Matrix_Check(x) && !SpMatrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y) && !SpMatrix_Check(y)) err_mtrx("y"); if (partial && !PyBool_Check(partial)) err_bool("partial"); if (X_ID(x) != X_ID(y)) err_conflicting_ids; int id = X_ID(x); if (X_NROWS(x) != X_NROWS(y) || X_NCOLS(x) != X_NCOLS(y)) PY_ERR_TYPE("dimensions of x and y do not match"); if (ao && convert_num[id](&a, ao, 1, 0)) err_type("alpha"); if (Matrix_Check(x) && Matrix_Check(y)) { int n = X_NROWS(x)*X_NCOLS(x); axpy[id](&n, (ao ? &a : &One[id]), MAT_BUF(x), (int *)&One[INT], MAT_BUF(y), (int *)&One[INT]); } else { void *z = NULL; if (sp_axpy[id]((ao ? a : One[id]), Matrix_Check(x) ? MAT_BUF(x): ((spmatrix *)x)->obj, Matrix_Check(y) ? MAT_BUF(y): ((spmatrix *)y)->obj, SpMatrix_Check(x), SpMatrix_Check(y), #if PY_MAJOR_VERSION >= 3 partial ? PyLong_AS_LONG(partial) : 0, &z)) #else partial ? PyInt_AS_LONG(partial) : 0, &z)) #endif return PyErr_NoMemory(); if (z) { free_ccs( ((spmatrix *)y)->obj ); ((spmatrix *)y)->obj = z; } } return Py_BuildValue(""); } static char doc_gemm[] = "General matrix-matrix product.\n\n" "gemm(A, B, C, transA='N', transB='N', alpha=1.0, beta=0.0, \n" " partial=False) \n\n" "PURPOSE\n" "Computes \n" "C := alpha*A*B + beta*C if transA = 'N' and transB = 'N'.\n" "C := alpha*A^T*B + beta*C if transA = 'T' and transB = 'N'.\n" "C := alpha*A^H*B + beta*C if transA = 'C' and transB = 'N'.\n" "C := alpha*A*B^T + beta*C if transA = 'N' and transB = 'T'.\n" "C := alpha*A^T*B^T + beta*C if transA = 'T' and transB = 'T'.\n" "C := alpha*A^H*B^T + beta*C if transA = 'C' and transB = 'T'.\n" "C := alpha*A*B^H + beta*C if transA = 'N' and transB = 'C'.\n" "C := alpha*A^T*B^H + beta*C if transA = 'T' and transB = 'C'.\n" "C := alpha*A^H*B^H + beta*C if transA = 'C' and transB = 'C'.\n" "If k=0, this reduces to C := beta*C.\n\n" "ARGUMENTS\n\n" "A 'd' or 'z' matrix\n\n" "B 'd' or 'z' matrix. Must have the same type as A.\n\n" "C 'd' or 'z' matrix. Must have the same type as A.\n\n" "transA 'N', 'T' or 'C'\n\n" "transB 'N', 'T' or 'C'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "partial boolean. If C is sparse and partial is True, then only the\n" " nonzero elements of C are updated irrespective of the\n" " sparsity patterns of A and B."; PyObject* base_gemm(PyObject *self, PyObject *args, PyObject *kwrds) { PyObject *A, *B, *C, *partial=NULL; PyObject *ao=NULL, *bo=NULL; number a, b; int m, n, k; #if PY_MAJOR_VERSION >= 3 int transA='N', transB='N'; char transA_, transB_; #else char transA='N', transB='N'; #endif char *kwlist[] = {"A", "B", "C", "transA", "transB", "alpha", "beta", "partial", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|CCOOO:gemm", kwlist, &A, &B, &C, &transA, &transB, &ao, &bo, &partial)) #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ccOOO:gemm", kwlist, &A, &B, &C, &transA, &transB, &ao, &bo, &partial)) #endif return NULL; if (!(Matrix_Check(A) || SpMatrix_Check(A))) PY_ERR_TYPE("A must a matrix or spmatrix"); if (!(Matrix_Check(B) || SpMatrix_Check(B))) PY_ERR_TYPE("B must a matrix or spmatrix"); if (!(Matrix_Check(C) || SpMatrix_Check(C))) PY_ERR_TYPE("C must a matrix or spmatrix"); if (partial && !PyBool_Check(partial)) err_bool("partial"); if (X_ID(A) != X_ID(B) || X_ID(A) != X_ID(C) || X_ID(B) != X_ID(C)) err_conflicting_ids; if (transA != 'N' && transA != 'T' && transA != 'C') err_char("transA", "'N', 'T', 'C'"); if (transB != 'N' && transB != 'T' && transB != 'C') err_char("transB", "'N', 'T', 'C'"); m = (transA == 'N') ? X_NROWS(A) : X_NCOLS(A); n = (transB == 'N') ? X_NCOLS(B) : X_NROWS(B); k = (transA == 'N') ? X_NCOLS(A) : X_NROWS(A); if (k != ((transB == 'N') ? X_NROWS(B) : X_NCOLS(B))) PY_ERR_TYPE("dimensions of A and B do not match"); if (m == 0 || n == 0) return Py_BuildValue(""); if (ao && convert_num[X_ID(A)](&a, ao, 1, 0)) err_type("alpha"); if (bo && convert_num[X_ID(A)](&b, bo, 1, 0)) err_type("beta"); #if PY_MAJOR_VERSION >= 3 transA_ = transA; transB_ = transB; #endif int id = X_ID(A); if (Matrix_Check(A) && Matrix_Check(B) && Matrix_Check(C)) { int ldA = MAX(1,MAT_NROWS(A)); int ldB = MAX(1,MAT_NROWS(B)); int ldC = MAX(1,MAT_NROWS(C)); if (id == INT) err_invalid_id; #if PY_MAJOR_VERSION >= 3 gemm[id](&transA_, &transB_, &m, &n, &k, (ao ? &a : &One[id]), MAT_BUF(A), &ldA, MAT_BUF(B), &ldB, (bo ? &b : &Zero[id]), MAT_BUF(C), &ldC); #else gemm[id](&transA, &transB, &m, &n, &k, (ao ? &a : &One[id]), MAT_BUF(A), &ldA, MAT_BUF(B), &ldB, (bo ? &b : &Zero[id]), MAT_BUF(C), &ldC); #endif } else { void *z = NULL; #if PY_MAJOR_VERSION >= 3 if (sp_gemm[id](transA_, transB_, (ao ? a : One[id]), Matrix_Check(A) ? MAT_BUF(A) : ((spmatrix *)A)->obj, Matrix_Check(B) ? MAT_BUF(B) : ((spmatrix *)B)->obj, (bo ? b : Zero[id]), Matrix_Check(C) ? MAT_BUF(C) : ((spmatrix *)C)->obj, SpMatrix_Check(A), SpMatrix_Check(B), SpMatrix_Check(C), partial ? PyLong_AS_LONG(partial) : 0, &z, m, n, k)) return PyErr_NoMemory(); #else if (sp_gemm[id](transA, transB, (ao ? a : One[id]), Matrix_Check(A) ? MAT_BUF(A) : ((spmatrix *)A)->obj, Matrix_Check(B) ? MAT_BUF(B) : ((spmatrix *)B)->obj, (bo ? b : Zero[id]), Matrix_Check(C) ? MAT_BUF(C) : ((spmatrix *)C)->obj, SpMatrix_Check(A), SpMatrix_Check(B), SpMatrix_Check(C), partial ? PyInt_AS_LONG(partial) : 0, &z, m, n, k)) return PyErr_NoMemory(); #endif if (z) { free_ccs( ((spmatrix *)C)->obj ); ((spmatrix *)C)->obj = z; } } return Py_BuildValue(""); } static char doc_gemv[] = "General matrix-vector product for sparse and dense matrices. \n\n" "gemv(A, x, y, trans='N', alpha=1.0, beta=0.0, m=A.size[0],\n" " n=A.size[1], incx=1, incy=1, offsetA=0, offsetx=0, offsety=0)\n\n" "PURPOSE\n" "If trans is 'N', computes y := alpha*A*x + beta*y.\n" "If trans is 'T', computes y := alpha*A^T*x + beta*y.\n" "If trans is 'C', computes y := alpha*A^H*x + beta*y.\n" "The matrix A is m by n.\n" "Returns immediately if n=0 and trans is 'T' or 'C', or if m=0 \n" "and trans is 'N'.\n" "Computes y := beta*y if n=0, m>0 and trans is 'N', or if m=0, \n" "n>0 and trans is 'T' or 'C'.\n\n" "ARGUMENTS\n" "A 'd' or 'z' (sp)matrix\n\n" "x 'd' or 'z' matrix. Must have the same type as A.\n\n" "y 'd' or 'z' matrix. Must have the same type as A.\n\n" "trans 'N', 'T' or 'C'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "m integer. If negative, the default value is used.\n\n" "n integer. If negative, the default value is used.\n\n" " If zero, the default value is used.\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "This sparse version of GEMV requires that\n" " m <= A.size[0] - (offsetA % A.size[0])"; static PyObject* base_gemv(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *x, *y; PyObject *A; PyObject *ao=NULL, *bo=NULL; number a, b; int m=-1, n=-1, ix=1, iy=1, oA=0, ox=0, oy=0; #if PY_MAJOR_VERSION >= 3 int trans='N'; char trans_; #else char trans='N'; #endif char *kwlist[] = {"A", "x", "y", "trans", "alpha", "beta", "m", "n", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COOiiiiiii:gemv", kwlist, &A, &x, &y, &trans, &ao, &bo, &m, &n, &ix, &iy, &oA, &ox, &oy)) return NULL; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiiii:gemv", kwlist, &A, &x, &y, &trans, &ao, &bo, &m, &n, &ix, &iy, &oA, &ox, &oy)) return NULL; #endif if (!Matrix_Check(A) && !SpMatrix_Check(A)) PY_ERR(PyExc_TypeError, "A must be a dense or sparse matrix"); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (MAT_ID(x) == INT || MAT_ID(y) == INT || X_ID(A) == INT) PY_ERR_TYPE("invalid matrix types"); if (X_ID(A) != MAT_ID(x) || X_ID(A) != MAT_ID(y)) err_conflicting_ids; if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N','T','C'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); int id = MAT_ID(x); if (m < 0) m = X_NROWS(A); if (n < 0) n = X_NCOLS(A); if ((!m && trans == 'N') || (!n && (trans == 'T' || trans == 'C'))) return Py_BuildValue(""); if (oA < 0) err_nn_int("offsetA"); if (n > 0 && m > 0 && oA + (n-1)*MAX(1,X_NROWS(A)) + m > X_NROWS(A)*X_NCOLS(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if ((trans == 'N' && n > 0 && ox + (n-1)*abs(ix) + 1 > MAT_LGT(x)) || ((trans == 'T' || trans == 'C') && m > 0 && ox + (m-1)*abs(ix) + 1 > MAT_LGT(x))) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if ((trans == 'N' && oy + (m-1)*abs(iy) + 1 > MAT_LGT(y)) || ((trans == 'T' || trans == 'C') && oy + (n-1)*abs(iy) + 1 > MAT_LGT(y))) err_buf_len("y"); if (ao && convert_num[MAT_ID(x)](&a, ao, 1, 0)) err_type("alpha"); if (bo && convert_num[MAT_ID(x)](&b, bo, 1, 0)) err_type("beta"); #if PY_MAJOR_VERSION >= 3 trans_ = trans; #endif if (Matrix_Check(A)) { int ldA = MAX(1,X_NROWS(A)); if (trans == 'N' && n == 0) scal[id](&m, (bo ? &b : &Zero[id]), MAT_BUF(y)+oy*E_SIZE[id], &iy); else if ((trans == 'T' || trans == 'C') && m == 0) scal[id](&n, (bo ? &b : &Zero[id]), MAT_BUF(y)+oy*E_SIZE[id], &iy); else #if PY_MAJOR_VERSION >= 3 gemv[id](&trans_, &m, &n, (ao ? &a : &One[id]), MAT_BUF(A) + oA*E_SIZE[id], &ldA, MAT_BUF(x) + ox*E_SIZE[id], &ix, (bo ? &b : &Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], &iy); #else gemv[id](&trans, &m, &n, (ao ? &a : &One[id]), MAT_BUF(A) + oA*E_SIZE[id], &ldA, MAT_BUF(x) + ox*E_SIZE[id], &ix, (bo ? &b : &Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], &iy); #endif } else { #if PY_MAJOR_VERSION >= 3 if (sp_gemv[id](trans_, m, n, (ao ? a : One[id]), ((spmatrix *)A)->obj, oA, MAT_BUF(x) + ox*E_SIZE[id], ix, (bo ? b : Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], iy)) return PyErr_NoMemory(); #else if (sp_gemv[id](trans, m, n, (ao ? a : One[id]), ((spmatrix *)A)->obj, oA, MAT_BUF(x) + ox*E_SIZE[id], ix, (bo ? b : Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], iy)) return PyErr_NoMemory(); #endif } return Py_BuildValue(""); } static char doc_syrk[] = "Rank-k update of symmetric sparse or dense matrix.\n\n" "syrk(A, C, uplo='L', trans='N', alpha=1.0, beta=0.0, partial=False)\n\n" "PURPOSE \n" "If trans is 'N', computes C := alpha*A*A^T + beta*C.\n" "If trans is 'T', computes C := alpha*A^T*A + beta*C.\n" "C is symmetric (real or complex) of order n. \n" "ARGUMENTS\n" "A 'd' or 'z' (sp)matrix\n\n" "C 'd' or 'z' (sp)matrix. Must have the same type as A.\n\n" "uplo 'L' or 'U'\n\n" "trans 'N' or 'T'\n\n" "alpha number (int, float or complex). Complex alpha is only\n" " allowed if A is complex.\n\n" "beta number (int, float or complex). Complex beta is only\n" " allowed if A is complex.\n\n" "partial boolean. If C is sparse and partial is True, then only the\n" " nonzero elements of C are updated irrespective of the\n" " sparsity patterns of A."; static PyObject* base_syrk(PyObject *self, PyObject *args, PyObject *kwrds) { PyObject *A, *C, *partial=NULL, *ao=NULL, *bo=NULL; number a, b; #if PY_MAJOR_VERSION >= 3 int trans='N', uplo='L'; char trans_, uplo_; #else char trans='N', uplo='L'; #endif char *kwlist[] = {"A", "C", "uplo", "trans", "alpha", "beta", "partial", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|CCOOO:syrk", kwlist, &A, &C, &uplo, &trans, &ao, &bo, &partial)) #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ccOOO:syrk", kwlist, &A, &C, &uplo, &trans, &ao, &bo, &partial)) #endif return NULL; if (!(Matrix_Check(A) || SpMatrix_Check(A))) PY_ERR_TYPE("A must be a dense or sparse matrix"); if (!(Matrix_Check(C) || SpMatrix_Check(C))) PY_ERR_TYPE("C must be a dense or sparse matrix"); int id = X_ID(A); if (id == INT) PY_ERR_TYPE("invalid matrix types"); if (id != X_ID(C)) err_conflicting_ids; if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (id == DOUBLE && trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (id == COMPLEX && trans != 'N' && trans != 'T') err_char("trans", "'N', 'T'"); if (partial && !PyBool_Check(partial)) err_bool("partial"); int n = (trans == 'N') ? X_NROWS(A) : X_NCOLS(A); int k = (trans == 'N') ? X_NCOLS(A) : X_NROWS(A); if (n == 0) return Py_BuildValue(""); if (ao && convert_num[id](&a, ao, 1, 0)) err_type("alpha"); if (bo && convert_num[id](&b, bo, 1, 0)) err_type("beta"); #if PY_MAJOR_VERSION >= 3 trans_ = trans; uplo_ = uplo; #endif if (Matrix_Check(A) && Matrix_Check(C)) { int ldA = MAX(1,MAT_NROWS(A)); int ldC = MAX(1,MAT_NROWS(C)); #if PY_MAJOR_VERSION >= 3 syrk[id](&uplo_, &trans_, &n, &k, (ao ? &a : &One[id]), MAT_BUF(A), &ldA, (bo ? &b : &Zero[id]), MAT_BUF(C), &ldC); #else syrk[id](&uplo, &trans, &n, &k, (ao ? &a : &One[id]), MAT_BUF(A), &ldA, (bo ? &b : &Zero[id]), MAT_BUF(C), &ldC); #endif } else { void *z = NULL; #if PY_MAJOR_VERSION >= 3 if (sp_syrk[id](uplo_, trans_, (ao ? a : One[id]), Matrix_Check(A) ? MAT_BUF(A) : ((spmatrix *)A)->obj, (bo ? b : Zero[id]), Matrix_Check(C) ? MAT_BUF(C) : ((spmatrix *)C)->obj, SpMatrix_Check(A), SpMatrix_Check(C), partial ? PyLong_AS_LONG(partial) : 0, (trans == 'N' ? X_NCOLS(A) : X_NROWS(A)), &z)) #else if (sp_syrk[id](uplo, trans, (ao ? a : One[id]), Matrix_Check(A) ? MAT_BUF(A) : ((spmatrix *)A)->obj, (bo ? b : Zero[id]), Matrix_Check(C) ? MAT_BUF(C) : ((spmatrix *)C)->obj, SpMatrix_Check(A), SpMatrix_Check(C), partial ? PyInt_AS_LONG(partial) : 0, (trans == 'N' ? X_NCOLS(A) : X_NROWS(A)), &z)) #endif return PyErr_NoMemory(); if (z) { free_ccs( ((spmatrix *)C)->obj ); ((spmatrix *)C)->obj = z; } } return Py_BuildValue(""); } static char doc_symv[] = "Matrix-vector product with a real symmetric dense or sparse matrix.\n\n" "symv(A, x, y, uplo='L', alpha=1.0, beta=0.0, n=A.size[0], \n" " ldA=max(1,A.size[0]), incx=1, incy=1, offsetA=0, offsetx=0,\n" " offsety=0)\n\n" "PURPOSE\n" "Computes y := alpha*A*x + beta*y with A real symmetric of order n." "n\n" "ARGUMENTS\n" "A 'd' (sp)matrix\n\n" "x 'd' matrix\n\n" "y 'd' matrix\n\n" "uplo 'L' or 'U'\n\n" "alpha real number (int or float)\n\n" "beta real number (int or float)\n\n" "n integer. If negative, the default value is used.\n" " If the default value is used, we require that\n" " A.size[0]=A.size[1].\n\n" "incx nonzero integer\n\n" "incy nonzero integer\n\n" "offsetA nonnegative integer\n\n" "offsetx nonnegative integer\n\n" "offsety nonnegative integer\n\n" "This sparse version of SYMV requires that\n" " m <= A.size[0] - (offsetA % A.size[0])"; static PyObject* base_symv(PyObject *self, PyObject *args, PyObject *kwrds) { PyObject *A, *ao=NULL, *bo=NULL; matrix *x, *y; number a, b; int n=-1, ix=1, iy=1, oA=0, ox=0, oy=0, ldA; #if PY_MAJOR_VERSION >= 3 int uplo='L'; char uplo_; #else char uplo='L'; #endif char *kwlist[] = {"A", "x", "y", "uplo", "alpha", "beta", "n", "incx", "incy", "offsetA", "offsetx", "offsety", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|COOiiiiii:symv", kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &ix, &iy, &oA, &ox, &oy)) #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|cOOiiiiii:symv", kwlist, &A, &x, &y, &uplo, &ao, &bo, &n, &ix, &iy, &oA, &ox, &oy)) #endif return NULL; if (!Matrix_Check(A) && !SpMatrix_Check(A)) PY_ERR_TYPE("A must be a dense or sparse matrix"); ldA = MAX(1,X_NROWS(A)); if (!Matrix_Check(x)) err_mtrx("x"); if (!Matrix_Check(y)) err_mtrx("y"); if (X_ID(A) != MAT_ID(x) || X_ID(A) != MAT_ID(y) || MAT_ID(x) != MAT_ID(y)) err_conflicting_ids; int id = X_ID(A); if (id == INT) PY_ERR_TYPE("invalid matrix types"); if (uplo != 'L' && uplo != 'U') err_char("uplo", "'L', 'U'"); if (ix == 0) err_nz_int("incx"); if (iy == 0) err_nz_int("incy"); if (n < 0) { if (X_NROWS(A) != X_NCOLS(A)) { PyErr_SetString(PyExc_ValueError, "A is not square"); return NULL; } n = X_NROWS(A); } if (n == 0) return Py_BuildValue(""); if (oA < 0) err_nn_int("offsetA"); if (oA + (n-1)*ldA + n > len(A)) err_buf_len("A"); if (ox < 0) err_nn_int("offsetx"); if (ox + (n-1)*abs(ix) + 1 > len(x)) err_buf_len("x"); if (oy < 0) err_nn_int("offsety"); if (oy + (n-1)*abs(iy) + 1 > len(y)) err_buf_len("y"); if (ao && convert_num[id](&a, ao, 1, 0)) err_type("alpha"); if (bo && convert_num[id](&b, bo, 1, 0)) err_type("beta"); #if PY_MAJOR_VERSION >= 3 uplo_ = uplo; #endif if (Matrix_Check(A)) { #if PY_MAJOR_VERSION >= 3 symv[id](&uplo_, &n, (ao ? &a : &One[id]), MAT_BUF(A) + oA*E_SIZE[id], &ldA, MAT_BUF(x) + ox*E_SIZE[id], &ix, (bo ? &b : &Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], &iy); #else symv[id](&uplo, &n, (ao ? &a : &One[id]), MAT_BUF(A) + oA*E_SIZE[id], &ldA, MAT_BUF(x) + ox*E_SIZE[id], &ix, (bo ? &b : &Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], &iy); #endif } else { #if PY_MAJOR_VERSION >= 3 if (sp_symv[id](uplo_, n, (ao ? a : One[id]), ((spmatrix *)A)->obj, oA, MAT_BUF(x) + ox*E_SIZE[id], ix, (bo ? b : Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], iy)) #else if (sp_symv[id](uplo, n, (ao ? a : One[id]), ((spmatrix *)A)->obj, oA, MAT_BUF(x) + ox*E_SIZE[id], ix, (bo ? b : Zero[id]), MAT_BUF(y) + oy*E_SIZE[id], iy)) #endif return PyErr_NoMemory(); } return Py_BuildValue(""); } spmatrix * sparse_concat(PyObject *L, int id_arg) ; static char doc_sparse[] = "Constructs a sparse block matrix.\n\n" "sparse(x, tc = None)\n\n" "PURPOSE\n" "Constructs a sparse block matrix from a list of block matrices. If a\n" "single matrix is given as argument, then the matrix is converted to\n" "sparse format, optionally with a different typcode. If a single list\n" "of subblocks is specified, then a block column matrix is created;\n" "otherwise when a list of lists is specified, then the inner lists\n" "specify the different block-columns. Each block element must be either\n" "a dense or sparse matrix, or a scalar, and dense matrices are converted\n" "to sparse format by removing 0 elements.\n\n" "ARGUMENTS\n" "x a single matrix, or a list of matrices and scalars, or a list of\n" " lists of matrices and scalars\n\n" "tc typecode character 'd' or 'z'."; static PyObject * sparse(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *Objx = NULL; static char *kwlist[] = { "x", "tc", NULL}; char tc = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|c:sparse", kwlist, &Objx, &tc)) return NULL; if (tc && !(VALID_TC_SP(tc))) PY_ERR_TYPE("tc must be 'd' or 'z'"); int id = (tc ? TC2ID(tc) : -1); spmatrix *ret = NULL; /* a matrix */ if (Matrix_Check(Objx)) { int m = MAT_NROWS(Objx), n = MAT_NCOLS(Objx); ret = SpMatrix_NewFromMatrix((matrix *)Objx, (id == -1 ? MAX(DOUBLE,MAT_ID(Objx)) : id)); MAT_NROWS(Objx) = m; MAT_NCOLS(Objx) = n; } /* sparse matrix */ else if (SpMatrix_Check(Objx)) { int nnz=0, ik, jk; for (jk=0; jk 1); int freeB = SpMatrix_Check(B) && (SP_LGT(B) > 1); if (freeA) { if (!(A = (PyObject *)dense((spmatrix *)A)) ) return PyErr_NoMemory(); } if (freeB) { if (!(B = (PyObject *)dense((spmatrix *)B)) ) return PyErr_NoMemory(); } PyObject *ret = (PyObject *)Matrix_New(m, n, id); if (!ret) { if (freeA) { Py_DECREF(A); } if (freeB) { Py_DECREF(B); } return PyErr_NoMemory(); } int_t i; for (i=0; i 0.0) SP_COL(ret)[j+1]++; } else if (SP_ROW(A)[ka] > SP_ROW(B)[kb]) { if (SP_VALD(B)[kb++] > 0.0) SP_COL(ret)[j+1]++; } else { SP_COL(ret)[j+1]++; ka++; kb++; } } while (ka < SP_COL(A)[j+1]) { if (SP_VALD(A)[ka++] > 0.0) SP_COL(ret)[j+1]++; } while (kb < SP_COL(B)[j+1]) { if (SP_VALD(B)[kb++] > 0.0) SP_COL(ret)[j+1]++; } } for (j=0; jobj->rowind ); free( ret->obj->values ); ret->obj->rowind = newrow; ret->obj->values = newval; ka = 0; kb = 0; for (j=0; j 0.0) { SP_ROW(ret)[kret] = SP_ROW(A)[ka]; SP_VALD(ret)[kret++] = SP_VALD(A)[ka]; } ka++; } else if (SP_ROW(A)[ka] > SP_ROW(B)[kb]) { if (SP_VALD(B)[kb] > 0.0) { SP_ROW(ret)[kret] = SP_ROW(B)[kb]; SP_VALD(ret)[kret++] = SP_VALD(B)[kb]; } kb++; } else { SP_ROW(ret)[kret] = SP_ROW(A)[ka]; SP_VALD(ret)[kret] = MAX(SP_VALD(A)[ka], SP_VALD(B)[kb]); kret++; ka++; kb++; } } while (ka < SP_COL(A)[j+1]) { if (SP_VALD(A)[ka] > 0.0) { SP_ROW(ret)[kret] = SP_ROW(A)[ka]; SP_VALD(ret)[kret++] = SP_VALD(A)[ka]; } ka++; } while (kb < SP_COL(B)[j+1]) { if (SP_VALD(B)[kb] > 0.0) { SP_ROW(ret)[kret] = SP_ROW(B)[kb]; SP_VALD(ret)[kret++] = SP_VALD(B)[kb]; } kb++; } } return (PyObject *)ret; } } PyObject * matrix_elem_min(PyObject *self, PyObject *args, PyObject *kwrds) { PyObject *A, *B; if (!PyArg_ParseTuple(args, "OO:emin", &A, &B)) return NULL; if (!(X_Matrix_Check(A) || PyNumber_Check(A)) || !(X_Matrix_Check(B) || PyNumber_Check(B))) PY_ERR_TYPE("arguments must be either matrices or python numbers"); if (PyComplex_Check(A) || (X_Matrix_Check(A) && X_ID(A)==COMPLEX)) PY_ERR_TYPE("ordering not defined for complex numbers"); if (PyComplex_Check(B) || (X_Matrix_Check(B) && X_ID(B)==COMPLEX)) PY_ERR_TYPE("ordering not defined for complex numbers"); int a_is_number = PyNumber_Check(A) || (Matrix_Check(A) && MAT_LGT(A) == 1) || (SpMatrix_Check(A) && SP_LGT(A) == 1); int b_is_number = PyNumber_Check(B) || (Matrix_Check(B) && MAT_LGT(B) == 1) || (SpMatrix_Check(B) && SP_LGT(B) == 1); int ida = PyNumber_Check(A) ? PyFloat_Check(A) : X_ID(A); int idb = PyNumber_Check(B) ? PyFloat_Check(B) : X_ID(B); int id = MAX( ida, idb ); number a, b; if (a_is_number) { if (PyNumber_Check(A) || Matrix_Check(A)) convert_num[id](&a, A, PyNumber_Check(A), 0); else a.d = (SP_LGT(A) ? SP_VALD(A)[0] : 0.0); } if (b_is_number) { if (PyNumber_Check(B) || Matrix_Check(B)) convert_num[id](&b, B, PyNumber_Check(B), 0); else b.d = (SP_LGT(B) ? SP_VALD(B)[0] : 0.0); } if ((a_is_number && b_is_number) && (!X_Matrix_Check(A) && !X_Matrix_Check(B))) { if (id == INT) return Py_BuildValue("i", MIN(a.i, b.i) ); else return Py_BuildValue("d", MIN(a.d, b.d) ); } if (!(a_is_number || b_is_number)) { if (X_NROWS(A) != X_NROWS(B) || X_NCOLS(A) != X_NCOLS(B)) PY_ERR_TYPE("incompatible dimensions"); } int_t m = ( !a_is_number ? X_NROWS(A) : (!b_is_number ? X_NROWS(B) : 1)); int_t n = ( !a_is_number ? X_NCOLS(A) : (!b_is_number ? X_NCOLS(B) : 1)); if ((Matrix_Check(A) || a_is_number) || (Matrix_Check(B) || b_is_number)) { int freeA = SpMatrix_Check(A) && (SP_LGT(A) > 1); int freeB = SpMatrix_Check(B) && (SP_LGT(B) > 1); if (freeA) { if (!(A = (PyObject *)dense((spmatrix *)A)) ) return PyErr_NoMemory(); } if (freeB) { if (!(B = (PyObject *)dense((spmatrix *)B)) ) return PyErr_NoMemory(); } PyObject *ret = (PyObject *)Matrix_New(m, n, id); if (!ret) { if (freeA) { Py_DECREF(A); } if (freeB) { Py_DECREF(B); } return PyErr_NoMemory(); } int_t i; for (i=0; i SP_ROW(B)[kb]) { if (SP_VALD(B)[kb++] < 0.0) SP_COL(ret)[j+1]++; } else { SP_COL(ret)[j+1]++; ka++; kb++; } } while (ka < SP_COL(A)[j+1]) { if (SP_VALD(A)[ka++] < 0.0) SP_COL(ret)[j+1]++; } while (kb < SP_COL(B)[j+1]) { if (SP_VALD(B)[kb++] < 0.0) SP_COL(ret)[j+1]++; } } for (j=0; jobj->rowind ); free( ret->obj->values ); ret->obj->rowind = newrow; ret->obj->values = newval; ka = 0; kb = 0; for (j=0; j SP_ROW(B)[kb]) { if (SP_VALD(B)[kb] < 0.0) { SP_ROW(ret)[kret] = SP_ROW(B)[kb]; SP_VALD(ret)[kret++] = SP_VALD(B)[kb]; } kb++; } else { SP_ROW(ret)[kret] = SP_ROW(A)[ka]; SP_VALD(ret)[kret] = MIN(SP_VALD(A)[ka], SP_VALD(B)[kb]); kret++; ka++; kb++; } } while (ka < SP_COL(A)[j+1]) { if (SP_VALD(A)[ka] < 0.0) { SP_ROW(ret)[kret] = SP_ROW(A)[ka]; SP_VALD(ret)[kret++] = SP_VALD(A)[ka]; } ka++; } while (kb < SP_COL(B)[j+1]) { if (SP_VALD(B)[kb] < 0.0) { SP_ROW(ret)[kret] = SP_ROW(B)[kb]; SP_VALD(ret)[kret++] = SP_VALD(B)[kb]; } kb++; } } return (PyObject *)ret; } } PyObject * matrix_elem_mul(matrix *self, PyObject *args, PyObject *kwrds) { PyObject *A, *B; if (!PyArg_ParseTuple(args, "OO:emul", &A, &B)) return NULL; if (!(X_Matrix_Check(A) || PyNumber_Check(A)) || !(X_Matrix_Check(B) || PyNumber_Check(B))) PY_ERR_TYPE("arguments must be either matrices or python numbers"); int a_is_number = PyNumber_Check(A) || (Matrix_Check(A) && MAT_LGT(A) == 1); int b_is_number = PyNumber_Check(B) || (Matrix_Check(B) && MAT_LGT(B) == 1); int ida, idb; #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(A)) { ida = INT; } #else if (PyInt_Check(A)) { ida = INT; } #endif else if (PyFloat_Check(A)) { ida = DOUBLE; } else if (PyComplex_Check(A)) { ida = COMPLEX; } else { ida = X_ID(A); } #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(B)) { idb = INT; } #else if (PyInt_Check(B)) { idb = INT; } #endif else if (PyFloat_Check(B)) { idb = DOUBLE; } else if (PyComplex_Check(B)) { idb = COMPLEX; } else { idb = X_ID(B); } int id = MAX( ida, idb ); number a, b; if (a_is_number) convert_num[id](&a, A, PyNumber_Check(A), 0); if (b_is_number) convert_num[id](&b, B, PyNumber_Check(B), 0); if (a_is_number && b_is_number && (!X_Matrix_Check(A) && !X_Matrix_Check(B))) { if (!X_Matrix_Check(A) && !X_Matrix_Check(B)) { if (id == INT) return Py_BuildValue("i", a.i*b.i ); else if (id == DOUBLE) return Py_BuildValue("d", a.d*b.d ); else { number c; c.z = a.z*b.z; return znum2PyObject(&c, 0); } } } if (!(a_is_number || b_is_number)) { if (X_NROWS(A) != X_NROWS(B) || X_NCOLS(A) != X_NCOLS(B)) PY_ERR_TYPE("incompatible dimensions"); } int_t m = ( !a_is_number ? X_NROWS(A) : (!b_is_number ? X_NROWS(B) : 1)); int_t n = ( !a_is_number ? X_NCOLS(A) : (!b_is_number ? X_NCOLS(B) : 1)); if ((Matrix_Check(A) || a_is_number) && (Matrix_Check(B) || b_is_number)) { PyObject *ret = (PyObject *)Matrix_New(m, n, id); if (!ret) return PyErr_NoMemory(); int_t i; for (i=0; i SP_ROW(B)[kb]) { kb++; } else { SP_COL(ret)[j+1]++; ka++; kb++; } } ka = SP_COL(A)[j+1]; kb = SP_COL(B)[j+1]; } for (j=0; jobj->rowind ); free( ret->obj->values ); ret->obj->rowind = newrow; ret->obj->values = newval; ka = 0; kb = 0; for (j=0; j SP_ROW(B)[kb]) { kb++; } else { SP_ROW(ret)[kret] = SP_ROW(A)[ka]; if (id == DOUBLE) SP_VALD(ret)[kret] = SP_VALD(A)[ka]*SP_VALD(B)[kb]; else SP_VALZ(ret)[kret] = (X_ID(A) == DOUBLE ? SP_VALD(A)[ka] : SP_VALZ(A)[ka])* (X_ID(B) == DOUBLE ? SP_VALD(B)[kb] : SP_VALZ(B)[kb]); kret++; ka++; kb++; } } ka = SP_COL(A)[j+1]; kb = SP_COL(B)[j+1]; } return (PyObject *)ret; } } PyObject * matrix_elem_div(matrix *self, PyObject *args, PyObject *kwrds) { PyObject *A, *B, *ret; if (!PyArg_ParseTuple(args, "OO:ediv", &A, &B)) return NULL; if (!(X_Matrix_Check(A) || PyNumber_Check(A)) || !(X_Matrix_Check(B) || PyNumber_Check(B))) PY_ERR_TYPE("arguments must be either matrices or python numbers"); if (SpMatrix_Check(B)) PY_ERR_TYPE("elementwise division with sparse matrix\n"); int a_is_number = PyNumber_Check(A) || (Matrix_Check(A) && MAT_LGT(A) == 1); int b_is_number = PyNumber_Check(B) || (Matrix_Check(B) && MAT_LGT(B) == 1); int ida, idb; #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(A)) { ida = INT; } #else if (PyInt_Check(A)) { ida = INT; } #endif else if (PyFloat_Check(A)) { ida = DOUBLE; } else if (PyComplex_Check(A)) { ida = COMPLEX; } else { ida = X_ID(A); } #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(B)) { idb = INT; } #else if (PyInt_Check(B)) { idb = INT; } #endif else if (PyFloat_Check(B)) { idb = DOUBLE; } else if (PyComplex_Check(B)) { idb = COMPLEX; } else { idb = X_ID(B); } #if PY_MAJOR_VERSION >= 3 int id = MAX( DOUBLE, MAX( ida, idb ) ) ; #else int id = MAX( ida, idb ); #endif number a, b; if (a_is_number) convert_num[id](&a, A, PyNumber_Check(A), 0); if (b_is_number) convert_num[id](&b, B, PyNumber_Check(B), 0); if ((a_is_number && b_is_number) && (!X_Matrix_Check(A) && !Matrix_Check(B))) { if (id == INT) { if (b.i == 0) PY_ERR(PyExc_ArithmeticError, "division by zero"); return Py_BuildValue("i", a.i/b.i ); } else if (id == DOUBLE) { if (b.d == 0.0) PY_ERR(PyExc_ArithmeticError, "division by zero"); return Py_BuildValue("d", a.d/b.d ); } else { if (b.z == 0.0) PY_ERR(PyExc_ArithmeticError, "division by zero"); number c; c.z = a.z/b.z; return znum2PyObject(&c, 0); } } if (!(a_is_number || b_is_number)) { if (X_NROWS(A) != MAT_NROWS(B) || X_NCOLS(A) != MAT_NCOLS(B)) PY_ERR_TYPE("incompatible dimensions"); } int m = ( !a_is_number ? X_NROWS(A) : (!b_is_number ? X_NROWS(B) : 1)); int n = ( !a_is_number ? X_NCOLS(A) : (!b_is_number ? X_NCOLS(B) : 1)); if ((Matrix_Check(A) || a_is_number) && (Matrix_Check(B) || b_is_number)) { if (!(ret = (PyObject *)Matrix_New(m, n, id))) return PyErr_NoMemory(); int i; for (i=0; i= 3 static PyModuleDef base_module = { PyModuleDef_HEAD_INIT, "base", base__doc__, -1, base_functions, NULL, NULL, NULL, NULL }; #define INITERROR return NULL PyMODINIT_FUNC PyInit_base(void) #else #define INITERROR return PyMODINIT_FUNC initbase(void) #endif { static void *base_API[8]; PyObject *base_mod, *c_api_object; #if PY_MAJOR_VERSION >= 3 base_mod = PyModule_Create(&base_module); if (base_mod == NULL) #else if (!(base_mod = Py_InitModule3("base", base_functions, base__doc__))) #endif INITERROR; /* for MS VC++ compatibility */ matrix_tp.tp_alloc = PyType_GenericAlloc; matrix_tp.tp_free = PyObject_Del; if (PyType_Ready(&matrix_tp) < 0) INITERROR; if (PyType_Ready(&matrix_tp) < 0) INITERROR; Py_INCREF(&matrix_tp); if (PyModule_AddObject(base_mod, "matrix", (PyObject *) &matrix_tp) < 0) INITERROR; spmatrix_tp.tp_alloc = PyType_GenericAlloc; spmatrix_tp.tp_free = PyObject_Del; if (PyType_Ready(&spmatrix_tp) < 0) INITERROR; Py_INCREF(&spmatrix_tp); if (PyModule_AddObject(base_mod, "spmatrix", (PyObject *) &spmatrix_tp) < 0) INITERROR; One[INT].i = 1; One[DOUBLE].d = 1.0; One[COMPLEX].z = 1.0; MinusOne[INT].i = -1; MinusOne[DOUBLE].d = -1.0; MinusOne[COMPLEX].z = -1.0; Zero[INT].i = 0; Zero[DOUBLE].d = 0.0; Zero[COMPLEX].z = 0.0; /* initialize the C API object */ base_API[0] = (void *)Matrix_New; base_API[1] = (void *)Matrix_NewFromMatrix; base_API[2] = (void *)Matrix_NewFromSequence; base_API[3] = (void *)Matrix_Check_func; base_API[4] = (void *)SpMatrix_New; base_API[5] = (void *)SpMatrix_NewFromSpMatrix; base_API[6] = (void *)SpMatrix_NewFromIJV; base_API[7] = (void *)SpMatrix_Check_func; #if PY_MAJOR_VERSION >= 3 /* Create a Capsule containing the API pointer array's address */ c_api_object = PyCapsule_New((void *)base_API, "base_API", NULL); #else /* Create a CObject containing the API pointer array's address */ c_api_object = PyCObject_FromVoidPtr((void *)base_API, NULL); #endif if (c_api_object != NULL) PyModule_AddObject(base_mod, "_C_API", c_api_object); #if PY_MAJOR_VERSION >= 3 return base_mod; #endif } cvxopt-1.1.4/src/C/sparse.c0000644000175000017500000035302211674452555014523 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define BASE_MODULE #include "Python.h" #include "cvxopt.h" #include "misc.h" #include #define CONJ(flag, val) (flag == 'C' ? conj(val) : val) extern const int E_SIZE[]; extern const char TC_CHAR[][2]; extern number One[3], MinusOne[3], Zero[3]; extern void (*write_num[])(void *, int, void *, int) ; extern int (*convert_num[])(void *, void *, int, int_t) ; extern PyObject * (*num2PyObject[])(void *, int) ; extern void (*scal[])(int *, number *, void *, int *) ; extern void (*axpy[])(int *, void *, void *, int *, void *, int *) ; extern void (*gemm[])(char *, char *, int *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *) ; extern int (*div_array[])(void *, number, int) ; extern int get_id(void *, int ) ; extern PyTypeObject matrix_tp ; extern matrix * Matrix_NewFromMatrix(matrix *, int) ; extern matrix * Matrix_NewFromSequence(PyObject *, int) ; #if PY_MAJOR_VERSION < 3 extern matrix * Matrix_NewFromArrayStruct(PyObject *, int, int_t *) ; #endif extern matrix * Matrix_NewFromNumber(int_t , int_t , int_t , void *, int ) ; extern matrix * create_indexlist(int, PyObject *) ; extern matrix * Matrix_New(int_t, int_t, int) ; extern matrix * dense(spmatrix *) ; extern PyObject * matrix_add(PyObject *, PyObject *) ; extern PyObject * matrix_sub(PyObject *, PyObject *) ; extern void * convert_mtx_alloc(matrix *, int) ; PyTypeObject spmatrix_tp ; spmatrix * SpMatrix_New(int_t, int_t, int_t, int ) ; extern void (*scal[])(int *, number *, void *, int *) ; extern void (*gemm[])(char *, char *, int *, int *, int *, void *, void *, int *, void *, int *, void *, void *, int *) ; extern void (*syrk[])(char *, char *, int *, int *, void *, void *, int *, void *, void *, int *) ; static int sp_daxpy(number, void *, void *, int, int, int, void **) ; static int sp_zaxpy(number, void *, void *, int, int, int, void **) ; int (*sp_axpy[])(number, void *, void *, int, int, int, void **) = { NULL, sp_daxpy, sp_zaxpy }; static int sp_dgemm(char, char, number, void *, void *, number, void *, int, int, int, int, void **, int, int, int) ; static int sp_zgemm(char, char, number, void *, void *, number, void *, int, int, int, int, void **, int, int, int) ; int (*sp_gemm[])(char, char, number, void *, void *, number, void *, int, int, int, int, void **, int, int, int) = { NULL, sp_dgemm, sp_zgemm }; static int sp_dgemv(char, int, int, number, void *, int, void *, int, number, void *, int) ; static int sp_zgemv(char, int, int, number, void *, int, void *, int, number, void *, int) ; int (*sp_gemv[])(char, int, int, number, void *, int, void *, int, number, void *, int) = { NULL, sp_dgemv, sp_zgemv } ; static int sp_dsymv(char, int, number, ccs *, int, void *, int, number, void *, int) ; static int sp_zsymv(char, int, number, ccs *, int, void *, int, number, void *, int) ; int (*sp_symv[])(char, int, number, ccs *, int, void *, int, number, void *, int) = { NULL, sp_dsymv, sp_zsymv } ; static int sp_dsyrk(char, char, number, void *, number, void *, int, int, int, int, void **) ; int (*sp_syrk[])(char, char, number, void *, number, void *, int, int, int, int, void **) = { NULL, sp_dsyrk, NULL }; typedef struct { int_t key, value; } int_list; static int comp_int(const void *x, const void *y) { if (((int_list *)x)->key == ((int_list *)y)->key) return 0; else return (((int_list *)x)->key > ((int_list *)y)->key ? 1 : -1); } typedef struct { int_t key; double value; } double_list; static int comp_double(const void *x, const void *y) { if (((double_list *)x)->key == ((double_list *)y)->key) return 0; else return (((double_list *)x)->key > ((double_list *)y)->key ? 1 : -1); } typedef struct { int_t key; complex value; } complex_list; static int comp_complex(const void *x, const void *y) { if (((complex_list *)x)->key == ((complex_list *)y)->key) return 0; else return (((complex_list *)x)->key > ((complex_list *)y)->key ? 1 : -1); } #define spmatrix_getitem_i(O,i,v) \ spmatrix_getitem_ij(O,i%SP_NROWS(O),i/SP_NROWS(O),v) #define spmatrix_setitem_i(O,i,v) \ spmatrix_setitem_ij(O,i%SP_NROWS(O),i/SP_NROWS(O),v) #define free_lists_exit(argI,argJ,I,J,ret) { \ if (argI && !Matrix_Check(argI)) { Py_XDECREF(I); } \ if (argJ && !Matrix_Check(argJ)) { Py_XDECREF(J); } \ return ret; } #define INCR_SP_ROW_IDX(O, j, k) { \ while (((ccs *)O)->colptr[j+1] == k+1) j++; \ k++; } int convert_array(void *dest, void *src, int dest_id, int src_id, int n) { if (dest_id != MAX(dest_id,src_id)) return -1; int i; if (dest_id == src_id) memcpy(dest, src, n*E_SIZE[dest_id]); else if (dest_id == DOUBLE) { for (i=0; inrows = nrows; obj->ncols = ncols; obj->id = id; obj->values = malloc(E_SIZE[id]*nnz); obj->colptr = calloc(ncols+1,sizeof(int_t)); obj->rowind = malloc(sizeof(int_t)*nnz); if (!obj->values || !obj->colptr || !obj->rowind) { free(obj->values); free(obj->colptr); free(obj->rowind); free(obj); return NULL; } return obj; } void free_ccs(ccs *obj) { free(obj->values); free(obj->rowind); free(obj->colptr); free(obj); } static int realloc_ccs(ccs *obj, int nnz) { int_t *rowind; void *values; if ((rowind = realloc(obj->rowind, nnz*sizeof(int_t)))) obj->rowind = rowind; else return 0; if ((values = realloc(obj->values, nnz*E_SIZE[obj->id]))) obj->values = values; else return 0; return 1; } static ccs * convert_ccs(ccs *src, int id) { if (src->id == id) return src; if (id != MAX(id,src->id)) PY_ERR_TYPE("incompatible matrix types"); ccs *ret = alloc_ccs(src->nrows,src->ncols,CCS_NNZ(src),id); if (!ret) return (ccs *)PyErr_NoMemory(); convert_array(ret->values, src->values, id, src->id, CCS_NNZ(src)); memcpy(ret->rowind, src->rowind, CCS_NNZ(src)*sizeof(int_t)); memcpy(ret->colptr, src->colptr, (src->ncols+1)*sizeof(int_t)); return ret; } spmatrix *SpMatrix_NewFromMatrix(matrix *src, int id) { spmatrix *A; int nnz = 0, i, j; if (id < MAT_ID(src)) PY_ERR_TYPE("illegal type conversion"); for (j=0; ji != Zero[INT].i)) || ((MAT_ID(src) == DOUBLE) && (a->d != Zero[DOUBLE].d)) || ((MAT_ID(src) == COMPLEX) && (a->z != Zero[COMPLEX].z))) nnz++; } } if (!(A = SpMatrix_New(MAT_NROWS(src), MAT_NCOLS(src), nnz, id))) return (spmatrix *)PyErr_NoMemory(); int cnt = 0; for (j=0; j 0 && !PyList_Check(PyList_GET_ITEM(L, 0))); for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) { col = (single_col ? L : PyList_GET_ITEM(L, j)); if (!PyList_Check(col)) PY_ERR_TYPE("L must be a list of lists with matrices"); mk = 0; for (i=0; ii != Zero[INT].i)) || ((MAT_ID(Lij) == DOUBLE) && (a->d != Zero[DOUBLE].d)) || ((MAT_ID(Lij) == COMPLEX) && (a->z != Zero[COMPLEX].z))) nnz++; } } } else if (SpMatrix_Check(Lij)) { int ik, jk; for (jk=0; jk= 0) && (id_arg < id)) PY_ERR_TYPE("illegal type conversion"); id = MAX(DOUBLE, MAX(id, id_arg)); spmatrix *A = SpMatrix_New(m, n, nnz, id); if (!A) return (spmatrix *)PyErr_NoMemory(); int ik = 0, jk, cnt = 0; nk = 0; for (j=0; j<(single_col ? 1 : PyList_GET_SIZE(L)); j++) { col = (single_col ? L : PyList_GET_ITEM(L, j)); if (PyList_GET_SIZE(col) > 0) { int tmp = (PY_NUMBER(PyList_GET_ITEM(col, 0)) ? 1 : X_NCOLS(PyList_GET_ITEM(col, 0))); for (jk=0; jkncols, A->nrows, CCS_NNZ(A), A->id); if (!B) return NULL; int_t i, j, *buf = calloc(A->nrows,sizeof(int_t)); if (!buf) { free_ccs(B); return NULL; } /* Run through matrix and count number of elms in each row */ for (i=0; icolptr[A->ncols]; i++) buf[ A->rowind[i] ]++; /* generate new colptr */ for (i=0; incols; i++) B->colptr[i+1] = B->colptr[i] + buf[i]; /* fill in rowind and values */ for (i=0; inrows; i++) buf[i] = 0; for (i=0; incols; i++) { if (A->id == DOUBLE) for (j=A->colptr[i]; jcolptr[i+1]; j++) { B->rowind[ B->colptr[A->rowind[j]] + buf[A->rowind[j]] ] = i; ((double *)B->values)[B->colptr[A->rowind[j]] + buf[A->rowind[j]]++] = ((double *)A->values)[j]; } else for (j=A->colptr[i]; jcolptr[i+1]; j++) { B->rowind[ B->colptr[A->rowind[j]] + buf[A->rowind[j]] ] = i; ((complex *)B->values)[B->colptr[A->rowind[j]]+buf[A->rowind[j]]++] = (conjugate ? conj(((complex *)A->values)[j]) : ((complex *)A->values)[j]); } } free(buf); return B; } static int sort_ccs(ccs *A) { ccs *t = transpose(A, 0); if (!t) return -1; ccs *t2 = transpose(t, 0); if (!t2) { free_ccs(t); return -1; } free(A->colptr); free(A->rowind); free(A->values); A->colptr = t2->colptr; A->rowind = t2->rowind; A->values = t2->values; free(t2); free_ccs(t); return 0; } /* Sparse accumulator (spa) - dense representation of a sparse vector */ typedef struct { void *val; char *nz; int *idx; int nnz, n, id; } spa; static spa * alloc_spa(int_t n, int id) { spa *s = malloc(sizeof(spa)); if (s) { s->val = malloc( E_SIZE[id]*n ); s->nz = malloc( n*sizeof(char) ); s->idx = malloc( n*sizeof(int) ); s->nnz = 0; s->n = n; s->id = id; } if (!s || !s->val || !s->nz || !s->idx) { free(s->val); free(s->nz); free(s->idx); free(s); return NULL; } int_t i; for (i=0; inz[i] = 0; return s; } static void free_spa(spa *s) { if (s) { free(s->val); free(s->nz); free(s->idx); free(s); } } static void init_spa(spa *s, ccs *X, int col) { int_t i; for (i=0; innz; i++) s->nz[s->idx[i]] = 0; s->nnz = 0; if (X && X->id == DOUBLE) { for (i=X->colptr[col]; icolptr[col+1]; i++) { s->nz[X->rowind[i]] = 1; ((double *)s->val)[X->rowind[i]] = ((double *)X->values)[i]; s->idx[s->nnz++] = X->rowind[i]; } } else if (X && X->id == COMPLEX) { for (i=X->colptr[col]; icolptr[col+1]; i++) { s->nz[X->rowind[i]] = 1; ((complex *)s->val)[X->rowind[i]] = ((complex *)X->values)[i]; s->idx[s->nnz++] = X->rowind[i]; } } } static inline void spa_daxpy_partial (double a, ccs *X, int col, spa *y) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) { if (y->nz[X->rowind[i]]) { ((double *)y->val)[X->rowind[i]] += a*((double *)X->values)[i]; } } } static inline void spa_zaxpy_partial (complex a, ccs *X, int col, spa *y) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) { if (y->nz[X->rowind[i]]) { ((complex *)y->val)[X->rowind[i]] += a*((complex *)X->values)[i]; } } } static inline void spa_daxpy (double a, ccs *X, int col, spa *y) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) { if (y->nz[X->rowind[i]]) { ((double *)y->val)[X->rowind[i]] += a*((double *)X->values)[i]; } else { ((double *)y->val)[X->rowind[i]] = a*((double *)X->values)[i]; y->nz[X->rowind[i]] = 1; y->idx[y->nnz++] = X->rowind[i]; } } } static inline void spa_zaxpy (complex a, ccs *X, char conjx, int col, spa *y) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) { if (y->nz[X->rowind[i]]) { ((complex *)y->val)[X->rowind[i]] += a*CONJ(conjx,((complex *)X->values)[i]); } else { ((complex *)y->val)[X->rowind[i]] = a*CONJ(conjx,((complex *)X->values)[i]); y->nz[X->rowind[i]] = 1; y->idx[y->nnz++] = X->rowind[i]; } } } static inline void spa_daxpy_uplo (double a, ccs *X, int col, spa *y, int j, char uplo) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) { if ((uplo == 'U' && X->rowind[i] <= j) || (uplo == 'L' && X->rowind[i] >= j)) { if (y->nz[X->rowind[i]]) { ((double *)y->val)[X->rowind[i]] += a*((double *)X->values)[i]; } else { ((double *)y->val)[X->rowind[i]] = a*((double *)X->values)[i]; y->nz[X->rowind[i]] = 1; y->idx[y->nnz++] = X->rowind[i]; } } } } static inline void spa_zaxpy_uplo (complex a, ccs *X, int col, spa *y, int j, char uplo) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) { if ((uplo == 'U' && X->rowind[i] <= j) || (uplo == 'L' && X->rowind[i] >= j)) { if (y->nz[X->rowind[i]]) { ((complex *)y->val)[X->rowind[i]] += a*((complex *)X->values)[i]; } else { ((complex *)y->val)[X->rowind[i]] = a*((complex *)X->values)[i]; y->nz[X->rowind[i]] = 1; y->idx[y->nnz++] = X->rowind[i]; } } } } static inline void spa_symb_axpy (ccs *X, int col, spa *y) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) if (!y->nz[X->rowind[i]]) { y->nz[X->rowind[i]] = 1; y->idx[y->nnz++] = X->rowind[i]; } } static inline void spa_symb_axpy_uplo (ccs *X, int col, spa *y, int j, char uplo) { int i; for (i=X->colptr[col]; icolptr[col+1]; i++) if ((uplo == 'U' && X->rowind[i] <= j) || (uplo == 'L' && X->rowind[i] >= j)) { if (!y->nz[X->rowind[i]]) { y->nz[X->rowind[i]] = 1; y->idx[y->nnz++] = X->rowind[i]; } } } static inline double spa_ddot (ccs *X, int col, spa *y) { int i; double a = 0; for (i=X->colptr[col]; icolptr[col+1]; i++) if (y->nz[X->rowind[i]]) a += ((double *)X->values)[i]*((double *)y->val)[X->rowind[i]]; return a; } static inline complex spa_zdot (ccs *X, int col, spa *y, char conjx, char conjy) { int i; complex a = 0; for (i=X->colptr[col]; icolptr[col+1]; i++) if (y->nz[X->rowind[i]]) a += CONJ(conjx, ((complex *)X->values)[i])* CONJ(conjy,((complex *)y->val)[X->rowind[i]]); return a; } static void spa2compressed(spa *s, ccs *A, int col) { int i, k=0; switch (A->id) { case (DOUBLE): for (i=A->colptr[col]; icolptr[col+1]; i++) { A->rowind[i] = s->idx[k]; ((double *)A->values)[i] = ((double *)s->val)[s->idx[k++]]; } break; case COMPLEX: for (i=A->colptr[col]; icolptr[col+1]; i++) { A->rowind[i] = s->idx[k]; ((complex *)A->values)[i] = ((complex *)s->val)[s->idx[k++]]; } break; } } static int sp_daxpy(number a, void *x, void *y, int sp_x, int sp_y, int partial, void **z) { int j, k; if (sp_x && !sp_y) { ccs *X = x; double *Y = y; for (j=0; jncols; j++) { for (k=X->colptr[j]; kcolptr[j+1]; k++) Y[X->rowind[k] + j*X->nrows] += a.d*(((double *)X->values)[k]); } } else if (sp_x && sp_y && partial) { ccs *X = x, *Y = y; spa *s = alloc_spa(X->nrows, DOUBLE); int n = X->ncols; for (j=0; jnrows, DOUBLE); int m = X->nrows, n = X->ncols; ccs *Z = alloc_ccs(m, n, X->colptr[n]+Y->colptr[n], DOUBLE); if (!Z) return -1; for (j=0; jcolptr[j+1] = Z->colptr[j] + s->nnz; spa2compressed(s, Z, j); } free_spa(s); Z->rowind = realloc(Z->rowind, Z->colptr[n]*sizeof(int_t)); Z->values = realloc(Z->values, Z->colptr[n]*sizeof(double)); ccs *Zt = transpose(Z, 0); free_ccs(Z); if (!Zt) return -1; *z = transpose(Zt, 0); free_ccs(Zt); if (!(*z)) return -1; } else if (!sp_x && sp_y && partial) { double *X = x; ccs *Y = y; int kY, jY; for (jY=0; jYncols; jY++) { for (kY=Y->colptr[jY]; kYcolptr[jY+1]; kY++) ((double *)Y->values)[kY] += a.d*X[jY*Y->nrows + Y->rowind[kY]]; } } else { // if (!sp_x && !sp_y) { double *X = x; ccs *Y = y; int mn = Y->nrows*Y->ncols; ccs *Z = alloc_ccs(Y->nrows, Y->ncols, mn, Y->id); if (!Z) return -1; memcpy(Z->values, X, sizeof(double)*mn); scal[Y->id](&mn, &a, Z->values, (int *)&One[INT]); int j, k; for (j=0; jncols; j++) { Z->colptr[j+1] = Z->colptr[j] + Y->nrows; for (k=0; knrows; k++) Z->rowind[j*Y->nrows+k] = k; for (k=Y->colptr[j]; kcolptr[j+1]; k++) ((double *)Z->values)[j*Y->nrows + Y->rowind[k]] += ((double *)Y->values)[k]; } *z = Z; } return 0; } static int sp_zaxpy(number a, void *x, void *y, int sp_x, int sp_y, int partial, void **z) { int j, k; if (sp_x && !sp_y) { ccs *X = x; complex *Y = y; for (j=0; jncols; j++) { for (k=X->colptr[j]; kcolptr[j+1]; k++) Y[X->rowind[k] + j*X->nrows] += a.z*(((complex *)X->values)[k]); } } else if (sp_x && sp_y && partial) { ccs *X = x, *Y = y; spa *s = alloc_spa(X->nrows, COMPLEX); int n = X->ncols; for (j=0; jnrows, COMPLEX); int m = X->nrows, n = X->ncols; ccs *Z = alloc_ccs(m, n, X->colptr[n]+Y->colptr[n], COMPLEX); if (!Z) return -1; for (j=0; jcolptr[j+1] = Z->colptr[j] + s->nnz; spa2compressed(s, Z, j); } free_spa(s); Z->rowind = realloc(Z->rowind, Z->colptr[n]*sizeof(int_t)); Z->values = realloc(Z->values, Z->colptr[n]*sizeof(complex)); ccs *Zt = transpose(Z, 0); free_ccs(Z); if (!Zt) return -1; *z = transpose(Zt, 0); free_ccs(Zt); if (!(*z)) return -1; } else if (!sp_x && sp_y && partial) { complex *X = x; ccs *Y = y; int kY, jY; for (jY=0; jYncols; jY++) { for (kY=Y->colptr[jY]; kYcolptr[jY+1]; kY++) ((complex *)Y->values)[kY] += a.z*X[jY*Y->nrows + Y->rowind[kY]]; } } else { // if (!p_x && !sp_y) { complex *X = x; ccs *Y = y; int mn = Y->nrows*Y->ncols; ccs *Z = alloc_ccs(Y->nrows, Y->ncols, mn, Y->id); if (!Z) return -1; memcpy(Z->values, X, sizeof(complex)*mn); scal[Y->id](&mn, &a, Z->values, (int *)&One[INT]); int j, k; for (j=0; jncols; j++) { Z->colptr[j+1] = Z->colptr[j] + Y->nrows; for (k=0; knrows; k++) Z->rowind[j*Y->nrows+k] = k; for (k=Y->colptr[j]; kcolptr[j+1]; k++) ((complex *)Z->values)[j*Y->nrows + Y->rowind[k]] += ((complex *)Y->values)[k]; } *z = Z; } return 0; } static int sp_dgemv(char tA, int m, int n, number alpha, void *a, int oA, void *x, int ix, number beta, void *y, int iy) { ccs *A = a; double *X = x, *Y = y; scal[A->id]((tA == 'N' ? &m : &n), &beta, Y, &iy); if (!m) return 0; int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows; if (tA == 'N') { for (j=oj; jcolptr[j]; kcolptr[j+1]; k++) if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m)) Y[iy*(A->rowind[k]-oi + (iy > 0 ? 0 : 1 - m))] += alpha.d*((double *)A->values)[k]* X[ix*(j-oj + (ix > 0 ? 0 : 1 - n))]; } } else { for (i=oj; icolptr[i]; kcolptr[i+1]; k++) { if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m)) Y[iy*(i-oj + (iy > 0 ? 0 : 1 - n))] += alpha.d* ((double *)A->values)[k]* X[ix*(A->rowind[k]-oi + (ix > 0 ? 0 : 1 - m))]; } } } return 0; } static int sp_zgemv(char tA, int m, int n, number alpha, void *a, int oA, void *x, int ix, number beta, void *y, int iy) { ccs *A = a; complex *X = x, *Y = y; scal[A->id]((tA == 'N' ? &m : &n), &beta, Y, &iy); if (!m) return 0; int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows; if (tA == 'N') { for (j=oj; jcolptr[j]; kcolptr[j+1]; k++) if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m)) Y[iy*(A->rowind[k]-oi + (iy > 0 ? 0 : 1 - m))] += alpha.z*((complex *)A->values)[k]* X[ix*(j-oj + (ix > 0 ? 0 : 1 - n))]; } } else { for (i=oj; icolptr[i]; kcolptr[i+1]; k++) { if ((A->rowind[k] >= oi) && (A->rowind[k] < oi+m)) Y[iy*(i-oj + (iy > 0 ? 0 : 1 - n))] += alpha.z* CONJ(tA, ((complex *)A->values)[k])* X[ix*(A->rowind[k]-oi + (ix > 0 ? 0 : 1 - m))]; } } } return 0; } int sp_dsymv(char uplo, int n, number alpha, ccs *A, int oA, void *x, int ix, number beta, void *y, int iy) { double *X = x, *Y = y; scal[A->id](&n, &beta, y, &iy); if (!n) return 0; int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows; for (j=0; jcolptr[j+oj]; k < A->colptr[j+oj+1]; k++) { i = A->rowind[k] - oi; if ((i >= 0) && (i < n)) { if ((uplo == 'U') && (i > j)) break; if ((uplo == 'U') && (i <= j)) { Y[iy*(i + (iy > 0 ? 0 : 1 - n))] += alpha.d*((double *)A->values)[k]* X[ix*(j + (ix > 0 ? 0 : 1-n))]; if (i != j) Y[iy*(j + (iy > 0 ? 0 : 1-n))] += alpha.d*((double *)A->values)[k]* X[ix*(i + (ix > 0 ? 0 : 1-n))]; } else if ((uplo == 'L') && (i >= j)) { Y[iy*(i + (iy > 0 ? 0 : 1-n))] += alpha.d*((double *)A->values)[k]* X[ix*(j + (ix > 0 ? 0 : 1-n))]; if (i != j) Y[iy*(j + (iy > 0 ? 0 : 1-n))] += alpha.d*((double *)A->values)[k]* X[ix*(i + (ix > 0 ? 0 : 1-n))]; } } } } return 0; } int sp_zsymv(char uplo, int n, number alpha, ccs *A, int oA, void *x, int ix, number beta, void *y, int iy) { complex *X = x, *Y = y; scal[A->id](&n, &beta, y, &iy); if (!n) return 0; int i, j, k, oi = oA % A->nrows, oj = oA / A->nrows; for (j=0; jcolptr[j+oj]; k < A->colptr[j+oj+1]; k++) { i = A->rowind[k] - oi; if ((i >= 0) && (i < n)) { if ((uplo == 'U') && (i > j)) break; if ((uplo == 'U') && (i <= j)) { Y[iy*(i + (iy > 0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]* X[ix*(j + (ix > 0 ? 0 : 1-n))]; if (i != j) Y[iy*(j+(iy>0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]* X[ix*(i + (ix > 0 ? 0 : 1-n))]; } else if ((uplo == 'L') && (i >= j)) { Y[iy*(i + (iy > 0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]* X[ix*(j + (ix > 0 ? 0 : 1-n))]; if (i != j) Y[iy*(j+(iy > 0 ? 0 : 1-n))] += alpha.z*((complex *)A->values)[k]* X[ix*(i + (ix > 0 ? 0 : 1-n))]; } } } } return 0; } static int sp_dgemm(char tA, char tB, number alpha, void *a, void *b, number beta, void *c, int sp_a, int sp_b, int sp_c, int partial, void **z, int m, int n, int k) { if (sp_a && sp_b && sp_c && partial) { ccs *A = (tA == 'T' ? a : transpose(a, 0)); ccs *B = (tB == 'N' ? b : transpose(b, 0)); ccs *C = c; int j, l; spa *s = alloc_spa(A->nrows, A->id); if (!s) { if (A != a) free_ccs(A); return -1; } for (j=0; jcolptr[j]; lcolptr[j+1]; l++) { init_spa(s, A, C->rowind[l]); ((double *)C->values)[l] = alpha.d*spa_ddot (B, j, s) + beta.d*((double *)C->values)[l]; } } free_spa(s); if (A != a) free_ccs(A); if (B != b) free_ccs(B); } else if (sp_a && sp_b && sp_c && !partial) { ccs *A = (tA == 'N' ? a : transpose(a, 0)); ccs *B = (tB == 'N' ? b : transpose(b, 0)); ccs *C = c; int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t)); spa *s = alloc_spa(A->nrows, A->id); if (!s || !colptr_new) { free(colptr_new); if (A != a) free_ccs(A); if (B != b) free_ccs(B); return -1; } int j, l; for (j=0; jcolptr[j]; lcolptr[j+1]; l++) spa_symb_axpy (A, B->rowind[l], s); colptr_new[j+1] = colptr_new[j] + s->nnz; } int nnz = colptr_new[n]; ccs *Z = alloc_ccs(m, n, MAX(nnz,CCS_NNZ(C)), C->id); if (!Z) { if (A != a) free_ccs(A); if (B != b) free_ccs(B); free(colptr_new); free_spa(s); return -1; } free(Z->colptr); Z->colptr = colptr_new; for (j=0; jcolptr[j]; lcolptr[j+1]; l++) spa_daxpy (alpha.d*((double *)B->values)[l], A, B->rowind[l], s); spa2compressed(s, Z, j); } free_spa(s); if (A != a) free_ccs(A); if (B != b) free_ccs(B); if (sort_ccs(Z)) { free_ccs(Z); return -1; } *z = Z; } else if (sp_a && sp_b && !sp_c) { ccs *A = (tA == 'N' ? a : transpose(a, 0)); ccs *B = (tB == 'N' ? b : transpose(b, 0)); double *C = c; spa *s = alloc_spa(A->nrows, A->id); if (!s) { if (A != a) free_ccs(A); if (B != b) free_ccs(B); return -1; } int mn = m*n; scal[A->id](&mn, &beta, C, (int *)&One[INT]); int j, l; for (j=0; jcolptr[j]; lcolptr[j+1]; l++) spa_daxpy (((double *)B->values)[l], A, B->rowind[l], s); for (l=0; lnnz; l++) C[j*A->nrows + s->idx[l]] += alpha.d*((double *)s->val)[s->idx[l]]; } free_spa(s); if (A != a) free_ccs(A); if (B != b) free_ccs(B); } else if (!sp_a && sp_b && !sp_c) { double *A = a, *C = c; ccs *B = (tB == 'N' ? b : transpose(b, 0)); int j, l, mn_ = m*n; scal[DOUBLE](&mn_, &beta, C, (int *)&One[INT]); for (j=0; jcolptr[j]; lcolptr[j+1]; l++) { double a_ = alpha.d*((double *)B->values)[l]; axpy[DOUBLE](&m, &a_, A + (tA=='N' ? B->rowind[l]*m : B->rowind[l]), (tA=='N' ? (int *)&One[INT] : &k), C + j*m, (int *)&One[INT]); } } if (B != b) free_ccs(B); } else if (sp_a && !sp_b && !sp_c) { ccs *A = (tA == 'N' ? a : transpose(a, 0)); double *B = b, *C = c; int j, l, mn_ = m*n, ib = (tB == 'N' ? k : 1); scal[DOUBLE](&mn_, &beta, C, (int *)&One[INT]); for (j=0; jncols; j++) { for (l=A->colptr[j]; lcolptr[j+1]; l++) { double a_ = alpha.d*((double *)A->values)[l]; axpy[DOUBLE](&n, &a_, B + (tB == 'N' ? j : j*n), &ib, C + A->rowind[l], &m); } } if (A != a) free_ccs(A); } else if (!sp_a && sp_b && sp_c && partial) { double *A = a, val; ccs *B = (tB == 'N' ? b : transpose(b, 0)), *C = c; int j, l, o; for (j=0; jcolptr[j]; ocolptr[j+1]; o++) { val = 0; for (l=B->colptr[j]; l < B->colptr[j+1]; l++) val += A[tA == 'N' ? C->rowind[o] + B->rowind[l]*m : B->rowind[l] + C->rowind[o]*B->nrows]* ((double *)B->values)[l]; ((double *)C->values)[o] = alpha.d*val + beta.d*((double *)C->values)[o]; } } if (B != b) free_ccs(B); } else if (!sp_a && sp_b && sp_c && !partial) { double *A = a; ccs *B = (tB == 'N' ? b : transpose(b,0)), *C = c; int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t)); if (!colptr_new) { if (B != b) free_ccs(B); free(colptr_new); return -1; } int j, l; for (j=0; jcolptr[j+1]-B->colptr[j])>0)*m, C->colptr[j+1]-C->colptr[j]); int nnz = colptr_new[n]; ccs *Z = alloc_ccs(m, n, nnz, C->id); if (!Z) { if (B != b) free_ccs(B); free(colptr_new); return -1; } free(Z->colptr); Z->colptr = colptr_new; for (l=0; lvalues)[l] = 0; for (j=0; jncols; j++) { if (B->colptr[j+1]-B->colptr[j]) for (l=0; lrowind[Z->colptr[j]+l] = l; for (k=B->colptr[j]; kcolptr[j+1]; k++) { double a_ = alpha.d*((double *)B->values)[k]; axpy[DOUBLE](&m, &a_, A + (tA=='N' ? B->rowind[k]*m : B->rowind[k]), (tA=='N' ? (int *)&One[INT] : &k), (double *)Z->values + Z->colptr[j], (int *)&One[INT]); } if (beta.d != 0.0) { if (Z->colptr[j+1]-Z->colptr[j] == m) { for (l=C->colptr[j]; lcolptr[j+1]; l++) { ((double *)Z->values)[Z->colptr[j]+C->rowind[l]] += beta.d*((double *)C->values)[l]; } } else { for (l=C->colptr[j]; lcolptr[j+1]; l++) { ((double *)Z->values)[Z->colptr[j]+l-C->colptr[j]] = beta.d*((double *)C->values)[l]; Z->rowind[Z->colptr[j]+l-C->colptr[j]] = C->rowind[l]; } } } } if (B != b) free_ccs(B); *z = Z; } else if (sp_a && !sp_b && sp_c && partial) { ccs *A = (tA == 'N' ? transpose(a,0) : a), *C = c; double *B = b, val; int j, l, o; for (j=0; jcolptr[j]; ocolptr[j+1]; o++) { val = 0; for (l=A->colptr[C->rowind[o]]; l < A->colptr[C->rowind[o]+1]; l++) val += ((double *)A->values)[l]* B[tB == 'N' ? j*A->nrows + A->rowind[l] : A->rowind[l]*C->ncols + j]; ((double *)C->values)[o] = alpha.d*val + beta.d*((double *)C->values)[o]; } } if (A != a) free_ccs(A); } else if (sp_a && !sp_b && sp_c && !partial) { ccs *A = (tA == 'N' ? a : transpose(a,0)), *C = c; double *B = b; spa *s = alloc_spa(A->nrows, A->id); int_t *colptr_new = calloc(n+1,sizeof(int_t)); if (!s || !colptr_new) { free(s); free(colptr_new); if (A != a) free_ccs(A); return -1; } int j, l; for (j=0; jncols; l++) spa_symb_axpy(A, l, s); if (beta.d != 0.0) spa_symb_axpy(C, j, s); colptr_new[j+1] = colptr_new[j] + s->nnz; } int nnz = colptr_new[n]; ccs *Z = alloc_ccs(m, n, nnz, C->id); if (!Z) { if (A != a) free_ccs(A); free_spa(s); free(colptr_new); return -1; } free(Z->colptr); Z->colptr = colptr_new; for (j=0; jncols; j++) { for (o=C->colptr[j]; ocolptr[j+1]; o++) { val = 0; for (l=0; lrowind[o] : l + C->rowind[o]*k]* B[tB == 'N' ? j*k + l : l*n + j]; ((double *)C->values)[o] = alpha.d*val + beta.d*((double *)C->values)[o]; } } } else if (!sp_a && !sp_b && sp_c && !partial) { double *A = a, *B = b; ccs *C = c; ccs *Z = alloc_ccs(m, n, m*n, C->id); if (!Z) return -1; int j, l; for (j=0; jvalues)[j] = 0.0; int ldA = MAX(1, (tA == 'N' ? m : k)); int ldB = MAX(1, (tB == 'N' ? k : n)); int ldC = MAX(1, m); gemm[DOUBLE](&tA, &tB, &m, &n, &k, &alpha, A, &ldA, B, &ldB, &Zero[DOUBLE], Z->values, &ldC); for (j=0; jrowind[j*m + l] = l; Z->colptr[j+1] = Z->colptr[j] + m; } if (beta.d != 0.0) { for (j=0; jcolptr[j]; lcolptr[j+1]; l++) { ((double *)Z->values)[j*m + C->rowind[l]] += beta.d*((double *)C->values)[l]; } } } *z = Z; } return 0; } static int sp_zgemm(char tA, char tB, number alpha, void *a, void *b, number beta, void *c, int sp_a, int sp_b, int sp_c, int partial, void **z, int m, int n, int k) { if (sp_a && sp_b && sp_c && partial) { ccs *A = (tA == 'N' ? transpose(a, 0) : a); ccs *B = (tB == 'N' ? b : transpose(b, 0)); ccs *C = c; int j, l; spa *s = alloc_spa(A->nrows, A->id); if (!s) { if (A != a) free_ccs(A); return -1; } for (j=0; jcolptr[j]; lcolptr[j+1]; l++) { init_spa(s, A, C->rowind[l]); ((complex *)C->values)[l] = alpha.z*spa_zdot(B, j, s, tB, tA) + beta.z*((complex *)C->values)[l]; } } free_spa(s); if (A != a) free_ccs(A); if (B != b) free_ccs(B); } else if (sp_a && sp_b && sp_c && !partial) { ccs *A = (tA == 'N' ? a : transpose(a, 0)); ccs *B = (tB == 'N' ? b : transpose(b, 0)); ccs *C = c; int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t)); spa *s = alloc_spa(A->nrows, A->id); if (!s || !colptr_new) { free(colptr_new); if (A != a) free_ccs(A); if (B != b) free_ccs(B); return -1; } int j, l; for (j=0; jcolptr[j]; lcolptr[j+1]; l++) spa_symb_axpy (A, B->rowind[l], s); colptr_new[j+1] = colptr_new[j] + s->nnz; } int nnz = colptr_new[n]; ccs *Z = alloc_ccs(m, n, nnz, A->id); if (!Z) { if (A != a) free_ccs(A); if (B != b) free_ccs(B); free(colptr_new); free_spa(s); return -1; } free(Z->colptr); Z->colptr = colptr_new; for (j=0; jcolptr[j]; lcolptr[j+1]; l++) spa_zaxpy(alpha.z*CONJ(tB, ((complex *)B->values)[l]), A, tA, B->rowind[l], s); spa2compressed(s, Z, j); } free_spa(s); if (A != a) free_ccs(A); if (B != b) free_ccs(B); if (sort_ccs(Z)) { free_ccs(Z); return -1; } *z = Z; } else if (sp_a && sp_b && !sp_c) { ccs *A = (tA == 'N' ? a : transpose(a, 0)); ccs *B = (tB == 'N' ? b : transpose(b, 0)); complex *C = c; spa *s = alloc_spa(A->nrows, A->id); if (!s) { if (A != a) free_ccs(A); if (B != b) free_ccs(B); return -1; } int mn = m*n; scal[A->id](&mn, &beta, C, (int *)&One[COMPLEX]); int j, l; for (j=0; jcolptr[j]; lcolptr[j+1]; l++) spa_zaxpy (CONJ(tB,((complex *)B->values)[l]), A, tA, B->rowind[l], s); for (l=0; lnnz; l++) C[j*A->nrows + s->idx[l]] += alpha.z*((complex *)s->val)[s->idx[l]]; } free_spa(s); if (A != a) free_ccs(A); if (B != b) free_ccs(B); } else if (!sp_a && sp_b && !sp_c) { complex *A = a, *C = c; ccs *B = (tB == 'N' ? b : transpose(b, 0)); int i, j, l, mn_ = m*n; scal[COMPLEX](&mn_, &beta, C, (int *)&One[COMPLEX]); for (j=0; jcolptr[j]; lcolptr[j+1]; l++) { for (i=0; irowind[l]*m : B->rowind[l]+i*k])* CONJ(tB,((complex *)B->values)[l]); } } if (B != b) free_ccs(B); } else if (sp_a && !sp_b && !sp_c) { ccs *A = (tA == 'N' ? a : transpose(a, 0)); complex *B = b, *C = c; int i, j, l, mn_ = m*n; scal[COMPLEX](&mn_, &beta, C, (int *)&One[INT]); for (j=0; jncols; j++) { for (l=A->colptr[j]; lcolptr[j+1]; l++) { for (i=0; irowind[l]+i*m] += alpha.z*CONJ(tA,((complex *)A->values)[l])* CONJ(tB,B[tB=='N' ? j+i*k : i+j*n]); } } if (A != a) free_ccs(A); } else if (!sp_a && sp_b && sp_c && partial) { complex *A = a, val; ccs *B = (tB == 'N' ? b : transpose(b, 0)), *C = c; int j, l, o; for (j=0; jcolptr[j]; ocolptr[j+1]; o++) { val = 0; for (l=B->colptr[j]; l < B->colptr[j+1]; l++) val += CONJ(tA,A[tA == 'N' ? C->rowind[o] + B->rowind[l]*m : B->rowind[l] + C->rowind[o]*B->nrows])* CONJ(tB,((complex *)B->values)[l]); ((complex *)C->values)[o] = alpha.z*val + beta.z*((complex *)C->values)[o]; } } if (B != b) free_ccs(B); } else if (!sp_a && sp_b && sp_c && !partial) { complex *A = a; ccs *B = (tB == 'N' ? b : transpose(b,0)), *C = c; int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t)); if (!colptr_new) { if (B != b) free_ccs(B); free(colptr_new); return -1; } int i, j, l; for (j=0; jcolptr[j+1]-B->colptr[j])>0)*m, C->colptr[j+1]-C->colptr[j]); int nnz = colptr_new[n]; ccs *Z = alloc_ccs(m, n, nnz, C->id); if (!Z) { if (B != b) free_ccs(B); free(colptr_new); return -1; } free(Z->colptr); Z->colptr = colptr_new; for (l=0; lvalues)[l] = 0; for (j=0; jncols; j++) { if (B->colptr[j+1]-B->colptr[j]) for (l=0; lrowind[Z->colptr[j]+l] = l; for (l=B->colptr[j]; lcolptr[j+1]; l++) { for (i=0; ivalues)[Z->colptr[j]+i] += alpha.z* CONJ(tA,A[tA=='N' ? B->rowind[l]*m+i : B->rowind[l]+i*k])* CONJ(tB,((complex *)B->values)[l]); } } if (beta.z != 0.0) { if (Z->colptr[j+1]-Z->colptr[j] == m) { for (l=C->colptr[j]; lcolptr[j+1]; l++) { ((complex *)Z->values)[Z->colptr[j]+C->rowind[l]] += beta.z*((complex *)C->values)[l]; } } else { for (l=C->colptr[j]; lcolptr[j+1]; l++) { ((complex *)Z->values)[Z->colptr[j]+l-C->colptr[j]] = beta.z*((complex *)C->values)[l]; Z->rowind[Z->colptr[j]+l-C->colptr[j]] = C->rowind[l]; } } } } if (B != b) free_ccs(B); *z = Z; } else if (sp_a && !sp_b && sp_c && partial) { ccs *A = (tA == 'N' ? transpose(a,0) : a), *C = c; complex *B = b, val; int j, l, o; for (j=0; jcolptr[j]; ocolptr[j+1]; o++) { val = 0; for (l=A->colptr[C->rowind[o]]; l < A->colptr[C->rowind[o]+1]; l++) val += CONJ(tA, ((complex *)A->values)[l])* CONJ(tB, B[tB == 'N' ? j*A->nrows + A->rowind[l] : A->rowind[l]*C->ncols + j]); ((complex *)C->values)[o] = alpha.z*val + beta.z*((complex *)C->values)[o]; } } if (A != a) free_ccs(A); } else if (sp_a && !sp_b && sp_c && !partial) { ccs *A = (tA == 'N' ? a : transpose(a,0)), *C = c; complex *B = b; spa *s = alloc_spa(A->nrows, A->id); int_t *colptr_new = calloc(n+1,sizeof(int_t)); if (!s || !colptr_new) { free(s); free(colptr_new); if (A != a) free_ccs(A); return -1; } int j, l; for (j=0; jncols; l++) spa_symb_axpy(A, l, s); if (beta.z != 0.0) spa_symb_axpy(C, j, s); colptr_new[j+1] = colptr_new[j] + s->nnz; } int nnz = colptr_new[n]; ccs *Z = alloc_ccs(m, n, nnz, C->id); if (!Z) { if (A != a) free_ccs(A); free_spa(s); free(colptr_new); return -1; } free(Z->colptr); Z->colptr = colptr_new; for (j=0; jncols; j++) { for (o=C->colptr[j]; ocolptr[j+1]; o++) { val = 0; for (l=0; lrowind[o] : l+C->rowind[o]*k])* CONJ(tB, B[tB == 'N' ? j*k + l : l*n + j]); ((complex *)C->values)[o] = alpha.z*val + beta.z*((complex *)C->values)[o]; } } } else if (!sp_a && !sp_b && sp_c && !partial) { complex *A = a, *B = b; ccs *C = c; ccs *Z = alloc_ccs(m, n, m*n, C->id); if (!Z) return -1; int j, l; for (j=0; jvalues)[j] = 0.0; int ldA = MAX(1, (tA == 'N' ? m : k)); int ldB = MAX(1, (tB == 'N' ? k : n)); int ldC = MAX(1, m); gemm[COMPLEX](&tA, &tB, &m, &n, &k, &alpha, A, &ldA, B, &ldB, &Zero[COMPLEX], Z->values, &ldC); for (j=0; jrowind[j*m + l] = l; Z->colptr[j+1] = Z->colptr[j] + m; } if (beta.z != 0.0) { for (j=0; jcolptr[j]; lcolptr[j+1]; l++) { ((complex *)Z->values)[j*m + C->rowind[l]] += beta.z*((complex *)C->values)[l]; } } } *z = Z; } return 0; } static int sp_dsyrk(char uplo, char trans, number alpha, void *a, number beta, void *c, int sp_a, int sp_c, int partial, int k, void **z) { if (sp_a && sp_c && partial) { ccs *A = (trans == 'N' ? transpose(a, 0) : a), *C = c; spa *s = alloc_spa(A->nrows, C->id); if (!A || !s) { if (A != a) free_ccs(A); free_spa(s); return -1; } int j, k; for (j=0; jncols; j++) { for (k=C->colptr[j]; kcolptr[j+1]; k++) { if ((uplo == 'L' && C->rowind[k] >= j) || (uplo == 'U' && C->rowind[k] <= j)) { init_spa(s, A, C->rowind[k]); ((double *)C->values)[k] = alpha.d*spa_ddot(A, j, s) + beta.d*((double *)C->values)[k]; } } } free_spa(s); if (A != a) free_ccs(A); } else if (sp_a && sp_c && !partial) { ccs *A = (trans == 'N' ? a : transpose(a, 0)); ccs *B = (trans == 'N' ? transpose(a, 0) : a); ccs *C = c; spa *s = alloc_spa(C->nrows, C->id); int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t)); if (!A || !B || !s || !colptr_new) { if (A != a) free_ccs(A); if (B != a) free_ccs(B); free_spa(s); free(colptr_new); return -1; } int j, k; for (j=0; jncols; j++) { init_spa(s, NULL, 0); if (beta.d != 0.0) spa_symb_axpy_uplo(C, j, s, j, uplo); for (k=B->colptr[j]; kcolptr[j+1]; k++) spa_symb_axpy_uplo(A, B->rowind[k], s, j, uplo); colptr_new[j+1] = colptr_new[j] + s->nnz; } int nnz = colptr_new[C->ncols]; ccs *Z = alloc_ccs(C->nrows, C->ncols, nnz, C->id); if (!Z) { if (A != a) free_ccs(A); if (B != a) free_ccs(B); free_spa(s); free(colptr_new); return -1; } free(Z->colptr); Z->colptr = colptr_new; for (j=0; jncols; j++) { init_spa(s, NULL, 0); if (beta.d != 0.0) spa_daxpy_uplo(beta.d, C, j, s, j, uplo); for (k=B->colptr[j]; kcolptr[j+1]; k++) { spa_daxpy_uplo(alpha.d*((double *)B->values)[k], A, B->rowind[k], s, j, uplo); } spa2compressed(s, Z, j); } if (A != a) free_ccs(A); if (B != a) free_ccs(B); free_spa(s); if (sort_ccs(Z)) { free_ccs(Z); return -1; } *z = Z; } else if (sp_a && !sp_c) { int n = (trans == 'N' ? ((ccs *)a)->nrows : ((ccs *)a)->ncols); ccs *A = (trans == 'N' ? a : transpose(a, 0)); ccs *B = (trans == 'N' ? transpose(a, 0) : a); double *C = c; spa *s = alloc_spa(n, A->id); if (!A || !B || !s) { if (A != a) free_ccs(A); if (B != a) free_ccs(B); free_spa(s); return -1; } int j, k; for (j=0; jncols; j++) { init_spa(s, NULL, 0); for (k=B->colptr[j]; kcolptr[j+1]; k++) { spa_daxpy_uplo(alpha.d*((double *)B->values)[k], A, B->rowind[k], s, j, uplo); } if (uplo == 'U') { int m = j+1; scal[DOUBLE](&m, &beta, C + j*n, (int *)&One[INT]); for (k=0; knnz; k++) { if (s->idx[k] <= j) C[j*n + s->idx[k]] += alpha.d*((double *)s->val)[s->idx[k]]; } } else { int m = n-j; scal[DOUBLE](&m, &beta, C + j*(n+1), (int *)&One[INT]); for (k=0; knnz; k++) { if (s->idx[k] >= j) C[j*n + s->idx[k]] += alpha.d*((double *)s->val)[s->idx[k]]; } } } if (A != a) free_ccs(A); if (B != a) free_ccs(B); free_spa(s); } else if (!sp_a && sp_c && partial) { ccs *C = c; double *A = a; int j, i, l, n=C->nrows; for (j=0; jcolptr[j]; icolptr[j+1]; i++) { if ((uplo == 'L' && C->rowind[i] >= j) || (uplo == 'U' && C->rowind[i] <= j)) { ((double *)C->values)[i] *= beta.d; for (l=0; lvalues)[i] += alpha.d*A[trans == 'N' ? C->rowind[i]+l*n : l+C->rowind[i]*k]* A[trans == 'N' ? j+l*n : l+j*k]; } } } } else if (!sp_a && sp_c) { ccs *C = c; double *A = a, *C_ = malloc( C->nrows*C->nrows*sizeof(double) ); int_t *colptr_new = calloc(C->ncols+1,sizeof(int_t)); if (!C_ || !colptr_new) { free(C_); free(colptr_new); return -1; } int j, i, n=C->nrows; for (j=0; jid); if (!Z) { free(C_); free(colptr_new); return -1; } free(Z->colptr); Z->colptr = colptr_new; syrk[DOUBLE](&uplo, &trans, &n, &k, &alpha, A, (trans == 'N' ? &n : &k), &Zero[DOUBLE], C_, &n); for (j=0; jcolptr[j]; icolptr[j+1]; i++) { if (uplo == 'U') { ((double *)Z->values)[i] = C_[j*n + i-Z->colptr[j]]; Z->rowind[i] = i-Z->colptr[j]; } else { ((double *)Z->values)[i] = C_[j*(n+1) + i-Z->colptr[j]]; Z->rowind[i] = j+i-Z->colptr[j]; } } for (i=C->colptr[j]; icolptr[j+1]; i++) { if (uplo == 'U' && C->rowind[i] <= j) ((double *)Z->values)[Z->colptr[j]+C->rowind[i]] += beta.d*((double *)C->values)[i]; else if (uplo == 'L' && C->rowind[i] >= j) ((double *)Z->values)[Z->colptr[j]+C->rowind[i]-j] += beta.d*((double *)C->values)[i]; } } free(C_); *z = Z; } return 0; } /* No error checking: Il and Jl must be valid indexlist, and Il,Jl,V must be of same length (V can also be NULL) */ static spmatrix * triplet2dccs(matrix *Il, matrix *Jl, matrix *V, int_t nrows, int_t ncols) { spmatrix *ret = SpMatrix_New(nrows,ncols, MAT_LGT(Il), DOUBLE); double_list *dlist = malloc(MAT_LGT(Jl)*sizeof(double_list)); int_t *colcnt = calloc(ncols,sizeof(int_t)); if (!ret || !dlist || !colcnt) { Py_XDECREF(ret); free(dlist); free(colcnt); return (spmatrix *)PyErr_NoMemory(); } /* build colptr */ int_t i,j,k,l; for (j=0; jobj = alloc_ccs(nrows, ncols, nnz, id); if (!ret->obj) { Py_DECREF(ret); return (spmatrix *)PyErr_NoMemory(); } return ret; } static spmatrix * SpMatrix_NewFromCCS(ccs *x) { spmatrix *ret; if (!(ret = (spmatrix *)spmatrix_tp.tp_alloc(&spmatrix_tp, 0))) return (spmatrix *)PyErr_NoMemory(); ret->obj = x; return ret; } /* SpMatrix_NewFromSpMatrix. In API. Returns a copy of an spmatrix object. Arguments: A : spmatrix object id : DOUBLE/COMPLEX */ spmatrix * SpMatrix_NewFromSpMatrix(spmatrix *A, int id) { if ((id == DOUBLE) && (SP_ID(A) == COMPLEX)) PY_ERR_TYPE("cannot convert complex to double"); spmatrix *ret = SpMatrix_New (SP_NROWS(A), SP_NCOLS(A), SP_NNZ(A), id); if (!ret) return (spmatrix *)PyErr_NoMemory(); convert_array(SP_VAL(ret), SP_VAL(A), id, SP_ID(A), SP_NNZ(A)); memcpy(SP_COL(ret), SP_COL(A), (SP_NCOLS(A)+1)*sizeof(int_t)); memcpy(SP_ROW(ret), SP_ROW(A), SP_NNZ(A)*sizeof(int_t)); return ret; } /* SpMatrix_NewFromIJV. Returns a spmatrix object from a triplet description. Arguments: Il,Jl,V : (INT,INT,DOUBLE/COMPLEX) triplet description m,n : Dimension of spmatrix. If either m==0 or n==0, then the dimension is taken as MAX(I) x MAX(Jl). id : DOUBLE, COMPLEX */ spmatrix * SpMatrix_NewFromIJV(matrix *Il, matrix *Jl, matrix *V, int_t m, int_t n, int id) { if (MAT_ID(Il) != INT || MAT_ID(Jl) != INT) PY_ERR_TYPE("index sets I and J must be integer"); if (MAT_LGT(Il) != MAT_LGT(Jl)) PY_ERR_TYPE("index sets I and J must be of same length"); if (V && !Matrix_Check(V)) PY_ERR_TYPE("invalid V argument"); if (V && Matrix_Check(V) && (MAX(id,MAT_ID(V)) != id)) PY_ERR_TYPE("matrix V has invalid type"); if (V && (MAT_LGT(V) != MAT_LGT(Il))) PY_ERR_TYPE("I, J and V must have same length"); if (!Il || !Jl) return SpMatrix_New(0,0,0,id); int_t k, Imax=-1, Jmax=-1; for (k=0; kImax) Imax = MAT_BUFI(Il)[k]; if (MAT_BUFI(Jl)[k]>Jmax) Jmax = MAT_BUFI(Jl)[k]; } if ((m<0) || (n<0)) { m = MAX(Imax+1,m); n = MAX(Jmax+1,n);} if (m < Imax+1 || n < Jmax+1) PY_ERR_TYPE("dimension too small"); for (k=0; k= m) || (MAT_BUFI(Jl)[k] < 0) || (MAT_BUFI(Jl)[k] >= n) ) PY_ERR_TYPE("index out of range"); return (id == DOUBLE ? triplet2dccs(Il,Jl,V,m,n) : triplet2zccs(Il,Jl,V,m,n)); } static void spmatrix_dealloc(spmatrix* self) { free(self->obj->values); free(self->obj->colptr); free(self->obj->rowind); free(self->obj); #if PY_MAJOR_VERSION >= 3 Py_TYPE(self)->tp_free((PyObject*)self); #else self->ob_type->tp_free((PyObject*)self); #endif } static PyObject * spmatrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *size = NULL; matrix *Il=NULL, *Jl=NULL, *V=NULL; int_t nrows = -1, ncols = -1; char tc = 0; static char *kwlist[] = { "V", "I", "J", "size","tc", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|OC:spmatrix", kwlist, &V, &Il, &Jl, &size, &tc)) #else if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO|Oc:spmatrix", kwlist, &V, &Il, &Jl, &size, &tc)) #endif return NULL; if (!(PySequence_Check((PyObject *)V) || Matrix_Check(V) || PY_NUMBER(V))) { PY_ERR_TYPE("V must be either a sequence type, a matrix, or a number"); } if (size && !PyArg_ParseTuple(size, "ll", &nrows, &ncols)) PY_ERR_TYPE("invalid dimension tuple"); if (size && (nrows < 0 || ncols < 0)) PY_ERR_TYPE("dimensions must be non-negative"); if (tc && !(VALID_TC_SP(tc))) PY_ERR_TYPE("tc must be 'd' or 'z'"); int id = (tc ? TC2ID(tc) : -1); #if PY_MAJOR_VERSION < 3 int_t ndim = 0; #endif /* convert lists to matrices */ if (Matrix_Check(Il)) Py_INCREF(Il); #if PY_MAJOR_VERSION < 3 else if (PyObject_HasAttrString((PyObject *)Il,"__array_struct__")) { if (!(Il = Matrix_NewFromArrayStruct((PyObject *)Il, INT, &ndim))) return NULL; } #endif else if (PySequence_Check((PyObject *)Il)) { if (!(Il = Matrix_NewFromSequence((PyObject *)Il, INT))) return NULL; } else PY_ERR_TYPE("invalid type for I"); if (Matrix_Check(Jl)) Py_INCREF(Jl); #if PY_MAJOR_VERSION < 3 else if (PyObject_HasAttrString((PyObject *)Jl,"__array_struct__")) { if (!(Jl = Matrix_NewFromArrayStruct((PyObject *)Jl, INT, &ndim))) { Py_DECREF(Il); return NULL; } } #endif else if (PySequence_Check((PyObject *)Jl)) { if (!(Jl = Matrix_NewFromSequence((PyObject *)Jl, INT))) { Py_DECREF(Il); return NULL; } } else { Py_DECREF(Il); PY_ERR_TYPE("invalid type for J"); } if (Matrix_Check(V)) Py_INCREF(V); #if PY_MAJOR_VERSION < 3 else if (PyObject_HasAttrString((PyObject *)V,"__array_struct__")) { int_t ndim = 0; if (!(V = Matrix_NewFromArrayStruct((PyObject *)V, id, &ndim))) { Py_DECREF(Il); Py_DECREF(Jl); return NULL; } } #endif else if (PySequence_Check((PyObject *)V)) { if (!(V = Matrix_NewFromSequence((PyObject *)V, id))) { Py_DECREF(Il); Py_DECREF(Jl); return NULL; } } else if (PY_NUMBER(V)) { if (!(V = Matrix_NewFromNumber(MAT_LGT(Il), 1, get_id(V, 1), V, 1))) { Py_DECREF(Il); Py_DECREF(Jl); return PyErr_NoMemory(); } } else { Py_DECREF(Il); Py_DECREF(Jl); PY_ERR_TYPE("invalid type for V"); } id = (id == -1 ? MAX(get_id(V, !Matrix_Check(V)), DOUBLE) : id); spmatrix *ret = SpMatrix_NewFromIJV(Il, Jl, V, nrows, ncols, id == -1 ? MAX(MAT_ID(V),DOUBLE) : id); Py_DECREF(Il); Py_DECREF(Jl); Py_DECREF(V); return (PyObject *)ret; } static PyObject * spmatrix_str(matrix *self) { PyObject *cvxopt = PyImport_ImportModule("cvxopt"); PyObject *str, *ret; if (!(str = PyObject_GetAttrString(cvxopt, "spmatrix_str"))) { Py_DECREF(cvxopt); PY_ERR(PyExc_KeyError, "missing 'spmatrix_str' in 'cvxopt'"); } Py_DECREF(cvxopt); if (!PyCallable_Check(str)) PY_ERR_TYPE("'spmatrix_str' is not callable"); ret = PyObject_CallFunctionObjArgs(str, (PyObject *)self, NULL); Py_DECREF(str); return ret; } static PyObject * spmatrix_repr(matrix *self) { PyObject *cvxopt = PyImport_ImportModule("cvxopt"); PyObject *repr, *ret; if (!(repr = PyObject_GetAttrString(cvxopt, "spmatrix_repr"))) { Py_DECREF(cvxopt); PY_ERR(PyExc_KeyError, "missing 'spmatrix_repr' in 'cvxopt'"); } Py_DECREF(cvxopt); if (!PyCallable_Check(repr)) PY_ERR_TYPE("'spmatrix_repr' is not callable"); ret = PyObject_CallFunctionObjArgs(repr, (PyObject *)self, NULL); Py_DECREF(repr); return ret; } static PyObject * spmatrix_richcompare(PyObject *self, PyObject *other, int op) { PY_ERR(PyExc_NotImplementedError, "matrix comparison not implemented"); } static PyObject * spmatrix_get_size(spmatrix *self, void *closure) { PyObject *t = PyTuple_New(2); #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(t, 0, PyLong_FromLong(SP_NROWS(self))); PyTuple_SET_ITEM(t, 1, PyLong_FromLong(SP_NCOLS(self))); #else PyTuple_SET_ITEM(t, 0, PyInt_FromLong(SP_NROWS(self))); PyTuple_SET_ITEM(t, 1, PyInt_FromLong(SP_NCOLS(self))); #endif return t; } static int spmatrix_set_size(spmatrix *self, PyObject *value, void *closure) { if (!value) PY_ERR_INT(PyExc_TypeError,"size attribute cannot be deleted"); if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) PY_ERR_INT(PyExc_TypeError, "can only assign a 2-tuple to size"); #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(PyTuple_GET_ITEM(value, 0)) || !PyLong_Check(PyTuple_GET_ITEM(value, 1))) #else if (!PyInt_Check(PyTuple_GET_ITEM(value, 0)) || !PyInt_Check(PyTuple_GET_ITEM(value, 1))) #endif PY_ERR_INT(PyExc_TypeError, "invalid size tuple"); #if PY_MAJOR_VERSION >= 3 int m = PyLong_AS_LONG(PyTuple_GET_ITEM(value, 0)); int n = PyLong_AS_LONG(PyTuple_GET_ITEM(value, 1)); #else int m = PyInt_AS_LONG(PyTuple_GET_ITEM(value, 0)); int n = PyInt_AS_LONG(PyTuple_GET_ITEM(value, 1)); #endif if (m<0 || n<0) PY_ERR_INT(PyExc_TypeError, "dimensions must be non-negative"); if (m*n != SP_NROWS(self)*SP_NCOLS(self)) PY_ERR_INT(PyExc_TypeError, "number of elements in matrix cannot change"); int_t *colptr = calloc((n+1),sizeof(int_t)); if (!colptr) PY_ERR_INT(PyExc_MemoryError, "insufficient memory"); int j, k, in, jn; for (j=0; j= 3 return PyUnicode_FromStringAndSize(TC_CHAR[SP_ID(self)], 1); #else return PyString_FromStringAndSize(TC_CHAR[SP_ID(self)], 1); #endif } static PyObject * spmatrix_get_V(spmatrix *self, void *closure) { matrix *ret = Matrix_New(SP_NNZ(self), 1, SP_ID(self)); if (!ret) return PyErr_NoMemory(); memcpy(MAT_BUF(ret), SP_VAL(self), SP_NNZ(self)*E_SIZE[SP_ID(self)]); return (PyObject *)ret; } static int spmatrix_set_V(spmatrix *self, PyObject *value, void *closure) { if (!value) PY_ERR_INT(PyExc_AttributeError, "attribute cannot be deleted"); if (PY_NUMBER(value)) { number val; if (convert_num[SP_ID(self)](&val, value, 1, 0)) PY_ERR_INT(PyExc_TypeError, "invalid type in assignment"); int i; for (i=0; iobj,0)); } static spmatrix * spmatrix_get_H(spmatrix *self, void *closure) { return SpMatrix_NewFromCCS(transpose(((spmatrix *)self)->obj,1)); } static PyGetSetDef spmatrix_getsets[] = { {"size", (getter) spmatrix_get_size, (setter) spmatrix_set_size, "matrix dimensions"}, {"typecode", (getter) spmatrix_get_typecode, NULL, "type character"}, {"V", (getter) spmatrix_get_V, (setter) spmatrix_set_V, "the value list of the matrix in triplet form"}, {"I", (getter) spmatrix_get_I, NULL, "the I (row) list of the matrix in triplet form"}, {"J", (getter) spmatrix_get_J, NULL, "the J (column) list of the matrix in triplet form"}, {"T", (getter) spmatrix_get_T, NULL, "transpose"}, {"H", (getter) spmatrix_get_H, NULL, "conjugate transpose"}, {"CCS", (getter) spmatrix_get_CCS, NULL, "CCS representation"}, {NULL} /* Sentinel */ }; static PyObject * spmatrix_getstate(spmatrix *self) { PyObject *Il = spmatrix_get_I(self, NULL); PyObject *Jl = spmatrix_get_J(self, NULL); PyObject *V = spmatrix_get_V(self, NULL); PyObject *size = PyTuple_New(2); if (!Il || !Jl || !V || !size) { Py_XDECREF(Il); Py_XDECREF(Jl); Py_XDECREF(V); Py_XDECREF(size); return NULL; } #if PY_MAJOR_VERSION >= 3 PyTuple_SET_ITEM(size, 0, PyLong_FromLong(SP_NROWS(self))); PyTuple_SET_ITEM(size, 1, PyLong_FromLong(SP_NCOLS(self))); #else PyTuple_SET_ITEM(size, 0, PyInt_FromLong(SP_NROWS(self))); PyTuple_SET_ITEM(size, 1, PyInt_FromLong(SP_NCOLS(self))); #endif return Py_BuildValue("NNNNs", V, Il, Jl, size, TC_CHAR[SP_ID(self)]); return NULL; } static PyObject * spmatrix_trans(spmatrix *self) { return (PyObject *)SpMatrix_NewFromCCS(transpose(((spmatrix *)self)->obj,0)); } static PyObject * spmatrix_ctrans(spmatrix *self) { return (PyObject *)SpMatrix_NewFromCCS(transpose(((spmatrix *)self)->obj,1)); } static PyObject * spmatrix_real(spmatrix *self) { if (SP_ID(self) != COMPLEX) return (PyObject *)SpMatrix_NewFromSpMatrix(self, SP_ID(self)); spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), SP_NNZ(self), DOUBLE); if (!ret) return PyErr_NoMemory(); int i; for (i=0; i < SP_NNZ(self); i++) SP_VALD(ret)[i] = creal(SP_VALZ(self)[i]); memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t)); memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t)); return (PyObject *)ret; } static PyObject * spmatrix_imag(spmatrix *self) { if (SP_ID(self) != COMPLEX) return (PyObject *)SpMatrix_NewFromSpMatrix(self, SP_ID(self)); spmatrix *ret = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), SP_NNZ(self), DOUBLE); if (!ret) return PyErr_NoMemory(); int i; for (i=0; i < SP_NNZ(self); i++) SP_VALD(ret)[i] = cimag(SP_VALZ(self)[i]); memcpy(SP_COL(ret), SP_COL(self), (SP_NCOLS(self)+1)*sizeof(int_t)); memcpy(SP_ROW(ret), SP_ROW(self), SP_NNZ(self)*sizeof(int_t)); return (PyObject *)ret; } static PyObject * spmatrix_reduce(spmatrix* self) { #if PY_MAJOR_VERSION >= 3 return Py_BuildValue("ON", Py_TYPE(self), spmatrix_getstate(self)); #else return Py_BuildValue("ON", self->ob_type, spmatrix_getstate(self)); #endif } static PyMethodDef spmatrix_methods[] = { {"real", (PyCFunction)spmatrix_real, METH_NOARGS, "Returns real part of sparse matrix"}, {"imag", (PyCFunction)spmatrix_imag, METH_NOARGS, "Returns imaginary part of sparse matrix"}, {"trans", (PyCFunction)spmatrix_trans, METH_NOARGS, "Returns the matrix transpose"}, {"ctrans", (PyCFunction)spmatrix_ctrans, METH_NOARGS, "Returns the matrix conjugate transpose"}, {"__reduce__", (PyCFunction)spmatrix_reduce, METH_NOARGS, "__reduce__() -> (cls, state)"}, {NULL} /* Sentinel */ }; static int bsearch_int(int_t *lower, int_t *upper, int_t key, int_t *k) { if (lower>upper) { *k = 0; return 0; } int_t *mid, *start = lower; while (upper - lower > 1) { mid = lower+((upper-lower)>>1); if (*mid > key) upper = mid; else if (*mid < key) lower = mid; else { *k = mid - start; return 1; } } if (*upper == key) { *k = upper - start; return 1; } else if (*lower == key) { *k = lower - start; return 1; } else { if (*lower > key) *k = lower - start; else if (*upper < key) *k = upper - start + 1; else *k = upper - start; return 0; } } int spmatrix_getitem_ij(spmatrix *A, int_t i, int_t j, number *value) { int_t k; if (SP_NNZ(A) && bsearch_int(&(SP_ROW(A)[SP_COL(A)[j]]),& (SP_ROW(A)[SP_COL(A)[j+1]-1]), i, &k)) { write_num[SP_ID(A)](value, 0, SP_VAL(A), SP_COL(A)[j]+k); return 1; } else { write_num[SP_ID(A)](value, 0, &Zero, 0); return 0; } } static void spmatrix_setitem_ij(spmatrix *A, int_t i, int_t j, number *value) { int_t k, l; if (bsearch_int(&(SP_ROW(A)[SP_COL(A)[j]]), &(SP_ROW(A)[SP_COL(A)[j+1]-1]),i, &k)) { write_num[SP_ID(A)](SP_VAL(A), SP_COL(A)[j] + k, value, 0); return; } k += SP_COL(A)[j]; for (l=j+1; lk; l--) { SP_ROW(A)[l] = SP_ROW(A)[l-1]; write_num[SP_ID(A)](SP_VAL(A),l,SP_VAL(A),l-1); } SP_ROW(A)[k] = i; write_num[SP_ID(A)](SP_VAL(A), k, value, 0); } static int spmatrix_length(spmatrix *self) { return SP_NNZ(self); } static PyObject* spmatrix_subscr(spmatrix* self, PyObject* args) { int_t i = 0, j = 0, k; number val; matrix *Il = NULL, *Jl = NULL; /* single integer */ #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(args)) { i = PyLong_AS_LONG(args); #else if (PyInt_Check(args)) { i = PyInt_AS_LONG(args); #endif if ( i<-SP_LGT(self) || i >= SP_LGT(self) ) PY_ERR(PyExc_IndexError, "index out of range"); spmatrix_getitem_i(self, CWRAP(i,SP_LGT(self)), &val); return num2PyObject[SP_ID(self)](&val, 0); } else if (PyList_Check(args) || Matrix_Check(args) || PySlice_Check(args)) { if (!(Il = create_indexlist(SP_LGT(self), args))) return NULL; int_t i, idx, lgt = MAT_LGT(Il), nnz = 0, k = 0; /* count # elements in index list */ for (i=0; i= SP_LGT(self)) { Py_DECREF(Il); PY_ERR(PyExc_IndexError, "index out of range"); } nnz += spmatrix_getitem_i(self, CWRAP(idx,SP_LGT(self)), &val); } spmatrix *B = SpMatrix_New(lgt,1,nnz,SP_ID(self)); if (!B) { Py_DECREF(Il); return PyErr_NoMemory(); } SP_COL(B)[1] = nnz; /* fill up rowind and values */ for (i=0; i= 3 if (PyLong_Check(argI) && PyLong_Check(argJ)) { i = PyLong_AS_LONG(argI); j = PyLong_AS_LONG(argJ); #else if (PyInt_Check(argI) && PyInt_Check(argJ)) { i = PyInt_AS_LONG(argI); j = PyInt_AS_LONG(argJ); #endif if ( OUT_RNG(i, SP_NROWS(self)) || OUT_RNG(j, SP_NCOLS(self)) ) PY_ERR(PyExc_IndexError, "index out of range"); spmatrix_getitem_ij(self,CWRAP(i,SP_NROWS(self)), CWRAP(j,SP_NCOLS(self)), &val); return num2PyObject[SP_ID(self)](&val,0); } if (PySlice_Check(argI)) { int_t rowstart, rowstop, rowstep, rowlgt, rowcnt; #if PY_MAJOR_VERSION >= 3 if (PySlice_GetIndicesEx(argI, SP_NROWS(self), &rowstart, &rowstop, &rowstep, &rowlgt) < 0) return NULL; #else if (PySlice_GetIndicesEx((PySliceObject*)argI, SP_NROWS(self), &rowstart, &rowstop, &rowstep, &rowlgt) < 0) return NULL; #endif int_t colstart, colstop, colstep, collgt, colcnt; if (PySlice_Check(argJ)) { #if PY_MAJOR_VERSION >= 3 if (PySlice_GetIndicesEx(argJ, SP_NCOLS(self), &colstart, &colstop, &colstep, &collgt) < 0) return NULL; #else if (PySlice_GetIndicesEx((PySliceObject*)argJ, SP_NCOLS(self), &colstart, &colstop, &colstep, &collgt) < 0) return NULL; #endif } #if PY_MAJOR_VERSION >= 3 else if (PyLong_Check(argJ)){ j = PyLong_AS_LONG(argJ); #else else if (PyInt_Check(argJ)){ j = PyInt_AS_LONG(argJ); #endif if ( OUT_RNG(j, SP_NCOLS(self)) ) PY_ERR(PyExc_IndexError, "index out of range"); colstart = CWRAP(j,SP_NCOLS(self)); colstop = colstart; collgt = 1; colstep = 1; } else if (PyList_Check(argJ) || Matrix_Check(argJ)) { if (!(Jl = create_indexlist(SP_NCOLS(self), argJ))) return NULL; colstart = 0; colstop = MAT_LGT(Jl)-1; collgt = MAT_LGT(Jl); colstep = 1; } else PY_ERR_TYPE("invalid index argument"); int_t *colptr = calloc(collgt+1, sizeof(int_t)); if (!colptr) { if (Jl && !Matrix_Check(argJ)) { Py_DECREF(Jl); } return PyErr_NoMemory(); } for (colcnt=0; colcnt 0) { for (k=SP_COL(self)[j]; k=SP_COL(self)[j]; k--) { while (rowstart + rowcnt*rowstep > SP_ROW(self)[k] && rowcnt < rowlgt) rowcnt++; if (rowcnt == rowlgt) break; if (rowstart + rowcnt*rowstep == SP_ROW(self)[k]) { colptr[colcnt+1]++; rowcnt++; } } } } } ccs *A; if (!(A = alloc_ccs(rowlgt, collgt, colptr[collgt], SP_ID(self)))) { free(colptr); if (Jl && !Matrix_Check(argJ)) { Py_DECREF(Jl); } return PyErr_NoMemory(); } free(A->colptr); A->colptr = colptr; for (colcnt=0; colcntrowind[A->colptr[colcnt] + rowcnt] = SP_ROW(self)[k]; if (SP_ID(self) == DOUBLE) ((double *)A->values)[colptr[colcnt] + rowcnt] = SP_VALD(self)[k]; else ((complex *)A->values)[colptr[colcnt] + rowcnt] = SP_VALZ(self)[k]; rowcnt++; } } else { rowcnt = 0; i = 0; if (rowstep > 0) { for (k=SP_COL(self)[j]; krowind[colptr[colcnt] + i] = rowcnt; if (SP_ID(self) == DOUBLE) ((double *)A->values)[colptr[colcnt] + i] = SP_VALD(self)[k]; else ((complex *)A->values)[colptr[colcnt] + i] = SP_VALZ(self)[k]; rowcnt++; i++; } } } else { for (k=SP_COL(self)[j+1]-1; k>=SP_COL(self)[j]; k--) { while (rowstart + rowcnt*rowstep > SP_ROW(self)[k] && rowcnt < rowlgt) rowcnt++; if (rowcnt == rowlgt) break; if (rowstart + rowcnt*rowstep == SP_ROW(self)[k]) { A->rowind[colptr[colcnt] + i] = rowcnt; if (SP_ID(self) == DOUBLE) ((double *)A->values)[colptr[colcnt] + i] = SP_VALD(self)[k]; else ((complex *)A->values)[colptr[colcnt] + i] = SP_VALZ(self)[k]; rowcnt++; i++; } } } } } if (Jl && !Matrix_Check(argJ)) { Py_DECREF(Jl); } spmatrix *B = SpMatrix_New(A->nrows, A->ncols, 0, A->id); free_ccs(B->obj); B->obj = A; return (PyObject *)B; } if (!(Il = create_indexlist(SP_NROWS(self), argI)) || !(Jl = create_indexlist(SP_NCOLS(self), argJ))) { free_lists_exit(argI, argJ, Il, Jl, NULL); } int lgt_row = MAT_LGT(Il), lgt_col = MAT_LGT(Jl), nnz = 0; ccs *A = self->obj; spa *s = alloc_spa(A->nrows, A->id); if (!s) { PyErr_SetString(PyExc_MemoryError, "insufficient memory"); free_lists_exit(argI, argJ, Il, Jl, NULL); } for (j=0; jnz[CWRAP(MAT_BUFI(Il)[k], SP_NROWS(self))]; } spmatrix *B = SpMatrix_New(lgt_row, lgt_col,nnz,A->id); if (!B) { free_spa(s); PyErr_SetNone(PyExc_MemoryError); free_lists_exit(argI, argJ, Il, Jl, NULL); } nnz = 0; for (j=0; jnz[ CWRAP(MAT_BUFI(Il)[k], SP_NROWS(self))]) { if (A->id == DOUBLE) SP_VALD(B)[nnz] = ((double *)s->val) [CWRAP(MAT_BUFI(Il)[k],SP_NROWS(self))]; else SP_VALZ(B)[nnz] = ((complex *)s->val) [CWRAP(MAT_BUFI(Il)[k],SP_NROWS(self))]; SP_ROW(B) [nnz++] = k; SP_COL(B)[j+1]++; } } SP_COL(B)[j+1] += SP_COL(B)[j]; } free_spa(s); free_lists_exit(argI, argJ, Il, Jl, (PyObject *)B); } static int spmatrix_ass_subscr(spmatrix* self, PyObject* args, PyObject* value) { int_t i = 0, j = 0, id = SP_ID(self), decref_val = 0, arraystruct_nd = 0; char itype; number val, tempval; matrix *Il = NULL, *Jl = NULL; if (!value) PY_ERR_INT(PyExc_NotImplementedError, "cannot delete matrix entries"); if (!(PY_NUMBER(value) || Matrix_Check(value) || SpMatrix_Check(value))){ #if PY_MAJOR_VERSION < 3 if (PyObject_HasAttrString(value,"__array_struct__")) value = (PyObject *)Matrix_NewFromArrayStruct(value, -1, &arraystruct_nd); else #endif value = (PyObject *)Matrix_NewFromSequence(value, SP_ID(self)); if (!value) PY_ERR_INT(PyExc_NotImplementedError, "invalid type in assignment"); decref_val = 1; } int val_id = get_id(value, (PY_NUMBER(value) ? 1 : 0)); if (val_id > id) PY_ERR_INT(PyExc_TypeError, "invalid type in assignment"); /* assignment value is matrix or number ? */ if (PY_NUMBER(value)) { if (convert_num[id](&val, value, 1, 0)) PY_ERR_INT(PyExc_TypeError, "invalid argument type"); itype = 'n'; } else if (Matrix_Check(value) && MAT_LGT(value)==1) { convert_num[id](&val, value, 0, 0); itype = 'n'; } else if (Matrix_Check(value)) itype = 'd'; else itype = 's'; /* single integer */ #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(args)) { #else if (PyInt_Check(args)) { #endif if (itype != 'n') PY_ERR_INT(PyExc_IndexError, "incompatible sizes in assignment"); #if PY_MAJOR_VERSION >= 3 i = PyLong_AsLong(args); #else i = PyInt_AsLong(args); #endif if ( i<-SP_LGT(self) || i >= SP_LGT(self) ) PY_ERR_INT(PyExc_IndexError, "index out of range"); i = CWRAP(i,SP_LGT(self)); if (spmatrix_getitem_i(self, i, &tempval)) spmatrix_setitem_i(self, i, &val); else { if (!realloc_ccs(self->obj, SP_NNZ(self)+1)) PY_ERR_INT(PyExc_MemoryError, "Cannot reallocate sparse matrix"); spmatrix_setitem_i(self, i, &val); } return 0; } /* integer matrix list */ if (PyList_Check(args) || Matrix_Check(args) || PySlice_Check(args)) { if (!(Il = create_indexlist(SP_LGT(self), args))) { if (decref_val) { Py_DECREF(value); } return -1; } int_t i, lgtI = MAT_LGT(Il); int_t nnz = SP_NNZ(self)+MAT_LGT(Il); if (((itype == 'd') && ((lgtI != MAT_LGT(value) || MAT_NCOLS(value) != 1))) || (((itype == 's') && ((lgtI != SP_LGT(value)) || SP_NCOLS(value) != 1)))) { if (!Matrix_Check(args)) { Py_DECREF(Il); } if (decref_val) { Py_DECREF(value); } PY_ERR_INT(PyExc_TypeError, "incompatible sizes in assignment"); } /* ass. argument is dense matrix or number */ if (itype == 'd' || itype == 'n') { int_t *col_merge = calloc(SP_NCOLS(self)+1,sizeof(int_t)); int_t *row_merge = malloc(nnz*sizeof(int_t)); void *val_merge = malloc(nnz*E_SIZE[id]); int_list *ilist = malloc(lgtI*sizeof(int_list)); if (!col_merge || !row_merge || !val_merge || !ilist) { if (!Matrix_Check(args)) { Py_DECREF(Il); } free(col_merge); free(row_merge); free(val_merge); free(ilist); if (decref_val) { Py_DECREF(value); } PY_ERR_INT(PyExc_MemoryError, "insufficient memory"); } for (i=0; i0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key)) { row_merge[tot_cnt] = rhs_i; if (itype == 'n') write_num[id](val_merge, tot_cnt++, &val, 0); else convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, value, 0, ilist[rhs_cnt].value); col_merge[j+1]++; } if (rhs_cnt++ < lgtI-1) { rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); rhs_i = ilist[rhs_cnt].key % SP_NROWS(self); } } if (rhs_cnt0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key)) { row_merge[tot_cnt] = rhs_i; if (itype == 'n') write_num[id](val_merge, tot_cnt++, &val, 0); else convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, value, 0, ilist[rhs_cnt].value); col_merge[j+1]++; } if (rhs_cnt++ < lgtI-1) { rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); rhs_i = ilist[rhs_cnt].key % SP_NROWS(self); } } else { row_merge[tot_cnt] = SP_ROW(self)[i]; write_num[id](val_merge, tot_cnt++, SP_VAL(self), i); col_merge[j+1]++; } } while (rhs_cnt0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key)) { row_merge[tot_cnt] = rhs_i; if (itype == 'n') write_num[id](val_merge, tot_cnt++, &val, 0); else convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, value, 0, ilist[rhs_cnt].value); col_merge[j+1]++; } if (rhs_cnt++ < lgtI-1) { rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); rhs_i = ilist[rhs_cnt].key % SP_NROWS(self); } } } for (i=0; iobj, SP_NNZ(self)); } /* ass. argument is a sparse matrix */ else { int_list *ilist = malloc(lgtI*sizeof(int_list)); int_t *col_merge = calloc(SP_NCOLS(self)+1,sizeof(int_t)); int_t *row_merge = malloc(nnz*sizeof(int_t)); void *val_merge = malloc(nnz*E_SIZE[id]); if (!ilist || !col_merge || !row_merge || !val_merge) { free(ilist); free(col_merge); free(row_merge); free(val_merge); if (!Matrix_Check(args)) { Py_DECREF(Il); } if (decref_val) { Py_DECREF(value); } PY_ERR_INT(PyExc_MemoryError, "insufficient memory"); } for (i=0; i= 0 && (rhs_cnt==0 || (rhs_cnt>0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key))) { row_merge[tot_cnt] = rhs_i; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(value) + E_SIZE[val_id]*ilist[rhs_cnt].value, id, val_id, 1); col_merge[j+1]++; } if (rhs_cnt++ < lgtI-1) { rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); rhs_i = ilist[rhs_cnt].key % SP_NROWS(self); } } if (rhs_cnt= 0 && (rhs_cnt==0 || (rhs_cnt>0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key))) { row_merge[tot_cnt] = rhs_i; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(value) + E_SIZE[val_id]*ilist[rhs_cnt].value, id, val_id, 1); col_merge[j+1]++; } if (rhs_cnt++ < lgtI-1) { rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); rhs_i = ilist[rhs_cnt].key % SP_NROWS(self); } } else { row_merge[tot_cnt] = SP_ROW(self)[i]; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(self) + E_SIZE[id]*i, id, id, 1); col_merge[j+1]++; } } while (rhs_cnt= 0 && (rhs_cnt==0 || (rhs_cnt>0 && ilist[rhs_cnt].key != ilist[rhs_cnt-1].key))) { row_merge[tot_cnt] = rhs_i; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(value) + E_SIZE[val_id]*ilist[rhs_cnt].value, id, val_id, 1); col_merge[j+1]++; } if (rhs_cnt++ < lgtI-1) { rhs_j = ilist[rhs_cnt].key / SP_NROWS(self); rhs_i = ilist[rhs_cnt].key % SP_NROWS(self); } } } for (i=0; iobj, SP_NNZ(self)); } if (!Matrix_Check(args)) { Py_DECREF(Il); } if (decref_val) { Py_DECREF(value); } return 0; } /* remainding cases are different two argument indexing */ PyObject *argI = NULL, *argJ = NULL; if (!PyArg_ParseTuple(args, "OO", &argI, &argJ)) PY_ERR_INT(PyExc_TypeError, "invalid index arguments"); /* two integers, subscript form, handle separately */ #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(argI) && PyLong_Check(argJ)) { #else if (PyInt_Check(argI) && PyInt_Check(argJ)) { #endif if (itype != 'n') PY_ERR_INT(PyExc_TypeError, "argument has wrong size"); #if PY_MAJOR_VERSION >= 3 i = PyLong_AS_LONG(argI); j = PyLong_AS_LONG(argJ); #else i = PyInt_AS_LONG(argI); j = PyInt_AS_LONG(argJ); #endif if ( OUT_RNG(i, SP_NROWS(self)) || OUT_RNG(j, SP_NCOLS(self)) ) PY_ERR_INT(PyExc_IndexError, "index out of range"); i = CWRAP(i,SP_NROWS(self)); j = CWRAP(j,SP_NCOLS(self)); if (spmatrix_getitem_ij(self, i, j, &tempval)) spmatrix_setitem_ij(self, i, j, &val); else { if (!realloc_ccs(self->obj, SP_NNZ(self)+1)) PY_ERR_INT(PyExc_MemoryError, "insufficient memory"); spmatrix_setitem_ij(self, i, j, &val); } return 0; } if (!(Il = create_indexlist(SP_NROWS(self), argI)) || !(Jl = create_indexlist(SP_NCOLS(self), argJ))) { PyErr_SetNone(PyExc_MemoryError); free_lists_exit(argI,argJ,Il,Jl,-1); } if (decref_val && arraystruct_nd < 2 && MAT_LGT(value) == MAT_LGT(Il)*MAT_LGT(Jl)) { MAT_NROWS(value) = MAT_LGT(Il); MAT_NCOLS(value) = MAT_LGT(Jl); } int_t lgtI = MAT_LGT(Il), lgtJ = MAT_LGT(Jl); if ((itype == 'd' && (lgtI != MAT_NROWS(value) || lgtJ != MAT_NCOLS(value))) || (itype == 's' && (lgtI != SP_NROWS(value) || lgtJ != SP_NCOLS(value)))) { if (!Matrix_Check(argI)) { Py_DECREF(Il); } if (!Matrix_Check(argJ)) { Py_DECREF(Jl); } if (decref_val) { Py_DECREF(value); } PY_ERR_INT(PyExc_TypeError, "incompatible size of assignment"); } /* ass. argument is dense matrix or number */ if ((itype == 'd' || itype == 'n') && lgtI*lgtJ> 0) { int_t nnz = SP_NNZ(self)+lgtI*lgtJ; int_t *col_merge = calloc(SP_NCOLS(self)+1,sizeof(int_t)); int_t *row_merge = malloc(nnz*sizeof(int_t)); void *val_merge = malloc(nnz*E_SIZE[id]); int_list *Is = malloc(lgtI*sizeof(int_list)); int_list *Js = malloc(lgtJ*sizeof(int_list)); if (!Is || !Js || !col_merge || !row_merge || !val_merge) { if (!Matrix_Check(argI)) { Py_DECREF(Il); } if (!Matrix_Check(argJ)) { Py_DECREF(Jl); } free(Is); free(Js); free(col_merge); free(row_merge); free(val_merge); if (decref_val) { Py_DECREF(value); } PY_ERR_INT(PyExc_MemoryError, "insufficient memory"); } for (i=0; i0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key)) { row_merge[tot_cnt] = rhs_i; if (itype == 'n') write_num[id](val_merge, tot_cnt++, &val, 0); else convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, value, 0, Is[rhs_cnti].value + lgtI*Js[rhs_cntj].value); col_merge[j+1]++; } if (rhs_cnti++ < lgtI-1) rhs_i = Is[rhs_cnti].key; } if (rhs_cnti0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key)) { row_merge[tot_cnt] = rhs_i; if (itype == 'n') write_num[id](val_merge, tot_cnt++, &val, 0); else convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, value, 0, Is[rhs_cnti].value + lgtI*Js[rhs_cntj].value); col_merge[j+1]++; } if (rhs_cnti++ < lgtI-1) rhs_i = Is[rhs_cnti].key; } else { row_merge[tot_cnt] = SP_ROW(self)[i]; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(self) + E_SIZE[id]*i, id, id, 1); col_merge[j+1]++; } } while (rhs_cnti0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key)) { row_merge[tot_cnt] = rhs_i; if (itype == 'n') write_num[id](val_merge, tot_cnt++, &val, 0); else convert_num[id](val_merge + E_SIZE[id]*tot_cnt++, value, 0, Is[rhs_cnti].value + lgtI*Js[rhs_cntj].value); col_merge[j+1]++; } if (rhs_cnti++ < lgtI-1) rhs_i = Is[rhs_cnti].key; } } for (i=0; iobj, SP_NNZ(self)); } /* ass. argument is a sparse matrix */ else if (itype == 's' && lgtI*lgtJ > 0) { int_t nnz = SP_NNZ(self)+SP_NNZ(value); int_t *col_merge = calloc((SP_NCOLS(self)+1),sizeof(int_t)); int_t *row_merge = malloc(nnz*sizeof(int_t)); void *val_merge = malloc(nnz*E_SIZE[id]); int_list *Is = malloc(lgtI*sizeof(int_list)); int_list *Js = malloc(lgtJ*sizeof(int_list)); if (!Is || !Js || !col_merge || !row_merge || !val_merge) { if (!Matrix_Check(argI)) { Py_DECREF(Il); } if (!Matrix_Check(argJ)) { Py_DECREF(Jl); } free(Is); free(Js); free(col_merge); free(row_merge); free(val_merge); if (decref_val) { Py_DECREF(value); } PY_ERR_INT(PyExc_MemoryError,"insufficient memory"); } for (i=0; i= 0 && (rhs_cnti==0 || (rhs_cnti>0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key))) { row_merge[tot_cnt] = rhs_i; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(value) + E_SIZE[val_id]* (Is[rhs_cnti].value+rhs_offs_rptr), id, val_id, 1); col_merge[j+1]++; } if (rhs_cnti++ < lgtI-1) rhs_i = Is[rhs_cnti].key; } if (rhs_cnti= 0 && (rhs_cnti==0 || (rhs_cnti>0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key))) { row_merge[tot_cnt] = rhs_i; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(value) + E_SIZE[val_id]* (Is[rhs_cnti].value+rhs_offs_rptr), id, val_id, 1); col_merge[j+1]++; } if (rhs_cnti++ < lgtI-1) rhs_i = Is[rhs_cnti].key; } else { row_merge[tot_cnt] = SP_ROW(self)[i]; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(self) + E_SIZE[id]*i, id, id, 1); col_merge[j+1]++; } } while (rhs_cnti= 0 && (rhs_cnti == 0 || (rhs_cnti>0 && Is[rhs_cnti].key != Is[rhs_cnti-1].key))) { row_merge[tot_cnt] = rhs_i; convert_array(val_merge + E_SIZE[id]*tot_cnt++, SP_VAL(value) + E_SIZE[val_id]* (Is[rhs_cnti].value+rhs_offs_rptr), id, val_id, 1); col_merge[j+1]++; } if (rhs_cnti++ < lgtI-1) rhs_i = Is[rhs_cnti].key; } } for (i=0; iobj, SP_NNZ(self)); } if (!Matrix_Check(argI)) { Py_DECREF(Il); } if (!Matrix_Check(argJ)) { Py_DECREF(Jl); } if (decref_val) { Py_DECREF(value); } return 0; } static PyMappingMethods spmatrix_as_mapping = { (lenfunc)spmatrix_length, (binaryfunc)spmatrix_subscr, (objobjargproc)spmatrix_ass_subscr }; static PyObject * spmatrix_neg(spmatrix *self) { spmatrix *x = SpMatrix_NewFromSpMatrix(self,SP_ID(self)); if (!x) return PyErr_NoMemory(); int n=SP_NNZ(x); scal[SP_ID(self)](&n, &MinusOne[SP_ID(self)], SP_VAL(x), (int *)&One[INT]); return (PyObject *)x; } static PyObject * spmatrix_pos(spmatrix *self) { spmatrix *x = SpMatrix_NewFromSpMatrix(self,SP_ID(self)); if (!x) return PyErr_NoMemory(); return (PyObject *)x; } static PyObject * spmatrix_abs(spmatrix *self) { spmatrix *x = SpMatrix_New(SP_NROWS(self), SP_NCOLS(self), SP_NNZ(self), DOUBLE); if (!x) return PyErr_NoMemory(); int_t i; if (SP_ID(self) == DOUBLE) for (i=0; iobj, id))) return NULL; if (!(y = (Matrix_Check(other) ? (void *)Matrix_NewFromMatrix((matrix *)other, id) : (void *)convert_ccs(((spmatrix *)other)->obj, id)))) { if (x->id != id) free_ccs(x); return NULL; } if (sp_axpy[id]((add ? One[id] : MinusOne[id]), x, (Matrix_Check(other) ? MAT_BUF(y) : y), 1, SpMatrix_Check(other), 0, (void *)&z)) { if (x->id != id) free_ccs(x); if (Matrix_Check(other)) Py_DECREF((PyObject *)y); else if (((ccs *)y)->id != id) free_ccs(y); return PyErr_NoMemory(); } if (x->id != id) free_ccs(x); if (SpMatrix_Check(other)) { if (((ccs *)y)->id != id) free_ccs(y); spmatrix *ret = SpMatrix_New(SP_NROWS(other), SP_NCOLS(other), 0, id); if (!ret) return PyErr_NoMemory(); free_ccs(ret->obj); ret->obj = z; return (PyObject *)ret; } else return (PyObject *)y; } static PyObject * spmatrix_add(PyObject *self, PyObject *other) { if (!SpMatrix_Check(self) && SpMatrix_Check(other)) { void *ptr = other; other = self; self = ptr; } PyObject *ret, *tmp; if (PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other)==1)) if ((tmp = (PyObject *)dense((spmatrix *)self))) { ret = matrix_add(tmp, other); Py_DECREF(tmp); return ret; } else return NULL; else return spmatrix_add_helper(self, other, 1); } static PyObject * spmatrix_iadd(PyObject *self, PyObject *other) { if (!SpMatrix_Check(other)) PY_ERR_TYPE("invalid inplace operation"); int id = SP_ID(self); if (SP_ID(other) > id) PY_ERR_TYPE("incompatible types for inplace operation"); if ((SP_NROWS(self) != SP_NROWS(other)) || (SP_NCOLS(self) != SP_NCOLS(other))) PY_ERR_TYPE("incompatible dimensions"); ccs *x = ((spmatrix *)self)->obj, *y; void *z; if (!(y = convert_ccs(((spmatrix *)other)->obj, id))) return NULL; if (sp_axpy[id](One[id], x, y, 1, 1, 0, &z)) { if (y->id != id) free_ccs(y); return PyErr_NoMemory(); } free_ccs(x); ((spmatrix *)self)->obj = z; if (y->id != id) free_ccs(y); Py_INCREF(self); return self; } static PyObject * spmatrix_sub(PyObject *self, PyObject *other) { PyObject *ret, *tmp; if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self)==1)) { if ((tmp = (PyObject *)dense((spmatrix *)other))) { ret = matrix_sub(self, tmp); Py_DECREF(tmp); return ret; } else return NULL; } else if (PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other)==1)) { if ((tmp = (PyObject *)dense((spmatrix *)self))) { ret = matrix_sub(tmp, other); Py_DECREF(tmp); return ret; } else return NULL; } else if (!SpMatrix_Check(self) && SpMatrix_Check(other)) { return spmatrix_add_helper(other, self, 0); } else if (SpMatrix_Check(self) && !SpMatrix_Check(other)) { if ((ret = spmatrix_add_helper(self, other, 0))) { int n = MAT_LGT(other), id = MAT_ID(ret); scal[id](&n, &MinusOne[id], MAT_BUF(ret), (int *)&One[INT]); return ret; } else return NULL; } else return spmatrix_add_helper(other, self, 0); } static PyObject * spmatrix_isub(PyObject *self, PyObject *other) { if (!SpMatrix_Check(other)) PY_ERR_TYPE("invalid inplace operation"); int id = SP_ID(self); if (SP_ID(other) > id) PY_ERR_TYPE("incompatible types for inplace operation"); if ((SP_NROWS(self) != SP_NROWS(other)) || (SP_NCOLS(self) != SP_NCOLS(other))) PY_ERR_TYPE("incompatible dimensions"); ccs *x = ((spmatrix *)self)->obj, *y; void *z; if (!(y = convert_ccs(((spmatrix *)other)->obj, id))) return NULL; if (sp_axpy[id](MinusOne[id], y, x, 1, 1, 0, &z)) { if (y->id != id) free_ccs(y); return PyErr_NoMemory(); } free_ccs(x); ((spmatrix *)self)->obj = z; if (y->id != id) free_ccs(y); Py_INCREF(self); return self; } static PyObject * spmatrix_mul(PyObject *self, PyObject *other) { if (!(SpMatrix_Check(self) || Matrix_Check(self) || PY_NUMBER(self)) || !(SpMatrix_Check(other) || Matrix_Check(other) || PY_NUMBER(other))) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } int id = MAX(get_id(self, PY_NUMBER(self)),get_id(other, PY_NUMBER(other))); if (PY_NUMBER(self) || (Matrix_Check(self) && MAT_LGT(self) == 1 && !(SpMatrix_Check(other) && SP_NROWS(other) == 1)) || PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other) == 1 && !(SpMatrix_Check(self) && SP_NCOLS(self) == 1)) ) { spmatrix *ret = SpMatrix_NewFromSpMatrix((spmatrix *) (SpMatrix_Check(self) ? self : other), id); number val; convert_num[id](&val, !SpMatrix_Check(self) ? self : other, PY_NUMBER(other) || PY_NUMBER(self), 0); scal[id]((int *)&SP_NNZ(ret), &val, SP_VAL(ret), (void *)&One[INT]); return (PyObject *)ret; } else { if (X_NCOLS(self) != X_NROWS(other)) PY_ERR_TYPE("incompatible dimensions"); void *x, *y, *z = NULL; int sp_c = SpMatrix_Check(self) && SpMatrix_Check(other); PyObject *C = (sp_c ? (PyObject *)SpMatrix_New(SP_NROWS(self), SP_NCOLS(other), 0, id) : (PyObject *)Matrix_New(X_NROWS(self), X_NCOLS(other), id)); if (SpMatrix_Check(self)) x = convert_ccs(((spmatrix *)self)->obj, id); else x = convert_mtx_alloc((matrix *)self, id); if (SpMatrix_Check(other)) y = convert_ccs(((spmatrix *)other)->obj, id); else y = convert_mtx_alloc((matrix *)other, id); if (!C || !x || !y) { PyErr_SetNone(PyExc_MemoryError); Py_XDECREF(C); C = NULL; goto cleanup; } if (sp_gemm[id]('N', 'N', One[id], x, y, Zero[id], sp_c ? ((spmatrix *)C)->obj : MAT_BUF(C), SpMatrix_Check(self), SpMatrix_Check(other), sp_c, 0, &z, X_NROWS(self), X_NCOLS(other), X_NROWS(other))) { PyErr_SetNone(PyExc_MemoryError); Py_DECREF(C); C = NULL; } if (z) { free_ccs( ((spmatrix *)C)->obj ); ((spmatrix *)C)->obj = z; } cleanup: if (SpMatrix_Check(self)) { if (((ccs *)x)->id != id) free_ccs(x); } else if (MAT_ID(self) != id) free(x); if (SpMatrix_Check(other)) { if (((ccs *)y)->id != id) free_ccs(y); } else if (MAT_ID(other) != id) free(y); return (PyObject *)C; } } static PyObject * spmatrix_imul(PyObject *self, PyObject *other) { if (!(PY_NUMBER(other) || (Matrix_Check(other) && MAT_LGT(other) == 1))) PY_ERR_TYPE("invalid operands for sparse multiplication"); if (SP_ID(self) < get_id(other, PY_NUMBER(other))) PY_ERR_TYPE("invalid operands for inplace sparse multiplication"); number val; convert_num[SP_ID(self)](&val, other, !Matrix_Check(other), 0); scal[SP_ID(self)]((int *)&SP_NNZ(self), &val, SP_VAL(self), (void *)&One[INT]); Py_INCREF(self); return self; } static PyObject * spmatrix_div_generic(spmatrix *A, PyObject *B, int inplace) { if (!SpMatrix_Check(A) || !(PY_NUMBER(B) || (Matrix_Check(B) && MAT_LGT(B)) == 1)) PY_ERR_TYPE("invalid operands for sparse division"); int idA = get_id(A, 0); int idB = get_id(B, (Matrix_Check(B) ? 0 : 1)); int id = MAX(idA,idB); number n; convert_num[id](&n, B, (Matrix_Check(B) ? 0 : 1), 0); if (!inplace) { PyObject *ret = (PyObject *)SpMatrix_NewFromSpMatrix((spmatrix *)A, id); if (!ret) return NULL; if (div_array[id](SP_VAL(ret), n, SP_NNZ(ret))) { Py_DECREF(ret); return NULL; } return ret; } else { if (id != idA) PY_ERR_TYPE("invalid inplace operation"); if (div_array[id](SP_VAL(A), n, SP_NNZ(A))) return NULL; Py_INCREF(A); return (PyObject *)A; } } static PyObject * spmatrix_div(PyObject *self,PyObject *other) { return spmatrix_div_generic((spmatrix *)self, other, 0); } static PyObject * spmatrix_idiv(PyObject *self,PyObject *other) { return spmatrix_div_generic((spmatrix *)self, other, 1); } static int spmatrix_nonzero(matrix *self) { int i, res = 0; for (i=0; i= 3 0, /*nb_reserved*/ #else 0, /*nb_long*/ #endif 0, /*nb_float*/ #if PY_MAJOR_VERSION < 3 0, /*nb_oct*/ 0, /*nb_hex*/ #endif (binaryfunc)spmatrix_iadd, /*nb_inplace_add*/ (binaryfunc)spmatrix_isub, /*nb_inplace_subtract*/ (binaryfunc)spmatrix_imul, /*nb_inplace_multiply*/ #if PY_MAJOR_VERSION < 3 (binaryfunc)spmatrix_idiv, /*nb_inplace_divide*/ #endif 0, /*nb_inplace_remainder*/ 0, /*nb_inplace_power*/ 0, /*nb_inplace_lshift*/ 0, /*nb_inplace_rshift*/ 0, /*nb_inplace_and*/ 0, /*nb_inplace_xor*/ 0, /*nb_inplace_or*/ 0, /*nb_floor_divide */ #if PY_MAJOR_VERSION >= 3 (binaryfunc)spmatrix_div, /* nb_true_divide */ #else 0, /* nb_true_divide */ #endif 0, /* nb_inplace_floor_divide */ #if PY_MAJOR_VERSION >= 3 (binaryfunc)spmatrix_idiv, /* nb_inplace_true_divide */ 0, /* nb_index */ #else 0, /* nb_inplace_true_divide */ #endif }; /*********************** Iterator **************************/ typedef struct { PyObject_HEAD long index; spmatrix *mObj; /* Set to NULL when iterator is exhausted */ } spmatrixiter; static PyTypeObject spmatrixiter_tp; #define SpMatrixIter_Check(O) PyObject_TypeCheck(O, &spmatrixiter_tp) static PyObject * spmatrix_iter(spmatrix *obj) { spmatrixiter *it; if (!SpMatrix_Check(obj)) { PyErr_BadInternalCall(); return NULL; } spmatrixiter_tp.tp_iter = PyObject_SelfIter; spmatrixiter_tp.tp_getattro = PyObject_GenericGetAttr; it = PyObject_GC_New(spmatrixiter, &spmatrixiter_tp); if (it == NULL) return NULL; Py_INCREF(obj); it->index = 0; it->mObj = obj; PyObject_GC_Track(it); return (PyObject *)it; } static void spmatrixiter_dealloc(spmatrixiter *it) { PyObject_GC_UnTrack(it); Py_XDECREF(it->mObj); PyObject_GC_Del(it); } static int spmatrixiter_traverse(spmatrixiter *it, visitproc visit, void *arg) { if (it->mObj == NULL) return 0; return visit((PyObject *)(it->mObj), arg); } static PyObject * spmatrixiter_next(spmatrixiter *it) { assert(SpMatrixIter_Check(it)); if (it->index >= SP_NNZ(it->mObj)) return NULL; return num2PyObject[SP_ID(it->mObj)](SP_VAL(it->mObj), it->index++); } static PyTypeObject spmatrixiter_tp = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, /* ob_size */ #endif "spmatrixiter", /* tp_name */ sizeof(spmatrixiter), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)spmatrixiter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compar */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)spmatrixiter_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ (iternextfunc)spmatrixiter_next, /* tp_iternext */ 0, /* tp_methods */ }; PyTypeObject spmatrix_tp = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, #endif "cvxopt.base.spmatrix", sizeof(spmatrix), 0, (destructor)spmatrix_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)spmatrix_repr, /* tp_repr */ &spmatrix_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ &spmatrix_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ (reprfunc)spmatrix_str, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ #if PY_MAJOR_VERSION >= 3 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ #else Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ #endif 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ (richcmpfunc)spmatrix_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ (getiterfunc)spmatrix_iter, /* tp_iter */ 0, /* tp_iternext */ spmatrix_methods, /* tp_methods */ 0, /* tp_members */ spmatrix_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ spmatrix_new, /* tp_new */ }; cvxopt-1.1.4/src/C/umfpack.c0000644000175000017500000005047711674452555014664 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cvxopt.h" #include "umfpack.h" #include "misc.h" #if (SIZEOF_INT < SIZEOF_LONG) #define UMFD(name) umfpack_dl_ ## name #define UMFZ(name) umfpack_zl_ ## name #else #define UMFD(name) umfpack_di_ ## name #define UMFZ(name) umfpack_zi_ ## name #endif const int E_SIZE[] = {sizeof(int_t), sizeof(double), sizeof(complex)}; static char umfpack_error[20]; PyDoc_STRVAR(umfpack__doc__,"Interface to the UMFPACK library.\n\n" "Routines for symbolic and numeric LU factorization of sparse\n" "matrices and for solving sparse sets of linear equations.\n" "The default control settings of UMPFACK are used.\n\n" "See also http://www.cise.ufl.edu/research/sparse/umfpack."); #if PY_MAJOR_VERSION >= 3 static void free_umfpack_d_symbolic(void *F) { void *Fptr = PyCapsule_GetPointer(F, PyCapsule_GetName(F)); UMFD(free_symbolic)(&Fptr); } #else static void free_umfpack_d_symbolic(void *F, void *descr) { UMFD(free_symbolic)(&F); } #endif #if PY_MAJOR_VERSION >= 3 static void free_umfpack_z_symbolic(void *F) { void *Fptr = PyCapsule_GetPointer(F, PyCapsule_GetName(F)); UMFZ(free_symbolic)(&Fptr); } #else static void free_umfpack_z_symbolic(void *F, void *descr) { UMFZ(free_symbolic)(&F); } #endif #if PY_MAJOR_VERSION >= 3 static void free_umfpack_d_numeric(void *F) { void *Fptr = PyCapsule_GetPointer(F, PyCapsule_GetName(F)); UMFD(free_numeric)(&Fptr); } #else static void free_umfpack_d_numeric(void *F, void *descr) { UMFD(free_numeric)(&F); } #endif #if PY_MAJOR_VERSION >= 3 static void free_umfpack_z_numeric(void *F) { void *Fptr = PyCapsule_GetPointer(F, PyCapsule_GetName(F)); UMFZ(free_numeric)(&Fptr); } #else static void free_umfpack_z_numeric(void *F, void *descr) { UMFZ(free_numeric)(&F); } #endif static char doc_linsolve[] = "Solves a sparse set of linear equations.\n\n" "linsolve(A, B, trans='N', nrhs=B.size[1], ldB=max(1,B.size[0]),\n" " offsetB=0)\n\n" "PURPOSE\n" "If trans is 'N', solves A*X = B.\n" "If trans is 'T', solves A^T*X = B.\n" "If trans is 'C', solves A^H*X = B.\n" "A is a sparse n by n matrix, and B is n by nrhs.\n" "On exit B is replaced by the solution. A is not modified.\n\n" "ARGUMENTS\n" "A square sparse matrix\n\n" "B dense matrix of the same type as A, stored following \n" " the BLAS conventions\n\n" "trans 'N', 'T' or 'C'\n\n" "nrhs integer. If negative, the default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetB nonnegative integer"; static PyObject* linsolve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A; matrix *B; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; #endif char trans='N'; double info[UMFPACK_INFO]; int oB=0, n, nrhs=-1, ldB=0, k; void *symbolic, *numeric, *x; char *kwlist[] = {"A", "B", "trans", "nrhs", "ldB", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ciii", kwlist, &A, &B, &trans_, &nrhs, &ldB, &oB)) return NULL; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|ciii", kwlist, &A, &B, &trans, &nrhs, &ldB, &oB)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A must be a square sparse matrix"); n = SP_NROWS(A); if (!Matrix_Check(B) || MAT_ID(B) != SP_ID(A)) PY_ERR_TYPE("B must a dense matrix of the same numeric type " "as A"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue("i", 0); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B"); if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (SP_ID(A) == DOUBLE) UMFD(symbolic)(n, n, SP_COL(A), SP_ROW(A), SP_VAL(A), &symbolic, NULL, info); else UMFZ(symbolic)(n, n, SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, &symbolic, NULL, info); if (info[UMFPACK_STATUS] != UMFPACK_OK){ if (SP_ID(A) == DOUBLE) UMFD(free_symbolic)(&symbolic); else UMFZ(free_symbolic)(&symbolic); if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory) return PyErr_NoMemory(); else { snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR", (int) info[UMFPACK_STATUS]); PyErr_SetString(PyExc_ValueError, umfpack_error); return NULL; } } if (SP_ID(A) == DOUBLE) { UMFD(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), symbolic, &numeric, NULL, info); UMFD(free_symbolic)(&symbolic); } else { UMFZ(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, symbolic, &numeric, NULL, info); UMFZ(free_symbolic)(&symbolic); } if (info[UMFPACK_STATUS] != UMFPACK_OK){ if (SP_ID(A) == DOUBLE) UMFD(free_numeric)(&numeric); else UMFZ(free_numeric)(&numeric); if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory) return PyErr_NoMemory(); else { if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix) PyErr_SetString(PyExc_ArithmeticError, "singular " "matrix"); else { snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR", (int) info[UMFPACK_STATUS]); PyErr_SetString(PyExc_ValueError, umfpack_error); } return NULL; } } if (!(x = malloc(n*E_SIZE[SP_ID(A)]))) { if (SP_ID(A) == DOUBLE) UMFD(free_numeric)(&numeric); else UMFZ(free_numeric)(&numeric); return PyErr_NoMemory(); } for (k=0; kbuffer + (k*ldB + oB)*E_SIZE[SP_ID(A)], x, n*E_SIZE[SP_ID(A)]); else break; } free(x); if (SP_ID(A) == DOUBLE) UMFD(free_numeric)(&numeric); else UMFZ(free_numeric)(&numeric); if (info[UMFPACK_STATUS] != UMFPACK_OK){ if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory) return PyErr_NoMemory(); else { if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix) PyErr_SetString(PyExc_ArithmeticError, "singular " "matrix"); else { snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR", (int) info[UMFPACK_STATUS]); PyErr_SetString(PyExc_ValueError, umfpack_error); } return NULL; } } return Py_BuildValue(""); } static char doc_symbolic[] = "Symbolic LU factorization of a sparse matrix.\n\n" "F = symbolic(A)\n\n" "ARGUMENTS\n" "A sparse matrix with at least one row and at least one\n" " column. A may be rectangular.\n\n" "F the symbolic factorization as an opaque C object"; static PyObject* symbolic(PyObject *self, PyObject *args) { spmatrix *A; double info[UMFPACK_INFO]; void *symbolic; if (!PyArg_ParseTuple(args, "O", &A)) return NULL; if (!SpMatrix_Check(A)) PY_ERR_TYPE("A must be a sparse matrix"); if (SP_NCOLS(A) == 0 || SP_NROWS(A) == 0) { PyErr_SetString(PyExc_ValueError, "A must have at least one " "row and column"); return NULL; } switch (SP_ID(A)){ case DOUBLE: UMFD(symbolic)(SP_NROWS(A), SP_NCOLS(A), SP_COL(A), SP_ROW(A), SP_VAL(A), &symbolic, NULL, info); if (info[UMFPACK_STATUS] == UMFPACK_OK) #if PY_MAJOR_VERSION >= 3 return (PyObject *) PyCapsule_New( (void *) symbolic, "UMFPACK SYM D FACTOR", (PyCapsule_Destructor) &free_umfpack_d_symbolic); #else return (PyObject *) PyCObject_FromVoidPtrAndDesc( (void *) symbolic, "UMFPACK SYM D FACTOR", free_umfpack_d_symbolic); #endif else UMFD(free_symbolic)(&symbolic); break; case COMPLEX: UMFZ(symbolic)(SP_NROWS(A), SP_NCOLS(A), SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, &symbolic, NULL, info); if (info[UMFPACK_STATUS] == UMFPACK_OK) #if PY_MAJOR_VERSION >= 3 return (PyObject *) PyCapsule_New( (void *) symbolic, "UMFPACK SYM Z FACTOR", (PyCapsule_Destructor) &free_umfpack_z_symbolic); #else return (PyObject *) PyCObject_FromVoidPtrAndDesc( (void *) symbolic, "UMFPACK SYM Z FACTOR", free_umfpack_z_symbolic); #endif else UMFZ(free_symbolic)(&symbolic); break; } if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory) return PyErr_NoMemory(); else { snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR", (int) info[UMFPACK_STATUS]); PyErr_SetString(PyExc_ValueError, umfpack_error); return NULL; } } static char doc_numeric[] = "Numeric LU factorization of a sparse matrix, given a symbolic\n" "factorization computed by umfpack.symbolic. Raises an\n" "ArithmeticError if A is singular.\n\n" "Fn = numeric(A, Fs)\n\n" "ARGUMENTS\n" "A sparse matrix; may be rectangular\n\n" "Fs symbolic factorization of A, or a matrix with the same\n" " sparsity pattern, dimensions, and typecode as A, \n" " created by umfpack.symbolic\n\n" "Fn the numeric factorization, as an opaque C object"; static PyObject* numeric(PyObject *self, PyObject *args) { spmatrix *A; PyObject *Fs; double info[UMFPACK_INFO]; void *numeric; #if PY_MAJOR_VERSION >= 3 void *Fsptr; const char *descrd = "UMFPACK SYM D FACTOR"; const char *descrz = "UMFPACK SYM Z FACTOR"; #endif if (!PyArg_ParseTuple(args, "OO", &A, &Fs)) return NULL; if (!SpMatrix_Check(A)) PY_ERR_TYPE("A must be a sparse matrix"); #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(Fs)) err_CO("Fs"); #else if (!PyCObject_Check(Fs)) err_CO("Fs"); #endif switch (SP_ID(A)) { case DOUBLE: #if PY_MAJOR_VERSION >= 3 TypeCheck_Capsule(Fs, descrd, "Fs is not the UMFPACK symbolic " "factor of a 'd' matrix"); if (!(Fsptr = (void *) PyCapsule_GetPointer(Fs, descrd))) err_CO("Fs"); UMFD(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), Fsptr, &numeric, NULL, info); #else TypeCheck_CObject(Fs, "UMFPACK SYM D FACTOR", "Fs is not " "the UMFPACK symbolic factor of a 'd' matrix"); UMFD(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), (void *) PyCObject_AsVoidPtr(Fs), &numeric, NULL, info); #endif if (info[UMFPACK_STATUS] == UMFPACK_OK) #if PY_MAJOR_VERSION >= 3 return (PyObject *) PyCapsule_New( (void *) numeric, "UMFPACK NUM D FACTOR", (PyCapsule_Destructor) &free_umfpack_d_numeric); #else return (PyObject *) PyCObject_FromVoidPtrAndDesc( (void *) numeric, "UMFPACK NUM D FACTOR", free_umfpack_d_numeric); #endif else UMFD(free_numeric)(&numeric); break; case COMPLEX: #if PY_MAJOR_VERSION >= 3 TypeCheck_Capsule(Fs, descrz, "Fs is not the UMFPACK symbolic " "factor of a 'z' matrix"); if (!(Fsptr = (void *) PyCapsule_GetPointer(Fs, descrz))) err_CO("Fs"); UMFZ(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, Fsptr, &numeric, NULL, info); #else TypeCheck_CObject(Fs, "UMFPACK SYM Z FACTOR", "Fs is not " "the UMFPACK symbolic factor of a 'z' matrix"); UMFZ(numeric)(SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, (void *) PyCObject_AsVoidPtr(Fs), &numeric, NULL, info); #endif if (info[UMFPACK_STATUS] == UMFPACK_OK) #if PY_MAJOR_VERSION >= 3 return (PyObject *) PyCapsule_New( (void *) numeric, "UMFPACK NUM Z FACTOR", (PyCapsule_Destructor) &free_umfpack_z_numeric); #else return (PyObject *) PyCObject_FromVoidPtrAndDesc( (void *) numeric, "UMFPACK NUM Z FACTOR", free_umfpack_z_numeric); #endif else UMFZ(free_numeric)(&numeric); break; } if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory) return PyErr_NoMemory(); else { if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix) PyErr_SetString(PyExc_ArithmeticError, "singular matrix"); else { snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR", (int) info[UMFPACK_STATUS]); PyErr_SetString(PyExc_ValueError, umfpack_error); } return NULL; } } static char doc_solve[] = "Solves a factored set of linear equations.\n\n" "solve(A, F, B, trans='N', nrhs=B.size[1], ldB=max(1,B.size[0]),\n" " offsetB=0)\n\n" "PURPOSE\n" "If trans is 'N', solves A*X = B.\n" "If trans is 'T', solves A^T*X = B.\n" "If trans is 'C', solves A^H*X = B.\n" "A is a sparse n by n matrix, and B is n by nrhs. F is the\n" "numeric factorization of A, computed by umfpack.numeric.\n" "On exit B is replaced by the solution. A is not modified.\n\n" "ARGUMENTS\n" "A square sparse matrix\n\n" "F numeric factorization, as returned by umfpack.numeric\n" "\n" "B dense matrix of the same type as A, stored following \n" " the BLAS conventions\n\n" "trans 'N', 'T' or 'C'\n\n" "nrhs integer. If negative, the default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetB nonnegative integer"; static PyObject* solve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A; PyObject *F; matrix *B; #if PY_MAJOR_VERSION >= 3 int trans_ = 'N'; const char *descrd = "UMFPACK NUM D FACTOR"; const char *descrz = "UMFPACK NUM Z FACTOR"; #endif char trans='N'; double *x, info[UMFPACK_INFO]; int oB=0, n, ldB=0, nrhs=-1, k; char *kwlist[] = {"A", "F", "B", "trans", "nrhs", "ldB", "offsetB", NULL}; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|Ciii", kwlist, &A, &F, &B, &trans_, &nrhs, &ldB, &oB)) return NULL; trans = (char) trans_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|ciii", kwlist, &A, &F, &B, &trans, &nrhs, &ldB, &oB)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A must a square sparse matrix"); n = SP_NROWS(A); #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F)) err_CO("F"); if (SP_ID(A) == DOUBLE) { TypeCheck_Capsule(F, descrd, "F is not the UMFPACK numeric factor " "of a 'd' matrix"); } else { TypeCheck_Capsule(F, descrz, "F is not the UMFPACK numeric factor " "of a 'z' matrix"); } #else if (!PyCObject_Check(F)) err_CO("F"); if (SP_ID(A) == DOUBLE) { TypeCheck_CObject(F, "UMFPACK NUM D FACTOR", "F is not the " "UMFPACK numeric factor of a 'd' matrix"); } else { TypeCheck_CObject(F, "UMFPACK NUM Z FACTOR", "F is not the " "UMFPACK numeric factor of a 'z' matrix"); } #endif if (!Matrix_Check(B) || MAT_ID(B) != SP_ID(A)) PY_ERR_TYPE("B must a dense matrix of the same numeric type " "as A"); if (nrhs < 0) nrhs = B->ncols; if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldB == 0) ldB = MAX(1,B->nrows); if (ldB < MAX(1,n)) err_ld("ldB"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B"); if (trans != 'N' && trans != 'T' && trans != 'C') err_char("trans", "'N', 'T', 'C'"); if (!(x = malloc(n*E_SIZE[SP_ID(A)]))) return PyErr_NoMemory(); for (k=0; k= 3 UMFD(solve)(trans == 'N' ? UMFPACK_A : UMFPACK_Aat, SP_COL(A), SP_ROW(A), SP_VAL(A), x, MAT_BUFD(B) + k*ldB + oB, (void *) PyCapsule_GetPointer(F, descrd), NULL, info); #else UMFD(solve)(trans == 'N' ? UMFPACK_A : UMFPACK_Aat, SP_COL(A), SP_ROW(A), SP_VAL(A), x, MAT_BUFD(B) + k*ldB + oB, (void *) PyCObject_AsVoidPtr(F), NULL, info); #endif else #if PY_MAJOR_VERSION >= 3 UMFZ(solve)(trans == 'N' ? UMFPACK_A : trans == 'C' ? UMFPACK_At : UMFPACK_Aat, SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, x, NULL, (double *)(MAT_BUFZ(B) + k*ldB + oB), NULL, (void *) PyCapsule_GetPointer(F, descrz), NULL, info); #else UMFZ(solve)(trans == 'N' ? UMFPACK_A : trans == 'C' ? UMFPACK_At : UMFPACK_Aat, SP_COL(A), SP_ROW(A), SP_VAL(A), NULL, x, NULL, (double *)(MAT_BUFZ(B) + k*ldB + oB), NULL, (void *) PyCObject_AsVoidPtr(F), NULL, info); #endif if (info[UMFPACK_STATUS] == UMFPACK_OK) memcpy(B->buffer + (k*ldB + oB)*E_SIZE[SP_ID(A)], x, n*E_SIZE[SP_ID(A)]); else break; } free(x); if (info[UMFPACK_STATUS] != UMFPACK_OK){ if (info[UMFPACK_STATUS] == UMFPACK_ERROR_out_of_memory) return PyErr_NoMemory(); else { if (info[UMFPACK_STATUS] == UMFPACK_WARNING_singular_matrix) PyErr_SetString(PyExc_ArithmeticError, "singular matrix"); else { snprintf(umfpack_error,20,"%s %i","UMFPACK ERROR", (int) info[UMFPACK_STATUS]); PyErr_SetString(PyExc_ValueError, umfpack_error); } return NULL; } } return Py_BuildValue(""); } static PyMethodDef umfpack_functions[] = { {"linsolve", (PyCFunction) linsolve, METH_VARARGS|METH_KEYWORDS, doc_linsolve}, {"symbolic", (PyCFunction) symbolic, METH_VARARGS, doc_symbolic}, {"numeric", (PyCFunction) numeric, METH_VARARGS, doc_numeric}, {"solve", (PyCFunction) solve, METH_VARARGS|METH_KEYWORDS, doc_solve}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef umfpack_module = { PyModuleDef_HEAD_INIT, "umfpack", umfpack__doc__, -1, umfpack_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_umfpack(void) { PyObject *m; if (!(m = PyModule_Create(&umfpack_module))) return NULL; if (import_cvxopt() < 0) return NULL; return m; } #else PyMODINIT_FUNC initumfpack(void) { PyObject *m; m = Py_InitModule3("cvxopt.umfpack", umfpack_functions, umfpack__doc__); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/0000755000175000017500000000000011674452555020132 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/README0000644000175000017500000000056711674452555021022 0ustar sonnesonneThis directory contains CVXOPT specific modifications to the libraries in SuiteSparse necessary to build them with CVXOPT using distutils. The additions are very minor; the directory contains a number of files for different numerical types (int, long, single and double precision floating point etc.) that would normally be automatically generated by the C preprocessor. cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/0000755000175000017500000000000011674452555021560 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_symbolic_usage.c0000644000175000017500000000011611674452555026300 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_start_front.c0000644000175000017500000000011311674452555025635 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_numeric.c0000644000175000017500000000011511674452555026065 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_valid.c0000644000175000017500000000010311674452555024151 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_valid.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_ltsolve.c0000644000175000017500000000010711674452555024763 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_singletons.c0000644000175000017500000000011411674452555025267 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_singletons.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_global.c0000644000175000017500000000006511674452555024006 0ustar sonnesonne#include "../../SuiteSparse/AMD/Source/amd_global.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_qsymbolic.c0000644000175000017500000000011511674452555026105 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_row_search.c0000644000175000017500000000011211674452555025423 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_numeric.c0000644000175000017500000000012011674452555026542 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_numeric.c0000644000175000017500000000011511674452555026113 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_fsize.c0000644000175000017500000000010711674452555024224 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_fsize.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lsolve.c0000644000175000017500000000011011674452555024546 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_symbolic.c0000644000175000017500000000012011674452555026243 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble.c0000644000175000017500000000011011674452555025032 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_transpose.c0000644000175000017500000000011111674452555025256 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble.c0000644000175000017500000000011011674452555025060 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_assemble_fixq.c0000644000175000017500000000012511674452555026115 0ustar sonnesonne#define ZINT #define FIXQ #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale.c0000644000175000017500000000010711674452555024365 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_scale.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_uhsolve.c0000644000175000017500000000014111674452555024733 0ustar sonnesonne#define DLONG #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel.c0000644000175000017500000000010611674452555024524 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_numeric.c0000644000175000017500000000011311674452555025571 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_wrapup.c0000644000175000017500000000011511674452555026150 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_wrapup.c0000644000175000017500000000011711674452555026127 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_2by2.c0000644000175000017500000000010411674452555024020 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_extend_front.c0000644000175000017500000000011411674452555025742 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale_column.c0000644000175000017500000000011611674452555025714 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_qsymbolic.c0000644000175000017500000000011711674452555026140 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_qsymbolic.c0000644000175000017500000000011711674452555026112 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_numeric.c0000644000175000017500000000011511674452555025550 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_head_block.c0000644000175000017500000000012411674452555027355 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_realloc.c0000644000175000017500000000010711674452555024522 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_realloc.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lsolve.c0000644000175000017500000000010611674452555024550 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_garbage_collection.c0000644000175000017500000000012211674452555027073 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_singletons.c0000644000175000017500000000011211674452555025262 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_singletons.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_grow_front.c0000644000175000017500000000011211674452555025455 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_start_front.c0000644000175000017500000000011511674452555025642 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_utsolve.c0000644000175000017500000000010711674452555024774 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_build_tuples.c0000644000175000017500000000011411674452555025736 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_analyze.c0000644000175000017500000000010711674452555024544 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_analyze.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_init_front.c0000644000175000017500000000011311674452555025415 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_symbolic.c0000644000175000017500000000011511674452555025755 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_postorder.c0000644000175000017500000000010611674452555025073 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_postorder.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_init.c0000644000175000017500000000011311674452555025545 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble.c0000644000175000017500000000011211674452555025037 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_element.c0000644000175000017500000000012311674452555026735 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_set_stats.c0000644000175000017500000000011311674452555025256 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_element.c0000644000175000017500000000012111674452555026730 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_tuple_lengths.c0000644000175000017500000000011511674452555026147 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_transpose.c0000644000175000017500000000011311674452555025311 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_create_elememt.c0000644000175000017500000000012011674452555026216 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_grow_front.c0000644000175000017500000000011411674452555025462 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_tuple_lengths.c0000644000175000017500000000011711674452555026154 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel_init.c0000644000175000017500000000011511674452555025552 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_2by2.c0000644000175000017500000000010711674452555024026 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_kernel.c0000644000175000017500000000011011674452555024522 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_alloc_tail_block.c0000644000175000017500000000012411674452555027405 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel_init.c0000644000175000017500000000011311674452555025573 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_numeric.c0000644000175000017500000000011311674452555025543 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_uhsolve.c0000644000175000017500000000013711674452555024763 0ustar sonnesonne#define ZINT #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_solve.c0000644000175000017500000000010511674452555024421 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu_drop.c0000644000175000017500000000012511674452555026153 0ustar sonnesonne#define ZINT #define DROP #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_set_stats.c0000644000175000017500000000011311674452555025304 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale.c0000644000175000017500000000010511674452555024332 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_scale.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_free_tail_block.c0000644000175000017500000000012511674452555027240 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_solve.c0000644000175000017500000000011111674452555025227 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_numeric.c0000644000175000017500000000012011674452555026570 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_free_symbolic.c0000644000175000017500000000012111674452555026750 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_extend_front.c0000644000175000017500000000011611674452555025775 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_ltsolve.c0000644000175000017500000000011111674452555024733 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_row_search.c0000644000175000017500000000011411674452555025430 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_grow_front.c0000644000175000017500000000011411674452555025434 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_free_tail_block.c0000644000175000017500000000012311674452555027205 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_utsolve.c0000644000175000017500000000011111674452555024772 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_dump.c0000644000175000017500000000010111674452555024012 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_dump.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_symbolic_usage.c0000644000175000017500000000011611674452555026252 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_usolve.c0000644000175000017500000000011011674452555024557 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_create_element.c0000644000175000017500000000011611674452555026221 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_lhsolve.c0000644000175000017500000000013711674452555024724 0ustar sonnesonne#define DINT #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_usolve.c0000644000175000017500000000011011674452555024605 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_2.c0000644000175000017500000000007711674452555023225 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_2.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale_column.c0000644000175000017500000000011411674452555025735 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_tuple_lengths.c0000644000175000017500000000011711674452555026126 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_is_permutation.c0000644000175000017500000000012011674452555026141 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_is_permutation.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_solve.c0000644000175000017500000000010711674452555024400 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_solve.c0000644000175000017500000000011111674452555025255 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_kernel.c0000644000175000017500000000010611674452555024552 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_post_tree.c0000644000175000017500000000010711674452555025062 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_post_tree.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_order.c0000644000175000017500000000010311674452555024165 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_order.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lhsolve.c0000644000175000017500000000013711674452555024752 0ustar sonnesonne#define ZINT #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_blas3_update.c0000644000175000017500000000011411674452555025637 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_wrapup.c0000644000175000017500000000011711674452555026155 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_colamd.c0000644000175000017500000000011011674452555024335 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_colamd.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_apply_order.c0000644000175000017500000000011411674452555025422 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_apply_order.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_create_element.c0000644000175000017500000000011611674452555026247 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_2.c0000644000175000017500000000007611674452555023221 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_2.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_tail_block.c0000644000175000017500000000012611674452555027364 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel.c0000644000175000017500000000011011674452555024550 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_kernel.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_valid_numeric.c0000644000175000017500000000011711674452555026072 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_init_memoryspace.c0000644000175000017500000000012611674452555027456 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu_drop.c0000644000175000017500000000012611674452555026131 0ustar sonnesonne#define DLONG #define DROP #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_kernel_init.c0000644000175000017500000000011511674452555025600 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_init.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_init_memoryspace.c0000644000175000017500000000012411674452555027451 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_usolve.c0000644000175000017500000000010611674452555024607 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_fsize.c0000644000175000017500000000010511674452555024217 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_fsize.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_element.c0000644000175000017500000000012111674452555026702 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_free_tail_block.c0000644000175000017500000000012511674452555027212 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_solve.c0000644000175000017500000000011311674452555025234 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_assemble_fixq.c0000644000175000017500000000012611674452555026073 0ustar sonnesonne#define DLONG #define FIXQ #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_valid_symbolic.c0000644000175000017500000000011611674452555026273 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_free_tail_block.c0000644000175000017500000000012311674452555027233 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_scale_column.c0000644000175000017500000000011411674452555025707 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_symbolic.c0000644000175000017500000000012011674452555026271 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_2by2.c0000644000175000017500000000010411674452555024046 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble.c0000644000175000017500000000011211674452555025065 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_build_tuples.c0000644000175000017500000000011611674452555025743 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_assemble_fixq.c0000644000175000017500000000012511674452555026067 0ustar sonnesonne#define DINT #define FIXQ #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_head_block.c0000644000175000017500000000012411674452555027327 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_transpose.c0000644000175000017500000000011111674452555025304 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_aat.c0000644000175000017500000000010011674452555023611 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_aat.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_head_block.c0000644000175000017500000000012611674452555027334 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_ltsolve.c0000644000175000017500000000010711674452555024735 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_create_elememt.c0000644000175000017500000000012011674452555026244 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_create_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_local_search.c0000644000175000017500000000011611674452555025715 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_init_front.c0000644000175000017500000000011411674452555025421 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_start_front.c0000644000175000017500000000011511674452555025614 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_symbolic.c0000644000175000017500000000012311674452555026727 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_defaults.c0000644000175000017500000000010611674452555024664 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_defaults.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu.c0000644000175000017500000000011011674452555025073 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_build_tuples.c0000644000175000017500000000011411674452555025764 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_extend_front.c0000644000175000017500000000011411674452555025770 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_free_numeric.c0000644000175000017500000000012211674452555026547 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_store_lu.c0000644000175000017500000000011211674452555025100 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_1.c0000644000175000017500000000007711674452555023224 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_1.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_apply_order.c0000644000175000017500000000011311674452555025416 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_apply_order.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_tuple_lengths.c0000644000175000017500000000011511674452555026121 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_numeric.c0000644000175000017500000000012211674452555026575 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_get_memory.c0000644000175000017500000000011211674452555025410 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lsolve.c0000644000175000017500000000011011674452555024574 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_store_lu.c0000644000175000017500000000011011674452555025121 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_symbolic.c0000644000175000017500000000011411674452555025723 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_tail_block.c0000644000175000017500000000012611674452555027412 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_preprocess.c0000644000175000017500000000010711674452555025240 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_preprocess.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_set_stats.c0000644000175000017500000000011111674452555025251 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_qsymbolic.c0000644000175000017500000000011511674452555026133 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_free_symbolic.c0000644000175000017500000000012311674452555026755 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_malloc.c0000644000175000017500000000011011674452555024345 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_malloc.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_lsolve.c0000644000175000017500000000010611674452555024576 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_lsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu.c0000644000175000017500000000011211674452555025126 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_build_tuples.c0000644000175000017500000000011611674452555025771 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_build_tuples.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_scale.c0000644000175000017500000000010511674452555024360 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_scale.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_valid_numeric.c0000644000175000017500000000011711674452555026120 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_valid_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_lhsolve.c0000644000175000017500000000014111674452555024750 0ustar sonnesonne#define ZLONG #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_postorder.c0000644000175000017500000000010711674452555025077 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_postorder.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_lhsolve.c0000644000175000017500000000014111674452555024722 0ustar sonnesonne#define DLONG #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_defaults.c0000644000175000017500000000010511674452555024660 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_defaults.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_store_lu_drop.c0000644000175000017500000000012511674452555026125 0ustar sonnesonne#define DINT #define DROP #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_garbage_collection.c0000644000175000017500000000012211674452555027045 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_alloc_head_block.c0000644000175000017500000000012611674452555027362 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_dl_symbolic.c0000644000175000017500000000011511674452555025727 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_solve.c0000644000175000017500000000010511674452555024373 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_utsolve.c0000644000175000017500000000010711674452555024746 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_solve.c0000644000175000017500000000011311674452555025262 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_extend_front.c0000644000175000017500000000011611674452555025747 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_extend_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_mem_init_memoryspace.c0000644000175000017500000000012611674452555027504 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_is_permutation.c0000644000175000017500000000011611674452555026143 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_is_permutation.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_grow_front.c0000644000175000017500000000011211674452555025427 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_grow_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_usolve.c0000644000175000017500000000010611674452555024561 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_usolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_valid_symbolic.c0000644000175000017500000000011611674452555026245 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_symbolic_usage.c0000644000175000017500000000012011674452555026250 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_get_memory.c0000644000175000017500000000011411674452555025415 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_malloc.c0000644000175000017500000000010611674452555024347 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_malloc.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_order.c0000644000175000017500000000010211674452555024161 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_order.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_blas3_update.c0000644000175000017500000000011611674452555025616 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_blas3_update.c0000644000175000017500000000011411674452555025611 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zl_numeric.c0000644000175000017500000000011511674452555025576 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umfpack_numeric.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_set_stats.c0000644000175000017500000000011111674452555025277 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_set_stats.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_garbage_collection.c0000644000175000017500000000012411674452555027052 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_uhsolve.c0000644000175000017500000000014111674452555024761 0ustar sonnesonne#define ZLONG #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_di_free_symbolic.c0000644000175000017500000000012111674452555026722 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_scale.c0000644000175000017500000000010711674452555024337 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_scale.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_realloc.c0000644000175000017500000000011111674452555024520 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_realloc.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_local_search.c0000644000175000017500000000011611674452555025667 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_local_search.c0000644000175000017500000000011411674452555025662 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_post_tree.c0000644000175000017500000000010611674452555025056 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_post_tree.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_uhsolve.c0000644000175000017500000000013711674452555024735 0ustar sonnesonne#define DINT #define CONJUGATE_SOLVE #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_get_memory.c0000644000175000017500000000011211674452555025436 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_scale_column.c0000644000175000017500000000011611674452555025742 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_scale_column.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_free.c0000644000175000017500000000010411674452555024017 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_free.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_free.c0000644000175000017500000000010611674452555024024 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_free.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_garbage_collection.c0000644000175000017500000000012411674452555027100 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_garbage_collection.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_assemble_fixq.c0000644000175000017500000000012611674452555026121 0ustar sonnesonne#define ZLONG #define FIXQ #include "../../SuiteSparse/UMFPACK/Source/umf_assemble.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_aat.c0000644000175000017500000000010111674452555023615 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_aat.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_mem_alloc_tail_block.c0000644000175000017500000000012411674452555027357 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_row_search.c0000644000175000017500000000011211674452555025375 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_row_search.c0000644000175000017500000000011411674452555025402 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_row_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_blas3_update.c0000644000175000017500000000011611674452555025644 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_blas3_update.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_1.c0000644000175000017500000000007611674452555023220 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_1.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_store_lu_drop.c0000644000175000017500000000012611674452555026157 0ustar sonnesonne#define ZLONG #define DROP #include "../../SuiteSparse/UMFPACK/Source/umf_store_lu.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_kernel_wrapup.c0000644000175000017500000000011511674452555026122 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_symbolic_usage.c0000644000175000017500000000012011674452555026276 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_l_analyze.c0000644000175000017500000000011111674452555024542 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_analyze.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_get_memory.c0000644000175000017500000000011411674452555025443 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_get_memory.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umfpack_zi_symbolic.c0000644000175000017500000000011411674452555025751 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umfpack_symbolic.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_ltsolve.c0000644000175000017500000000011111674452555024761 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_ltsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_mem_alloc_element.c0000644000175000017500000000012311674452555026707 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_utsolve.c0000644000175000017500000000011111674452555024744 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_utsolve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_dl_transpose.c0000644000175000017500000000011311674452555025263 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/UMFPACK/Source/umf_transpose.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_local_search.c0000644000175000017500000000011411674452555025710 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_local_search.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_mem_init_memoryspace.c0000644000175000017500000000012411674452555027477 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_dump.c0000644000175000017500000000010211674452555024016 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_dump.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_i_valid.c0000644000175000017500000000010211674452555024145 0ustar sonnesonne#define DINT #include "../../SuiteSparse/AMD/Source/amd_valid.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_solve.c0000644000175000017500000000010711674452555024426 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_solve.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/amd_l_preprocess.c0000644000175000017500000000011011674452555025235 0ustar sonnesonne#define DLONG #include "../../SuiteSparse/AMD/Source/amd_preprocess.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zi_init_front.c0000644000175000017500000000011311674452555025443 0ustar sonnesonne#define ZINT #include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_i_colamd.c0000644000175000017500000000010611674452555024337 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_colamd.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_di_start_front.c0000644000175000017500000000011311674452555025607 0ustar sonnesonne#define DINT #include "../../SuiteSparse/UMFPACK/Source/umf_start_front.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_2by2.c0000644000175000017500000000010711674452555024054 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_2by2.c" cvxopt-1.1.4/src/C/SuiteSparse_cvxopt_extra/umfpack/umf_zl_init_front.c0000644000175000017500000000011411674452555025447 0ustar sonnesonne#define ZLONG #include "../../SuiteSparse/UMFPACK/Source/umf_init_front.c" cvxopt-1.1.4/src/C/glpk.c0000644000175000017500000006212311674452555014162 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cvxopt.h" #include "misc.h" #include "glpk.h" PyDoc_STRVAR(glpk__doc__, "Interface to the simplex and mixed integer LP algorithms in GLPK.\n\n" "The GLPK control parameters have the default values listed in \n" "the GLPK documentation, except for 'LPX_K_PRESOL', which is set\n" "to 1 and cannot be modified. The other parameters can be\n" "modified by making an entry in the dictionary glpk.options.\n" "For example, the command glpk.options['LPX_K_MSGLEV'] = 0 turns\n" "off the printed output during execution of glpk.simplex().\n" "See the documentation at www.gnu.org/software/glpk/glpk.html for\n" "the list of GLPK control parameters and their default values."); static PyObject *glpk_module; typedef struct { char name[20]; int idx; char type; } param_tuple; static const param_tuple GLPK_PARAM_LIST[] = { {"LPX_K_MSGLEV", LPX_K_MSGLEV, 'i'}, {"LPX_K_SCALE", LPX_K_SCALE, 'i'}, {"LPX_K_DUAL", LPX_K_DUAL, 'i'}, {"LPX_K_PRICE", LPX_K_PRICE, 'i'}, {"LPX_K_RELAX", LPX_K_RELAX, 'f'}, {"LPX_K_TOLBND", LPX_K_TOLBND, 'f'}, {"LPX_K_TOLDJ", LPX_K_TOLDJ, 'f'}, {"LPX_K_TOLPIV", LPX_K_TOLPIV, 'f'}, {"LPX_K_ROUND", LPX_K_ROUND, 'i'}, {"LPX_K_OBJLL", LPX_K_OBJLL, 'f'}, {"LPX_K_OBJUL", LPX_K_OBJUL, 'f'}, {"LPX_K_ITLIM", LPX_K_ITLIM, 'i'}, {"LPX_K_ITCNT", LPX_K_ITCNT, 'i'}, {"LPX_K_TMLIM", LPX_K_TMLIM, 'f'}, {"LPX_K_OUTFRQ", LPX_K_OUTFRQ, 'i'}, {"LPX_K_OUTDLY", LPX_K_OUTDLY, 'f'}, {"LPX_K_BRANCH", LPX_K_BRANCH, 'i'}, {"LPX_K_BTRACK", LPX_K_BTRACK, 'i'}, {"LPX_K_TOLINT", LPX_K_TOLINT, 'f'}, {"LPX_K_TOLOBJ", LPX_K_TOLOBJ, 'f'}, {"LPX_K_MPSINFO", LPX_K_MPSINFO, 'i'}, {"LPX_K_MPSOBJ", LPX_K_MPSOBJ, 'i'}, {"LPX_K_MPSORIG", LPX_K_MPSORIG, 'i'}, {"LPX_K_MPSWIDE", LPX_K_MPSWIDE, 'i'}, {"LPX_K_MPSFREE", LPX_K_MPSFREE, 'i'}, {"LPX_K_MPSSKIP", LPX_K_MPSSKIP, 'i'}, {"LPX_K_LPTORIG", LPX_K_LPTORIG, 'i'}, {"LPX_K_PRESOL", LPX_K_PRESOL, 'i'}, }; /* 28 paramaters */ #if PY_MAJOR_VERSION >= 3 static int get_param_idx(const char *str, int *idx, char *type) #else static int get_param_idx(char *str, int *idx, char *type) #endif { int i; for (i=0; i<28; i++) { if (!strcmp(GLPK_PARAM_LIST[i].name, str)) { *idx = GLPK_PARAM_LIST[i].idx; *type = GLPK_PARAM_LIST[i].type; return 1; } } return 0; } static char doc_simplex[] = "Solves a linear program using GLPK.\n\n" "(status, x, z, y) = lp(c, G, h, A, b)\n" "(status, x, z) = lp(c, G, h)\n\n" "PURPOSE\n" "(status, x, z, y) = lp(c, G, h, A, b) solves the pair\n" "of primal and dual LPs\n\n" " minimize c'*x maximize -h'*z + b'*y\n" " subject to G*x <= h subject to G'*z + A'*y + c = 0\n" " A*x = b z >= 0.\n\n" "(status, x, z) = lp(c, G, h) solves the pair of primal\n" "and dual LPs\n\n" " minimize c'*x maximize -h'*z \n" " subject to G*x <= h subject to G'*z + c = 0\n" " z >= 0.\n\n" "ARGUMENTS\n" "c nx1 dense 'd' matrix with n>=1\n\n" "G mxn dense or sparse 'd' matrix with m>=1\n\n" "h mx1 dense 'd' matrix\n\n" "A pxn dense or sparse 'd' matrix with p>=0\n\n" "b px1 dnese 'd' matrix\n\n" "status 'optimal', 'primal infeasible', 'dual infeasible' \n" " or 'unknown'\n\n" "x if status is 'optimal', a primal optimal solution;\n" " None otherwise\n\n" "z,y if status is 'optimal', the dual optimal solution;\n" " None otherwise"; static PyObject *simplex(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *c, *h, *b=NULL, *x=NULL, *z=NULL, *y=NULL; PyObject *G, *A=NULL, *t=NULL, *param, *key, *value; LPX *lp; int m, n, p, i, j, k, nnz, nnzmax, *rn=NULL, *cn=NULL, param_id; int_t pos=0; double *a=NULL, val; char param_type, err_str[100]; #if PY_MAJOR_VERSION >= 3 const char *keystr; #else char *keystr; #endif char *kwlist[] = {"c", "G", "h", "A", "b", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|OO", kwlist, &c, &G, &h, &A, &b)) return NULL; if ((Matrix_Check(G) && MAT_ID(G) != DOUBLE) || (SpMatrix_Check(G) && SP_ID(G) != DOUBLE) || (!Matrix_Check(G) && !SpMatrix_Check(G))){ PyErr_SetString(PyExc_TypeError, "G must be a 'd' matrix"); return NULL; } if ((m = Matrix_Check(G) ? MAT_NROWS(G) : SP_NROWS(G)) <= 0) err_p_int("m"); if ((n = Matrix_Check(G) ? MAT_NCOLS(G) : SP_NCOLS(G)) <= 0) err_p_int("n"); if (!Matrix_Check(h) || h->id != DOUBLE) err_dbl_mtrx("h"); if (h->nrows != m || h->ncols != 1){ PyErr_SetString(PyExc_ValueError, "incompatible dimensions"); return NULL; } if (A){ if ((Matrix_Check(A) && MAT_ID(A) != DOUBLE) || (SpMatrix_Check(A) && SP_ID(A) != DOUBLE) || (!Matrix_Check(A) && !SpMatrix_Check(A))){ PyErr_SetString(PyExc_ValueError, "A must be a dense " "'d' matrix or a general sparse matrix"); return NULL; } if ((p = Matrix_Check(A) ? MAT_NROWS(A) : SP_NROWS(A)) < 0) err_p_int("p"); if ((Matrix_Check(A) ? MAT_NCOLS(A) : SP_NCOLS(A)) != n){ PyErr_SetString(PyExc_ValueError, "incompatible " "dimensions"); return NULL; } } else p = 0; if (b && (!Matrix_Check(b) || b->id != DOUBLE)) err_dbl_mtrx("b"); if ((b && (b->nrows != p || b->ncols != 1)) || (!b && p !=0 )){ PyErr_SetString(PyExc_ValueError, "incompatible dimensions"); return NULL; } lp = lpx_create_prob(); lpx_add_rows(lp, m+p); lpx_add_cols(lp, n); for (i=0; i= 3 if ((PyUnicode_Check(key)) && get_param_idx(_PyUnicode_AsString(key), ¶m_id, ¶m_type)){ keystr = _PyUnicode_AsString(key); #else if ((keystr = PyString_AsString(key)) && get_param_idx(keystr, ¶m_id, ¶m_type)){ #endif if (param_type == 'i'){ #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value)){ #else if (!PyInt_Check(value)){ #endif sprintf(err_str, "invalid value for integer " "GLPK parameter: %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); lpx_delete_prob(lp); Py_DECREF(param); return NULL; } if (!strcmp("LPX_K_PRESOL", keystr) && #if PY_MAJOR_VERSION >= 3 PyLong_AS_LONG(value) != 1){ #else PyInt_AS_LONG(value) != 1){ #endif PyErr_Warn(PyExc_UserWarning, "ignoring value of " "GLPK parameter 'LPX_K_PRESOL'"); } else lpx_set_int_parm(lp, param_id, #if PY_MAJOR_VERSION >= 3 PyLong_AS_LONG(value)); #else PyInt_AS_LONG(value)); #endif } else { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value) && !PyFloat_Check(value)){ #else if (!PyInt_Check(value) && !PyFloat_Check(value)){ #endif sprintf(err_str, "invalid value for floating point " "GLPK parameter: %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); lpx_delete_prob(lp); Py_DECREF(param); return NULL; } lpx_set_real_parm(lp, param_id, PyFloat_AsDouble(value)); } } lpx_set_int_parm(lp, LPX_K_PRESOL, 1); Py_DECREF(param); switch (lpx_simplex(lp)){ case LPX_E_OK: x = (matrix *) Matrix_New(n,1,DOUBLE); z = (matrix *) Matrix_New(m,1,DOUBLE); if (A) y = (matrix *) Matrix_New(p,1,DOUBLE); if (!x || !z || (A && !y)){ Py_XDECREF(x); Py_XDECREF(z); Py_XDECREF(y); Py_XDECREF(t); lpx_delete_prob(lp); return PyErr_NoMemory(); } PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("optimal")); #else PyString_FromString("optimal")); #endif for (i=0; i= 3 PyUnicode_FromString("primal infeasible")); #else PyString_FromString("primal infeasible")); #endif break; case LPX_E_NODFS: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("dual infeasible")); #else PyString_FromString("dual infeasible")); #endif break; default: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("unknown")); #else PyString_FromString("unknown")); #endif } lpx_delete_prob(lp); PyTuple_SET_ITEM(t, 1, Py_BuildValue("")); PyTuple_SET_ITEM(t, 2, Py_BuildValue("")); if (A) PyTuple_SET_ITEM(t, 3, Py_BuildValue("")); return (PyObject *) t; } static char doc_integer[] = "Solves a mixed integer linear program using GLPK.\n\n" "(status, x) = ilp(c, G, h, A, b, I, B)\n\n" "PURPOSE\n" "Solves the mixed integer linear programming problem\n\n" " minimize c'*x\n" " subject to G*x <= h\n" " A*x = b\n" " x[I] are all integer\n" " x[B] are all binary\n\n" "ARGUMENTS\n" "c nx1 dense 'd' matrix with n>=1\n\n" "G mxn dense or sparse 'd' matrix with m>=1\n\n" "h mx1 dense 'd' matrix\n\n" "A pxn dense or sparse 'd' matrix with p>=0\n\n" "b px1 dense 'd' matrix\n\n" "I set with indices of integer variables\n\n" "B set with indices of binary variables\n\n" "status 'optimal', 'primal infeasible', 'dual infeasible', \n" " 'invalid MIP formulation', 'maxiters exceeded', \n" " 'time limit exceeded', 'unknown'\n\n" "x an optimal solution if status is 'optimal';\n" " None otherwise"; static PyObject *integer(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *c, *h, *b=NULL, *x=NULL; PyObject *G, *A=NULL, *IntSet=NULL, *BinSet = NULL; PyObject *t=NULL, *param, *key, *value; LPX *lp; int m, n, p, i, j, k, nnz, nnzmax, *rn=NULL, *cn=NULL, param_id; int_t pos=0; double *a=NULL, val; char param_type, err_str[100]; #if PY_MAJOR_VERSION >= 3 const char *keystr; #else char *keystr; #endif char *kwlist[] = {"c", "G", "h", "A", "b", "I", "B", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OOO|OOOO", kwlist, &c, &G, &h, &A, &b, &IntSet, &BinSet)) return NULL; if ((Matrix_Check(G) && MAT_ID(G) != DOUBLE) || (SpMatrix_Check(G) && SP_ID(G) != DOUBLE) || (!Matrix_Check(G) && !SpMatrix_Check(G))){ PyErr_SetString(PyExc_TypeError, "G must be a 'd' matrix"); return NULL; } if ((m = Matrix_Check(G) ? MAT_NROWS(G) : SP_NROWS(G)) <= 0) err_p_int("m"); if ((n = Matrix_Check(G) ? MAT_NCOLS(G) : SP_NCOLS(G)) <= 0) err_p_int("n"); if (!Matrix_Check(h) || h->id != DOUBLE) err_dbl_mtrx("h"); if (h->nrows != m || h->ncols != 1){ PyErr_SetString(PyExc_ValueError, "incompatible dimensions"); return NULL; } if (A){ if ((Matrix_Check(A) && MAT_ID(A) != DOUBLE) || (SpMatrix_Check(A) && SP_ID(A) != DOUBLE) || (!Matrix_Check(A) && !SpMatrix_Check(A))){ PyErr_SetString(PyExc_ValueError, "A must be a dense " "'d' matrix or a general sparse matrix"); return NULL; } if ((p = Matrix_Check(A) ? MAT_NROWS(A) : SP_NROWS(A)) < 0) err_p_int("p"); if ((Matrix_Check(A) ? MAT_NCOLS(A) : SP_NCOLS(A)) != n){ PyErr_SetString(PyExc_ValueError, "incompatible " "dimensions"); return NULL; } } else p = 0; if (b && (!Matrix_Check(b) || b->id != DOUBLE)) err_dbl_mtrx("b"); if ((b && (b->nrows != p || b->ncols != 1)) || (!b && p !=0 )){ PyErr_SetString(PyExc_ValueError, "incompatible dimensions"); return NULL; } if ((IntSet) && (!PyAnySet_Check(IntSet))) PY_ERR_TYPE("invalid integer index set"); if ((BinSet) && (!PyAnySet_Check(BinSet))) PY_ERR_TYPE("invalid binary index set"); lp = lpx_create_prob(); lpx_add_rows(lp, m+p); lpx_add_cols(lp, n); for (i=0; i= 3 if ((PyUnicode_Check(key)) && (keystr = PyUnicode_AS_DATA(key)) && get_param_idx(keystr, ¶m_id, ¶m_type)){ #else if ((keystr = PyString_AsString(key)) && get_param_idx(keystr, ¶m_id, ¶m_type)){ #endif if (param_type == 'i'){ #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value)){ #else if (!PyInt_Check(value)){ #endif sprintf(err_str, "invalid value for integer " "GLPK parameter: %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); lpx_delete_prob(lp); Py_DECREF(param); return NULL; } if (!strcmp("LPX_K_PRESOL", keystr) && #if PY_MAJOR_VERSION >= 3 PyLong_AS_LONG(value) != 1){ #else PyInt_AS_LONG(value) != 1){ #endif PyErr_Warn(PyExc_UserWarning, "ignoring value of " "GLPK parameter 'LPX_K_PRESOL'"); } else #if PY_MAJOR_VERSION >= 3 lpx_set_int_parm(lp, param_id, PyLong_AS_LONG(value)); #else lpx_set_int_parm(lp, param_id, PyInt_AS_LONG(value)); #endif } else { #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value) && !PyFloat_Check(value)){ #else if (!PyInt_Check(value) && !PyFloat_Check(value)){ #endif sprintf(err_str, "invalid value for floating point " "GLPK parameter: %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); lpx_delete_prob(lp); Py_DECREF(param); return NULL; } lpx_set_real_parm(lp, param_id, PyFloat_AsDouble(value)); } } lpx_set_int_parm(lp, LPX_K_PRESOL, 1); Py_DECREF(param); if (IntSet) { PyObject *iter = PySequence_Fast(IntSet, "Critical error: not sequence"); for (i=0; i= 3 if (!PyLong_Check(tmp)) { #else if (!PyInt_Check(tmp)) { #endif lpx_delete_prob(lp); Py_DECREF(iter); PY_ERR_TYPE("non-integer element in I"); } #if PY_MAJOR_VERSION >= 3 int k = PyLong_AS_LONG(tmp); #else int k = PyInt_AS_LONG(tmp); #endif if ((k < 0) || (k >= n)) { lpx_delete_prob(lp); Py_DECREF(iter); PY_ERR(PyExc_IndexError, "index element out of range in I"); } glp_set_col_kind(lp, k+1, GLP_IV); } Py_DECREF(iter); } if (BinSet) { PyObject *iter = PySequence_Fast(BinSet, "Critical error: not sequence"); for (i=0; i= 3 if (!PyLong_Check(tmp)) { #else if (!PyInt_Check(tmp)) { #endif lpx_delete_prob(lp); Py_DECREF(iter); PY_ERR_TYPE("non-binary element in I"); } #if PY_MAJOR_VERSION >= 3 int k = PyLong_AS_LONG(tmp); #else int k = PyInt_AS_LONG(tmp); #endif if ((k < 0) || (k >= n)) { lpx_delete_prob(lp); Py_DECREF(iter); PY_ERR(PyExc_IndexError, "index element out of range in B"); } glp_set_col_kind(lp, k+1, GLP_BV); } Py_DECREF(iter); } switch (lpx_intopt(lp)){ case LPX_E_OK: x = (matrix *) Matrix_New(n,1,DOUBLE); if (!x) { Py_XDECREF(t); lpx_delete_prob(lp); return PyErr_NoMemory(); } PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("optimal")); #else PyString_FromString("optimal")); #endif for (i=0; i= 3 PyUnicode_FromString("invalid MIP formulation")); #else PyString_FromString("invalid MIP formulation")); #endif case LPX_E_NOPFS: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("primal infeasible")); #else PyString_FromString("primal infeasible")); #endif case LPX_E_NODFS: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("dual infeasible")); #else PyString_FromString("dual infeasible")); #endif case LPX_E_ITLIM: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("maxiters exceeded")); #else PyString_FromString("maxiters exceeded")); #endif case LPX_E_TMLIM: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("time limit exceeded")); #else PyString_FromString("time limit exceeded")); #endif case LPX_E_SING: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("singular or ill-conditioned basis")); #else PyString_FromString("singular or ill-conditioned basis")); #endif default: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("unknown")); #else PyString_FromString("unknown")); #endif } lpx_delete_prob(lp); PyTuple_SET_ITEM(t, 1, Py_BuildValue("")); return (PyObject *) t; } static PyMethodDef glpk_functions[] = { {"lp", (PyCFunction) simplex, METH_VARARGS|METH_KEYWORDS, doc_simplex}, {"ilp", (PyCFunction) integer, METH_VARARGS|METH_KEYWORDS, doc_integer}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef glpk_module_def = { PyModuleDef_HEAD_INIT, "glpk", glpk__doc__, -1, glpk_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_glpk(void) { if (!(glpk_module = PyModule_Create(&glpk_module_def))) return NULL; PyModule_AddObject(glpk_module, "options", PyDict_New()); if (import_cvxopt() < 0) return NULL; return glpk_module; } #else PyMODINIT_FUNC initglpk(void) { glpk_module = Py_InitModule3("cvxopt.glpk", glpk_functions, glpk__doc__); PyModule_AddObject(glpk_module, "options", PyDict_New()); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/misc.h0000644000175000017500000000706611674452555014172 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef __MISC__ #define __MISC__ #if PY_MAJOR_VERSION >= 3 #define PY_NUMBER(O) (PyLong_Check(O) || PyFloat_Check(O) || PyComplex_Check(O)) #else #define PY_NUMBER(O) (PyInt_Check(O) || PyFloat_Check(O) || PyComplex_Check(O)) #endif #ifndef NO_ANSI99_COMPLEX typedef union { double d; int_t i; complex z; } number; #endif #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) #define PY_ERR(E,str) { PyErr_SetString(E, str); return NULL; } #define PY_ERR_INT(E,str) { PyErr_SetString(E, str); return -1; } #define PY_ERR_TYPE(str) PY_ERR(PyExc_TypeError, str) /* Python style cyclic wrap-around for indices*/ #define CWRAP(i,m) (i >= 0 ? i : m+i) #define OUT_RNG(i, dim) (i < -dim || i >= dim) #define VALID_TC_MAT(t) (t=='i' || t=='d' || t=='z') #define VALID_TC_SP(t) (t=='d' || t=='z') #define TC2ID(c) (c=='i' ? 0 : (c=='d' ? 1 : 2)) #define X_ID(O) (Matrix_Check(O) ? MAT_ID(O) : SP_ID(O)) #define X_NROWS(O) (Matrix_Check(O) ? MAT_NROWS(O) : SP_NROWS(O)) #define X_NCOLS(O) (Matrix_Check(O) ? MAT_NCOLS(O) : SP_NCOLS(O)) #define X_Matrix_Check(O) (Matrix_Check(O) || SpMatrix_Check(O)) #if PY_MAJOR_VERSION >= 3 #define TypeCheck_Capsule(O,str,errstr) { \ if (!PyCapsule_CheckExact(O)) PY_ERR(PyExc_TypeError, errstr); \ const char *descr = PyCapsule_GetName(O); \ if (!descr || strcmp(descr,str)) PY_ERR(PyExc_TypeError,errstr); } #else #define TypeCheck_CObject(O,str,errstr) { \ char *descr = PyCObject_GetDesc(O); \ if (!descr || strcmp(descr,str)) PY_ERR(PyExc_TypeError,errstr); } #endif #define len(x) (Matrix_Check(x) ? MAT_LGT(x) : SP_LGT(x)) #define err_mtrx(s) PY_ERR_TYPE(s " must be a matrix") #define err_bool(s) PY_ERR_TYPE(s " must be True or False") #define err_conflicting_ids { \ PY_ERR_TYPE("conflicting types for matrix arguments"); } #define err_invalid_id {PY_ERR_TYPE( \ "matrix arguments must have type 'd' or 'z'") } #define err_nz_int(s) PY_ERR_TYPE(s " must be a nonzero integer") #define err_nn_int(s) PY_ERR_TYPE(s " must be a nonnegative integer") #define err_buf_len(s) PY_ERR_TYPE("length of " s " is too small") #define err_type(s) PY_ERR_TYPE("incompatible type for " s) #define err_p_int(s) { \ PY_ERR(PyExc_ValueError, s " must be a positive integer") } #define err_char(s1,s2) { \ PY_ERR(PyExc_ValueError, "possible values of " s1 " are: " s2) } #define err_ld(s) { \ PY_ERR(PyExc_ValueError, "illegal value of " s) } #define err_int_mtrx(s) { \ PY_ERR_TYPE(s " must be a matrix with typecode 'i'") } #define err_dbl_mtrx(s) { \ PY_ERR_TYPE(s " must be a matrix with typecode 'd'") } #if PY_MAJOR_VERSION >= 3 #define err_CO(s) PY_ERR_TYPE(s " is not a Capsule") #else #define err_CO(s) PY_ERR_TYPE(s " is not a CObject") #endif #define err_msk_noparam "missing options dictionary" #endif cvxopt-1.1.4/src/C/SuiteSparse/0000755000175000017500000000000011674452555015324 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/AMD/0000755000175000017500000000000011674452555015725 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/AMD/Makefile0000644000175000017500000000326311674452555017371 0ustar sonnesonne#------------------------------------------------------------------------------ # AMD Makefile (for GNU Make or original make) #------------------------------------------------------------------------------ default: demo include ../UFconfig/UFconfig.mk # Compile all C code, including the C-callable routines. # Do not compile the FORTRAN versions, or MATLAB interface. demo: ( cd Lib ; $(MAKE) ) ( cd Demo ; $(MAKE) ) # Compile all C code, including the C-callable routine and the mexFunctions. # Do not compile the FORTRAN versions. all: ( cd Lib ; $(MAKE) ) ( cd Demo ; $(MAKE) ) ( cd MATLAB ; $(MAKE) ) # compile just the C-callable libraries (not mexFunctions or Demos) library: ( cd Lib ; $(MAKE) ) # compile the FORTRAN libraries and demo programs (not compiled by "make all") fortran: ( cd Lib ; $(MAKE) fortran ) ( cd Demo ; $(MAKE) fortran ) # compile a FORTRAN demo program that calls the C version of AMD # (not compiled by "make all") cross: ( cd Demo ; $(MAKE) cross ) # remove object files, but keep the compiled programs and library archives clean: ( cd Lib ; $(MAKE) clean ) ( cd Demo ; $(MAKE) clean ) ( cd MATLAB ; $(MAKE) clean ) ( cd Doc ; $(MAKE) clean ) # clean, and then remove compiled programs and library archives purge: ( cd Lib ; $(MAKE) purge ) ( cd Demo ; $(MAKE) purge ) ( cd MATLAB ; $(MAKE) purge ) ( cd Doc ; $(MAKE) purge ) distclean: purge # create PDF documents for the original distribution doc: ( cd Doc ; $(MAKE) ) # get ready for distribution dist: purge ( cd Demo ; $(MAKE) dist ) ( cd Doc ; $(MAKE) ) ccode: library lib: library # compile the MATLAB mexFunction mex: ( cd MATLAB ; $(MAKE) ) cvxopt-1.1.4/src/C/SuiteSparse/AMD/README.txt0000644000175000017500000002151011674452555017422 0ustar sonnesonneAMD Version 2.2, Copyright (c) 2007 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. AMD is available under alternate licences; contact T. Davis for details. AMD: a set of routines for permuting sparse matrices prior to factorization. Includes a version in C, a version in Fortran, and a MATLAB mexFunction. Requires UFconfig, in the ../UFconfig directory relative to this directory. Quick start (Unix, or Windows with Cygwin): To compile, test, and install AMD, you may wish to first configure the installation by editting the ../UFconfig/UFconfig.mk file. Next, cd to this directory (AMD) and type "make" (or "make lib" if you do not have MATLAB). To compile and run a demo program for the Fortran version, type "make fortran". When done, type "make clean" to remove unused *.o files (keeps the compiled libraries and demo programs). See the User Guide (Doc/AMD_UserGuide.pdf), or ../UFconfig/UFconfig.mk for more details. Quick start (for MATLAB users); To compile, test, and install the AMD mexFunction, cd to the AMD/MATLAB directory and type amd_make at the MATLAB prompt. If you have MATLAB 7.2 or earlier and use "make mex", you must first edit UFconfig/UFconfig.h to remove the "-largeArrayDims" option from the MEX command (or just use amd_make.m inside MATLAB). ------------------------------------------------------------------------------- AMD License: Your use or distribution of AMD or any modified version of AMD implies that you agree to this License. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU LGPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. Availability: http://www.cise.ufl.edu/research/sparse/amd ------------------------------------------------------------------------------- This is the AMD README file. It is a terse overview of AMD. Refer to the User Guide (Doc/AMD_UserGuide.pdf) for how to install and use AMD. Description: AMD is a set of routines for pre-ordering sparse matrices prior to Cholesky or LU factorization, using the approximate minimum degree ordering algorithm. Written in ANSI/ISO C with a MATLAB interface, and in Fortran 77. Authors: Timothy A. Davis (davis at cise.ufl.edu), University of Florida. Patrick R. Amestory, ENSEEIHT, Toulouse, France. Iain S. Duff, Rutherford Appleton Laboratory, UK. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974, DMS-9803599, and CCR-0203270. Portions of this work were done while on sabbatical at Stanford University and Lawrence Berkeley National Laboratory (with funding from the SciDAC program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon for making this sabbatical possible. ------------------------------------------------------------------------------- Files and directories in the AMD distribution: ------------------------------------------------------------------------------- --------------------------------------------------------------------------- Subdirectories of the AMD directory: --------------------------------------------------------------------------- Doc documentation Source primary source code Include include file for use in your code that calls AMD Demo demo programs. also serves as test of the AMD installation. MATLAB AMD mexFunction for MATLAB, and supporting m-files Lib where the compiled C-callable and Fortran-callable AMD libraries placed. --------------------------------------------------------------------------- Files in the AMD directory: --------------------------------------------------------------------------- Makefile top-level Makefile for GNU make or original make. Windows users would require Cygwin to use "make" README.txt this file --------------------------------------------------------------------------- Doc directory: documentation --------------------------------------------------------------------------- ChangeLog change log License the AMD License Makefile for creating the documentation AMD_UserGuide.bib AMD User Guide (references) AMD_UserGuide.tex AMD User Guide (LaTeX) AMD_UserGuide.pdf AMD User Guide (PDF) lesser.txt the GNU LGPL license --------------------------------------------------------------------------- Source directory: --------------------------------------------------------------------------- amd_order.c user-callable, primary AMD ordering routine amd_control.c user-callable, prints the control parameters amd_defaults.c user-callable, sets default control parameters amd_info.c user-callable, prints the statistics from AMD amd_1.c non-user-callable, construct A+A' amd_2.c user-callable, primary ordering kernel (a C version of amd.f and amdbar.f, with post-ordering added) amd_aat.c non-user-callable, computes nnz (A+A') amd_dump.c non-user-callable, debugging routines amd_postorder.c non-user-callable, postorder amd_post_tree.c non-user-callable, postorder just one tree amd_valid.c non-user-callable, verifies a matrix amd_preprocess.c non-user-callable, computes A', removes duplic amd.f user-callable Fortran 77 version amdbar.f user-callable Fortran 77 version --------------------------------------------------------------------------- Include directory: --------------------------------------------------------------------------- amd.h include file for C programs that use AMD amd_internal.h non-user-callable, include file for AMD --------------------------------------------------------------------------- Demo directory: --------------------------------------------------------------------------- Makefile for GNU make or original make amd_demo.c C demo program for AMD amd_demo.out output of amd_demo.c amd_demo2.c C demo program for AMD, jumbled matrix amd_demo2.out output of amd_demo2.c amd_l_demo.c C demo program for AMD (UF_long version) amd_l_demo.out output of amd_l_demo.c amd_simple.c simple C demo program for AMD amd_simple.out output of amd_simple.c amd_f77demo.f Fortran 77 demo program for AMD amd_f77demo.out output of amd_f77demo.f amd_f77simple.c simple Fortran 77 demo program for AMD amd_f77simple.out output of amd_f77simple.f amd_f77cross.f Fortran 77 demo, calls the C version of AMD amd_f77cross.out output of amd_f77cross.f amd_f77wrapper.c Fortran-callable wrapper for C version of AMD --------------------------------------------------------------------------- MATLAB directory: --------------------------------------------------------------------------- GNUmakefile a nice Makefile, for GNU make Makefile an ugly Unix Makefile (for older make's) Contents.m for "help amd2" listing of toolbox contents amd2.m MATLAB help file for AMD amd_make.m MATLAB m-file for compiling AMD mexFunction amd_install.m compile and install the AMD mexFunction amd_mex.c AMD mexFunction for MATLAB amd_demo.m MATLAB demo for AMD amd_demo.m.out diary output of amd_demo.m can_24.mat input file for AMD demo --------------------------------------------------------------------------- Lib directory: libamd.a and libamdf77.a libraries placed here --------------------------------------------------------------------------- GNUmakefile a nice Makefile, for GNU make Makefile an ugly Unix Makefile (for older make's) libamd.def AMD definitions for Windows cvxopt-1.1.4/src/C/SuiteSparse/AMD/Doc/0000755000175000017500000000000011674452555016432 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.bib0000644000175000017500000000470311674452555021471 0ustar sonnesonne@string{SIREV = "{SIAM} Review"} @string{SIMAX = "{SIAM} J. Matrix Anal. Applic."} @string{SIAMJSC = "{SIAM} J. Sci. Comput."} @string{TOMS = "{ACM} Trans. Math. Softw."} @article{schu:01, author = {J. Schulze}, title = {Towards a tighter coupling of bottom-up and top-down sparse matrix ordering methods}, journal = {BIT}, volume = {41}, number = {4}, pages = "800--841", year = {2001} } @article{GeorgeLiu89, author={George, A. and Liu, J. W. H.}, year={1989}, title={The Evolution of the Minimum Degree Ordering Algorithm}, journal=SIREV, volume={31}, number={1}, pages={1--19}} @article{AmestoyDavisDuff96, author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.}, title={An approximate minimum degree ordering algorithm}, journal=SIMAX, year={1996} ,volume={17} ,number={4} ,pages={886-905} } @article{AmestoyDavisDuff04, author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.}, title={Algorithm 837: An approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,number={3} ,pages={381-388} } @misc{hsl:2002, author = {HSL}, title = "{HSL} 2002: {A} collection of {F}ortran codes for large scale scientific computation", note = {{\tt www.cse.clrc.ac.uk/nag/hsl}}, year = 2002} @article{RothbergEisenstat98, author={Rothberg, E. and Eisenstat, S. C.}, title={Node selection strategies for bottom-up sparse matrix orderings}, journal=SIMAX, year={1998} ,volume={19} ,number={3} ,pages={682-695} } @article{KarypisKumar98e, author={Karypis, G. and Kumar, V.}, title={A fast and high quality multilevel scheme for partitioning irregular graphs}, journal=SIAMJSC, year={1998} ,volume={20} ,pages={359-392} } @article{Chaco, author={B. Hendrickson and E. Rothberg}, title={Improving the runtime and quality of nested dissection ordering}, journal=SIAMJSC, year={1999} ,volume={20} ,pages={468--489} } @article{PellegriniRomanAmestoy00, author={Pellegrini, F. and Roman, J. and Amestoy, P.}, title={Hybridizing nested dissection and halo approximate minimum degree for efficient sparse matrix ordering}, journal={Concurrency: Practice and Experience}, year={2000} ,volume={12} ,pages={68-84} } @article{DavisGilbertLarimoreNg04, author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.}, title={A column approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,pages={353-376} } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Doc/Makefile0000644000175000017500000000200011674452555020062 0ustar sonnesonne#------------------------------------------------------------------------------ # AMD Makefile for compiling on Unix systems (for GNU or original make) #------------------------------------------------------------------------------ default: dist include ../../UFconfig/UFconfig.mk #------------------------------------------------------------------------------ # Remove all but the files in the original distribution #------------------------------------------------------------------------------ clean: - $(RM) $(CLEAN) purge: distclean distclean: clean - $(RM) *.aux *.bbl *.blg *.log *.toc #------------------------------------------------------------------------------ # Create the User Guide and Quick Start Guide #------------------------------------------------------------------------------ AMD_UserGuide.pdf: AMD_UserGuide.tex AMD_UserGuide.bib pdflatex AMD_UserGuide bibtex AMD_UserGuide pdflatex AMD_UserGuide pdflatex AMD_UserGuide dist: AMD_UserGuide.pdf - $(RM) *.aux *.bbl *.blg *.log *.toc cvxopt-1.1.4/src/C/SuiteSparse/AMD/Doc/License0000644000175000017500000000342711674452555017745 0ustar sonnesonneAMD, Copyright (c) by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. AMD is available under alternate licenses, contact T. Davis for details. AMD License: Your use or distribution of AMD or any modified version of AMD implies that you agree to this License. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU LGPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. Availability: http://www.cise.ufl.edu/research/sparse/amd ------------------------------------------------------------------------------- cvxopt-1.1.4/src/C/SuiteSparse/AMD/Doc/ChangeLog0000644000175000017500000001122011674452555020200 0ustar sonnesonneMay 31, 2007: version 2.2.0 * port to 64-bit MATLAB * Makefile moved from Source/ to Lib/ * minor changes to printing routines (amd_control.c, amd_info.c) Dec 12, 2006, version 2.0.4 * minor MATLAB code cleanup Nov 29, 2006, version 2.0.3 * changed MATLAB function name to amd2, so as not to conflict with the now built-in version of AMD in MATLAB (which is the same thing as the AMD here...). Sept 28, 2006, version 2.0.2 * #define SIZE_T_MAX not done if already defined (Mac OSX). Aug 31, 2006: * trivial change to comments in amd.m Apr 30, 2006: AMD Version 2.0: * long integer redefined as UF_long, controlled by UFconfig.h. * amd_order no longer requires its input to have sorted columns. It can also tolerate duplicate entries in each column. If these conditions hold, but the matrix is otherwise valid, amd_order returns AMD_OK_BUT_JUMBLED (a warning, not an error). * amd_preprocess no longer deemed user-callable, since it is no longer needed (it was used to ensure the input matrix had sorted columns with no duplicate entries). It still exists, with additional parameters, and is called by amd_order if necessary. amd_wpreprocess and amd_preprocess_valid removed. Fortran interface routine amdpreproc removed. * Integer overflow computations modified, to extend the size of problem that the "int" version can solve when used in an LP64 compilation. * amd_demo2.c simplified (it tests AMD with a jumbled matrix). * amd_valid returned TRUE/FALSE in v1.2. It now returns AMD_OK, AMD_OK_BUT_JUMBLED, or AMD_INVALID. Only in the latter case is the matrix unsuitable as input to amd_order. * amd_internal.h include file moved from AMD/Source to AMD/Include. Nov 15, 2005: * minor editting of comments; version number (1.2) unchanged. Aug. 30, 2005: AMD Version 1.2 * AMD v1.2 is upward compatible with v1.1 and v1.0, except that v1.2 no longer includes the compile-time redefinition of malloc and free. * Makefile modified to use UFconfig.mk. "Make" directory removed. * License changed to GNU LGPL. * Easier inclusion in C++ programs. * option to allow compile-time redefinition of malloc and free (added to v1.1) removed for v1.2. Replaced with a run-time redefinition. AMD includes function pointers for malloc, free, calloc, realloc, and printf, so that all those routines can be redefined at compile time. These function pointers are global variables, and so are not technically thread-safe, unless you use defaults and don't need to change them (the common case) or if you change them in one thread before using them in other threads. * added #define'd version number * minor modification to AMD_2 to ensure all lines can be tested, without conditional compilation. * moved the prototype for AMD_2 from amd_internal.h to amd.h * moved the prototype for AMD_valid from amd_internal.h to amd.h * MATLAB mexFunction uses libamd.a (compiled with cc) instead of compiling each AMD source file with the mex command * long demo (amd_l_demo.c) added. Jan. 21, 2004: AMD Version 1.1 * No bugs found or fixed - new features added, only * amd_preprocess added, to allow for more general input of the matrix A. * ME=0 added to amd*.f, unused DEXT variable removed from amdbar.f, to avoid spurious compiler warnings (this was not a bug). * amd_demo2.c and amd_demo2.out added, to test/demo amd_preprocess. * option to allow compile-time redefinition of malloc, free, printf added * amd_demo.c shortened slightly (removed printing of PAP') * User Guide modified (more details added) * linewidth reduced from 80 to 79 columns Oct. 7, 2003: AMD version 1.0.1. * MATLAB mexFunction modified, to remove call to mexCallMATLAB function. This function can take a long time to call, particularly if you are ordering many small matrices. May 6, 2003: AMD Version 1.0 released. * converted to C (compare amd.f and amdbar.f with amd_2.c) * dense rows/column removed prior to ordering * elimination tree post-ordering added * demos, user guide written * statistics added (nz in L, flop count, symmetry of A) * computes the pattern of A+A' if A is unsymmetric * user's input matrix no longer overwritten * degree lists initialized differently * IOVFLO argument removed from Fortran versions (amd.f and amdbar.f) * parameters added (dense row/column detection, aggressive absorption) * MATLAB mexFunction added Jan, 1996: * amdbar.f posted at http://www.netlib.org (with a restricted License) * amd.f appears as MC47B/BD in the Harwell Subroutine Library (without the IOVFLO argument) cvxopt-1.1.4/src/C/SuiteSparse/AMD/Doc/lesser.txt0000644000175000017500000006350011674452555020474 0ustar sonnesonne GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! cvxopt-1.1.4/src/C/SuiteSparse/AMD/Doc/AMD_UserGuide.tex0000644000175000017500000014675311674452555021551 0ustar sonnesonne\documentclass[11pt]{article} \newcommand{\m}[1]{{\bf{#1}}} % for matrices and vectors \newcommand{\tr}{^{\sf T}} % transpose \topmargin 0in \textheight 9in \oddsidemargin 0pt \evensidemargin 0pt \textwidth 6.5in %------------------------------------------------------------------------------ \begin{document} %------------------------------------------------------------------------------ \title{AMD Version 2.2 User Guide} \author{Patrick R. Amestoy\thanks{ENSEEIHT-IRIT, 2 rue Camichel 31017 Toulouse, France. email: amestoy@enseeiht.fr. http://www.enseeiht.fr/$\sim$amestoy.} \and Timothy A. Davis\thanks{ Dept.~of Computer and Information Science and Engineering, Univ.~of Florida, Gainesville, FL, USA. email: davis@cise.ufl.edu. http://www.cise.ufl.edu/$\sim$davis. This work was supported by the National Science Foundation, under grants ASC-9111263, DMS-9223088, and CCR-0203270. Portions of the work were done while on sabbatical at Stanford University and Lawrence Berkeley National Laboratory (with funding from Stanford University and the SciDAC program). } \and Iain S. Duff\thanks{Rutherford Appleton Laboratory, Chilton, Didcot, Oxon OX11 0QX, England. email: i.s.duff@rl.ac.uk. http://www.numerical.rl.ac.uk/people/isd/isd.html. This work was supported by the EPSRC under grant GR/R46441. }} \date{May 31, 2007} \maketitle %------------------------------------------------------------------------------ \begin{abstract} AMD is a set of routines that implements the approximate minimum degree ordering algorithm to permute sparse matrices prior to numerical factorization. There are versions written in both C and Fortran 77. A MATLAB interface is included. \end{abstract} %------------------------------------------------------------------------------ Technical report TR-04-002 (revised), CISE Department, University of Florida, Gainesville, FL, 2007. AMD Version 2.2, Copyright\copyright 2007 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. AMD is available under alternate licences; contact T. Davis for details. {\bf AMD License:} Your use or distribution of AMD or any modified version of AMD implies that you agree to this License. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU LGPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. {\bf Availability:} http://www.cise.ufl.edu/research/sparse/amd {\bf Acknowledgments:} This work was supported by the National Science Foundation, under grants ASC-9111263 and DMS-9223088 and CCR-0203270. The conversion to C, the addition of the elimination tree post-ordering, and the handling of dense rows and columns were done while Davis was on sabbatical at Stanford University and Lawrence Berkeley National Laboratory. %------------------------------------------------------------------------------ \newpage \section{Overview} %------------------------------------------------------------------------------ AMD is a set of routines for preordering a sparse matrix prior to numerical factorization. It uses an approximate minimum degree ordering algorithm \cite{AmestoyDavisDuff96,AmestoyDavisDuff04} to find a permutation matrix $\m{P}$ so that the Cholesky factorization $\m{PAP}\tr=\m{LL}\tr$ has fewer (often much fewer) nonzero entries than the Cholesky factorization of $\m{A}$. The algorithm is typically much faster than other ordering methods and minimum degree ordering algorithms that compute an exact degree \cite{GeorgeLiu89}. Some methods, such as approximate deficiency \cite{RothbergEisenstat98} and graph-partitioning based methods \cite{Chaco,KarypisKumar98e,PellegriniRomanAmestoy00,schu:01} can produce better orderings, depending on the matrix. The algorithm starts with an undirected graph representation of a symmetric sparse matrix $\m{A}$. Node $i$ in the graph corresponds to row and column $i$ of the matrix, and there is an edge $(i,j)$ in the graph if $a_{ij}$ is nonzero. The degree of a node is initialized to the number of off-diagonal nonzeros in row $i$, which is the size of the set of nodes adjacent to $i$ in the graph. The selection of a pivot $a_{ii}$ from the diagonal of $\m{A}$ and the first step of Gaussian elimination corresponds to one step of graph elimination. Numerical fill-in causes new nonzero entries in the matrix (fill-in refers to nonzeros in $\m{L}$ that are not in $\m{A}$). Node $i$ is eliminated and edges are added to its neighbors so that they form a clique (or {\em element}). To reduce fill-in, node $i$ is selected as the node of least degree in the graph. This process repeats until the graph is eliminated. The clique is represented implicitly. Rather than listing all the new edges in the graph, a single list of nodes is kept which represents the clique. This list corresponds to the nonzero pattern of the first column of $\m{L}$. As the elimination proceeds, some of these cliques become subsets of subsequent cliques, and are removed. This graph can be stored in place, that is using the same amount of memory as the original graph. The most costly part of the minimum degree algorithm is the recomputation of the degrees of nodes adjacent to the current pivot element. Rather than keep track of the exact degree, the approximate minimum degree algorithm finds an upper bound on the degree that is easier to compute. For nodes of least degree, this bound tends to be tight. Using the approximate degree instead of the exact degree leads to a substantial savings in run time, particularly for very irregularly structured matrices. It has no effect on the quality of the ordering. In the C version of AMD, the elimination phase is followed by an elimination tree post-ordering. This has no effect on fill-in, but reorganizes the ordering so that the subsequent numerical factorization is more efficient. It also includes a pre-processing phase in which nodes of very high degree are removed (without causing fill-in), and placed last in the permutation $\m{P}$. This reduces the run time substantially if the matrix has a few rows with many nonzero entries, and has little effect on the quality of the ordering. The C version operates on the symmetric nonzero pattern of $\m{A}+\m{A}\tr$, so it can be given an unsymmetric matrix, or either the lower or upper triangular part of a symmetric matrix. The two Fortran versions of AMD are essentially identical to two versions of the AMD algorithm discussed in an earlier paper \cite{AmestoyDavisDuff96} (approximate minimum external degree, both with and without aggressive absorption). For a discussion of the long history of the minimum degree algorithm, see \cite{GeorgeLiu89}. %------------------------------------------------------------------------------ \section{Availability} %------------------------------------------------------------------------------ In addition to appearing as a Collected Algorithm of the ACM, \newline AMD is available at http://www.cise.ufl.edu/research/sparse. The Fortran version is available as the routine {\tt MC47} in HSL (formerly the Harwell Subroutine Library) \cite{hsl:2002}. %------------------------------------------------------------------------------ \section{Using AMD in MATLAB} %------------------------------------------------------------------------------ The MATLAB function {\tt amd} is now a built-in function in MATLAB 7.3 (R2006b). The built-in {\tt amd} and the {\tt amd2} function provided here differ in how the optional parameters are passed (the 2nd input parameter). To use AMD2 in MATLAB, you must first compile the AMD2 mexFunction. Just type {\tt make} in the Unix system shell, while in the {\tt AMD/MATLAB} directory. You can also type {\tt amd\_make} in MATLAB, while in the {\tt AMD/MATLAB} directory. Place the {\tt AMD/MATLAB} directory in your MATLAB path. This can be done on any system with MATLAB, including Windows. See Section~\ref{Install} for more details on how to install AMD. The MATLAB statement {\tt p=amd(A)} finds a permutation vector {\tt p} such that the Cholesky factorization {\tt chol(A(p,p))} is typically sparser than {\tt chol(A)}. If {\tt A} is unsymmetric, {\tt amd(A)} is identical to {\tt amd(A+A')} (ignoring numerical cancellation). If {\tt A} is not symmetric positive definite, but has substantial diagonal entries and a mostly symmetric nonzero pattern, then this ordering is also suitable for LU factorization. A partial pivoting threshold may be required to prevent pivots from being selected off the diagonal, such as the statement {\tt [L,U,P] = lu (A (p,p), 0.1)}. Type {\tt help lu} for more details. The statement {\tt [L,U,P,Q] = lu (A (p,p))} in MATLAB 6.5 is not suitable, however, because it uses UMFPACK Version 4.0 and thus does not attempt to select pivots from the diagonal. UMFPACK Version 4.1 in MATLAB 7.0 and later uses several strategies, including a symmetric pivoting strategy, and will give you better results if you want to factorize an unsymmetric matrix of this type. Refer to the UMFPACK User Guide for more details, at http://www.cise.ufl.edu/research/sparse/umfpack. The AMD mexFunction is much faster than the built-in MATLAB symmetric minimum degree ordering methods, SYMAMD and SYMMMD. Its ordering quality is comparable to SYMAMD, and better than SYMMMD \cite{DavisGilbertLarimoreNg04}. An optional input argument can be used to modify the control parameters for AMD (aggressive absorption, dense row/column handling, and printing of statistics). An optional output argument provides statistics on the ordering, including an analysis of the fill-in and the floating-point operation count for a subsequent factorization. For more details (once AMD is installed), type {\tt help amd} in the MATLAB command window. %------------------------------------------------------------------------------ \section{Using AMD in a C program} \label{Cversion} %------------------------------------------------------------------------------ The C-callable AMD library consists of seven user-callable routines and one include file. There are two versions of each of the routines, with {\tt int} and {\tt long} integers. The routines with prefix {\tt amd\_l\_} use {\tt long} integer arguments; the others use {\tt int} integer arguments. If you compile AMD in the standard ILP32 mode (32-bit {\tt int}'s, {\tt long}'s, and pointers) then the versions are essentially identical. You will be able to solve problems using up to 2GB of memory. If you compile AMD in the standard LP64 mode, the size of an {\tt int} remains 32-bits, but the size of a {\tt long} and a pointer both get promoted to 64-bits. The following routines are fully described in Section~\ref{Primary}: \begin{itemize} \item {\tt amd\_order} ({\tt long} version: {\tt amd\_l\_order}) {\footnotesize \begin{verbatim} #include "amd.h" int n, Ap [n+1], Ai [nz], P [n] ; double Control [AMD_CONTROL], Info [AMD_INFO] ; int result = amd_order (n, Ap, Ai, P, Control, Info) ; \end{verbatim} } Computes the approximate minimum degree ordering of an $n$-by-$n$ matrix $\m{A}$. Returns a permutation vector {\tt P} of size {\tt n}, where {\tt P[k] = i} if row and column {\tt i} are the {\tt k}th row and column in the permuted matrix. This routine allocates its own memory of size $1.2e+9n$ integers, where $e$ is the number of nonzeros in $\m{A}+\m{A}\tr$. It computes statistics about the matrix $\m{A}$, such as the symmetry of its nonzero pattern, the number of nonzeros in $\m{L}$, and the number of floating-point operations required for Cholesky and LU factorizations (which are returned in the {\tt Info} array). The user's input matrix is not modified. It returns {\tt AMD\_OK} if successful, {\tt AMD\_OK\_BUT\_JUMBLED} if successful (but the matrix had unsorted and/or duplicate row indices), {\tt AMD\_INVALID} if the matrix is invalid, {\tt AMD\_OUT\_OF\_MEMORY} if out of memory. \item {\tt amd\_defaults} ({\tt long} version: {\tt amd\_l\_defaults}) {\footnotesize \begin{verbatim} #include "amd.h" double Control [AMD_CONTROL] ; amd_defaults (Control) ; \end{verbatim} } Sets the default control parameters in the {\tt Control} array. These can then be modified as desired before passing the array to the other AMD routines. \item {\tt amd\_control} ({\tt long} version: {\tt amd\_l\_control}) {\footnotesize \begin{verbatim} #include "amd.h" double Control [AMD_CONTROL] ; amd_control (Control) ; \end{verbatim} } Prints a description of the control parameters, and their values. \item {\tt amd\_info} ({\tt long} version: {\tt amd\_l\_info}) {\footnotesize \begin{verbatim} #include "amd.h" double Info [AMD_INFO] ; amd_info (Info) ; \end{verbatim} } Prints a description of the statistics computed by AMD, and their values. \item {\tt amd\_valid} ({\tt long} version: {\tt amd\_valid}) {\footnotesize \begin{verbatim} #include "amd.h" int n, Ap [n+1], Ai [nz] ; int result = amd_valid (n, n, Ap, Ai) ; \end{verbatim} } Returns {\tt AMD\_OK} or {\tt AMD\_OK\_BUT\_JUMBLED} if the matrix is valid as input to {\tt amd\_order}; the latter is returned if the matrix has unsorted and/or duplicate row indices in one or more columns. Returns {\tt AMD\_INVALID} if the matrix cannot be passed to {\tt amd\_order}. For {\tt amd\_order}, the matrix must also be square. The first two arguments are the number of rows and the number of columns of the matrix. For its use in AMD, these must both equal {\tt n}. \item {\tt amd\_2} ({\tt long} version: {\tt amd\_l2}) AMD ordering kernel. It is faster than {\tt amd\_order}, and can be called by the user, but it is difficult to use. It does not check its inputs for errors. It does not require the columns of its input matrix to be sorted, but it destroys the matrix on output. Additional workspace must be passed. Refer to the source file {\tt AMD/Source/amd\_2.c} for a description. \end{itemize} The nonzero pattern of the matrix $\m{A}$ is represented in compressed column form. For an $n$-by-$n$ matrix $\m{A}$ with {\tt nz} nonzero entries, the representation consists of two arrays: {\tt Ap} of size {\tt n+1} and {\tt Ai} of size {\tt nz}. The row indices of entries in column {\tt j} are stored in {\tt Ai[Ap[j]} $\ldots$ {\tt Ap[j+1]-1]}. For {\tt amd\_order}, if duplicate row indices are present, or if the row indices in any given column are not sorted in ascending order, then {\tt amd\_order} creates an internal copy of the matrix with sorted rows and no duplicate entries, and orders the copy. This adds slightly to the time and memory usage of {\tt amd\_order}, but is not an error condition. The matrix is 0-based, and thus row indices must be in the range {\tt 0} to {\tt n-1}. The first entry {\tt Ap[0]} must be zero. The total number of entries in the matrix is thus {\tt nz = Ap[n]}. The matrix must be square, but it does not need to be symmetric. The {\tt amd\_order} routine constructs the nonzero pattern of $\m{B} = \m{A}+\m{A}\tr$ (without forming $\m{A}\tr$ explicitly if $\m{A}$ has sorted columns and no duplicate entries), and then orders the matrix $\m{B}$. Thus, either the lower triangular part of $\m{A}$, the upper triangular part, or any combination may be passed. The transpose $\m{A}\tr$ may also be passed to {\tt amd\_order}. The diagonal entries may be present, but are ignored. %------------------------------------------------------------------------------ \subsection{Control parameters} \label{control_param} %------------------------------------------------------------------------------ Control parameters are set in an optional {\tt Control} array. It is optional in the sense that if a {\tt NULL} pointer is passed for the {\tt Control} input argument, then default control parameters are used. % \begin{itemize} \item {\tt Control[AMD\_DENSE]} (or {\tt Control(1)} in MATLAB): controls the threshold for ``dense'' rows/columns. A dense row/column in $\m{A}+\m{A}\tr$ can cause AMD to spend significant time in ordering the matrix. If {\tt Control[AMD\_DENSE]} $\ge 0$, rows/columns with more than {\tt Control[AMD\_DENSE]} $\sqrt{n}$ entries are ignored during the ordering, and placed last in the output order. The default value of {\tt Control[AMD\_DENSE]} is 10. If negative, no rows/columns are treated as ``dense.'' Rows/columns with 16 or fewer off-diagonal entries are never considered ``dense.'' % \item {\tt Control[AMD\_AGGRESSIVE]} (or {\tt Control(2)} in MATLAB): controls whether or not to use aggressive absorption, in which a prior element is absorbed into the current element if it is a subset of the current element, even if it is not adjacent to the current pivot element (refer to \cite{AmestoyDavisDuff96,AmestoyDavisDuff04} for more details). The default value is nonzero, which means that aggressive absorption will be performed. This nearly always leads to a better ordering (because the approximate degrees are more accurate) and a lower execution time. There are cases where it can lead to a slightly worse ordering, however. To turn it off, set {\tt Control[AMD\_AGGRESSIVE]} to 0. % \end{itemize} Statistics are returned in the {\tt Info} array (if {\tt Info} is {\tt NULL}, then no statistics are returned). Refer to {\tt amd.h} file, for more details (14 different statistics are returned, so the list is not included here). %------------------------------------------------------------------------------ \subsection{Sample C program} %------------------------------------------------------------------------------ The following program, {\tt amd\_demo.c}, illustrates the basic use of AMD. See Section~\ref{Synopsis} for a short description of each calling sequence. {\footnotesize \begin{verbatim} #include #include "amd.h" int n = 5 ; int Ap [ ] = { 0, 2, 6, 10, 12, 14} ; int Ai [ ] = { 0,1, 0,1,2,4, 1,2,3,4, 2,3, 1,4 } ; int P [5] ; int main (void) { int k ; (void) amd_order (n, Ap, Ai, P, (double *) NULL, (double *) NULL) ; for (k = 0 ; k < n ; k++) printf ("P [%d] = %d\n", k, P [k]) ; return (0) ; } \end{verbatim} } The {\tt Ap} and {\tt Ai} arrays represent the binary matrix \[ \m{A} = \left[ \begin{array}{rrrrr} 1 & 1 & 0 & 0 & 0 \\ 1 & 1 & 1 & 0 & 1 \\ 0 & 1 & 1 & 1 & 0 \\ 0 & 0 & 1 & 1 & 0 \\ 0 & 1 & 1 & 0 & 1 \\ \end{array} \right]. \] The diagonal entries are ignored. % AMD constructs the pattern of $\m{A}+\m{A}\tr$, and returns a permutation vector of $(0, 3, 1, 4, 2)$. % Since the matrix is unsymmetric but with a mostly symmetric nonzero pattern, this would be a suitable permutation for an LU factorization of a matrix with this nonzero pattern and whose diagonal entries are not too small. The program uses default control settings and does not return any statistics about the ordering, factorization, or solution ({\tt Control} and {\tt Info} are both {\tt (double *) NULL}). It also ignores the status value returned by {\tt amd\_order}. More example programs are included with the AMD package. The {\tt amd\_demo.c} program provides a more detailed demo of AMD. Another example is the AMD mexFunction, {\tt amd\_mex.c}. %------------------------------------------------------------------------------ \subsection{A note about zero-sized arrays} %------------------------------------------------------------------------------ AMD uses several user-provided arrays of size {\tt n} or {\tt nz}. Either {\tt n} or {\tt nz} can be zero. If you attempt to {\tt malloc} an array of size zero, however, {\tt malloc} will return a null pointer which AMD will report as invalid. If you {\tt malloc} an array of size {\tt n} or {\tt nz} to pass to AMD, make sure that you handle the {\tt n} = 0 and {\tt nz = 0} cases correctly. %------------------------------------------------------------------------------ \section{Synopsis of C-callable routines} \label{Synopsis} %------------------------------------------------------------------------------ The matrix $\m{A}$ is {\tt n}-by-{\tt n} with {\tt nz} entries. {\footnotesize \begin{verbatim} #include "amd.h" int n, status, Ap [n+1], Ai [nz], P [n] ; double Control [AMD_CONTROL], Info [AMD_INFO] ; amd_defaults (Control) ; status = amd_order (n, Ap, Ai, P, Control, Info) ; amd_control (Control) ; amd_info (Info) ; status = amd_valid (n, n, Ap, Ai) ; \end{verbatim} } The {\tt amd\_l\_*} routines are identical, except that all {\tt int} arguments become {\tt long}: {\footnotesize \begin{verbatim} #include "amd.h" long n, status, Ap [n+1], Ai [nz], P [n] ; double Control [AMD_CONTROL], Info [AMD_INFO] ; amd_l_defaults (Control) ; status = amd_l_order (n, Ap, Ai, P, Control, Info) ; amd_l_control (Control) ; amd_l_info (Info) ; status = amd_l_valid (n, n, Ap, Ai) ; \end{verbatim} } %------------------------------------------------------------------------------ \section{Using AMD in a Fortran program} %------------------------------------------------------------------------------ Two Fortran versions of AMD are provided. The {\tt AMD} routine computes the approximate minimum degree ordering, using aggressive absorption. The {\tt AMDBAR} routine is identical, except that it does not perform aggressive absorption. The {\tt AMD} routine is essentially identical to the HSL routine {\tt MC47B/BD}. Note that earlier versions of the Fortran {\tt AMD} and {\tt AMDBAR} routines included an {\tt IOVFLO} argument, which is no longer present. In contrast to the C version, the Fortran routines require a symmetric nonzero pattern, with no diagonal entries present although the {\tt MC47A/AD} wrapper in HSL allows duplicates, ignores out-of-range entries, and only uses entries from the upper triangular part of the matrix. Although we have an experimental Fortran code for treating ``dense'' rows, the Fortran codes in this release do not treat ``dense'' rows and columns of $\m{A}$ differently, and thus their run time can be high if there are a few dense rows and columns in the matrix. They do not perform a post-ordering of the elimination tree, compute statistics on the ordering, or check the validity of their input arguments. These facilities are provided by {\tt MC47A/AD} and other subroutines from HSL. Only one {\tt integer} version of each Fortran routine is provided. Both Fortran routines overwrite the user's input matrix, in contrast to the C version. % The C version does not return the elimination or assembly tree. The Fortran version returns an assembly tree; refer to the User Guide for details. The following is the syntax of the {\tt AMD} Fortran routine. The {\tt AMDBAR} routine is identical except for the routine name. {\footnotesize \begin{verbatim} INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N), DEGREE (N), NV (N), $ NEXT (N), LAST (N), HEAD (N), ELEN (N), W (N), LEN (N) CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, $ LAST, HEAD, ELEN, DEGREE, NCMPA, W) CALL AMDBAR (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, $ LAST, HEAD, ELEN, DEGREE, NCMPA, W) \end{verbatim} } The input matrix is provided to {\tt AMD} and {\tt AMDBAR} in three arrays, {\tt PE}, of size {\tt N}, {\tt LEN}, of size {\tt N}, and {\tt IW}, of size {\tt IWLEN}. The size of {\tt IW} must be at least {\tt NZ+N}. The recommended size is {\tt 1.2*NZ + N}. On input, the indices of nonzero entries in row {\tt I} are stored in {\tt IW}. {\tt PE(I)} is the index in {\tt IW} of the start of row {\tt I}. {\tt LEN(I)} is the number of entries in row {\tt I}. The matrix is 1-based, with row and column indices in the range 1 to {\tt N}. Row {\tt I} is contained in {\tt IW (PE(I)} $\ldots \:$ {\tt PE(I) + LEN(I) - 1)}. The diagonal entries must not be present. The indices within each row must not contain any duplicates, but they need not be sorted. The rows themselves need not be in any particular order, and there may be empty space between the rows. If {\tt LEN(I)} is zero, then there are no off-diagonal entries in row {\tt I}, and {\tt PE(I)} is ignored. The integer {\tt PFREE} defines what part of {\tt IW} contains the user's input matrix, which is held in {\tt IW(1}~$\ldots~\:${\tt PFREE-1)}. The contents of {\tt IW} and {\tt LEN} are undefined on output, and {\tt PE} is modified to contain information about the ordering. As the algorithm proceeds, it modifies the {\tt IW} array, placing the pattern of the partially eliminated matrix in {\tt IW(PFREE} $\ldots \:${\tt IWLEN)}. If this space is exhausted, the space is compressed. The number of compressions performed on the {\tt IW} array is returned in the scalar {\tt NCMPA}. The value of {\tt PFREE} on output is the length of {\tt IW} required for no compressions to be needed. The output permutation is returned in the array {\tt LAST}, of size {\tt N}. If {\tt I=LAST(K)}, then {\tt I} is the {\tt K}th row in the permuted matrix. The inverse permutation is returned in the array {\tt ELEN}, where {\tt K=ELEN(I)} if {\tt I} is the {\tt K}th row in the permuted matrix. On output, the {\tt PE} and {\tt NV} arrays hold the assembly tree, a supernodal elimination tree that represents the relationship between columns of the Cholesky factor $\m{L}$. If {\tt NV(I)} $> 0$, then {\tt I} is a node in the assembly tree, and the parent of {\tt I} is {\tt -PE(I)}. If {\tt I} is a root of the tree, then {\tt PE(I)} is zero. The value of {\tt NV(I)} is the number of entries in the corresponding column of $\m{L}$, including the diagonal. If {\tt NV(I)} is zero, then {\tt I} is a non-principal node that is not in the assembly tree. Node {\tt -PE(I)} is the parent of node {\tt I} in a subtree, the root of which is a node in the assembly tree. All nodes in one subtree belong to the same supernode in the assembly tree. The other size {\tt N} arrays ({\tt DEGREE}, {\tt HEAD}, {\tt NEXT}, and {\tt W}) are used as workspace, and are not defined on input or output. If you want to use a simpler user-interface and compute the elimination tree post-ordering, you should be able to call the C routines {\tt amd\_order} or {\tt amd\_l\_order} from a Fortran program. Just be sure to take into account the 0-based indexing in the {\tt P}, {\tt Ap}, and {\tt Ai} arguments to {\tt amd\_order} and {\tt amd\_l\_order}. A sample interface is provided in the files {\tt AMD/Demo/amd\_f77cross.f} and {\tt AMD/Demo/amd\_f77wrapper.c}. To compile the {\tt amd\_f77cross} program, type {\tt make cross} in the {\tt AMD/Demo} directory. The Fortran-to-C calling conventions are highly non-portable, so this example is not guaranteed to work with your compiler C and Fortran compilers. The output of {\tt amd\_f77cross} is in {\tt amd\_f77cross.out}. %------------------------------------------------------------------------------ \section{Sample Fortran main program} %------------------------------------------------------------------------------ The following program illustrates the basic usage of the Fortran version of AMD. The {\tt AP} and {\tt AI} arrays represent the binary matrix \[ \m{A} = \left[ \begin{array}{rrrrr} 1 & 1 & 0 & 0 & 0 \\ 1 & 1 & 1 & 0 & 1 \\ 0 & 1 & 1 & 1 & 1 \\ 0 & 0 & 1 & 1 & 0 \\ 0 & 1 & 1 & 0 & 1 \\ \end{array} \right] \] in a conventional 1-based column-oriented form, except that the diagonal entries are not present. The matrix has the same as nonzero pattern of $\m{A}+\m{A}\tr$ in the C program, in Section~\ref{Cversion}. The output permutation is $(4, 1, 3, 5, 2)$. It differs from the permutation returned by the C routine {\tt amd\_order} because a post-order of the elimination tree has not yet been performed. {\footnotesize \begin{verbatim} INTEGER N, NZ, J, K, P, IWLEN, PFREE, NCMPA PARAMETER (N = 5, NZ = 10, IWLEN = 17) INTEGER AP (N+1), AI (NZ), LAST (N), PE (N), LEN (N), ELEN (N), $ IW (IWLEN), DEGREE (N), NV (N), NEXT (N), HEAD (N), W (N) DATA AP / 1, 2, 5, 8, 9, 11/ DATA AI / 2, 1,3,5, 2,4,5, 3, 2,3 / C load the matrix into the AMD workspace DO 10 J = 1,N PE (J) = AP (J) LEN (J) = AP (J+1) - AP (J) 10 CONTINUE DO 20 P = 1,NZ IW (P) = AI (P) 20 CONTINUE PFREE = NZ + 1 C order the matrix (destroys the copy of A in IW, PE, and LEN) CALL AMD (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, LAST, HEAD, $ ELEN, DEGREE, NCMPA, W) DO 60 K = 1, N PRINT 50, K, LAST (K) 50 FORMAT ('P (',I2,') = ', I2) 60 CONTINUE END \end{verbatim} } The {\tt Demo} directory contains an example of how the C version may be called from a Fortran program, but this is highly non-portable. For this reason, it is placed in the {\tt Demo} directory, not in the primary {\tt Source} directory. %------------------------------------------------------------------------------ \section{Installation} \label{Install} %------------------------------------------------------------------------------ The following discussion assumes you have the {\tt make} program, either in Unix, or in Windows with Cygwin. System-dependent configurations are in the {\tt ../UFconfig/UFconfig.mk} file. You can edit that file to customize the compilation. The default settings will work on most systems. Sample configuration files are provided for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha. To compile and install the C-callable AMD library, go to the {\tt AMD} directory and type {\tt make}. The library will be placed in {\tt AMD/Lib/libamd.a}. Three demo programs of the AMD ordering routine will be compiled and tested in the {\tt AMD/Demo} directory. The outputs of these demo programs will then be compared with output files in the distribution. To compile and install the Fortran-callable AMD library, go to the {\tt AMD} directory and type {\tt make fortran}. The library will be placed in {\tt AMD/Lib/libamdf77.a}. A demo program will be compiled and tested in the {\tt AMD/Demo} directory. The output will be compared with an output file in the distribution. Typing {\tt make clean} will remove all but the final compiled libraries and demo programs. Typing {\tt make purge} or {\tt make distclean} removes all files not in the original distribution. If you compile AMD and then later change the {\tt ../UFconfig/UFconfig.mk} file then you should type {\tt make purge} and then {\tt make} to recompile. When you compile your program that uses the C-callable AMD library, you need to add the {\tt AMD/Lib/libamd.a} library and you need to tell your compiler to look in the {\tt AMD/Include} directory for include files. To compile a Fortran program that calls the Fortran AMD library, you need to add the {\tt AMD/Lib/libamdf77.a} library. See {\tt AMD/Demo/Makefile} for an example. If all you want to use is the AMD2 mexFunction in MATLAB, you can skip the use of the {\tt make} command entirely. Simply type {\tt amd\_make} in MATLAB while in the {\tt AMD/MATLAB} directory. This works on any system with MATLAB, including Windows. Alternately, type {\tt make} in the {\tt AMD/MATLAB} directory, or just use the built-in {\tt amd} in MATLAB 7.3 or later. If you have MATLAB 7.2 or earlier, you must first edit UFconfig/UFconfig.h to remove the "-largeArrayDims" option from the MEX command, prior to {\tt make mex} or {\tt make} in the MATLAB directory (or just use {\tt amd\_make.m} inside MATLAB. If you are including AMD as a subset of a larger library and do not want to link the C standard I/O library, or if you simply do not need to use them, you can safely remove the {\tt amd\_control.c} and {\tt amd\_info.c} files. Similarly, if you use default parameters (or define your own {\tt Control} array), then you can exclude the {\tt amd\_defaults.c} file. Each of these files contains the user-callable routines of the same name. None of these auxiliary routines are directly called by {\tt amd\_order}. The {\tt amd\_dump.c} file contains debugging routines that are neither used nor compiled unless debugging is enabled. The {\tt amd\_internal.h} file must be edited to enable debugging; refer to the instructions in that file. The bare minimum files required to use just {\tt amd\_order} are {\tt amd.h} and {\tt amd\_internal.h} in the {\tt Include} directory, and {\tt amd\_1.c}, {\tt amd\_2.c}, {\tt amd\_aat.c}, {\tt amd\_global.c}, {\tt and\_order.c}, {\tt amd\_postorder.c}, {\tt amd\_post\_tree.c}, {\tt amd\_preprocess.c}, and {\tt amd\_valid.c} in the {\tt Source} directory. %------------------------------------------------------------------------------ \newpage \section{The AMD routines} \label{Primary} %------------------------------------------------------------------------------ The file {\tt AMD/Include/amd.h} listed below describes each user-callable routine in the C version of AMD, and gives details on their use. {\footnotesize \begin{verbatim} /* ========================================================================= */ /* === AMD: approximate minimum degree ordering =========================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD Version 2.2, Copyright (c) 2007 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD finds a symmetric ordering P of a matrix A so that the Cholesky * factorization of P*A*P' has fewer nonzeros and takes less work than the * Cholesky factorization of A. If A is not symmetric, then it performs its * ordering on the matrix A+A'. Two sets of user-callable routines are * provided, one for int integers and the other for UF_long integers. * * The method is based on the approximate minimum degree algorithm, discussed * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm", * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp. * 886-905, 1996. This package can perform both the AMD ordering (with * aggressive absorption), and the AMDBAR ordering (without aggressive * absorption) discussed in the above paper. This package differs from the * Fortran codes discussed in the paper: * * (1) it can ignore "dense" rows and columns, leading to faster run times * (2) it computes the ordering of A+A' if A is not symmetric * (3) it is followed by a depth-first post-ordering of the assembly tree * (or supernodal elimination tree) * * For historical reasons, the Fortran versions, amd.f and amdbar.f, have * been left (nearly) unchanged. They compute the identical ordering as * described in the above paper. */ #ifndef AMD_H #define AMD_H /* make it easy for C++ programs to include AMD */ #ifdef __cplusplus extern "C" { #endif /* get the definition of size_t: */ #include /* define UF_long */ #include "UFconfig.h" int amd_order /* returns AMD_OK, AMD_OK_BUT_JUMBLED, * AMD_INVALID, or AMD_OUT_OF_MEMORY */ ( int n, /* A is n-by-n. n must be >= 0. */ const int Ap [ ], /* column pointers for A, of size n+1 */ const int Ai [ ], /* row indices of A, of size nz = Ap [n] */ int P [ ], /* output permutation, of size n */ double Control [ ], /* input Control settings, of size AMD_CONTROL */ double Info [ ] /* output Info statistics, of size AMD_INFO */ ) ; UF_long amd_l_order /* see above for description of arguments */ ( UF_long n, const UF_long Ap [ ], const UF_long Ai [ ], UF_long P [ ], double Control [ ], double Info [ ] ) ; /* Input arguments (not modified): * * n: the matrix A is n-by-n. * Ap: an int/UF_long array of size n+1, containing column pointers of A. * Ai: an int/UF_long array of size nz, containing the row indices of A, * where nz = Ap [n]. * Control: a double array of size AMD_CONTROL, containing control * parameters. Defaults are used if Control is NULL. * * Output arguments (not defined on input): * * P: an int/UF_long array of size n, containing the output permutation. If * row i is the kth pivot row, then P [k] = i. In MATLAB notation, * the reordered matrix is A (P,P). * Info: a double array of size AMD_INFO, containing statistical * information. Ignored if Info is NULL. * * On input, the matrix A is stored in column-oriented form. The row indices * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1]. * * If the row indices appear in ascending order in each column, and there * are no duplicate entries, then amd_order is slightly more efficient in * terms of time and memory usage. If this condition does not hold, a copy * of the matrix is created (where these conditions do hold), and the copy is * ordered. This feature is new to v2.0 (v1.2 and earlier required this * condition to hold for the input matrix). * * Row indices must be in the range 0 to * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n]. * The matrix does not need to be symmetric, and the diagonal does not need to * be present (if diagonal entries are present, they are ignored except for * the output statistic Info [AMD_NZDIAG]). The arrays Ai and Ap are not * modified. This form of the Ap and Ai arrays to represent the nonzero * pattern of the matrix A is the same as that used internally by MATLAB. * If you wish to use a more flexible input structure, please see the * umfpack_*_triplet_to_col routines in the UMFPACK package, at * http://www.cise.ufl.edu/research/sparse/umfpack. * * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the * range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0 * to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these * restrictions are not met, AMD returns AMD_INVALID. * * AMD returns: * * AMD_OK if the matrix is valid and sufficient memory can be allocated to * perform the ordering. * * AMD_OUT_OF_MEMORY if not enough memory can be allocated. * * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is * NULL. * * AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate * entries, but was otherwise valid. * * The AMD routine first forms the pattern of the matrix A+A', and then * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of * the original is the kth pivotal row. In MATLAB notation, the permuted * matrix is A (P,P), except that 0-based indexing is used instead of the * 1-based indexing in MATLAB. * * The Control array is used to set various parameters for AMD. If a NULL * pointer is passed, default values are used. The Control array is not * modified. * * Control [AMD_DENSE]: controls the threshold for "dense" rows/columns. * A dense row/column in A+A' can cause AMD to spend a lot of time in * ordering the matrix. If Control [AMD_DENSE] >= 0, rows/columns * with more than Control [AMD_DENSE] * sqrt (n) entries are ignored * during the ordering, and placed last in the output order. The * default value of Control [AMD_DENSE] is 10. If negative, no * rows/columns are treated as "dense". Rows/columns with 16 or * fewer off-diagonal entries are never considered "dense". * * Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive * absorption, in which a prior element is absorbed into the current * element if is a subset of the current element, even if it is not * adjacent to the current pivot element (refer to Amestoy, Davis, * & Duff, 1996, for more details). The default value is nonzero, * which means to perform aggressive absorption. This nearly always * leads to a better ordering (because the approximate degrees are * more accurate) and a lower execution time. There are cases where * it can lead to a slightly worse ordering, however. To turn it off, * set Control [AMD_AGGRESSIVE] to 0. * * Control [2..4] are not used in the current version, but may be used in * future versions. * * The Info array provides statistics about the ordering on output. If it is * not present, the statistics are not returned. This is not an error * condition. * * Info [AMD_STATUS]: the return value of AMD, either AMD_OK, * AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID. * * Info [AMD_N]: n, the size of the input matrix * * Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n] * * Info [AMD_SYMMETRY]: the symmetry of the matrix A. It is the number * of "matched" off-diagonal entries divided by the total number of * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also * an entry, for any pair (i,j) for which i != j. In MATLAB notation, * S = spones (A) ; * B = tril (S, -1) + triu (S, 1) ; * symmetry = nnz (B & B') / nnz (B) ; * * Info [AMD_NZDIAG]: the number of entries on the diagonal of A. * * Info [AMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the * diagonal. If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1) * with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n * (the smallest possible value). If A is perfectly unsymmetric * (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for * example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz * (the largest possible value). * * Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were * removed from A prior to ordering. These are placed last in the * output order P. * * Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes. In the * current version, this is 1.2 * Info [AMD_NZ_A_PLUS_AT] + 9*n * times the size of an integer. This is at most 2.4nz + 9n. This * excludes the size of the input arguments Ai, Ap, and P, which have * a total size of nz + 2*n + 1 integers. * * Info [AMD_NCMPA]: the number of garbage collections performed. * * Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal). * This is a slight upper bound because mass elimination is combined * with the approximate degree update. It is a rough upper bound if * there are many "dense" rows/columns. The rest of the statistics, * below, are also slight or rough upper bounds, for the same reasons. * The post-ordering of the assembly tree might also not exactly * correspond to a true elimination tree postordering. * * Info [AMD_NDIV]: the number of divide operations for a subsequent LDL' * or LU factorization of the permuted matrix A (P,P). * * Info [AMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a * subsequent LDL' factorization of A (P,P). * * Info [AMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a * subsequent LU factorization of A (P,P), assuming that no numerical * pivoting is required. * * Info [AMD_DMAX]: the maximum number of nonzeros in any column of L, * including the diagonal. * * Info [14..19] are not used in the current version, but may be used in * future versions. */ /* ------------------------------------------------------------------------- */ /* direct interface to AMD */ /* ------------------------------------------------------------------------- */ /* amd_2 is the primary AMD ordering routine. It is not meant to be * user-callable because of its restrictive inputs and because it destroys * the user's input matrix. It does not check its inputs for errors, either. * However, if you can work with these restrictions it can be faster than * amd_order and use less memory (assuming that you can create your own copy * of the matrix for AMD to destroy). Refer to AMD/Source/amd_2.c for a * description of each parameter. */ void amd_2 ( int n, int Pe [ ], int Iw [ ], int Len [ ], int iwlen, int pfree, int Nv [ ], int Next [ ], int Last [ ], int Head [ ], int Elen [ ], int Degree [ ], int W [ ], double Control [ ], double Info [ ] ) ; void amd_l2 ( UF_long n, UF_long Pe [ ], UF_long Iw [ ], UF_long Len [ ], UF_long iwlen, UF_long pfree, UF_long Nv [ ], UF_long Next [ ], UF_long Last [ ], UF_long Head [ ], UF_long Elen [ ], UF_long Degree [ ], UF_long W [ ], double Control [ ], double Info [ ] ) ; /* ------------------------------------------------------------------------- */ /* amd_valid */ /* ------------------------------------------------------------------------- */ /* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to * amd_order; the latter is returned if the matrix has unsorted and/or * duplicate row indices in one or more columns. Returns AMD_INVALID if the * matrix cannot be passed to amd_order. For amd_order, the matrix must also * be square. The first two arguments are the number of rows and the number * of columns of the matrix. For its use in AMD, these must both equal n. * * NOTE: this routine returned TRUE/FALSE in v1.2 and earlier. */ int amd_valid ( int n_row, /* # of rows */ int n_col, /* # of columns */ const int Ap [ ], /* column pointers, of size n_col+1 */ const int Ai [ ] /* row indices, of size Ap [n_col] */ ) ; UF_long amd_l_valid ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ] ) ; /* ------------------------------------------------------------------------- */ /* AMD memory manager and printf routines */ /* ------------------------------------------------------------------------- */ /* The user can redefine these to change the malloc, free, and printf routines * that AMD uses. */ #ifndef EXTERN #define EXTERN extern #endif EXTERN void *(*amd_malloc) (size_t) ; /* pointer to malloc */ EXTERN void (*amd_free) (void *) ; /* pointer to free */ EXTERN void *(*amd_realloc) (void *, size_t) ; /* pointer to realloc */ EXTERN void *(*amd_calloc) (size_t, size_t) ; /* pointer to calloc */ EXTERN int (*amd_printf) (const char *, ...) ; /* pointer to printf */ /* ------------------------------------------------------------------------- */ /* AMD Control and Info arrays */ /* ------------------------------------------------------------------------- */ /* amd_defaults: sets the default control settings */ void amd_defaults (double Control [ ]) ; void amd_l_defaults (double Control [ ]) ; /* amd_control: prints the control settings */ void amd_control (double Control [ ]) ; void amd_l_control (double Control [ ]) ; /* amd_info: prints the statistics */ void amd_info (double Info [ ]) ; void amd_l_info (double Info [ ]) ; #define AMD_CONTROL 5 /* size of Control array */ #define AMD_INFO 20 /* size of Info array */ /* contents of Control */ #define AMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */ #define AMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */ /* default Control settings */ #define AMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */ #define AMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */ /* contents of Info */ #define AMD_STATUS 0 /* return value of amd_order and amd_l_order */ #define AMD_N 1 /* A is n-by-n */ #define AMD_NZ 2 /* number of nonzeros in A */ #define AMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */ #define AMD_NZDIAG 4 /* # of entries on diagonal */ #define AMD_NZ_A_PLUS_AT 5 /* nz in A+A' */ #define AMD_NDENSE 6 /* number of "dense" rows/columns in A */ #define AMD_MEMORY 7 /* amount of memory used by AMD */ #define AMD_NCMPA 8 /* number of garbage collections in AMD */ #define AMD_LNZ 9 /* approx. nz in L, excluding the diagonal */ #define AMD_NDIV 10 /* number of fl. point divides for LU and LDL' */ #define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */ #define AMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */ #define AMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */ /* ------------------------------------------------------------------------- */ /* return values of AMD */ /* ------------------------------------------------------------------------- */ #define AMD_OK 0 /* success */ #define AMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */ #define AMD_INVALID -2 /* input arguments are not valid */ #define AMD_OK_BUT_JUMBLED 1 /* input matrix is OK for amd_order, but * columns were not sorted, and/or duplicate entries were present. AMD had * to do extra work before ordering the matrix. This is a warning, not an * error. */ /* ========================================================================== */ /* === AMD version ========================================================== */ /* ========================================================================== */ /* AMD Version 1.2 and later include the following definitions. * As an example, to test if the version you are using is 1.2 or later: * * #ifdef AMD_VERSION * if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ... * #endif * * This also works during compile-time: * * #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2)) * printf ("This is version 1.2 or later\n") ; * #else * printf ("This is an early version\n") ; * #endif * * Versions 1.1 and earlier of AMD do not include a #define'd version number. */ #define AMD_DATE "May 31, 2007" #define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) #define AMD_MAIN_VERSION 2 #define AMD_SUB_VERSION 2 #define AMD_SUBSUB_VERSION 0 #define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION) #ifdef __cplusplus } #endif #endif #endif \end{verbatim} } %------------------------------------------------------------------------------ \newpage % References %------------------------------------------------------------------------------ \bibliographystyle{plain} \bibliography{AMD_UserGuide} \end{document} cvxopt-1.1.4/src/C/SuiteSparse/AMD/Include/0000755000175000017500000000000011674452555017310 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/AMD/Include/amd.h0000644000175000017500000004161511674452555020231 0ustar sonnesonne/* ========================================================================= */ /* === AMD: approximate minimum degree ordering =========================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD Version 2.2, Copyright (c) 2007 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD finds a symmetric ordering P of a matrix A so that the Cholesky * factorization of P*A*P' has fewer nonzeros and takes less work than the * Cholesky factorization of A. If A is not symmetric, then it performs its * ordering on the matrix A+A'. Two sets of user-callable routines are * provided, one for int integers and the other for UF_long integers. * * The method is based on the approximate minimum degree algorithm, discussed * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm", * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp. * 886-905, 1996. This package can perform both the AMD ordering (with * aggressive absorption), and the AMDBAR ordering (without aggressive * absorption) discussed in the above paper. This package differs from the * Fortran codes discussed in the paper: * * (1) it can ignore "dense" rows and columns, leading to faster run times * (2) it computes the ordering of A+A' if A is not symmetric * (3) it is followed by a depth-first post-ordering of the assembly tree * (or supernodal elimination tree) * * For historical reasons, the Fortran versions, amd.f and amdbar.f, have * been left (nearly) unchanged. They compute the identical ordering as * described in the above paper. */ #ifndef AMD_H #define AMD_H /* make it easy for C++ programs to include AMD */ #ifdef __cplusplus extern "C" { #endif /* get the definition of size_t: */ #include /* define UF_long */ #include "UFconfig.h" int amd_order /* returns AMD_OK, AMD_OK_BUT_JUMBLED, * AMD_INVALID, or AMD_OUT_OF_MEMORY */ ( int n, /* A is n-by-n. n must be >= 0. */ const int Ap [ ], /* column pointers for A, of size n+1 */ const int Ai [ ], /* row indices of A, of size nz = Ap [n] */ int P [ ], /* output permutation, of size n */ double Control [ ], /* input Control settings, of size AMD_CONTROL */ double Info [ ] /* output Info statistics, of size AMD_INFO */ ) ; UF_long amd_l_order /* see above for description of arguments */ ( UF_long n, const UF_long Ap [ ], const UF_long Ai [ ], UF_long P [ ], double Control [ ], double Info [ ] ) ; /* Input arguments (not modified): * * n: the matrix A is n-by-n. * Ap: an int/UF_long array of size n+1, containing column pointers of A. * Ai: an int/UF_long array of size nz, containing the row indices of A, * where nz = Ap [n]. * Control: a double array of size AMD_CONTROL, containing control * parameters. Defaults are used if Control is NULL. * * Output arguments (not defined on input): * * P: an int/UF_long array of size n, containing the output permutation. If * row i is the kth pivot row, then P [k] = i. In MATLAB notation, * the reordered matrix is A (P,P). * Info: a double array of size AMD_INFO, containing statistical * information. Ignored if Info is NULL. * * On input, the matrix A is stored in column-oriented form. The row indices * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1]. * * If the row indices appear in ascending order in each column, and there * are no duplicate entries, then amd_order is slightly more efficient in * terms of time and memory usage. If this condition does not hold, a copy * of the matrix is created (where these conditions do hold), and the copy is * ordered. This feature is new to v2.0 (v1.2 and earlier required this * condition to hold for the input matrix). * * Row indices must be in the range 0 to * n-1. Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros * in A. The array Ap is of size n+1, and the array Ai is of size nz = Ap [n]. * The matrix does not need to be symmetric, and the diagonal does not need to * be present (if diagonal entries are present, they are ignored except for * the output statistic Info [AMD_NZDIAG]). The arrays Ai and Ap are not * modified. This form of the Ap and Ai arrays to represent the nonzero * pattern of the matrix A is the same as that used internally by MATLAB. * If you wish to use a more flexible input structure, please see the * umfpack_*_triplet_to_col routines in the UMFPACK package, at * http://www.cise.ufl.edu/research/sparse/umfpack. * * Restrictions: n >= 0. Ap [0] = 0. Ap [j] <= Ap [j+1] for all j in the * range 0 to n-1. nz = Ap [n] >= 0. Ai [0..nz-1] must be in the range 0 * to n-1. Finally, Ai, Ap, and P must not be NULL. If any of these * restrictions are not met, AMD returns AMD_INVALID. * * AMD returns: * * AMD_OK if the matrix is valid and sufficient memory can be allocated to * perform the ordering. * * AMD_OUT_OF_MEMORY if not enough memory can be allocated. * * AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is * NULL. * * AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate * entries, but was otherwise valid. * * The AMD routine first forms the pattern of the matrix A+A', and then * computes a fill-reducing ordering, P. If P [k] = i, then row/column i of * the original is the kth pivotal row. In MATLAB notation, the permuted * matrix is A (P,P), except that 0-based indexing is used instead of the * 1-based indexing in MATLAB. * * The Control array is used to set various parameters for AMD. If a NULL * pointer is passed, default values are used. The Control array is not * modified. * * Control [AMD_DENSE]: controls the threshold for "dense" rows/columns. * A dense row/column in A+A' can cause AMD to spend a lot of time in * ordering the matrix. If Control [AMD_DENSE] >= 0, rows/columns * with more than Control [AMD_DENSE] * sqrt (n) entries are ignored * during the ordering, and placed last in the output order. The * default value of Control [AMD_DENSE] is 10. If negative, no * rows/columns are treated as "dense". Rows/columns with 16 or * fewer off-diagonal entries are never considered "dense". * * Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive * absorption, in which a prior element is absorbed into the current * element if is a subset of the current element, even if it is not * adjacent to the current pivot element (refer to Amestoy, Davis, * & Duff, 1996, for more details). The default value is nonzero, * which means to perform aggressive absorption. This nearly always * leads to a better ordering (because the approximate degrees are * more accurate) and a lower execution time. There are cases where * it can lead to a slightly worse ordering, however. To turn it off, * set Control [AMD_AGGRESSIVE] to 0. * * Control [2..4] are not used in the current version, but may be used in * future versions. * * The Info array provides statistics about the ordering on output. If it is * not present, the statistics are not returned. This is not an error * condition. * * Info [AMD_STATUS]: the return value of AMD, either AMD_OK, * AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID. * * Info [AMD_N]: n, the size of the input matrix * * Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n] * * Info [AMD_SYMMETRY]: the symmetry of the matrix A. It is the number * of "matched" off-diagonal entries divided by the total number of * off-diagonal entries. An entry A(i,j) is matched if A(j,i) is also * an entry, for any pair (i,j) for which i != j. In MATLAB notation, * S = spones (A) ; * B = tril (S, -1) + triu (S, 1) ; * symmetry = nnz (B & B') / nnz (B) ; * * Info [AMD_NZDIAG]: the number of entries on the diagonal of A. * * Info [AMD_NZ_A_PLUS_AT]: the number of nonzeros in A+A', excluding the * diagonal. If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1) * with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n * (the smallest possible value). If A is perfectly unsymmetric * (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for * example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz * (the largest possible value). * * Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were * removed from A prior to ordering. These are placed last in the * output order P. * * Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes. In the * current version, this is 1.2 * Info [AMD_NZ_A_PLUS_AT] + 9*n * times the size of an integer. This is at most 2.4nz + 9n. This * excludes the size of the input arguments Ai, Ap, and P, which have * a total size of nz + 2*n + 1 integers. * * Info [AMD_NCMPA]: the number of garbage collections performed. * * Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal). * This is a slight upper bound because mass elimination is combined * with the approximate degree update. It is a rough upper bound if * there are many "dense" rows/columns. The rest of the statistics, * below, are also slight or rough upper bounds, for the same reasons. * The post-ordering of the assembly tree might also not exactly * correspond to a true elimination tree postordering. * * Info [AMD_NDIV]: the number of divide operations for a subsequent LDL' * or LU factorization of the permuted matrix A (P,P). * * Info [AMD_NMULTSUBS_LDL]: the number of multiply-subtract pairs for a * subsequent LDL' factorization of A (P,P). * * Info [AMD_NMULTSUBS_LU]: the number of multiply-subtract pairs for a * subsequent LU factorization of A (P,P), assuming that no numerical * pivoting is required. * * Info [AMD_DMAX]: the maximum number of nonzeros in any column of L, * including the diagonal. * * Info [14..19] are not used in the current version, but may be used in * future versions. */ /* ------------------------------------------------------------------------- */ /* direct interface to AMD */ /* ------------------------------------------------------------------------- */ /* amd_2 is the primary AMD ordering routine. It is not meant to be * user-callable because of its restrictive inputs and because it destroys * the user's input matrix. It does not check its inputs for errors, either. * However, if you can work with these restrictions it can be faster than * amd_order and use less memory (assuming that you can create your own copy * of the matrix for AMD to destroy). Refer to AMD/Source/amd_2.c for a * description of each parameter. */ void amd_2 ( int n, int Pe [ ], int Iw [ ], int Len [ ], int iwlen, int pfree, int Nv [ ], int Next [ ], int Last [ ], int Head [ ], int Elen [ ], int Degree [ ], int W [ ], double Control [ ], double Info [ ] ) ; void amd_l2 ( UF_long n, UF_long Pe [ ], UF_long Iw [ ], UF_long Len [ ], UF_long iwlen, UF_long pfree, UF_long Nv [ ], UF_long Next [ ], UF_long Last [ ], UF_long Head [ ], UF_long Elen [ ], UF_long Degree [ ], UF_long W [ ], double Control [ ], double Info [ ] ) ; /* ------------------------------------------------------------------------- */ /* amd_valid */ /* ------------------------------------------------------------------------- */ /* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to * amd_order; the latter is returned if the matrix has unsorted and/or * duplicate row indices in one or more columns. Returns AMD_INVALID if the * matrix cannot be passed to amd_order. For amd_order, the matrix must also * be square. The first two arguments are the number of rows and the number * of columns of the matrix. For its use in AMD, these must both equal n. * * NOTE: this routine returned TRUE/FALSE in v1.2 and earlier. */ int amd_valid ( int n_row, /* # of rows */ int n_col, /* # of columns */ const int Ap [ ], /* column pointers, of size n_col+1 */ const int Ai [ ] /* row indices, of size Ap [n_col] */ ) ; UF_long amd_l_valid ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ] ) ; /* ------------------------------------------------------------------------- */ /* AMD memory manager and printf routines */ /* ------------------------------------------------------------------------- */ /* The user can redefine these to change the malloc, free, and printf routines * that AMD uses. */ #ifndef EXTERN #define EXTERN extern #endif EXTERN void *(*amd_malloc) (size_t) ; /* pointer to malloc */ EXTERN void (*amd_free) (void *) ; /* pointer to free */ EXTERN void *(*amd_realloc) (void *, size_t) ; /* pointer to realloc */ EXTERN void *(*amd_calloc) (size_t, size_t) ; /* pointer to calloc */ EXTERN int (*amd_printf) (const char *, ...) ; /* pointer to printf */ /* ------------------------------------------------------------------------- */ /* AMD Control and Info arrays */ /* ------------------------------------------------------------------------- */ /* amd_defaults: sets the default control settings */ void amd_defaults (double Control [ ]) ; void amd_l_defaults (double Control [ ]) ; /* amd_control: prints the control settings */ void amd_control (double Control [ ]) ; void amd_l_control (double Control [ ]) ; /* amd_info: prints the statistics */ void amd_info (double Info [ ]) ; void amd_l_info (double Info [ ]) ; #define AMD_CONTROL 5 /* size of Control array */ #define AMD_INFO 20 /* size of Info array */ /* contents of Control */ #define AMD_DENSE 0 /* "dense" if degree > Control [0] * sqrt (n) */ #define AMD_AGGRESSIVE 1 /* do aggressive absorption if Control [1] != 0 */ /* default Control settings */ #define AMD_DEFAULT_DENSE 10.0 /* default "dense" degree 10*sqrt(n) */ #define AMD_DEFAULT_AGGRESSIVE 1 /* do aggressive absorption by default */ /* contents of Info */ #define AMD_STATUS 0 /* return value of amd_order and amd_l_order */ #define AMD_N 1 /* A is n-by-n */ #define AMD_NZ 2 /* number of nonzeros in A */ #define AMD_SYMMETRY 3 /* symmetry of pattern (1 is sym., 0 is unsym.) */ #define AMD_NZDIAG 4 /* # of entries on diagonal */ #define AMD_NZ_A_PLUS_AT 5 /* nz in A+A' */ #define AMD_NDENSE 6 /* number of "dense" rows/columns in A */ #define AMD_MEMORY 7 /* amount of memory used by AMD */ #define AMD_NCMPA 8 /* number of garbage collections in AMD */ #define AMD_LNZ 9 /* approx. nz in L, excluding the diagonal */ #define AMD_NDIV 10 /* number of fl. point divides for LU and LDL' */ #define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */ #define AMD_NMULTSUBS_LU 12 /* number of fl. point (*,-) pairs for LU */ #define AMD_DMAX 13 /* max nz. in any column of L, incl. diagonal */ /* ------------------------------------------------------------------------- */ /* return values of AMD */ /* ------------------------------------------------------------------------- */ #define AMD_OK 0 /* success */ #define AMD_OUT_OF_MEMORY -1 /* malloc failed, or problem too large */ #define AMD_INVALID -2 /* input arguments are not valid */ #define AMD_OK_BUT_JUMBLED 1 /* input matrix is OK for amd_order, but * columns were not sorted, and/or duplicate entries were present. AMD had * to do extra work before ordering the matrix. This is a warning, not an * error. */ /* ========================================================================== */ /* === AMD version ========================================================== */ /* ========================================================================== */ /* AMD Version 1.2 and later include the following definitions. * As an example, to test if the version you are using is 1.2 or later: * * #ifdef AMD_VERSION * if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ... * #endif * * This also works during compile-time: * * #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2)) * printf ("This is version 1.2 or later\n") ; * #else * printf ("This is an early version\n") ; * #endif * * Versions 1.1 and earlier of AMD do not include a #define'd version number. */ #define AMD_DATE "May 31, 2007" #define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) #define AMD_MAIN_VERSION 2 #define AMD_SUB_VERSION 2 #define AMD_SUBSUB_VERSION 0 #define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION) #ifdef __cplusplus } #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/AMD/Include/amd_internal.h0000644000175000017500000002204411674452555022120 0ustar sonnesonne/* ========================================================================= */ /* === amd_internal.h ====================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* This file is for internal use in AMD itself, and does not normally need to * be included in user code (it is included in UMFPACK, however). All others * should use amd.h instead. * * The following compile-time definitions affect how AMD is compiled. * * -DNPRINT * * Disable all printing. stdio.h will not be included. Printing can * be re-enabled at run-time by setting the global pointer amd_printf * to printf (or mexPrintf for a MATLAB mexFunction). * * -DNMALLOC * * No memory manager is defined at compile-time. You MUST define the * function pointers amd_malloc, amd_free, amd_realloc, and * amd_calloc at run-time for AMD to work properly. */ /* ========================================================================= */ /* === NDEBUG ============================================================== */ /* ========================================================================= */ /* * Turning on debugging takes some work (see below). If you do not edit this * file, then debugging is always turned off, regardless of whether or not * -DNDEBUG is specified in your compiler options. * * If AMD is being compiled as a mexFunction, then MATLAB_MEX_FILE is defined, * and mxAssert is used instead of assert. If debugging is not enabled, no * MATLAB include files or functions are used. Thus, the AMD library libamd.a * can be safely used in either a stand-alone C program or in another * mexFunction, without any change. */ /* AMD will be exceedingly slow when running in debug mode. The next three lines ensure that debugging is turned off. */ #ifndef NDEBUG #define NDEBUG #endif /* To enable debugging, uncomment the following line: #undef NDEBUG */ /* ------------------------------------------------------------------------- */ /* ANSI include files */ /* ------------------------------------------------------------------------- */ /* from stdlib.h: size_t, malloc, free, realloc, and calloc */ #include #if !defined(NPRINT) || !defined(NDEBUG) /* from stdio.h: printf. Not included if NPRINT is defined at compile time. * fopen and fscanf are used when debugging. */ #include #endif /* from limits.h: INT_MAX and LONG_MAX */ #include /* from math.h: sqrt */ #include /* ------------------------------------------------------------------------- */ /* MATLAB include files (only if being used in or via MATLAB) */ /* ------------------------------------------------------------------------- */ #ifdef MATLAB_MEX_FILE #include "matrix.h" #include "mex.h" #endif /* ------------------------------------------------------------------------- */ /* basic definitions */ /* ------------------------------------------------------------------------- */ #ifdef FLIP #undef FLIP #endif #ifdef MAX #undef MAX #endif #ifdef MIN #undef MIN #endif #ifdef EMPTY #undef EMPTY #endif #ifdef GLOBAL #undef GLOBAL #endif #ifdef PRIVATE #undef PRIVATE #endif /* FLIP is a "negation about -1", and is used to mark an integer i that is * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i * for all integers i. UNFLIP (i) is >= EMPTY. */ #define EMPTY (-1) #define FLIP(i) (-(i)-2) #define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i)) /* for integer MAX/MIN, or for doubles when we don't care how NaN's behave: */ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) /* logical expression of p implies q: */ #define IMPLIES(p,q) (!(p) || (q)) /* Note that the IBM RS 6000 xlc predefines TRUE and FALSE in . */ /* The Compaq Alpha also predefines TRUE and FALSE. */ #ifdef TRUE #undef TRUE #endif #ifdef FALSE #undef FALSE #endif #define TRUE (1) #define FALSE (0) #define PRIVATE static #define GLOBAL #define EMPTY (-1) /* Note that Linux's gcc 2.96 defines NULL as ((void *) 0), but other */ /* compilers (even gcc 2.95.2 on Solaris) define NULL as 0 or (0). We */ /* need to use the ANSI standard value of 0. */ #ifdef NULL #undef NULL #endif #define NULL 0 /* largest value of size_t */ #ifndef SIZE_T_MAX #define SIZE_T_MAX ((size_t) (-1)) #endif /* ------------------------------------------------------------------------- */ /* integer type for AMD: int or UF_long */ /* ------------------------------------------------------------------------- */ /* define UF_long */ #include "UFconfig.h" #if defined (DLONG) || defined (ZLONG) #define Int UF_long #define ID UF_long_id #define Int_MAX UF_long_max #define AMD_order amd_l_order #define AMD_defaults amd_l_defaults #define AMD_control amd_l_control #define AMD_info amd_l_info #define AMD_1 amd_l1 #define AMD_2 amd_l2 #define AMD_valid amd_l_valid #define AMD_aat amd_l_aat #define AMD_postorder amd_l_postorder #define AMD_post_tree amd_l_post_tree #define AMD_dump amd_l_dump #define AMD_debug amd_l_debug #define AMD_debug_init amd_l_debug_init #define AMD_preprocess amd_l_preprocess #else #define Int int #define ID "%d" #define Int_MAX INT_MAX #define AMD_order amd_order #define AMD_defaults amd_defaults #define AMD_control amd_control #define AMD_info amd_info #define AMD_1 amd_1 #define AMD_2 amd_2 #define AMD_valid amd_valid #define AMD_aat amd_aat #define AMD_postorder amd_postorder #define AMD_post_tree amd_post_tree #define AMD_dump amd_dump #define AMD_debug amd_debug #define AMD_debug_init amd_debug_init #define AMD_preprocess amd_preprocess #endif /* ========================================================================= */ /* === PRINTF macro ======================================================== */ /* ========================================================================= */ /* All output goes through the PRINTF macro. */ #define PRINTF(params) { if (amd_printf != NULL) (void) amd_printf params ; } /* ------------------------------------------------------------------------- */ /* AMD routine definitions (user-callable) */ /* ------------------------------------------------------------------------- */ #include "amd.h" /* ------------------------------------------------------------------------- */ /* AMD routine definitions (not user-callable) */ /* ------------------------------------------------------------------------- */ GLOBAL size_t AMD_aat ( Int n, const Int Ap [ ], const Int Ai [ ], Int Len [ ], Int Tp [ ], double Info [ ] ) ; GLOBAL void AMD_1 ( Int n, const Int Ap [ ], const Int Ai [ ], Int P [ ], Int Pinv [ ], Int Len [ ], Int slen, Int S [ ], double Control [ ], double Info [ ] ) ; GLOBAL void AMD_postorder ( Int nn, Int Parent [ ], Int Npiv [ ], Int Fsize [ ], Int Order [ ], Int Child [ ], Int Sibling [ ], Int Stack [ ] ) ; GLOBAL Int AMD_post_tree ( Int root, Int k, Int Child [ ], const Int Sibling [ ], Int Order [ ], Int Stack [ ] #ifndef NDEBUG , Int nn #endif ) ; GLOBAL void AMD_preprocess ( Int n, const Int Ap [ ], const Int Ai [ ], Int Rp [ ], Int Ri [ ], Int W [ ], Int Flag [ ] ) ; /* ------------------------------------------------------------------------- */ /* debugging definitions */ /* ------------------------------------------------------------------------- */ #ifndef NDEBUG /* from assert.h: assert macro */ #include #ifndef EXTERN #define EXTERN extern #endif EXTERN Int AMD_debug ; GLOBAL void AMD_debug_init ( char *s ) ; GLOBAL void AMD_dump ( Int n, Int Pe [ ], Int Iw [ ], Int Len [ ], Int iwlen, Int pfree, Int Nv [ ], Int Next [ ], Int Last [ ], Int Head [ ], Int Elen [ ], Int Degree [ ], Int W [ ], Int nel ) ; #ifdef ASSERT #undef ASSERT #endif /* Use mxAssert if AMD is compiled into a mexFunction */ #ifdef MATLAB_MEX_FILE #define ASSERT(expression) (mxAssert ((expression), "")) #else #define ASSERT(expression) (assert (expression)) #endif #define AMD_DEBUG0(params) { PRINTF (params) ; } #define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF (params) ; } #define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF (params) ; } #define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF (params) ; } #define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF (params) ; } #else /* no debugging */ #define ASSERT(expression) #define AMD_DEBUG0(params) #define AMD_DEBUG1(params) #define AMD_DEBUG2(params) #define AMD_DEBUG3(params) #define AMD_DEBUG4(params) #endif cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/0000755000175000017500000000000011674452555017165 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_global.c0000644000175000017500000000627511674452555021424 0ustar sonnesonne/* ========================================================================= */ /* === amd_global ========================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ #include #ifdef MATLAB_MEX_FILE #include "mex.h" #include "matrix.h" #endif #ifndef NULL #define NULL 0 #endif /* ========================================================================= */ /* === Default AMD memory manager ========================================== */ /* ========================================================================= */ /* The user can redefine these global pointers at run-time to change the memory * manager used by AMD. AMD only uses malloc and free; realloc and calloc are * include for completeness, in case another package wants to use the same * memory manager as AMD. * * If compiling as a MATLAB mexFunction, the default memory manager is mxMalloc. * You can also compile AMD as a standard ANSI-C library and link a mexFunction * against it, and then redefine these pointers at run-time, in your * mexFunction. * * If -DNMALLOC is defined at compile-time, no memory manager is specified at * compile-time. You must then define these functions at run-time, before * calling AMD, for AMD to work properly. */ #ifndef NMALLOC #ifdef MATLAB_MEX_FILE /* MATLAB mexFunction: */ void *(*amd_malloc) (size_t) = mxMalloc ; void (*amd_free) (void *) = mxFree ; void *(*amd_realloc) (void *, size_t) = mxRealloc ; void *(*amd_calloc) (size_t, size_t) = mxCalloc ; #else /* standard ANSI-C: */ void *(*amd_malloc) (size_t) = malloc ; void (*amd_free) (void *) = free ; void *(*amd_realloc) (void *, size_t) = realloc ; void *(*amd_calloc) (size_t, size_t) = calloc ; #endif #else /* no memory manager defined at compile-time; you MUST define one at run-time */ void *(*amd_malloc) (size_t) = NULL ; void (*amd_free) (void *) = NULL ; void *(*amd_realloc) (void *, size_t) = NULL ; void *(*amd_calloc) (size_t, size_t) = NULL ; #endif /* ========================================================================= */ /* === Default AMD printf routine ========================================== */ /* ========================================================================= */ /* The user can redefine this global pointer at run-time to change the printf * routine used by AMD. If NULL, no printing occurs. * * If -DNPRINT is defined at compile-time, stdio.h is not included. Printing * can then be enabled at run-time by setting amd_printf to a non-NULL function. */ #ifndef NPRINT #ifdef MATLAB_MEX_FILE int (*amd_printf) (const char *, ...) = mexPrintf ; #else #include int (*amd_printf) (const char *, ...) = printf ; #endif #else int (*amd_printf) (const char *, ...) = NULL ; #endif cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_aat.c0000644000175000017500000001147711674452555020731 0ustar sonnesonne/* ========================================================================= */ /* === AMD_aat ============================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD_aat: compute the symmetry of the pattern of A, and count the number of * nonzeros each column of A+A' (excluding the diagonal). Assumes the input * matrix has no errors, with sorted columns and no duplicates * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not * checked). */ #include "amd_internal.h" GLOBAL size_t AMD_aat /* returns nz in A+A' */ ( Int n, const Int Ap [ ], const Int Ai [ ], Int Len [ ], /* Len [j]: length of column j of A+A', excl diagonal*/ Int Tp [ ], /* workspace of size n */ double Info [ ] ) { Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ; double sym ; size_t nzaat ; #ifndef NDEBUG AMD_debug_init ("AMD AAT") ; for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ; ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; #endif if (Info != (double *) NULL) { /* clear the Info array, if it exists */ for (i = 0 ; i < AMD_INFO ; i++) { Info [i] = EMPTY ; } Info [AMD_STATUS] = AMD_OK ; } for (k = 0 ; k < n ; k++) { Len [k] = 0 ; } nzdiag = 0 ; nzboth = 0 ; nz = Ap [n] ; for (k = 0 ; k < n ; k++) { p1 = Ap [k] ; p2 = Ap [k+1] ; AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ; /* construct A+A' */ for (p = p1 ; p < p2 ; ) { /* scan the upper triangular part of A */ j = Ai [p] ; if (j < k) { /* entry A (j,k) is in the strictly upper triangular part, * add both A (j,k) and A (k,j) to the matrix A+A' */ Len [j]++ ; Len [k]++ ; AMD_DEBUG3 ((" upper ("ID","ID") ("ID","ID")\n", j,k, k,j)); p++ ; } else if (j == k) { /* skip the diagonal */ p++ ; nzdiag++ ; break ; } else /* j > k */ { /* first entry below the diagonal */ break ; } /* scan lower triangular part of A, in column j until reaching * row k. Start where last scan left off. */ ASSERT (Tp [j] != EMPTY) ; ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; pj2 = Ap [j+1] ; for (pj = Tp [j] ; pj < pj2 ; ) { i = Ai [pj] ; if (i < k) { /* A (i,j) is only in the lower part, not in upper. * add both A (i,j) and A (j,i) to the matrix A+A' */ Len [i]++ ; Len [j]++ ; AMD_DEBUG3 ((" lower ("ID","ID") ("ID","ID")\n", i,j, j,i)) ; pj++ ; } else if (i == k) { /* entry A (k,j) in lower part and A (j,k) in upper */ pj++ ; nzboth++ ; break ; } else /* i > k */ { /* consider this entry later, when k advances to i */ break ; } } Tp [j] = pj ; } /* Tp [k] points to the entry just below the diagonal in column k */ Tp [k] = p ; } /* clean up, for remaining mismatched entries */ for (j = 0 ; j < n ; j++) { for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) { i = Ai [pj] ; /* A (i,j) is only in the lower part, not in upper. * add both A (i,j) and A (j,i) to the matrix A+A' */ Len [i]++ ; Len [j]++ ; AMD_DEBUG3 ((" lower cleanup ("ID","ID") ("ID","ID")\n", i,j, j,i)) ; } } /* --------------------------------------------------------------------- */ /* compute the symmetry of the nonzero pattern of A */ /* --------------------------------------------------------------------- */ /* Given a matrix A, the symmetry of A is: * B = tril (spones (A), -1) + triu (spones (A), 1) ; * sym = nnz (B & B') / nnz (B) ; * or 1 if nnz (B) is zero. */ if (nz == nzdiag) { sym = 1 ; } else { sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ; } nzaat = 0 ; for (k = 0 ; k < n ; k++) { nzaat += Len [k] ; } AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n", (double) nzaat)) ; AMD_DEBUG1 ((" nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n", nzboth, nz, nzdiag, sym)) ; if (Info != (double *) NULL) { Info [AMD_STATUS] = AMD_OK ; Info [AMD_N] = n ; Info [AMD_NZ] = nz ; Info [AMD_SYMMETRY] = sym ; /* symmetry of pattern of A */ Info [AMD_NZDIAG] = nzdiag ; /* nonzeros on diagonal of A */ Info [AMD_NZ_A_PLUS_AT] = nzaat ; /* nonzeros in A+A' */ } return (nzaat) ; } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_control.c0000644000175000017500000000351211674452555021633 0ustar sonnesonne/* ========================================================================= */ /* === AMD_control ========================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable. Prints the control parameters for AMD. See amd.h * for details. If the Control array is not present, the defaults are * printed instead. */ #include "amd_internal.h" GLOBAL void AMD_control ( double Control [ ] ) { double alpha ; Int aggressive ; if (Control != (double *) NULL) { alpha = Control [AMD_DENSE] ; aggressive = Control [AMD_AGGRESSIVE] != 0 ; } else { alpha = AMD_DEFAULT_DENSE ; aggressive = AMD_DEFAULT_AGGRESSIVE ; } PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n" " dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ; if (alpha < 0) { PRINTF ((" no rows treated as dense\n")) ; } else { PRINTF (( " (rows with more than max (%g * sqrt (n), 16) entries are\n" " considered \"dense\", and placed last in output permutation)\n", alpha)) ; } if (aggressive) { PRINTF ((" aggressive absorption: yes\n")) ; } else { PRINTF ((" aggressive absorption: no\n")) ; } PRINTF ((" size of AMD integer: %d\n\n", sizeof (Int))) ; } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_dump.c0000644000175000017500000001174411674452555021126 0ustar sonnesonne/* ========================================================================= */ /* === AMD_dump ============================================================ */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Debugging routines for AMD. Not used if NDEBUG is not defined at compile- * time (the default). See comments in amd_internal.h on how to enable * debugging. Not user-callable. */ #include "amd_internal.h" #ifndef NDEBUG /* This global variable is present only when debugging */ GLOBAL Int AMD_debug = -999 ; /* default is no debug printing */ /* ========================================================================= */ /* === AMD_debug_init ====================================================== */ /* ========================================================================= */ /* Sets the debug print level, by reading the file debug.amd (if it exists) */ GLOBAL void AMD_debug_init ( char *s ) { FILE *f ; f = fopen ("debug.amd", "r") ; if (f == (FILE *) NULL) { AMD_debug = -999 ; } else { fscanf (f, ID, &AMD_debug) ; fclose (f) ; } if (AMD_debug >= 0) { printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ; } } /* ========================================================================= */ /* === AMD_dump ============================================================ */ /* ========================================================================= */ /* Dump AMD's data structure, except for the hash buckets. This routine * cannot be called when the hash buckets are non-empty. */ GLOBAL void AMD_dump ( Int n, /* A is n-by-n */ Int Pe [ ], /* pe [0..n-1]: index in iw of start of row i */ Int Iw [ ], /* workspace of size iwlen, iwlen [0..pfree-1] * holds the matrix on input */ Int Len [ ], /* len [0..n-1]: length for row i */ Int iwlen, /* length of iw */ Int pfree, /* iw [pfree ... iwlen-1] is empty on input */ Int Nv [ ], /* nv [0..n-1] */ Int Next [ ], /* next [0..n-1] */ Int Last [ ], /* last [0..n-1] */ Int Head [ ], /* head [0..n-1] */ Int Elen [ ], /* size n */ Int Degree [ ], /* size n */ Int W [ ], /* size n */ Int nel ) { Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ; if (AMD_debug < 0) return ; ASSERT (pfree <= iwlen) ; AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ; for (i = 0 ; i < n ; i++) { pe = Pe [i] ; elen = Elen [i] ; nv = Nv [i] ; len = Len [i] ; w = W [i] ; if (elen >= EMPTY) { if (nv == 0) { AMD_DEBUG3 (("\nI "ID": nonprincipal: ", i)) ; ASSERT (elen == EMPTY) ; if (pe == EMPTY) { AMD_DEBUG3 ((" dense node\n")) ; ASSERT (w == 1) ; } else { ASSERT (pe < EMPTY) ; AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i]))); } } else { AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i)); AMD_DEBUG3 ((" nv(i): "ID" Flag: %d\n", nv, (nv < 0))) ; ASSERT (elen >= 0) ; ASSERT (nv > 0 && pe >= 0) ; p = pe ; AMD_DEBUG3 ((" e/s: ")) ; if (elen == 0) AMD_DEBUG3 ((" : ")) ; ASSERT (pe + len <= pfree) ; for (k = 0 ; k < len ; k++) { j = Iw [p] ; AMD_DEBUG3 ((" "ID"", j)) ; ASSERT (j >= 0 && j < n) ; if (k == elen-1) AMD_DEBUG3 ((" : ")) ; p++ ; } AMD_DEBUG3 (("\n")) ; } } else { e = i ; if (w == 0) { AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ; ASSERT (nv > 0 && pe < 0) ; AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ; } else { AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ; ASSERT (nv > 0 && pe >= 0) ; p = pe ; AMD_DEBUG3 ((" : ")) ; ASSERT (pe + len <= pfree) ; for (k = 0 ; k < len ; k++) { j = Iw [p] ; AMD_DEBUG3 ((" "ID"", j)) ; ASSERT (j >= 0 && j < n) ; p++ ; } AMD_DEBUG3 (("\n")) ; } } } /* this routine cannot be called when the hash buckets are non-empty */ AMD_DEBUG3 (("\nDegree lists:\n")) ; if (nel >= 0) { cnt = 0 ; for (deg = 0 ; deg < n ; deg++) { if (Head [deg] == EMPTY) continue ; ilast = EMPTY ; AMD_DEBUG3 ((ID": \n", deg)) ; for (i = Head [deg] ; i != EMPTY ; i = Next [i]) { AMD_DEBUG3 ((" "ID" : next "ID" last "ID" deg "ID"\n", i, Next [i], Last [i], Degree [i])) ; ASSERT (i >= 0 && i < n && ilast == Last [i] && deg == Degree [i]) ; cnt += Nv [i] ; ilast = i ; } AMD_DEBUG3 (("\n")) ; } ASSERT (cnt == n - nel) ; } } #endif cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amdbar.f0000644000175000017500000014607211674452555020574 0ustar sonnesonneC----------------------------------------------------------------------- C AMDBAR: approximate minimum degree, without aggressive absorption C----------------------------------------------------------------------- SUBROUTINE AMDBAR $ (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, $ LAST, HEAD, ELEN, DEGREE, NCMPA, W) INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N), $ DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N), $ ELEN (N), W (N), LEN (N) C Given a representation of the nonzero pattern of a symmetric matrix, C A, (excluding the diagonal) perform an approximate minimum C (UMFPACK/MA38-style) degree ordering to compute a pivot order C such that the introduction of nonzeros (fill-in) in the Cholesky C factors A = LL^T are kept low. At each step, the pivot C selected is the one with the minimum UMFPACK/MA38-style C upper-bound on the external degree. C C This routine does not do aggresive absorption (as done by AMD). C ********************************************************************** C ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ****** C ********************************************************************** C References: C C [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern C multifrontal method for sparse LU factorization", SIAM J. C Matrix Analysis and Applications, vol. 18, no. 1, pp. C 140-158. Discusses UMFPACK / MA38, which first introduced C the approximate minimum degree used by this routine. C C [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An C approximate degree ordering algorithm," SIAM J. Matrix C Analysis and Applications, vol. 17, no. 4, pp. 886-905, C 1996. Discusses AMD, AMDBAR, and MC47B. C C [3] Alan George and Joseph Liu, "The evolution of the minimum C degree ordering algorithm," SIAM Review, vol. 31, no. 1, C pp. 1-19, 1989. We list below the features mentioned in C that paper that this code includes: C C mass elimination: C Yes. MA27 relied on supervariable detection for mass C elimination. C indistinguishable nodes: C Yes (we call these "supervariables"). This was also in C the MA27 code - although we modified the method of C detecting them (the previous hash was the true degree, C which we no longer keep track of). A supervariable is C a set of rows with identical nonzero pattern. All C variables in a supervariable are eliminated together. C Each supervariable has as its numerical name that of C one of its variables (its principal variable). C quotient graph representation: C Yes. We use the term "element" for the cliques formed C during elimination. This was also in the MA27 code. C The algorithm can operate in place, but it will work C more efficiently if given some "elbow room." C element absorption: C Yes. This was also in the MA27 code. C external degree: C Yes. The MA27 code was based on the true degree. C incomplete degree update and multiple elimination: C No. This was not in MA27, either. Our method of C degree update within MC47B/BD is element-based, not C variable-based. It is thus not well-suited for use C with incomplete degree update or multiple elimination. C----------------------------------------------------------------------- C Authors, and Copyright (C) 1995 by: C Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid. C C Acknowledgements: C This work (and the UMFPACK package) was supported by the C National Science Foundation (ASC-9111263 and DMS-9223088). C The UMFPACK/MA38 approximate degree update algorithm, the C unsymmetric analog which forms the basis of MC47B/BD, was C developed while Tim Davis was supported by CERFACS (Toulouse, C France) in a post-doctoral position. C C Date: September, 1995 C----------------------------------------------------------------------- C----------------------------------------------------------------------- C INPUT ARGUMENTS (unaltered): C----------------------------------------------------------------------- C n: The matrix order. C C Restriction: 1 .le. n .lt. (iovflo/2)-2, where iovflo is C the largest positive integer that your computer can represent. C iwlen: The length of iw (1..iwlen). On input, the matrix is C stored in iw (1..pfree-1). However, iw (1..iwlen) should be C slightly larger than what is required to hold the matrix, at C least iwlen .ge. pfree + n is recommended. Otherwise, C excessive compressions will take place. C *** We do not recommend running this algorithm with *** C *** iwlen .lt. pfree + n. *** C *** Better performance will be obtained if *** C *** iwlen .ge. pfree + n *** C *** or better yet *** C *** iwlen .gt. 1.2 * pfree *** C *** (where pfree is its value on input). *** C The algorithm will not run at all if iwlen .lt. pfree-1. C C Restriction: iwlen .ge. pfree-1 C----------------------------------------------------------------------- C INPUT/OUPUT ARGUMENTS: C----------------------------------------------------------------------- C pe: On input, pe (i) is the index in iw of the start of row i, or C zero if row i has no off-diagonal non-zeros. C C During execution, it is used for both supervariables and C elements: C C * Principal supervariable i: index into iw of the C description of supervariable i. A supervariable C represents one or more rows of the matrix C with identical nonzero pattern. C * Non-principal supervariable i: if i has been absorbed C into another supervariable j, then pe (i) = -j. C That is, j has the same pattern as i. C Note that j might later be absorbed into another C supervariable j2, in which case pe (i) is still -j, C and pe (j) = -j2. C * Unabsorbed element e: the index into iw of the description C of element e, if e has not yet been absorbed by a C subsequent element. Element e is created when C the supervariable of the same name is selected as C the pivot. C * Absorbed element e: if element e is absorbed into element C e2, then pe (e) = -e2. This occurs when the pattern of C e (that is, Le) is found to be a subset of the pattern C of e2 (that is, Le2). If element e is "null" (it has C no nonzeros outside its pivot block), then pe (e) = 0. C C On output, pe holds the assembly tree/forest, which implicitly C represents a pivot order with identical fill-in as the actual C order (via a depth-first search of the tree). C C On output: C If nv (i) .gt. 0, then i represents a node in the assembly tree, C and the parent of i is -pe (i), or zero if i is a root. C If nv (i) = 0, then (i,-pe (i)) represents an edge in a C subtree, the root of which is a node in the assembly tree. C pfree: On input the tail end of the array, iw (pfree..iwlen), C is empty, and the matrix is stored in iw (1..pfree-1). C During execution, additional data is placed in iw, and pfree C is modified so that iw (pfree..iwlen) is always the unused part C of iw. On output, pfree is set equal to the size of iw that C would have been needed for no compressions to occur. If C ncmpa is zero, then pfree (on output) is less than or equal to C iwlen, and the space iw (pfree+1 ... iwlen) was not used. C Otherwise, pfree (on output) is greater than iwlen, and all the C memory in iw was used. C----------------------------------------------------------------------- C INPUT/MODIFIED (undefined on output): C----------------------------------------------------------------------- C len: On input, len (i) holds the number of entries in row i of the C matrix, excluding the diagonal. The contents of len (1..n) C are undefined on output. C iw: On input, iw (1..pfree-1) holds the description of each row i C in the matrix. The matrix must be symmetric, and both upper C and lower triangular parts must be present. The diagonal must C not be present. Row i is held as follows: C C len (i): the length of the row i data structure C iw (pe (i) ... pe (i) + len (i) - 1): C the list of column indices for nonzeros C in row i (simple supervariables), excluding C the diagonal. All supervariables start with C one row/column each (supervariable i is just C row i). C if len (i) is zero on input, then pe (i) is ignored C on input. C C Note that the rows need not be in any particular order, C and there may be empty space between the rows. C C During execution, the supervariable i experiences fill-in. C This is represented by placing in i a list of the elements C that cause fill-in in supervariable i: C C len (i): the length of supervariable i C iw (pe (i) ... pe (i) + elen (i) - 1): C the list of elements that contain i. This list C is kept short by removing absorbed elements. C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1): C the list of supervariables in i. This list C is kept short by removing nonprincipal C variables, and any entry j that is also C contained in at least one of the elements C (j in Le) in the list for i (e in row i). C C When supervariable i is selected as pivot, we create an C element e of the same name (e=i): C C len (e): the length of element e C iw (pe (e) ... pe (e) + len (e) - 1): C the list of supervariables in element e. C C An element represents the fill-in that occurs when supervariable C i is selected as pivot (which represents the selection of row i C and all non-principal variables whose principal variable is i). C We use the term Le to denote the set of all supervariables C in element e. Absorbed supervariables and elements are pruned C from these lists when computationally convenient. C C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION. C The contents of iw are undefined on output. C----------------------------------------------------------------------- C OUTPUT (need not be set on input): C----------------------------------------------------------------------- C nv: During execution, abs (nv (i)) is equal to the number of rows C that are represented by the principal supervariable i. If i is C a nonprincipal variable, then nv (i) = 0. Initially, C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a C principal variable in the pattern Lme of the current pivot C element me. On output, nv (e) holds the true degree of element C e at the time it was created (including the diagonal part). C ncmpa: The number of times iw was compressed. If this is C excessive, then the execution took longer than what could have C been. To reduce ncmpa, try increasing iwlen to be 10% or 20% C larger than the value of pfree on input (or at least C iwlen .ge. pfree + n). The fastest performance will be C obtained when ncmpa is returned as zero. If iwlen is set to C the value returned by pfree on *output*, then no compressions C will occur. C elen: See the description of iw above. At the start of execution, C elen (i) is set to zero. During execution, elen (i) is the C number of elements in the list for supervariable i. When e C becomes an element, elen (e) = -nel is set, where nel is the C current step of factorization. elen (i) = 0 is done when i C becomes nonprincipal. C C For variables, elen (i) .ge. 0 holds until just before the C permutation vectors are computed. For elements, C elen (e) .lt. 0 holds. C C On output elen (1..n) holds the inverse permutation (the same C as the 'INVP' argument in Sparspak). That is, if k = elen (i), C then row i is the kth pivot row. Row i of A appears as the C (elen(i))-th row in the permuted matrix, PAP^T. C last: In a degree list, last (i) is the supervariable preceding i, C or zero if i is the head of the list. In a hash bucket, C last (i) is the hash key for i. last (head (hash)) is also C used as the head of a hash bucket if head (hash) contains a C degree list (see head, below). C C On output, last (1..n) holds the permutation (the same as the C 'PERM' argument in Sparspak). That is, if i = last (k), then C row i is the kth pivot row. Row last (k) of A is the k-th row C in the permuted matrix, PAP^T. C----------------------------------------------------------------------- C LOCAL (not input or output - used only during execution): C----------------------------------------------------------------------- C degree: If i is a supervariable, then degree (i) holds the C current approximation of the external degree of row i (an upper C bound). The external degree is the number of nonzeros in row i, C minus abs (nv (i)) (the diagonal part). The bound is equal to C the external degree if elen (i) is less than or equal to two. C C We also use the term "external degree" for elements e to refer C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|, C which is the degree of the off-diagonal part of the element e C (not including the diagonal part). C head: head is used for degree lists. head (deg) is the first C supervariable in a degree list (all supervariables i in a C degree list deg have the same approximate degree, namely, C deg = degree (i)). If the list deg is empty then C head (deg) = 0. C C During supervariable detection head (hash) also serves as a C pointer to a hash bucket. C If head (hash) .gt. 0, there is a degree list of degree hash. C The hash bucket head pointer is last (head (hash)). C If head (hash) = 0, then the degree list and hash bucket are C both empty. C If head (hash) .lt. 0, then the degree list is empty, and C -head (hash) is the head of the hash bucket. C After supervariable detection is complete, all hash buckets C are empty, and the (last (head (hash)) = 0) condition is C restored for the non-empty degree lists. C next: next (i) is the supervariable following i in a link list, or C zero if i is the last in the list. Used for two kinds of C lists: degree lists and hash buckets (a supervariable can be C in only one kind of list at a time). C w: The flag array w determines the status of elements and C variables, and the external degree of elements. C C for elements: C if w (e) = 0, then the element e is absorbed C if w (e) .ge. wflg, then w (e) - wflg is the size of C the set |Le \ Lme|, in terms of nonzeros (the C sum of abs (nv (i)) for each principal variable i that C is both in the pattern of element e and NOT in the C pattern of the current pivot element, me). C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has C not yet been seen in the scan of the element lists in C the computation of |Le\Lme| in loop 150 below. C C for variables: C during supervariable detection, if w (j) .ne. wflg then j is C not in the pattern of variable i C C The w array is initialized by setting w (i) = 1 for all i, C and by setting wflg = 2. It is reinitialized if wflg becomes C too large (to ensure that wflg+n does not cause integer C overflow). C----------------------------------------------------------------------- C LOCAL INTEGERS: C----------------------------------------------------------------------- INTEGER DEG, DEGME, DMAX, E, ELENME, ELN, HASH, HMOD, I, $ ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3, $ LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM, $ NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X C deg: the degree of a variable or element C degme: size, |Lme|, of the current element, me (= degree (me)) C dext: external degree, |Le \ Lme|, of some element e C dmax: largest |Le| seen so far C e: an element C elenme: the length, elen (me), of element list of pivotal var. C eln: the length, elen (...), of an element list C hash: the computed value of the hash function C hmod: the hash function is computed modulo hmod = max (1,n-1) C i: a supervariable C ilast: the entry in a link list preceding i C inext: the entry in a link list following i C j: a supervariable C jlast: the entry in a link list preceding j C jnext: the entry in a link list, or path, following j C k: the pivot order of an element or variable C knt1: loop counter used during element construction C knt2: loop counter used during element construction C knt3: loop counter used during compression C lenj: len (j) C ln: length of a supervariable list C maxmem: amount of memory needed for no compressions C me: current supervariable being eliminated, and the C current element created by eliminating that C supervariable C mem: memory in use assuming no compressions have occurred C mindeg: current minimum degree C nel: number of pivots selected so far C newmem: amount of new memory needed for current pivot element C nleft: n - nel, the number of nonpivotal rows/columns remaining C nvi: the number of variables in a supervariable i (= nv (i)) C nvj: the number of variables in a supervariable j (= nv (j)) C nvpiv: number of pivots in current element C slenme: number of variables in variable list of pivotal variable C we: w (e) C wflg: used for flagging the w array. See description of iw. C wnvi: wflg - nv (i) C x: either a supervariable or an element C----------------------------------------------------------------------- C LOCAL POINTERS: C----------------------------------------------------------------------- INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC C Any parameter (pe (...) or pfree) or local variable C starting with "p" (for Pointer) is an index into iw, C and all indices into iw use variables starting with C "p." The only exception to this rule is the iwlen C input argument. C p: pointer into lots of things C p1: pe (i) for some variable i (start of element list) C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list) C p3: index of first supervariable in clean list C pdst: destination pointer, for compression C pend: end of memory to compress C pj: pointer into an element or variable C pme: pointer into the current element (pme1...pme2) C pme1: the current element, me, is stored in iw (pme1...pme2) C pme2: the end of the current element C pn: pointer into a "clean" variable, also used to compress C psrc: source pointer, for compression C----------------------------------------------------------------------- C FUNCTIONS CALLED: C----------------------------------------------------------------------- INTRINSIC MAX, MIN, MOD C======================================================================= C INITIALIZATIONS C======================================================================= WFLG = 2 MINDEG = 1 NCMPA = 0 NEL = 0 HMOD = MAX (1, N-1) DMAX = 0 MEM = PFREE - 1 MAXMEM = MEM ME = 0 DO 10 I = 1, N LAST (I) = 0 HEAD (I) = 0 NV (I) = 1 W (I) = 1 ELEN (I) = 0 DEGREE (I) = LEN (I) 10 CONTINUE C ---------------------------------------------------------------- C initialize degree lists and eliminate rows with no off-diag. nz. C ---------------------------------------------------------------- DO 20 I = 1, N DEG = DEGREE (I) IF (DEG .GT. 0) THEN C ---------------------------------------------------------- C place i in the degree list corresponding to its degree C ---------------------------------------------------------- INEXT = HEAD (DEG) IF (INEXT .NE. 0) LAST (INEXT) = I NEXT (I) = INEXT HEAD (DEG) = I ELSE C ---------------------------------------------------------- C we have a variable that can be eliminated at once because C there is no off-diagonal non-zero in its row. C ---------------------------------------------------------- NEL = NEL + 1 ELEN (I) = -NEL PE (I) = 0 W (I) = 0 ENDIF 20 CONTINUE C======================================================================= C WHILE (selecting pivots) DO C======================================================================= 30 CONTINUE IF (NEL .LT. N) THEN C======================================================================= C GET PIVOT OF MINIMUM DEGREE C======================================================================= C ------------------------------------------------------------- C find next supervariable for elimination C ------------------------------------------------------------- DO 40 DEG = MINDEG, N ME = HEAD (DEG) IF (ME .GT. 0) GOTO 50 40 CONTINUE 50 CONTINUE MINDEG = DEG C ------------------------------------------------------------- C remove chosen variable from link list C ------------------------------------------------------------- INEXT = NEXT (ME) IF (INEXT .NE. 0) LAST (INEXT) = 0 HEAD (DEG) = INEXT C ------------------------------------------------------------- C me represents the elimination of pivots nel+1 to nel+nv(me). C place me itself as the first in this set. It will be moved C to the nel+nv(me) position when the permutation vectors are C computed. C ------------------------------------------------------------- ELENME = ELEN (ME) ELEN (ME) = - (NEL + 1) NVPIV = NV (ME) NEL = NEL + NVPIV C======================================================================= C CONSTRUCT NEW ELEMENT C======================================================================= C ------------------------------------------------------------- C At this point, me is the pivotal supervariable. It will be C converted into the current element. Scan list of the C pivotal supervariable, me, setting tree pointers and C constructing new list of supervariables for the new element, C me. p is a pointer to the current position in the old list. C ------------------------------------------------------------- C flag the variable "me" as being in Lme by negating nv (me) NV (ME) = -NVPIV DEGME = 0 IF (ELENME .EQ. 0) THEN C ---------------------------------------------------------- C construct the new element in place C ---------------------------------------------------------- PME1 = PE (ME) PME2 = PME1 - 1 DO 60 P = PME1, PME1 + LEN (ME) - 1 I = IW (P) NVI = NV (I) IF (NVI .GT. 0) THEN C ---------------------------------------------------- C i is a principal variable not yet placed in Lme. C store i in new list C ---------------------------------------------------- DEGME = DEGME + NVI C flag i as being in Lme by negating nv (i) NV (I) = -NVI PME2 = PME2 + 1 IW (PME2) = I C ---------------------------------------------------- C remove variable i from degree list. C ---------------------------------------------------- ILAST = LAST (I) INEXT = NEXT (I) IF (INEXT .NE. 0) LAST (INEXT) = ILAST IF (ILAST .NE. 0) THEN NEXT (ILAST) = INEXT ELSE C i is at the head of the degree list HEAD (DEGREE (I)) = INEXT ENDIF ENDIF 60 CONTINUE C this element takes no new memory in iw: NEWMEM = 0 ELSE C ---------------------------------------------------------- C construct the new element in empty space, iw (pfree ...) C ---------------------------------------------------------- P = PE (ME) PME1 = PFREE SLENME = LEN (ME) - ELENME DO 120 KNT1 = 1, ELENME + 1 IF (KNT1 .GT. ELENME) THEN C search the supervariables in me. E = ME PJ = P LN = SLENME ELSE C search the elements in me. E = IW (P) P = P + 1 PJ = PE (E) LN = LEN (E) ENDIF C ------------------------------------------------------- C search for different supervariables and add them to the C new list, compressing when necessary. this loop is C executed once for each element in the list and once for C all the supervariables in the list. C ------------------------------------------------------- DO 110 KNT2 = 1, LN I = IW (PJ) PJ = PJ + 1 NVI = NV (I) IF (NVI .GT. 0) THEN C ------------------------------------------------- C compress iw, if necessary C ------------------------------------------------- IF (PFREE .GT. IWLEN) THEN C prepare for compressing iw by adjusting C pointers and lengths so that the lists being C searched in the inner and outer loops contain C only the remaining entries. PE (ME) = P LEN (ME) = LEN (ME) - KNT1 IF (LEN (ME) .EQ. 0) THEN C nothing left of supervariable me PE (ME) = 0 ENDIF PE (E) = PJ LEN (E) = LN - KNT2 IF (LEN (E) .EQ. 0) THEN C nothing left of element e PE (E) = 0 ENDIF NCMPA = NCMPA + 1 C store first item in pe C set first entry to -item DO 70 J = 1, N PN = PE (J) IF (PN .GT. 0) THEN PE (J) = IW (PN) IW (PN) = -J ENDIF 70 CONTINUE C psrc/pdst point to source/destination PDST = 1 PSRC = 1 PEND = PME1 - 1 C while loop: 80 CONTINUE IF (PSRC .LE. PEND) THEN C search for next negative entry J = -IW (PSRC) PSRC = PSRC + 1 IF (J .GT. 0) THEN IW (PDST) = PE (J) PE (J) = PDST PDST = PDST + 1 C copy from source to destination LENJ = LEN (J) DO 90 KNT3 = 0, LENJ - 2 IW (PDST + KNT3) = IW (PSRC + KNT3) 90 CONTINUE PDST = PDST + LENJ - 1 PSRC = PSRC + LENJ - 1 ENDIF GOTO 80 ENDIF C move the new partially-constructed element P1 = PDST DO 100 PSRC = PME1, PFREE - 1 IW (PDST) = IW (PSRC) PDST = PDST + 1 100 CONTINUE PME1 = P1 PFREE = PDST PJ = PE (E) P = PE (ME) ENDIF C ------------------------------------------------- C i is a principal variable not yet placed in Lme C store i in new list C ------------------------------------------------- DEGME = DEGME + NVI C flag i as being in Lme by negating nv (i) NV (I) = -NVI IW (PFREE) = I PFREE = PFREE + 1 C ------------------------------------------------- C remove variable i from degree link list C ------------------------------------------------- ILAST = LAST (I) INEXT = NEXT (I) IF (INEXT .NE. 0) LAST (INEXT) = ILAST IF (ILAST .NE. 0) THEN NEXT (ILAST) = INEXT ELSE C i is at the head of the degree list HEAD (DEGREE (I)) = INEXT ENDIF ENDIF 110 CONTINUE IF (E .NE. ME) THEN C set tree pointer and flag to indicate element e is C absorbed into new element me (the parent of e is me) PE (E) = -ME W (E) = 0 ENDIF 120 CONTINUE PME2 = PFREE - 1 C this element takes newmem new memory in iw (possibly zero) NEWMEM = PFREE - PME1 MEM = MEM + NEWMEM MAXMEM = MAX (MAXMEM, MEM) ENDIF C ------------------------------------------------------------- C me has now been converted into an element in iw (pme1..pme2) C ------------------------------------------------------------- C degme holds the external degree of new element DEGREE (ME) = DEGME PE (ME) = PME1 LEN (ME) = PME2 - PME1 + 1 C ------------------------------------------------------------- C make sure that wflg is not too large. With the current C value of wflg, wflg+n must not cause integer overflow C ------------------------------------------------------------- IF (WFLG + N .LE. WFLG) THEN DO 130 X = 1, N IF (W (X) .NE. 0) W (X) = 1 130 CONTINUE WFLG = 2 ENDIF C======================================================================= C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS C======================================================================= C ------------------------------------------------------------- C Scan 1: compute the external degrees of previous elements C with respect to the current element. That is: C (w (e) - wflg) = |Le \ Lme| C for each element e that appears in any supervariable in Lme. C The notation Le refers to the pattern (list of C supervariables) of a previous element e, where e is not yet C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))). C The notation Lme refers to the pattern of the current element C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes C zero, then the element e will be absorbed in scan 2. C ------------------------------------------------------------- DO 150 PME = PME1, PME2 I = IW (PME) ELN = ELEN (I) IF (ELN .GT. 0) THEN C note that nv (i) has been negated to denote i in Lme: NVI = -NV (I) WNVI = WFLG - NVI DO 140 P = PE (I), PE (I) + ELN - 1 E = IW (P) WE = W (E) IF (WE .GE. WFLG) THEN C unabsorbed element e has been seen in this loop WE = WE - NVI ELSE IF (WE .NE. 0) THEN C e is an unabsorbed element C this is the first we have seen e in all of Scan 1 WE = DEGREE (E) + WNVI ENDIF W (E) = WE 140 CONTINUE ENDIF 150 CONTINUE C======================================================================= C DEGREE UPDATE AND ELEMENT ABSORPTION C======================================================================= C ------------------------------------------------------------- C Scan 2: for each i in Lme, sum up the degree of Lme (which C is degme), plus the sum of the external degrees of each Le C for the elements e appearing within i, plus the C supervariables in i. Place i in hash list. C ------------------------------------------------------------- DO 180 PME = PME1, PME2 I = IW (PME) P1 = PE (I) P2 = P1 + ELEN (I) - 1 PN = P1 HASH = 0 DEG = 0 C ---------------------------------------------------------- C scan the element list associated with supervariable i C ---------------------------------------------------------- C UMFPACK/MA38-style approximate degree: DO 160 P = P1, P2 E = IW (P) WE = W (E) IF (WE .NE. 0) THEN C e is an unabsorbed element DEG = DEG + WE - WFLG IW (PN) = E PN = PN + 1 HASH = HASH + E ENDIF 160 CONTINUE C count the number of elements in i (including me): ELEN (I) = PN - P1 + 1 C ---------------------------------------------------------- C scan the supervariables in the list associated with i C ---------------------------------------------------------- P3 = PN DO 170 P = P2 + 1, P1 + LEN (I) - 1 J = IW (P) NVJ = NV (J) IF (NVJ .GT. 0) THEN C j is unabsorbed, and not in Lme. C add to degree and add to new list DEG = DEG + NVJ IW (PN) = J PN = PN + 1 HASH = HASH + J ENDIF 170 CONTINUE C ---------------------------------------------------------- C update the degree and check for mass elimination C ---------------------------------------------------------- IF (ELEN (I) .EQ. 1 .AND. P3 .EQ. PN) THEN C ------------------------------------------------------- C mass elimination C ------------------------------------------------------- C There is nothing left of this node except for an C edge to the current pivot element. elen (i) is 1, C and there are no variables adjacent to node i. C Absorb i into the current pivot element, me. PE (I) = -ME NVI = -NV (I) DEGME = DEGME - NVI NVPIV = NVPIV + NVI NEL = NEL + NVI NV (I) = 0 ELEN (I) = 0 ELSE C ------------------------------------------------------- C update the upper-bound degree of i C ------------------------------------------------------- C the following degree does not yet include the size C of the current element, which is added later: DEGREE (I) = MIN (DEGREE (I), DEG) C ------------------------------------------------------- C add me to the list for i C ------------------------------------------------------- C move first supervariable to end of list IW (PN) = IW (P3) C move first element to end of element part of list IW (P3) = IW (P1) C add new element to front of list. IW (P1) = ME C store the new length of the list in len (i) LEN (I) = PN - P1 + 1 C ------------------------------------------------------- C place in hash bucket. Save hash key of i in last (i). C ------------------------------------------------------- HASH = MOD (HASH, HMOD) + 1 J = HEAD (HASH) IF (J .LE. 0) THEN C the degree list is empty, hash head is -j NEXT (I) = -J HEAD (HASH) = -I ELSE C degree list is not empty C use last (head (hash)) as hash head NEXT (I) = LAST (J) LAST (J) = I ENDIF LAST (I) = HASH ENDIF 180 CONTINUE DEGREE (ME) = DEGME C ------------------------------------------------------------- C Clear the counter array, w (...), by incrementing wflg. C ------------------------------------------------------------- DMAX = MAX (DMAX, DEGME) WFLG = WFLG + DMAX C make sure that wflg+n does not cause integer overflow IF (WFLG + N .LE. WFLG) THEN DO 190 X = 1, N IF (W (X) .NE. 0) W (X) = 1 190 CONTINUE WFLG = 2 ENDIF C at this point, w (1..n) .lt. wflg holds C======================================================================= C SUPERVARIABLE DETECTION C======================================================================= DO 250 PME = PME1, PME2 I = IW (PME) IF (NV (I) .LT. 0) THEN C i is a principal variable in Lme C ------------------------------------------------------- C examine all hash buckets with 2 or more variables. We C do this by examing all unique hash keys for super- C variables in the pattern Lme of the current element, me C ------------------------------------------------------- HASH = LAST (I) C let i = head of hash bucket, and empty the hash bucket J = HEAD (HASH) IF (J .EQ. 0) GOTO 250 IF (J .LT. 0) THEN C degree list is empty I = -J HEAD (HASH) = 0 ELSE C degree list is not empty, restore last () of head I = LAST (J) LAST (J) = 0 ENDIF IF (I .EQ. 0) GOTO 250 C while loop: 200 CONTINUE IF (NEXT (I) .NE. 0) THEN C ---------------------------------------------------- C this bucket has one or more variables following i. C scan all of them to see if i can absorb any entries C that follow i in hash bucket. Scatter i into w. C ---------------------------------------------------- LN = LEN (I) ELN = ELEN (I) C do not flag the first element in the list (me) DO 210 P = PE (I) + 1, PE (I) + LN - 1 W (IW (P)) = WFLG 210 CONTINUE C ---------------------------------------------------- C scan every other entry j following i in bucket C ---------------------------------------------------- JLAST = I J = NEXT (I) C while loop: 220 CONTINUE IF (J .NE. 0) THEN C ------------------------------------------------- C check if j and i have identical nonzero pattern C ------------------------------------------------- IF (LEN (J) .NE. LN) THEN C i and j do not have same size data structure GOTO 240 ENDIF IF (ELEN (J) .NE. ELN) THEN C i and j do not have same number of adjacent el GOTO 240 ENDIF C do not flag the first element in the list (me) DO 230 P = PE (J) + 1, PE (J) + LN - 1 IF (W (IW (P)) .NE. WFLG) THEN C an entry (iw(p)) is in j but not in i GOTO 240 ENDIF 230 CONTINUE C ------------------------------------------------- C found it! j can be absorbed into i C ------------------------------------------------- PE (J) = -I C both nv (i) and nv (j) are negated since they C are in Lme, and the absolute values of each C are the number of variables in i and j: NV (I) = NV (I) + NV (J) NV (J) = 0 ELEN (J) = 0 C delete j from hash bucket J = NEXT (J) NEXT (JLAST) = J GOTO 220 C ------------------------------------------------- 240 CONTINUE C j cannot be absorbed into i C ------------------------------------------------- JLAST = J J = NEXT (J) GOTO 220 ENDIF C ---------------------------------------------------- C no more variables can be absorbed into i C go to next i in bucket and clear flag array C ---------------------------------------------------- WFLG = WFLG + 1 I = NEXT (I) IF (I .NE. 0) GOTO 200 ENDIF ENDIF 250 CONTINUE C======================================================================= C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT C======================================================================= P = PME1 NLEFT = N - NEL DO 260 PME = PME1, PME2 I = IW (PME) NVI = -NV (I) IF (NVI .GT. 0) THEN C i is a principal variable in Lme C restore nv (i) to signify that i is principal NV (I) = NVI C ------------------------------------------------------- C compute the external degree (add size of current elem) C ------------------------------------------------------- DEG = MAX (1, MIN (DEGREE (I) + DEGME-NVI, NLEFT-NVI)) C ------------------------------------------------------- C place the supervariable at the head of the degree list C ------------------------------------------------------- INEXT = HEAD (DEG) IF (INEXT .NE. 0) LAST (INEXT) = I NEXT (I) = INEXT LAST (I) = 0 HEAD (DEG) = I C ------------------------------------------------------- C save the new degree, and find the minimum degree C ------------------------------------------------------- MINDEG = MIN (MINDEG, DEG) DEGREE (I) = DEG C ------------------------------------------------------- C place the supervariable in the element pattern C ------------------------------------------------------- IW (P) = I P = P + 1 ENDIF 260 CONTINUE C======================================================================= C FINALIZE THE NEW ELEMENT C======================================================================= NV (ME) = NVPIV + DEGME C nv (me) is now the degree of pivot (including diagonal part) C save the length of the list for the new element me LEN (ME) = P - PME1 IF (LEN (ME) .EQ. 0) THEN C there is nothing left of the current pivot element PE (ME) = 0 W (ME) = 0 ENDIF IF (NEWMEM .NE. 0) THEN C element was not constructed in place: deallocate part C of it (final size is less than or equal to newmem, C since newly nonprincipal variables have been removed). PFREE = P MEM = MEM - NEWMEM + LEN (ME) ENDIF C======================================================================= C END WHILE (selecting pivots) GOTO 30 ENDIF C======================================================================= C======================================================================= C COMPUTE THE PERMUTATION VECTORS C======================================================================= C ---------------------------------------------------------------- C The time taken by the following code is O(n). At this C point, elen (e) = -k has been done for all elements e, C and elen (i) = 0 has been done for all nonprincipal C variables i. At this point, there are no principal C supervariables left, and all elements are absorbed. C ---------------------------------------------------------------- C ---------------------------------------------------------------- C compute the ordering of unordered nonprincipal variables C ---------------------------------------------------------------- DO 290 I = 1, N IF (ELEN (I) .EQ. 0) THEN C ---------------------------------------------------------- C i is an un-ordered row. Traverse the tree from i until C reaching an element, e. The element, e, was the C principal supervariable of i and all nodes in the path C from i to when e was selected as pivot. C ---------------------------------------------------------- J = -PE (I) C while (j is a variable) do: 270 CONTINUE IF (ELEN (J) .GE. 0) THEN J = -PE (J) GOTO 270 ENDIF E = J C ---------------------------------------------------------- C get the current pivot ordering of e C ---------------------------------------------------------- K = -ELEN (E) C ---------------------------------------------------------- C traverse the path again from i to e, and compress the C path (all nodes point to e). Path compression allows C this code to compute in O(n) time. Order the unordered C nodes in the path, and place the element e at the end. C ---------------------------------------------------------- J = I C while (j is a variable) do: 280 CONTINUE IF (ELEN (J) .GE. 0) THEN JNEXT = -PE (J) PE (J) = -E IF (ELEN (J) .EQ. 0) THEN C j is an unordered row ELEN (J) = K K = K + 1 ENDIF J = JNEXT GOTO 280 ENDIF C leave elen (e) negative, so we know it is an element ELEN (E) = -K ENDIF 290 CONTINUE C ---------------------------------------------------------------- C reset the inverse permutation (elen (1..n)) to be positive, C and compute the permutation (last (1..n)). C ---------------------------------------------------------------- DO 300 I = 1, N K = ABS (ELEN (I)) LAST (K) = I ELEN (I) = K 300 CONTINUE C======================================================================= C RETURN THE MEMORY USAGE IN IW C======================================================================= C If maxmem is less than or equal to iwlen, then no compressions C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise C compressions did occur, and iwlen would have had to have been C greater than or equal to maxmem for no compressions to occur. C Return the value of maxmem in the pfree argument. PFREE = MAXMEM RETURN END cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_order.c0000644000175000017500000001351411674452555021271 0ustar sonnesonne/* ========================================================================= */ /* === AMD_order =========================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable AMD minimum degree ordering routine. See amd.h for * documentation. */ #include "amd_internal.h" /* ========================================================================= */ /* === AMD_order =========================================================== */ /* ========================================================================= */ GLOBAL Int AMD_order ( Int n, const Int Ap [ ], const Int Ai [ ], Int P [ ], double Control [ ], double Info [ ] ) { Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ; size_t nzaat, slen ; double mem = 0 ; #ifndef NDEBUG AMD_debug_init ("amd") ; #endif /* clear the Info array, if it exists */ info = Info != (double *) NULL ; if (info) { for (i = 0 ; i < AMD_INFO ; i++) { Info [i] = EMPTY ; } Info [AMD_N] = n ; Info [AMD_STATUS] = AMD_OK ; } /* make sure inputs exist and n is >= 0 */ if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0) { if (info) Info [AMD_STATUS] = AMD_INVALID ; return (AMD_INVALID) ; /* arguments are invalid */ } if (n == 0) { return (AMD_OK) ; /* n is 0 so there's nothing to do */ } nz = Ap [n] ; if (info) { Info [AMD_NZ] = nz ; } if (nz < 0) { if (info) Info [AMD_STATUS] = AMD_INVALID ; return (AMD_INVALID) ; } /* check if n or nz will cause size_t overflow */ if (((size_t) n) >= SIZE_T_MAX / sizeof (Int) || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int)) { if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; /* problem too large */ } /* check the input matrix: AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */ status = AMD_valid (n, n, Ap, Ai) ; if (status == AMD_INVALID) { if (info) Info [AMD_STATUS] = AMD_INVALID ; return (AMD_INVALID) ; /* matrix is invalid */ } /* allocate two size-n integer workspaces */ Len = amd_malloc (n * sizeof (Int)) ; Pinv = amd_malloc (n * sizeof (Int)) ; mem += n ; mem += n ; if (!Len || !Pinv) { /* :: out of memory :: */ amd_free (Len) ; amd_free (Pinv) ; if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } if (status == AMD_OK_BUT_JUMBLED) { /* sort the input matrix and remove duplicate entries */ AMD_DEBUG1 (("Matrix is jumbled\n")) ; Rp = amd_malloc ((n+1) * sizeof (Int)) ; Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ; mem += (n+1) ; mem += MAX (nz,1) ; if (!Rp || !Ri) { /* :: out of memory :: */ amd_free (Rp) ; amd_free (Ri) ; amd_free (Len) ; amd_free (Pinv) ; if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } /* use Len and Pinv as workspace to create R = A' */ AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ; Cp = Rp ; Ci = Ri ; } else { /* order the input matrix as-is. No need to compute R = A' first */ Rp = NULL ; Ri = NULL ; Cp = (Int *) Ap ; Ci = (Int *) Ai ; } /* --------------------------------------------------------------------- */ /* determine the symmetry and count off-diagonal nonzeros in A+A' */ /* --------------------------------------------------------------------- */ nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ; AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ; ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ; /* --------------------------------------------------------------------- */ /* allocate workspace for matrix, elbow room, and 6 size-n vectors */ /* --------------------------------------------------------------------- */ S = NULL ; slen = nzaat ; /* space for matrix */ ok = ((slen + nzaat/5) >= slen) ; /* check for size_t overflow */ slen += nzaat/5 ; /* add elbow room */ for (i = 0 ; ok && i < 7 ; i++) { ok = ((slen + n) > slen) ; /* check for size_t overflow */ slen += n ; /* size-n elbow room, 6 size-n work */ } mem += slen ; ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */ ok = ok && (slen < Int_MAX) ; /* S[i] for Int i must be OK */ if (ok) { S = amd_malloc (slen * sizeof (Int)) ; } AMD_DEBUG1 (("slen %g\n", (double) slen)) ; if (!S) { /* :: out of memory :: (or problem too large) */ amd_free (Rp) ; amd_free (Ri) ; amd_free (Len) ; amd_free (Pinv) ; if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } if (info) { /* memory usage, in bytes. */ Info [AMD_MEMORY] = mem * sizeof (Int) ; } /* --------------------------------------------------------------------- */ /* order the matrix */ /* --------------------------------------------------------------------- */ AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ; /* --------------------------------------------------------------------- */ /* free the workspace */ /* --------------------------------------------------------------------- */ amd_free (Rp) ; amd_free (Ri) ; amd_free (Len) ; amd_free (Pinv) ; amd_free (S) ; if (info) Info [AMD_STATUS] = status ; return (status) ; /* successful ordering */ } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_preprocess.c0000644000175000017500000000746011674452555022346 0ustar sonnesonne/* ========================================================================= */ /* === AMD_preprocess ====================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Sorts, removes duplicate entries, and transposes from the nonzero pattern of * a column-form matrix A, to obtain the matrix R. The input matrix can have * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be * AMD_INVALID). * * This input condition is NOT checked. This routine is not user-callable. */ #include "amd_internal.h" /* ========================================================================= */ /* === AMD_preprocess ====================================================== */ /* ========================================================================= */ /* AMD_preprocess does not check its input for errors or allocate workspace. * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold. */ GLOBAL void AMD_preprocess ( Int n, /* input matrix: A is n-by-n */ const Int Ap [ ], /* size n+1 */ const Int Ai [ ], /* size nz = Ap [n] */ /* output matrix R: */ Int Rp [ ], /* size n+1 */ Int Ri [ ], /* size nz (or less, if duplicates present) */ Int W [ ], /* workspace of size n */ Int Flag [ ] /* workspace of size n */ ) { /* --------------------------------------------------------------------- */ /* local variables */ /* --------------------------------------------------------------------- */ Int i, j, p, p2 ; ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ; /* --------------------------------------------------------------------- */ /* count the entries in each row of A (excluding duplicates) */ /* --------------------------------------------------------------------- */ for (i = 0 ; i < n ; i++) { W [i] = 0 ; /* # of nonzeros in row i (excl duplicates) */ Flag [i] = EMPTY ; /* Flag [i] = j if i appears in column j */ } for (j = 0 ; j < n ; j++) { p2 = Ap [j+1] ; for (p = Ap [j] ; p < p2 ; p++) { i = Ai [p] ; if (Flag [i] != j) { /* row index i has not yet appeared in column j */ W [i]++ ; /* one more entry in row i */ Flag [i] = j ; /* flag row index i as appearing in col j*/ } } } /* --------------------------------------------------------------------- */ /* compute the row pointers for R */ /* --------------------------------------------------------------------- */ Rp [0] = 0 ; for (i = 0 ; i < n ; i++) { Rp [i+1] = Rp [i] + W [i] ; } for (i = 0 ; i < n ; i++) { W [i] = Rp [i] ; Flag [i] = EMPTY ; } /* --------------------------------------------------------------------- */ /* construct the row form matrix R */ /* --------------------------------------------------------------------- */ /* R = row form of pattern of A */ for (j = 0 ; j < n ; j++) { p2 = Ap [j+1] ; for (p = Ap [j] ; p < p2 ; p++) { i = Ai [p] ; if (Flag [i] != j) { /* row index i has not yet appeared in column j */ Ri [W [i]++] = j ; /* put col j in row i */ Flag [i] = j ; /* flag row index i as appearing in col j*/ } } } #ifndef NDEBUG ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ; for (j = 0 ; j < n ; j++) { ASSERT (W [j] == Rp [j+1]) ; } #endif } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_2.c0000644000175000017500000017646711674452555020340 0ustar sonnesonne/* ========================================================================= */ /* === AMD_2 =============================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD_2: performs the AMD ordering on a symmetric sparse matrix A, followed * by a postordering (via depth-first search) of the assembly tree using the * AMD_postorder routine. */ #include "amd_internal.h" /* ========================================================================= */ /* === clear_flag ========================================================== */ /* ========================================================================= */ static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n) { Int x ; if (wflg < 2 || wflg >= wbig) { for (x = 0 ; x < n ; x++) { if (W [x] != 0) W [x] = 1 ; } wflg = 2 ; } /* at this point, W [0..n-1] < wflg holds */ return (wflg) ; } /* ========================================================================= */ /* === AMD_2 =============================================================== */ /* ========================================================================= */ GLOBAL void AMD_2 ( Int n, /* A is n-by-n, where n > 0 */ Int Pe [ ], /* Pe [0..n-1]: index in Iw of row i on input */ Int Iw [ ], /* workspace of size iwlen. Iw [0..pfree-1] * holds the matrix on input */ Int Len [ ], /* Len [0..n-1]: length for row/column i on input */ Int iwlen, /* length of Iw. iwlen >= pfree + n */ Int pfree, /* Iw [pfree ... iwlen-1] is empty on input */ /* 7 size-n workspaces, not defined on input: */ Int Nv [ ], /* the size of each supernode on output */ Int Next [ ], /* the output inverse permutation */ Int Last [ ], /* the output permutation */ Int Head [ ], Int Elen [ ], /* the size columns of L for each supernode */ Int Degree [ ], Int W [ ], /* control parameters and output statistics */ double Control [ ], /* array of size AMD_CONTROL */ double Info [ ] /* array of size AMD_INFO */ ) { /* * Given a representation of the nonzero pattern of a symmetric matrix, A, * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style) * degree ordering to compute a pivot order such that the introduction of * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low. At each * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style * upper-bound on the external degree. This routine can optionally perform * aggresive absorption (as done by MC47B in the Harwell Subroutine * Library). * * The approximate degree algorithm implemented here is the symmetric analog of * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern * MultiFrontal PACKage, both by Davis and Duff). The routine is based on the * MA27 minimum degree ordering algorithm by Iain Duff and John Reid. * * This routine is a translation of the original AMDBAR and MC47B routines, * in Fortran, with the following modifications: * * (1) dense rows/columns are removed prior to ordering the matrix, and placed * last in the output order. The presence of a dense row/column can * increase the ordering time by up to O(n^2), unless they are removed * prior to ordering. * * (2) the minimum degree ordering is followed by a postordering (depth-first * search) of the assembly tree. Note that mass elimination (discussed * below) combined with the approximate degree update can lead to the mass * elimination of nodes with lower exact degree than the current pivot * element. No additional fill-in is caused in the representation of the * Schur complement. The mass-eliminated nodes merge with the current * pivot element. They are ordered prior to the current pivot element. * Because they can have lower exact degree than the current element, the * merger of two or more of these nodes in the current pivot element can * lead to a single element that is not a "fundamental supernode". The * diagonal block can have zeros in it. Thus, the assembly tree used here * is not guaranteed to be the precise supernodal elemination tree (with * "funadmental" supernodes), and the postordering performed by this * routine is not guaranteed to be a precise postordering of the * elimination tree. * * (3) input parameters are added, to control aggressive absorption and the * detection of "dense" rows/columns of A. * * (4) additional statistical information is returned, such as the number of * nonzeros in L, and the flop counts for subsequent LDL' and LU * factorizations. These are slight upper bounds, because of the mass * elimination issue discussed above. * * (5) additional routines are added to interface this routine to MATLAB * to provide a simple C-callable user-interface, to check inputs for * errors, compute the symmetry of the pattern of A and the number of * nonzeros in each row/column of A+A', to compute the pattern of A+A', * to perform the assembly tree postordering, and to provide debugging * ouput. Many of these functions are also provided by the Fortran * Harwell Subroutine Library routine MC47A. * * (6) both int and UF_long versions are provided. In the descriptions below * and integer is and int or UF_long depending on which version is * being used. ********************************************************************** ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ****** ********************************************************************** ** If you want error checking, a more versatile input format, and a ** ** simpler user interface, use amd_order or amd_l_order instead. ** ** This routine is not meant to be user-callable. ** ********************************************************************** * ---------------------------------------------------------------------------- * References: * ---------------------------------------------------------------------------- * * [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal * method for sparse LU factorization", SIAM J. Matrix Analysis and * Applications, vol. 18, no. 1, pp. 140-158. Discusses UMFPACK / MA38, * which first introduced the approximate minimum degree used by this * routine. * * [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate * minimum degree ordering algorithm," SIAM J. Matrix Analysis and * Applications, vol. 17, no. 4, pp. 886-905, 1996. Discusses AMDBAR and * MC47B, which are the Fortran versions of this routine. * * [3] Alan George and Joseph Liu, "The evolution of the minimum degree * ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989. * We list below the features mentioned in that paper that this code * includes: * * mass elimination: * Yes. MA27 relied on supervariable detection for mass elimination. * * indistinguishable nodes: * Yes (we call these "supervariables"). This was also in the MA27 * code - although we modified the method of detecting them (the * previous hash was the true degree, which we no longer keep track * of). A supervariable is a set of rows with identical nonzero * pattern. All variables in a supervariable are eliminated together. * Each supervariable has as its numerical name that of one of its * variables (its principal variable). * * quotient graph representation: * Yes. We use the term "element" for the cliques formed during * elimination. This was also in the MA27 code. The algorithm can * operate in place, but it will work more efficiently if given some * "elbow room." * * element absorption: * Yes. This was also in the MA27 code. * * external degree: * Yes. The MA27 code was based on the true degree. * * incomplete degree update and multiple elimination: * No. This was not in MA27, either. Our method of degree update * within MC47B is element-based, not variable-based. It is thus * not well-suited for use with incomplete degree update or multiple * elimination. * * Authors, and Copyright (C) 2004 by: * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid. * * Acknowledgements: This work (and the UMFPACK package) was supported by the * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270). * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog * which forms the basis of AMD, was developed while Tim Davis was supported by * CERFACS (Toulouse, France) in a post-doctoral position. This C version, and * the etree postorder, were written while Tim Davis was on sabbatical at * Stanford University and Lawrence Berkeley National Laboratory. * ---------------------------------------------------------------------------- * INPUT ARGUMENTS (unaltered): * ---------------------------------------------------------------------------- * n: The matrix order. Restriction: n >= 1. * * iwlen: The size of the Iw array. On input, the matrix is stored in * Iw [0..pfree-1]. However, Iw [0..iwlen-1] should be slightly larger * than what is required to hold the matrix, at least iwlen >= pfree + n. * Otherwise, excessive compressions will take place. The recommended * value of iwlen is 1.2 * pfree + n, which is the value used in the * user-callable interface to this routine (amd_order.c). The algorithm * will not run at all if iwlen < pfree. Restriction: iwlen >= pfree + n. * Note that this is slightly more restrictive than the actual minimum * (iwlen >= pfree), but AMD_2 will be very slow with no elbow room. * Thus, this routine enforces a bare minimum elbow room of size n. * * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty, * and the matrix is stored in Iw [0..pfree-1]. During execution, * additional data is placed in Iw, and pfree is modified so that * Iw [pfree..iwlen-1] is always the unused part of Iw. * * Control: A double array of size AMD_CONTROL containing input parameters * that affect how the ordering is computed. If NULL, then default * settings are used. * * Control [AMD_DENSE] is used to determine whether or not a given input * row is "dense". A row is "dense" if the number of entries in the row * exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or * fewer entries are never considered "dense". To turn off the detection * of dense rows, set Control [AMD_DENSE] to a negative number, or to a * number larger than sqrt (n). The default value of Control [AMD_DENSE] * is AMD_DEFAULT_DENSE, which is defined in amd.h as 10. * * Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive * absorption is to be performed. If nonzero, then aggressive absorption * is performed (this is the default). * ---------------------------------------------------------------------------- * INPUT/OUPUT ARGUMENTS: * ---------------------------------------------------------------------------- * * Pe: An integer array of size n. On input, Pe [i] is the index in Iw of * the start of row i. Pe [i] is ignored if row i has no off-diagonal * entries. Thus Pe [i] must be in the range 0 to pfree-1 for non-empty * rows. * * During execution, it is used for both supervariables and elements: * * Principal supervariable i: index into Iw of the description of * supervariable i. A supervariable represents one or more rows of * the matrix with identical nonzero pattern. In this case, * Pe [i] >= 0. * * Non-principal supervariable i: if i has been absorbed into another * supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined * as (-(j)-2). Row j has the same pattern as row i. Note that j * might later be absorbed into another supervariable j2, in which * case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is * < EMPTY, where EMPTY is defined as (-1) in amd_internal.h. * * Unabsorbed element e: the index into Iw of the description of element * e, if e has not yet been absorbed by a subsequent element. Element * e is created when the supervariable of the same name is selected as * the pivot. In this case, Pe [i] >= 0. * * Absorbed element e: if element e is absorbed into element e2, then * Pe [e] = FLIP (e2). This occurs when the pattern of e (which we * refer to as Le) is found to be a subset of the pattern of e2 (that * is, Le2). In this case, Pe [i] < EMPTY. If element e is "null" * (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY, * and e is the root of an assembly subtree (or the whole tree if * there is just one such root). * * Dense variable i: if i is "dense", then Pe [i] = EMPTY. * * On output, Pe holds the assembly tree/forest, which implicitly * represents a pivot order with identical fill-in as the actual order * (via a depth-first search of the tree), as follows. If Nv [i] > 0, * then i represents a node in the assembly tree, and the parent of i is * Pe [i], or EMPTY if i is a root. If Nv [i] = 0, then (i, Pe [i]) * represents an edge in a subtree, the root of which is a node in the * assembly tree. Note that i refers to a row/column in the original * matrix, not the permuted matrix. * * Info: A double array of size AMD_INFO. If present, (that is, not NULL), * then statistics about the ordering are returned in the Info array. * See amd.h for a description. * ---------------------------------------------------------------------------- * INPUT/MODIFIED (undefined on output): * ---------------------------------------------------------------------------- * * Len: An integer array of size n. On input, Len [i] holds the number of * entries in row i of the matrix, excluding the diagonal. The contents * of Len are undefined on output. * * Iw: An integer array of size iwlen. On input, Iw [0..pfree-1] holds the * description of each row i in the matrix. The matrix must be symmetric, * and both upper and lower triangular parts must be present. The * diagonal must not be present. Row i is held as follows: * * Len [i]: the length of the row i data structure in the Iw array. * Iw [Pe [i] ... Pe [i] + Len [i] - 1]: * the list of column indices for nonzeros in row i (simple * supervariables), excluding the diagonal. All supervariables * start with one row/column each (supervariable i is just row i). * If Len [i] is zero on input, then Pe [i] is ignored on input. * * Note that the rows need not be in any particular order, and there * may be empty space between the rows. * * During execution, the supervariable i experiences fill-in. This is * represented by placing in i a list of the elements that cause fill-in * in supervariable i: * * Len [i]: the length of supervariable i in the Iw array. * Iw [Pe [i] ... Pe [i] + Elen [i] - 1]: * the list of elements that contain i. This list is kept short * by removing absorbed elements. * Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]: * the list of supervariables in i. This list is kept short by * removing nonprincipal variables, and any entry j that is also * contained in at least one of the elements (j in Le) in the list * for i (e in row i). * * When supervariable i is selected as pivot, we create an element e of * the same name (e=i): * * Len [e]: the length of element e in the Iw array. * Iw [Pe [e] ... Pe [e] + Len [e] - 1]: * the list of supervariables in element e. * * An element represents the fill-in that occurs when supervariable i is * selected as pivot (which represents the selection of row i and all * non-principal variables whose principal variable is i). We use the * term Le to denote the set of all supervariables in element e. Absorbed * supervariables and elements are pruned from these lists when * computationally convenient. * * CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION. * The contents of Iw are undefined on output. * ---------------------------------------------------------------------------- * OUTPUT (need not be set on input): * ---------------------------------------------------------------------------- * * Nv: An integer array of size n. During execution, ABS (Nv [i]) is equal to * the number of rows that are represented by the principal supervariable * i. If i is a nonprincipal or dense variable, then Nv [i] = 0. * Initially, Nv [i] = 1 for all i. Nv [i] < 0 signifies that i is a * principal variable in the pattern Lme of the current pivot element me. * After element me is constructed, Nv [i] is set back to a positive * value. * * On output, Nv [i] holds the number of pivots represented by super * row/column i of the original matrix, or Nv [i] = 0 for non-principal * rows/columns. Note that i refers to a row/column in the original * matrix, not the permuted matrix. * * Elen: An integer array of size n. See the description of Iw above. At the * start of execution, Elen [i] is set to zero for all rows i. During * execution, Elen [i] is the number of elements in the list for * supervariable i. When e becomes an element, Elen [e] = FLIP (esize) is * set, where esize is the size of the element (the number of pivots, plus * the number of nonpivotal entries). Thus Elen [e] < EMPTY. * Elen (i) = EMPTY set when variable i becomes nonprincipal. * * For variables, Elen (i) >= EMPTY holds until just before the * postordering and permutation vectors are computed. For elements, * Elen [e] < EMPTY holds. * * On output, Elen [i] is the degree of the row/column in the Cholesky * factorization of the permuted matrix, corresponding to the original row * i, if i is a super row/column. It is equal to EMPTY if i is * non-principal. Note that i refers to a row/column in the original * matrix, not the permuted matrix. * * Note that the contents of Elen on output differ from the Fortran * version (Elen holds the inverse permutation in the Fortran version, * which is instead returned in the Next array in this C version, * described below). * * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY * if i is the head of the list. In a hash bucket, Last [i] is the hash * key for i. * * Last [Head [hash]] is also used as the head of a hash bucket if * Head [hash] contains a degree list (see the description of Head, * below). * * On output, Last [0..n-1] holds the permutation. That is, if * i = Last [k], then row i is the kth pivot row (where k ranges from 0 to * n-1). Row Last [k] of A is the kth row in the permuted matrix, PAP'. * * Next: Next [i] is the supervariable following i in a link list, or EMPTY if * i is the last in the list. Used for two kinds of lists: degree lists * and hash buckets (a supervariable can be in only one kind of list at a * time). * * On output Next [0..n-1] holds the inverse permutation. That is, if * k = Next [i], then row i is the kth pivot row. Row i of A appears as * the (Next[i])-th row in the permuted matrix, PAP'. * * Note that the contents of Next on output differ from the Fortran * version (Next is undefined on output in the Fortran version). * ---------------------------------------------------------------------------- * LOCAL WORKSPACE (not input or output - used only during execution): * ---------------------------------------------------------------------------- * * Degree: An integer array of size n. If i is a supervariable, then * Degree [i] holds the current approximation of the external degree of * row i (an upper bound). The external degree is the number of nonzeros * in row i, minus ABS (Nv [i]), the diagonal part. The bound is equal to * the exact external degree if Elen [i] is less than or equal to two. * * We also use the term "external degree" for elements e to refer to * |Le \ Lme|. If e is an element, then Degree [e] is |Le|, which is the * degree of the off-diagonal part of the element e (not including the * diagonal part). * * Head: An integer array of size n. Head is used for degree lists. * Head [deg] is the first supervariable in a degree list. All * supervariables i in a degree list Head [deg] have the same approximate * degree, namely, deg = Degree [i]. If the list Head [deg] is empty then * Head [deg] = EMPTY. * * During supervariable detection Head [hash] also serves as a pointer to * a hash bucket. If Head [hash] >= 0, there is a degree list of degree * hash. The hash bucket head pointer is Last [Head [hash]]. If * Head [hash] = EMPTY, then the degree list and hash bucket are both * empty. If Head [hash] < EMPTY, then the degree list is empty, and * FLIP (Head [hash]) is the head of the hash bucket. After supervariable * detection is complete, all hash buckets are empty, and the * (Last [Head [hash]] = EMPTY) condition is restored for the non-empty * degree lists. * * W: An integer array of size n. The flag array W determines the status of * elements and variables, and the external degree of elements. * * for elements: * if W [e] = 0, then the element e is absorbed. * if W [e] >= wflg, then W [e] - wflg is the size of the set * |Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for * each principal variable i that is both in the pattern of * element e and NOT in the pattern of the current pivot element, * me). * if wflg > W [e] > 0, then e is not absorbed and has not yet been * seen in the scan of the element lists in the computation of * |Le\Lme| in Scan 1 below. * * for variables: * during supervariable detection, if W [j] != wflg then j is * not in the pattern of variable i. * * The W array is initialized by setting W [i] = 1 for all i, and by * setting wflg = 2. It is reinitialized if wflg becomes too large (to * ensure that wflg+n does not cause integer overflow). * ---------------------------------------------------------------------------- * LOCAL INTEGERS: * ---------------------------------------------------------------------------- */ Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j, jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft, nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa, dense, aggressive ; unsigned Int hash ; /* unsigned, so that hash % n is well defined.*/ /* * deg: the degree of a variable or element * degme: size, |Lme|, of the current element, me (= Degree [me]) * dext: external degree, |Le \ Lme|, of some element e * lemax: largest |Le| seen so far (called dmax in Fortran version) * e: an element * elenme: the length, Elen [me], of element list of pivotal variable * eln: the length, Elen [...], of an element list * hash: the computed value of the hash function * i: a supervariable * ilast: the entry in a link list preceding i * inext: the entry in a link list following i * j: a supervariable * jlast: the entry in a link list preceding j * jnext: the entry in a link list, or path, following j * k: the pivot order of an element or variable * knt1: loop counter used during element construction * knt2: loop counter used during element construction * knt3: loop counter used during compression * lenj: Len [j] * ln: length of a supervariable list * me: current supervariable being eliminated, and the current * element created by eliminating that supervariable * mindeg: current minimum degree * nel: number of pivots selected so far * nleft: n - nel, the number of nonpivotal rows/columns remaining * nvi: the number of variables in a supervariable i (= Nv [i]) * nvj: the number of variables in a supervariable j (= Nv [j]) * nvpiv: number of pivots in current element * slenme: number of variables in variable list of pivotal variable * wbig: = INT_MAX - n for the int version, UF_long_max - n for the * UF_long version. wflg is not allowed to be >= wbig. * we: W [e] * wflg: used for flagging the W array. See description of Iw. * wnvi: wflg - Nv [i] * x: either a supervariable or an element * * ok: true if supervariable j can be absorbed into i * ndense: number of "dense" rows/columns * dense: rows/columns with initial degree > dense are considered "dense" * aggressive: true if aggressive absorption is being performed * ncmpa: number of garbage collections * ---------------------------------------------------------------------------- * LOCAL DOUBLES, used for statistical output only (except for alpha): * ---------------------------------------------------------------------------- */ double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ; /* * f: nvpiv * r: degme + nvpiv * ndiv: number of divisions for LU or LDL' factorizations * s: number of multiply-subtract pairs for LU factorization, for the * current element me * nms_lu number of multiply-subtract pairs for LU factorization * nms_ldl number of multiply-subtract pairs for LDL' factorization * dmax: the largest number of entries in any column of L, including the * diagonal * alpha: "dense" degree ratio * lnz: the number of nonzeros in L (excluding the diagonal) * lnzme: the number of nonzeros in L (excl. the diagonal) for the * current element me * ---------------------------------------------------------------------------- * LOCAL "POINTERS" (indices into the Iw array) * ---------------------------------------------------------------------------- */ Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ; /* * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for * Pointer) is an index into Iw, and all indices into Iw use variables starting * with "p." The only exception to this rule is the iwlen input argument. * * p: pointer into lots of things * p1: Pe [i] for some variable i (start of element list) * p2: Pe [i] + Elen [i] - 1 for some variable i * p3: index of first supervariable in clean list * p4: * pdst: destination pointer, for compression * pend: end of memory to compress * pj: pointer into an element or variable * pme: pointer into the current element (pme1...pme2) * pme1: the current element, me, is stored in Iw [pme1...pme2] * pme2: the end of the current element * pn: pointer into a "clean" variable, also used to compress * psrc: source pointer, for compression */ /* ========================================================================= */ /* INITIALIZATIONS */ /* ========================================================================= */ /* Note that this restriction on iwlen is slightly more restrictive than * what is actually required in AMD_2. AMD_2 can operate with no elbow * room at all, but it will be slow. For better performance, at least * size-n elbow room is enforced. */ ASSERT (iwlen >= pfree + n) ; ASSERT (n > 0) ; /* initialize output statistics */ lnz = 0 ; ndiv = 0 ; nms_lu = 0 ; nms_ldl = 0 ; dmax = 1 ; me = EMPTY ; mindeg = 0 ; ncmpa = 0 ; nel = 0 ; lemax = 0 ; /* get control parameters */ if (Control != (double *) NULL) { alpha = Control [AMD_DENSE] ; aggressive = (Control [AMD_AGGRESSIVE] != 0) ; } else { alpha = AMD_DEFAULT_DENSE ; aggressive = AMD_DEFAULT_AGGRESSIVE ; } /* Note: if alpha is NaN, this is undefined: */ if (alpha < 0) { /* only remove completely dense rows/columns */ dense = n-2 ; } else { dense = alpha * sqrt ((double) n) ; } dense = MAX (16, dense) ; dense = MIN (n, dense) ; AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n", alpha, aggressive)) ; for (i = 0 ; i < n ; i++) { Last [i] = EMPTY ; Head [i] = EMPTY ; Next [i] = EMPTY ; /* if separate Hhead array is used for hash buckets: * Hhead [i] = EMPTY ; */ Nv [i] = 1 ; W [i] = 1 ; Elen [i] = 0 ; Degree [i] = Len [i] ; } #ifndef NDEBUG AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ; AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last, Head, Elen, Degree, W, -1) ; #endif /* initialize wflg */ wbig = Int_MAX - n ; wflg = clear_flag (0, wbig, W, n) ; /* --------------------------------------------------------------------- */ /* initialize degree lists and eliminate dense and empty rows */ /* --------------------------------------------------------------------- */ ndense = 0 ; for (i = 0 ; i < n ; i++) { deg = Degree [i] ; ASSERT (deg >= 0 && deg < n) ; if (deg == 0) { /* ------------------------------------------------------------- * we have a variable that can be eliminated at once because * there is no off-diagonal non-zero in its row. Note that * Nv [i] = 1 for an empty variable i. It is treated just * the same as an eliminated element i. * ------------------------------------------------------------- */ Elen [i] = FLIP (1) ; nel++ ; Pe [i] = EMPTY ; W [i] = 0 ; } else if (deg > dense) { /* ------------------------------------------------------------- * Dense variables are not treated as elements, but as unordered, * non-principal variables that have no parent. They do not take * part in the postorder, since Nv [i] = 0. Note that the Fortran * version does not have this option. * ------------------------------------------------------------- */ AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ; ndense++ ; Nv [i] = 0 ; /* do not postorder this node */ Elen [i] = EMPTY ; nel++ ; Pe [i] = EMPTY ; } else { /* ------------------------------------------------------------- * place i in the degree list corresponding to its degree * ------------------------------------------------------------- */ inext = Head [deg] ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = i ; Next [i] = inext ; Head [deg] = i ; } } /* ========================================================================= */ /* WHILE (selecting pivots) DO */ /* ========================================================================= */ while (nel < n) { #ifndef NDEBUG AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ; if (AMD_debug >= 2) { AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last, Head, Elen, Degree, W, nel) ; } #endif /* ========================================================================= */ /* GET PIVOT OF MINIMUM DEGREE */ /* ========================================================================= */ /* ----------------------------------------------------------------- */ /* find next supervariable for elimination */ /* ----------------------------------------------------------------- */ ASSERT (mindeg >= 0 && mindeg < n) ; for (deg = mindeg ; deg < n ; deg++) { me = Head [deg] ; if (me != EMPTY) break ; } mindeg = deg ; ASSERT (me >= 0 && me < n) ; AMD_DEBUG1 (("=================me: "ID"\n", me)) ; /* ----------------------------------------------------------------- */ /* remove chosen variable from link list */ /* ----------------------------------------------------------------- */ inext = Next [me] ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = EMPTY ; Head [deg] = inext ; /* ----------------------------------------------------------------- */ /* me represents the elimination of pivots nel to nel+Nv[me]-1. */ /* place me itself as the first in this set. */ /* ----------------------------------------------------------------- */ elenme = Elen [me] ; nvpiv = Nv [me] ; ASSERT (nvpiv > 0) ; nel += nvpiv ; /* ========================================================================= */ /* CONSTRUCT NEW ELEMENT */ /* ========================================================================= */ /* ----------------------------------------------------------------- * At this point, me is the pivotal supervariable. It will be * converted into the current element. Scan list of the pivotal * supervariable, me, setting tree pointers and constructing new list * of supervariables for the new element, me. p is a pointer to the * current position in the old list. * ----------------------------------------------------------------- */ /* flag the variable "me" as being in Lme by negating Nv [me] */ Nv [me] = -nvpiv ; degme = 0 ; ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; if (elenme == 0) { /* ------------------------------------------------------------- */ /* construct the new element in place */ /* ------------------------------------------------------------- */ pme1 = Pe [me] ; pme2 = pme1 - 1 ; for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++) { i = Iw [p] ; ASSERT (i >= 0 && i < n && Nv [i] >= 0) ; nvi = Nv [i] ; if (nvi > 0) { /* ----------------------------------------------------- */ /* i is a principal variable not yet placed in Lme. */ /* store i in new list */ /* ----------------------------------------------------- */ /* flag i as being in Lme by negating Nv [i] */ degme += nvi ; Nv [i] = -nvi ; Iw [++pme2] = i ; /* ----------------------------------------------------- */ /* remove variable i from degree list. */ /* ----------------------------------------------------- */ ilast = Last [i] ; inext = Next [i] ; ASSERT (ilast >= EMPTY && ilast < n) ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = ilast ; if (ilast != EMPTY) { Next [ilast] = inext ; } else { /* i is at the head of the degree list */ ASSERT (Degree [i] >= 0 && Degree [i] < n) ; Head [Degree [i]] = inext ; } } } } else { /* ------------------------------------------------------------- */ /* construct the new element in empty space, Iw [pfree ...] */ /* ------------------------------------------------------------- */ p = Pe [me] ; pme1 = pfree ; slenme = Len [me] - elenme ; for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++) { if (knt1 > elenme) { /* search the supervariables in me. */ e = me ; pj = p ; ln = slenme ; AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ; } else { /* search the elements in me. */ e = Iw [p++] ; ASSERT (e >= 0 && e < n) ; pj = Pe [e] ; ln = Len [e] ; AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ; ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ; } ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ; /* --------------------------------------------------------- * search for different supervariables and add them to the * new list, compressing when necessary. this loop is * executed once for each element in the list and once for * all the supervariables in the list. * --------------------------------------------------------- */ for (knt2 = 1 ; knt2 <= ln ; knt2++) { i = Iw [pj++] ; ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY)); nvi = Nv [i] ; AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n", i, Elen [i], Nv [i], wflg)) ; if (nvi > 0) { /* ------------------------------------------------- */ /* compress Iw, if necessary */ /* ------------------------------------------------- */ if (pfree >= iwlen) { AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ; /* prepare for compressing Iw by adjusting pointers * and lengths so that the lists being searched in * the inner and outer loops contain only the * remaining entries. */ Pe [me] = p ; Len [me] -= knt1 ; /* check if nothing left of supervariable me */ if (Len [me] == 0) Pe [me] = EMPTY ; Pe [e] = pj ; Len [e] = ln - knt2 ; /* nothing left of element e */ if (Len [e] == 0) Pe [e] = EMPTY ; ncmpa++ ; /* one more garbage collection */ /* store first entry of each object in Pe */ /* FLIP the first entry in each object */ for (j = 0 ; j < n ; j++) { pn = Pe [j] ; if (pn >= 0) { ASSERT (pn >= 0 && pn < iwlen) ; Pe [j] = Iw [pn] ; Iw [pn] = FLIP (j) ; } } /* psrc/pdst point to source/destination */ psrc = 0 ; pdst = 0 ; pend = pme1 - 1 ; while (psrc <= pend) { /* search for next FLIP'd entry */ j = FLIP (Iw [psrc++]) ; if (j >= 0) { AMD_DEBUG2 (("Got object j: "ID"\n", j)) ; Iw [pdst] = Pe [j] ; Pe [j] = pdst++ ; lenj = Len [j] ; /* copy from source to destination */ for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++) { Iw [pdst++] = Iw [psrc++] ; } } } /* move the new partially-constructed element */ p1 = pdst ; for (psrc = pme1 ; psrc <= pfree-1 ; psrc++) { Iw [pdst++] = Iw [psrc] ; } pme1 = p1 ; pfree = pdst ; pj = Pe [e] ; p = Pe [me] ; } /* ------------------------------------------------- */ /* i is a principal variable not yet placed in Lme */ /* store i in new list */ /* ------------------------------------------------- */ /* flag i as being in Lme by negating Nv [i] */ degme += nvi ; Nv [i] = -nvi ; Iw [pfree++] = i ; AMD_DEBUG2 ((" s: "ID" nv "ID"\n", i, Nv [i])); /* ------------------------------------------------- */ /* remove variable i from degree link list */ /* ------------------------------------------------- */ ilast = Last [i] ; inext = Next [i] ; ASSERT (ilast >= EMPTY && ilast < n) ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = ilast ; if (ilast != EMPTY) { Next [ilast] = inext ; } else { /* i is at the head of the degree list */ ASSERT (Degree [i] >= 0 && Degree [i] < n) ; Head [Degree [i]] = inext ; } } } if (e != me) { /* set tree pointer and flag to indicate element e is * absorbed into new element me (the parent of e is me) */ AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ; Pe [e] = FLIP (me) ; W [e] = 0 ; } } pme2 = pfree - 1 ; } /* ----------------------------------------------------------------- */ /* me has now been converted into an element in Iw [pme1..pme2] */ /* ----------------------------------------------------------------- */ /* degme holds the external degree of new element */ Degree [me] = degme ; Pe [me] = pme1 ; Len [me] = pme2 - pme1 + 1 ; ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ; Elen [me] = FLIP (nvpiv + degme) ; /* FLIP (Elen (me)) is now the degree of pivot (including * diagonal part). */ #ifndef NDEBUG AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ; for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme])); AMD_DEBUG3 (("\n")) ; #endif /* ----------------------------------------------------------------- */ /* make sure that wflg is not too large. */ /* ----------------------------------------------------------------- */ /* With the current value of wflg, wflg+n must not cause integer * overflow */ wflg = clear_flag (wflg, wbig, W, n) ; /* ========================================================================= */ /* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */ /* ========================================================================= */ /* ----------------------------------------------------------------- * Scan 1: compute the external degrees of previous elements with * respect to the current element. That is: * (W [e] - wflg) = |Le \ Lme| * for each element e that appears in any supervariable in Lme. The * notation Le refers to the pattern (list of supervariables) of a * previous element e, where e is not yet absorbed, stored in * Iw [Pe [e] + 1 ... Pe [e] + Len [e]]. The notation Lme * refers to the pattern of the current element (stored in * Iw [pme1..pme2]). If aggressive absorption is enabled, and * (W [e] - wflg) becomes zero, then the element e will be absorbed * in Scan 2. * ----------------------------------------------------------------- */ AMD_DEBUG2 (("me: ")) ; for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n) ; eln = Elen [i] ; AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ; if (eln > 0) { /* note that Nv [i] has been negated to denote i in Lme: */ nvi = -Nv [i] ; ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ; wnvi = wflg - nvi ; for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++) { e = Iw [p] ; ASSERT (e >= 0 && e < n) ; we = W [e] ; AMD_DEBUG4 ((" e "ID" we "ID" ", e, we)) ; if (we >= wflg) { /* unabsorbed element e has been seen in this loop */ AMD_DEBUG4 ((" unabsorbed, first time seen")) ; we -= nvi ; } else if (we != 0) { /* e is an unabsorbed element */ /* this is the first we have seen e in all of Scan 1 */ AMD_DEBUG4 ((" unabsorbed")) ; we = Degree [e] + wnvi ; } AMD_DEBUG4 (("\n")) ; W [e] = we ; } } } AMD_DEBUG2 (("\n")) ; /* ========================================================================= */ /* DEGREE UPDATE AND ELEMENT ABSORPTION */ /* ========================================================================= */ /* ----------------------------------------------------------------- * Scan 2: for each i in Lme, sum up the degree of Lme (which is * degme), plus the sum of the external degrees of each Le for the * elements e appearing within i, plus the supervariables in i. * Place i in hash list. * ----------------------------------------------------------------- */ for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ; AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i])); p1 = Pe [i] ; p2 = p1 + Elen [i] - 1 ; pn = p1 ; hash = 0 ; deg = 0 ; ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ; /* ------------------------------------------------------------- */ /* scan the element list associated with supervariable i */ /* ------------------------------------------------------------- */ /* UMFPACK/MA38-style approximate degree: */ if (aggressive) { for (p = p1 ; p <= p2 ; p++) { e = Iw [p] ; ASSERT (e >= 0 && e < n) ; we = W [e] ; if (we != 0) { /* e is an unabsorbed element */ /* dext = | Le \ Lme | */ dext = we - wflg ; if (dext > 0) { deg += dext ; Iw [pn++] = e ; hash += e ; AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; } else { /* external degree of e is zero, absorb e into me*/ AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n", e, me)) ; ASSERT (dext == 0) ; Pe [e] = FLIP (me) ; W [e] = 0 ; } } } } else { for (p = p1 ; p <= p2 ; p++) { e = Iw [p] ; ASSERT (e >= 0 && e < n) ; we = W [e] ; if (we != 0) { /* e is an unabsorbed element */ dext = we - wflg ; ASSERT (dext >= 0) ; deg += dext ; Iw [pn++] = e ; hash += e ; AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ; } } } /* count the number of elements in i (including me): */ Elen [i] = pn - p1 + 1 ; /* ------------------------------------------------------------- */ /* scan the supervariables in the list associated with i */ /* ------------------------------------------------------------- */ /* The bulk of the AMD run time is typically spent in this loop, * particularly if the matrix has many dense rows that are not * removed prior to ordering. */ p3 = pn ; p4 = p1 + Len [i] ; for (p = p2 + 1 ; p < p4 ; p++) { j = Iw [p] ; ASSERT (j >= 0 && j < n) ; nvj = Nv [j] ; if (nvj > 0) { /* j is unabsorbed, and not in Lme. */ /* add to degree and add to new list */ deg += nvj ; Iw [pn++] = j ; hash += j ; AMD_DEBUG4 ((" s: "ID" hash "ID" Nv[j]= "ID"\n", j, hash, nvj)) ; } } /* ------------------------------------------------------------- */ /* update the degree and check for mass elimination */ /* ------------------------------------------------------------- */ /* with aggressive absorption, deg==0 is identical to the * Elen [i] == 1 && p3 == pn test, below. */ ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ; if (Elen [i] == 1 && p3 == pn) { /* --------------------------------------------------------- */ /* mass elimination */ /* --------------------------------------------------------- */ /* There is nothing left of this node except for an edge to * the current pivot element. Elen [i] is 1, and there are * no variables adjacent to node i. Absorb i into the * current pivot element, me. Note that if there are two or * more mass eliminations, fillin due to mass elimination is * possible within the nvpiv-by-nvpiv pivot block. It is this * step that causes AMD's analysis to be an upper bound. * * The reason is that the selected pivot has a lower * approximate degree than the true degree of the two mass * eliminated nodes. There is no edge between the two mass * eliminated nodes. They are merged with the current pivot * anyway. * * No fillin occurs in the Schur complement, in any case, * and this effect does not decrease the quality of the * ordering itself, just the quality of the nonzero and * flop count analysis. It also means that the post-ordering * is not an exact elimination tree post-ordering. */ AMD_DEBUG1 ((" MASS i "ID" => parent e "ID"\n", i, me)) ; Pe [i] = FLIP (me) ; nvi = -Nv [i] ; degme -= nvi ; nvpiv += nvi ; nel += nvi ; Nv [i] = 0 ; Elen [i] = EMPTY ; } else { /* --------------------------------------------------------- */ /* update the upper-bound degree of i */ /* --------------------------------------------------------- */ /* the following degree does not yet include the size * of the current element, which is added later: */ Degree [i] = MIN (Degree [i], deg) ; /* --------------------------------------------------------- */ /* add me to the list for i */ /* --------------------------------------------------------- */ /* move first supervariable to end of list */ Iw [pn] = Iw [p3] ; /* move first element to end of element part of list */ Iw [p3] = Iw [p1] ; /* add new element, me, to front of list. */ Iw [p1] = me ; /* store the new length of the list in Len [i] */ Len [i] = pn - p1 + 1 ; /* --------------------------------------------------------- */ /* place in hash bucket. Save hash key of i in Last [i]. */ /* --------------------------------------------------------- */ /* NOTE: this can fail if hash is negative, because the ANSI C * standard does not define a % b when a and/or b are negative. * That's why hash is defined as an unsigned Int, to avoid this * problem. */ hash = hash % n ; ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ; /* if the Hhead array is not used: */ j = Head [hash] ; if (j <= EMPTY) { /* degree list is empty, hash head is FLIP (j) */ Next [i] = FLIP (j) ; Head [hash] = FLIP (i) ; } else { /* degree list is not empty, use Last [Head [hash]] as * hash head. */ Next [i] = Last [j] ; Last [j] = i ; } /* if a separate Hhead array is used: * Next [i] = Hhead [hash] ; Hhead [hash] = i ; */ Last [i] = hash ; } } Degree [me] = degme ; /* ----------------------------------------------------------------- */ /* Clear the counter array, W [...], by incrementing wflg. */ /* ----------------------------------------------------------------- */ /* make sure that wflg+n does not cause integer overflow */ lemax = MAX (lemax, degme) ; wflg += lemax ; wflg = clear_flag (wflg, wbig, W, n) ; /* at this point, W [0..n-1] < wflg holds */ /* ========================================================================= */ /* SUPERVARIABLE DETECTION */ /* ========================================================================= */ AMD_DEBUG1 (("Detecting supervariables:\n")) ; for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n) ; AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ; if (Nv [i] < 0) { /* i is a principal variable in Lme */ /* --------------------------------------------------------- * examine all hash buckets with 2 or more variables. We do * this by examing all unique hash keys for supervariables in * the pattern Lme of the current element, me * --------------------------------------------------------- */ /* let i = head of hash bucket, and empty the hash bucket */ ASSERT (Last [i] >= 0 && Last [i] < n) ; hash = Last [i] ; /* if Hhead array is not used: */ j = Head [hash] ; if (j == EMPTY) { /* hash bucket and degree list are both empty */ i = EMPTY ; } else if (j < EMPTY) { /* degree list is empty */ i = FLIP (j) ; Head [hash] = EMPTY ; } else { /* degree list is not empty, restore Last [j] of head j */ i = Last [j] ; Last [j] = EMPTY ; } /* if separate Hhead array is used: * i = Hhead [hash] ; Hhead [hash] = EMPTY ; */ ASSERT (i >= EMPTY && i < n) ; AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ; while (i != EMPTY && Next [i] != EMPTY) { /* ----------------------------------------------------- * this bucket has one or more variables following i. * scan all of them to see if i can absorb any entries * that follow i in hash bucket. Scatter i into w. * ----------------------------------------------------- */ ln = Len [i] ; eln = Elen [i] ; ASSERT (ln >= 0 && eln >= 0) ; ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ; /* do not flag the first element in the list (me) */ for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++) { ASSERT (Iw [p] >= 0 && Iw [p] < n) ; W [Iw [p]] = wflg ; } /* ----------------------------------------------------- */ /* scan every other entry j following i in bucket */ /* ----------------------------------------------------- */ jlast = i ; j = Next [i] ; ASSERT (j >= EMPTY && j < n) ; while (j != EMPTY) { /* ------------------------------------------------- */ /* check if j and i have identical nonzero pattern */ /* ------------------------------------------------- */ AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ; /* check if i and j have the same Len and Elen */ ASSERT (Len [j] >= 0 && Elen [j] >= 0) ; ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ; ok = (Len [j] == ln) && (Elen [j] == eln) ; /* skip the first element in the list (me) */ for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++) { ASSERT (Iw [p] >= 0 && Iw [p] < n) ; if (W [Iw [p]] != wflg) ok = 0 ; } if (ok) { /* --------------------------------------------- */ /* found it! j can be absorbed into i */ /* --------------------------------------------- */ AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i)); Pe [j] = FLIP (i) ; /* both Nv [i] and Nv [j] are negated since they */ /* are in Lme, and the absolute values of each */ /* are the number of variables in i and j: */ Nv [i] += Nv [j] ; Nv [j] = 0 ; Elen [j] = EMPTY ; /* delete j from hash bucket */ ASSERT (j != Next [j]) ; j = Next [j] ; Next [jlast] = j ; } else { /* j cannot be absorbed into i */ jlast = j ; ASSERT (j != Next [j]) ; j = Next [j] ; } ASSERT (j >= EMPTY && j < n) ; } /* ----------------------------------------------------- * no more variables can be absorbed into i * go to next i in bucket and clear flag array * ----------------------------------------------------- */ wflg++ ; i = Next [i] ; ASSERT (i >= EMPTY && i < n) ; } } } AMD_DEBUG2 (("detect done\n")) ; /* ========================================================================= */ /* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */ /* ========================================================================= */ p = pme1 ; nleft = n - nel ; for (pme = pme1 ; pme <= pme2 ; pme++) { i = Iw [pme] ; ASSERT (i >= 0 && i < n) ; nvi = -Nv [i] ; AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ; if (nvi > 0) { /* i is a principal variable in Lme */ /* restore Nv [i] to signify that i is principal */ Nv [i] = nvi ; /* --------------------------------------------------------- */ /* compute the external degree (add size of current element) */ /* --------------------------------------------------------- */ deg = Degree [i] + degme - nvi ; deg = MIN (deg, nleft - nvi) ; ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ; /* --------------------------------------------------------- */ /* place the supervariable at the head of the degree list */ /* --------------------------------------------------------- */ inext = Head [deg] ; ASSERT (inext >= EMPTY && inext < n) ; if (inext != EMPTY) Last [inext] = i ; Next [i] = inext ; Last [i] = EMPTY ; Head [deg] = i ; /* --------------------------------------------------------- */ /* save the new degree, and find the minimum degree */ /* --------------------------------------------------------- */ mindeg = MIN (mindeg, deg) ; Degree [i] = deg ; /* --------------------------------------------------------- */ /* place the supervariable in the element pattern */ /* --------------------------------------------------------- */ Iw [p++] = i ; } } AMD_DEBUG2 (("restore done\n")) ; /* ========================================================================= */ /* FINALIZE THE NEW ELEMENT */ /* ========================================================================= */ AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ; Nv [me] = nvpiv ; /* save the length of the list for the new element me */ Len [me] = p - pme1 ; if (Len [me] == 0) { /* there is nothing left of the current pivot element */ /* it is a root of the assembly tree */ Pe [me] = EMPTY ; W [me] = 0 ; } if (elenme != 0) { /* element was not constructed in place: deallocate part of */ /* it since newly nonprincipal variables may have been removed */ pfree = p ; } /* The new element has nvpiv pivots and the size of the contribution * block for a multifrontal method is degme-by-degme, not including * the "dense" rows/columns. If the "dense" rows/columns are included, * the frontal matrix is no larger than * (degme+ndense)-by-(degme+ndense). */ if (Info != (double *) NULL) { f = nvpiv ; r = degme + ndense ; dmax = MAX (dmax, f + r) ; /* number of nonzeros in L (excluding the diagonal) */ lnzme = f*r + (f-1)*f/2 ; lnz += lnzme ; /* number of divide operations for LDL' and for LU */ ndiv += lnzme ; /* number of multiply-subtract pairs for LU */ s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ; nms_lu += s ; /* number of multiply-subtract pairs for LDL' */ nms_ldl += (s + lnzme)/2 ; } #ifndef NDEBUG AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n ::::\n", nel, n)) ; for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++) { AMD_DEBUG3 ((" "ID"", Iw [pme])) ; } AMD_DEBUG3 (("\n")) ; #endif } /* ========================================================================= */ /* DONE SELECTING PIVOTS */ /* ========================================================================= */ if (Info != (double *) NULL) { /* count the work to factorize the ndense-by-ndense submatrix */ f = ndense ; dmax = MAX (dmax, (double) ndense) ; /* number of nonzeros in L (excluding the diagonal) */ lnzme = (f-1)*f/2 ; lnz += lnzme ; /* number of divide operations for LDL' and for LU */ ndiv += lnzme ; /* number of multiply-subtract pairs for LU */ s = (f-1)*f*(2*f-1)/6 ; nms_lu += s ; /* number of multiply-subtract pairs for LDL' */ nms_ldl += (s + lnzme)/2 ; /* number of nz's in L (excl. diagonal) */ Info [AMD_LNZ] = lnz ; /* number of divide ops for LU and LDL' */ Info [AMD_NDIV] = ndiv ; /* number of multiply-subtract pairs for LDL' */ Info [AMD_NMULTSUBS_LDL] = nms_ldl ; /* number of multiply-subtract pairs for LU */ Info [AMD_NMULTSUBS_LU] = nms_lu ; /* number of "dense" rows/columns */ Info [AMD_NDENSE] = ndense ; /* largest front is dmax-by-dmax */ Info [AMD_DMAX] = dmax ; /* number of garbage collections in AMD */ Info [AMD_NCMPA] = ncmpa ; /* successful ordering */ Info [AMD_STATUS] = AMD_OK ; } /* ========================================================================= */ /* POST-ORDERING */ /* ========================================================================= */ /* ------------------------------------------------------------------------- * Variables at this point: * * Pe: holds the elimination tree. The parent of j is FLIP (Pe [j]), * or EMPTY if j is a root. The tree holds both elements and * non-principal (unordered) variables absorbed into them. * Dense variables are non-principal and unordered. * * Elen: holds the size of each element, including the diagonal part. * FLIP (Elen [e]) > 0 if e is an element. For unordered * variables i, Elen [i] is EMPTY. * * Nv: Nv [e] > 0 is the number of pivots represented by the element e. * For unordered variables i, Nv [i] is zero. * * Contents no longer needed: * W, Iw, Len, Degree, Head, Next, Last. * * The matrix itself has been destroyed. * * n: the size of the matrix. * No other scalars needed (pfree, iwlen, etc.) * ------------------------------------------------------------------------- */ /* restore Pe */ for (i = 0 ; i < n ; i++) { Pe [i] = FLIP (Pe [i]) ; } /* restore Elen, for output information, and for postordering */ for (i = 0 ; i < n ; i++) { Elen [i] = FLIP (Elen [i]) ; } /* Now the parent of j is Pe [j], or EMPTY if j is a root. Elen [e] > 0 * is the size of element e. Elen [i] is EMPTY for unordered variable i. */ #ifndef NDEBUG AMD_DEBUG2 (("\nTree:\n")) ; for (i = 0 ; i < n ; i++) { AMD_DEBUG2 ((" "ID" parent: "ID" ", i, Pe [i])) ; ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ; if (Nv [i] > 0) { /* this is an element */ e = i ; AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ; ASSERT (Elen [e] > 0) ; } AMD_DEBUG2 (("\n")) ; } AMD_DEBUG2 (("\nelements:\n")) ; for (e = 0 ; e < n ; e++) { if (Nv [e] > 0) { AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e, Elen [e], Nv [e])) ; } } AMD_DEBUG2 (("\nvariables:\n")) ; for (i = 0 ; i < n ; i++) { Int cnt ; if (Nv [i] == 0) { AMD_DEBUG3 (("i unordered: "ID"\n", i)) ; j = Pe [i] ; cnt = 0 ; AMD_DEBUG3 ((" j: "ID"\n", j)) ; if (j == EMPTY) { AMD_DEBUG3 ((" i is a dense variable\n")) ; } else { ASSERT (j >= 0 && j < n) ; while (Nv [j] == 0) { AMD_DEBUG3 ((" j : "ID"\n", j)) ; j = Pe [j] ; AMD_DEBUG3 ((" j:: "ID"\n", j)) ; cnt++ ; if (cnt > n) break ; } e = j ; AMD_DEBUG3 ((" got to e: "ID"\n", e)) ; } } } #endif /* ========================================================================= */ /* compress the paths of the variables */ /* ========================================================================= */ for (i = 0 ; i < n ; i++) { if (Nv [i] == 0) { /* ------------------------------------------------------------- * i is an un-ordered row. Traverse the tree from i until * reaching an element, e. The element, e, was the principal * supervariable of i and all nodes in the path from i to when e * was selected as pivot. * ------------------------------------------------------------- */ AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ; j = Pe [i] ; ASSERT (j >= EMPTY && j < n) ; AMD_DEBUG3 ((" j: "ID"\n", j)) ; if (j == EMPTY) { /* Skip a dense variable. It has no parent. */ AMD_DEBUG3 ((" i is a dense variable\n")) ; continue ; } /* while (j is a variable) */ while (Nv [j] == 0) { AMD_DEBUG3 ((" j : "ID"\n", j)) ; j = Pe [j] ; AMD_DEBUG3 ((" j:: "ID"\n", j)) ; ASSERT (j >= 0 && j < n) ; } /* got to an element e */ e = j ; AMD_DEBUG3 (("got to e: "ID"\n", e)) ; /* ------------------------------------------------------------- * traverse the path again from i to e, and compress the path * (all nodes point to e). Path compression allows this code to * compute in O(n) time. * ------------------------------------------------------------- */ j = i ; /* while (j is a variable) */ while (Nv [j] == 0) { jnext = Pe [j] ; AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ; Pe [j] = e ; j = jnext ; ASSERT (j >= 0 && j < n) ; } } } /* ========================================================================= */ /* postorder the assembly tree */ /* ========================================================================= */ AMD_postorder (n, Pe, Nv, Elen, W, /* output order */ Head, Next, Last) ; /* workspace */ /* ========================================================================= */ /* compute output permutation and inverse permutation */ /* ========================================================================= */ /* W [e] = k means that element e is the kth element in the new * order. e is in the range 0 to n-1, and k is in the range 0 to * the number of elements. Use Head for inverse order. */ for (k = 0 ; k < n ; k++) { Head [k] = EMPTY ; Next [k] = EMPTY ; } for (e = 0 ; e < n ; e++) { k = W [e] ; ASSERT ((k == EMPTY) == (Nv [e] == 0)) ; if (k != EMPTY) { ASSERT (k >= 0 && k < n) ; Head [k] = e ; } } /* construct output inverse permutation in Next, * and permutation in Last */ nel = 0 ; for (k = 0 ; k < n ; k++) { e = Head [k] ; if (e == EMPTY) break ; ASSERT (e >= 0 && e < n && Nv [e] > 0) ; Next [e] = nel ; nel += Nv [e] ; } ASSERT (nel == n - ndense) ; /* order non-principal variables (dense, & those merged into supervar's) */ for (i = 0 ; i < n ; i++) { if (Nv [i] == 0) { e = Pe [i] ; ASSERT (e >= EMPTY && e < n) ; if (e != EMPTY) { /* This is an unordered variable that was merged * into element e via supernode detection or mass * elimination of i when e became the pivot element. * Place i in order just before e. */ ASSERT (Next [i] == EMPTY && Nv [e] > 0) ; Next [i] = Next [e] ; Next [e]++ ; } else { /* This is a dense unordered variable, with no parent. * Place it last in the output order. */ Next [i] = nel++ ; } } } ASSERT (nel == n) ; AMD_DEBUG2 (("\n\nPerm:\n")) ; for (i = 0 ; i < n ; i++) { k = Next [i] ; ASSERT (k >= 0 && k < n) ; Last [k] = i ; AMD_DEBUG2 ((" perm ["ID"] = "ID"\n", k, i)) ; } } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_valid.c0000644000175000017500000000576411674452555021265 0ustar sonnesonne/* ========================================================================= */ /* === AMD_valid =========================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Check if a column-form matrix is valid or not. The matrix A is * n_row-by-n_col. The row indices of entries in column j are in * Ai [Ap [j] ... Ap [j+1]-1]. Required conditions are: * * n_row >= 0 * n_col >= 0 * nz = Ap [n_col] >= 0 number of entries in the matrix * Ap [0] == 0 * Ap [j] <= Ap [j+1] for all j in the range 0 to n_col. * Ai [0 ... nz-1] must be in the range 0 to n_row-1. * * If any of the above conditions hold, AMD_INVALID is returned. If the * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning, * not an error): * * row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending * order, and/or duplicate entries exist. * * Otherwise, AMD_OK is returned. * * In v1.2 and earlier, this function returned TRUE if the matrix was valid * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or * AMD_OK_BUT_JUMBLED). */ #include "amd_internal.h" GLOBAL Int AMD_valid ( /* inputs, not modified on output: */ Int n_row, /* A is n_row-by-n_col */ Int n_col, const Int Ap [ ], /* column pointers of A, of size n_col+1 */ const Int Ai [ ] /* row indices of A, of size nz = Ap [n_col] */ ) { Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ; if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL) { return (AMD_INVALID) ; } nz = Ap [n_col] ; if (Ap [0] != 0 || nz < 0) { /* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */ AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ; return (AMD_INVALID) ; } for (j = 0 ; j < n_col ; j++) { p1 = Ap [j] ; p2 = Ap [j+1] ; AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ; if (p1 > p2) { /* column pointers must be ascending */ AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ; return (AMD_INVALID) ; } ilast = EMPTY ; for (p = p1 ; p < p2 ; p++) { i = Ai [p] ; AMD_DEBUG3 (("row: "ID"\n", i)) ; if (i < 0 || i >= n_row) { /* row index out of range */ AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i)); return (AMD_INVALID) ; } if (i <= ilast) { /* row index unsorted, or duplicate entry present */ AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i)); result = AMD_OK_BUT_JUMBLED ; } ilast = i ; } } return (result) ; } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_post_tree.c0000644000175000017500000000730711674452555022165 0ustar sonnesonne/* ========================================================================= */ /* === AMD_post_tree ======================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Post-ordering of a supernodal elimination tree. */ #include "amd_internal.h" GLOBAL Int AMD_post_tree ( Int root, /* root of the tree */ Int k, /* start numbering at k */ Int Child [ ], /* input argument of size nn, undefined on * output. Child [i] is the head of a link * list of all nodes that are children of node * i in the tree. */ const Int Sibling [ ], /* input argument of size nn, not modified. * If f is a node in the link list of the * children of node i, then Sibling [f] is the * next child of node i. */ Int Order [ ], /* output order, of size nn. Order [i] = k * if node i is the kth node of the reordered * tree. */ Int Stack [ ] /* workspace of size nn */ #ifndef NDEBUG , Int nn /* nodes are in the range 0..nn-1. */ #endif ) { Int f, head, h, i ; #if 0 /* --------------------------------------------------------------------- */ /* recursive version (Stack [ ] is not used): */ /* --------------------------------------------------------------------- */ /* this is simple, but can caouse stack overflow if nn is large */ i = root ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ; } Order [i] = k++ ; return (k) ; #endif /* --------------------------------------------------------------------- */ /* non-recursive version, using an explicit stack */ /* --------------------------------------------------------------------- */ /* push root on the stack */ head = 0 ; Stack [0] = root ; while (head >= 0) { /* get head of stack */ ASSERT (head < nn) ; i = Stack [head] ; AMD_DEBUG1 (("head of stack "ID" \n", i)) ; ASSERT (i >= 0 && i < nn) ; if (Child [i] != EMPTY) { /* the children of i are not yet ordered */ /* push each child onto the stack in reverse order */ /* so that small ones at the head of the list get popped first */ /* and the biggest one at the end of the list gets popped last */ for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { head++ ; ASSERT (head < nn) ; ASSERT (f >= 0 && f < nn) ; } h = head ; ASSERT (head < nn) ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (h > 0) ; Stack [h--] = f ; AMD_DEBUG1 (("push "ID" on stack\n", f)) ; ASSERT (f >= 0 && f < nn) ; } ASSERT (Stack [h] == i) ; /* delete child list so that i gets ordered next time we see it */ Child [i] = EMPTY ; } else { /* the children of i (if there were any) are already ordered */ /* remove i from the stack and order it. Front i is kth front */ head-- ; AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ; Order [i] = k++ ; ASSERT (k <= nn) ; } #ifndef NDEBUG AMD_DEBUG1 (("\nStack:")) ; for (h = head ; h >= 0 ; h--) { Int j = Stack [h] ; AMD_DEBUG1 ((" "ID, j)) ; ASSERT (j >= 0 && j < nn) ; } AMD_DEBUG1 (("\n\n")) ; ASSERT (head < nn) ; #endif } return (k) ; } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_defaults.c0000644000175000017500000000246511674452555021770 0ustar sonnesonne/* ========================================================================= */ /* === AMD_defaults ======================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable. Sets default control parameters for AMD. See amd.h * for details. */ #include "amd_internal.h" /* ========================================================================= */ /* === AMD defaults ======================================================== */ /* ========================================================================= */ GLOBAL void AMD_defaults ( double Control [ ] ) { Int i ; if (Control != (double *) NULL) { for (i = 0 ; i < AMD_CONTROL ; i++) { Control [i] = 0 ; } Control [AMD_DENSE] = AMD_DEFAULT_DENSE ; Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ; } } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_1.c0000644000175000017500000001323611674452555020317 0ustar sonnesonne/* ========================================================================= */ /* === AMD_1 =============================================================== */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering. * * The n-by-n sparse matrix A can be unsymmetric. It is stored in MATLAB-style * compressed-column form, with sorted row indices in each column, and no * duplicate entries. Diagonal entries may be present, but they are ignored. * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1]. * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A. The * size of the matrix, n, must be greater than or equal to zero. * * This routine must be preceded by a call to AMD_aat, which computes the * number of entries in each row/column in A+A', excluding the diagonal. * Len [j], on input, is the number of entries in row/column j of A+A'. This * routine constructs the matrix A+A' and then calls AMD_2. No error checking * is performed (this was done in AMD_valid). */ #include "amd_internal.h" GLOBAL void AMD_1 ( Int n, /* n > 0 */ const Int Ap [ ], /* input of size n+1, not modified */ const Int Ai [ ], /* input of size nz = Ap [n], not modified */ Int P [ ], /* size n output permutation */ Int Pinv [ ], /* size n output inverse permutation */ Int Len [ ], /* size n input, undefined on output */ Int slen, /* slen >= sum (Len [0..n-1]) + 7n, * ideally slen = 1.2 * sum (Len) + 8n */ Int S [ ], /* size slen workspace */ double Control [ ], /* input array of size AMD_CONTROL */ double Info [ ] /* output array of size AMD_INFO */ ) { Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head, *Elen, *Degree, *s, *W, *Sp, *Tp ; /* --------------------------------------------------------------------- */ /* construct the matrix for AMD_2 */ /* --------------------------------------------------------------------- */ ASSERT (n > 0) ; iwlen = slen - 6*n ; s = S ; Pe = s ; s += n ; Nv = s ; s += n ; Head = s ; s += n ; Elen = s ; s += n ; Degree = s ; s += n ; W = s ; s += n ; Iw = s ; s += iwlen ; ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; /* construct the pointers for A+A' */ Sp = Nv ; /* use Nv and W as workspace for Sp and Tp [ */ Tp = W ; pfree = 0 ; for (j = 0 ; j < n ; j++) { Pe [j] = pfree ; Sp [j] = pfree ; pfree += Len [j] ; } /* Note that this restriction on iwlen is slightly more restrictive than * what is strictly required in AMD_2. AMD_2 can operate with no elbow * room at all, but it will be very slow. For better performance, at * least size-n elbow room is enforced. */ ASSERT (iwlen >= pfree + n) ; #ifndef NDEBUG for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ; #endif for (k = 0 ; k < n ; k++) { AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k)) ; p1 = Ap [k] ; p2 = Ap [k+1] ; /* construct A+A' */ for (p = p1 ; p < p2 ; ) { /* scan the upper triangular part of A */ j = Ai [p] ; ASSERT (j >= 0 && j < n) ; if (j < k) { /* entry A (j,k) in the strictly upper triangular part */ ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ; Iw [Sp [j]++] = k ; Iw [Sp [k]++] = j ; p++ ; } else if (j == k) { /* skip the diagonal */ p++ ; break ; } else /* j > k */ { /* first entry below the diagonal */ break ; } /* scan lower triangular part of A, in column j until reaching * row k. Start where last scan left off. */ ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ; pj2 = Ap [j+1] ; for (pj = Tp [j] ; pj < pj2 ; ) { i = Ai [pj] ; ASSERT (i >= 0 && i < n) ; if (i < k) { /* A (i,j) is only in the lower part, not in upper */ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; Iw [Sp [i]++] = j ; Iw [Sp [j]++] = i ; pj++ ; } else if (i == k) { /* entry A (k,j) in lower part and A (j,k) in upper */ pj++ ; break ; } else /* i > k */ { /* consider this entry later, when k advances to i */ break ; } } Tp [j] = pj ; } Tp [k] = p ; } /* clean up, for remaining mismatched entries */ for (j = 0 ; j < n ; j++) { for (pj = Tp [j] ; pj < Ap [j+1] ; pj++) { i = Ai [pj] ; ASSERT (i >= 0 && i < n) ; /* A (i,j) is only in the lower part, not in upper */ ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ; ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ; Iw [Sp [i]++] = j ; Iw [Sp [j]++] = i ; } } #ifndef NDEBUG for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ; ASSERT (Sp [n-1] == pfree) ; #endif /* Tp and Sp no longer needed ] */ /* --------------------------------------------------------------------- */ /* order the matrix */ /* --------------------------------------------------------------------- */ AMD_2 (n, Pe, Iw, Len, iwlen, pfree, Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ; } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd.f0000644000175000017500000014662111674452555020107 0ustar sonnesonneC----------------------------------------------------------------------- C AMD: approximate minimum degree, with aggressive absorption C----------------------------------------------------------------------- SUBROUTINE AMD $ (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT, $ LAST, HEAD, ELEN, DEGREE, NCMPA, W) INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N), $ DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N), $ ELEN (N), W (N), LEN (N) C Given a representation of the nonzero pattern of a symmetric matrix, C A, (excluding the diagonal) perform an approximate minimum C (UMFPACK/MA38-style) degree ordering to compute a pivot order C such that the introduction of nonzeros (fill-in) in the Cholesky C factors A = LL^T are kept low. At each step, the pivot C selected is the one with the minimum UMFPACK/MA38-style C upper-bound on the external degree. C C Aggresive absorption is used to tighten the bound on the degree. C ********************************************************************** C ***** CAUTION: ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT. ****** C ********************************************************************** C References: C C [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern C multifrontal method for sparse LU factorization", SIAM J. C Matrix Analysis and Applications, vol. 18, no. 1, pp. C 140-158. Discusses UMFPACK / MA38, which first introduced C the approximate minimum degree used by this routine. C C [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An C approximate degree ordering algorithm," SIAM J. Matrix C Analysis and Applications, vol. 17, no. 4, pp. 886-905, C 1996. Discusses AMD, AMDBAR, and MC47B. C C [3] Alan George and Joseph Liu, "The evolution of the minimum C degree ordering algorithm," SIAM Review, vol. 31, no. 1, C pp. 1-19, 1989. We list below the features mentioned in C that paper that this code includes: C C mass elimination: C Yes. MA27 relied on supervariable detection for mass C elimination. C indistinguishable nodes: C Yes (we call these "supervariables"). This was also in C the MA27 code - although we modified the method of C detecting them (the previous hash was the true degree, C which we no longer keep track of). A supervariable is C a set of rows with identical nonzero pattern. All C variables in a supervariable are eliminated together. C Each supervariable has as its numerical name that of C one of its variables (its principal variable). C quotient graph representation: C Yes. We use the term "element" for the cliques formed C during elimination. This was also in the MA27 code. C The algorithm can operate in place, but it will work C more efficiently if given some "elbow room." C element absorption: C Yes. This was also in the MA27 code. C external degree: C Yes. The MA27 code was based on the true degree. C incomplete degree update and multiple elimination: C No. This was not in MA27, either. Our method of C degree update within MC47B/BD is element-based, not C variable-based. It is thus not well-suited for use C with incomplete degree update or multiple elimination. C----------------------------------------------------------------------- C Authors, and Copyright (C) 1995 by: C Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid. C C Acknowledgements: C This work (and the UMFPACK package) was supported by the C National Science Foundation (ASC-9111263 and DMS-9223088). C The UMFPACK/MA38 approximate degree update algorithm, the C unsymmetric analog which forms the basis of MC47B/BD, was C developed while Tim Davis was supported by CERFACS (Toulouse, C France) in a post-doctoral position. C C Date: September, 1995 C----------------------------------------------------------------------- C----------------------------------------------------------------------- C INPUT ARGUMENTS (unaltered): C----------------------------------------------------------------------- C n: The matrix order. C C Restriction: 1 .le. n .lt. (iovflo/2)-2, where iovflo is C the largest positive integer that your computer can represent. C iwlen: The length of iw (1..iwlen). On input, the matrix is C stored in iw (1..pfree-1). However, iw (1..iwlen) should be C slightly larger than what is required to hold the matrix, at C least iwlen .ge. pfree + n is recommended. Otherwise, C excessive compressions will take place. C *** We do not recommend running this algorithm with *** C *** iwlen .lt. pfree + n. *** C *** Better performance will be obtained if *** C *** iwlen .ge. pfree + n *** C *** or better yet *** C *** iwlen .gt. 1.2 * pfree *** C *** (where pfree is its value on input). *** C The algorithm will not run at all if iwlen .lt. pfree-1. C C Restriction: iwlen .ge. pfree-1 C----------------------------------------------------------------------- C INPUT/OUPUT ARGUMENTS: C----------------------------------------------------------------------- C pe: On input, pe (i) is the index in iw of the start of row i, or C zero if row i has no off-diagonal non-zeros. C C During execution, it is used for both supervariables and C elements: C C * Principal supervariable i: index into iw of the C description of supervariable i. A supervariable C represents one or more rows of the matrix C with identical nonzero pattern. C * Non-principal supervariable i: if i has been absorbed C into another supervariable j, then pe (i) = -j. C That is, j has the same pattern as i. C Note that j might later be absorbed into another C supervariable j2, in which case pe (i) is still -j, C and pe (j) = -j2. C * Unabsorbed element e: the index into iw of the description C of element e, if e has not yet been absorbed by a C subsequent element. Element e is created when C the supervariable of the same name is selected as C the pivot. C * Absorbed element e: if element e is absorbed into element C e2, then pe (e) = -e2. This occurs when the pattern of C e (that is, Le) is found to be a subset of the pattern C of e2 (that is, Le2). If element e is "null" (it has C no nonzeros outside its pivot block), then pe (e) = 0. C C On output, pe holds the assembly tree/forest, which implicitly C represents a pivot order with identical fill-in as the actual C order (via a depth-first search of the tree). C C On output: C If nv (i) .gt. 0, then i represents a node in the assembly tree, C and the parent of i is -pe (i), or zero if i is a root. C If nv (i) = 0, then (i,-pe (i)) represents an edge in a C subtree, the root of which is a node in the assembly tree. C pfree: On input the tail end of the array, iw (pfree..iwlen), C is empty, and the matrix is stored in iw (1..pfree-1). C During execution, additional data is placed in iw, and pfree C is modified so that iw (pfree..iwlen) is always the unused part C of iw. On output, pfree is set equal to the size of iw that C would have been needed for no compressions to occur. If C ncmpa is zero, then pfree (on output) is less than or equal to C iwlen, and the space iw (pfree+1 ... iwlen) was not used. C Otherwise, pfree (on output) is greater than iwlen, and all the C memory in iw was used. C----------------------------------------------------------------------- C INPUT/MODIFIED (undefined on output): C----------------------------------------------------------------------- C len: On input, len (i) holds the number of entries in row i of the C matrix, excluding the diagonal. The contents of len (1..n) C are undefined on output. C iw: On input, iw (1..pfree-1) holds the description of each row i C in the matrix. The matrix must be symmetric, and both upper C and lower triangular parts must be present. The diagonal must C not be present. Row i is held as follows: C C len (i): the length of the row i data structure C iw (pe (i) ... pe (i) + len (i) - 1): C the list of column indices for nonzeros C in row i (simple supervariables), excluding C the diagonal. All supervariables start with C one row/column each (supervariable i is just C row i). C if len (i) is zero on input, then pe (i) is ignored C on input. C C Note that the rows need not be in any particular order, C and there may be empty space between the rows. C C During execution, the supervariable i experiences fill-in. C This is represented by placing in i a list of the elements C that cause fill-in in supervariable i: C C len (i): the length of supervariable i C iw (pe (i) ... pe (i) + elen (i) - 1): C the list of elements that contain i. This list C is kept short by removing absorbed elements. C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1): C the list of supervariables in i. This list C is kept short by removing nonprincipal C variables, and any entry j that is also C contained in at least one of the elements C (j in Le) in the list for i (e in row i). C C When supervariable i is selected as pivot, we create an C element e of the same name (e=i): C C len (e): the length of element e C iw (pe (e) ... pe (e) + len (e) - 1): C the list of supervariables in element e. C C An element represents the fill-in that occurs when supervariable C i is selected as pivot (which represents the selection of row i C and all non-principal variables whose principal variable is i). C We use the term Le to denote the set of all supervariables C in element e. Absorbed supervariables and elements are pruned C from these lists when computationally convenient. C C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION. C The contents of iw are undefined on output. C----------------------------------------------------------------------- C OUTPUT (need not be set on input): C----------------------------------------------------------------------- C nv: During execution, abs (nv (i)) is equal to the number of rows C that are represented by the principal supervariable i. If i is C a nonprincipal variable, then nv (i) = 0. Initially, C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a C principal variable in the pattern Lme of the current pivot C element me. On output, nv (e) holds the true degree of element C e at the time it was created (including the diagonal part). C ncmpa: The number of times iw was compressed. If this is C excessive, then the execution took longer than what could have C been. To reduce ncmpa, try increasing iwlen to be 10% or 20% C larger than the value of pfree on input (or at least C iwlen .ge. pfree + n). The fastest performance will be C obtained when ncmpa is returned as zero. If iwlen is set to C the value returned by pfree on *output*, then no compressions C will occur. C elen: See the description of iw above. At the start of execution, C elen (i) is set to zero. During execution, elen (i) is the C number of elements in the list for supervariable i. When e C becomes an element, elen (e) = -nel is set, where nel is the C current step of factorization. elen (i) = 0 is done when i C becomes nonprincipal. C C For variables, elen (i) .ge. 0 holds until just before the C permutation vectors are computed. For elements, C elen (e) .lt. 0 holds. C C On output elen (1..n) holds the inverse permutation (the same C as the 'INVP' argument in Sparspak). That is, if k = elen (i), C then row i is the kth pivot row. Row i of A appears as the C (elen(i))-th row in the permuted matrix, PAP^T. C last: In a degree list, last (i) is the supervariable preceding i, C or zero if i is the head of the list. In a hash bucket, C last (i) is the hash key for i. last (head (hash)) is also C used as the head of a hash bucket if head (hash) contains a C degree list (see head, below). C C On output, last (1..n) holds the permutation (the same as the C 'PERM' argument in Sparspak). That is, if i = last (k), then C row i is the kth pivot row. Row last (k) of A is the k-th row C in the permuted matrix, PAP^T. C----------------------------------------------------------------------- C LOCAL (not input or output - used only during execution): C----------------------------------------------------------------------- C degree: If i is a supervariable, then degree (i) holds the C current approximation of the external degree of row i (an upper C bound). The external degree is the number of nonzeros in row i, C minus abs (nv (i)) (the diagonal part). The bound is equal to C the external degree if elen (i) is less than or equal to two. C C We also use the term "external degree" for elements e to refer C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|, C which is the degree of the off-diagonal part of the element e C (not including the diagonal part). C head: head is used for degree lists. head (deg) is the first C supervariable in a degree list (all supervariables i in a C degree list deg have the same approximate degree, namely, C deg = degree (i)). If the list deg is empty then C head (deg) = 0. C C During supervariable detection head (hash) also serves as a C pointer to a hash bucket. C If head (hash) .gt. 0, there is a degree list of degree hash. C The hash bucket head pointer is last (head (hash)). C If head (hash) = 0, then the degree list and hash bucket are C both empty. C If head (hash) .lt. 0, then the degree list is empty, and C -head (hash) is the head of the hash bucket. C After supervariable detection is complete, all hash buckets C are empty, and the (last (head (hash)) = 0) condition is C restored for the non-empty degree lists. C next: next (i) is the supervariable following i in a link list, or C zero if i is the last in the list. Used for two kinds of C lists: degree lists and hash buckets (a supervariable can be C in only one kind of list at a time). C w: The flag array w determines the status of elements and C variables, and the external degree of elements. C C for elements: C if w (e) = 0, then the element e is absorbed C if w (e) .ge. wflg, then w (e) - wflg is the size of C the set |Le \ Lme|, in terms of nonzeros (the C sum of abs (nv (i)) for each principal variable i that C is both in the pattern of element e and NOT in the C pattern of the current pivot element, me). C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has C not yet been seen in the scan of the element lists in C the computation of |Le\Lme| in loop 150 below. C C for variables: C during supervariable detection, if w (j) .ne. wflg then j is C not in the pattern of variable i C C The w array is initialized by setting w (i) = 1 for all i, C and by setting wflg = 2. It is reinitialized if wflg becomes C too large (to ensure that wflg+n does not cause integer C overflow). C----------------------------------------------------------------------- C LOCAL INTEGERS: C----------------------------------------------------------------------- INTEGER DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, HASH, HMOD, I, $ ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3, $ LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM, $ NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X C deg: the degree of a variable or element C degme: size, |Lme|, of the current element, me (= degree (me)) C dext: external degree, |Le \ Lme|, of some element e C dmax: largest |Le| seen so far C e: an element C elenme: the length, elen (me), of element list of pivotal var. C eln: the length, elen (...), of an element list C hash: the computed value of the hash function C hmod: the hash function is computed modulo hmod = max (1,n-1) C i: a supervariable C ilast: the entry in a link list preceding i C inext: the entry in a link list following i C j: a supervariable C jlast: the entry in a link list preceding j C jnext: the entry in a link list, or path, following j C k: the pivot order of an element or variable C knt1: loop counter used during element construction C knt2: loop counter used during element construction C knt3: loop counter used during compression C lenj: len (j) C ln: length of a supervariable list C maxmem: amount of memory needed for no compressions C me: current supervariable being eliminated, and the C current element created by eliminating that C supervariable C mem: memory in use assuming no compressions have occurred C mindeg: current minimum degree C nel: number of pivots selected so far C newmem: amount of new memory needed for current pivot element C nleft: n - nel, the number of nonpivotal rows/columns remaining C nvi: the number of variables in a supervariable i (= nv (i)) C nvj: the number of variables in a supervariable j (= nv (j)) C nvpiv: number of pivots in current element C slenme: number of variables in variable list of pivotal variable C we: w (e) C wflg: used for flagging the w array. See description of iw. C wnvi: wflg - nv (i) C x: either a supervariable or an element C----------------------------------------------------------------------- C LOCAL POINTERS: C----------------------------------------------------------------------- INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC C Any parameter (pe (...) or pfree) or local variable C starting with "p" (for Pointer) is an index into iw, C and all indices into iw use variables starting with C "p." The only exception to this rule is the iwlen C input argument. C p: pointer into lots of things C p1: pe (i) for some variable i (start of element list) C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list) C p3: index of first supervariable in clean list C pdst: destination pointer, for compression C pend: end of memory to compress C pj: pointer into an element or variable C pme: pointer into the current element (pme1...pme2) C pme1: the current element, me, is stored in iw (pme1...pme2) C pme2: the end of the current element C pn: pointer into a "clean" variable, also used to compress C psrc: source pointer, for compression C----------------------------------------------------------------------- C FUNCTIONS CALLED: C----------------------------------------------------------------------- INTRINSIC MAX, MIN, MOD C======================================================================= C INITIALIZATIONS C======================================================================= WFLG = 2 MINDEG = 1 NCMPA = 0 NEL = 0 HMOD = MAX (1, N-1) DMAX = 0 MEM = PFREE - 1 MAXMEM = MEM ME = 0 DO 10 I = 1, N LAST (I) = 0 HEAD (I) = 0 NV (I) = 1 W (I) = 1 ELEN (I) = 0 DEGREE (I) = LEN (I) 10 CONTINUE C ---------------------------------------------------------------- C initialize degree lists and eliminate rows with no off-diag. nz. C ---------------------------------------------------------------- DO 20 I = 1, N DEG = DEGREE (I) IF (DEG .GT. 0) THEN C ---------------------------------------------------------- C place i in the degree list corresponding to its degree C ---------------------------------------------------------- INEXT = HEAD (DEG) IF (INEXT .NE. 0) LAST (INEXT) = I NEXT (I) = INEXT HEAD (DEG) = I ELSE C ---------------------------------------------------------- C we have a variable that can be eliminated at once because C there is no off-diagonal non-zero in its row. C ---------------------------------------------------------- NEL = NEL + 1 ELEN (I) = -NEL PE (I) = 0 W (I) = 0 ENDIF 20 CONTINUE C======================================================================= C WHILE (selecting pivots) DO C======================================================================= 30 CONTINUE IF (NEL .LT. N) THEN C======================================================================= C GET PIVOT OF MINIMUM DEGREE C======================================================================= C ------------------------------------------------------------- C find next supervariable for elimination C ------------------------------------------------------------- DO 40 DEG = MINDEG, N ME = HEAD (DEG) IF (ME .GT. 0) GOTO 50 40 CONTINUE 50 CONTINUE MINDEG = DEG C ------------------------------------------------------------- C remove chosen variable from link list C ------------------------------------------------------------- INEXT = NEXT (ME) IF (INEXT .NE. 0) LAST (INEXT) = 0 HEAD (DEG) = INEXT C ------------------------------------------------------------- C me represents the elimination of pivots nel+1 to nel+nv(me). C place me itself as the first in this set. It will be moved C to the nel+nv(me) position when the permutation vectors are C computed. C ------------------------------------------------------------- ELENME = ELEN (ME) ELEN (ME) = - (NEL + 1) NVPIV = NV (ME) NEL = NEL + NVPIV C======================================================================= C CONSTRUCT NEW ELEMENT C======================================================================= C ------------------------------------------------------------- C At this point, me is the pivotal supervariable. It will be C converted into the current element. Scan list of the C pivotal supervariable, me, setting tree pointers and C constructing new list of supervariables for the new element, C me. p is a pointer to the current position in the old list. C ------------------------------------------------------------- C flag the variable "me" as being in Lme by negating nv (me) NV (ME) = -NVPIV DEGME = 0 IF (ELENME .EQ. 0) THEN C ---------------------------------------------------------- C construct the new element in place C ---------------------------------------------------------- PME1 = PE (ME) PME2 = PME1 - 1 DO 60 P = PME1, PME1 + LEN (ME) - 1 I = IW (P) NVI = NV (I) IF (NVI .GT. 0) THEN C ---------------------------------------------------- C i is a principal variable not yet placed in Lme. C store i in new list C ---------------------------------------------------- DEGME = DEGME + NVI C flag i as being in Lme by negating nv (i) NV (I) = -NVI PME2 = PME2 + 1 IW (PME2) = I C ---------------------------------------------------- C remove variable i from degree list. C ---------------------------------------------------- ILAST = LAST (I) INEXT = NEXT (I) IF (INEXT .NE. 0) LAST (INEXT) = ILAST IF (ILAST .NE. 0) THEN NEXT (ILAST) = INEXT ELSE C i is at the head of the degree list HEAD (DEGREE (I)) = INEXT ENDIF ENDIF 60 CONTINUE C this element takes no new memory in iw: NEWMEM = 0 ELSE C ---------------------------------------------------------- C construct the new element in empty space, iw (pfree ...) C ---------------------------------------------------------- P = PE (ME) PME1 = PFREE SLENME = LEN (ME) - ELENME DO 120 KNT1 = 1, ELENME + 1 IF (KNT1 .GT. ELENME) THEN C search the supervariables in me. E = ME PJ = P LN = SLENME ELSE C search the elements in me. E = IW (P) P = P + 1 PJ = PE (E) LN = LEN (E) ENDIF C ------------------------------------------------------- C search for different supervariables and add them to the C new list, compressing when necessary. this loop is C executed once for each element in the list and once for C all the supervariables in the list. C ------------------------------------------------------- DO 110 KNT2 = 1, LN I = IW (PJ) PJ = PJ + 1 NVI = NV (I) IF (NVI .GT. 0) THEN C ------------------------------------------------- C compress iw, if necessary C ------------------------------------------------- IF (PFREE .GT. IWLEN) THEN C prepare for compressing iw by adjusting C pointers and lengths so that the lists being C searched in the inner and outer loops contain C only the remaining entries. PE (ME) = P LEN (ME) = LEN (ME) - KNT1 IF (LEN (ME) .EQ. 0) THEN C nothing left of supervariable me PE (ME) = 0 ENDIF PE (E) = PJ LEN (E) = LN - KNT2 IF (LEN (E) .EQ. 0) THEN C nothing left of element e PE (E) = 0 ENDIF NCMPA = NCMPA + 1 C store first item in pe C set first entry to -item DO 70 J = 1, N PN = PE (J) IF (PN .GT. 0) THEN PE (J) = IW (PN) IW (PN) = -J ENDIF 70 CONTINUE C psrc/pdst point to source/destination PDST = 1 PSRC = 1 PEND = PME1 - 1 C while loop: 80 CONTINUE IF (PSRC .LE. PEND) THEN C search for next negative entry J = -IW (PSRC) PSRC = PSRC + 1 IF (J .GT. 0) THEN IW (PDST) = PE (J) PE (J) = PDST PDST = PDST + 1 C copy from source to destination LENJ = LEN (J) DO 90 KNT3 = 0, LENJ - 2 IW (PDST + KNT3) = IW (PSRC + KNT3) 90 CONTINUE PDST = PDST + LENJ - 1 PSRC = PSRC + LENJ - 1 ENDIF GOTO 80 ENDIF C move the new partially-constructed element P1 = PDST DO 100 PSRC = PME1, PFREE - 1 IW (PDST) = IW (PSRC) PDST = PDST + 1 100 CONTINUE PME1 = P1 PFREE = PDST PJ = PE (E) P = PE (ME) ENDIF C ------------------------------------------------- C i is a principal variable not yet placed in Lme C store i in new list C ------------------------------------------------- DEGME = DEGME + NVI C flag i as being in Lme by negating nv (i) NV (I) = -NVI IW (PFREE) = I PFREE = PFREE + 1 C ------------------------------------------------- C remove variable i from degree link list C ------------------------------------------------- ILAST = LAST (I) INEXT = NEXT (I) IF (INEXT .NE. 0) LAST (INEXT) = ILAST IF (ILAST .NE. 0) THEN NEXT (ILAST) = INEXT ELSE C i is at the head of the degree list HEAD (DEGREE (I)) = INEXT ENDIF ENDIF 110 CONTINUE IF (E .NE. ME) THEN C set tree pointer and flag to indicate element e is C absorbed into new element me (the parent of e is me) PE (E) = -ME W (E) = 0 ENDIF 120 CONTINUE PME2 = PFREE - 1 C this element takes newmem new memory in iw (possibly zero) NEWMEM = PFREE - PME1 MEM = MEM + NEWMEM MAXMEM = MAX (MAXMEM, MEM) ENDIF C ------------------------------------------------------------- C me has now been converted into an element in iw (pme1..pme2) C ------------------------------------------------------------- C degme holds the external degree of new element DEGREE (ME) = DEGME PE (ME) = PME1 LEN (ME) = PME2 - PME1 + 1 C ------------------------------------------------------------- C make sure that wflg is not too large. With the current C value of wflg, wflg+n must not cause integer overflow C ------------------------------------------------------------- IF (WFLG + N .LE. WFLG) THEN DO 130 X = 1, N IF (W (X) .NE. 0) W (X) = 1 130 CONTINUE WFLG = 2 ENDIF C======================================================================= C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS C======================================================================= C ------------------------------------------------------------- C Scan 1: compute the external degrees of previous elements C with respect to the current element. That is: C (w (e) - wflg) = |Le \ Lme| C for each element e that appears in any supervariable in Lme. C The notation Le refers to the pattern (list of C supervariables) of a previous element e, where e is not yet C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))). C The notation Lme refers to the pattern of the current element C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes C zero, then the element e will be absorbed in scan 2. C ------------------------------------------------------------- DO 150 PME = PME1, PME2 I = IW (PME) ELN = ELEN (I) IF (ELN .GT. 0) THEN C note that nv (i) has been negated to denote i in Lme: NVI = -NV (I) WNVI = WFLG - NVI DO 140 P = PE (I), PE (I) + ELN - 1 E = IW (P) WE = W (E) IF (WE .GE. WFLG) THEN C unabsorbed element e has been seen in this loop WE = WE - NVI ELSE IF (WE .NE. 0) THEN C e is an unabsorbed element C this is the first we have seen e in all of Scan 1 WE = DEGREE (E) + WNVI ENDIF W (E) = WE 140 CONTINUE ENDIF 150 CONTINUE C======================================================================= C DEGREE UPDATE AND ELEMENT ABSORPTION C======================================================================= C ------------------------------------------------------------- C Scan 2: for each i in Lme, sum up the degree of Lme (which C is degme), plus the sum of the external degrees of each Le C for the elements e appearing within i, plus the C supervariables in i. Place i in hash list. C ------------------------------------------------------------- DO 180 PME = PME1, PME2 I = IW (PME) P1 = PE (I) P2 = P1 + ELEN (I) - 1 PN = P1 HASH = 0 DEG = 0 C ---------------------------------------------------------- C scan the element list associated with supervariable i C ---------------------------------------------------------- DO 160 P = P1, P2 E = IW (P) C dext = | Le \ Lme | DEXT = W (E) - WFLG IF (DEXT .GT. 0) THEN DEG = DEG + DEXT IW (PN) = E PN = PN + 1 HASH = HASH + E ELSE IF (DEXT .EQ. 0) THEN C aggressive absorption: e is not adjacent to me, but C the |Le \ Lme| is 0, so absorb it into me PE (E) = -ME W (E) = 0 ELSE C element e has already been absorbed, due to C regular absorption, in do loop 120 above. Ignore it. CONTINUE ENDIF 160 CONTINUE C count the number of elements in i (including me): ELEN (I) = PN - P1 + 1 C ---------------------------------------------------------- C scan the supervariables in the list associated with i C ---------------------------------------------------------- P3 = PN DO 170 P = P2 + 1, P1 + LEN (I) - 1 J = IW (P) NVJ = NV (J) IF (NVJ .GT. 0) THEN C j is unabsorbed, and not in Lme. C add to degree and add to new list DEG = DEG + NVJ IW (PN) = J PN = PN + 1 HASH = HASH + J ENDIF 170 CONTINUE C ---------------------------------------------------------- C update the degree and check for mass elimination C ---------------------------------------------------------- IF (DEG .EQ. 0) THEN C ------------------------------------------------------- C mass elimination C ------------------------------------------------------- C There is nothing left of this node except for an C edge to the current pivot element. elen (i) is 1, C and there are no variables adjacent to node i. C Absorb i into the current pivot element, me. PE (I) = -ME NVI = -NV (I) DEGME = DEGME - NVI NVPIV = NVPIV + NVI NEL = NEL + NVI NV (I) = 0 ELEN (I) = 0 ELSE C ------------------------------------------------------- C update the upper-bound degree of i C ------------------------------------------------------- C the following degree does not yet include the size C of the current element, which is added later: DEGREE (I) = MIN (DEGREE (I), DEG) C ------------------------------------------------------- C add me to the list for i C ------------------------------------------------------- C move first supervariable to end of list IW (PN) = IW (P3) C move first element to end of element part of list IW (P3) = IW (P1) C add new element to front of list. IW (P1) = ME C store the new length of the list in len (i) LEN (I) = PN - P1 + 1 C ------------------------------------------------------- C place in hash bucket. Save hash key of i in last (i). C ------------------------------------------------------- HASH = MOD (HASH, HMOD) + 1 J = HEAD (HASH) IF (J .LE. 0) THEN C the degree list is empty, hash head is -j NEXT (I) = -J HEAD (HASH) = -I ELSE C degree list is not empty C use last (head (hash)) as hash head NEXT (I) = LAST (J) LAST (J) = I ENDIF LAST (I) = HASH ENDIF 180 CONTINUE DEGREE (ME) = DEGME C ------------------------------------------------------------- C Clear the counter array, w (...), by incrementing wflg. C ------------------------------------------------------------- DMAX = MAX (DMAX, DEGME) WFLG = WFLG + DMAX C make sure that wflg+n does not cause integer overflow IF (WFLG + N .LE. WFLG) THEN DO 190 X = 1, N IF (W (X) .NE. 0) W (X) = 1 190 CONTINUE WFLG = 2 ENDIF C at this point, w (1..n) .lt. wflg holds C======================================================================= C SUPERVARIABLE DETECTION C======================================================================= DO 250 PME = PME1, PME2 I = IW (PME) IF (NV (I) .LT. 0) THEN C i is a principal variable in Lme C ------------------------------------------------------- C examine all hash buckets with 2 or more variables. We C do this by examing all unique hash keys for super- C variables in the pattern Lme of the current element, me C ------------------------------------------------------- HASH = LAST (I) C let i = head of hash bucket, and empty the hash bucket J = HEAD (HASH) IF (J .EQ. 0) GOTO 250 IF (J .LT. 0) THEN C degree list is empty I = -J HEAD (HASH) = 0 ELSE C degree list is not empty, restore last () of head I = LAST (J) LAST (J) = 0 ENDIF IF (I .EQ. 0) GOTO 250 C while loop: 200 CONTINUE IF (NEXT (I) .NE. 0) THEN C ---------------------------------------------------- C this bucket has one or more variables following i. C scan all of them to see if i can absorb any entries C that follow i in hash bucket. Scatter i into w. C ---------------------------------------------------- LN = LEN (I) ELN = ELEN (I) C do not flag the first element in the list (me) DO 210 P = PE (I) + 1, PE (I) + LN - 1 W (IW (P)) = WFLG 210 CONTINUE C ---------------------------------------------------- C scan every other entry j following i in bucket C ---------------------------------------------------- JLAST = I J = NEXT (I) C while loop: 220 CONTINUE IF (J .NE. 0) THEN C ------------------------------------------------- C check if j and i have identical nonzero pattern C ------------------------------------------------- IF (LEN (J) .NE. LN) THEN C i and j do not have same size data structure GOTO 240 ENDIF IF (ELEN (J) .NE. ELN) THEN C i and j do not have same number of adjacent el GOTO 240 ENDIF C do not flag the first element in the list (me) DO 230 P = PE (J) + 1, PE (J) + LN - 1 IF (W (IW (P)) .NE. WFLG) THEN C an entry (iw(p)) is in j but not in i GOTO 240 ENDIF 230 CONTINUE C ------------------------------------------------- C found it! j can be absorbed into i C ------------------------------------------------- PE (J) = -I C both nv (i) and nv (j) are negated since they C are in Lme, and the absolute values of each C are the number of variables in i and j: NV (I) = NV (I) + NV (J) NV (J) = 0 ELEN (J) = 0 C delete j from hash bucket J = NEXT (J) NEXT (JLAST) = J GOTO 220 C ------------------------------------------------- 240 CONTINUE C j cannot be absorbed into i C ------------------------------------------------- JLAST = J J = NEXT (J) GOTO 220 ENDIF C ---------------------------------------------------- C no more variables can be absorbed into i C go to next i in bucket and clear flag array C ---------------------------------------------------- WFLG = WFLG + 1 I = NEXT (I) IF (I .NE. 0) GOTO 200 ENDIF ENDIF 250 CONTINUE C======================================================================= C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT C======================================================================= P = PME1 NLEFT = N - NEL DO 260 PME = PME1, PME2 I = IW (PME) NVI = -NV (I) IF (NVI .GT. 0) THEN C i is a principal variable in Lme C restore nv (i) to signify that i is principal NV (I) = NVI C ------------------------------------------------------- C compute the external degree (add size of current elem) C ------------------------------------------------------- DEG = MIN (DEGREE (I) + DEGME - NVI, NLEFT - NVI) C ------------------------------------------------------- C place the supervariable at the head of the degree list C ------------------------------------------------------- INEXT = HEAD (DEG) IF (INEXT .NE. 0) LAST (INEXT) = I NEXT (I) = INEXT LAST (I) = 0 HEAD (DEG) = I C ------------------------------------------------------- C save the new degree, and find the minimum degree C ------------------------------------------------------- MINDEG = MIN (MINDEG, DEG) DEGREE (I) = DEG C ------------------------------------------------------- C place the supervariable in the element pattern C ------------------------------------------------------- IW (P) = I P = P + 1 ENDIF 260 CONTINUE C======================================================================= C FINALIZE THE NEW ELEMENT C======================================================================= NV (ME) = NVPIV + DEGME C nv (me) is now the degree of pivot (including diagonal part) C save the length of the list for the new element me LEN (ME) = P - PME1 IF (LEN (ME) .EQ. 0) THEN C there is nothing left of the current pivot element PE (ME) = 0 W (ME) = 0 ENDIF IF (NEWMEM .NE. 0) THEN C element was not constructed in place: deallocate part C of it (final size is less than or equal to newmem, C since newly nonprincipal variables have been removed). PFREE = P MEM = MEM - NEWMEM + LEN (ME) ENDIF C======================================================================= C END WHILE (selecting pivots) GOTO 30 ENDIF C======================================================================= C======================================================================= C COMPUTE THE PERMUTATION VECTORS C======================================================================= C ---------------------------------------------------------------- C The time taken by the following code is O(n). At this C point, elen (e) = -k has been done for all elements e, C and elen (i) = 0 has been done for all nonprincipal C variables i. At this point, there are no principal C supervariables left, and all elements are absorbed. C ---------------------------------------------------------------- C ---------------------------------------------------------------- C compute the ordering of unordered nonprincipal variables C ---------------------------------------------------------------- DO 290 I = 1, N IF (ELEN (I) .EQ. 0) THEN C ---------------------------------------------------------- C i is an un-ordered row. Traverse the tree from i until C reaching an element, e. The element, e, was the C principal supervariable of i and all nodes in the path C from i to when e was selected as pivot. C ---------------------------------------------------------- J = -PE (I) C while (j is a variable) do: 270 CONTINUE IF (ELEN (J) .GE. 0) THEN J = -PE (J) GOTO 270 ENDIF E = J C ---------------------------------------------------------- C get the current pivot ordering of e C ---------------------------------------------------------- K = -ELEN (E) C ---------------------------------------------------------- C traverse the path again from i to e, and compress the C path (all nodes point to e). Path compression allows C this code to compute in O(n) time. Order the unordered C nodes in the path, and place the element e at the end. C ---------------------------------------------------------- J = I C while (j is a variable) do: 280 CONTINUE IF (ELEN (J) .GE. 0) THEN JNEXT = -PE (J) PE (J) = -E IF (ELEN (J) .EQ. 0) THEN C j is an unordered row ELEN (J) = K K = K + 1 ENDIF J = JNEXT GOTO 280 ENDIF C leave elen (e) negative, so we know it is an element ELEN (E) = -K ENDIF 290 CONTINUE C ---------------------------------------------------------------- C reset the inverse permutation (elen (1..n)) to be positive, C and compute the permutation (last (1..n)). C ---------------------------------------------------------------- DO 300 I = 1, N K = ABS (ELEN (I)) LAST (K) = I ELEN (I) = K 300 CONTINUE C======================================================================= C RETURN THE MEMORY USAGE IN IW C======================================================================= C If maxmem is less than or equal to iwlen, then no compressions C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise C compressions did occur, and iwlen would have had to have been C greater than or equal to maxmem for no compressions to occur. C Return the value of maxmem in the pfree argument. PFREE = MAXMEM RETURN END cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_info.c0000644000175000017500000001023511674452555021106 0ustar sonnesonne/* ========================================================================= */ /* === AMD_info ============================================================ */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* User-callable. Prints the output statistics for AMD. See amd.h * for details. If the Info array is not present, nothing is printed. */ #include "amd_internal.h" #define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }} GLOBAL void AMD_info ( double Info [ ] ) { double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ; PRINTF (("\nAMD version %d.%d.%d, %s, results:\n", AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ; if (!Info) { return ; } n = Info [AMD_N] ; ndiv = Info [AMD_NDIV] ; nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ; nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ; lnz = Info [AMD_LNZ] ; lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ; /* AMD return status */ PRINTF ((" status: ")) ; if (Info [AMD_STATUS] == AMD_OK) { PRINTF (("OK\n")) ; } else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY) { PRINTF (("out of memory\n")) ; } else if (Info [AMD_STATUS] == AMD_INVALID) { PRINTF (("invalid matrix\n")) ; } else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED) { PRINTF (("OK, but jumbled\n")) ; } else { PRINTF (("unknown\n")) ; } /* statistics about the input matrix */ PRI (" n, dimension of A: %.20g\n", n); PRI (" nz, number of nonzeros in A: %.20g\n", Info [AMD_NZ]) ; PRI (" symmetry of A: %.4f\n", Info [AMD_SYMMETRY]) ; PRI (" number of nonzeros on diagonal: %.20g\n", Info [AMD_NZDIAG]) ; PRI (" nonzeros in pattern of A+A' (excl. diagonal): %.20g\n", Info [AMD_NZ_A_PLUS_AT]) ; PRI (" # dense rows/columns of A+A': %.20g\n", Info [AMD_NDENSE]) ; /* statistics about AMD's behavior */ PRI (" memory used, in bytes: %.20g\n", Info [AMD_MEMORY]) ; PRI (" # of memory compactions: %.20g\n", Info [AMD_NCMPA]) ; /* statistics about the ordering quality */ PRINTF (("\n" " The following approximate statistics are for a subsequent\n" " factorization of A(P,P) + A(P,P)'. They are slight upper\n" " bounds if there are no dense rows/columns in A+A', and become\n" " looser if dense rows/columns exist.\n\n")) ; PRI (" nonzeros in L (excluding diagonal): %.20g\n", lnz) ; PRI (" nonzeros in L (including diagonal): %.20g\n", lnzd) ; PRI (" # divide operations for LDL' or LU: %.20g\n", ndiv) ; PRI (" # multiply-subtract operations for LDL': %.20g\n", nmultsubs_ldl) ; PRI (" # multiply-subtract operations for LU: %.20g\n", nmultsubs_lu) ; PRI (" max nz. in any column of L (incl. diagonal): %.20g\n", Info [AMD_DMAX]) ; /* total flop counts for various factorizations */ if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0) { PRINTF (("\n" " chol flop count for real A, sqrt counted as 1 flop: %.20g\n" " LDL' flop count for real A: %.20g\n" " LDL' flop count for complex A: %.20g\n" " LU flop count for real A (with no pivoting): %.20g\n" " LU flop count for complex A (with no pivoting): %.20g\n\n", n + ndiv + 2*nmultsubs_ldl, ndiv + 2*nmultsubs_ldl, 9*ndiv + 8*nmultsubs_ldl, ndiv + 2*nmultsubs_lu, 9*ndiv + 8*nmultsubs_lu)) ; } } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Source/amd_postorder.c0000644000175000017500000001272511674452555022202 0ustar sonnesonne/* ========================================================================= */ /* === AMD_postorder ======================================================= */ /* ========================================================================= */ /* ------------------------------------------------------------------------- */ /* AMD, Copyright (c) Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README.txt for License. */ /* email: davis at cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/amd */ /* ------------------------------------------------------------------------- */ /* Perform a postordering (via depth-first search) of an assembly tree. */ #include "amd_internal.h" GLOBAL void AMD_postorder ( /* inputs, not modified on output: */ Int nn, /* nodes are in the range 0..nn-1 */ Int Parent [ ], /* Parent [j] is the parent of j, or EMPTY if root */ Int Nv [ ], /* Nv [j] > 0 number of pivots represented by node j, * or zero if j is not a node. */ Int Fsize [ ], /* Fsize [j]: size of node j */ /* output, not defined on input: */ Int Order [ ], /* output post-order */ /* workspaces of size nn: */ Int Child [ ], Int Sibling [ ], Int Stack [ ] ) { Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ; for (j = 0 ; j < nn ; j++) { Child [j] = EMPTY ; Sibling [j] = EMPTY ; } /* --------------------------------------------------------------------- */ /* place the children in link lists - bigger elements tend to be last */ /* --------------------------------------------------------------------- */ for (j = nn-1 ; j >= 0 ; j--) { if (Nv [j] > 0) { /* this is an element */ parent = Parent [j] ; if (parent != EMPTY) { /* place the element in link list of the children its parent */ /* bigger elements will tend to be at the end of the list */ Sibling [j] = Child [parent] ; Child [parent] = j ; } } } #ifndef NDEBUG { Int nels, ff, nchild ; AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n")); nels = 0 ; for (j = 0 ; j < nn ; j++) { if (Nv [j] > 0) { AMD_DEBUG1 (( ""ID" : nels "ID" npiv "ID" size "ID " parent "ID" maxfr "ID"\n", j, nels, Nv [j], Fsize [j], Parent [j], Fsize [j])) ; /* this is an element */ /* dump the link list of children */ nchild = 0 ; AMD_DEBUG1 ((" Children: ")) ; for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff]) { AMD_DEBUG1 ((ID" ", ff)) ; ASSERT (Parent [ff] == j) ; nchild++ ; ASSERT (nchild < nn) ; } AMD_DEBUG1 (("\n")) ; parent = Parent [j] ; if (parent != EMPTY) { ASSERT (Nv [parent] > 0) ; } nels++ ; } } } AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n" "the biggest child last in each list:\n")) ; #endif /* --------------------------------------------------------------------- */ /* place the largest child last in the list of children for each node */ /* --------------------------------------------------------------------- */ for (i = 0 ; i < nn ; i++) { if (Nv [i] > 0 && Child [i] != EMPTY) { #ifndef NDEBUG Int nchild ; AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ; nchild = 0 ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (f >= 0 && f < nn) ; AMD_DEBUG1 ((" f: "ID" size: "ID"\n", f, Fsize [f])) ; nchild++ ; ASSERT (nchild <= nn) ; } #endif /* find the biggest element in the child list */ fprev = EMPTY ; maxfrsize = EMPTY ; bigfprev = EMPTY ; bigf = EMPTY ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (f >= 0 && f < nn) ; frsize = Fsize [f] ; if (frsize >= maxfrsize) { /* this is the biggest seen so far */ maxfrsize = frsize ; bigfprev = fprev ; bigf = f ; } fprev = f ; } ASSERT (bigf != EMPTY) ; fnext = Sibling [bigf] ; AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID " fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ; if (fnext != EMPTY) { /* if fnext is EMPTY then bigf is already at the end of list */ if (bigfprev == EMPTY) { /* delete bigf from the element of the list */ Child [i] = fnext ; } else { /* delete bigf from the middle of the list */ Sibling [bigfprev] = fnext ; } /* put bigf at the end of the list */ Sibling [bigf] = EMPTY ; ASSERT (Child [i] != EMPTY) ; ASSERT (fprev != bigf) ; ASSERT (fprev != EMPTY) ; Sibling [fprev] = bigf ; } #ifndef NDEBUG AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ; for (f = Child [i] ; f != EMPTY ; f = Sibling [f]) { ASSERT (f >= 0 && f < nn) ; AMD_DEBUG1 ((" "ID" "ID"\n", f, Fsize [f])) ; ASSERT (Nv [f] > 0) ; nchild-- ; } ASSERT (nchild == 0) ; #endif } } /* --------------------------------------------------------------------- */ /* postorder the assembly tree */ /* --------------------------------------------------------------------- */ for (i = 0 ; i < nn ; i++) { Order [i] = EMPTY ; } k = 0 ; for (i = 0 ; i < nn ; i++) { if (Parent [i] == EMPTY && Nv [i] > 0) { AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ; k = AMD_post_tree (i, k, Child, Sibling, Order, Stack #ifndef NDEBUG , nn #endif ) ; } } } cvxopt-1.1.4/src/C/SuiteSparse/AMD/Lib/0000755000175000017500000000000011674452555016433 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/AMD/Lib/libamd.def0000644000175000017500000000021011674452555020334 0ustar sonnesonneLIBRARY libamd.dll EXPORTS amd_order amd_defaults amd_control amd_info amd_2 amd_l_order amd_l_defaults amd_l_control amd_l_info amd_l2 cvxopt-1.1.4/src/C/SuiteSparse/AMD/Lib/Makefile0000644000175000017500000000611111674452555020072 0ustar sonnesonne#------------------------------------------------------------------------------- # AMD Makefile for compiling on Unix systems (for original Make ONLY) #------------------------------------------------------------------------------- # This is a very ugly Makefile, and is only provided for those who do not # have GNU make. Note that it is not used if you have GNU make. It ignores # dependency checking and just compiles everything. default: everything include ../../UFconfig/UFconfig.mk C = $(CC) $(CFLAGS) $(CONFIG) -I../Include -I../../UFconfig everything: $(C) -DDINT -c ../Source/amd_aat.c -o amd_i_aat.o $(C) -DDINT -c ../Source/amd_1.c -o amd_i_1.o $(C) -DDINT -c ../Source/amd_2.c -o amd_i_2.o $(C) -DDINT -c ../Source/amd_dump.c -o amd_i_dump.o $(C) -DDINT -c ../Source/amd_postorder.c -o amd_i_postorder.o $(C) -DDINT -c ../Source/amd_post_tree.c -o amd_i_post_tree.o $(C) -DDINT -c ../Source/amd_defaults.c -o amd_i_defaults.o $(C) -DDINT -c ../Source/amd_order.c -o amd_i_order.o $(C) -DDINT -c ../Source/amd_control.c -o amd_i_control.o $(C) -DDINT -c ../Source/amd_info.c -o amd_i_info.o $(C) -DDINT -c ../Source/amd_valid.c -o amd_i_valid.o $(C) -DDINT -c ../Source/amd_preprocess.c -o amd_i_preprocess.o $(C) -DDLONG -c ../Source/amd_aat.c -o amd_l_aat.o $(C) -DDLONG -c ../Source/amd_1.c -o ../Source/amd_l_1.o $(C) -DDLONG -c ../Source/amd_2.c -o amd_l_2.o $(C) -DDLONG -c ../Source/amd_dump.c -o amd_l_dump.o $(C) -DDLONG -c ../Source/amd_postorder.c -o amd_l_postorder.o $(C) -DDLONG -c ../Source/amd_post_tree.c -o amd_l_post_tree.o $(C) -DDLONG -c ../Source/amd_defaults.c -o amd_l_defaults.o $(C) -DDLONG -c ../Source/amd_order.c -o amd_l_order.o $(C) -DDLONG -c ../Source/amd_control.c -o amd_l_control.o $(C) -DDLONG -c ../Source/amd_info.c -o amd_l_info.o $(C) -DDLONG -c ../Source/amd_valid.c -o amd_l_valid.o $(C) -DDLONG -c ../Source/amd_preprocess.c -o amd_l_preprocess.o $(C) -c ../Source/amd_global.c $(AR) ../Lib/libamd.a amd_i_aat.o amd_i_1.o amd_i_2.o amd_i_dump.o \ amd_i_postorder.o amd_i_post_tree.o amd_i_defaults.o amd_i_order.o \ amd_i_control.o amd_i_info.o amd_i_valid.o amd_l_aat.o amd_l_1.o \ amd_l_2.o amd_l_dump.o amd_l_postorder.o amd_l_post_tree.o \ amd_l_defaults.o amd_l_order.o amd_l_control.o amd_l_info.o \ amd_l_valid.o amd_i_preprocess.o amd_l_preprocess.o amd_global.o - $(RANLIB) ../Lib/libamd.a #------------------------------------------------------------------------------- # compile the Fortran versions and the libamdf77.a library #------------------------------------------------------------------------------- fortran: $(F77) $(F77FLAGS) -c ../Source/amd.f -o amd.o $(F77) $(F77FLAGS) -c ../Source/amdbar.f -o amdbar.o $(AR) ../Lib/libamdf77.a amd.o amdbar.o - $(RANLIB) ../Lib/libamdf77.a #------------------------------------------------------------------------------- # Remove all but the files in the original distribution #------------------------------------------------------------------------------- clean: - $(RM) $(CLEAN) purge: distclean distclean: clean - $(RM) ../Lib/libamd.a ../Lib/libamdf77.a cvxopt-1.1.4/src/C/SuiteSparse/AMD/Lib/GNUmakefile0000644000175000017500000000512411674452555020507 0ustar sonnesonne#------------------------------------------------------------------------------- # AMD Makefile for compiling on Unix systems (for GNU make only) #------------------------------------------------------------------------------- default: ../Lib/libamd.a include ../../UFconfig/UFconfig.mk C = $(CC) $(CFLAGS) $(CONFIG) -I../Include -I../../UFconfig #------------------------------------------------------------------------------- # source files #------------------------------------------------------------------------------- AMD = amd_aat amd_1 amd_2 amd_dump amd_postorder amd_post_tree amd_defaults \ amd_order amd_control amd_info amd_valid amd_preprocess UFCONFIG = ../../UFconfig/UFconfig.h INC = ../Include/amd.h ../Include/amd_internal.h $(UFCONFIG) #------------------------------------------------------------------------------- # object files for each version #------------------------------------------------------------------------------- AMDI = $(addsuffix .o, $(subst amd_,amd_i_,$(AMD))) AMDL = $(addsuffix .o, $(subst amd_,amd_l_,$(AMD))) #------------------------------------------------------------------------------- # compile each int and long routine (with no real/complex version) #------------------------------------------------------------------------------- amd_global.o: ../Source/amd_global.c $(INC) $(C) -c $< -o $@ amd_i_%.o: ../Source/amd_%.c $(INC) $(C) -DDINT -c $< -o $@ amd_l_%.o: ../Source/amd_%.c $(INC) $(C) -DDLONG -c $< -o $@ #------------------------------------------------------------------------------- # Create the libamd.a library (C versions only) #------------------------------------------------------------------------------- ../Lib/libamd.a: amd_global.o $(AMDI) $(AMDL) $(AR) ../Lib/libamd.a $^ - $(RANLIB) ../Lib/libamd.a #------------------------------------------------------------------------------- # compile the Fortran versions and the libamdf77.a library #------------------------------------------------------------------------------- fortran: ../Lib/libamdf77.a AMDF77 = amd.o amdbar.o amd.o: ../Source/amd.f $(F77) $(F77FLAGS) -c ../Source/amd.f -o amd.o amdbar.o: ../Source/amdbar.f $(F77) $(F77FLAGS) -c ../Source/amdbar.f -o amdbar.o ../Lib/libamdf77.a: $(AMDF77) $(AR) ../Lib/libamdf77.a $^ - $(RANLIB) ../Lib/libamdf77.a #------------------------------------------------------------------------------- # Remove all but the files in the original distribution #------------------------------------------------------------------------------- clean: - $(RM) $(CLEAN) purge: distclean distclean: clean - $(RM) ../Lib/libamd.a ../Lib/libamdf77.a cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/0000755000175000017500000000000011674452555016263 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Demo/0000755000175000017500000000000011674452555017147 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Demo/colamd_example.out0000644000175000017500000000213111674452555022647 0ustar sonnesonnecolamd 5-by-4 input matrix: Column 0, with 3 entries: row 0 row 1 row 4 Column 1, with 2 entries: row 2 row 4 Column 2, with 4 entries: row 0 row 1 row 2 row 3 Column 3, with 2 entries: row 1 row 3 colamd version 2.7, Nov 1, 2007: OK. colamd: number of dense or empty rows ignored: 0 colamd: number of dense or empty columns ignored: 0 colamd: number of garbage collections performed: 0 colamd column ordering: 1st column: 1 2nd column: 0 3rd column: 2 4th column: 3 symamd 5-by-5 input matrix: Entries in strictly lower triangular part: Column 0, with 1 entries: row 1 Column 1, with 2 entries: row 2 row 3 Column 2, with 0 entries: Column 3, with 1 entries: row 4 Column 4, with 0 entries: symamd version 2.7, Nov 1, 2007: OK. symamd: number of dense or empty rows ignored: 0 symamd: number of dense or empty columns ignored: 0 symamd: number of garbage collections performed: 0 symamd column ordering: 1st row/column: 0 2nd row/column: 2 3rd row/column: 1 4th row/column: 3 5th row/column: 4 cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Demo/colamd_example.c0000644000175000017500000001344511674452555022274 0ustar sonnesonne/* ========================================================================== */ /* === colamd and symamd example ============================================ */ /* ========================================================================== */ /* COLAMD / SYMAMD example colamd example of use, to order the columns of a 5-by-4 matrix with 11 nonzero entries in the following nonzero pattern, with default knobs. x 0 x 0 x 0 x x 0 x x 0 0 0 x x x x 0 0 symamd example of use, to order the rows and columns of a 5-by-5 matrix with 13 nonzero entries in the following nonzero pattern, with default knobs. x x 0 0 0 x x x x 0 0 x x 0 0 0 x 0 x x 0 0 0 x x (where x denotes a nonzero value). See http://www.cise.ufl.edu/research/sparse/colamd/ (the colamd.c file) for the routines this program calls, and for the License. */ /* ========================================================================== */ #include #include "colamd.h" #define A_NNZ 11 #define A_NROW 5 #define A_NCOL 4 #define ALEN 150 #define B_NNZ 4 #define B_N 5 int main (void) { /* ====================================================================== */ /* input matrix A definition */ /* ====================================================================== */ int A [ALEN] = { 0, 1, 4, /* row indices of nonzeros in column 0 */ 2, 4, /* row indices of nonzeros in column 1 */ 0, 1, 2, 3, /* row indices of nonzeros in column 2 */ 1, 3} ; /* row indices of nonzeros in column 3 */ int p [ ] = { 0, /* column 0 is in A [0..2] */ 3, /* column 1 is in A [3..4] */ 5, /* column 2 is in A [5..8] */ 9, /* column 3 is in A [9..10] */ A_NNZ} ; /* number of nonzeros in A */ /* ====================================================================== */ /* input matrix B definition */ /* ====================================================================== */ int B [ ] = { /* Note: only strictly lower triangular part */ /* is included, since symamd ignores the */ /* diagonal and upper triangular part of B. */ 1, /* row indices of nonzeros in column 0 */ 2, 3, /* row indices of nonzeros in column 1 */ /* row indices of nonzeros in column 2 (none) */ 4 /* row indices of nonzeros in column 3 */ } ; /* row indices of nonzeros in column 4 (none) */ int q [ ] = { 0, /* column 0 is in B [0] */ 1, /* column 1 is in B [1..2] */ 3, /* column 2 is empty */ 3, /* column 3 is in B [3] */ 4, /* column 4 is empty */ B_NNZ} ; /* number of nonzeros in strictly lower B */ /* ====================================================================== */ /* other variable definitions */ /* ====================================================================== */ int perm [B_N+1] ; /* note the size is N+1 */ int stats [COLAMD_STATS] ; /* for colamd and symamd output statistics */ int row, col, pp, length, ok ; /* ====================================================================== */ /* dump the input matrix A */ /* ====================================================================== */ printf ("colamd %d-by-%d input matrix:\n", A_NROW, A_NCOL) ; for (col = 0 ; col < A_NCOL ; col++) { length = p [col+1] - p [col] ; printf ("Column %d, with %d entries:\n", col, length) ; for (pp = p [col] ; pp < p [col+1] ; pp++) { row = A [pp] ; printf (" row %d\n", row) ; } } /* ====================================================================== */ /* order the matrix. Note that this destroys A and overwrites p */ /* ====================================================================== */ ok = colamd (A_NROW, A_NCOL, ALEN, A, p, (double *) NULL, stats) ; colamd_report (stats) ; if (!ok) { printf ("colamd error!\n") ; exit (1) ; } /* ====================================================================== */ /* print the column ordering */ /* ====================================================================== */ printf ("colamd column ordering:\n") ; printf ("1st column: %d\n", p [0]) ; printf ("2nd column: %d\n", p [1]) ; printf ("3rd column: %d\n", p [2]) ; printf ("4th column: %d\n", p [3]) ; /* ====================================================================== */ /* dump the strictly lower triangular part of symmetric input matrix B */ /* ====================================================================== */ printf ("\n\nsymamd %d-by-%d input matrix:\n", B_N, B_N) ; printf ("Entries in strictly lower triangular part:\n") ; for (col = 0 ; col < B_N ; col++) { length = q [col+1] - q [col] ; printf ("Column %d, with %d entries:\n", col, length) ; for (pp = q [col] ; pp < q [col+1] ; pp++) { row = B [pp] ; printf (" row %d\n", row) ; } } /* ====================================================================== */ /* order the matrix B. Note that this does not modify B or q. */ /* ====================================================================== */ ok = symamd (B_N, B, q, perm, (double *) NULL, stats, &calloc, &free) ; symamd_report (stats) ; if (!ok) { printf ("symamd error!\n") ; exit (1) ; } /* ====================================================================== */ /* print the symmetric ordering */ /* ====================================================================== */ printf ("symamd column ordering:\n") ; printf ("1st row/column: %d\n", perm [0]) ; printf ("2nd row/column: %d\n", perm [1]) ; printf ("3rd row/column: %d\n", perm [2]) ; printf ("4th row/column: %d\n", perm [3]) ; printf ("5th row/column: %d\n", perm [4]) ; exit (0) ; } cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Demo/Makefile0000644000175000017500000000253111674452555020610 0ustar sonnesonne#----------------------------------------------------------------------------- # compile the COLAMD demo #----------------------------------------------------------------------------- default: colamd_example colamd_l_example include ../../UFconfig/UFconfig.mk I = -I../Include -I../../UFconfig C = $(CC) $(CFLAGS) $(I) library: ( cd ../Lib ; $(MAKE) ) #------------------------------------------------------------------------------ # Create the demo program, run it, and compare the output #------------------------------------------------------------------------------ dist: colamd_example: colamd_example.c library $(C) -o colamd_example colamd_example.c ../Lib/libcolamd.a -lm - ./colamd_example > my_colamd_example.out - diff colamd_example.out my_colamd_example.out colamd_l_example: colamd_l_example.c library $(C) -o colamd_l_example colamd_l_example.c ../Lib/libcolamd.a -lm - ./colamd_l_example > my_colamd_l_example.out - diff colamd_example.out my_colamd_example.out #------------------------------------------------------------------------------ # Remove all but the files in the original distribution #------------------------------------------------------------------------------ clean: - $(RM) $(CLEAN) purge: distclean distclean: clean - $(RM) colamd_example colamd_l_example - $(RM) my_colamd_example.out my_colamd_l_example.out cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Demo/colamd_l_example.c0000644000175000017500000001361111674452555022602 0ustar sonnesonne/* ========================================================================== */ /* === colamd and symamd example ============================================ */ /* ========================================================================== */ /* COLAMD / SYMAMD example colamd example of use, to order the columns of a 5-by-4 matrix with 11 nonzero entries in the following nonzero pattern, with default knobs. x 0 x 0 x 0 x x 0 x x 0 0 0 x x x x 0 0 symamd example of use, to order the rows and columns of a 5-by-5 matrix with 13 nonzero entries in the following nonzero pattern, with default knobs. x x 0 0 0 x x x x 0 0 x x 0 0 0 x 0 x x 0 0 0 x x (where x denotes a nonzero value). See http://www.cise.ufl.edu/research/sparse/colamd/ (the colamd.c file) for the routines this program calls, and for the License. */ /* ========================================================================== */ #include #include "colamd.h" #define A_NNZ 11 #define A_NROW 5 #define A_NCOL 4 #define ALEN 150 #define B_NNZ 4 #define B_N 5 /* define UF_long */ #include "UFconfig.h" int main (void) { /* ====================================================================== */ /* input matrix A definition */ /* ====================================================================== */ UF_long A [ALEN] = { 0, 1, 4, /* row indices of nonzeros in column 0 */ 2, 4, /* row indices of nonzeros in column 1 */ 0, 1, 2, 3, /* row indices of nonzeros in column 2 */ 1, 3} ; /* row indices of nonzeros in column 3 */ UF_long p [ ] = { 0, /* column 0 is in A [0..2] */ 3, /* column 1 is in A [3..4] */ 5, /* column 2 is in A [5..8] */ 9, /* column 3 is in A [9..10] */ A_NNZ} ; /* number of nonzeros in A */ /* ====================================================================== */ /* input matrix B definition */ /* ====================================================================== */ UF_long B [ ] = { /* Note: only strictly lower triangular part */ /* is included, since symamd ignores the */ /* diagonal and upper triangular part of B. */ 1, /* row indices of nonzeros in column 0 */ 2, 3, /* row indices of nonzeros in column 1 */ /* row indices of nonzeros in column 2 (none) */ 4 /* row indices of nonzeros in column 3 */ } ; /* row indices of nonzeros in column 4 (none) */ UF_long q [ ] = { 0, /* column 0 is in B [0] */ 1, /* column 1 is in B [1..2] */ 3, /* column 2 is empty */ 3, /* column 3 is in B [3] */ 4, /* column 4 is empty */ B_NNZ} ; /* number of nonzeros in strictly lower B */ /* ====================================================================== */ /* other variable definitions */ /* ====================================================================== */ UF_long perm [B_N+1] ; /* note the size is N+1 */ UF_long stats [COLAMD_STATS] ;/* for colamd and symamd output statistics */ UF_long row, col, pp, length, ok ; /* ====================================================================== */ /* dump the input matrix A */ /* ====================================================================== */ printf ("colamd %d-by-%d input matrix:\n", A_NROW, A_NCOL) ; for (col = 0 ; col < A_NCOL ; col++) { length = p [col+1] - p [col] ; printf ("Column %ld, with %ld entries:\n", col, length) ; for (pp = p [col] ; pp < p [col+1] ; pp++) { row = A [pp] ; printf (" row %ld\n", row) ; } } /* ====================================================================== */ /* order the matrix. Note that this destroys A and overwrites p */ /* ====================================================================== */ ok = colamd_l (A_NROW, A_NCOL, ALEN, A, p, (double *) NULL, stats) ; colamd_l_report (stats) ; if (!ok) { printf ("colamd error!\n") ; exit (1) ; } /* ====================================================================== */ /* print the column ordering */ /* ====================================================================== */ printf ("colamd_l column ordering:\n") ; printf ("1st column: %ld\n", p [0]) ; printf ("2nd column: %ld\n", p [1]) ; printf ("3rd column: %ld\n", p [2]) ; printf ("4th column: %ld\n", p [3]) ; /* ====================================================================== */ /* dump the strictly lower triangular part of symmetric input matrix B */ /* ====================================================================== */ printf ("\n\nsymamd_l %d-by-%d input matrix:\n", B_N, B_N) ; printf ("Entries in strictly lower triangular part:\n") ; for (col = 0 ; col < B_N ; col++) { length = q [col+1] - q [col] ; printf ("Column %ld, with %ld entries:\n", col, length) ; for (pp = q [col] ; pp < q [col+1] ; pp++) { row = B [pp] ; printf (" row %ld\n", row) ; } } /* ====================================================================== */ /* order the matrix B. Note that this does not modify B or q. */ /* ====================================================================== */ ok = symamd_l (B_N, B, q, perm, (double *) NULL, stats, &calloc, &free) ; symamd_l_report (stats) ; if (!ok) { printf ("symamd error!\n") ; exit (1) ; } /* ====================================================================== */ /* print the symmetric ordering */ /* ====================================================================== */ printf ("symamd_l column ordering:\n") ; printf ("1st row/column: %ld\n", perm [0]) ; printf ("2nd row/column: %ld\n", perm [1]) ; printf ("3rd row/column: %ld\n", perm [2]) ; printf ("4th row/column: %ld\n", perm [3]) ; printf ("5th row/column: %ld\n", perm [4]) ; exit (0) ; } cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Demo/colamd_l_example.out0000644000175000017500000000213711674452555023170 0ustar sonnesonnecolamd 5-by-4 input matrix: Column 0, with 3 entries: row 0 row 1 row 4 Column 1, with 2 entries: row 2 row 4 Column 2, with 4 entries: row 0 row 1 row 2 row 3 Column 3, with 2 entries: row 1 row 3 colamd version 2.7, Nov 1, 2007: OK. colamd: number of dense or empty rows ignored: 0 colamd: number of dense or empty columns ignored: 0 colamd: number of garbage collections performed: 0 colamd_l column ordering: 1st column: 1 2nd column: 0 3rd column: 2 4th column: 3 symamd_l 5-by-5 input matrix: Entries in strictly lower triangular part: Column 0, with 1 entries: row 1 Column 1, with 2 entries: row 2 row 3 Column 2, with 0 entries: Column 3, with 1 entries: row 4 Column 4, with 0 entries: symamd version 2.7, Nov 1, 2007: OK. symamd: number of dense or empty rows ignored: 0 symamd: number of dense or empty columns ignored: 0 symamd: number of garbage collections performed: 0 symamd_l column ordering: 1st row/column: 0 2nd row/column: 2 3rd row/column: 1 4th row/column: 3 5th row/column: 4 cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Makefile0000644000175000017500000000223111674452555017721 0ustar sonnesonne#------------------------------------------------------------------------------ # COLAMD Makefile #------------------------------------------------------------------------------ default: demo include ../UFconfig/UFconfig.mk # Compile all C code, including the C-callable routine and the mexFunctions. # Do not the MATLAB interface. demo: ( cd Lib ; $(MAKE) ) ( cd Demo ; $(MAKE) ) # Compile all C code, including the C-callable routine and the mexFunctions. all: ( cd Lib ; $(MAKE) ) ( cd Demo ; $(MAKE) ) ( cd MATLAB ; $(MAKE) ) # compile just the C-callable libraries (not mexFunctions or Demos) library: ( cd Lib ; $(MAKE) ) # remove object files, but keep the compiled programs and library archives clean: ( cd Lib ; $(MAKE) clean ) ( cd Demo ; $(MAKE) clean ) ( cd MATLAB ; $(MAKE) clean ) # clean, and then remove compiled programs and library archives purge: ( cd Lib ; $(MAKE) purge ) ( cd Demo ; $(MAKE) purge ) ( cd MATLAB ; $(MAKE) purge ) distclean: purge # get ready for distribution dist: purge ( cd Demo ; $(MAKE) dist ) ccode: library lib: library # compile the MATLAB mexFunction mex: ( cd MATLAB ; $(MAKE) ) cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/README.txt0000644000175000017500000001236511674452555017770 0ustar sonnesonneThe COLAMD ordering method - Version 2.7 ------------------------------------------------------------------------------- The COLAMD column approximate minimum degree ordering algorithm computes a permutation vector P such that the LU factorization of A (:,P) tends to be sparser than that of A. The Cholesky factorization of (A (:,P))'*(A (:,P)) will also tend to be sparser than that of A'*A. SYMAMD is a symmetric minimum degree ordering method based on COLAMD, available as a MATLAB-callable function. It constructs a matrix M such that M'*M has the same pattern as A, and then uses COLAMD to compute a column ordering of M. Colamd and symamd tend to be faster and generate better orderings than their MATLAB counterparts, colmmd and symmmd. To compile and test the colamd m-files and mexFunctions, just unpack the COLAMD/ directory from the COLAMD.tar.gz file, and run MATLAB from within that directory. Next, type colamd_test to compile and test colamd and symamd. This will work on any computer with MATLAB (Unix, PC, or Mac). Alternatively, type "make" (in Unix) to compile and run a simple example C code, without using MATLAB. To compile and install the colamd m-files and mexFunctions, just cd to COLAMD/MATLAB and type colamd_install in the MATLAB command window. A short demo will run. Optionally, type colamd_test to run an extensive tests. Type "make" in Unix in the COLAMD directory to compile the C-callable library and to run a short demo. If you have MATLAB 7.2 or earlier, you must first edit UFconfig/UFconfig.h to remove the "-largeArrayDims" option from the MEX command (or just use colamd_make.m inside MATLAB). Colamd is a built-in routine in MATLAB, available from The Mathworks, Inc. Under most cases, the compiled COLAMD from Versions 2.0 to the current version do not differ. Colamd Versions 2.2 and 2.3 differ only in their mexFunction interaces to MATLAB. v2.4 fixes a bug in the symamd routine in v2.3. The bug (in v2.3 and earlier) has no effect on the MATLAB symamd mexFunction. v2.5 adds additional checks for integer overflow, so that the "int" version can be safely used with 64-bit pointers. Refer to the ChangeLog for more details. To use colamd and symamd within an application written in C, all you need are colamd.c, colamd_global.c, and colamd.h, which are the C-callable colamd/symamd codes. See colamd.c for more information on how to call colamd from a C program. Requires UFconfig, in the ../UFconfig directory relative to this directory. Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. See http://www.cise.ufl.edu/research/sparse/colamd (the colamd.c file) for the License. Related papers: T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004. T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, an approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, 2004. "An approximate minimum degree column ordering algorithm", S. I. Larimore, MS Thesis, Dept. of Computer and Information Science and Engineering, University of Florida, Gainesville, FL, 1998. CISE Tech Report TR-98-016. Available at ftp://ftp.cise.ufl.edu/cis/tech-reports/tr98/tr98-016.ps via anonymous ftp. Approximate Deficiency for Ordering the Columns of a Matrix, J. L. Kern, Senior Thesis, Dept. of Computer and Information Science and Engineering, University of Florida, Gainesville, FL, 1999. Available at http://www.cise.ufl.edu/~davis/Kern/kern.ps Authors: Stefan I. Larimore and Timothy A. Davis, University of Florida, in collaboration with John Gilbert, Xerox PARC (now at UC Santa Barbara), and Esmong Ng, Lawrence Berkeley National Laboratory (much of this work he did while at Oak Ridge National Laboratory). COLAMD files: Demo simple demo Doc additional documentation (see colamd.c for more) Include include file Lib compiled C-callable library Makefile primary Unix Makefile MATLAB MATLAB functions README.txt this file Source C source code ./Demo: colamd_example.c simple example colamd_example.out output of colamd_example.c colamd_l_example.c simple example, long integers colamd_l_example.out output of colamd_l_example.c Makefile Makefile for C demos ./Doc: ChangeLog change log lesser.txt license ./Include: colamd.h include file ./Lib: Makefile Makefile for C-callable library ./MATLAB: colamd2.m MATLAB interface for colamd2 colamd_demo.m simple demo colamd_install.m compile and install colamd2 and symamd2 colamd_make.m compile colamd2 and symamd2 colamdmex.ca MATLAB mexFunction for colamd2 colamd_test.m extensive test colamdtestmex.c test function for colamd Contents.m contents of the MATLAB directory luflops.m test code Makefile Makefile for MATLAB functions symamd2.m MATLAB interface for symamd2 symamdmex.c MATLAB mexFunction for symamd2 symamdtestmex.c test function for symamd ./Source: colamd.c primary source code colamd_global.c globally defined function pointers (malloc, free, ...) cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Doc/0000755000175000017500000000000011674452555016770 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Doc/ChangeLog0000644000175000017500000001075111674452555020546 0ustar sonnesonneMay 31, 2007: version 2.7.0 * ported to 64-bit MATLAB * subdirectories added (Source/, Include/, Lib/, Doc/, MATLAB/, Demo/) Dec 12, 2006, version 2.5.2 * minor MATLAB cleanup. MATLAB functions renamed colamd2 and symamd2, so that they do not conflict with the built-in versions. Note that the MATLAB built-in functions colamd and symamd are identical to the colamd and symamd functions here. Aug 31, 2006: Version 2.5.1 * minor change to colamd.m and symamd.m, to use etree instead of sparsfun. Apr. 30, 2006: Version 2.5 * colamd_recommended modified, to do more careful integer overflow checking. It now returns size_t, not int. colamd_l_recommended also returns size_t. A zero is returned if an error occurs. A postive return value denotes success. In v2.4 and earlier, -1 was returned on error (an int or long). * long replaced with UF_long integer, which is long except on WIN64. Nov 15, 2005: * minor editting of comments; version number (2.4) unchanged. Changes from Version 2.3 to 2.4 (Aug 30, 2005) * Makefile now relies on ../UFconfig/UFconfig.mk * changed the dense row/col detection. The meaning of the knobs has thus changed. * added an option to turn off aggressive absorption. It was always on in versions 2.3 and earlier. * added a #define'd version number * added a function pointer (colamd_printf) for COLAMD's printing. * added a -DNPRINT option, to turn off printing at compile-time. * added a check for integer overflow in colamd_recommended * minor changes to allow for more simpler 100% test coverage * bug fix. If symamd v2.3 fails to allocate its copy of the input matrix, then it erroneously frees a calloc'd workspace twice. This bug has no effect on the MATLAB symamd mexFunction, since mxCalloc terminates the mexFunction if it fails to allocate memory. Similarly, UMFPACK is not affected because it does not use symamd. The bug has no effect on the colamd ordering routine in v2.3. Changes from Version 2.2 to 2.3 (Sept. 8, 2003) * removed the call to the MATLAB spparms ('spumoni') function. This can take a lot of time if you are ordering many small matrices. Only affects the MATLAB interface (colamdmex.c, symamdmex.c, colamdtestmex.c, and symamdtestmex.c). The usage of the optional 2nd argument to the colamd and symamd mexFunctions was changed accordingly. Changes from Version 2.1 to 2.2 (Sept. 23, 2002) * extensive testing routines added (colamd_test.m, colamdtestmex.c, and symamdtestmex.c), and the Makefile modified accordingly. * a few typos in the comments corrected * use of the MATLAB "flops" command removed from colamd_demo, and an m-file routine luflops.m added. * an explicit typecast from unsigned to int added, for COLAMD_C and COLAMD_R in colamd.h. * #include added to colamd_example.c Changes from Version 2.0 to 2.1 (May 4, 2001) * TRUE and FALSE are predefined on some systems, so they are defined here only if not already defined. * web site changed * UNIX Makefile modified, to handle the case if "." is not in your path. Changes from Version 1.0 to 2.0 (January 31, 2000) No bugs were found in version 1.1. These changes merely add new functionality. * added the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro. * moved the output statistics, from A, to a separate output argument. The arguments changed for the C-callable routines. * added colamd_report and symamd_report. * added a C-callable symamd routine. Formerly, symamd was only available as a mexFunction from MATLAB. * added error-checking to symamd. Formerly, it assumed its input was error-free. * added the optional stats and knobs arguments to the symamd mexFunction * deleted colamd_help. A help message is still available from "help colamd" and "help symamd" in MATLAB. * deleted colamdtree.m and symamdtree.m. Now, colamd.m and symamd.m also do the elimination tree post-ordering. The Version 1.1 colamd and symamd mexFunctions, which do not do the post- ordering, are now visible as colamdmex and symamdmex from MATLAB. Essentialy, the post-ordering is now the default behavior of colamd.m and symamd.m, to match the behavior of colmmd and symmmd. The post-ordering is only available in the MATLAB interface, not the C-callable interface. * made a slight change to the dense row/column detection in symamd, to match the stated specifications. cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Doc/lesser.txt0000644000175000017500000006350011674452555021032 0ustar sonnesonne GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Include/0000755000175000017500000000000011674452555017646 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Include/colamd.h0000644000175000017500000002073111674452555021261 0ustar sonnesonne/* ========================================================================== */ /* === colamd/symamd prototypes and definitions ============================= */ /* ========================================================================== */ /* COLAMD / SYMAMD include file You must include this file (colamd.h) in any routine that uses colamd, symamd, or the related macros and definitions. Authors: The authors of the code itself are Stefan I. Larimore and Timothy A. Davis (davis at cise.ufl.edu), University of Florida. The algorithm was developed in collaboration with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974 and DMS-9803599. Notice: Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. Permission is hereby granted to use, copy, modify, and/or distribute this program, provided that the Copyright, this License, and the Availability of the original version is retained on all copies and made accessible to the end-user of any code or package that includes COLAMD or any modified version of COLAMD. Availability: The colamd/symamd library is available at http://www.cise.ufl.edu/research/sparse/colamd/ This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.h file. It is required by the colamd.c, colamdmex.c, and symamdmex.c files, and by any C code that calls the routines whose prototypes are listed below, or that uses the colamd/symamd definitions listed below. */ #ifndef COLAMD_H #define COLAMD_H /* make it easy for C++ programs to include COLAMD */ #ifdef __cplusplus extern "C" { #endif /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ #include /* ========================================================================== */ /* === COLAMD version ======================================================= */ /* ========================================================================== */ /* COLAMD Version 2.4 and later will include the following definitions. * As an example, to test if the version you are using is 2.4 or later: * * #ifdef COLAMD_VERSION * if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ... * #endif * * This also works during compile-time: * * #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) * printf ("This is version 2.4 or later\n") ; * #else * printf ("This is an early version\n") ; * #endif * * Versions 2.3 and earlier of COLAMD do not include a #define'd version number. */ #define COLAMD_DATE "Nov 1, 2007" #define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub)) #define COLAMD_MAIN_VERSION 2 #define COLAMD_SUB_VERSION 7 #define COLAMD_SUBSUB_VERSION 1 #define COLAMD_VERSION \ COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION) /* ========================================================================== */ /* === Knob and statistics definitions ====================================== */ /* ========================================================================== */ /* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ #define COLAMD_KNOBS 20 /* number of output statistics. Only stats [0..6] are currently used. */ #define COLAMD_STATS 20 /* knobs [0] and stats [0]: dense row knob and output statistic. */ #define COLAMD_DENSE_ROW 0 /* knobs [1] and stats [1]: dense column knob and output statistic. */ #define COLAMD_DENSE_COL 1 /* knobs [2]: aggressive absorption */ #define COLAMD_AGGRESSIVE 2 /* stats [2]: memory defragmentation count output statistic */ #define COLAMD_DEFRAG_COUNT 2 /* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */ #define COLAMD_STATUS 3 /* stats [4..6]: error info, or info on jumbled columns */ #define COLAMD_INFO1 4 #define COLAMD_INFO2 5 #define COLAMD_INFO3 6 /* error codes returned in stats [3]: */ #define COLAMD_OK (0) #define COLAMD_OK_BUT_JUMBLED (1) #define COLAMD_ERROR_A_not_present (-1) #define COLAMD_ERROR_p_not_present (-2) #define COLAMD_ERROR_nrow_negative (-3) #define COLAMD_ERROR_ncol_negative (-4) #define COLAMD_ERROR_nnz_negative (-5) #define COLAMD_ERROR_p0_nonzero (-6) #define COLAMD_ERROR_A_too_small (-7) #define COLAMD_ERROR_col_length_negative (-8) #define COLAMD_ERROR_row_index_out_of_bounds (-9) #define COLAMD_ERROR_out_of_memory (-10) #define COLAMD_ERROR_internal_error (-999) /* ========================================================================== */ /* === Prototypes of user-callable routines ================================= */ /* ========================================================================== */ /* define UF_long */ #include "UFconfig.h" size_t colamd_recommended /* returns recommended value of Alen, */ /* or 0 if input arguments are erroneous */ ( int nnz, /* nonzeros in A */ int n_row, /* number of rows in A */ int n_col /* number of columns in A */ ) ; size_t colamd_l_recommended /* returns recommended value of Alen, */ /* or 0 if input arguments are erroneous */ ( UF_long nnz, /* nonzeros in A */ UF_long n_row, /* number of rows in A */ UF_long n_col /* number of columns in A */ ) ; void colamd_set_defaults /* sets default parameters */ ( /* knobs argument is modified on output */ double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ ) ; void colamd_l_set_defaults /* sets default parameters */ ( /* knobs argument is modified on output */ double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ ) ; int colamd /* returns (1) if successful, (0) otherwise*/ ( /* A and p arguments are modified on output */ int n_row, /* number of rows in A */ int n_col, /* number of columns in A */ int Alen, /* size of the array A */ int A [], /* row indices of A, of size Alen */ int p [], /* column pointers of A, of size n_col+1 */ double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ int stats [COLAMD_STATS] /* colamd output statistics and error codes */ ) ; UF_long colamd_l /* returns (1) if successful, (0) otherwise*/ ( /* A and p arguments are modified on output */ UF_long n_row, /* number of rows in A */ UF_long n_col, /* number of columns in A */ UF_long Alen, /* size of the array A */ UF_long A [], /* row indices of A, of size Alen */ UF_long p [], /* column pointers of A, of size n_col+1 */ double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ UF_long stats [COLAMD_STATS]/* colamd output statistics and error codes */ ) ; int symamd /* return (1) if OK, (0) otherwise */ ( int n, /* number of rows and columns of A */ int A [], /* row indices of A */ int p [], /* column pointers of A */ int perm [], /* output permutation, size n_col+1 */ double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ int stats [COLAMD_STATS], /* output statistics and error codes */ void * (*allocate) (size_t, size_t), /* pointer to calloc (ANSI C) or */ /* mxCalloc (for MATLAB mexFunction) */ void (*release) (void *) /* pointer to free (ANSI C) or */ /* mxFree (for MATLAB mexFunction) */ ) ; UF_long symamd_l /* return (1) if OK, (0) otherwise */ ( UF_long n, /* number of rows and columns of A */ UF_long A [], /* row indices of A */ UF_long p [], /* column pointers of A */ UF_long perm [], /* output permutation, size n_col+1 */ double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ UF_long stats [COLAMD_STATS], /* output statistics and error codes */ void * (*allocate) (size_t, size_t), /* pointer to calloc (ANSI C) or */ /* mxCalloc (for MATLAB mexFunction) */ void (*release) (void *) /* pointer to free (ANSI C) or */ /* mxFree (for MATLAB mexFunction) */ ) ; void colamd_report ( int stats [COLAMD_STATS] ) ; void colamd_l_report ( UF_long stats [COLAMD_STATS] ) ; void symamd_report ( int stats [COLAMD_STATS] ) ; void symamd_l_report ( UF_long stats [COLAMD_STATS] ) ; #ifndef EXTERN #define EXTERN extern #endif EXTERN int (*colamd_printf) (const char *, ...) ; #ifdef __cplusplus } #endif #endif /* COLAMD_H */ cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Source/0000755000175000017500000000000011674452555017523 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Source/colamd_global.c0000644000175000017500000000155711674452555022456 0ustar sonnesonne/* ========================================================================== */ /* === colamd_global.c ====================================================== */ /* ========================================================================== */ /* ---------------------------------------------------------------------------- * COLAMD, Copyright (C) 2007, Timothy A. Davis. * See License.txt for the Version 2.1 of the GNU Lesser General Public License * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Global variables for COLAMD */ #ifndef NPRINT #ifdef MATLAB_MEX_FILE #include "mex.h" int (*colamd_printf) (const char *, ...) = mexPrintf ; #else #include int (*colamd_printf) (const char *, ...) = printf ; #endif #else int (*colamd_printf) (const char *, ...) = ((void *) 0) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Source/colamd.c0000644000175000017500000032304611674452555021136 0ustar sonnesonne/* ========================================================================== */ /* === colamd/symamd - a sparse matrix column ordering algorithm ============ */ /* ========================================================================== */ /* COLAMD / SYMAMD colamd: an approximate minimum degree column ordering algorithm, for LU factorization of symmetric or unsymmetric matrices, QR factorization, least squares, interior point methods for linear programming problems, and other related problems. symamd: an approximate minimum degree ordering algorithm for Cholesky factorization of symmetric matrices. Purpose: Colamd computes a permutation Q such that the Cholesky factorization of (AQ)'(AQ) has less fill-in and requires fewer floating point operations than A'A. This also provides a good ordering for sparse partial pivoting methods, P(AQ) = LU, where Q is computed prior to numerical factorization, and P is computed during numerical factorization via conventional partial pivoting with row interchanges. Colamd is the column ordering method used in SuperLU, part of the ScaLAPACK library. It is also available as built-in function in MATLAB Version 6, available from MathWorks, Inc. (http://www.mathworks.com). This routine can be used in place of colmmd in MATLAB. Symamd computes a permutation P of a symmetric matrix A such that the Cholesky factorization of PAP' has less fill-in and requires fewer floating point operations than A. Symamd constructs a matrix M such that M'M has the same nonzero pattern of A, and then orders the columns of M using colmmd. The column ordering of M is then returned as the row and column ordering P of A. Authors: The authors of the code itself are Stefan I. Larimore and Timothy A. Davis (davis at cise.ufl.edu), University of Florida. The algorithm was developed in collaboration with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974 and DMS-9803599. Copyright and License: Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved. COLAMD is also available under alternate licenses, contact T. Davis for details. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU LGPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. Availability: The colamd/symamd library is available at http://www.cise.ufl.edu/research/sparse/colamd/ This is the http://www.cise.ufl.edu/research/sparse/colamd/colamd.c file. It requires the colamd.h file. It is required by the colamdmex.c and symamdmex.c files, for the MATLAB interface to colamd and symamd. Appears as ACM Algorithm 836. See the ChangeLog file for changes since Version 1.0. References: T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004. T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD, an approximate column minimum degree ordering algorithm, ACM Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380, 2004. */ /* ========================================================================== */ /* === Description of user-callable routines ================================ */ /* ========================================================================== */ /* COLAMD includes both int and UF_long versions of all its routines. The * description below is for the int version. For UF_long, all int arguments * become UF_long. UF_long is normally defined as long, except for WIN64. ---------------------------------------------------------------------------- colamd_recommended: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" size_t colamd_recommended (int nnz, int n_row, int n_col) ; size_t colamd_l_recommended (UF_long nnz, UF_long n_row, UF_long n_col) ; Purpose: Returns recommended value of Alen for use by colamd. Returns 0 if any input argument is negative. The use of this routine is optional. Not needed for symamd, which dynamically allocates its own memory. Note that in v2.4 and earlier, these routines returned int or long. They now return a value of type size_t. Arguments (all input arguments): int nnz ; Number of nonzeros in the matrix A. This must be the same value as p [n_col] in the call to colamd - otherwise you will get a wrong value of the recommended memory to use. int n_row ; Number of rows in the matrix A. int n_col ; Number of columns in the matrix A. ---------------------------------------------------------------------------- colamd_set_defaults: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" colamd_set_defaults (double knobs [COLAMD_KNOBS]) ; colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ; Purpose: Sets the default parameters. The use of this routine is optional. Arguments: double knobs [COLAMD_KNOBS] ; Output only. NOTE: the meaning of the dense row/col knobs has changed in v2.4 knobs [0] and knobs [1] control dense row and col detection: Colamd: rows with more than max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col)) entries are removed prior to ordering. Columns with more than max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col))) entries are removed prior to ordering, and placed last in the output column ordering. Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0]. Rows and columns with more than max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n)) entries are removed prior to ordering, and placed last in the output ordering. COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1, respectively, in colamd.h. Default values of these two knobs are both 10. Currently, only knobs [0] and knobs [1] are used, but future versions may use more knobs. If so, they will be properly set to their defaults by the future version of colamd_set_defaults, so that the code that calls colamd will not need to change, assuming that you either use colamd_set_defaults, or pass a (double *) NULL pointer as the knobs array to colamd or symamd. knobs [2]: aggressive absorption knobs [COLAMD_AGGRESSIVE] controls whether or not to do aggressive absorption during the ordering. Default is TRUE. ---------------------------------------------------------------------------- colamd: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" int colamd (int n_row, int n_col, int Alen, int *A, int *p, double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ; UF_long colamd_l (UF_long n_row, UF_long n_col, UF_long Alen, UF_long *A, UF_long *p, double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS]) ; Purpose: Computes a column ordering (Q) of A such that P(AQ)=LU or (AQ)'AQ=LL' have less fill-in and require fewer floating point operations than factorizing the unpermuted matrix A or A'A, respectively. Returns: TRUE (1) if successful, FALSE (0) otherwise. Arguments: int n_row ; Input argument. Number of rows in the matrix A. Restriction: n_row >= 0. Colamd returns FALSE if n_row is negative. int n_col ; Input argument. Number of columns in the matrix A. Restriction: n_col >= 0. Colamd returns FALSE if n_col is negative. int Alen ; Input argument. Restriction (see note): Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col Colamd returns FALSE if these conditions are not met. Note: this restriction makes an modest assumption regarding the size of the two typedef's structures in colamd.h. We do, however, guarantee that Alen >= colamd_recommended (nnz, n_row, n_col) will be sufficient. Note: the macro version does not check for integer overflow, and thus is not recommended. Use the colamd_recommended routine instead. int A [Alen] ; Input argument, undefined on output. A is an integer array of size Alen. Alen must be at least as large as the bare minimum value given above, but this is very low, and can result in excessive run time. For best performance, we recommend that Alen be greater than or equal to colamd_recommended (nnz, n_row, n_col), which adds nnz/5 to the bare minimum value given above. On input, the row indices of the entries in column c of the matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a given column c need not be in ascending order, and duplicate row indices may be be present. However, colamd will work a little faster if both of these conditions are met (Colamd puts the matrix into this format, if it finds that the the conditions are not met). The matrix is 0-based. That is, rows are in the range 0 to n_row-1, and columns are in the range 0 to n_col-1. Colamd returns FALSE if any row index is out of range. The contents of A are modified during ordering, and are undefined on output. int p [n_col+1] ; Both input and output argument. p is an integer array of size n_col+1. On input, it holds the "pointers" for the column form of the matrix A. Column c of the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first entry, p [0], must be zero, and p [c] <= p [c+1] must hold for all c in the range 0 to n_col-1. The value p [n_col] is thus the total number of entries in the pattern of the matrix A. Colamd returns FALSE if these conditions are not met. On output, if colamd returns TRUE, the array p holds the column permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is the first column index in the new ordering, and p [n_col-1] is the last. That is, p [k] = j means that column j of A is the kth pivot column, in AQ, where k is in the range 0 to n_col-1 (p [0] = j means that column j of A is the first column in AQ). If colamd returns FALSE, then no permutation is returned, and p is undefined on output. double knobs [COLAMD_KNOBS] ; Input argument. See colamd_set_defaults for a description. int stats [COLAMD_STATS] ; Output argument. Statistics on the ordering, and error status. See colamd.h for related definitions. Colamd returns FALSE if stats is not present. stats [0]: number of dense or empty rows ignored. stats [1]: number of dense or empty columns ignored (and ordered last in the output permutation p) Note that a row can become "empty" if it contains only "dense" and/or "empty" columns, and similarly a column can become "empty" if it only contains "dense" and/or "empty" rows. stats [2]: number of garbage collections performed. This can be excessively high if Alen is close to the minimum required value. stats [3]: status code. < 0 is an error code. > 1 is a warning or notice. 0 OK. Each column of the input matrix contained row indices in increasing order, with no duplicates. 1 OK, but columns of input matrix were jumbled (unsorted columns or duplicate entries). Colamd had to do some extra work to sort the matrix first and remove duplicate entries, but it still was able to return a valid permutation (return value of colamd was TRUE). stats [4]: highest numbered column that is unsorted or has duplicate entries. stats [5]: last seen duplicate or unsorted row index. stats [6]: number of duplicate or unsorted row indices. -1 A is a null pointer -2 p is a null pointer -3 n_row is negative stats [4]: n_row -4 n_col is negative stats [4]: n_col -5 number of nonzeros in matrix is negative stats [4]: number of nonzeros, p [n_col] -6 p [0] is nonzero stats [4]: p [0] -7 A is too small stats [4]: required size stats [5]: actual size (Alen) -8 a column has a negative number of entries stats [4]: column with < 0 entries stats [5]: number of entries in col -9 a row index is out of bounds stats [4]: column with bad row index stats [5]: bad row index stats [6]: n_row, # of rows of matrx -10 (unused; see symamd.c) -999 (unused; see symamd.c) Future versions may return more statistics in the stats array. Example: See http://www.cise.ufl.edu/research/sparse/colamd/example.c for a complete example. To order the columns of a 5-by-4 matrix with 11 nonzero entries in the following nonzero pattern x 0 x 0 x 0 x x 0 x x 0 0 0 x x x x 0 0 with default knobs and no output statistics, do the following: #include "colamd.h" #define ALEN 100 int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ; int p [ ] = {0, 3, 5, 9, 11} ; int stats [COLAMD_STATS] ; colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ; The permutation is returned in the array p, and A is destroyed. ---------------------------------------------------------------------------- symamd: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" int symamd (int n, int *A, int *p, int *perm, double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS], void (*allocate) (size_t, size_t), void (*release) (void *)) ; UF_long symamd_l (UF_long n, UF_long *A, UF_long *p, UF_long *perm, double knobs [COLAMD_KNOBS], UF_long stats [COLAMD_STATS], void (*allocate) (size_t, size_t), void (*release) (void *)) ; Purpose: The symamd routine computes an ordering P of a symmetric sparse matrix A such that the Cholesky factorization PAP' = LL' remains sparse. It is based on a column ordering of a matrix M constructed so that the nonzero pattern of M'M is the same as A. The matrix A is assumed to be symmetric; only the strictly lower triangular part is accessed. You must pass your selected memory allocator (usually calloc/free or mxCalloc/mxFree) to symamd, for it to allocate memory for the temporary matrix M. Returns: TRUE (1) if successful, FALSE (0) otherwise. Arguments: int n ; Input argument. Number of rows and columns in the symmetrix matrix A. Restriction: n >= 0. Symamd returns FALSE if n is negative. int A [nnz] ; Input argument. A is an integer array of size nnz, where nnz = p [n]. The row indices of the entries in column c of the matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a given column c need not be in ascending order, and duplicate row indices may be present. However, symamd will run faster if the columns are in sorted order with no duplicate entries. The matrix is 0-based. That is, rows are in the range 0 to n-1, and columns are in the range 0 to n-1. Symamd returns FALSE if any row index is out of range. The contents of A are not modified. int p [n+1] ; Input argument. p is an integer array of size n+1. On input, it holds the "pointers" for the column form of the matrix A. Column c of the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first entry, p [0], must be zero, and p [c] <= p [c+1] must hold for all c in the range 0 to n-1. The value p [n] is thus the total number of entries in the pattern of the matrix A. Symamd returns FALSE if these conditions are not met. The contents of p are not modified. int perm [n+1] ; Output argument. On output, if symamd returns TRUE, the array perm holds the permutation P, where perm [0] is the first index in the new ordering, and perm [n-1] is the last. That is, perm [k] = j means that row and column j of A is the kth column in PAP', where k is in the range 0 to n-1 (perm [0] = j means that row and column j of A are the first row and column in PAP'). The array is used as a workspace during the ordering, which is why it must be of length n+1, not just n. double knobs [COLAMD_KNOBS] ; Input argument. See colamd_set_defaults for a description. int stats [COLAMD_STATS] ; Output argument. Statistics on the ordering, and error status. See colamd.h for related definitions. Symamd returns FALSE if stats is not present. stats [0]: number of dense or empty row and columns ignored (and ordered last in the output permutation perm). Note that a row/column can become "empty" if it contains only "dense" and/or "empty" columns/rows. stats [1]: (same as stats [0]) stats [2]: number of garbage collections performed. stats [3]: status code. < 0 is an error code. > 1 is a warning or notice. 0 OK. Each column of the input matrix contained row indices in increasing order, with no duplicates. 1 OK, but columns of input matrix were jumbled (unsorted columns or duplicate entries). Symamd had to do some extra work to sort the matrix first and remove duplicate entries, but it still was able to return a valid permutation (return value of symamd was TRUE). stats [4]: highest numbered column that is unsorted or has duplicate entries. stats [5]: last seen duplicate or unsorted row index. stats [6]: number of duplicate or unsorted row indices. -1 A is a null pointer -2 p is a null pointer -3 (unused, see colamd.c) -4 n is negative stats [4]: n -5 number of nonzeros in matrix is negative stats [4]: # of nonzeros (p [n]). -6 p [0] is nonzero stats [4]: p [0] -7 (unused) -8 a column has a negative number of entries stats [4]: column with < 0 entries stats [5]: number of entries in col -9 a row index is out of bounds stats [4]: column with bad row index stats [5]: bad row index stats [6]: n_row, # of rows of matrx -10 out of memory (unable to allocate temporary workspace for M or count arrays using the "allocate" routine passed into symamd). Future versions may return more statistics in the stats array. void * (*allocate) (size_t, size_t) A pointer to a function providing memory allocation. The allocated memory must be returned initialized to zero. For a C application, this argument should normally be a pointer to calloc. For a MATLAB mexFunction, the routine mxCalloc is passed instead. void (*release) (size_t, size_t) A pointer to a function that frees memory allocated by the memory allocation routine above. For a C application, this argument should normally be a pointer to free. For a MATLAB mexFunction, the routine mxFree is passed instead. ---------------------------------------------------------------------------- colamd_report: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" colamd_report (int stats [COLAMD_STATS]) ; colamd_l_report (UF_long stats [COLAMD_STATS]) ; Purpose: Prints the error status and statistics recorded in the stats array on the standard error output (for a standard C routine) or on the MATLAB output (for a mexFunction). Arguments: int stats [COLAMD_STATS] ; Input only. Statistics from colamd. ---------------------------------------------------------------------------- symamd_report: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" symamd_report (int stats [COLAMD_STATS]) ; symamd_l_report (UF_long stats [COLAMD_STATS]) ; Purpose: Prints the error status and statistics recorded in the stats array on the standard error output (for a standard C routine) or on the MATLAB output (for a mexFunction). Arguments: int stats [COLAMD_STATS] ; Input only. Statistics from symamd. */ /* ========================================================================== */ /* === Scaffolding code definitions ======================================== */ /* ========================================================================== */ /* Ensure that debugging is turned off: */ #ifndef NDEBUG #define NDEBUG #endif /* turn on debugging by uncommenting the following line #undef NDEBUG */ /* Our "scaffolding code" philosophy: In our opinion, well-written library code should keep its "debugging" code, and just normally have it turned off by the compiler so as not to interfere with performance. This serves several purposes: (1) assertions act as comments to the reader, telling you what the code expects at that point. All assertions will always be true (unless there really is a bug, of course). (2) leaving in the scaffolding code assists anyone who would like to modify the code, or understand the algorithm (by reading the debugging output, one can get a glimpse into what the code is doing). (3) (gasp!) for actually finding bugs. This code has been heavily tested and "should" be fully functional and bug-free ... but you never know... The code will become outrageously slow when debugging is enabled. To control the level of debugging output, set an environment variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging, you should see the following message on the standard output: colamd: debug version, D = 1 (THIS WILL BE SLOW!) or a similar message for symamd. If you don't, then debugging has not been enabled. */ /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ #include "colamd.h" #include #include #ifdef MATLAB_MEX_FILE #include "mex.h" #include "matrix.h" #endif /* MATLAB_MEX_FILE */ #if !defined (NPRINT) || !defined (NDEBUG) #include #endif #ifndef NULL #define NULL ((void *) 0) #endif /* ========================================================================== */ /* === int or UF_long ======================================================= */ /* ========================================================================== */ /* define UF_long */ #include "UFconfig.h" #ifdef DLONG #define Int UF_long #define ID UF_long_id #define Int_MAX UF_long_max #define COLAMD_recommended colamd_l_recommended #define COLAMD_set_defaults colamd_l_set_defaults #define COLAMD_MAIN colamd_l #define SYMAMD_MAIN symamd_l #define COLAMD_report colamd_l_report #define SYMAMD_report symamd_l_report #else #define Int int #define ID "%d" #define Int_MAX INT_MAX #define COLAMD_recommended colamd_recommended #define COLAMD_set_defaults colamd_set_defaults #define COLAMD_MAIN colamd #define SYMAMD_MAIN symamd #define COLAMD_report colamd_report #define SYMAMD_report symamd_report #endif /* ========================================================================== */ /* === Row and Column structures ============================================ */ /* ========================================================================== */ /* User code that makes use of the colamd/symamd routines need not directly */ /* reference these structures. They are used only for colamd_recommended. */ typedef struct Colamd_Col_struct { Int start ; /* index for A of first row in this column, or DEAD */ /* if column is dead */ Int length ; /* number of rows in this column */ union { Int thickness ; /* number of original columns represented by this */ /* col, if the column is alive */ Int parent ; /* parent in parent tree super-column structure, if */ /* the column is dead */ } shared1 ; union { Int score ; /* the score used to maintain heap, if col is alive */ Int order ; /* pivot ordering of this column, if col is dead */ } shared2 ; union { Int headhash ; /* head of a hash bucket, if col is at the head of */ /* a degree list */ Int hash ; /* hash value, if col is not in a degree list */ Int prev ; /* previous column in degree list, if col is in a */ /* degree list (but not at the head of a degree list) */ } shared3 ; union { Int degree_next ; /* next column, if col is in a degree list */ Int hash_next ; /* next column, if col is in a hash list */ } shared4 ; } Colamd_Col ; typedef struct Colamd_Row_struct { Int start ; /* index for A of first col in this row */ Int length ; /* number of principal columns in this row */ union { Int degree ; /* number of principal & non-principal columns in row */ Int p ; /* used as a row pointer in init_rows_cols () */ } shared1 ; union { Int mark ; /* for computing set differences and marking dead rows*/ Int first_column ;/* first column in row (used in garbage collection) */ } shared2 ; } Colamd_Row ; /* ========================================================================== */ /* === Definitions ========================================================== */ /* ========================================================================== */ /* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ #define PUBLIC #define PRIVATE static #define DENSE_DEGREE(alpha,n) \ ((Int) MAX (16.0, (alpha) * sqrt ((double) (n)))) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define ONES_COMPLEMENT(r) (-(r)-1) /* -------------------------------------------------------------------------- */ /* Change for version 2.1: define TRUE and FALSE only if not yet defined */ /* -------------------------------------------------------------------------- */ #ifndef TRUE #define TRUE (1) #endif #ifndef FALSE #define FALSE (0) #endif /* -------------------------------------------------------------------------- */ #define EMPTY (-1) /* Row and column status */ #define ALIVE (0) #define DEAD (-1) /* Column status */ #define DEAD_PRINCIPAL (-1) #define DEAD_NON_PRINCIPAL (-2) /* Macros for row and column status update and checking. */ #define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) #define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) #define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) #define COL_IS_DEAD(c) (Col [c].start < ALIVE) #define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) #define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) #define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } #define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } #define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } /* ========================================================================== */ /* === Colamd reporting mechanism =========================================== */ /* ========================================================================== */ #if defined (MATLAB_MEX_FILE) || defined (MATHWORKS) /* In MATLAB, matrices are 1-based to the user, but 0-based internally */ #define INDEX(i) ((i)+1) #else /* In C, matrices are 0-based and indices are reported as such in *_report */ #define INDEX(i) (i) #endif /* All output goes through the PRINTF macro. */ #define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; } /* ========================================================================== */ /* === Prototypes of PRIVATE routines ======================================= */ /* ========================================================================== */ PRIVATE Int init_rows_cols ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int p [], Int stats [COLAMD_STATS] ) ; PRIVATE void init_scoring ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int head [], double knobs [COLAMD_KNOBS], Int *p_n_row2, Int *p_n_col2, Int *p_max_deg ) ; PRIVATE Int find_ordering ( Int n_row, Int n_col, Int Alen, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int head [], Int n_col2, Int max_deg, Int pfree, Int aggressive ) ; PRIVATE void order_children ( Int n_col, Colamd_Col Col [], Int p [] ) ; PRIVATE void detect_super_cols ( #ifndef NDEBUG Int n_col, Colamd_Row Row [], #endif /* NDEBUG */ Colamd_Col Col [], Int A [], Int head [], Int row_start, Int row_length ) ; PRIVATE Int garbage_collection ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int *pfree ) ; PRIVATE Int clear_mark ( Int tag_mark, Int max_mark, Int n_row, Colamd_Row Row [] ) ; PRIVATE void print_report ( char *method, Int stats [COLAMD_STATS] ) ; /* ========================================================================== */ /* === Debugging prototypes and definitions ================================= */ /* ========================================================================== */ #ifndef NDEBUG #include /* colamd_debug is the *ONLY* global variable, and is only */ /* present when debugging */ PRIVATE Int colamd_debug = 0 ; /* debug print level */ #define DEBUG0(params) { PRINTF (params) ; } #define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; } #define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; } #define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; } #define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; } #ifdef MATLAB_MEX_FILE #define ASSERT(expression) (mxAssert ((expression), "")) #else #define ASSERT(expression) (assert (expression)) #endif /* MATLAB_MEX_FILE */ PRIVATE void colamd_get_debug /* gets the debug print level from getenv */ ( char *method ) ; PRIVATE void debug_deg_lists ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int head [], Int min_score, Int should, Int max_deg ) ; PRIVATE void debug_mark ( Int n_row, Colamd_Row Row [], Int tag_mark, Int max_mark ) ; PRIVATE void debug_matrix ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [] ) ; PRIVATE void debug_structures ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int n_col2 ) ; #else /* NDEBUG */ /* === No debugging ========================================================= */ #define DEBUG0(params) ; #define DEBUG1(params) ; #define DEBUG2(params) ; #define DEBUG3(params) ; #define DEBUG4(params) ; #define ASSERT(expression) #endif /* NDEBUG */ /* ========================================================================== */ /* === USER-CALLABLE ROUTINES: ============================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === colamd_recommended =================================================== */ /* ========================================================================== */ /* The colamd_recommended routine returns the suggested size for Alen. This value has been determined to provide good balance between the number of garbage collections and the memory requirements for colamd. If any argument is negative, or if integer overflow occurs, a 0 is returned as an error condition. 2*nnz space is required for the row and column indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is required for the Col and Row arrays, respectively, which are internal to colamd (roughly 6*n_col + 4*n_row). An additional n_col space is the minimal amount of "elbow room", and nnz/5 more space is recommended for run time efficiency. Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10. This function is not needed when using symamd. */ /* add two values of type size_t, and check for integer overflow */ static size_t t_add (size_t a, size_t b, int *ok) { (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ; return ((*ok) ? (a + b) : 0) ; } /* compute a*k where k is a small integer, and check for integer overflow */ static size_t t_mult (size_t a, size_t k, int *ok) { size_t i, s = 0 ; for (i = 0 ; i < k ; i++) { s = t_add (s, a, ok) ; } return (s) ; } /* size of the Col and Row structures */ #define COLAMD_C(n_col,ok) \ ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int))) #define COLAMD_R(n_row,ok) \ ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int))) PUBLIC size_t COLAMD_recommended /* returns recommended value of Alen. */ ( /* === Parameters ======================================================= */ Int nnz, /* number of nonzeros in A */ Int n_row, /* number of rows in A */ Int n_col /* number of columns in A */ ) { size_t s, c, r ; int ok = TRUE ; if (nnz < 0 || n_row < 0 || n_col < 0) { return (0) ; } s = t_mult (nnz, 2, &ok) ; /* 2*nnz */ c = COLAMD_C (n_col, &ok) ; /* size of column structures */ r = COLAMD_R (n_row, &ok) ; /* size of row structures */ s = t_add (s, c, &ok) ; s = t_add (s, r, &ok) ; s = t_add (s, n_col, &ok) ; /* elbow room */ s = t_add (s, nnz/5, &ok) ; /* elbow room */ ok = ok && (s < Int_MAX) ; return (ok ? s : 0) ; } /* ========================================================================== */ /* === colamd_set_defaults ================================================== */ /* ========================================================================== */ /* The colamd_set_defaults routine sets the default values of the user- controllable parameters for colamd and symamd: Colamd: rows with more than max (16, knobs [0] * sqrt (n_col)) entries are removed prior to ordering. Columns with more than max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed prior to ordering, and placed last in the output column ordering. Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n)) entries are removed prior to ordering, and placed last in the output ordering. knobs [0] dense row control knobs [1] dense column control knobs [2] if nonzero, do aggresive absorption knobs [3..19] unused, but future versions might use this */ PUBLIC void COLAMD_set_defaults ( /* === Parameters ======================================================= */ double knobs [COLAMD_KNOBS] /* knob array */ ) { /* === Local variables ================================================== */ Int i ; if (!knobs) { return ; /* no knobs to initialize */ } for (i = 0 ; i < COLAMD_KNOBS ; i++) { knobs [i] = 0 ; } knobs [COLAMD_DENSE_ROW] = 10 ; knobs [COLAMD_DENSE_COL] = 10 ; knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default: do aggressive absorption*/ } /* ========================================================================== */ /* === symamd =============================================================== */ /* ========================================================================== */ PUBLIC Int SYMAMD_MAIN /* return TRUE if OK, FALSE otherwise */ ( /* === Parameters ======================================================= */ Int n, /* number of rows and columns of A */ Int A [], /* row indices of A */ Int p [], /* column pointers of A */ Int perm [], /* output permutation, size n+1 */ double knobs [COLAMD_KNOBS], /* parameters (uses defaults if NULL) */ Int stats [COLAMD_STATS], /* output statistics and error codes */ void * (*allocate) (size_t, size_t), /* pointer to calloc (ANSI C) or */ /* mxCalloc (for MATLAB mexFunction) */ void (*release) (void *) /* pointer to free (ANSI C) or */ /* mxFree (for MATLAB mexFunction) */ ) { /* === Local variables ================================================== */ Int *count ; /* length of each column of M, and col pointer*/ Int *mark ; /* mark array for finding duplicate entries */ Int *M ; /* row indices of matrix M */ size_t Mlen ; /* length of M */ Int n_row ; /* number of rows in M */ Int nnz ; /* number of entries in A */ Int i ; /* row index of A */ Int j ; /* column index of A */ Int k ; /* row index of M */ Int mnz ; /* number of nonzeros in M */ Int pp ; /* index into a column of A */ Int last_row ; /* last row seen in the current column */ Int length ; /* number of nonzeros in a column */ double cknobs [COLAMD_KNOBS] ; /* knobs for colamd */ double default_knobs [COLAMD_KNOBS] ; /* default knobs for colamd */ #ifndef NDEBUG colamd_get_debug ("symamd") ; #endif /* NDEBUG */ /* === Check the input arguments ======================================== */ if (!stats) { DEBUG0 (("symamd: stats not present\n")) ; return (FALSE) ; } for (i = 0 ; i < COLAMD_STATS ; i++) { stats [i] = 0 ; } stats [COLAMD_STATUS] = COLAMD_OK ; stats [COLAMD_INFO1] = -1 ; stats [COLAMD_INFO2] = -1 ; if (!A) { stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; DEBUG0 (("symamd: A not present\n")) ; return (FALSE) ; } if (!p) /* p is not present */ { stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; DEBUG0 (("symamd: p not present\n")) ; return (FALSE) ; } if (n < 0) /* n must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; stats [COLAMD_INFO1] = n ; DEBUG0 (("symamd: n negative %d\n", n)) ; return (FALSE) ; } nnz = p [n] ; if (nnz < 0) /* nnz must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; stats [COLAMD_INFO1] = nnz ; DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ; return (FALSE) ; } if (p [0] != 0) { stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; stats [COLAMD_INFO1] = p [0] ; DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ; return (FALSE) ; } /* === If no knobs, set default knobs =================================== */ if (!knobs) { COLAMD_set_defaults (default_knobs) ; knobs = default_knobs ; } /* === Allocate count and mark ========================================== */ count = (Int *) ((*allocate) (n+1, sizeof (Int))) ; if (!count) { stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ; return (FALSE) ; } mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ; if (!mark) { stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; (*release) ((void *) count) ; DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ; return (FALSE) ; } /* === Compute column counts of M, check if A is valid ================== */ stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ for (i = 0 ; i < n ; i++) { mark [i] = -1 ; } for (j = 0 ; j < n ; j++) { last_row = -1 ; length = p [j+1] - p [j] ; if (length < 0) { /* column pointers must be non-decreasing */ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; stats [COLAMD_INFO1] = j ; stats [COLAMD_INFO2] = length ; (*release) ((void *) count) ; (*release) ((void *) mark) ; DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ; return (FALSE) ; } for (pp = p [j] ; pp < p [j+1] ; pp++) { i = A [pp] ; if (i < 0 || i >= n) { /* row index i, in column j, is out of bounds */ stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; stats [COLAMD_INFO1] = j ; stats [COLAMD_INFO2] = i ; stats [COLAMD_INFO3] = n ; (*release) ((void *) count) ; (*release) ((void *) mark) ; DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ; return (FALSE) ; } if (i <= last_row || mark [i] == j) { /* row index is unsorted or repeated (or both), thus col */ /* is jumbled. This is a notice, not an error condition. */ stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; stats [COLAMD_INFO1] = j ; stats [COLAMD_INFO2] = i ; (stats [COLAMD_INFO3]) ++ ; DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ; } if (i > j && mark [i] != j) { /* row k of M will contain column indices i and j */ count [i]++ ; count [j]++ ; } /* mark the row as having been seen in this column */ mark [i] = j ; last_row = i ; } } /* v2.4: removed free(mark) */ /* === Compute column pointers of M ===================================== */ /* use output permutation, perm, for column pointers of M */ perm [0] = 0 ; for (j = 1 ; j <= n ; j++) { perm [j] = perm [j-1] + count [j-1] ; } for (j = 0 ; j < n ; j++) { count [j] = perm [j] ; } /* === Construct M ====================================================== */ mnz = perm [n] ; n_row = mnz / 2 ; Mlen = COLAMD_recommended (mnz, n_row, n) ; M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ; DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n", n_row, n, mnz, (double) Mlen)) ; if (!M) { stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ; (*release) ((void *) count) ; (*release) ((void *) mark) ; DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ; return (FALSE) ; } k = 0 ; if (stats [COLAMD_STATUS] == COLAMD_OK) { /* Matrix is OK */ for (j = 0 ; j < n ; j++) { ASSERT (p [j+1] - p [j] >= 0) ; for (pp = p [j] ; pp < p [j+1] ; pp++) { i = A [pp] ; ASSERT (i >= 0 && i < n) ; if (i > j) { /* row k of M contains column indices i and j */ M [count [i]++] = k ; M [count [j]++] = k ; k++ ; } } } } else { /* Matrix is jumbled. Do not add duplicates to M. Unsorted cols OK. */ DEBUG0 (("symamd: Duplicates in A.\n")) ; for (i = 0 ; i < n ; i++) { mark [i] = -1 ; } for (j = 0 ; j < n ; j++) { ASSERT (p [j+1] - p [j] >= 0) ; for (pp = p [j] ; pp < p [j+1] ; pp++) { i = A [pp] ; ASSERT (i >= 0 && i < n) ; if (i > j && mark [i] != j) { /* row k of M contains column indices i and j */ M [count [i]++] = k ; M [count [j]++] = k ; k++ ; mark [i] = j ; } } } /* v2.4: free(mark) moved below */ } /* count and mark no longer needed */ (*release) ((void *) count) ; (*release) ((void *) mark) ; /* v2.4: free (mark) moved here */ ASSERT (k == n_row) ; /* === Adjust the knobs for M =========================================== */ for (i = 0 ; i < COLAMD_KNOBS ; i++) { cknobs [i] = knobs [i] ; } /* there are no dense rows in M */ cknobs [COLAMD_DENSE_ROW] = -1 ; cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ; /* === Order the columns of M =========================================== */ /* v2.4: colamd cannot fail here, so the error check is removed */ (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ; /* Note that the output permutation is now in perm */ /* === get the statistics for symamd from colamd ======================== */ /* a dense column in colamd means a dense row and col in symamd */ stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ; /* === Free M =========================================================== */ (*release) ((void *) M) ; DEBUG0 (("symamd: done.\n")) ; return (TRUE) ; } /* ========================================================================== */ /* === colamd =============================================================== */ /* ========================================================================== */ /* The colamd routine computes a column ordering Q of a sparse matrix A such that the LU factorization P(AQ) = LU remains sparse, where P is selected via partial pivoting. The routine can also be viewed as providing a permutation Q such that the Cholesky factorization (AQ)'(AQ) = LL' remains sparse. */ PUBLIC Int COLAMD_MAIN /* returns TRUE if successful, FALSE otherwise*/ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows in A */ Int n_col, /* number of columns in A */ Int Alen, /* length of A */ Int A [], /* row indices of A */ Int p [], /* pointers to columns in A */ double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */ Int stats [COLAMD_STATS] /* output statistics and error codes */ ) { /* === Local variables ================================================== */ Int i ; /* loop index */ Int nnz ; /* nonzeros in A */ size_t Row_size ; /* size of Row [], in integers */ size_t Col_size ; /* size of Col [], in integers */ size_t need ; /* minimum required length of A */ Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */ Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */ Int n_col2 ; /* number of non-dense, non-empty columns */ Int n_row2 ; /* number of non-dense, non-empty rows */ Int ngarbage ; /* number of garbage collections performed */ Int max_deg ; /* maximum row degree */ double default_knobs [COLAMD_KNOBS] ; /* default knobs array */ Int aggressive ; /* do aggressive absorption */ int ok ; #ifndef NDEBUG colamd_get_debug ("colamd") ; #endif /* NDEBUG */ /* === Check the input arguments ======================================== */ if (!stats) { DEBUG0 (("colamd: stats not present\n")) ; return (FALSE) ; } for (i = 0 ; i < COLAMD_STATS ; i++) { stats [i] = 0 ; } stats [COLAMD_STATUS] = COLAMD_OK ; stats [COLAMD_INFO1] = -1 ; stats [COLAMD_INFO2] = -1 ; if (!A) /* A is not present */ { stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; DEBUG0 (("colamd: A not present\n")) ; return (FALSE) ; } if (!p) /* p is not present */ { stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; DEBUG0 (("colamd: p not present\n")) ; return (FALSE) ; } if (n_row < 0) /* n_row must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ; stats [COLAMD_INFO1] = n_row ; DEBUG0 (("colamd: nrow negative %d\n", n_row)) ; return (FALSE) ; } if (n_col < 0) /* n_col must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; stats [COLAMD_INFO1] = n_col ; DEBUG0 (("colamd: ncol negative %d\n", n_col)) ; return (FALSE) ; } nnz = p [n_col] ; if (nnz < 0) /* nnz must be >= 0 */ { stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; stats [COLAMD_INFO1] = nnz ; DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ; return (FALSE) ; } if (p [0] != 0) { stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; stats [COLAMD_INFO1] = p [0] ; DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ; return (FALSE) ; } /* === If no knobs, set default knobs =================================== */ if (!knobs) { COLAMD_set_defaults (default_knobs) ; knobs = default_knobs ; } aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ; /* === Allocate the Row and Col arrays from array A ===================== */ ok = TRUE ; Col_size = COLAMD_C (n_col, &ok) ; /* size of Col array of structs */ Row_size = COLAMD_R (n_row, &ok) ; /* size of Row array of structs */ /* need = 2*nnz + n_col + Col_size + Row_size ; */ need = t_mult (nnz, 2, &ok) ; need = t_add (need, n_col, &ok) ; need = t_add (need, Col_size, &ok) ; need = t_add (need, Row_size, &ok) ; if (!ok || need > (size_t) Alen || need > Int_MAX) { /* not enough space in array A to perform the ordering */ stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ; stats [COLAMD_INFO1] = need ; stats [COLAMD_INFO2] = Alen ; DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen)); return (FALSE) ; } Alen -= Col_size + Row_size ; Col = (Colamd_Col *) &A [Alen] ; Row = (Colamd_Row *) &A [Alen + Col_size] ; /* === Construct the row and column data structures ===================== */ if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats)) { /* input matrix is invalid */ DEBUG0 (("colamd: Matrix invalid\n")) ; return (FALSE) ; } /* === Initialize scores, kill dense rows/columns ======================= */ init_scoring (n_row, n_col, Row, Col, A, p, knobs, &n_row2, &n_col2, &max_deg) ; /* === Order the supercolumns =========================================== */ ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, n_col2, max_deg, 2*nnz, aggressive) ; /* === Order the non-principal columns ================================== */ order_children (n_col, Col, p) ; /* === Return statistics in stats ======================================= */ stats [COLAMD_DENSE_ROW] = n_row - n_row2 ; stats [COLAMD_DENSE_COL] = n_col - n_col2 ; stats [COLAMD_DEFRAG_COUNT] = ngarbage ; DEBUG0 (("colamd: done.\n")) ; return (TRUE) ; } /* ========================================================================== */ /* === colamd_report ======================================================== */ /* ========================================================================== */ PUBLIC void COLAMD_report ( Int stats [COLAMD_STATS] ) { print_report ("colamd", stats) ; } /* ========================================================================== */ /* === symamd_report ======================================================== */ /* ========================================================================== */ PUBLIC void SYMAMD_report ( Int stats [COLAMD_STATS] ) { print_report ("symamd", stats) ; } /* ========================================================================== */ /* === NON-USER-CALLABLE ROUTINES: ========================================== */ /* ========================================================================== */ /* There are no user-callable routines beyond this point in the file */ /* ========================================================================== */ /* === init_rows_cols ======================================================= */ /* ========================================================================== */ /* Takes the column form of the matrix in A and creates the row form of the matrix. Also, row and column attributes are stored in the Col and Row structs. If the columns are un-sorted or contain duplicate row indices, this routine will also sort and remove duplicate row indices from the column form of the matrix. Returns FALSE if the matrix is invalid, TRUE otherwise. Not user-callable. */ PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* row indices of A, of size Alen */ Int p [], /* pointers to columns in A, of size n_col+1 */ Int stats [COLAMD_STATS] /* colamd statistics */ ) { /* === Local variables ================================================== */ Int col ; /* a column index */ Int row ; /* a row index */ Int *cp ; /* a column pointer */ Int *cp_end ; /* a pointer to the end of a column */ Int *rp ; /* a row pointer */ Int *rp_end ; /* a pointer to the end of a row */ Int last_row ; /* previous row */ /* === Initialize columns, and check column pointers ==================== */ for (col = 0 ; col < n_col ; col++) { Col [col].start = p [col] ; Col [col].length = p [col+1] - p [col] ; if (Col [col].length < 0) { /* column pointers must be non-decreasing */ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = Col [col].length ; DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ; return (FALSE) ; } Col [col].shared1.thickness = 1 ; Col [col].shared2.score = 0 ; Col [col].shared3.prev = EMPTY ; Col [col].shared4.degree_next = EMPTY ; } /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ /* === Scan columns, compute row degrees, and check row indices ========= */ stats [COLAMD_INFO3] = 0 ; /* number of duplicate or unsorted row indices*/ for (row = 0 ; row < n_row ; row++) { Row [row].length = 0 ; Row [row].shared2.mark = -1 ; } for (col = 0 ; col < n_col ; col++) { last_row = -1 ; cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { row = *cp++ ; /* make sure row indices within range */ if (row < 0 || row >= n_row) { stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = row ; stats [COLAMD_INFO3] = n_row ; DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ; return (FALSE) ; } if (row <= last_row || Row [row].shared2.mark == col) { /* row index are unsorted or repeated (or both), thus col */ /* is jumbled. This is a notice, not an error condition. */ stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = row ; (stats [COLAMD_INFO3]) ++ ; DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col)); } if (Row [row].shared2.mark != col) { Row [row].length++ ; } else { /* this is a repeated entry in the column, */ /* it will be removed */ Col [col].length-- ; } /* mark the row as having been seen in this column */ Row [row].shared2.mark = col ; last_row = row ; } } /* === Compute row pointers ============================================= */ /* row form of the matrix starts directly after the column */ /* form of matrix in A */ Row [0].start = p [n_col] ; Row [0].shared1.p = Row [0].start ; Row [0].shared2.mark = -1 ; for (row = 1 ; row < n_row ; row++) { Row [row].start = Row [row-1].start + Row [row-1].length ; Row [row].shared1.p = Row [row].start ; Row [row].shared2.mark = -1 ; } /* === Create row form ================================================== */ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) { /* if cols jumbled, watch for repeated row indices */ for (col = 0 ; col < n_col ; col++) { cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { row = *cp++ ; if (Row [row].shared2.mark != col) { A [(Row [row].shared1.p)++] = col ; Row [row].shared2.mark = col ; } } } } else { /* if cols not jumbled, we don't need the mark (this is faster) */ for (col = 0 ; col < n_col ; col++) { cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { A [(Row [*cp++].shared1.p)++] = col ; } } } /* === Clear the row marks and set row degrees ========================== */ for (row = 0 ; row < n_row ; row++) { Row [row].shared2.mark = 0 ; Row [row].shared1.degree = Row [row].length ; } /* === See if we need to re-create columns ============================== */ if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED) { DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ; #ifndef NDEBUG /* make sure column lengths are correct */ for (col = 0 ; col < n_col ; col++) { p [col] = Col [col].length ; } for (row = 0 ; row < n_row ; row++) { rp = &A [Row [row].start] ; rp_end = rp + Row [row].length ; while (rp < rp_end) { p [*rp++]-- ; } } for (col = 0 ; col < n_col ; col++) { ASSERT (p [col] == 0) ; } /* now p is all zero (different than when debugging is turned off) */ #endif /* NDEBUG */ /* === Compute col pointers ========================================= */ /* col form of the matrix starts at A [0]. */ /* Note, we may have a gap between the col form and the row */ /* form if there were duplicate entries, if so, it will be */ /* removed upon the first garbage collection */ Col [0].start = 0 ; p [0] = Col [0].start ; for (col = 1 ; col < n_col ; col++) { /* note that the lengths here are for pruned columns, i.e. */ /* no duplicate row indices will exist for these columns */ Col [col].start = Col [col-1].start + Col [col-1].length ; p [col] = Col [col].start ; } /* === Re-create col form =========================================== */ for (row = 0 ; row < n_row ; row++) { rp = &A [Row [row].start] ; rp_end = rp + Row [row].length ; while (rp < rp_end) { A [(p [*rp++])++] = row ; } } } /* === Done. Matrix is not (or no longer) jumbled ====================== */ return (TRUE) ; } /* ========================================================================== */ /* === init_scoring ========================================================= */ /* ========================================================================== */ /* Kills dense or empty columns and rows, calculates an initial score for each column, and places all columns in the degree lists. Not user-callable. */ PRIVATE void init_scoring ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* column form and row form of A */ Int head [], /* of size n_col+1 */ double knobs [COLAMD_KNOBS],/* parameters */ Int *p_n_row2, /* number of non-dense, non-empty rows */ Int *p_n_col2, /* number of non-dense, non-empty columns */ Int *p_max_deg /* maximum row degree */ ) { /* === Local variables ================================================== */ Int c ; /* a column index */ Int r, row ; /* a row index */ Int *cp ; /* a column pointer */ Int deg ; /* degree of a row or column */ Int *cp_end ; /* a pointer to the end of a column */ Int *new_cp ; /* new column pointer */ Int col_length ; /* length of pruned column */ Int score ; /* current column score */ Int n_col2 ; /* number of non-dense, non-empty columns */ Int n_row2 ; /* number of non-dense, non-empty rows */ Int dense_row_count ; /* remove rows with more entries than this */ Int dense_col_count ; /* remove cols with more entries than this */ Int min_score ; /* smallest column score */ Int max_deg ; /* maximum row degree */ Int next_col ; /* Used to add to degree list.*/ #ifndef NDEBUG Int debug_count ; /* debug only. */ #endif /* NDEBUG */ /* === Extract knobs ==================================================== */ /* Note: if knobs contains a NaN, this is undefined: */ if (knobs [COLAMD_DENSE_ROW] < 0) { /* only remove completely dense rows */ dense_row_count = n_col-1 ; } else { dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ; } if (knobs [COLAMD_DENSE_COL] < 0) { /* only remove completely dense columns */ dense_col_count = n_row-1 ; } else { dense_col_count = DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ; } DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ; max_deg = 0 ; n_col2 = n_col ; n_row2 = n_row ; /* === Kill empty columns =============================================== */ /* Put the empty columns at the end in their natural order, so that LU */ /* factorization can proceed as far as possible. */ for (c = n_col-1 ; c >= 0 ; c--) { deg = Col [c].length ; if (deg == 0) { /* this is a empty column, kill and order it last */ Col [c].shared2.order = --n_col2 ; KILL_PRINCIPAL_COL (c) ; } } DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ; /* === Kill dense columns =============================================== */ /* Put the dense columns at the end, in their natural order */ for (c = n_col-1 ; c >= 0 ; c--) { /* skip any dead columns */ if (COL_IS_DEAD (c)) { continue ; } deg = Col [c].length ; if (deg > dense_col_count) { /* this is a dense column, kill and order it last */ Col [c].shared2.order = --n_col2 ; /* decrement the row degrees */ cp = &A [Col [c].start] ; cp_end = cp + Col [c].length ; while (cp < cp_end) { Row [*cp++].shared1.degree-- ; } KILL_PRINCIPAL_COL (c) ; } } DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ; /* === Kill dense and empty rows ======================================== */ for (r = 0 ; r < n_row ; r++) { deg = Row [r].shared1.degree ; ASSERT (deg >= 0 && deg <= n_col) ; if (deg > dense_row_count || deg == 0) { /* kill a dense or empty row */ KILL_ROW (r) ; --n_row2 ; } else { /* keep track of max degree of remaining rows */ max_deg = MAX (max_deg, deg) ; } } DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ; /* === Compute initial column scores ==================================== */ /* At this point the row degrees are accurate. They reflect the number */ /* of "live" (non-dense) columns in each row. No empty rows exist. */ /* Some "live" columns may contain only dead rows, however. These are */ /* pruned in the code below. */ /* now find the initial matlab score for each column */ for (c = n_col-1 ; c >= 0 ; c--) { /* skip dead column */ if (COL_IS_DEAD (c)) { continue ; } score = 0 ; cp = &A [Col [c].start] ; new_cp = cp ; cp_end = cp + Col [c].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; /* skip if dead */ if (ROW_IS_DEAD (row)) { continue ; } /* compact the column */ *new_cp++ = row ; /* add row's external degree */ score += Row [row].shared1.degree - 1 ; /* guard against integer overflow */ score = MIN (score, n_col) ; } /* determine pruned column length */ col_length = (Int) (new_cp - &A [Col [c].start]) ; if (col_length == 0) { /* a newly-made null column (all rows in this col are "dense" */ /* and have already been killed) */ DEBUG2 (("Newly null killed: %d\n", c)) ; Col [c].shared2.order = --n_col2 ; KILL_PRINCIPAL_COL (c) ; } else { /* set column length and set score */ ASSERT (score >= 0) ; ASSERT (score <= n_col) ; Col [c].length = col_length ; Col [c].shared2.score = score ; } } DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n", n_col-n_col2)) ; /* At this point, all empty rows and columns are dead. All live columns */ /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ /* yet). Rows may contain dead columns, but all live rows contain at */ /* least one live column. */ #ifndef NDEBUG debug_structures (n_row, n_col, Row, Col, A, n_col2) ; #endif /* NDEBUG */ /* === Initialize degree lists ========================================== */ #ifndef NDEBUG debug_count = 0 ; #endif /* NDEBUG */ /* clear the hash buckets */ for (c = 0 ; c <= n_col ; c++) { head [c] = EMPTY ; } min_score = n_col ; /* place in reverse order, so low column indices are at the front */ /* of the lists. This is to encourage natural tie-breaking */ for (c = n_col-1 ; c >= 0 ; c--) { /* only add principal columns to degree lists */ if (COL_IS_ALIVE (c)) { DEBUG4 (("place %d score %d minscore %d ncol %d\n", c, Col [c].shared2.score, min_score, n_col)) ; /* === Add columns score to DList =============================== */ score = Col [c].shared2.score ; ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (score >= 0) ; ASSERT (score <= n_col) ; ASSERT (head [score] >= EMPTY) ; /* now add this column to dList at proper score location */ next_col = head [score] ; Col [c].shared3.prev = EMPTY ; Col [c].shared4.degree_next = next_col ; /* if there already was a column with the same score, set its */ /* previous pointer to this new column */ if (next_col != EMPTY) { Col [next_col].shared3.prev = c ; } head [score] = c ; /* see if this score is less than current min */ min_score = MIN (min_score, score) ; #ifndef NDEBUG debug_count++ ; #endif /* NDEBUG */ } } #ifndef NDEBUG DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n", debug_count, n_col, n_col-debug_count)) ; ASSERT (debug_count == n_col2) ; debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; #endif /* NDEBUG */ /* === Return number of remaining columns, and max row degree =========== */ *p_n_col2 = n_col2 ; *p_n_row2 = n_row2 ; *p_max_deg = max_deg ; } /* ========================================================================== */ /* === find_ordering ======================================================== */ /* ========================================================================== */ /* Order the principal columns of the supercolumn form of the matrix (no supercolumns on input). Uses a minimum approximate column minimum degree ordering method. Not user-callable. */ PRIVATE Int find_ordering /* return the number of garbage collections */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Int Alen, /* size of A, 2*nnz + n_col or larger */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* column form and row form of A */ Int head [], /* of size n_col+1 */ Int n_col2, /* Remaining columns to order */ Int max_deg, /* Maximum row degree */ Int pfree, /* index of first free slot (2*nnz on entry) */ Int aggressive ) { /* === Local variables ================================================== */ Int k ; /* current pivot ordering step */ Int pivot_col ; /* current pivot column */ Int *cp ; /* a column pointer */ Int *rp ; /* a row pointer */ Int pivot_row ; /* current pivot row */ Int *new_cp ; /* modified column pointer */ Int *new_rp ; /* modified row pointer */ Int pivot_row_start ; /* pointer to start of pivot row */ Int pivot_row_degree ; /* number of columns in pivot row */ Int pivot_row_length ; /* number of supercolumns in pivot row */ Int pivot_col_score ; /* score of pivot column */ Int needed_memory ; /* free space needed for pivot row */ Int *cp_end ; /* pointer to the end of a column */ Int *rp_end ; /* pointer to the end of a row */ Int row ; /* a row index */ Int col ; /* a column index */ Int max_score ; /* maximum possible score */ Int cur_score ; /* score of current column */ unsigned Int hash ; /* hash value for supernode detection */ Int head_column ; /* head of hash bucket */ Int first_col ; /* first column in hash bucket */ Int tag_mark ; /* marker value for mark array */ Int row_mark ; /* Row [row].shared2.mark */ Int set_difference ; /* set difference size of row with pivot row */ Int min_score ; /* smallest column score */ Int col_thickness ; /* "thickness" (no. of columns in a supercol) */ Int max_mark ; /* maximum value of tag_mark */ Int pivot_col_thickness ; /* number of columns represented by pivot col */ Int prev_col ; /* Used by Dlist operations. */ Int next_col ; /* Used by Dlist operations. */ Int ngarbage ; /* number of garbage collections performed */ #ifndef NDEBUG Int debug_d ; /* debug loop counter */ Int debug_step = 0 ; /* debug loop counter */ #endif /* NDEBUG */ /* === Initialization and clear mark ==================================== */ max_mark = INT_MAX - n_col ; /* INT_MAX defined in */ tag_mark = clear_mark (0, max_mark, n_row, Row) ; min_score = 0 ; ngarbage = 0 ; DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ; /* === Order the columns ================================================ */ for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) { #ifndef NDEBUG if (debug_step % 100 == 0) { DEBUG2 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; } else { DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ; } debug_step++ ; debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k, max_deg) ; debug_matrix (n_row, n_col, Row, Col, A) ; #endif /* NDEBUG */ /* === Select pivot column, and order it ============================ */ /* make sure degree list isn't empty */ ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (head [min_score] >= EMPTY) ; #ifndef NDEBUG for (debug_d = 0 ; debug_d < min_score ; debug_d++) { ASSERT (head [debug_d] == EMPTY) ; } #endif /* NDEBUG */ /* get pivot column from head of minimum degree list */ while (head [min_score] == EMPTY && min_score < n_col) { min_score++ ; } pivot_col = head [min_score] ; ASSERT (pivot_col >= 0 && pivot_col <= n_col) ; next_col = Col [pivot_col].shared4.degree_next ; head [min_score] = next_col ; if (next_col != EMPTY) { Col [next_col].shared3.prev = EMPTY ; } ASSERT (COL_IS_ALIVE (pivot_col)) ; /* remember score for defrag check */ pivot_col_score = Col [pivot_col].shared2.score ; /* the pivot column is the kth column in the pivot order */ Col [pivot_col].shared2.order = k ; /* increment order count by column thickness */ pivot_col_thickness = Col [pivot_col].shared1.thickness ; k += pivot_col_thickness ; ASSERT (pivot_col_thickness > 0) ; DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ; /* === Garbage_collection, if necessary ============================= */ needed_memory = MIN (pivot_col_score, n_col - k) ; if (pfree + needed_memory >= Alen) { pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; ngarbage++ ; /* after garbage collection we will have enough */ ASSERT (pfree + needed_memory < Alen) ; /* garbage collection has wiped out the Row[].shared2.mark array */ tag_mark = clear_mark (0, max_mark, n_row, Row) ; #ifndef NDEBUG debug_matrix (n_row, n_col, Row, Col, A) ; #endif /* NDEBUG */ } /* === Compute pivot row pattern ==================================== */ /* get starting location for this new merged row */ pivot_row_start = pfree ; /* initialize new row counts to zero */ pivot_row_degree = 0 ; /* tag pivot column as having been visited so it isn't included */ /* in merged pivot row */ Col [pivot_col].shared1.thickness = -pivot_col_thickness ; /* pivot row is the union of all rows in the pivot column pattern */ cp = &A [Col [pivot_col].start] ; cp_end = cp + Col [pivot_col].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ; /* skip if row is dead */ if (ROW_IS_ALIVE (row)) { rp = &A [Row [row].start] ; rp_end = rp + Row [row].length ; while (rp < rp_end) { /* get a column */ col = *rp++ ; /* add the column, if alive and untagged */ col_thickness = Col [col].shared1.thickness ; if (col_thickness > 0 && COL_IS_ALIVE (col)) { /* tag column in pivot row */ Col [col].shared1.thickness = -col_thickness ; ASSERT (pfree < Alen) ; /* place column in pivot row */ A [pfree++] = col ; pivot_row_degree += col_thickness ; } } } } /* clear tag on pivot column */ Col [pivot_col].shared1.thickness = pivot_col_thickness ; max_deg = MAX (max_deg, pivot_row_degree) ; #ifndef NDEBUG DEBUG3 (("check2\n")) ; debug_mark (n_row, Row, tag_mark, max_mark) ; #endif /* NDEBUG */ /* === Kill all rows used to construct pivot row ==================== */ /* also kill pivot row, temporarily */ cp = &A [Col [pivot_col].start] ; cp_end = cp + Col [pivot_col].length ; while (cp < cp_end) { /* may be killing an already dead row */ row = *cp++ ; DEBUG3 (("Kill row in pivot col: %d\n", row)) ; KILL_ROW (row) ; } /* === Select a row index to use as the new pivot row =============== */ pivot_row_length = pfree - pivot_row_start ; if (pivot_row_length > 0) { /* pick the "pivot" row arbitrarily (first row in col) */ pivot_row = A [Col [pivot_col].start] ; DEBUG3 (("Pivotal row is %d\n", pivot_row)) ; } else { /* there is no pivot row, since it is of zero length */ pivot_row = EMPTY ; ASSERT (pivot_row_length == 0) ; } ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ; /* === Approximate degree computation =============================== */ /* Here begins the computation of the approximate degree. The column */ /* score is the sum of the pivot row "length", plus the size of the */ /* set differences of each row in the column minus the pattern of the */ /* pivot row itself. The column ("thickness") itself is also */ /* excluded from the column score (we thus use an approximate */ /* external degree). */ /* The time taken by the following code (compute set differences, and */ /* add them up) is proportional to the size of the data structure */ /* being scanned - that is, the sum of the sizes of each column in */ /* the pivot row. Thus, the amortized time to compute a column score */ /* is proportional to the size of that column (where size, in this */ /* context, is the column "length", or the number of row indices */ /* in that column). The number of row indices in a column is */ /* monotonically non-decreasing, from the length of the original */ /* column on input to colamd. */ /* === Compute set differences ====================================== */ DEBUG3 (("** Computing set differences phase. **\n")) ; /* pivot row is currently dead - it will be revived later. */ DEBUG3 (("Pivot row: ")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { col = *rp++ ; ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; DEBUG3 (("Col: %d\n", col)) ; /* clear tags used to construct pivot row pattern */ col_thickness = -Col [col].shared1.thickness ; ASSERT (col_thickness > 0) ; Col [col].shared1.thickness = col_thickness ; /* === Remove column from degree list =========================== */ cur_score = Col [col].shared2.score ; prev_col = Col [col].shared3.prev ; next_col = Col [col].shared4.degree_next ; ASSERT (cur_score >= 0) ; ASSERT (cur_score <= n_col) ; ASSERT (cur_score >= EMPTY) ; if (prev_col == EMPTY) { head [cur_score] = next_col ; } else { Col [prev_col].shared4.degree_next = next_col ; } if (next_col != EMPTY) { Col [next_col].shared3.prev = prev_col ; } /* === Scan the column ========================================== */ cp = &A [Col [col].start] ; cp_end = cp + Col [col].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; row_mark = Row [row].shared2.mark ; /* skip if dead */ if (ROW_IS_MARKED_DEAD (row_mark)) { continue ; } ASSERT (row != pivot_row) ; set_difference = row_mark - tag_mark ; /* check if the row has been seen yet */ if (set_difference < 0) { ASSERT (Row [row].shared1.degree <= max_deg) ; set_difference = Row [row].shared1.degree ; } /* subtract column thickness from this row's set difference */ set_difference -= col_thickness ; ASSERT (set_difference >= 0) ; /* absorb this row if the set difference becomes zero */ if (set_difference == 0 && aggressive) { DEBUG3 (("aggressive absorption. Row: %d\n", row)) ; KILL_ROW (row) ; } else { /* save the new mark */ Row [row].shared2.mark = set_difference + tag_mark ; } } } #ifndef NDEBUG debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k-pivot_row_degree, max_deg) ; #endif /* NDEBUG */ /* === Add up set differences for each column ======================= */ DEBUG3 (("** Adding set differences phase. **\n")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { /* get a column */ col = *rp++ ; ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; hash = 0 ; cur_score = 0 ; cp = &A [Col [col].start] ; /* compact the column */ new_cp = cp ; cp_end = cp + Col [col].length ; DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ; while (cp < cp_end) { /* get a row */ row = *cp++ ; ASSERT(row >= 0 && row < n_row) ; row_mark = Row [row].shared2.mark ; /* skip if dead */ if (ROW_IS_MARKED_DEAD (row_mark)) { DEBUG4 ((" Row %d, dead\n", row)) ; continue ; } DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark)); ASSERT (row_mark >= tag_mark) ; /* compact the column */ *new_cp++ = row ; /* compute hash function */ hash += row ; /* add set difference */ cur_score += row_mark - tag_mark ; /* integer overflow... */ cur_score = MIN (cur_score, n_col) ; } /* recompute the column's length */ Col [col].length = (Int) (new_cp - &A [Col [col].start]) ; /* === Further mass elimination ================================= */ if (Col [col].length == 0) { DEBUG4 (("further mass elimination. Col: %d\n", col)) ; /* nothing left but the pivot row in this column */ KILL_PRINCIPAL_COL (col) ; pivot_row_degree -= Col [col].shared1.thickness ; ASSERT (pivot_row_degree >= 0) ; /* order it */ Col [col].shared2.order = k ; /* increment order count by column thickness */ k += Col [col].shared1.thickness ; } else { /* === Prepare for supercolumn detection ==================== */ DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ; /* save score so far */ Col [col].shared2.score = cur_score ; /* add column to hash table, for supercolumn detection */ hash %= n_col + 1 ; DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; ASSERT (((Int) hash) <= n_col) ; head_column = head [hash] ; if (head_column > EMPTY) { /* degree list "hash" is non-empty, use prev (shared3) of */ /* first column in degree list as head of hash bucket */ first_col = Col [head_column].shared3.headhash ; Col [head_column].shared3.headhash = col ; } else { /* degree list "hash" is empty, use head as hash bucket */ first_col = - (head_column + 2) ; head [hash] = - (col + 2) ; } Col [col].shared4.hash_next = first_col ; /* save hash function in Col [col].shared3.hash */ Col [col].shared3.hash = (Int) hash ; ASSERT (COL_IS_ALIVE (col)) ; } } /* The approximate external column degree is now computed. */ /* === Supercolumn detection ======================================== */ DEBUG3 (("** Supercolumn detection phase. **\n")) ; detect_super_cols ( #ifndef NDEBUG n_col, Row, #endif /* NDEBUG */ Col, A, head, pivot_row_start, pivot_row_length) ; /* === Kill the pivotal column ====================================== */ KILL_PRINCIPAL_COL (pivot_col) ; /* === Clear mark =================================================== */ tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ; #ifndef NDEBUG DEBUG3 (("check3\n")) ; debug_mark (n_row, Row, tag_mark, max_mark) ; #endif /* NDEBUG */ /* === Finalize the new pivot row, and column scores ================ */ DEBUG3 (("** Finalize scores phase. **\n")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; /* compact the pivot row */ new_rp = rp ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { col = *rp++ ; /* skip dead columns */ if (COL_IS_DEAD (col)) { continue ; } *new_rp++ = col ; /* add new pivot row to column */ A [Col [col].start + (Col [col].length++)] = pivot_row ; /* retrieve score so far and add on pivot row's degree. */ /* (we wait until here for this in case the pivot */ /* row's degree was reduced due to mass elimination). */ cur_score = Col [col].shared2.score + pivot_row_degree ; /* calculate the max possible score as the number of */ /* external columns minus the 'k' value minus the */ /* columns thickness */ max_score = n_col - k - Col [col].shared1.thickness ; /* make the score the external degree of the union-of-rows */ cur_score -= Col [col].shared1.thickness ; /* make sure score is less or equal than the max score */ cur_score = MIN (cur_score, max_score) ; ASSERT (cur_score >= 0) ; /* store updated score */ Col [col].shared2.score = cur_score ; /* === Place column back in degree list ========================= */ ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (cur_score >= 0) ; ASSERT (cur_score <= n_col) ; ASSERT (head [cur_score] >= EMPTY) ; next_col = head [cur_score] ; Col [col].shared4.degree_next = next_col ; Col [col].shared3.prev = EMPTY ; if (next_col != EMPTY) { Col [next_col].shared3.prev = col ; } head [cur_score] = col ; /* see if this score is less than current min */ min_score = MIN (min_score, cur_score) ; } #ifndef NDEBUG debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k, max_deg) ; #endif /* NDEBUG */ /* === Resurrect the new pivot row ================================== */ if (pivot_row_degree > 0) { /* update pivot row length to reflect any cols that were killed */ /* during super-col detection and mass elimination */ Row [pivot_row].start = pivot_row_start ; Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ; ASSERT (Row [pivot_row].length > 0) ; Row [pivot_row].shared1.degree = pivot_row_degree ; Row [pivot_row].shared2.mark = 0 ; /* pivot row is no longer dead */ DEBUG1 (("Resurrect Pivot_row %d deg: %d\n", pivot_row, pivot_row_degree)) ; } } /* === All principal columns have now been ordered ====================== */ return (ngarbage) ; } /* ========================================================================== */ /* === order_children ======================================================= */ /* ========================================================================== */ /* The find_ordering routine has ordered all of the principal columns (the representatives of the supercolumns). The non-principal columns have not yet been ordered. This routine orders those columns by walking up the parent tree (a column is a child of the column which absorbed it). The final permutation vector is then placed in p [0 ... n_col-1], with p [0] being the first column, and p [n_col-1] being the last. It doesn't look like it at first glance, but be assured that this routine takes time linear in the number of columns. Although not immediately obvious, the time taken by this routine is O (n_col), that is, linear in the number of columns. Not user-callable. */ PRIVATE void order_children ( /* === Parameters ======================================================= */ Int n_col, /* number of columns of A */ Colamd_Col Col [], /* of size n_col+1 */ Int p [] /* p [0 ... n_col-1] is the column permutation*/ ) { /* === Local variables ================================================== */ Int i ; /* loop counter for all columns */ Int c ; /* column index */ Int parent ; /* index of column's parent */ Int order ; /* column's order */ /* === Order each non-principal column ================================== */ for (i = 0 ; i < n_col ; i++) { /* find an un-ordered non-principal column */ ASSERT (COL_IS_DEAD (i)) ; if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY) { parent = i ; /* once found, find its principal parent */ do { parent = Col [parent].shared1.parent ; } while (!COL_IS_DEAD_PRINCIPAL (parent)) ; /* now, order all un-ordered non-principal columns along path */ /* to this parent. collapse tree at the same time */ c = i ; /* get order of parent */ order = Col [parent].shared2.order ; do { ASSERT (Col [c].shared2.order == EMPTY) ; /* order this column */ Col [c].shared2.order = order++ ; /* collaps tree */ Col [c].shared1.parent = parent ; /* get immediate parent of this column */ c = Col [c].shared1.parent ; /* continue until we hit an ordered column. There are */ /* guarranteed not to be anymore unordered columns */ /* above an ordered column */ } while (Col [c].shared2.order == EMPTY) ; /* re-order the super_col parent to largest order for this group */ Col [parent].shared2.order = order ; } } /* === Generate the permutation ========================================= */ for (c = 0 ; c < n_col ; c++) { p [Col [c].shared2.order] = c ; } } /* ========================================================================== */ /* === detect_super_cols ==================================================== */ /* ========================================================================== */ /* Detects supercolumns by finding matches between columns in the hash buckets. Check amongst columns in the set A [row_start ... row_start + row_length-1]. The columns under consideration are currently *not* in the degree lists, and have already been placed in the hash buckets. The hash bucket for columns whose hash function is equal to h is stored as follows: if head [h] is >= 0, then head [h] contains a degree list, so: head [h] is the first column in degree bucket h. Col [head [h]].headhash gives the first column in hash bucket h. otherwise, the degree list is empty, and: -(head [h] + 2) is the first column in hash bucket h. For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous column" pointer. Col [c].shared3.hash is used instead as the hash number for that column. The value of Col [c].shared4.hash_next is the next column in the same hash bucket. Assuming no, or "few" hash collisions, the time taken by this routine is linear in the sum of the sizes (lengths) of each column whose score has just been computed in the approximate degree computation. Not user-callable. */ PRIVATE void detect_super_cols ( /* === Parameters ======================================================= */ #ifndef NDEBUG /* these two parameters are only needed when debugging is enabled: */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ #endif /* NDEBUG */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* row indices of A */ Int head [], /* head of degree lists and hash buckets */ Int row_start, /* pointer to set of columns to check */ Int row_length /* number of columns to check */ ) { /* === Local variables ================================================== */ Int hash ; /* hash value for a column */ Int *rp ; /* pointer to a row */ Int c ; /* a column index */ Int super_c ; /* column index of the column to absorb into */ Int *cp1 ; /* column pointer for column super_c */ Int *cp2 ; /* column pointer for column c */ Int length ; /* length of column super_c */ Int prev_c ; /* column preceding c in hash bucket */ Int i ; /* loop counter */ Int *rp_end ; /* pointer to the end of the row */ Int col ; /* a column index in the row to check */ Int head_column ; /* first column in hash bucket or degree list */ Int first_col ; /* first column in hash bucket */ /* === Consider each column in the row ================================== */ rp = &A [row_start] ; rp_end = rp + row_length ; while (rp < rp_end) { col = *rp++ ; if (COL_IS_DEAD (col)) { continue ; } /* get hash number for this column */ hash = Col [col].shared3.hash ; ASSERT (hash <= n_col) ; /* === Get the first column in this hash bucket ===================== */ head_column = head [hash] ; if (head_column > EMPTY) { first_col = Col [head_column].shared3.headhash ; } else { first_col = - (head_column + 2) ; } /* === Consider each column in the hash bucket ====================== */ for (super_c = first_col ; super_c != EMPTY ; super_c = Col [super_c].shared4.hash_next) { ASSERT (COL_IS_ALIVE (super_c)) ; ASSERT (Col [super_c].shared3.hash == hash) ; length = Col [super_c].length ; /* prev_c is the column preceding column c in the hash bucket */ prev_c = super_c ; /* === Compare super_c with all columns after it ================ */ for (c = Col [super_c].shared4.hash_next ; c != EMPTY ; c = Col [c].shared4.hash_next) { ASSERT (c != super_c) ; ASSERT (COL_IS_ALIVE (c)) ; ASSERT (Col [c].shared3.hash == hash) ; /* not identical if lengths or scores are different */ if (Col [c].length != length || Col [c].shared2.score != Col [super_c].shared2.score) { prev_c = c ; continue ; } /* compare the two columns */ cp1 = &A [Col [super_c].start] ; cp2 = &A [Col [c].start] ; for (i = 0 ; i < length ; i++) { /* the columns are "clean" (no dead rows) */ ASSERT (ROW_IS_ALIVE (*cp1)) ; ASSERT (ROW_IS_ALIVE (*cp2)) ; /* row indices will same order for both supercols, */ /* no gather scatter nessasary */ if (*cp1++ != *cp2++) { break ; } } /* the two columns are different if the for-loop "broke" */ if (i != length) { prev_c = c ; continue ; } /* === Got it! two columns are identical =================== */ ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ; Col [super_c].shared1.thickness += Col [c].shared1.thickness ; Col [c].shared1.parent = super_c ; KILL_NON_PRINCIPAL_COL (c) ; /* order c later, in order_children() */ Col [c].shared2.order = EMPTY ; /* remove c from hash bucket */ Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; } } /* === Empty this hash bucket ======================================= */ if (head_column > EMPTY) { /* corresponding degree list "hash" is not empty */ Col [head_column].shared3.headhash = EMPTY ; } else { /* corresponding degree list "hash" is empty */ head [hash] = EMPTY ; } } } /* ========================================================================== */ /* === garbage_collection =================================================== */ /* ========================================================================== */ /* Defragments and compacts columns and rows in the workspace A. Used when all avaliable memory has been used while performing row merging. Returns the index of the first free position in A, after garbage collection. The time taken by this routine is linear is the size of the array A, which is itself linear in the number of nonzeros in the input matrix. Not user-callable. */ PRIVATE Int garbage_collection /* returns the new value of pfree */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows */ Int n_col, /* number of columns */ Colamd_Row Row [], /* row info */ Colamd_Col Col [], /* column info */ Int A [], /* A [0 ... Alen-1] holds the matrix */ Int *pfree /* &A [0] ... pfree is in use */ ) { /* === Local variables ================================================== */ Int *psrc ; /* source pointer */ Int *pdest ; /* destination pointer */ Int j ; /* counter */ Int r ; /* a row index */ Int c ; /* a column index */ Int length ; /* length of a row or column */ #ifndef NDEBUG Int debug_rows ; DEBUG2 (("Defrag..\n")) ; for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ; debug_rows = 0 ; #endif /* NDEBUG */ /* === Defragment the columns =========================================== */ pdest = &A[0] ; for (c = 0 ; c < n_col ; c++) { if (COL_IS_ALIVE (c)) { psrc = &A [Col [c].start] ; /* move and compact the column */ ASSERT (pdest <= psrc) ; Col [c].start = (Int) (pdest - &A [0]) ; length = Col [c].length ; for (j = 0 ; j < length ; j++) { r = *psrc++ ; if (ROW_IS_ALIVE (r)) { *pdest++ = r ; } } Col [c].length = (Int) (pdest - &A [Col [c].start]) ; } } /* === Prepare to defragment the rows =================================== */ for (r = 0 ; r < n_row ; r++) { if (ROW_IS_DEAD (r) || (Row [r].length == 0)) { /* This row is already dead, or is of zero length. Cannot compact * a row of zero length, so kill it. NOTE: in the current version, * there are no zero-length live rows. Kill the row (for the first * time, or again) just to be safe. */ KILL_ROW (r) ; } else { /* save first column index in Row [r].shared2.first_column */ psrc = &A [Row [r].start] ; Row [r].shared2.first_column = *psrc ; ASSERT (ROW_IS_ALIVE (r)) ; /* flag the start of the row with the one's complement of row */ *psrc = ONES_COMPLEMENT (r) ; #ifndef NDEBUG debug_rows++ ; #endif /* NDEBUG */ } } /* === Defragment the rows ============================================== */ psrc = pdest ; while (psrc < pfree) { /* find a negative number ... the start of a row */ if (*psrc++ < 0) { psrc-- ; /* get the row index */ r = ONES_COMPLEMENT (*psrc) ; ASSERT (r >= 0 && r < n_row) ; /* restore first column index */ *psrc = Row [r].shared2.first_column ; ASSERT (ROW_IS_ALIVE (r)) ; ASSERT (Row [r].length > 0) ; /* move and compact the row */ ASSERT (pdest <= psrc) ; Row [r].start = (Int) (pdest - &A [0]) ; length = Row [r].length ; for (j = 0 ; j < length ; j++) { c = *psrc++ ; if (COL_IS_ALIVE (c)) { *pdest++ = c ; } } Row [r].length = (Int) (pdest - &A [Row [r].start]) ; ASSERT (Row [r].length > 0) ; #ifndef NDEBUG debug_rows-- ; #endif /* NDEBUG */ } } /* ensure we found all the rows */ ASSERT (debug_rows == 0) ; /* === Return the new value of pfree ==================================== */ return ((Int) (pdest - &A [0])) ; } /* ========================================================================== */ /* === clear_mark =========================================================== */ /* ========================================================================== */ /* Clears the Row [].shared2.mark array, and returns the new tag_mark. Return value is the new tag_mark. Not user-callable. */ PRIVATE Int clear_mark /* return the new value for tag_mark */ ( /* === Parameters ======================================================= */ Int tag_mark, /* new value of tag_mark */ Int max_mark, /* max allowed value of tag_mark */ Int n_row, /* number of rows in A */ Colamd_Row Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ ) { /* === Local variables ================================================== */ Int r ; if (tag_mark <= 0 || tag_mark >= max_mark) { for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { Row [r].shared2.mark = 0 ; } } tag_mark = 1 ; } return (tag_mark) ; } /* ========================================================================== */ /* === print_report ========================================================= */ /* ========================================================================== */ PRIVATE void print_report ( char *method, Int stats [COLAMD_STATS] ) { Int i1, i2, i3 ; PRINTF (("\n%s version %d.%d, %s: ", method, COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ; if (!stats) { PRINTF (("No statistics available.\n")) ; return ; } i1 = stats [COLAMD_INFO1] ; i2 = stats [COLAMD_INFO2] ; i3 = stats [COLAMD_INFO3] ; if (stats [COLAMD_STATUS] >= 0) { PRINTF (("OK. ")) ; } else { PRINTF (("ERROR. ")) ; } switch (stats [COLAMD_STATUS]) { case COLAMD_OK_BUT_JUMBLED: PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ; PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n", method, i3)) ; PRINTF(("%s: last seen duplicate or out-of-order row index: %d\n", method, INDEX (i2))) ; PRINTF(("%s: last seen in column: %d", method, INDEX (i1))) ; /* no break - fall through to next case instead */ case COLAMD_OK: PRINTF(("\n")) ; PRINTF(("%s: number of dense or empty rows ignored: %d\n", method, stats [COLAMD_DENSE_ROW])) ; PRINTF(("%s: number of dense or empty columns ignored: %d\n", method, stats [COLAMD_DENSE_COL])) ; PRINTF(("%s: number of garbage collections performed: %d\n", method, stats [COLAMD_DEFRAG_COUNT])) ; break ; case COLAMD_ERROR_A_not_present: PRINTF(("Array A (row indices of matrix) not present.\n")) ; break ; case COLAMD_ERROR_p_not_present: PRINTF(("Array p (column pointers for matrix) not present.\n")) ; break ; case COLAMD_ERROR_nrow_negative: PRINTF(("Invalid number of rows (%d).\n", i1)) ; break ; case COLAMD_ERROR_ncol_negative: PRINTF(("Invalid number of columns (%d).\n", i1)) ; break ; case COLAMD_ERROR_nnz_negative: PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ; break ; case COLAMD_ERROR_p0_nonzero: PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1)); break ; case COLAMD_ERROR_A_too_small: PRINTF(("Array A too small.\n")) ; PRINTF((" Need Alen >= %d, but given only Alen = %d.\n", i1, i2)) ; break ; case COLAMD_ERROR_col_length_negative: PRINTF (("Column %d has a negative number of nonzero entries (%d).\n", INDEX (i1), i2)) ; break ; case COLAMD_ERROR_row_index_out_of_bounds: PRINTF (("Row index (row %d) out of bounds (%d to %d) in column %d.\n", INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ; break ; case COLAMD_ERROR_out_of_memory: PRINTF(("Out of memory.\n")) ; break ; /* v2.4: internal-error case deleted */ } } /* ========================================================================== */ /* === colamd debugging routines ============================================ */ /* ========================================================================== */ /* When debugging is disabled, the remainder of this file is ignored. */ #ifndef NDEBUG /* ========================================================================== */ /* === debug_structures ===================================================== */ /* ========================================================================== */ /* At this point, all empty rows and columns are dead. All live columns are "clean" (containing no dead rows) and simplicial (no supercolumns yet). Rows may contain dead columns, but all live rows contain at least one live column. */ PRIVATE void debug_structures ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int n_col2 ) { /* === Local variables ================================================== */ Int i ; Int c ; Int *cp ; Int *cp_end ; Int len ; Int score ; Int r ; Int *rp ; Int *rp_end ; Int deg ; /* === Check A, Row, and Col ============================================ */ for (c = 0 ; c < n_col ; c++) { if (COL_IS_ALIVE (c)) { len = Col [c].length ; score = Col [c].shared2.score ; DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ; ASSERT (len > 0) ; ASSERT (score >= 0) ; ASSERT (Col [c].shared1.thickness == 1) ; cp = &A [Col [c].start] ; cp_end = cp + len ; while (cp < cp_end) { r = *cp++ ; ASSERT (ROW_IS_ALIVE (r)) ; } } else { i = Col [c].shared2.order ; ASSERT (i >= n_col2 && i < n_col) ; } } for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { i = 0 ; len = Row [r].length ; deg = Row [r].shared1.degree ; ASSERT (len > 0) ; ASSERT (deg > 0) ; rp = &A [Row [r].start] ; rp_end = rp + len ; while (rp < rp_end) { c = *rp++ ; if (COL_IS_ALIVE (c)) { i++ ; } } ASSERT (i > 0) ; } } } /* ========================================================================== */ /* === debug_deg_lists ====================================================== */ /* ========================================================================== */ /* Prints the contents of the degree lists. Counts the number of columns in the degree list and compares it to the total it should have. Also checks the row degrees. */ PRIVATE void debug_deg_lists ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int head [], Int min_score, Int should, Int max_deg ) { /* === Local variables ================================================== */ Int deg ; Int col ; Int have ; Int row ; /* === Check the degree lists =========================================== */ if (n_col > 10000 && colamd_debug <= 0) { return ; } have = 0 ; DEBUG4 (("Degree lists: %d\n", min_score)) ; for (deg = 0 ; deg <= n_col ; deg++) { col = head [deg] ; if (col == EMPTY) { continue ; } DEBUG4 (("%d:", deg)) ; while (col != EMPTY) { DEBUG4 ((" %d", col)) ; have += Col [col].shared1.thickness ; ASSERT (COL_IS_ALIVE (col)) ; col = Col [col].shared4.degree_next ; } DEBUG4 (("\n")) ; } DEBUG4 (("should %d have %d\n", should, have)) ; ASSERT (should == have) ; /* === Check the row degrees ============================================ */ if (n_row > 10000 && colamd_debug <= 0) { return ; } for (row = 0 ; row < n_row ; row++) { if (ROW_IS_ALIVE (row)) { ASSERT (Row [row].shared1.degree <= max_deg) ; } } } /* ========================================================================== */ /* === debug_mark =========================================================== */ /* ========================================================================== */ /* Ensures that the tag_mark is less that the maximum and also ensures that each entry in the mark array is less than the tag mark. */ PRIVATE void debug_mark ( /* === Parameters ======================================================= */ Int n_row, Colamd_Row Row [], Int tag_mark, Int max_mark ) { /* === Local variables ================================================== */ Int r ; /* === Check the Row marks ============================================== */ ASSERT (tag_mark > 0 && tag_mark <= max_mark) ; if (n_row > 10000 && colamd_debug <= 0) { return ; } for (r = 0 ; r < n_row ; r++) { ASSERT (Row [r].shared2.mark < tag_mark) ; } } /* ========================================================================== */ /* === debug_matrix ========================================================= */ /* ========================================================================== */ /* Prints out the contents of the columns and the rows. */ PRIVATE void debug_matrix ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [] ) { /* === Local variables ================================================== */ Int r ; Int c ; Int *rp ; Int *rp_end ; Int *cp ; Int *cp_end ; /* === Dump the rows and columns of the matrix ========================== */ if (colamd_debug < 3) { return ; } DEBUG3 (("DUMP MATRIX:\n")) ; for (r = 0 ; r < n_row ; r++) { DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ; if (ROW_IS_DEAD (r)) { continue ; } DEBUG3 (("start %d length %d degree %d\n", Row [r].start, Row [r].length, Row [r].shared1.degree)) ; rp = &A [Row [r].start] ; rp_end = rp + Row [r].length ; while (rp < rp_end) { c = *rp++ ; DEBUG4 ((" %d col %d\n", COL_IS_ALIVE (c), c)) ; } } for (c = 0 ; c < n_col ; c++) { DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ; if (COL_IS_DEAD (c)) { continue ; } DEBUG3 (("start %d length %d shared1 %d shared2 %d\n", Col [c].start, Col [c].length, Col [c].shared1.thickness, Col [c].shared2.score)) ; cp = &A [Col [c].start] ; cp_end = cp + Col [c].length ; while (cp < cp_end) { r = *cp++ ; DEBUG4 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; } } } PRIVATE void colamd_get_debug ( char *method ) { FILE *f ; colamd_debug = 0 ; /* no debug printing */ f = fopen ("debug", "r") ; if (f == (FILE *) NULL) { colamd_debug = 0 ; } else { fscanf (f, "%d", &colamd_debug) ; fclose (f) ; } DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n", method, colamd_debug)) ; } #endif /* NDEBUG */ cvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Lib/0000755000175000017500000000000011674452555016771 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/COLAMD/Lib/Makefile0000644000175000017500000000143711674452555020436 0ustar sonnesonne#------------------------------------------------------------------------------- # COLAMD Makefile #------------------------------------------------------------------------------- default: libcolamd.a include ../../UFconfig/UFconfig.mk I = -I../Include -I../../UFconfig INC = ../Include/colamd.h ../../UFconfig/UFconfig.h SRC = ../Source/colamd.c ../Source/colamd_global.c # creates libcolamd.a, a C-callable COLAMD library libcolamd.a: $(SRC) $(INC) $(CC) $(CFLAGS) $(I) -c ../Source/colamd_global.c $(CC) $(CFLAGS) $(I) -c ../Source/colamd.c $(CC) $(CFLAGS) $(I) -c ../Source/colamd.c -DDLONG -o colamd_l.o $(AR) libcolamd.a colamd.o colamd_l.o colamd_global.o ccode: libcolamd.a library: libcolamd.a clean: - $(RM) $(CLEAN) purge: distclean distclean: clean - $(RM) libcolamd.a cvxopt-1.1.4/src/C/SuiteSparse/Makefile0000644000175000017500000000633411674452555016772 0ustar sonnesonne#------------------------------------------------------------------------------- # Makefile for all UF sparse matrix packages #------------------------------------------------------------------------------- include UFconfig/UFconfig.mk # Compile the default rules for each package default: ( cd UFconfig/xerbla ; $(MAKE) ) # ( cd metis-4.0 ; $(MAKE) ) ( cd AMD ; $(MAKE) ) ( cd CAMD ; $(MAKE) ) ( cd COLAMD ; $(MAKE) ) ( cd BTF ; $(MAKE) ) ( cd KLU ; $(MAKE) ) ( cd LDL ; $(MAKE) ) ( cd CCOLAMD ; $(MAKE) ) ( cd UMFPACK ; $(MAKE) ) ( cd CHOLMOD ; $(MAKE) ) ( cd CSparse ; $(MAKE) ) ( cd CXSparse ; $(MAKE) ) ( cd SPQR ; $(MAKE) ) # ( cd LPDASA ; $(MAKE) ) # ( cd PARAKLETE ; $(MAKE) ) library: default # Compile the MATLAB mexFunctions (except RBio and UFcollection) # CHOLMOD and KLU will fail if you don't have METIS (use SuiteSparse_install.m # in the MATLAB Command Window instead to compile them without METIS) mex: ( cd AMD ; $(MAKE) mex ) ( cd CAMD ; $(MAKE) mex ) ( cd COLAMD ; $(MAKE) mex ) ( cd BTF ; $(MAKE) mex ) ( cd LDL ; $(MAKE) mex ) ( cd CCOLAMD ; $(MAKE) mex ) ( cd CXSparse ; $(MAKE) mex ) ( cd CSparse ; $(MAKE) mex ) ( cd UMFPACK ; $(MAKE) mex ) ( cd SPQR ; $(MAKE) mex ) ( cd CHOLMOD ; $(MAKE) mex ) ( cd KLU ; $(MAKE) mex ) # Remove all files not in the original distribution purge: ( cd UFconfig/xerbla ; $(MAKE) purge ) # ( cd metis-4.0 ; $(MAKE) realclean ) ( cd AMD ; $(MAKE) purge ) ( cd CAMD ; $(MAKE) purge ) ( cd COLAMD ; $(MAKE) purge ) ( cd BTF ; $(MAKE) purge ) ( cd KLU ; $(MAKE) purge ) ( cd LDL ; $(MAKE) purge ) ( cd CCOLAMD ; $(MAKE) purge ) ( cd UMFPACK ; $(MAKE) purge ) ( cd CHOLMOD ; $(MAKE) purge ) ( cd CSparse ; $(MAKE) purge ) ( cd CXSparse ; $(MAKE) purge ) ( cd RBio ; $(RM) *.mex* ) ( cd UFcollection ; $(RM) *.mex* ) ( cd SSMULT ; $(RM) *.mex* ) ( cd SPQR ; $(MAKE) purge ) - $(RM) MATLAB_Tools/spok/*.mex* MATLAB_Tools/spok/private/*.mex* # ( cd LPDASA ; $(MAKE) purge ) # ( cd PARAKLETE ; $(MAKE) purge ) # Remove all files not in the original distribution, but keep the libraries clean: ( cd UFconfig/xerbla ; $(MAKE) clean ) # ( cd metis-4.0 ; $(MAKE) clean ) ( cd AMD ; $(MAKE) clean ) ( cd CAMD ; $(MAKE) clean ) ( cd COLAMD ; $(MAKE) clean ) ( cd BTF ; $(MAKE) clean ) ( cd KLU ; $(MAKE) clean ) ( cd LDL ; $(MAKE) clean ) ( cd CCOLAMD ; $(MAKE) clean ) ( cd UMFPACK ; $(MAKE) clean ) ( cd CHOLMOD ; $(MAKE) clean ) ( cd CSparse ; $(MAKE) clean ) ( cd CXSparse ; $(MAKE) clean ) ( cd SPQR ; $(MAKE) clean ) # ( cd LPDASA ; $(MAKE) clean ) # ( cd PARAKLETE ; $(MAKE) clean ) distclean: purge # Create CXSparse from CSparse. Note that the CXSparse directory should # initially not exist. cx: ( cd CSparse ; $(MAKE) purge ) ( cd CXSparse_newfiles ; tar cfv - * | gzip -9 > ../CXSparse_newfiles.tar.gz ) ./CSparse_to_CXSparse CSparse CXSparse CXSparse_newfiles.tar.gz ( cd CXSparse/Demo ; $(MAKE) ) ( cd CXSparse/Demo ; $(MAKE) > cs_demo.out ) ( cd CXSparse ; $(MAKE) purge ) # statement coverage (Linux only); this requires a lot of time. # The umfpack tcov requires a lot of disk space cov: ( cd CXSparse ; $(MAKE) cov ) ( cd CSparse ; $(MAKE) cov ) ( cd KLU ; $(MAKE) cov ) ( cd CHOLMOD ; $(MAKE) cov ) ( cd UMFPACK ; $(MAKE) cov ) ( cd SPQR ; $(MAKE) cov ) cvxopt-1.1.4/src/C/SuiteSparse/UFconfig/0000755000175000017500000000000011674452555017024 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/UFconfig/xerbla/0000755000175000017500000000000011674452555020301 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/UFconfig/xerbla/xerbla.f0000644000175000017500000000236011674452555021726 0ustar sonnesonne SUBROUTINE XERBLA( SRNAME, INFO ) * * -- LAPACK auxiliary routine (version 3.0) -- * Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., * Courant Institute, Argonne National Lab, and Rice University * September 30, 1994 * * .. Scalar Arguments .. CHARACTER*6 SRNAME INTEGER INFO * .. * * Purpose * ======= * * XERBLA is an error handler for the LAPACK routines. * It is called by an LAPACK routine if an input parameter has an * invalid value. A message is printed and execution stops. * * Installers may consider modifying the STOP statement in order to * call system-specific exception-handling facilities. * * Arguments * ========= * * SRNAME (input) CHARACTER*6 * The name of the routine which called XERBLA. * * INFO (input) INTEGER * The position of the invalid parameter in the parameter list * of the calling routine. * * ===================================================================== * * .. Executable Statements .. * ***** WRITE( *, FMT = 9999 )SRNAME, INFO * ***** STOP * ***** 9999 FORMAT( ' ** On entry to ', A6, ' parameter number ', I2, ' had ', ***** $ 'an illegal value' ) * * End of XERBLA * END cvxopt-1.1.4/src/C/SuiteSparse/UFconfig/xerbla/xerbla.h0000644000175000017500000000012211674452555021722 0ustar sonnesonnevoid xerbla_ (char *srname, int *info) ; void xerbla (char *srname, int *info) ; cvxopt-1.1.4/src/C/SuiteSparse/UFconfig/xerbla/Makefile0000644000175000017500000000071611674452555021745 0ustar sonnesonne# Makefile for null-output xerbla default: ccode include ../UFconfig.mk ccode: libcerbla.a fortran: libxerbla.a all: libxerbla.a libcerbla.a # Fortran version: libxerbla.a: xerbla.f $(F77) $(F77FLAGS) -c xerbla.f $(AR) libxerbla.a xerbla.o - $(RM) xerbla.o # C version: libcerbla.a: xerbla.c xerbla.h $(CC) $(CFLAGS) -c xerbla.c $(AR) libcerbla.a xerbla.o - $(RM) xerbla.o distclean: purge purge: clean - $(RM) *.o *.a clean: - $(RM) $(CLEAN) cvxopt-1.1.4/src/C/SuiteSparse/UFconfig/xerbla/xerbla.c0000644000175000017500000000020711674452555021721 0ustar sonnesonne void xerbla_ (char *srname, int *info) { /* do nothing */ ; } void xerbla (char *srname, int *info) { /* do nothing */ ; } cvxopt-1.1.4/src/C/SuiteSparse/UFconfig/README.txt0000644000175000017500000000315111674452555020522 0ustar sonnesonneUFconfig contains configuration settings for all many of the software packages that I develop or co-author. Note that older versions of some of these packages do not require UFconfig. Package Description ------- ----------- AMD approximate minimum degree ordering CAMD constrained AMD COLAMD column approximate minimum degree ordering CCOLAMD constrained approximate minimum degree ordering UMFPACK sparse LU factorization, with the BLAS CXSparse int/long/real/complex version of CSparse CHOLMOD sparse Cholesky factorization, update/downdate KLU sparse LU factorization, BLAS-free BTF permutation to block triangular form LDL concise sparse LDL' LPDASA LP Dual Active Set Algorithm SuiteSparseQR sparse QR factorization UFconfig is not required by: CSparse a Concise Sparse matrix package RBio read/write files in Rutherford/Boeing format UFcollection tools for managing the UF Sparse Matrix Collection LINFACTOR simple m-file to show how to use LU and CHOL to solve Ax=b MESHND 2D and 3D mesh generation and nested dissection ordering MATLAB_Tools misc collection of m-files SSMULT sparse matrix times sparse matrix, for use in MATLAB In addition, the xerbla/ directory contains Fortan and C versions of the BLAS/LAPACK xerbla routine, which is called when an invalid input is passed to the BLAS or LAPACK. The xerbla provided here does not print any message, so the entire Fortran I/O library does not need to be linked into a C application. Most versions of the BLAS contain xerbla, but those from K. Goto do not. Use this if you need too. cvxopt-1.1.4/src/C/SuiteSparse/UFconfig/UFconfig.mk0000644000175000017500000003053511674452555021063 0ustar sonnesonne#=============================================================================== # UFconfig.mk: common configuration file for the SuiteSparse #=============================================================================== # This file contains all configuration settings for all packages authored or # co-authored by Tim Davis at the University of Florida: # # Package Version Description # ------- ------- ----------- # AMD 1.2 or later approximate minimum degree ordering # COLAMD 2.4 or later column approximate minimum degree ordering # CCOLAMD 1.0 or later constrained column approximate minimum degree ordering # CAMD any constrained approximate minimum degree ordering # UMFPACK 4.5 or later sparse LU factorization, with the BLAS # CHOLMOD any sparse Cholesky factorization, update/downdate # KLU 0.8 or later sparse LU factorization, BLAS-free # BTF 0.8 or later permutation to block triangular form # LDL 1.2 or later concise sparse LDL' # LPDASA any linear program solve (dual active set algorithm) # CXSparse any extended version of CSparse (int/long, real/complex) # SuiteSparseQR any sparse QR factorization # # The UFconfig directory and the above packages should all appear in a single # directory, in order for the Makefile's within each package to find this file. # # To enable an option of the form "# OPTION = ...", edit this file and # delete the "#" in the first column of the option you wish to use. #------------------------------------------------------------------------------ # Generic configuration #------------------------------------------------------------------------------ # C compiler and compiler flags: These will normally not give you optimal # performance. You should select the optimization parameters that are best # for your system. On Linux, use "CFLAGS = -O3 -fexceptions" for example. CC = cc # CFLAGS = -O (for example; see below for details) # C++ compiler (also uses CFLAGS) CPLUSPLUS = g++ # ranlib, and ar, for generating libraries RANLIB = ranlib AR = ar cr # delete and rename a file RM = rm -f MV = mv -f # Fortran compiler (not normally required) F77 = f77 F77FLAGS = -O F77LIB = # C and Fortran libraries LIB = -lm # For compiling MATLAB mexFunctions (MATLAB 7.5 or later) MEX = mex -O -largeArrayDims -lmwlapack -lmwblas # For compiling MATLAB mexFunctions (MATLAB 7.3 and 7.4) # MEX = mex -O -largeArrayDims -lmwlapack # For MATLAB 7.2 or earlier, you must use one of these options: # MEX = mex -O -lmwlapack # MEX = mex -O # Which version of MAKE you are using (default is "make") # MAKE = make # MAKE = gmake #------------------------------------------------------------------------------ # BLAS and LAPACK configuration: #------------------------------------------------------------------------------ # UMFPACK and CHOLMOD both require the BLAS. CHOLMOD also requires LAPACK. # See Kazushige Goto's BLAS at http://www.cs.utexas.edu/users/flame/goto/ or # http://www.tacc.utexas.edu/~kgoto/ for the best BLAS to use with CHOLMOD. # LAPACK is at http://www.netlib.org/lapack/ . You can use the standard # Fortran LAPACK along with Goto's BLAS to obtain very good performance. # CHOLMOD gets a peak numeric factorization rate of 3.6 Gflops on a 3.2 GHz # Pentium 4 (512K cache, 4GB main memory) with the Goto BLAS, and 6 Gflops # on a 2.5Ghz dual-core AMD Opteron. # These settings will probably not work, since there is no fixed convention for # naming the BLAS and LAPACK library (*.a or *.so) files. # Using the Goto BLAS: # BLAS = -lgoto -lgfortran -lgfortranbegin -lg2c # This is probably slow ... it might connect to the Standard Reference BLAS: BLAS = -lblas -lgfortran -lgfortranbegin -lg2c LAPACK = -llapack # Using non-optimized versions: # BLAS = -lblas_plain -lgfortran -lgfortranbegin -lg2c # LAPACK = -llapack_plain # The BLAS might not contain xerbla, an error-handling routine for LAPACK and # the BLAS. Also, the standard xerbla requires the Fortran I/O library, and # stops the application program if an error occurs. A C version of xerbla # distributed with this software (UFconfig/xerbla/libcerbla.a) includes a # Fortran-callable xerbla routine that prints nothing and does not stop the # application program. This is optional. # XERBLA = ../../UFconfig/xerbla/libcerbla.a # If you wish to use the XERBLA in LAPACK and/or the BLAS instead, # use this option: XERBLA = # If you wish to use the Fortran UFconfig/xerbla/xerbla.f instead, use this: # XERBLA = ../../UFconfig/xerbla/libxerbla.a #------------------------------------------------------------------------------ # METIS, optionally used by CHOLMOD #------------------------------------------------------------------------------ # If you do not have METIS, or do not wish to use it in CHOLMOD, you must # compile CHOLMOD with the -DNPARTITION flag. You must also use the # "METIS =" option, below. # The path is relative to where it is used, in CHOLMOD/Lib, CHOLMOD/MATLAB, etc. # You may wish to use an absolute path. METIS is optional. Compile # CHOLMOD with -DNPARTITION if you do not wish to use METIS. METIS_PATH = ../../metis-4.0 METIS = ../../metis-4.0/libmetis.a # If you use CHOLMOD_CONFIG = -DNPARTITION then you must use the following # options: # METIS_PATH = # METIS = #------------------------------------------------------------------------------ # UMFPACK configuration: #------------------------------------------------------------------------------ # Configuration flags for UMFPACK. See UMFPACK/Source/umf_config.h for details. # # -DNBLAS do not use the BLAS. UMFPACK will be very slow. # -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by # LAPACK and the BLAS (defaults to 'int') # -DNSUNPERF do not use the Sun Perf. Library (default is use it on Solaris) # -DNPOSIX do not use POSIX routines sysconf and times. # -DGETRUSAGE use getrusage # -DNO_TIMER do not use any timing routines # -DNRECIPROCAL do not multiply by the reciprocal # -DNO_DIVIDE_BY_ZERO do not divide by zero UMFPACK_CONFIG = #------------------------------------------------------------------------------ # CHOLMOD configuration #------------------------------------------------------------------------------ # CHOLMOD Library Modules, which appear in libcholmod.a: # Core requires: none # Check requires: Core # Cholesky requires: Core, AMD, COLAMD. optional: Partition, Supernodal # MatrixOps requires: Core # Modify requires: Core # Partition requires: Core, CCOLAMD, METIS. optional: Cholesky # Supernodal requires: Core, BLAS, LAPACK # # CHOLMOD test/demo Modules (all are GNU GPL, do not appear in libcholmod.a): # Tcov requires: Core, Check, Cholesky, MatrixOps, Modify, Supernodal # optional: Partition # Valgrind same as Tcov # Demo requires: Core, Check, Cholesky, MatrixOps, Supernodal # optional: Partition # # Configuration flags: # -DNCHECK do not include the Check module. License GNU LGPL # -DNCHOLESKY do not include the Cholesky module. License GNU LGPL # -DNPARTITION do not include the Partition module. License GNU LGPL # also do not include METIS. # -DNGPL do not include any GNU GPL Modules in the CHOLMOD library: # -DNMATRIXOPS do not include the MatrixOps module. License GNU GPL # -DNMODIFY do not include the Modify module. License GNU GPL # -DNSUPERNODAL do not include the Supernodal module. License GNU GPL # # -DNPRINT do not print anything. # -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by # LAPACK and the BLAS (defaults to 'int') # -DNSUNPERF for Solaris only. If defined, do not use the Sun # Performance Library CHOLMOD_CONFIG = #------------------------------------------------------------------------------ # SuiteSparseQR configuration: #------------------------------------------------------------------------------ # The SuiteSparseQR library can be compiled with the following options: # # -DNPARTITION do not include the CHOLMOD partition module # -DNEXPERT do not include the functions in SuiteSparseQR_expert.cpp # -DTIMING enable timing and flop counts # -DHAVE_TBB enable the use of Intel's Threading Building Blocks (TBB) # default, without timing, without TBB: SPQR_CONFIG = # with timing and TBB: # SPQR_CONFIG = -DTIMING -DHAVE_TBB # with timing # SPQR_CONFIG = -DTIMING # with TBB, you must select this: # TBB = -ltbb # without TBB: TBB = # with timing, you must include the timing library: # RTLIB = -lrt # without timing RTLIB = #------------------------------------------------------------------------------ # Linux #------------------------------------------------------------------------------ # Using default compilers: # CC = gcc CFLAGS = -O3 -fexceptions # alternatives: # CFLAGS = -g -fexceptions \ -Wall -W -Wshadow -Wmissing-prototypes -Wstrict-prototypes \ -Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi # CFLAGS = -O3 -fexceptions \ -Wall -W -Werror -Wshadow -Wmissing-prototypes -Wstrict-prototypes \ -Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi # CFLAGS = -O3 -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE # CFLAGS = -O3 # CFLAGS = -O3 -g -fexceptions # CFLAGS = -g -fexceptions \ -Wall -W -Wshadow \ -Wredundant-decls -Wdisabled-optimization -ansi # consider: # -fforce-addr -fmove-all-movables -freduce-all-givs -ftsp-ordering # -frename-registers -ffast-math -funroll-loops # Using the Goto BLAS: # BLAS = -lgoto -lfrtbegin -lg2c $(XERBLA) -lpthread # Using Intel's icc and ifort compilers: # (does not work for mexFunctions unless you add a mexopts.sh file) # F77 = ifort # CC = icc # CFLAGS = -O3 -xN -vec_report=0 # CFLAGS = -g # old (broken): CFLAGS = -ansi -O3 -ip -tpp7 -xW -vec_report0 # 64bit: # F77FLAGS = -O -m64 # CFLAGS = -O3 -fexceptions -m64 # BLAS = -lgoto64 -lfrtbegin -lg2c -lpthread $(XERBLA) # LAPACK = -llapack64 # SUSE Linux 10.1, AMD Opteron, with GOTO Blas # F77 = gfortran # BLAS = -lgoto_opteron64 -lgfortran # SUSE Linux 10.1, Intel Pentium, with GOTO Blas # F77 = gfortran # BLAS = -lgoto -lgfortran #------------------------------------------------------------------------------ # Solaris #------------------------------------------------------------------------------ # 32-bit # CFLAGS = -KPIC -dalign -xc99=%none -Xc -xlibmieee -xO5 -xlibmil -m32 # 64-bit # CFLAGS = -fast -KPIC -xc99=%none -xlibmieee -xlibmil -m64 -Xc # FFLAGS = -fast -KPIC -dalign -xlibmil -m64 # The Sun Performance Library includes both LAPACK and the BLAS: # BLAS = -xlic_lib=sunperf # LAPACK = #------------------------------------------------------------------------------ # Compaq Alpha #------------------------------------------------------------------------------ # 64-bit mode only # CFLAGS = -O2 -std1 # BLAS = -ldxml # LAPACK = #------------------------------------------------------------------------------ # Macintosh #------------------------------------------------------------------------------ # CC = gcc # CFLAGS = -O3 -fno-common -no-cpp-precomp -fexceptions # LIB = -lstdc++ # BLAS = -framework Accelerate # LAPACK = -framework Accelerate #------------------------------------------------------------------------------ # IBM RS 6000 #------------------------------------------------------------------------------ # BLAS = -lessl # LAPACK = # 32-bit mode: # CFLAGS = -O4 -qipa -qmaxmem=16384 -qproto # F77FLAGS = -O4 -qipa -qmaxmem=16384 # 64-bit mode: # CFLAGS = -O4 -qipa -qmaxmem=16384 -q64 -qproto # F77FLAGS = -O4 -qipa -qmaxmem=16384 -q64 # AR = ar -X64 #------------------------------------------------------------------------------ # SGI IRIX #------------------------------------------------------------------------------ # BLAS = -lscsl # LAPACK = # 32-bit mode # CFLAGS = -O # 64-bit mode (32 bit int's and 64-bit long's): # CFLAGS = -64 # F77FLAGS = -64 # SGI doesn't have ranlib # RANLIB = echo #------------------------------------------------------------------------------ # AMD Opteron (64 bit) #------------------------------------------------------------------------------ # BLAS = -lgoto_opteron64 -lg2c # LAPACK = -llapack_opteron64 # SUSE Linux 10.1, AMD Opteron # F77 = gfortran # BLAS = -lgoto_opteron64 -lgfortran # LAPACK = -llapack_opteron64 #------------------------------------------------------------------------------ # remove object files and profile output #------------------------------------------------------------------------------ CLEAN = *.o *.obj *.ln *.bb *.bbg *.da *.tcov *.gcov gmon.out *.bak *.d *.gcda *.gcno cvxopt-1.1.4/src/C/SuiteSparse/UFconfig/UFconfig.h0000644000175000017500000001021111674452555020670 0ustar sonnesonne/* ========================================================================== */ /* === UFconfig.h =========================================================== */ /* ========================================================================== */ /* Configuration file for SuiteSparse: a Suite of Sparse matrix packages * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others). * * UFconfig.h provides the definition of the long integer. On most systems, * a C program can be compiled in LP64 mode, in which long's and pointers are * both 64-bits, and int's are 32-bits. Windows 64, however, uses the LLP64 * model, in which int's and long's are 32-bits, and long long's and pointers * are 64-bits. * * SuiteSparse packages that include long integer versions are * intended for the LP64 mode. However, as a workaround for Windows 64 * (and perhaps other systems), the long integer can be redefined. * * If _WIN64 is defined, then the __int64 type is used instead of long. * * The long integer can also be defined at compile time. For example, this * could be added to UFconfig.mk: * * CFLAGS = -O -D'UF_long=long long' -D'UF_long_max=9223372036854775801' \ * -D'UF_long_id="%lld"' * * This file defines UF_long as either long (on all but _WIN64) or * __int64 on Windows 64. The intent is that a UF_long is always a 64-bit * integer in a 64-bit code. ptrdiff_t might be a better choice than long; * it is always the same size as a pointer. * * This file also defines the SUITESPARSE_VERSION and related definitions. * * Copyright (c) 2007, University of Florida. No licensing restrictions * apply to this file or to the UFconfig directory. Author: Timothy A. Davis. */ #ifndef _UFCONFIG_H #define _UFCONFIG_H #ifdef __cplusplus extern "C" { #endif #include /* ========================================================================== */ /* === UF_long ============================================================== */ /* ========================================================================== */ #ifndef UF_long #ifdef _WIN64 #define UF_long __int64 #define UF_long_max _I64_MAX #define UF_long_id "%I64d" #else #define UF_long long #define UF_long_max LONG_MAX #define UF_long_id "%ld" #endif #endif /* ========================================================================== */ /* === SuiteSparse version ================================================== */ /* ========================================================================== */ /* SuiteSparse is not a package itself, but a collection of packages, some of * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD, * COLAMD, CAMD, and CCOLAMD, etc). A version number is provided here for the * collection itself. The versions of packages within each version of * SuiteSparse are meant to work together. Combining one packge from one * version of SuiteSparse, with another package from another version of * SuiteSparse, may or may not work. * * SuiteSparse Version 3.4.0 contains the following packages: * * AMD version 2.2.0 * CAMD version 2.2.0 * COLAMD version 2.7.1 * CCOLAMD version 2.7.1 * CHOLMOD version 1.7.1 * CSparse version 2.2.3 * CXSparse version 2.2.3 * KLU version 1.1.0 * BTF version 1.1.0 * LDL version 2.0.1 * UFconfig version number is the same as SuiteSparse * UMFPACK version 5.4.0 * RBio version 1.1.2 * UFcollection version 1.2.0 * LINFACTOR version 1.1.0 * MESHND version 1.1.1 * SSMULT version 2.0.0 * MATLAB_Tools no specific version number * SuiteSparseQR version 1.1.2 * * Other package dependencies: * BLAS required by CHOLMOD and UMFPACK * LAPACK required by CHOLMOD * METIS 4.0.1 required by CHOLMOD (optional) and KLU (optional) */ #define SUITESPARSE_DATE "May 20, 2009" #define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub)) #define SUITESPARSE_MAIN_VERSION 3 #define SUITESPARSE_SUB_VERSION 4 #define SUITESPARSE_SUBSUB_VERSION 0 #define SUITESPARSE_VERSION \ SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION) #ifdef __cplusplus } #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/0000755000175000017500000000000011674452555016412 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Makefile0000644000175000017500000000371611674452555020061 0ustar sonnesonne#------------------------------------------------------------------------------- # UMFPACK makefile (for GNU make or original make) #------------------------------------------------------------------------------- # UMFPACK requires the AMD package to be in ../AMD default: library include ../UFconfig/UFconfig.mk # compile all C code (except hb, fortran, and fortran64), including AMD and the # MATLAB mexFunctions all: ( cd ../AMD ; $(MAKE) library ) ( cd ../AMD ; $(MAKE) mex ) ( cd Lib ; $(MAKE) ) ( cd Demo ; $(MAKE) ) ( cd MATLAB ; $(MAKE) ) - cat Doc/License # compile just the C-callable libraries and demo programs (not mexFunctions) library: ( cd ../AMD ; $(MAKE) library ) ( cd Lib ; $(MAKE) ) ( cd Demo ; $(MAKE) ) - cat Doc/License # compile the FORTRAN interface and demo program fortran: ( cd Demo ; $(MAKE) fortran ) # compile the 64-bit FORTRAN interface and demo program fortran64: ( cd Demo ; $(MAKE) fortran64 ) # compile the Harwell/Boeing demo program hb: ( cd Demo ; $(MAKE) hb ) # remove object files, but keep the compiled programs and library archives clean: ( cd ../AMD ; $(MAKE) clean ) ( cd Lib ; $(MAKE) clean ) ( cd Demo ; $(MAKE) clean ) ( cd MATLAB ; $(MAKE) clean ) ( cd Doc ; $(MAKE) clean ) # clean, and then remove compiled programs and library archives purge: ( cd ../AMD ; $(MAKE) purge ) ( cd Lib ; $(MAKE) purge ) ( cd Demo ; $(MAKE) purge ) ( cd MATLAB ; $(MAKE) purge ) ( cd Doc ; $(MAKE) purge ) # create PDF documents for the original distribution doc: ( cd ../AMD ; $(MAKE) doc ) ( cd Doc ; $(MAKE) ) # get ready for distribution dist: purge ( cd ../AMD ; $(MAKE) dist ) ( cd Demo ; $(MAKE) dist ) ( cd Doc ; $(MAKE) ) distclean: purge ccode: library # compile the MATLAB mexFunction mex: ( cd ../AMD/MATLAB ; $(MAKE) ) ( cd MATLAB ; $(MAKE) ) # statement coverage (requires Linux; takes a lot of time and disk space) cov: purge ( cd Tcov ; ./DO.linux ; ./covall ) cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/README.txt0000644000175000017500000004403711674452555020120 0ustar sonnesonneUMFPACK : a set of routines solving sparse linear systems via LU factorization. Requires three other packages: the BLAS (dense matrix operations), AMD (sparse matrix minimum degree ordering), and UFconfig. Includes a C-callable and MATLAB interface, and a basic FORTRAN 77 interface to a subset of the C-callable routines. Requires AMD Version 2.0 or later. The AMD, UFconfig, and UMFPACK directories must all reside in the same parent directory. Quick start (Unix, or Windows with Cygwin): To compile, test, and install both UMFPACK and AMD, the UMFPACK and AMD directories must be in the same parent directory. To configure, edit the UFconfig/UFconfig.mk file (otherwise, you may get warnings that the BLAS (dgemm, etc) are not found). You may use UMFPACK_CONFIG = -DNBLAS in the UFconfig/UFconfig.mk file, to avoid using the BLAS, but UMFPACK will be slow. Next, cd to this directory (UMFPACK) and type "make". To compile and run a FORTRAN demo program for Harwell/Boeing matrices, type "make hb". To compile a FORTRAN main program that calls the 32-bit C-callable UMFPACK library, type "make fortran". When done, type "make clean" to remove unused *.o files (keeps the compiled libraries and demo programs). See the User Guide (Doc/UserGuide.pdf), or ../UFconfig/UFconfig.mk for more details (including options for compiling in 64-bit mode). Quick start (for MATLAB users): To compile, test, and install the UMFPACK mexFunction, cd to the UMFPACK/MATLAB directory and type umfpack_make at the MATLAB prompt. NOTE: DO NOT ATTEMPT TO USE THIS CODE IN 64-BIT MATLAB (v7.3). It is not yet ported to that version of MATLAB. -------------------------------------------------------------------------------- UMFPACK, Copyright (c) 1995-2006 by Timothy A. Davis. All Rights Reserved. UMFPACK is available under alternate licences; contact T. Davis for details. UMFPACK License: Your use or distribution of UMFPACK or any modified version of UMFPACK implies that you agree to this License. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU GPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. Availability: http://www.cise.ufl.edu/research/sparse/umfpack UMFPACK (including versions 2.2.1 and earlier, in FORTRAN) is available at http://www.cise.ufl.edu/research/sparse. MA38 is available in the Harwell Subroutine Library. This version of UMFPACK includes a modified form of COLAMD Version 2.0, originally released on Jan. 31, 2000, also available at http://www.cise.ufl.edu/research/sparse. COLAMD V2.0 is also incorporated as a built-in function in MATLAB version 6.1, by The MathWorks, Inc. (http://www.mathworks.com). COLAMD V1.0 appears as a column-preordering in SuperLU (SuperLU is available at http://www.netlib.org). UMFPACK v4.0 is a built-in routine in MATLAB 6.5. UMFPACK v4.3 is a built-in routine in MATLAB 7.1. -------------------------------------------------------------------------------- Refer to ../AMD/README for the License for AMD, which is a separate package for ordering sparse matrices that is required by UMFPACK. UMFPACK v4.5 cannot use AMD v1.1 or earlier. UMFPACK 5.x requires AMD v2.0 or later. -------------------------------------------------------------------------------- This is the UMFPACK README.txt file. It is a terse overview of UMFPACK. Refer to the User Guide (Doc/UserGuide.pdf) for how to install and use UMFPACK, or to the Quick Start Guide, QuickStart.pdf. Description: UMFPACK is a set of routines for solving unsymmetric sparse linear systems, Ax=b, using the Unsymmetric MultiFrontal method. Written in ANSI/ISO C, with a MATLAB (Version 6.0 or later) interface. For best performance, UMFPACK requires an optimized BLAS library. It can also be compiled without any BLAS at all. UMFPACK requires AMD Version 2.0. Authors: Timothy A. Davis (davis@cise.ufl.edu), University of Florida. Includes a modified version of COLAMD V2.0, by Stefan I. Larimore and Timothy A. Davis, University of Florida. The COLAMD algorithm was developed in collaboration with John Gilbert, Xerox Palo Alto Research Center, and Esmond Ng, Lawrence Berkeley National Laboratory. Includes AMD, by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. UMFPACK Version 2.2.1 (MA38 in the Harwell Subroutine Library) is co-authored with Iain S. Duff, Rutherford Appleton Laboratory. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974, DMS-9803599, and CCR-0203270. Portions of this work were done while on sabbatical at Stanford University and Lawrence Berkeley National Laboratory (with funding from the SciDAC program). I would like to thank Gene Golub, Esmond Ng, and Horst Simon for making this sabbatical possible. I would also like to thank the many researchers who provided sparse matrices from a wide range of domains and used earlier versions of UMFPACK/ MA38 in their applications, and thus assisted in the practical development of the algorithm (see http://www.cise.ufl.edu/research/sparse, future contributions of matrices are always welcome). The MathWorks, Inc., provided a pre-release of MATLAB V6 which allowed me to release the first umfpack mexFunction (v3.0) about 6 months earlier than I had originally planned. They also supported the extension of UMFPACK to complex, singular, and rectangular matrices (UMFPACK v4.0). Penny Anderson (The MathWorks, Inc.), Anshul Gupta (IBM), and Friedrich Grund (WAIS) assisted in porting UMFPACK to different platforms. Penny Anderson also incorporated UMFPACK v4.0 into MATLAB, for lu, backslash (\), and forward slash (/). David Bateman (Motorola) wrote the initial version of the packed complex input option, and umfpack_get_determinant. -------------------------------------------------------------------------------- Files and directories in the UMFPACK distribution: -------------------------------------------------------------------------------- ---------------------------------------------------------------------------- Subdirectories of the UMFPACK directory: ---------------------------------------------------------------------------- Doc documentation Source primary source code Include include files for use in your code that calls UMFPACK Demo demo programs. also serves as test of the UMFPACK installation. MATLAB UMFPACK mexFunction for MATLAB, and supporting m-files Lib where the compiled C-callable UMFPACK library is placed. ---------------------------------------------------------------------------- Files in the UMFPACK directory: ---------------------------------------------------------------------------- Makefile top-level Makefile for GNU make or original make. Windows users would require Cygwin to use "make" README.txt this file ---------------------------------------------------------------------------- Doc directory: documentation ---------------------------------------------------------------------------- ChangeLog change log License the UMFPACK License Makefile for creating the documentation QuickStart.tex Quick Start guide (source) QuickStart.pdf Quick Start guide (PDF) UserGuide.bib User Guide (references) UserGuide.sed1 sed script for processing UserGuide.stex UserGuide.sed2 sed script for processing UserGuide.stex UserGuide.stex User Guide (LaTeX) UserGuide.pdf User Guide (PDF) ---------------------------------------------------------------------------- Source directory: ---------------------------------------------------------------------------- cholmod_blas.h an exact copy of CHOLMOD/Include/cholmod_blas.h umfpack_col_to_triplet.c convert col form to triplet umfpack_defaults.c set Control defaults umfpack_free_numeric.c free Numeric object umfpack_free_symbolic.c free Symbolic object umfpack_get_determinant.c compute determinant from Numeric object umfpack_get_lunz.c get nz's in L and U umfpack_get_numeric.c get Numeric object umfpack_get_symbolic.c get Symbolic object umfpack_load_numeric.c load Numeric object from file umfpack_load_symbolic.c load Symbolic object from file umfpack_numeric.c numeric factorization umfpack_qsymbolic.c symbolic factorization, user Q umfpack_report_control.c print Control settings umfpack_report_info.c print Info statistics umfpack_report_matrix.c print col or row-form sparse matrix umfpack_report_numeric.c print Numeric object umfpack_report_perm.c print permutation umfpack_report_status.c print return status umfpack_report_symbolic.c print Symbolic object umfpack_report_triplet.c print triplet matrix umfpack_report_vector.c print dense vector umfpack_save_numeric.c save Numeric object to file umfpack_save_symbolic.c save Symbolic object to file umfpack_scale.c scale a vector umfpack_solve.c solve a linear system umfpack_symbolic.c symbolic factorization umfpack_tictoc.c timer umfpack_timer.c timer umfpack_transpose.c transpose a matrix umfpack_triplet_to_col.c convert triplet to col form umf_config.h configuration file (BLAS, memory, timer) umf_internal.h definitions internal to UMFPACK umf_version.h version definitions (int/UF_long, real/complex) umf_2by2.[ch] umf_analyze.[ch] symbolic factorization of A'*A umf_apply_order.[ch] apply column etree postorder umf_assemble.[ch] assemble elements into current front umf_blas3_update.[ch] rank-k update. Uses level-3 BLAS umf_build_tuples.[ch] construct tuples for elements umf_colamd.[ch] COLAMD pre-ordering, modified for UMFPACK umf_create_element.[ch] create a new element umf_dump.[ch] debugging routines, not normally active umf_extend_front.[ch] extend the current frontal matrix umf_free.[ch] free memory umf_fsize.[ch] determine largest front in each subtree umf_garbage_collection.[ch] compact Numeric->Memory umf_get_memory.[ch] make Numeric->Memory bigger umf_grow_front.[ch] make current frontal matrix bigger umf_init_front.[ch] initialize a new frontal matrix umf_is_permutation.[ch] checks the validity of a permutation vector umf_kernel.[ch] the main numeric factorization kernel umf_kernel_init.[ch] initializations for umf_kernel umf_kernel_wrapup.[ch] wrapup for umf_kernel umf_local_search.[ch] local row and column pivot search umf_lsolve.[ch] solve Lx=b umf_ltsolve.[ch] solve L'x=b and L.'x=b umf_malloc.[ch] malloc some memory umf_mem_alloc_element.[ch] allocate element in Numeric->Memory umf_mem_alloc_head_block.[ch] alloc. block at head of Numeric->Memory umf_mem_alloc_tail_block.[ch] alloc. block at tail of Numeric->Memory umf_mem_free_tail_block.[ch] free block at tail of Numeric->Memory umf_mem_init_memoryspace.[ch] initialize Numeric->Memory umf_realloc.[ch] realloc memory umf_report_perm.[ch] print a permutation vector umf_report_vector.[ch] print a double vector umf_row_search.[ch] look for a pivot row umf_scale.[ch] scale the pivot column umf_scale_column.[ch] move pivot row & column into place, log P and Q umf_set_stats.[ch] set statistics (final or estimates) umf_singletons.[ch] find all zero-cost pivots umf_solve.[ch] solve a linear system umf_start_front.[ch] start a new frontal matrix for one frontal chain umf_store_lu.[ch] store LU factors of current front umf_symbolic_usage.[ch] determine memory usage for Symbolic object umf_transpose.[ch] transpose a matrix in row or col form umf_triplet.[ch] convert triplet to column form umf_tuple_lengths.[ch] determine the tuple list lengths umf_usolve.[ch] solve Ux=b umf_utsolve.[ch] solve U'x=b and U.'x=b umf_valid_numeric.[ch] checks the validity of a Numeric object umf_valid_symbolic.[ch] check the validity of a Symbolic object ---------------------------------------------------------------------------- Include directory: ---------------------------------------------------------------------------- umfpack.h include file for user programs. Includes all of the following files. This serves are source- code level documenation. These files are also used to construct the User Guide. umfpack_col_to_triplet.h umfpack_defaults.h umfpack_free_numeric.h umfpack_free_symbolic.h umfpack_get_determinant.h umfpack_get_lunz.h umfpack_get_numeric.h umfpack_get_symbolic.h umfpack_load_numeric.h umfpack_load_symbolic.h umfpack_numeric.h umfpack_qsymbolic.h umfpack_report_control.h umfpack_report_info.h umfpack_report_matrix.h umfpack_report_numeric.h umfpack_report_perm.h umfpack_report_status.h umfpack_report_symbolic.h umfpack_report_triplet.h umfpack_report_vector.h umfpack_save_numeric.h umfpack_save_symbolic.h umfpack_scale.h umfpack_solve.h umfpack_symbolic.h umfpack_tictoc.h umfpack_timer.h umfpack_transpose.h umfpack_triplet_to_col.h umfpack_wsolve.h note that there is no umfpack_wsolve.c. The umfpack_*_wsolve routines are created from the umfpack_solve.c file. ---------------------------------------------------------------------------- Demo directory: ---------------------------------------------------------------------------- Makefile for GNU make or original make umfpack_simple.c a simple demo umpack_xx_demo.c template to create the demo codes below umfpack_di_demo.sed for creating umfpack_di_demo.c umfpack_dl_demo.sed for creating umfpack_dl_demo.c umfpack_zi_demo.sed for creating umfpack_zi_demo.c umfpack_zl_demo.sed for creating umfpack_zl_demo.c umfpack_di_demo.c a full demo (real/int version) umfpack_dl_demo.c a full demo (real/UF_long version) umfpack_zi_demo.c a full demo (complex/int version) umfpack_zl_demo.c a full demo (complex/UF_long version) umfpack_di_demo.out umfpack_di_demo output umfpack_dl_demo.out umfpack_dl_demo output umfpack_zi_demo.out umfpack_zi_demo output umfpack_zl_demo.out umfpack_zl_demo output umf4.c a demo (real/int) for Harwell/Boeing matrices umf4.out output of "make hb" HB directory of sample Harwell/Boeing matrices readhb.f reads HB matrices, keeps zero entries readhb_nozeros.f reads HB matrices, removes zero entries readhb_size.f reads HB matrix dimension, nnz tmp empty directory for umf4.c demo umf4_f77wrapper.c a simple FORTRAN interface for UMFPACK. compile with "make fortran" umf4hb.f a demo of the FORTRAN interface umf4hb.out output of "make fortran" umf4_f77zwrapper.c a simple FORTRAN interface for the complex UMFPACK routines. compile with "make fortran" umf4zhb.f a demo of the FORTRAN interface (complex) umf4zhb.out output of umf4zhb with HB/qc324.cua umf4hb64.f 64-bit version of umf4hb.f simple_compile a single command that compiles the double/int version of UMFPACK (useful prototype for Microsoft Visual Studio project) ---------------------------------------------------------------------------- MATLAB directory: ---------------------------------------------------------------------------- Contents.m for "help umfpack" listing of toolbox contents GNUmakefile a nice Makefile, for GNU make Makefile an ugly Unix Makefile (for older make's) lu_normest.m 1-norm estimate of A-L*U (by Hager & Davis). luflop.m for "help luflop" luflopmex.c luflop mexFunction, for computing LU flop count umfpack.m for "help umfpack" umfpack_btf.m solve Ax=b using umfpack and dmperm umfpack_demo.m a full umfpack demo umfpack_details.m the details of how to use umfpack umfpack_make.m compile the umfpack mexFunction within MATLAB umfpack_report.m report statistics umfpack_simple.m a simple umfpack demo umfpack_solve.m x=A\b or b/A for arbitrary b umfpack_test.m extensive test, requires UF sparse matrices umfpackmex.c the umfpack mexFunction west0067.mat sparse matrix for umfpack_demo.m umfpack_demo.m.out output of umfpack_demo.m umfpack_simple.m.out output of umfpack_simple lcc_lib/lapacksyms.def LAPACK definitions for lcc compiler (Windows) lcc_lib/libmwlapack.lib LAPACK definitions for lcc compiler (Windows) ---------------------------------------------------------------------------- Lib directory: libumfpack.a library placed here ---------------------------------------------------------------------------- GNUmakefile a nice Makefile, for GNU make Makefile an ugly Unix Makefile (for older make's) libumfpack.def UMPFACK definitions for Windows cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/0000755000175000017500000000000011674452555017117 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed10000644000175000017500000000414511674452555021575 0ustar sonnesonne/INCLUDE umfpack_col_to_triplet.h/r ../Include/umfpack_col_to_triplet.h /INCLUDE umfpack_defaults.h/r ../Include/umfpack_defaults.h /INCLUDE umfpack_free_numeric.h/r ../Include/umfpack_free_numeric.h /INCLUDE umfpack_free_symbolic.h/r ../Include/umfpack_free_symbolic.h /INCLUDE umfpack_get_lunz.h/r ../Include/umfpack_get_lunz.h /INCLUDE umfpack_get_numeric.h/r ../Include/umfpack_get_numeric.h /INCLUDE umfpack_get_symbolic.h/r ../Include/umfpack_get_symbolic.h /INCLUDE umfpack_get_scale.h/r ../Include/umfpack_get_scale.h /INCLUDE umfpack_numeric.h/r ../Include/umfpack_numeric.h /INCLUDE umfpack_qsymbolic.h/r ../Include/umfpack_qsymbolic.h /INCLUDE umfpack_report_control.h/r ../Include/umfpack_report_control.h /INCLUDE umfpack_report_info.h/r ../Include/umfpack_report_info.h /INCLUDE umfpack_report_matrix.h/r ../Include/umfpack_report_matrix.h /INCLUDE umfpack_report_numeric.h/r ../Include/umfpack_report_numeric.h /INCLUDE umfpack_report_perm.h/r ../Include/umfpack_report_perm.h /INCLUDE umfpack_report_status.h/r ../Include/umfpack_report_status.h /INCLUDE umfpack_report_symbolic.h/r ../Include/umfpack_report_symbolic.h /INCLUDE umfpack_report_triplet.h/r ../Include/umfpack_report_triplet.h /INCLUDE umfpack_report_vector.h/r ../Include/umfpack_report_vector.h /INCLUDE umfpack_simple.c/r ../Demo/umfpack_simple.c /INCLUDE umfpack_solve.h/r ../Include/umfpack_solve.h /INCLUDE umfpack_scale.h/r ../Include/umfpack_scale.h /INCLUDE umfpack_symbolic.h/r ../Include/umfpack_symbolic.h /INCLUDE umfpack_timer.h/r ../Include/umfpack_timer.h /INCLUDE umfpack_tictoc.h/r ../Include/umfpack_tictoc.h /INCLUDE umfpack_transpose.h/r ../Include/umfpack_transpose.h /INCLUDE umfpack_triplet_to_col.h/r ../Include/umfpack_triplet_to_col.h /INCLUDE umfpack_wsolve.h/r ../Include/umfpack_wsolve.h /INCLUDE umfpack_load_numeric.h/r ../Include/umfpack_load_numeric.h /INCLUDE umfpack_load_symbolic.h/r ../Include/umfpack_load_symbolic.h /INCLUDE umfpack_save_numeric.h/r ../Include/umfpack_save_numeric.h /INCLUDE umfpack_save_symbolic.h/r ../Include/umfpack_save_symbolic.h /INCLUDE umfpack_get_determinant.h/r ../Include/umfpack_get_determinant.h cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/Makefile0000644000175000017500000000417211674452555020563 0ustar sonnesonne#------------------------------------------------------------------------------- # UMFPACK Makefile for compiling on Unix systems (for GNU or original make) #------------------------------------------------------------------------------- # UMFPACK Version 4.4, Copyright (c) 2005 by Timothy A. Davis. # All Rights Reserved. See ../Doc/License for License. default: dist include ../../UFconfig/UFconfig.mk #------------------------------------------------------------------------------- # Remove all but the files in the original distribution #------------------------------------------------------------------------------- # Note that UserGuide.tex is created from UserGuide.stex, the files in # the ../Include directory, and the ../Demo/umfpack_simple.c file. purge: clean - $(RM) *.aux *.bbl *.blg *.log *.toc - $(RM) UserGuide.tex clean: - $(RM) $(CLEAN) #------------------------------------------------------------------------------- # Create the User Guide and Quick Start Guide #------------------------------------------------------------------------------- UMFPACK = umfpack_col_to_triplet umfpack_defaults umfpack_free_numeric \ umfpack_free_symbolic umfpack_get_numeric umfpack_get_lunz \ umfpack_get_determinant \ umfpack_get_symbolic umfpack_numeric umfpack_qsymbolic \ umfpack_report_control umfpack_report_info umfpack_report_matrix \ umfpack_report_numeric umfpack_report_perm umfpack_report_status \ umfpack_report_symbolic umfpack_report_triplet \ umfpack_report_vector umfpack_solve umfpack_symbolic \ umfpack_transpose umfpack_triplet_to_col umfpack_scale UMFPACKW = umfpack_wsolve USER = $(UMFPACKW) $(UMFPACK) SRC = $(addprefix ../Include/, $(addsuffix .h,$(USER))) ../Demo/umfpack_simple.c UserGuide.pdf: UserGuide.stex UserGuide.sed1 UserGuide.sed2 $(SRC) UserGuide.bib sed -f UserGuide.sed1 < UserGuide.stex | sed -f UserGuide.sed2 \ | expand -8 > UserGuide.tex pdflatex UserGuide bibtex UserGuide pdflatex UserGuide pdflatex UserGuide QuickStart.pdf: QuickStart.tex pdflatex QuickStart pdflatex QuickStart dist: QuickStart.pdf UserGuide.pdf - $(RM) *.aux *.bbl *.blg *.log *.toc - $(RM) UserGuide.tex cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/QuickStart.tex0000644000175000017500000012432311674452555021740 0ustar sonnesonne%------------------------------------------------------------------------------- % The QuickStart.tex file. %------------------------------------------------------------------------------- \documentclass[11pt]{article} \newcommand{\m}[1]{{\bf{#1}}} % for matrices and vectors \newcommand{\tr}{^{\sf T}} % transpose \topmargin 0in \textheight 9in \oddsidemargin 0pt \evensidemargin 0pt \textwidth 6.5in \begin{document} \author{Timothy A. Davis \\ Dept. of Computer and Information Science and Engineering \\ Univ. of Florida, Gainesville, FL} \title{UMFPACK Version 5.4.0 Quick Start Guide} \date{May 20, 2009} \maketitle %------------------------------------------------------------------------------- \begin{abstract} UMFPACK is a set of routines for solving unsymmetric sparse linear systems, $\m{Ax}=\m{b}$, using the Unsymmetric-pattern MultiFrontal method and direct sparse LU factorization. It is written in ANSI/ISO C, with a MATLAB interface. UMFPACK relies on the Level-3 Basic Linear Algebra Subprograms (dense matrix multiply) for its performance. This code works on Windows and many versions of Unix (Sun Solaris, Red Hat Linux, IBM AIX, SGI IRIX, and Compaq Alpha). This is a ``quick start'' guide for Unix users of the C interface. \end{abstract} %------------------------------------------------------------------------------- Copyright\copyright 1995-2009 by Timothy A. Davis. All Rights Reserved. Refer to the UMFPACK User Guide for the License. See \newline http://www.cise.ufl.edu/research/sparse/umfpack for the code and full documentation. %------------------------------------------------------------------------------- \section{Overview} %------------------------------------------------------------------------------- UMFPACK is a set of routines for solving systems of linear equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and unsymmetric. The sparse matrix $\m{A}$ can be square or rectangular, singular or non-singular, and real or complex (or any combination). Only square matrices $\m{A}$ can be used to solve $\m{Ax}=\m{b}$ or related systems. Rectangular matrices can only be factorized. UMFPACK is a built-in routine in MATLAB used by the forward and backslash operator, and the {\tt lu} routine. The following is a short introduction to Unix users of the C interface of UMFPACK. %------------------------------------------------------------------------------- The C-callable UMFPACK library consists of 32 user-callable routines and one include file. Twenty-eight of the routines come in four versions, with different sizes of integers and for real or complex floating-point numbers. This Quick Start Guide assumes you are working with real matrices (not complex) and with {\tt int}'s as integers (not {\tt long}'s). Refer to the User Guide for information about the complex and long integer versions. The include file {\tt umfpack.h} must be included in any C program that uses UMFPACK. For more details, see: {\em A column pre-ordering strategy for the unsymmetric-pattern multifrontal method}, Davis, T. A., ACM Trans. Math. Software, vol 30. no 2, 2004, pp. 165-195, and {\em Algorithm 832: {UMFPACK}, an unsymmetric-pattern multifrontal method}, same issue, pp. 196-199. %------------------------------------------------------------------------------- \section{Primary routines, and a simple example} %------------------------------------------------------------------------------- Five primary UMFPACK routines are required to factorize $\m{A}$ or solve $\m{Ax}=\m{b}$. An overview of the primary features of the routines is given in Section~\ref{Primary}. Additional routines are available for passing a different column ordering to UMFPACK, changing default parameters, manipulating sparse matrices, getting the LU factors, save and loading the LU factors from a file, computing the determinant, and reporting results. See the User Guide for more information. \begin{itemize} \item {\tt umfpack\_di\_symbolic}: Pre-orders the columns of $\m{A}$ to reduce fill-in and performs a symbolic analysis. Returns an opaque {\tt Symbolic} object as a {\tt void *} pointer. The object contains the symbolic analysis and is needed for the numerical factorization. \item {\tt umfpack\_di\_numeric}: Numerically scales and then factorizes a sparse matrix $\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$, where $\m{P}$ and $\m{Q}$ are permutation matrices, $\m{R}$ is a diagonal matrix of scale factors, $\m{L}$ is lower triangular with unit diagonal, and $\m{U}$ is upper triangular. Requires the symbolic ordering and analysis computed by {\tt umfpack\_di\_symbolic}. Returns an opaque {\tt Numeric} object as a {\tt void *} pointer. The object contains the numerical factorization and is used by {\tt umfpack\_di\_solve}. \item {\tt umfpack\_di\_solve}: Solves a sparse linear system ($\m{Ax}=\m{b}$, $\m{A}\tr\m{x}=\m{b}$, or systems involving just $\m{L}$ or $\m{U}$), using the numeric factorization computed by {\tt umfpack\_di\_numeric}. \item {\tt umfpack\_di\_free\_symbolic}: Frees the {\tt Symbolic} object created by {\tt umfpack\_di\_symbolic}. \item {\tt umfpack\_di\_free\_numeric}: Frees the {\tt Numeric} object created by {\tt umfpack\_di\_numeric}. \end{itemize} The matrix $\m{A}$ is represented in compressed column form, which is identical to the sparse matrix representation used by MATLAB. It consists of three arrays, where the matrix is {\tt m}-by-{\tt n}, with {\tt nz} entries: {\footnotesize \begin{verbatim} int Ap [n+1] ; int Ai [nz] ; double Ax [nz] ; \end{verbatim} } All nonzeros are entries, but an entry may be numerically zero. The row indices of entries in column {\tt j} are stored in {\tt Ai[Ap[j]} ... {\tt Ap[j+1]-1]}. The corresponding numerical values are stored in {\tt Ax[Ap[j]} ... {\tt Ap[j+1]-1]}. No duplicate row indices may be present, and the row indices in any given column must be sorted in ascending order. The first entry {\tt Ap[0]} must be zero. The total number of entries in the matrix is thus {\tt nz = Ap[n]}. Except for the fact that extra zero entries can be included, there is thus a unique compressed column representation of any given matrix $\m{A}$. Here is a simple main program, {\tt umfpack\_simple.c}, that illustrates the basic usage of UMFPACK. {\footnotesize \begin{verbatim} #include #include "umfpack.h" int n = 5 ; int Ap [ ] = {0, 2, 5, 9, 10, 12} ; int Ai [ ] = { 0, 1, 0, 2, 4, 1, 2, 3, 4, 2, 1, 4} ; double Ax [ ] = {2., 3., 3., -1., 4., 4., -3., 1., 2., 2., 6., 1.} ; double b [ ] = {8., 45., -3., 3., 19.} ; double x [5] ; int main (void) { double *null = (double *) NULL ; int i ; void *Symbolic, *Numeric ; (void) umfpack_di_symbolic (n, n, Ap, Ai, Ax, &Symbolic, null, null) ; (void) umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, null, null) ; umfpack_di_free_symbolic (&Symbolic) ; (void) umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, x, b, Numeric, null, null) ; umfpack_di_free_numeric (&Numeric) ; for (i = 0 ; i < n ; i++) printf ("x [%d] = %g\n", i, x [i]) ; return (0) ; } \end{verbatim} } The {\tt Ap}, {\tt Ai}, and {\tt Ax} arrays represent the matrix \[ \m{A} = \left[ \begin{array}{rrrrr} 2 & 3 & 0 & 0 & 0 \\ 3 & 0 & 4 & 0 & 6 \\ 0 & -1 & -3 & 2 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 4 & 2 & 0 & 1 \\ \end{array} \right]. \] and the solution is $\m{x} = [1 \, 2 \, 3 \, 4 \, 5]\tr$. The program uses default control settings and does not return any statistics about the ordering, factorization, or solution ({\tt Control} and {\tt Info} are both {\tt (double *) NULL}). For routines to manipulate a simpler ``triplet-form'' data structure for your sparse matrix $\m{A}$, refer to the UMFPACK User Guide. %------------------------------------------------------------------------------- \section{Synopsis of primary C-callable routines} \label{Synopsis} %------------------------------------------------------------------------------- The matrix $\m{A}$ is {\tt m}-by-{\tt n} with {\tt nz} entries. The optional {\tt umfpack\_di\_defaults} routine loads the default control parameters into the {\tt Control} array. The settings can then be modified before passing the array to the other routines. Refer to Section~\ref{Primary} for more details. {\footnotesize \begin{verbatim} #include "umfpack.h" int status, sys, n, m, nz, Ap [n+1], Ai [nz] ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], Ax [nz], X [n], B [n] ; void *Symbolic, *Numeric ; umfpack_di_defaults (Control) ; status = umfpack_di_symbolic (m, n, Ap, Ai, Ax, &Symbolic, Control, Info) ; status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ; status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ; umfpack_di_free_symbolic (&Symbolic) ; umfpack_di_free_numeric (&Numeric) ; \end{verbatim} } %------------------------------------------------------------------------------- \section{Installation} \label{Install} %------------------------------------------------------------------------------- You will need to install AMD v2.2 to use UMFPACK. Note that this version of UMFPACK cannot use AMD v1.2 or earlier. The {\tt UMFPACK} and {\tt AMD} subdirectories must be placed side-by-side within the same parent directory. AMD is a stand-alone package that is required by UMFPACK. UMFPACK can be compiled without the BLAS but your performance will be much less than what it should be. System-dependent configurations are in the {\tt UFconfig/UFconfig.mk} file. The default settings will work on most systems, except for the BLAS definition. Sample configurations are provided for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha. To compile and install both packages, go to the UMFPACK directory and type {\tt make}. This will compile the libraries ({\tt AMD/Lib/libamd.a} and {\tt UMFPACK/Lib/libumfpack.a}). A demo of the AMD ordering routine will be compiled and tested in the {\tt AMD/Demo} directory, and five demo programs will then be compiled and tested in the {\tt UMFPACK/Demo} directory. The outputs of these demo programs will then be compared with output files in the distribution. Expect to see a few differences, such as residual norms, compile-time control settings, and perhaps memory usage differences. To use {\tt make} to compile the MATLAB mexFunctions for MATLAB and AMD, you can either type {\tt make mex} in the UMFPACK directory. You may first need to edit the {\tt UFconfig/UFconfig.mk} file to modify the definition of the {\tt MEX}, if you have a version of MATLAB older than Version 7.2. Remove the {\tt -largeArrayDims} definition. If you use the MATLAB command {\tt umfpack\_make} in the MATLAB directory, then this case is handled for you automatically. If you compile UMFPACK and AMD and then later change the {\tt UFconfig/UFconfig.mk} file then you should type {\tt make purge} and then {\tt make} to recompile. Here are the various parameters that you can control in your {\tt UFconfig/UFconfig.mk} file: \begin{itemize} \item {\tt CC = } your C compiler, such as {\tt cc}. \item {\tt RANLIB = } your system's {\tt ranlib} program, if needed. \item {\tt CFLAGS = } optimization flags, such as {\tt -O}. \item {\tt UMFPACK\_CONFIG = } configuration settings, for the BLAS, memory allocation routines, and timing routines. \item {\tt LIB = } your libraries, such as {\tt -lm} or {\tt -lblas}. \item {\tt RM =} the command to delete a file. \item {\tt MV =} the command to rename a file. \item {\tt MEX =} the command to compile a MATLAB mexFunction. \item {\tt F77 =} the command to compile a Fortran program (optional). \item {\tt F77FLAGS =} the Fortran compiler flags (optional). \item {\tt F77LIB =} the Fortran libraries (optional). \end{itemize} The {\tt UMFPACK\_CONFIG} string can include combinations of the following; most deal with how the BLAS are called: \begin{itemize} \item {\tt -DNBLAS} if you do not have any BLAS at all. \item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun Performance Library. \item {\tt -DLONGBLAS} if your BLAS takes non-{\tt int} integer arguments. \item {\tt -DBLAS\_INT = } the integer used by the BLAS. \item {\tt -DBLAS\_NO\_UNDERSCORE} for controlling how C calls the Fortran BLAS. This is set automatically for Windows, Sun Solaris, SGI Irix, Red Hat Linux, Compaq Alpha, and AIX (the IBM RS 6000). \item {\tt -DGETRUSAGE} if you have the {\tt getrusage} function. \item {\tt -DNPOSIX} if you do not have the POSIX-compliant {\tt sysconf} and {\tt times} routines. \item {\tt -DNRECIPROCAL} controls a trade-off between speed and accuracy. This is off by default (speed preferred over accuracy) except when compiling for MATLAB. \end{itemize} When you compile your program that uses the C-callable UMFPACK library, you need to add the both {\tt UMFPACK/Lib/libumfpack.a} and {\tt AMD/Lib/libamd.a} libraries, and you need to tell your compiler to look in the directories {\tt UMFPACK/Include} and {\tt AMD/Include} for include files. See {\tt UMFPACK/Demo/Makefile} for an example. You do not need to directly include any AMD include files in your program, unless you directly call AMD routines. You only need the \begin{verbatim} #include "umfpack.h" \end{verbatim} statement, as described in Section~\ref{Synopsis}. %------------------------------------------------------------------------------- \newpage \section{The primary UMFPACK routines} \label{Primary} %------------------------------------------------------------------------------- \subsection{umfpack\_di\_symbolic} {\footnotesize \begin{verbatim} int umfpack_di_symbolic ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; Purpose: Given nonzero pattern of a sparse matrix A in column-oriented form, umfpack_di_symbolic performs a column pre-ordering to reduce fill-in (using COLAMD or AMD) and a symbolic factorization. This is required before the matrix can be numerically factorized with umfpack_di_numeric. For the following discussion, let S be the submatrix of A obtained after eliminating all pivots of zero Markowitz cost. S has dimension (n_row-n1-nempty_row) -by- (n_col-n1-nempty_col), where n1 = Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS], nempty_row = Info [UMFPACK_NEMPTY_ROW] and nempty_col = Info [UMFPACK_NEMPTY_COL]. Returns: The status code is returned. See Info [UMFPACK_STATUS], below. Arguments: int n_row ; Input argument, not modified. int n_col ; Input argument, not modified. A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0. int Ap [n_col+1] ; Input argument, not modified. Ap is an integer array of size n_col+1. On input, it holds the "pointers" for the column form of the sparse matrix A. Column j of the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The first entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all j in the range 0 to n_col-1. The value nz = Ap [n_col] is thus the total number of entries in the pattern of the matrix A. nz must be greater than or equal to zero. int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col]. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j must be in ascending order, and no duplicate row indices may be present. Row indices must be in the range 0 to n_row-1 (the matrix is 0-based). double Ax [nz] ; Optional input argument, not modified. The numerical values of the sparse matrix A. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. Used only by the 2-by-2 strategy to determine whether entries are "large" or "small". You do not have to pass the same numerical values to umfpack_di_numeric. If Ax is not present (a (double *) NULL pointer), then any entry in A is assumed to be "large". void **Symbolic ; Output argument. **Symbolic is the address of a (void *) pointer variable in the user's calling routine (see Syntax, above). On input, the contents of this variable are not defined. On output, this variable holds a (void *) pointer to the Symbolic object (if successful), or (void *) NULL if a failure occurred. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Only the primary parameters are listed below: Control [UMFPACK_STRATEGY]: This is the most important control parameter. It determines what kind of ordering and pivoting strategy that UMFPACK should use. It is new to Version 4.1 There are 4 options: UMFPACK_STRATEGY_AUTO: This is the default. The input matrix is analyzed to determine how symmetric the nonzero pattern is, and how many entries there are on the diagonal. It then selects one of the following strategies. Refer to the User Guide for a description of how the strategy is automatically selected. UMFPACK_STRATEGY_UNSYMMETRIC: Use the unsymmetric strategy. COLAMD is used to order the columns of A, followed by a postorder of the column elimination tree. No attempt is made to perform diagonal pivoting. The column ordering is refined during factorization. This strategy was the only one provided with UMFPACK V4.0. In the numerical factorization, the Control [UMFPACK_SYM_PIVOT_TOLERANCE] parameter is ignored. A pivot is selected if its magnitude is >= Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry in its column. UMFPACK_STRATEGY_SYMMETRIC: Use the symmetric strategy (new to Version 4.1). In this method, the approximate minimum degree ordering (AMD) is applied to A+A', followed by a postorder of the elimination tree of A+A'. UMFPACK attempts to perform diagonal pivoting during numerical factorization. No refinement of the column preordering is performed during factorization. In the numerical factorization, a nonzero entry on the diagonal is selected as the pivot if its magnitude is >= Control [UMFPACK_SYM_PIVOT_TOLERANCE] (default 0.001) times the largest entry in its column. If this is not acceptable, then an off-diagonal pivot is selected with magnitude >= Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry in its column. UMFPACK_STRATEGY_2BY2: option disabled. Control [UMFPACK_2BY2_TOLERANCE]: ignored. Control [UMFPACK_SCALE]: This parameter is new to V4.1. See umfpack_numeric.h for a description. Only affects the 2-by-2 strategy. Default: UMFPACK_SCALE_SUM. double Info [UMFPACK_INFO] ; Output argument, not defined on input. Contains statistics about the symbolic analysis. If a (double *) NULL pointer is passed, then no statistics are returned in Info (this is not an error condition). The entire Info array is cleared (all entries set to -1) and then the following statistics are computed (only the primary statistics are listed): Info [UMFPACK_STATUS]: status code. This is also the return value, whether or not Info is present. UMFPACK_OK Each column of the input matrix contained row indices in increasing order, with no duplicates. Only in this case does umfpack_di_symbolic compute a valid symbolic factorization. For the other cases below, no Symbolic object is created (*Symbolic is (void *) NULL). UMFPACK_ERROR_n_nonpositive n is less than or equal to zero. UMFPACK_ERROR_invalid_matrix Number of entries in the matrix is negative, Ap [0] is nonzero, a column has a negative number of entries, a row index is out of bounds, or the columns of input matrix were jumbled (unsorted columns or duplicate entries). UMFPACK_ERROR_out_of_memory Insufficient memory to perform the symbolic analysis. If the analysis requires more than 2GB of memory and you are using the 32-bit ("int") version of UMFPACK, then you are guaranteed to run out of memory. Try using the 64-bit version of UMFPACK. UMFPACK_ERROR_argument_missing One or more required arguments is missing. UMFPACK_ERROR_internal_error Something very serious went wrong. This is a bug. Please contact the author (davis@cise.ufl.edu). Info [UMFPACK_SIZE_OF_UNIT]: the number of bytes in a Unit, for memory usage statistics below. Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]: the amount of memory (in Units) required for umfpack_di_symbolic to complete. This count includes the size of the Symbolic object itself, which is also reported in Info [UMFPACK_SYMBOLIC_SIZE]. Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]: an estimate of the final size (in Units) of the entire Numeric object (both fixed-size and variable- sized parts), which holds the LU factorization (including the L, U, P and Q matrices). Info [UMFPACK_PEAK_MEMORY_ESTIMATE]: an estimate of the total amount of memory (in Units) required by umfpack_di_symbolic and umfpack_di_numeric to perform both the symbolic and numeric factorization. This is the larger of the amount of memory needed in umfpack_di_numeric itself, and the amount of memory needed in umfpack_di_symbolic (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]). The count includes the size of both the Symbolic and Numeric objects themselves. It can be a very loose upper bound, particularly when the symmetric or 2-by-2 strategies are used. Info [UMFPACK_FLOPS_ESTIMATE]: an estimate of the total floating-point operations required to factorize the matrix. This is a "true" theoretical estimate of the number of flops that would be performed by a flop-parsimonious sparse LU algorithm. It assumes that no extra flops are performed except for what is strictly required to compute the LU factorization. It ignores, for example, the flops performed by umfpack_di_numeric to add contribution blocks of frontal matrices together. If L and U are the upper bound on the pattern of the factors, then this flop count estimate can be represented in MATLAB (for real matrices, not complex) as: Lnz = full (sum (spones (L))) - 1 ; % nz in each col of L Unz = full (sum (spones (U')))' - 1 ; % nz in each row of U flops = 2*Lnz*Unz + sum (Lnz) ; The actual "true flop" count found by umfpack_di_numeric will be less than this estimate. Info [UMFPACK_LNZ_ESTIMATE]: an estimate of the number of nonzeros in L, including the diagonal. Since L is unit-diagonal, the diagonal of L is not stored. This estimate is a strict upper bound on the actual nonzeros in L to be computed by umfpack_di_numeric. Info [UMFPACK_UNZ_ESTIMATE]: an estimate of the number of nonzeros in U, including the diagonal. This estimate is a strict upper bound on the actual nonzeros in U to be computed by umfpack_di_numeric. Info [UMFPACK_SYMBOLIC_TIME]: The CPU time taken, in seconds. Info [UMFPACK_STRATEGY_USED]: The ordering strategy used: UMFPACK_STRATEGY_SYMMETRIC or UMFPACK_STRATEGY_UNSYMMETRIC \end{verbatim} } %------------------------------------------------------------------------------- \newpage \subsection{umfpack\_di\_numeric} {\footnotesize \begin{verbatim} int umfpack_di_numeric ( const int Ap [ ], const int Ai [ ], const double Ax [ ], void *Symbolic, void **Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; Purpose: Given a sparse matrix A in column-oriented form, and a symbolic analysis computed by umfpack_di_symbolic, the umfpack_di_numeric routine performs the numerical factorization, PAQ=LU, PRAQ=LU, or P(R\A)Q=LU, where P and Q are permutation matrices (represented as permutation vectors), R is the row scaling, L is unit-lower triangular, and U is upper triangular. This is required before the system Ax=b (or other related linear systems) can be solved. umfpack_di_numeric can be called multiple times for each call to umfpack_di_symbolic, to factorize a sequence of matrices with identical nonzero pattern. Simply compute the Symbolic object once, with umfpack_di_symbolic, and reuse it for subsequent matrices. umfpack_di_numeric safely detects if the pattern changes, and sets an appropriate error code. Returns: The status code is returned. See Info [UMFPACK_STATUS], below. Arguments: int Ap [n_col+1] ; Input argument, not modified. This must be identical to the Ap array passed to umfpack_di_symbolic. The value of n_col is what was passed to umfpack_di_symbolic (this is held in the Symbolic object). int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col]. This must be identical to the Ai array passed to umfpack_di_symbolic. double Ax [nz] ; Input argument, not modified, of size nz = Ap [n_col]. The numerical values of the sparse matrix A. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. void *Symbolic ; Input argument, not modified. The Symbolic object, which holds the symbolic factorization computed by umfpack_di_symbolic. The Symbolic object is not modified by umfpack_di_numeric. void **Numeric ; Output argument. **Numeric is the address of a (void *) pointer variable in the user's calling routine (see Syntax, above). On input, the contents of this variable are not defined. On output, this variable holds a (void *) pointer to the Numeric object (if successful), or (void *) NULL if a failure occurred. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Only the primary parameters are listed below: Control [UMFPACK_PIVOT_TOLERANCE]: relative pivot tolerance for threshold partial pivoting with row interchanges. In any given column, an entry is numerically acceptable if its absolute value is greater than or equal to Control [UMFPACK_PIVOT_TOLERANCE] times the largest absolute value in the column. A value of 1.0 gives true partial pivoting. If less than or equal to zero, then any nonzero entry is numerically acceptable as a pivot (this is changed from Version 4.0). Default: 0.1. Smaller values tend to lead to sparser LU factors, but the solution to the linear system can become inaccurate. Larger values can lead to a more accurate solution (but not always), and usually an increase in the total work. Control [UMFPACK_SYM_PIVOT_TOLERANCE]: This parameter is new to V4.1. If diagonal pivoting is attempted (the symmetric or symmetric-2by2 strategies are used) then this parameter is used to control when the diagonal entry is selected in a given pivot column. The absolute value of the entry must be >= Control [UMFPACK_SYM_PIVOT_TOLERANCE] times the largest absolute value in the column. A value of zero will ensure that no off-diagonal pivoting is performed, except that zero diagonal entries are not selected if there are any off-diagonal nonzero entries. If an off-diagonal pivot is selected, an attempt is made to restore symmetry later on. Suppose A (i,j) is selected, where i != j. If column i has not yet been selected as a pivot column, then the entry A (j,i) is redefined as a "diagonal" entry, except that the tighter tolerance (Control [UMFPACK_PIVOT_TOLERANCE]) is applied. This strategy has an effect similar to 2-by-2 pivoting for symmetric indefinite matrices. If a 2-by-2 block pivot with nonzero structure i j i: 0 x j: x 0 is selected in a symmetric indefinite factorization method, the 2-by-2 block is inverted and a rank-2 update is applied. In UMFPACK, this 2-by-2 block would be reordered as j i i: x 0 j: 0 x In both cases, the symmetry of the Schur complement is preserved. Control [UMFPACK_SCALE]: This parameter is new to V4.1. Version 4.0 did not scale the matrix. Note that the user's input matrix is never modified, only an internal copy is scaled. There are three valid settings for this parameter. If any other value is provided, the default is used. UMFPACK_SCALE_NONE: no scaling is performed. UMFPACK_SCALE_SUM: each row of the input matrix A is divided by the sum of the absolute values of the entries in that row. The scaled matrix has an infinity norm of 1. UMFPACK_SCALE_MAX: each row of the input matrix A is divided by the maximum the absolute values of the entries in that row. In the scaled matrix the largest entry in each row has a magnitude exactly equal to 1. Scaling is very important for the "symmetric" strategy when diagonal pivoting is attempted. It also improves the performance of the "unsymmetric" strategy. Default: UMFPACK_SCALE_SUM. double Info [UMFPACK_INFO] ; Output argument. Contains statistics about the numeric factorization. If a (double *) NULL pointer is passed, then no statistics are returned in Info (this is not an error condition). The following statistics are computed in umfpack_di_numeric (only the primary statistics are listed): Info [UMFPACK_STATUS]: status code. This is also the return value, whether or not Info is present. UMFPACK_OK Numeric factorization was successful. umfpack_di_numeric computed a valid numeric factorization. UMFPACK_WARNING_singular_matrix Numeric factorization was successful, but the matrix is singular. umfpack_di_numeric computed a valid numeric factorization, but you will get a divide by zero in umfpack_di_solve. For the other cases below, no Numeric object is created (*Numeric is (void *) NULL). UMFPACK_ERROR_out_of_memory Insufficient memory to complete the numeric factorization. UMFPACK_ERROR_argument_missing One or more required arguments are missing. UMFPACK_ERROR_invalid_Symbolic_object Symbolic object provided as input is invalid. UMFPACK_ERROR_different_pattern The pattern (Ap and/or Ai) has changed since the call to umfpack_di_symbolic which produced the Symbolic object. Info [UMFPACK_NUMERIC_SIZE]: the actual final size (in Units) of the entire Numeric object, including the final size of the variable part of the object. Info [UMFPACK_NUMERIC_SIZE_ESTIMATE], an estimate, was computed by umfpack_di_symbolic. The estimate is normally an upper bound on the actual final size, but this is not guaranteed. Info [UMFPACK_PEAK_MEMORY]: the actual peak memory usage (in Units) of both umfpack_di_symbolic and umfpack_di_numeric. An estimate, Info [UMFPACK_PEAK_MEMORY_ESTIMATE], was computed by umfpack_di_symbolic. The estimate is normally an upper bound on the actual peak usage, but this is not guaranteed. With testing on hundreds of matrix arising in real applications, I have never observed a matrix where this estimate or the Numeric size estimate was less than the actual result, but this is theoretically possible. Please send me one if you find such a matrix. Info [UMFPACK_FLOPS]: the actual count of the (useful) floating-point operations performed. An estimate, Info [UMFPACK_FLOPS_ESTIMATE], was computed by umfpack_di_symbolic. The estimate is guaranteed to be an upper bound on this flop count. The flop count excludes "useless" flops on zero values, flops performed during the pivot search (for tentative updates and assembly of candidate columns), and flops performed to add frontal matrices together. Info [UMFPACK_LNZ]: the actual nonzero entries in final factor L, including the diagonal. This excludes any zero entries in L, although some of these are stored in the Numeric object. The Info [UMFPACK_LU_ENTRIES] statistic does account for all explicitly stored zeros, however. Info [UMFPACK_LNZ_ESTIMATE], an estimate, was computed by umfpack_di_symbolic. The estimate is guaranteed to be an upper bound on Info [UMFPACK_LNZ]. Info [UMFPACK_UNZ]: the actual nonzero entries in final factor U, including the diagonal. This excludes any zero entries in U, although some of these are stored in the Numeric object. The Info [UMFPACK_LU_ENTRIES] statistic does account for all explicitly stored zeros, however. Info [UMFPACK_UNZ_ESTIMATE], an estimate, was computed by umfpack_di_symbolic. The estimate is guaranteed to be an upper bound on Info [UMFPACK_UNZ]. Info [UMFPACK_NUMERIC_TIME]: The CPU time taken, in seconds. \end{verbatim} } %------------------------------------------------------------------------------- \newpage \subsection{umfpack\_di\_solve} {\footnotesize \begin{verbatim} int umfpack_di_solve ( int sys, const int Ap [ ], const int Ai [ ], const double Ax [ ], double X [ ], const double B [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; Purpose: Given LU factors computed by umfpack_di_numeric (PAQ=LU, PRAQ=LU, or P(R\A)Q=LU) and the right-hand-side, B, solve a linear system for the solution X. Iterative refinement is optionally performed. Only square systems are handled. Singular matrices result in a divide-by-zero for all systems except those involving just the matrix L. Iterative refinement is not performed for singular matrices. In the discussion below, n is equal to n_row and n_col, because only square systems are handled. Returns: The status code is returned. See Info [UMFPACK_STATUS], below. Arguments: int sys ; Input argument, not modified. Defines which system to solve. (') is the linear algebraic transpose. sys value system solved UMFPACK_A Ax=b UMFPACK_At A'x=b UMFPACK_Pt_L P'Lx=b UMFPACK_L Lx=b UMFPACK_Lt_P L'Px=b UMFPACK_Lt L'x=b UMFPACK_U_Qt UQ'x=b UMFPACK_U Ux=b UMFPACK_Q_Ut QU'x=b UMFPACK_Ut U'x=b Iterative refinement can be optionally performed when sys is any of the following: UMFPACK_A Ax=b UMFPACK_At A'x=b For the other values of the sys argument, iterative refinement is not performed (Control [UMFPACK_IRSTEP], Ap, Ai, and Ax are ignored). int Ap [n+1] ; Input argument, not modified. int Ai [nz] ; Input argument, not modified. double Ax [nz] ; Input argument, not modified. If iterative refinement is requested (Control [UMFPACK_IRSTEP] >= 1, Ax=b or A'x=b is being solved, and A is nonsingular), then these arrays must be identical to the same ones passed to umfpack_di_numeric. The umfpack_di_solve routine does not check the contents of these arguments, so the results are undefined if Ap, Ai, Ax, are modified between the calls the umfpack_di_numeric and umfpack_di_solve. These three arrays do not need to be present (NULL pointers can be passed) if Control [UMFPACK_IRSTEP] is zero, or if a system other than Ax=b or A'x=b is being solved, or if A is singular, since in each of these cases A is not accessed. double X [n] ; Output argument. The solution to the linear system, where n = n_row = n_col is the dimension of the matrices A, L, and U. double B [n] ; Input argument, not modified. The right-hand side vector, b, stored as a conventional array of size n (or two arrays of size n for complex versions). This routine does not solve for multiple right-hand-sides, nor does it allow b to be stored in a sparse-column form. void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_di_numeric. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Control [UMFPACK_IRSTEP]: The maximum number of iterative refinement steps to attempt. A value less than zero is treated as zero. If less than 1, or if Ax=b or A'x=b is not being solved, or if A is singular, then the Ap, Ai, and Ax arguments are not accessed. Default: 2. double Info [UMFPACK_INFO] ; Output argument. Contains statistics about the solution factorization. If a (double *) NULL pointer is passed, then no statistics are returned in Info (this is not an error condition). The following statistics are computed in umfpack_di_solve (only the primary statistics are listed): Info [UMFPACK_STATUS]: status code. This is also the return value, whether or not Info is present. UMFPACK_OK The linear system was successfully solved. UMFPACK_WARNING_singular_matrix A divide-by-zero occurred. Your solution will contain Inf's and/or NaN's. Some parts of the solution may be valid. For example, solving Ax=b with A = [2 0] b = [ 1 ] returns x = [ 0.5 ] [0 0] [ 0 ] [ Inf ] UMFPACK_ERROR_out_of_memory Insufficient memory to solve the linear system. UMFPACK_ERROR_argument_missing One or more required arguments are missing. The B and X arguments are always required. Info and Control are not required. Ap, Ai and Ax are required if Ax=b or A'x=b is to be solved, the (default) iterative refinement is requested, and the matrix A is nonsingular. UMFPACK_ERROR_invalid_system The sys argument is not valid, or the matrix A is not square. UMFPACK_ERROR_invalid_Numeric_object The Numeric object is not valid. Info [UMFPACK_SOLVE_FLOPS]: the number of floating point operations performed to solve the linear system. This includes the work taken for all iterative refinement steps, including the backtrack (if any). Info [UMFPACK_SOLVE_TIME]: The time taken, in seconds. \end{verbatim} } %------------------------------------------------------------------------------- \newpage \subsection{umfpack\_di\_free\_symbolic} {\footnotesize \begin{verbatim} void umfpack_di_free_symbolic ( void **Symbolic ) ; Purpose: Deallocates the Symbolic object and sets the Symbolic handle to NULL. Arguments: void **Symbolic ; Input argument, deallocated and Symbolic is set to (void *) NULL on output. \end{verbatim} } %------------------------------------------------------------------------------- \subsection{umfpack\_di\_free\_numeric} {\footnotesize \begin{verbatim} void umfpack_di_free_numeric ( void **Numeric ) ; Purpose: Deallocates the Numeric object and sets the Numeric handle to NULL. Arguments: void **Numeric ; Input argument, deallocated and Numeric is set to (void *) NULL on output. \end{verbatim} } %------------------------------------------------------------------------------- \subsection{umfpack\_di\_defaults} {\footnotesize \begin{verbatim} void umfpack_di_defaults ( double Control [UMFPACK_CONTROL] ) ; Purpose: Sets the default control parameter settings. Arguments: double Control [UMFPACK_CONTROL] ; Output argument. Control is set to the default control parameter settings. \end{verbatim} } \end{document} cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/gpl.txt0000644000175000017500000004313311674452555020446 0ustar sonnesonne GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/License0000644000175000017500000000326411674452555020431 0ustar sonnesonneUMFPACK Version 5.2.0, Copyright 1995-2007 by Timothy A. Davis. All Rights Reserved. UMFPACK is available under alternate licenses, contact T. Davis for details. UMFPACK License: Your use or distribution of UMFPACK or any modified version of UMFPACK implies that you agree to this License. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU GPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. Availability: http://www.cise.ufl.edu/research/sparse/umfpack cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/ChangeLog0000644000175000017500000004464411674452555020705 0ustar sonnesonneMay 20, 2009, version 5.4.0 * bug fix in umfpack_make.m for Windows * disabled 2-by-2 strategy. It conflicts with how structurally singular matrices are handled. March 24, 2009, version 5.3.0 * bug fix for 2-by-2 strategy (diagonal map) for structurally singular matrices * compiler workaround for gcc 4.2.{3,4} in umf_singletons.c * added additional timer options in umfpack_timer.c (for POSIX) Sept 22, 2008 * minor update to documentation; no change to code Nov 1, 2007, version 5.2.0 * change of license to GNU GPL from GNU LGPL. This is the primary change to this version. * minor lint cleanup * port to MATLAB 7.5 (added -lmwblas to mex command) * added info output to the umfpack_btf command. May 31, 2007, version 5.1.0 * port to 64-bit MATLAB * Makefiles updated to reflect directory changes to AMD (UMFPACK v5.1.0 requires AMD v2.2.0) * Source/Makefile and GNUMakefile moved to Lib/ Dec 12, 2006: version 5.0.3 * minor MATLAB cleanup. Renamed umfpack mexFunction to umfpack2, to avoid filename clash with the built-in version of umfpack. Dec 2, 2006, version 5.0.2 * minor change to umfpack_report_info: does not print timings less than 0.001 seconds. * bug fix for complex case when using a non-gcc compiler (simplified the scaling of the pivot column). Does not affect the use of UMFPACK in MATLAB. Aug 31, 2006, version 5.0.1 * Minor correction to comments in umfpack_get_numeric.h. May 5, 2006, version 5.0 * Tcov subdirectory added. This has existed since the first C version of UMFPACK, but is only now included in the released version. It provides a near 100% test coverage for UMFPACK. The code isn't pretty, but it works. * now uses CHOLMOD's method for interfacing to the BLAS, including the BLAS_INT definition. This way, the UF_long version of UMFPACK can call the int BLAS. * revised to use AMD v2.0 Apr 7, 2006 * Minor correction to UMFPACK/Source/Makefile, for those who do not have GNU make. No change to version number, because no code was modified. Oct 10, 2005, version 4.6 * umf_solve.c modified for the complex case. A, X, and b can be split complex or unsplit. Prior version required the form of A, X, and B to be identical (all split or all unsplit). (Thanks to David Bateman). * added Cygwin to architecture detection. * added UMFPACK_SUBSUB_VERSION Aug. 30, 2005: v4.5 released * License changed to GNU LGPL. * The Make/ directory removed; configurations are now in ../UFconfig. * requires AMD v1.2 or later * added UMFPACK_MAIN_VERSION and UMFPACK_SUB_VERSION, defined as 4 and 5, respectively, for version 4.5. These macros will be updated for all future versions. See Include/umfpack.h for details. * function pointers used for malloc, free, calloc, realloc, printf, hypot, and complex divide. Defined in AMD/Source/amd_global.c, AMD/Source/amd_internal.h, UMFPACK/Source/umfpack_global.c, and UMFPACK/Include/umfpack_global.h. Compile-time dependence on The MathWorks "util.h", ut* routines and ut* macros removed. Jan. 28, 2005: v4.4 released * bug fix: when Qinit is provided to umfpack_*_qsymbolic, only the symmetric and unsymmetric strategies are now permitted. The auto and 2-by-2 strategies are not allowed. In v4.3 and earlier, providing Qinit and requesting the symmetric strategy did not always work (you got the unsymmetric strategy instead). This does not affect umfpack_*_symbolic, which computes its own ordering and can use all 4 strategies (auto, symmetric, unsymmetric, and 2-by-2). * umfpack_get_determinant added. (Thanks to David Bateman). * packed complex case added for all routines (previously only used in umfpack_report_vector). This allows arrays of ANSI C/C++ complex type to be passed directly to UMFPACK. * added umf_multicomple.c to assist in the compilation of UMFPACK in Microsoft Visual Studio, which does not have the required flexibility of the Unix "make" command. * local variable declarations reordered to encourage double-word alignment of double's and Entry's, for better performance. * note that with the exception of the behavior when a user-provided ordering is passed to umfpack_*_qsymbolic, versions 4.1 through 4.4 have comparable performance (ordering quality, memory usage, and run time). v4.1 is much better than v4.0 in performance. Jan. 11, 2005: v4.3.1 released * bug fix in umf_solve. This bug is only the 4th one found in the C versions of UMFPACK to date (Version 3.0 to 4.3.1, from March 2001 to Jan. 2005, excluding workarounds for quirky compilers). No bugs have been reported in the last Fortran version of UMFPACK (MA38, or UMFPACK V2.2.1) since its release in Jan. 1998. In Version 4.3, a bug in umf_solve caused iterative refinement to be disabled when solving A'x=b or A.'x=b after factorizing A. Modified the umfpack mexFunction to factorize A and then solve A'x=b when performing the operation x=b/A (as "umfpack(b,'/',A). Note that this has no effect on the use of UMFPACK in MATLAB itself, since MATLAB does not use the umfpack mexFunction for x=b/A. When computing x=b/A, MATLAB factorizes A' and computes x=(A'\b')' instead. The following source code files changed: UMFPACK/MATLAB/umfpackmex.c (see above) UMFPACK/Source/umf_solve.c (see source code: 2 lines changed) UMFPACK/Include/umfpack.h (version and date changed) UMFPACK/MATLAB/umfpack_test.m (new file) Jan. 16, 2004: v4.3 released. * user interface of v4.3 is upwardly-compatible with v4.2 and v4.1. No bugs found in v4.1 (except for one workaround for an old compiler). These changes add features only. * Note that v4.0 has a bug in umf_scale_column.c. The bug was patched in that version on Jan. 12, 2004. The bug does not appear in v4.1 and later. The bug is thus present in MATLAB 6.5, but it occurs very rarely, fortunately. It can occur when dividing a nonzero entry in the pivot column by the pivot value results in an underflow. * added to umfpackmex.c, for DBL_EPSILON. Some non-standard compilers (Microsoft Visual C++) require this. * #pragma added to umf_analyze.c, as a workaround around a bug in an old Intel compiler. * mexFunction interface to MATLAB modified. Call to mexCallMATLAB removed, which can be slow. In V4.1 it was used only to get MATLAB's spparms ('spumoni') value. * The AMD mexFunction was also modified in the same way (v1.1), with the call to mexCallMATLAB removed. Note that UMFPACK v4.1 through v4.3 can use either AMD v1.0 or AMD v1.1. * -DNO_DIVIDE_BY_ZERO option added. If this non-default option is enabled at compile time, and if the pivot value is zero, then no division occurs (zeros on the diagonal of U are treated as if they were equal to one). By default, the division by zero does occur. * -DNO_TIMER option added. If this non-default option is enabled at compile time, then no timers (times ( ), clock ( ), getrusage ( )) are used. V4.2: A special release for COMSOL, Inc., only (FEMLAB) * drop tolerance added. A few new parameters in the Control array are used, and a few new Info entries. May 6, 2003: V4.1 released. * No bugs were found in the prior version, Version 4.0. New features added only. Major changes throughout the code. User interface nearly unchanged, however. * Version 4.1 is upward-compatible with Version 4.0. The calling sequence of some user-callable routines in Version 4.0 have changed in this version. The routines umfpack_*_symbolic, umfpack_*_qsymbolic, umfpack_*_get_symbolic, and umfpack_*_get_numeric have new arguments added to them. The new arguments are optional. If you want to use a calling sequence similar to v4.0, simply pass NULL pointers in place of the new arguments. There are two new timing routines, umfpack_tic and umfpack_toc. A new user-callable routine, umfpack_*_scale, has been added. * "auto", "unsymmetric", "symmetric", and "2-by-2" strategies added. The symmetric strategy uses AMD on A+A' as the column preordering, followed by a postorder of the assembly tree of A+A'. Column ordering refinement is turned off, and diagonal entries are prefered as pivots. V4.0 only had the unsymmetric strategy. The 2-by-2 strategy does row permutations and attempts to find a zero-free diagonal while at the same time maintaining structural symmetry, and then uses the symmetric strategy on the permuted matrix. * row-scaling added. The default is to divide each row by the sum of the absolute values of each row. Other options are no scaling, and to divide each row by the max abs value in each row. * Matrices with upper bound memory usage greater than the maximum integer (2GB for 32-bit int's) can now be factorized (assuming the actual memory usage is still less than the maximum integer). With this change, the UMFPACK_ERROR_problem_too_large error code is no longer returned. * The current frontal matrix (Work->Fx) is no longer allocated as a static size, via malloc. It can grow and shrink, and is allocated from Numeric->Memory. * The AMD (Version 1.0) package is now required. It is available separately. To compile UMFPACK, it must appear as ../AMD if you are in the main UMFPACK directory. * The UMFPACK mexFunction now uses the internal utMalloc, utRealloc, and utFree routines, by default (except on Windows). * Three control parameters for modifying relaxed amalgamation removed. These values are now fixed at compile-time. * Many new statistics added to Info, and new control parameters added. * The umfpack mexFunction now returns permutation matrices for P and Q, not permutation vectors. It also returns the scale factors as a diagonal matrix. The factorization is now L*U = P*(R\A)*Q. * Option added for controlling the initial allocation of the workspace for the current frontal matrix. * pivot tolerance of zero treated differently. symmetric pivot tolerance added. * Makefile and GNUmakefile changed. umf_* routines with no double or complex values are now compiled just twice (int and long versions) rather than 4 times. * New routines added to save and load the Numeric and Symbolic objects to/from binary files. * Simple Fortran interface added. Apr 11, 2002: * Version 4.0 released. * bug fix: the Microsoft compiler doesn't handle NaN's properly. utIsNaN, and other ut* routines, added for MathWorks version to handle this properly. Apr 1, 2002: * bug fix: if a column was all NaN's, then UMFPACK would fail to find a pivot row. umf_row_search.c and umf_internal.h modified to fix this problem. Mar 9, 2002: V4.0beta released * Map argument added to umfpack_*_triplet_to_col. New files (umf_triplet.[ch]) added. * minor changes made so that UMFPACK can be compiled with g++ * additional error checking added to umfpack_*_numeric, for detecting more changes in pattern (Ap, Ai) since last call to umfpack_*_symbolic Feb 21, 2002: * User Guide explains the Makefile vs. GNUmakefile * umf_config.h modified, so that the complex SCSL C-BLAS uses (void *) arguments instead of (scsl_zomplex *). gcc generates some spurious warnings (cc doesn't complain). Affects the SGI IRIX only. * ported to Compaq Alpha Feb 20, 2002: V4.0 (alpha) released. * V4.0 not yet ported to the Compaq Alpha (V3.2 was ported). Feb 6 to Feb 19, 2002: * Relaxed restrictions on sizes of arrays for umfpack_*_transpose and umfpack_*_triplet_to_col. Size of "max(n,nz)" now just size nz. * workspace for umfpack_*_wsolve increased in size. * two user arrays for umfpack_*_get_symbolic increased in size, by 1 (Chain_maxrows, Chain_maxcols). * lu_normest.m added. Jan 18 to Feb 5, 2002: * The matrix A can be complex, singular, and/or rectangular. The solve step that uses the LU factors can only handle matrices that are complex or real, singuluar or non-singular, and *** square ***, however. * Estimate of the condition number computed: (min (abs (diag (U))) / (max (abs (diag (U))))) * Forward/backsolves can solve with A.' as well as A'. * char * arguments removed from user-callable routines to make it easier for Fortran to call UMFPACK. No Fortran interface is (yet) provided, however. The solve codes for umfpack_*_*solve changed to #define'd integers: UMFPACK_A Ax=b UMFPACK_At A'x=b UMFPACK_Aat A.'x=b UMFPACK_Pt_L P'Lx=b UMFPACK_L Lx=b UMFPACK_Lt_P L'Px=b UMFPACK_Lat_P L.'Px=b UMFPACK_Lt L'x=b UMFPACK_U_Qt UQ'x=b UMFPACK_U Ux=b UMFPACK_Q_Ut QU'x=b UMFPACK_Q_Uat QU.'x=b UMFPACK_Ut U'x=b UMFPACK_Uat U.'x=b All arguments are now either int, long scalars (pass by value), or int, long, double arrays (pass by reference), or void * pointers (pass by value or reference). A void * pointer is of size 32 or 64 bits on most machines. There is no need for the caller (C or Fortran) to dereference the void * pointers, so these can be treated as integer*4 or integer*8 in Fortran. A Fortran interface would have to have all arguments passed by reference. * All user-callable routine names changed. The four sets are now: umfpack_di_* real (double precision), int's as integers umfpack_dl_* real (double precision), longs's as integers umfpack_zi_* real (double precision), int's as integers umfpack_zl_* real (double precision), longs's as integers * Ptree (row preordering) and info on pivotal rows for each front added to Symbolic object (extracted by umfpack_*_get_symbolic). Ptree added as output argument to "umfpack (A, 'symbolic')" mexFunction. * umfpack_*_transpose can do A' or A.' * umfpack_wsolve.c file removed (now generated from umfpack_solve.c). * Can now extract just the diagonal of U with umfpack_*_get_numeric, without having to extract the entire matrix U. * UMFPACK_ERROR_singular_matrix (-2) removed. * UMFPACK_WARNING_singular_matrix (1) added. * Control [UMFPACK_PIVOT_OPTION] removed. No longer any symmetric pivot option (conflicts with the handling of singular and rectangular matrices). * Iterative refinement can do Ax=b, A'x=b, or A.'x=b. * Most floating-point operations done in macros, to support the complex versions. * Info [UMFPACK_N] is now Info [UMFPACK_NROW] * Info [UMFPACK_NCOL], Info [UMFPACK_UDIAG_NZ], Info [UMFPACK_UDIAG_NZ] added. * umfpack_* routines with "n" as input now use two arguments, n_row and n_col. * umfpack mexFunction now explicitly transposes A for b/A. It computes it using the array transpose as (A.'\b.').' January 1, 2002: UMFPACK Version 3.2 released. Submitted to ACM Trans. on Mathematical Software. * The umfpack mexFunction now returns the Info array when the matrix is singular. Returned an empty array prior to this change. * Renamed variable that conflicted with system library routines (system and j1). * Added a #ifdef MATHWORKS definition, so the built-in UMFPACK routine (in a future release of MATLAB) can use the internal ut* memory allocation routines, ut* assertion routine, and utPrintf. * MAX and MIN are not defined if they are already defined. * A bug fix in umf_kernel_init (a variable was not properly initialized). * Removed unused variables. October 8, 2001: UMFPACK Version 3.1 released. August-October, 2001: * added umfpack_btf M-file. * modified the BLAS update in the frontal matrix. If there are only a few pivots in remaining in the current front, then the BLAS3 update is delayed to include pivots in the next front. * Removed the special-case handling of dense columns from the numerical factorization (kept it in the colamd preordering). This improves the performance of UMFPACK on dense matrices by a factor of 5 or so, and simplifies the code. * Added a symmetric-preference pivoting option. The option slightly (but uniformly) improves the ordering when factorizing matrices with symmetric nonzero pattern. That class of matrix is better handled by the symmetric-pattern multifrontal method (MA41 in the Harwell Subroutine Library), however. * Fixed the detection of integer overflow. The 32-bit version cannot make use of more than 2GB of main memory (use the 64-bit version in that case, instead). The 32-bit version did not correctly detect when it was trying to factorize too large of a matrix. May 4, 2001: * SGI port extended. It can now call the SCSL Scientific Library, with 64-bit BLAS. Make.sgi and umf_config.h modified. April 30, 2001: UMFPACK Version 3.0 released. Changes since 3.0Beta release: * long integer version added (umfpack_l_* user-callable routines). * Peak memory usage in the numerical factorization reduced by a total of 12n integers (8n temporary workspace used during numerical factorization, and 4n for the permanent LU factors which was allocated at the beginning of factorization). * Ported to the IBM RS 6000 and Compaq Alpha, with help from Anshul Gupta and Friedrich Grund, respectively. * 64-bit version added. Uses dgemm_64, dgemv_64, and dger_64 in the Sun Performance Library. 64-bit versions with the BLAS might not work on any other platform, because they take int's as their integer input arguments instead of long's. Unfortunately, the proposed ANSI definition of the C-BLAS also uses int's as input integer arguments. It ought to use long's, or include a version that uses long's, just like the Sun Performance Library BLAS. * Additional statistics returned in Info: Info [UMFPACK_SIZE_OF_INT] sizeof (int) Info [UMFPACK_SIZE_OF_LONG] sizeof (long) Info [UMFPACK_SIZE_OF_POINTER] sizeof (void *) Info [UMFPACK_SIZE_OF_ENTRY] (was Info [UMFPACK_WORD]) Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE] est. front matrix size Info [UMFPACK_MAX_FRONT_SIZE] actual max frontal matrix size. Contents of Info rearranged. * UMFPACK_ERROR_bad_configurution error code replaced with UMFPACK_ERROR_problem_too_large error code. The "bad configuration" error occured when sizeof (int) < sizeof (size_t). Now, the int version of UMFPACK can use 32-bit int's and 64-bit pointers, and the long version can use 64-bit long's and 64-bit pointers. Both versions check to see if the array sizes allocated are larger than what can be accessed by an integer index variable (int or long, depending on the version), and returns UMFPACK_ERROR_problem_too_large if they become too large. March 15, 2001: UMFPACK Version 3.0Beta released. cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.sed20000644000175000017500000000004711674452555021573 0ustar sonnesonne/[/][*]/d /[*][/]/d /INCLUDE umfpack/d cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.bib0000644000175000017500000002046311674452555021476 0ustar sonnesonne@string{TOMS = "ACM Trans. Math. Softw."} @string{SIMAX = "SIAM J. Matrix Anal. Applic."} @string{SINUM = "SIAM J. Numer. Anal."} @string{SIAMJSC = "SIAM J. Sci. Comput."} @string{SIAMJSSC = "SIAM J. Sci. Statist. Comput."} @string{IJNME = "Internat. J. Numer. Methods Eng."} @string{SIAMJADM = "SIAM J. Alg. Disc. Meth."} @article{AmestoyDavisDuff96, author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.}, title={An approximate minimum degree ordering algorithm}, journal=SIMAX, year={1996} ,volume={17} ,number={4} ,pages={886-905}} @article{AmestoyDavisDuff03, author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.}, title={Algorithm 837: {AMD}, an approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,number={3} ,pages={381-388}} @techreport{AmestoyDavisDuff03_user, author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.}, title={{AMD} Version 1.0 User Guide}, institution={CISE Dept., Univ. of Florida}, year={2003} ,number={TR-03-011} ,address={Gainesville, FL} ,note={www.cise.ufl.edu/tech-reports.} } @article{Davis03, author={Davis, T. A.}, title={A column pre-ordering strategy for the unsymmetric-pattern multifrontal method}, journal=TOMS, year={2004} ,volume={30} ,number={2} ,pages={165-195}} @article{Davis03_algo, author={Davis, T. A.}, title={Algorithm 832: {UMFPACK}, an unsymmetric-pattern multifrontal method}, journal=TOMS, year={2004} ,volume={30} ,number={2} ,pages={196-199}} @techreport{Davis03_umf, author={Davis, T. A.}, title={{UMFPACK} User Guide}, institution={Univ. of Florida, CISE Dept.}, year={2005} ,number={TR-04-003 (revised)} ,address={Gainesville, FL} ,note={(www.cise.ufl.edu/tech-reports)} } @techreport{Davis03_umfquick, author={Davis, T. A.}, title={{UMFPACK} Quick Start Guide}, institution={Univ. of Florida, CISE Dept.}, year={2005} ,number={TR-04-005 (revised)} ,address={Gainesville, FL} ,note={(www.cise.ufl.edu/tech-reports)} } @article{DavisDuff97, author={Davis, T. A. and Duff, I. S.}, title={An unsymmetric-pattern multifrontal method for sparse {LU} factorization}, journal=SIMAX, year={1997} ,volume={18} ,number={1} ,pages={140-158}} @article{DavisDuff99, author={Davis, T. A. and Duff, I. S.}, title={A combined unifrontal/multifrontal method for unsymmetric sparse matrices}, journal=TOMS, volume={25}, number={1}, pages={1-19}, year={1999}} @article{SuperLU99, author={Demmel, J. W. and Eisenstat, S. C. and Gilbert, J. R. and Li, X. S. and Liu, J. W. H.}, title={A supernodal approach to sparse partial pivoting}, journal=SIMAX, year={1999} ,volume={20} ,number={3} ,pages={720-755} ,note={www.netlib.org} } @article{ACM679a, author={Dongarra, J. J. and Du Croz, J. and Duff, I. S. and Hammarling, S.}, title={A set of level-3 basic linear algebra subprograms}, journal=TOMS, year={1990} ,volume={16} ,number={1} ,pages={1--17}} @article{netlib, author={Dongarra, J. J. and Grosse, E.}, title={Distribution of mathematical software via electronic mail}, journal={Comm. ACM}, year={1987} ,volume={30} ,pages={403-407} ,note={www.netlib.org} } @article{Duff78b, author={Duff, I. S. and Reid, J. K.}, year={1978}, title={Algorithm 529: Permutations to Block Triangular Form}, journal=TOMS, volume={4}, annote={f}, number={2}, pages={189-192}, keywords={102 ordering block triangular form}} @article{Duff81b, author={Duff, I. S.}, year={1981}, title={Algorithm 575: Permutations for a Zero-Free Diagonal}, journal=TOMS, annote={f}, volume={7}, pages={387-390}, keywords={ordering, zero-free diagonal}} @techreport{GotoVandeGeijn02, author = {Goto, K. and van de Geijn, R.}, title = {On Reducing {TLB} Misses in Matrix Multiplication, {FLAME} Working Note 9}, institution={The University of Texas at Austin, Department of Computer Sciences}, number={TR-2002-55}, month={Nov.}, year={2002}} @article{GeorgeNg85, author={George, A. and Ng, E. G.}, year={1985}, title={An Implementation of {G}aussian Elimination with Partial Pivoting for Sparse Systems}, journal=SIAMJSSC, volume={6}, number={2}, pages={390-409}} @article{GeorgeNg87, author={George, A. and Ng, E. G.}, year={1987}, title={Symbolic Factorization for Sparse {G}aussian Elimination with Partial Pivoting}, journal={SIAM J. Sci. Statist. Comput.}, volume={8}, number={6}, pages={877-898}} @article{GilbertMolerSchreiber, author={Gilbert, J. R. and Moler, C. and Schreiber, R.}, title={Sparse matrices in {MATLAB}: design and implementation}, journal=SIMAX, year={1992} ,volume={13} ,number={1} ,pages={333-356}} @article{GilbertPeierls88, author={Gilbert, J. R. and Peierls, T.}, year={1988}, title={Sparse Partial Pivoting in Time Proportional to Arithmetic Operations}, journal={SIAM J. Sci. Statist. Comput.}, volume={9}, pages={862-874}} @article{Gustavson78, author={Gustavson, F. G.}, year={1978}, title={Two Fast Algorithms for Sparse Matrices: Multiplication and Permuted Transposition}, journal=TOMS, volume={4}, number={3}, pages={250-269}} @techreport{Larimore98, author={Larimore, S. I.}, title={An approximate minimum degree column ordering algorithm}, institution={Univ. of Florida, CISE Dept.}, year={1998} ,number={TR-98-016} ,address={Gainesville, FL} ,note={www.cise.ufl.edu/tech-reports}} @article{DavisGilbertLarimoreNg00, author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.}, title={A column approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,number={3} ,pages={353-376}} @article{DavisGilbertLarimoreNg00_algo, author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.}, title={Algorithm 836: {COLAMD}, a column approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,number={3} ,pages={377-380}} @INCOLLECTION{GilbertNg93, author = {J. R. Gilbert and E. G. Ng}, editor = {A. George and J. R. Gilbert and J. W.H. Liu}, year = 1993, title = {Predicting Structure in Nonsymmetric Sparse Matrix Factorizations}, booktitle = {Graph Theory and Sparse Matrix Computation}, series = {Volume 56 of the {IMA} Volumes in Mathematics and its Applications}, pages = {107-139}, publisher = {Springer-Verlag} } @techreport{ATLAS, author={Whaley, R. C and Petitet, A. and Dongarra, J. J.}, title={Automated Emperical Optimization of Software and the {ATLAS} Project}, institution={Computer Science Department, The University of Tennessee}, year={2000} ,number={LAPACK Working Note 147} ,month={September} ,note={www.netlib.org/atlas} } @article{DaydeDuff99, author = "M. J. Dayd\'{e} and I. S. Duff", title = "The {RISC} {BLAS}: A Blocked Implementation of Level 3 {BLAS} for {RISC} Processors", journal = TOMS, volume = "25", number = "3", month = {Sept.}, year ="1999" } @article{ardd:89, author = {M. Arioli and J. W. Demmel and I. S. Duff}, year = "1989", title = {Solving sparse linear systems with sparse backward error}, journal = SIMAX, volume = {10}, pages = {165-190} } @article{DavisHager99, author={Davis, T. A. and Hager, W. W.}, title={Modifying a sparse {C}holesky factorization}, journal=SIMAX, year={1999} ,volume={20} ,number={3} ,pages={606-627} } @article{dusc:96, author = {I. S. Duff and J. A. Scott}, title = {The design of a new frontal code for solving sparse unsymmetric systems}, journal = TOMS, year = "1996", volume = "22", number = "1", pages = "30-45" } @article{Duff78a, author={Duff, I. S. and Reid, J. K.}, year={1978}, title={An Implementation of {T}arjan's Algorithm for the Block Triangularization of a Matrix}, journal=TOMS, volume={4}, number={2}, pages={137-147} } @book{GeorgeLiu, author={George, A. and Liu, J. W. H.}, year={1981}, title={Computer Solution of Large Sparse Positive Definite Systems}, publisher={Englewood Cliffs, New Jersey: Prentice-Hall} } @article{GilbertNgPeyton94, author={Gilbert, J. R. and Ng, E. G. and Peyton, B. W.}, title={An efficient algorithm to compute row and column counts for sparse {C}holesky factorization}, journal=SIMAX, year={1994} ,volume={15} ,number={4} ,pages={1075-1091} } @techreport{DuffGrimesLewis87b, author={Duff, I. S. and Grimes, R. G. and Lewis, J. G.}, year={1987}, title={Users' Guide for the Harwell-Boeing Sparse Matrix Test Collection}, institution={AERE Harwell Laboratory, United Kingdom Atomic Energy Authority}} cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Doc/UserGuide.stex0000644000175000017500000033276011674452555021733 0ustar sonnesonne%------------------------------------------------------------------------------- % The UserGuide.stex file. Processed into UserGuide.tex via sed. %------------------------------------------------------------------------------- \documentclass[11pt]{article} \newcommand{\m}[1]{{\bf{#1}}} % for matrices and vectors \newcommand{\tr}{^{\sf T}} % transpose \newcommand{\he}{^{\sf H}} % complex conjugate transpose \newcommand{\implies}{\rightarrow} \topmargin 0in \textheight 9in \oddsidemargin 0pt \evensidemargin 0pt \textwidth 6.5in \begin{document} \author{Timothy A. Davis \\ Dept. of Computer and Information Science and Engineering \\ Univ. of Florida, Gainesville, FL} \title{UMFPACK Version 5.4.0 User Guide} \date{May 20, 2009} \maketitle %------------------------------------------------------------------------------- \begin{abstract} UMFPACK is a set of routines for solving unsymmetric sparse linear systems, $\m{Ax}=\m{b}$, using the Unsymmetric MultiFrontal method and direct sparse LU factorization. It is written in ANSI/ISO C, with a MATLAB interface. UMFPACK relies on the Level-3 Basic Linear Algebra Subprograms (dense matrix multiply) for its performance. This code works on Windows and many versions of Unix (Sun Solaris, Red Hat Linux, IBM AIX, SGI IRIX, and Compaq Alpha). \end{abstract} %------------------------------------------------------------------------------- Technical Report TR-04-003 (revised) Copyright\copyright 1995-2009 by Timothy A. Davis. All Rights Reserved. UMFPACK is available under alternate licences; contact T. Davis for details. {\bf UMFPACK License:} Your use or distribution of UMFPACK or any modified version of UMFPACK implies that you agree to this License. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Permission is hereby granted to use or copy this program under the terms of the GNU GPL, provided that the Copyright, this License, and the Availability of the original version is retained on all copies. User documentation of any code that uses this code or any modified version of this code must cite the Copyright, this License, the Availability note, and "Used by permission." Permission to modify the code and to distribute modified code is granted, provided the Copyright, this License, and the Availability note are retained, and a notice that the code was modified is included. {\bf Availability:} http://www.cise.ufl.edu/research/sparse/umfpack {\bf Acknowledgments:} This work was supported by the National Science Foundation, under grants DMS-9504974, DMS-9803599, and CCR-0203270. The upgrade to Version 4.1 and the inclusion of the symmetric and 2-by-2 pivoting strategies were done while the author was on sabbatical at Stanford University and Lawrence Berkeley National Laboratory. %------------------------------------------------------------------------------- \newpage %------------------------------------------------------------------------------- \tableofcontents %------------------------------------------------------------------------------- \newpage \section{Overview} %------------------------------------------------------------------------------- UMFPACK\footnote{Pronounced with two syllables: umph-pack} is a set of routines for solving systems of linear equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and unsymmetric. It is based on the Unsymmetric-pattern MultiFrontal method \cite{DavisDuff97,DavisDuff99}. UMFPACK factorizes $\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$, where $\m{L}$ and $\m{U}$ are lower and upper triangular, respectively, $\m{P}$ and $\m{Q}$ are permutation matrices, and $\m{R}$ is a diagonal matrix of row scaling factors (or $\m{R}=\m{I}$ if row-scaling is not used). Both $\m{P}$ and $\m{Q}$ are chosen to reduce fill-in (new nonzeros in $\m{L}$ and $\m{U}$ that are not present in $\m{A}$). The permutation $\m{P}$ has the dual role of reducing fill-in and maintaining numerical accuracy (via relaxed partial pivoting and row interchanges). The sparse matrix $\m{A}$ can be square or rectangular, singular or non-singular, and real or complex (or any combination). Only square matrices $\m{A}$ can be used to solve $\m{Ax}=\m{b}$ or related systems. Rectangular matrices can only be factorized. UMFPACK first finds a column pre-ordering that reduces fill-in, without regard to numerical values. It scales and analyzes the matrix, and then automatically selects one of two strategies for pre-ordering the rows and columns: {\em unsymmetric} and {\em symmetric}. These strategies are described below. First, all pivots with zero Markowitz cost are eliminated and placed in the LU factors. The remaining submatrix $\m{S}$ is then analyzed. The following rules are applied, and the first one that matches defines the strategy. \begin{itemize} \item Rule 1: $\m{A}$ rectangular $\implies$ unsymmetric. \item Rule 2: If the zero-Markowitz elimination results in a rectangular $\m{S}$, or an $\m{S}$ whose diagonal has not been preserved, the unsymmetric strategy is used. \item The symmetry $\sigma_1$ of $\m{S}$ is computed. It is defined as the number of {\em matched} off-diagonal entries, divided by the total number of off-diagonal entries. An entry $s_{ij}$ is matched if $s_{ji}$ is also an entry. They need not be numerically equal. An {\em entry} is a value in $\m{A}$ which is present in the input data structure. All nonzeros are entries, but some entries may be numerically zero. Let $d$ be the number of nonzero entries on the diagonal of $\m{S}$. Let $\m{S}$ be $\nu$-by-$\nu$. Rule 3: $(\sigma_1 \ge 0.7) \:\wedge\: (d \ge 0.9 \nu) \implies$ symmetric. The matrix has a nearly symmetric nonzero pattern (70\% or more), and a mostly-zero-free diagonal (90\% or more nonzero). \item Rule 4: Otherwise, the unsymmetric strategy is used. \end{itemize} Each strategy is described below: \begin{itemize} \item {\em unsymmetric}: The column pre-ordering of $\m{S}$ is computed by a modified version of COLAMD \cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00,Larimore98}. The method finds a symmetric permutation $\m{Q}$ of the matrix $\m{S}\tr\m{S}$ (without forming $\m{S}\tr\m{S}$ explicitly). This is a good choice for $\m{Q}$, since the Cholesky factors of $\m{(SQ)\tr(SQ)}$ are an upper bound (in terms of nonzero pattern) of the factor $\m{U}$ for the unsymmetric LU factorization ($\m{PSQ}=\m{LU}$) regardless of the choice of $\m{P}$ \cite{GeorgeNg85,GeorgeNg87,GilbertNg93}. This modified version of COLAMD also computes the column elimination tree and post-orders the tree. It finds the upper bound on the number of nonzeros in L and U. It also has a different threshold for determining dense rows and columns. During factorization, the column pre-ordering can be modified. Columns within a single super-column can be reshuffled, to reduce fill-in. Threshold partial pivoting is used with no preference given to the diagonal entry. Within a given pivot column $j$, an entry $a_{ij}$ can be chosen if $|a_{ij}| \ge 0.1 \max |a_{*j}|$. Among those numerically acceptable entries, the sparsest row $i$ is chosen as the pivot row. \item {\em symmetric}: The column ordering is computed from AMD \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}, applied to the pattern of $\m{S}+\m{S}\tr$ followed by a post-ordering of the supernodal elimination tree of $\m{S}+\m{S}\tr$. No modification of the column pre-ordering is made during numerical factorization. Threshold partial pivoting is used, with a strong preference given to the diagonal entry. The diagonal entry is chosen if $a_{jj} \ge 0.001 \max |a_{*j}|$. Otherwise, a sparse row is selected, using the same method used by the unsymmetric strategy. \end{itemize} The symmetric strategy, and their automatic selection, are new to Version 4.1. Version 4.0 only used the unsymmetric strategy. Versions 4.1 through 5.3 included a {\em 2-by-2} ordering strategy, but this option has been disabled in Version 5.4. Once the strategy is selected, the factorization of the matrix $\m{A}$ is broken down into the factorization of a sequence of dense rectangular frontal matrices. The frontal matrices are related to each other by a supernodal column elimination tree, in which each node in the tree represents one frontal matrix. This analysis phase also determines upper bounds on the memory usage, the floating-point operation count, and the number of nonzeros in the LU factors. UMFPACK factorizes each {\em chain} of frontal matrices in a single working array, similar to how the unifrontal method \cite{dusc:96} factorizes the whole matrix. A chain of frontal matrices is a sequence of fronts where the parent of front $i$ is $i$+1 in the supernodal column elimination tree. For the nonsingular matrices factorized with the unsymmetric strategy, there are exactly the same number of chains as there are leaves in the supernodal column elimination tree. UMFPACK is an outer-product based, right-looking method. At the $k$-th step of Gaussian elimination, it represents the updated submatrix $\m{A}_k$ as an implicit summation of a set of dense sub-matrices (referred to as {\em elements}, borrowing a phrase from finite-element methods) that arise when the frontal matrices are factorized and their pivot rows and columns eliminated. Each frontal matrix represents the elimination of one or more columns; each column of $\m{A}$ will be eliminated in a specific frontal matrix, and which frontal matrix will be used for which column is determined by the pre-analysis phase. The pre-analysis phase also determines the worst-case size of each frontal matrix so that they can hold any candidate pivot column and any candidate pivot row. From the perspective of the analysis phase, any candidate pivot column in the frontal matrix is identical (in terms of nonzero pattern), and so is any row. However, the numeric factorization phase has more information than the analysis phase. It uses this information to reorder the columns within each frontal matrix to reduce fill-in. Similarly, since the number of nonzeros in each row and column are maintained (more precisely, COLMMD-style approximate degrees \cite{GilbertMolerSchreiber}), a pivot row can be selected based on sparsity-preserving criteria (low degree) as well as numerical considerations (relaxed threshold partial pivoting). When the symmetric strategy are used, the column preordering is not refined during numeric factorization. Row pivoting for sparsity and numerical accuracy is performed if the diagonal entry is too small. More details of the method, including experimental results, are described in \cite{Davis03,Davis03_algo}, available at http://www.cise.ufl.edu/tech-reports. %------------------------------------------------------------------------------- \section{Availability} %------------------------------------------------------------------------------- In addition to appearing as a Collected Algorithm of the ACM, UMFPACK is available at \newline http://www.cise.ufl.edu/research/sparse. It is included as a built-in routine in MATLAB. Version 4.0 (in MATLAB 6.5) does not have the symmetric strategy and it takes less advantage of the level-3 BLAS \cite{DaydeDuff99,ACM679a,ATLAS,GotoVandeGeijn02}. Versions 5.x through v4.1 tend to be much faster than Version 4.0, particularly on unsymmetric matrices with mostly symmetric nonzero pattern (such as finite element and circuit simulation matrices). Version 3.0 and following make use of a modified version of COLAMD V2.0 by Timothy A.~Davis, Stefan Larimore, John Gilbert, and Esmond Ng. The original COLAMD V2.1 is available in as a built-in routine in MATLAB V6.0 (or later), and at http://www.cise.ufl.edu/research/sparse. These codes are also available in Netlib \cite{netlib} at http://www.netlib.org. UMFPACK Versions 2.2.1 and earlier, co-authored with Iain Duff, are available at http://www.cise.ufl.edu/research/sparse and as MA38 (functionally equivalent to Version 2.2.1) in the Harwell Subroutine Library. {\bf NOTE: you must use the correct version of AMD with UMFPACK; using an old version of AMD with a newer version of UMFPACK can fail.} %------------------------------------------------------------------------------- \section{Primary changes from prior versions} %------------------------------------------------------------------------------- A detailed list of changes is in the {\tt ChangeLog} file. %------------------------------------------------------------------------------- \subsection{Version 5.4.0} %------------------------------------------------------------------------------- Disabled the 2-by-2 ordering strategy. Bug fix for \verb'umfpack_make.m' for Windows. %------------------------------------------------------------------------------- \subsection{Version 5.3.0} %------------------------------------------------------------------------------- A bug fix for structurally singular matrices, and a compiler workaround for gcc versions 4.2.(3 and 4). %------------------------------------------------------------------------------- \subsection{Version 5.2.0} %------------------------------------------------------------------------------- Change of license from GNU Lesser GPL to the GNU GPL. %------------------------------------------------------------------------------- \subsection{Version 5.1.0} %------------------------------------------------------------------------------- Port of MATLAB interface to 64-bit MATLAB. %------------------------------------------------------------------------------- \subsection{Version 5.0.3} %------------------------------------------------------------------------------- Renamed the MATLAB function to {\tt umfpack2}, so as not to confict with itself (the MATLAB built-in version of UMFPACK). %------------------------------------------------------------------------------- \subsection{Version 5.0} %------------------------------------------------------------------------------- Changed {\tt long} to {\tt UF\_long}, controlled by the {\tt UFconfig.h} file. A {\tt UF\_long} is normally just {\tt long}, except on the Windows 64 (WIN64) platform. In that case, it becomes {\tt \_\_int64}. %------------------------------------------------------------------------------- \subsection{Version 4.6} %------------------------------------------------------------------------------- Added additional options to {\tt umf\_solve.c}. %------------------------------------------------------------------------------- \subsection{Version 4.5} %------------------------------------------------------------------------------- Added function pointers for malloc, calloc, realloc, free, printf, hypot, and complex divisiion, so that these functions can be redefined at run-time. Added a version number so you can determine the version of UMFPACK at run time or compile time. UMFPACK requires AMD v2.0 or later. %------------------------------------------------------------------------------- \subsection{Version 4.4} %------------------------------------------------------------------------------- Bug fix in strategy selection in {\tt umfpack\_*\_qsymbolic}. Added packed complex case for all complex input/output arguments. Added {\tt umfpack\_get\_determinant}. Added minimal support for Microsoft Visual Studio (the {\tt umf\_multicompile.c} file). %------------------------------------------------------------------------------- \subsection{Version 4.3.1} %------------------------------------------------------------------------------- Minor bug fix in the forward/backsolve. This bug had the effect of turning off iterative refinement when solving $\m{A}\tr\m{x}=\m{b}$ after factorizing $\m{A}$. UMFPACK mexFunction now factorizes $\m{A}\tr$ in its forward-slash operation. %------------------------------------------------------------------------------- \subsection{Version 4.3} %------------------------------------------------------------------------------- No changes are visible to the C or MATLAB user, except the presence of one new control parameter in the {\tt Control} array, and three new statistics in the {\tt Info} array. The primary change is the addition of an (optional) drop tolerance. %------------------------------------------------------------------------------- \subsection{Version 4.1} %------------------------------------------------------------------------------- The following is a summary of the main changes that are visible to the C or MATLAB user: \begin{enumerate} \item New ordering strategies added. No changes are required in user code (either C or MATLAB) to use the new default strategy, which is an automatic selection of the unsymmetric, symmetric, or 2-by-2 strategies. \item Row scaling added. This is only visible to the MATLAB caller when using the form {\tt [L,U,P,Q,R] = umfpack (A)}, to retrieve the LU factors. Likewise, it is only visible to the C caller when the LU factors are retrieved, or when solving systems with just $\m{L}$ or $\m{U}$. New C-callable and MATLAB-callable routines are included to get and to apply the scale factors computed by UMFPACK. Row scaling is enabled by default, but can be disabled. Row scaling usually leads to a better factorization, particularly when the symmetric strategy is used. \item Error code {\tt UMFPACK\_ERROR\_problem\_to\_large} removed. Version 4.0 would generate this error when the upper bound memory usage exceeded 2GB (for the {\tt int} version), even when the actual memory usage was less than this. The new version properly handles this case, and can successfully factorize the matrix if sufficient memory is available. \item New control parameters and statistics provided. \item The AMD symmetric approximate minimum degree ordering routine added \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}. It is used by UMFPACK, and can also be called independently from C or MATLAB. \item The {\tt umfpack} mexFunction now returns permutation matrices, not permutation vectors, when using the form {\tt [L,U,P,Q] = umfpack (A)} or the new form {\tt [L,U,P,Q,R] = umfpack (A)}. \item New arguments added to the user-callable routines {\tt umfpack\_*\_symbolic}, {\tt umfpack\_*\_qsymbolic}, {\tt umfpack\_*\_get\_numeric}, and {\tt umfpack\_*\_get\_symbolic}. The symbolic analysis now makes use of the numerical values of the matrix $\m{A}$, to guide the 2-by-2 strategy. The subsequent matrix passed to the numeric factorization step does not have to have the same numerical values. All of the new arguments are optional. If you do not wish to include them, simply pass {\tt NULL} pointers instead. The 2-by-2 strategy will assume all entries are numerically large, for example. \item New routines added to save and load the {\tt Numeric} and {\tt Symbolic} objects to and from a binary file. \item A Fortran interface added. It provides access to a subset of UMFPACK's features. \item You can compute an incomplete LU factorization, by dropping small entries from $\m{L}$ and $\m{U}$. By default, no nonzero entry is dropped, no matter how small in absolute value. This feature is new to Version 4.3. \end{enumerate} %------------------------------------------------------------------------------- \section{Using UMFPACK in MATLAB} %------------------------------------------------------------------------------- The easiest way to use UMFPACK is within MATLAB. Version 4.3 is a built-in routine in MATLAB 7.0.4, and is used in {\tt x = A}$\backslash${\tt b} when {\tt A} is sparse, square, unsymmetric (or symmetric but not positive definite), and with nonzero entries that are not confined in a narrow band. It is also used for the {\tt [L,U,P,Q] = lu (A)} usage of {\tt lu}. Type {\tt help lu} in MATLAB 6.5 or later for more details. To use the UMFPACK mexFunction, you must download and compile it, since the mexFunction itself is not part of MATLAB. The following discussion assumes that you have MATLAB Version 6.0 or later (which includes the BLAS, and the {\tt colamd} ordering routine). To compile both the UMFPACK and AMD mexFunctions, just type {\tt make} in the Unix system shell, while in the {\tt UMFPACK} directory. You can also type {\tt umfpack\_make} in MATLAB, if you are in the {\tt UMFPACK/MATLAB} directory, or if that directory is in your MATLAB path. This works on any system with MATLAB, including Windows. See Section~\ref{Install} for more details on how to install UMFPACK. Once installed, the UMFPACK mexFunction can analyze, factor, and solve linear systems. Table~\ref{matlab} summarizes some of the more common uses of the UMFPACK mexFunction within MATLAB. An optional input argument can be used to modify the control parameters for UMFPACK, and an optional output argument provides statistics on the factorization. Refer to the AMD User Guide for more details about the AMD mexFunction. \begin{table} \caption{Using UMFPACK's MATLAB interface} \label{matlab} \vspace{0.1in} {\footnotesize \begin{tabular}{l|l|l} \hline Function & Using UMFPACK & MATLAB 6.0 equivalent \\ \hline & & \\ \begin{minipage}[t]{1.5in} Solve $\m{Ax}=\m{b}$. \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} x = umfpack (A,'\',b) ; \end{verbatim} \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} x = A \ b ; \end{verbatim} \end{minipage} \\ & & \\ \hline & & \\ \begin{minipage}[t]{1.5in} Solve $\m{Ax}=\m{b}$ using a different row and column pre-ordering (symmetric ordering). \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} S = spones (A) ; Q = symamd (S+S') ; Control = umfpack ; Control (6) = 3 ; x = umfpack (A,Q,'\',b,Control) ; \end{verbatim} \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} spparms ('autommd',0) ; S = spones (A) ; Q = symamd (S+S') ; x = A (Q,Q) \ b (Q) ; x (Q) = x ; spparms ('autommd',1) ; \end{verbatim} \end{minipage} \\ & & \\ \hline & & \\ \begin{minipage}[t]{1.5in} Solve $\m{A}\tr\m{x}\tr = \m{b}\tr$. \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} x = umfpack (b,'/',A) ; \end{verbatim} Note: $\m{A}$ is factorized. \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} x = b / A ; \end{verbatim} Note: $\m{A}\tr$ is factorized. \end{minipage} \\ & & \\ \hline & & \\ \begin{minipage}[t]{1.5in} Scale and factorize $\m{A}$, then solve $\m{Ax}=\m{b}$. \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} [L,U,P,Q,R] = umfpack (A) ; c = P * (R \ b) ; x = Q * (U \ (L \ c)) ; \end{verbatim} \end{minipage} & \begin{minipage}[t]{2.2in} \begin{verbatim} [m n] = size (A) ; r = full (sum (abs (A), 2)) ; r (find (r == 0)) = 1 ; R = spdiags (r, 0, m, m) ; I = speye (n) ; Q = I (:, colamd (A)) ; [L,U,P] = lu ((R\A)*Q) ; c = P * (R \ b) ; x = Q * (U \ (L \ c)) ; \end{verbatim} \end{minipage} \\ & & \\ \hline \end{tabular} } \end{table} Note: in MATLAB 6.5 or later, use {\tt spparms ('autoamd',0)} in addition to {\tt spparms ('autommd',0)}, in Table~\ref{matlab}, to turn off MATLAB's default reordering. UMFPACK requires {\tt b} to be a dense vector (real or complex) of the appropriate dimension. This is more restrictive than what you can do with MATLAB's backslash or forward slash. See {\tt umfpack\_solve} for an M-file that removes this restriction. This restriction does not apply to the built-in backslash operator in MATLAB 6.5 or later, which uses UMFPACK to factorize the matrix. You can do this yourself in MATLAB: {\footnotesize \begin{verbatim} [L,U,P,Q,R] = umfpack (A) ; x = Q * (U \ (L \ (P * (R \ b)))) ; \end{verbatim} } or, with no row scaling: {\footnotesize \begin{verbatim} [L,U,P,Q] = umfpack (A) ; x = Q * (U \ (L \ (P * b))) ; \end{verbatim} } The above examples do not make use of the iterative refinement that is built into {\tt x = }{\tt umfpack (A,'}$\backslash${\tt ',b)} however. MATLAB's {\tt [L,U,P] = lu(A)} returns a lower triangular {\tt L}, an upper triangular {\tt U}, and a permutation matrix {\tt P} such that {\tt P*A} is equal to {\tt L*U}. UMFPACK behaves differently. By default, it scales the rows of {\tt A} and reorders the columns of {\tt A} prior to factorization, so that {\tt L*U} is equal to {\tt P*(R}$\backslash${\tt A)*Q}, where {\tt R} is a diagonal sparse matrix of scale factors for the rows of {\tt A}. The scale factors {\tt R} are applied to {\tt A} via the MATLAB expression {\tt R}$\backslash${\tt A} to avoid multiplying by the reciprocal, which can be numerically inaccurate. There are more options; you can provide your own column pre-ordering (in which case UMFPACK does not call COLAMD or AMD), you can modify other control settings (similar to the {\tt spparms} in MATLAB), and you can get various statistics on the analysis, factorization, and solution of the linear system. Type {\tt umfpack\_details} and {\tt umfpack\_report} in MATLAB for more information. Two demo M-files are provided. Just type {\tt umfpack\_simple} and {\tt umfpack\_demo} to run them. The output of these two programs should be about the same as the files {\tt umfpack\_simple.m.out} and {\tt umfpack\_demo.m.out} that are provided. Factorizing {\tt A'} (or {\tt A.'}) and using the transposed factors can sometimes be faster than factorizing {\tt A}. It can also be preferable to factorize {\tt A'} if {\tt A} is rectangular. UMFPACK pre-orders the columns to maintain sparsity; the row ordering is not determined until the matrix is factorized. Thus, if {\tt A} is {\tt m} by {\tt n} with structural rank {\tt m} and {\tt m} $<$ {\tt n}, then {\tt umfpack} might not find a factor {\tt U} with a structurally zero-free diagonal. Unless the matrix ill-conditioned or poorly scaled, factorizing {\tt A'} in this case will guarantee that both factors will have zero-free diagonals (in the structural sense; they may be numerically zero). Note that there is no guarantee as to the size of the diagonal entries of {\tt U}; UMFPACK does not do a rank-revealing factorization. Here's how you can factorize {\tt A'} and get the factors of {\tt A} instead: \begin{verbatim} [l,u,p,q] = umfpack (A') ; L = u' ; U = l' ; P = q ; Q = p ; clear l u p q \end{verbatim} This is an alternative to {\tt [L,U,P,Q]=umfpack(A)}. A simple M-file ({\tt umfpack\_btf}) is provided that first permutes the matrix to upper block triangular form, using MATLAB's {\tt dmperm} routine, and then solves each block. The LU factors are not returned. Its usage is simple: {\tt x = umfpack\_btf(A,b)}. Type {\tt help umfpack\_btf} for more options. An estimate of the 1-norm of {\tt L*U-P*A*Q} can be computed in MATLAB as {\tt lu\_normest(P*A*Q,L,U)}, using the {\tt lu\_normest.m} M-file by Hager and Davis \cite{DavisHager99} that is included with the UMFPACK distribution. With row scaling enabled, use {\tt lu\_normest(P*(R}$\backslash${\tt A)*Q,L,U)} instead. One issue you may encounter is how UMFPACK allocates its memory when being used in a mexFunction. One part of its working space is of variable size. The symbolic analysis phase determines an upper bound on the size of this memory, but not all of this memory will typically be used in the numerical factorization. UMFPACK tries to allocate a decent amount of working space. This is 70\% of the upper bound, by default, for the unsymmetric strategy. For the symmetric strategy, the fraction of the upper bound is computed automatically (assuming a best-case scenario with no numerical pivoting required during numeric factorization). If this initial allocation fails, it reduces its request and uses less memory. If the space is not large enough during factorization, it is increased via {\tt mxRealloc}. However, {\tt mxMalloc} and {\tt mxRealloc} abort the {\tt umfpack} mexFunction if they fail, so this strategy does not work in MATLAB. To compute the determinant with UMFPACK: \begin{verbatim} d = umfpack (A, 'det') ; [d e] = umfpack (A, 'det') ; \end{verbatim} The first case is identical to MATLAB's {\tt det}. The second case returns the determinant in the form $d \times 10^e$, which avoids overflow if $e$ is large. %------------------------------------------------------------------------------- \section{Using UMFPACK in a C program} \label{C} %------------------------------------------------------------------------------- The C-callable UMFPACK library consists of 32 user-callable routines and one include file. All but three of the routines come in four versions, with different sizes of integers and for real or complex floating-point numbers: \begin{enumerate} \item {\tt umfpack\_di\_*}: real double precision, {\tt int} integers. \item {\tt umfpack\_dl\_*}: real double precision, {\tt UF\_long} integers. \item {\tt umfpack\_zi\_*}: complex double precision, {\tt int} integers. \item {\tt umfpack\_zl\_*}: complex double precision, {\tt UF\_long} integers. \end{enumerate} where {\tt *} denotes the specific name of one of the routines. Routine names beginning with {\tt umf\_} are internal to the package, and should not be called by the user. The include file {\tt umfpack.h} must be included in any C program that uses UMFPACK. The other three routines are the same for all four versions. In addition, the C-callable AMD library distributed with UMFPACK includes 4 user-callable routines (in two versions with {\tt int} and {\tt UF\_long} integers) and one include file. Refer to the AMD documentation for more details. Use only one version for any one problem; do not attempt to use one version to analyze the matrix and another version to factorize the matrix, for example. The notation {\tt umfpack\_di\_*} refers to all user-callable routines for the real double precision and {\tt int} integer case. The notation {\tt umfpack\_*\_numeric}, for example, refers all four versions (real/complex, int/UF\_long) of a single operation (in this case numeric factorization). %------------------------------------------------------------------------------- \subsection{The size of an integer} %------------------------------------------------------------------------------- The {\tt umfpack\_di\_*} and {\tt umfpack\_zi\_*} routines use {\tt int} integer arguments; those starting with {\tt umfpack\_dl\_} or {\tt umfpack\_zl\_} use {\tt UF\_long} integer arguments. If you compile UMFPACK in the standard ILP32 mode (32-bit {\tt int}'s, {\tt long}'s, and pointers) then the versions are essentially identical. You will be able to solve problems using up to 2GB of memory. If you compile UMFPACK in the standard LP64 mode, the size of an {\tt int} remains 32-bits, but the size of a {\tt long} and a pointer both get promoted to 64-bits. In the LP64 mode, the {\tt umfpack\_dl\_*} and {\tt umfpack\_zl\_*} routines can solve huge problems (not limited to 2GB), limited of course by the amount of available memory. The only drawback to the 64-bit mode is that not all BLAS libraries support 64-bit integers. This limits the performance you will obtain. Those that do support 64-bit integers are specific to particular architectures, and are not portable. UMFPACK and AMD should be compiled in the same mode. If you compile UMFPACK and AMD in the LP64 mode, be sure to add {\tt -DLP64} to the compilation command. See the examples in the {\tt UFconfig/UFconfig.mk} file. %------------------------------------------------------------------------------- \subsection{Real and complex floating-point} %------------------------------------------------------------------------------- The {\tt umfpack\_di\_*} and {\tt umfpack\_dl\_*} routines take (real) double precision arguments, and return double precision arguments. In the {\tt umfpack\_zi\_*} and {\tt umfpack\_zl\_*} routines, these same arguments hold the real part of the matrices; and second double precision arrays hold the imaginary part of the input and output matrices. Internally, complex numbers are stored in arrays with their real and imaginary parts interleaved, as required by the BLAS (``packed'' complex form). New to Version 4.4 is the option of providing input/output arguments in packed complex form. %------------------------------------------------------------------------------- \subsection{Primary routines, and a simple example} %------------------------------------------------------------------------------- Five primary UMFPACK routines are required to factorize $\m{A}$ or solve $\m{Ax}=\m{b}$. They are fully described in Section~\ref{Primary}: \begin{itemize} \item {\tt umfpack\_*\_symbolic}: Pre-orders the columns of $\m{A}$ to reduce fill-in. Returns an opaque {\tt Symbolic} object as a {\tt void *} pointer. The object contains the symbolic analysis and is needed for the numeric factorization. This routine requires only $O(|\m{A}|)$ space, where $|\m{A}|$ is the number of nonzero entries in the matrix. It computes upper bounds on the nonzeros in $\m{L}$ and $\m{U}$, the floating-point operations required, and the memory usage of {\tt umfpack\_*\_numeric}. The {\tt Symbolic} object is small; it contains just the column pre-ordering, the supernodal column elimination tree, and information about each frontal matrix. It is no larger than about $13n$ integers if $\m{A}$ is $n$-by-$n$. \item {\tt umfpack\_*\_numeric}: Numerically scales and then factorizes a sparse matrix into $\m{PAQ}$, $\m{PRAQ}$, or $\m{PR}^{-1}\m{AQ}$ into the product $\m{LU}$, where $\m{P}$ and $\m{Q}$ are permutation matrices, $\m{R}$ is a diagonal matrix of scale factors, $\m{L}$ is lower triangular with unit diagonal, and $\m{U}$ is upper triangular. Requires the symbolic ordering and analysis computed by {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic}. Returns an opaque {\tt Numeric} object as a {\tt void *} pointer. The object contains the numerical factorization and is used by {\tt umfpack\_*\_solve}. You can factorize a new matrix with a different values (but identical pattern) as the matrix analyzed by {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic} by re-using the {\tt Symbolic} object (this feature is available when using UMFPACK in a C or Fortran program, but not in MATLAB). The matrix $\m{U}$ will have zeros on the diagonal if $\m{A}$ is singular; this produces a warning, but the factorization is still valid. \item {\tt umfpack\_*\_solve}: Solves a sparse linear system ($\m{Ax}=\m{b}$, $\m{A}\tr\m{x}=\m{b}$, or systems involving just $\m{L}$ or $\m{U}$), using the numeric factorization computed by {\tt umfpack\_*\_numeric}. Iterative refinement with sparse backward error \cite{ardd:89} is used by default. The matrix $\m{A}$ must be square. If it is singular, then a divide-by-zero will occur, and your solution with contain IEEE Inf's or NaN's in the appropriate places. \item {\tt umfpack\_*\_free\_symbolic}: Frees the {\tt Symbolic} object created by {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic}. \item {\tt umfpack\_*\_free\_numeric}: Frees the {\tt Numeric} object created by {\tt umfpack\_*\_numeric}. \end{itemize} Be careful not to free a {\tt Symbolic} object with {\tt umfpack\_*\_free\_numeric}. Nor should you attempt to free a {\tt Numeric} object with {\tt umfpack\_*\_free\_symbolic}. Failure to free these objects will lead to memory leaks. The matrix $\m{A}$ is represented in compressed column form, which is identical to the sparse matrix representation used by MATLAB. It consists of three or four arrays, where the matrix is {\tt m}-by-{\tt n}, with {\tt nz} entries. For the {\tt int} version of UMFPACK: {\footnotesize \begin{verbatim} int Ap [n+1] ; int Ai [nz] ; double Ax [nz] ; \end{verbatim} } For the {\tt UF\_long} version of UMFPACK: {\footnotesize \begin{verbatim} UF_long Ap [n+1] ; UF_long Ai [nz] ; double Ax [nz] ; \end{verbatim} } The complex versions add another array for the imaginary part: {\footnotesize \begin{verbatim} double Az [nz] ; \end{verbatim} } Alternatively, if {\tt Az} is {\tt NULL}, the real part of the $k$th entry is located in {\tt Ax[2*k]} and the imaginary part is located in {\tt Ax[2*k+1]}, and the {\tt Ax} array is of size {\tt 2*nz}. All nonzeros are entries, but an entry may be numerically zero. The row indices of entries in column {\tt j} are stored in {\tt Ai[Ap[j]} \ldots {\tt Ap[j+1]-1]}. The corresponding numerical values are stored in {\tt Ax[Ap[j]} \ldots {\tt Ap[j+1]-1]}. The imaginary part, for the complex versions, is stored in {\tt Az[Ap[j]} \ldots {\tt Ap[j+1]-1]} (see above for the packed complex case). No duplicate row indices may be present, and the row indices in any given column must be sorted in ascending order. The first entry {\tt Ap[0]} must be zero. The total number of entries in the matrix is thus {\tt nz = Ap[n]}. Except for the fact that extra zero entries can be included, there is thus a unique compressed column representation of any given matrix $\m{A}$. For a more flexible method for providing an input matrix to UMFPACK, see Section~\ref{triplet}. Here is a simple main program, {\tt umfpack\_simple.c}, that illustrates the basic usage of UMFPACK. See Section~\ref{Synopsis} for a short description of each calling sequence, including a list of options for the first argument of {\tt umfpack\_di\_solve}. {\footnotesize \begin{verbatim} INCLUDE umfpack_simple.c via sed \end{verbatim} } The {\tt Ap}, {\tt Ai}, and {\tt Ax} arrays represent the matrix \[ \m{A} = \left[ \begin{array}{rrrrr} 2 & 3 & 0 & 0 & 0 \\ 3 & 0 & 4 & 0 & 6 \\ 0 & -1 & -3 & 2 & 0 \\ 0 & 0 & 1 & 0 & 0 \\ 0 & 4 & 2 & 0 & 1 \\ \end{array} \right]. \] and the solution to $\m{Ax}=\m{b}$ is $\m{x} = [1 \, 2 \, 3 \, 4 \, 5]\tr$. The program uses default control settings and does not return any statistics about the ordering, factorization, or solution ({\tt Control} and {\tt Info} are both {\tt (double *) NULL}). It also ignores the status value returned by most user-callable UMFPACK routines. %------------------------------------------------------------------------------- \subsection{A note about zero-sized arrays} %------------------------------------------------------------------------------- UMFPACK uses many user-provided arrays of size {\tt m} or {\tt n} (the order of the matrix), and of size {\tt nz} (the number of nonzeros in a matrix). UMFPACK does not handle zero-dimensioned arrays; it returns an error code if {\tt m} or {\tt n} are zero. However, {\tt nz} can be zero, since all singular matrices are handled correctly. If you attempt to {\tt malloc} an array of size {\tt nz} = 0, however, {\tt malloc} will return a null pointer which UMFPACK will report as a missing argument. If you {\tt malloc} an array of size {\tt nz} to pass to UMFPACK, make sure that you handle the {\tt nz} = 0 case correctly (use a size equal to the maximum of {\tt nz} and 1, or use a size of {\tt nz+1}). %------------------------------------------------------------------------------- \subsection{Alternative routines} %------------------------------------------------------------------------------- Three alternative routines are provided that modify UMFPACK's default behavior. They are fully described in Section~\ref{Alternative}: \begin{itemize} \item {\tt umfpack\_*\_defaults}: Sets the default control parameters in the {\tt Control} array. These can then be modified as desired before passing the array to the other UMFPACK routines. Control parameters are summarized in Section~\ref{control_param}. Three particular parameters deserve special notice. UMFPACK uses relaxed partial pivoting, where a candidate pivot entry is numerically acceptable if its magnitude is greater than or equal to a tolerance parameter times the magnitude of the largest entry in the same column. The parameter {\tt Control [UMFPACK\_PIVOT\_TOLERANCE]} has a default value of 0.1, and is used for the unsymmetric strategy. For complex matrices, a cheap approximation of the absolute value is used for the threshold pivoting test ($|a| \approx |a_{\mbox{real}}|+|a_{\mbox{imag}}|$). For the symmetric strategy, a second tolerance is used for diagonal entries: \newline {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]}, with a default value of 0.001. The first parameter (with a default of 0.1) is used for any off-diagonal candidate pivot entries. These two parameters may be too small for some matrices, particularly for ill-conditioned or poorly scaled ones. With the default pivot tolerances and default iterative refinement, {\tt x = umfpack (A,'}$\backslash${\tt ',b)} is just as accurate as (or more accurate) than {\tt x = A}$\backslash${\tt b} in MATLAB 6.1 for nearly all matrices. If {\tt Control [UMFPACK\_PIVOT\_TOLERANCE]} is zero, than any nonzero entry is acceptable as a pivot (this is changed from Version 4.0, which treated a value of 0.0 the same as 1.0). If the symmetric strategy is used, and {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]} is zero, then any nonzero entry on the diagonal is accepted as a pivot. Off-diagonal pivoting will still occur if the diagonal entry is exactly zero. The {\tt Control [UMFPACK\_SYM\_PIVOT\_TOLERANCE]} parameter is new to Version 4.1. It is similar in function to the pivot tolerance for left-looking methods (the MATLAB {\tt THRESH} option in {\tt [L,U,P] = lu (A, THRESH)}, and the pivot tolerance parameter in SuperLU). The parameter {\tt Control [UMFPACK\_STRATEGY]} can be used to bypass UMFPACK's automatic strategy selection. The automatic strategy nearly always selects the best method. When it does not, the different methods nearly always give about the same quality of results. There may be cases where the automatic strategy fails to pick a good strategy. Also, you can save some computing time if you know the right strategy for your set of matrix problems. \item {\tt umfpack\_*\_qsymbolic}: An alternative to {\tt umfpack\_*\_symbolic}. Allows the user to specify his or her own column pre-ordering, rather than using the default COLAMD or AMD pre-orderings. For example, a graph partitioning-based order of $\m{A}\tr\m{A}$ would be suitable for UMFPACK's unsymmetric strategy. A partitioning of $\m{A}+\m{A}\tr$ would be suitable for UMFPACK's symmetric strategy. \item {\tt umfpack\_*\_wsolve}: An alternative to {\tt umfpack\_*\_solve} which does not dynamically allocate any memory. Requires the user to pass two additional work arrays. \end{itemize} %------------------------------------------------------------------------------- \subsection{Matrix manipulation routines} \label{triplet} %------------------------------------------------------------------------------- The compressed column data structure is compact, and simplifies the UMFPACK routines that operate on the sparse matrix $\m{A}$. However, it can be inconvenient for the user to generate. Section~\ref{Manipulate} presents the details of routines for manipulating sparse matrices in {\em triplet} form, compressed column form, and compressed row form (the transpose of the compressed column form). The triplet form of a matrix consists of three or four arrays. For the {\tt int} version of UMFPACK: {\footnotesize \begin{verbatim} int Ti [nz] ; int Tj [nz] ; double Tx [nz] ; \end{verbatim} } For the {\tt UF\_long} version: {\footnotesize \begin{verbatim} UF_long Ti [nz] ; UF_long Tj [nz] ; double Tx [nz] ; \end{verbatim} } The complex versions use another array to hold the imaginary part: {\footnotesize \begin{verbatim} double Tz [nz] ; \end{verbatim} } The {\tt k}-th triplet is $(i,j,a_{ij})$, where $i =$ {\tt Ti[k]}, $j =$ {\tt Tj[k]}, and $a_{ij} =$ {\tt Tx[k]}. For the complex versions, {\tt Tx[k]} is the real part of $a_{ij}$ and {\tt Tz[k]} is the imaginary part. The triplets can be in any order in the {\tt Ti}, {\tt Tj}, and {\tt Tx} arrays (and {\tt Tz} for the complex versions), and duplicate entries may exist. If {\tt Tz} is NULL, then the array {\tt Tx} becomes of size {\tt 2*nz}, and the real and imaginary parts of the {\tt k}-th triplet are located in {\tt Tx[2*k]} and {\tt Tx[2*k+1]}, respectively. Any duplicate entries are summed when the triplet form is converted to compressed column form. This is a convenient way to create a matrix arising in finite-element methods, for example. Four routines are provided for manipulating sparse matrices: \begin{itemize} \item {\tt umfpack\_*\_triplet\_to\_col}: Converts a triplet form of a matrix to compressed column form (ready for input to \newline {\tt umfpack\_*\_symbolic}, {\tt umfpack\_*\_qsymbolic}, and {\tt umfpack\_*\_numeric}). Identical to {\tt A = spconvert(i,j,x)} in MATLAB, except that zero entries are not removed, so that the pattern of entries in the compressed column form of $\m{A}$ are fully under user control. This is important if you want to factorize a new matrix with the {\tt Symbolic} object from a prior matrix with the same pattern as the new one. \item {\tt umfpack\_*\_col\_to\_triplet}: The opposite of {\tt umfpack\_*\_triplet\_to\_col}. Identical to {\tt [i,j,x] = find(A)} in MATLAB, except that numerically zero entries may be included. \item {\tt umfpack\_*\_transpose}: Transposes and optionally permutes a column form matrix \cite{Gustavson78}. Identical to {\tt R = A(P,Q)'} (linear algebraic transpose, using the complex conjugate) or {\tt R = A(P,Q).'} (the array transpose) in MATLAB, except for the presence of numerically zero entries. Factorizing $\m{A}\tr$ and then solving $\m{Ax}=\m{b}$ with the transposed factors can sometimes be much faster or much slower than factorizing $\m{A}$. It is highly dependent on your particular matrix. \item {\tt umfpack\_*\_scale}: Applies the row scale factors to a user-provided vector. This is not required to solve the sparse linear system $\m{Ax}=\m{b}$ or $\m{A}\tr\m{x}=\m{b}$, since {\tt umfpack\_*\_solve} applies the scale factors for those systems. \end{itemize} It is quite easy to add matrices in triplet form, subtract them, transpose them, permute them, construct a submatrix, and multiply a triplet-form matrix times a vector. UMFPACK does not provide code for these basic operations, however. Refer to the discussion of {\tt umfpack\_*\_triplet\_to\_col} in Section~\ref{Manipulate} for more details on how to compute these operations in your own code. The only primary matrix operation not provided by UMFPACK is the multiplication of two sparse matrices \cite{Gustavson78}. The CHOLMOD provides many of these matrix operations, which can then be used in conjunction with UMFPACK. See my web page for details. %------------------------------------------------------------------------------- \subsection{Getting the contents of opaque objects} %------------------------------------------------------------------------------- There are cases where you may wish to do more with the LU factorization of a matrix than solve a linear system. The opaque {\tt Symbolic} and {\tt Numeric} objects are just that - opaque. You cannot do anything with them except to pass them back to subsequent calls to UMFPACK. Three routines are provided for copying their contents into user-provided arrays using simpler data structures. Four routines are provided for saving and loading the {\tt Numeric} and {\tt Symbolic} objects to/from binary files. An additional routine is provided that computes the determinant. They are fully described in Section~\ref{Get}: \begin{itemize} \item {\tt umfpack\_*\_get\_lunz}: Returns the number of nonzeros in $\m{L}$ and $\m{U}$. \item {\tt umfpack\_*\_get\_numeric}: Copies $\m{L}$, $\m{U}$, $\m{P}$, $\m{Q}$, and $\m{R}$ from the {\tt Numeric} object into arrays provided by the user. The matrix $\m{L}$ is returned in compressed row form (with the column indices in each row sorted in ascending order). The matrix $\m{U}$ is returned in compressed column form (with sorted columns). There are no explicit zero entries in $\m{L}$ and $\m{U}$, but such entries may exist in the {\tt Numeric} object. The permutations $\m{P}$ and $\m{Q}$ are represented as permutation vectors, where {\tt P[k] = i} means that row {\tt i} of the original matrix is the the {\tt k}-th row of $\m{PAQ}$, and where {\tt Q[k] = j} means that column {\tt j} of the original matrix is the {\tt k}-th column of $\m{PAQ}$. This is identical to how MATLAB uses permutation vectors (type {\tt help colamd} in MATLAB 6.1 or later). \item {\tt umfpack\_*\_get\_symbolic}: Copies the contents of the {\tt Symbolic} object (the initial row and column preordering, supernodal column elimination tree, and information about each frontal matrix) into arrays provided by the user. \item {\tt umfpack\_*\_get\_determinant}: Computes the determinant from the diagonal of $\m{U}$ and the permutations $\m{P}$ and $\m{Q}$. This is mostly of theoretical interest. It is not a good test to determine if your matrix is singular or not. \item {\tt umfpack\_*\_save\_numeric}: Saves a copy of the {\tt Numeric} object to a file, in binary format. \item {\tt umfpack\_*\_load\_numeric}: Creates a {\tt Numeric} object by loading it from a file created by {\tt umfpack\_*\_save\_numeric}. \item {\tt umfpack\_*\_save\_symbolic}: Saves a copy of the {\tt Symbolic} object to a file, in binary format. \item {\tt umfpack\_*\_load\_symbolic}: Creates a {\tt Symbolic} object by loading it from a file created by {\tt umfpack\_*\_save\_symbolic}. \end{itemize} UMFPACK itself does not make use of these routines; they are provided solely for returning the contents of the opaque {\tt Symbolic} and {\tt Numeric} objects to the user, and saving/loading them to/from a binary file. None of them do any computation, except for {\tt umfpack\_*\_get\_determinant}. %------------------------------------------------------------------------------- \subsection{Reporting routines} \label{Reporting} %------------------------------------------------------------------------------- None of the UMFPACK routines discussed so far prints anything, even when an error occurs. UMFPACK provides you with nine routines for printing the input and output arguments (including the {\tt Control} settings and {\tt Info} statistics) of UMFPACK routines discussed above. They are fully described in Section~\ref{Report}: \begin{itemize} \item {\tt umfpack\_*\_report\_status}: Prints the status (return value) of other {\tt umfpack\_*} routines. \item {\tt umfpack\_*\_report\_info}: Prints the statistics returned in the {\tt Info} array by {\tt umfpack\_*\_*symbolic}, {\tt umfpack\_*\_numeric}, and {\tt umfpack\_*\_*solve}. \item {\tt umfpack\_*\_report\_control}: Prints the {\tt Control} settings. \item {\tt umfpack\_*\_report\_matrix}: Verifies and prints a compressed column-form or compressed row-form sparse matrix. \item {\tt umfpack\_*\_report\_triplet}: Verifies and prints a matrix in triplet form. \item {\tt umfpack\_*\_report\_symbolic}: Verifies and prints a {\tt Symbolic} object. \item {\tt umfpack\_*\_report\_numeric}: Verifies and prints a {\tt Numeric} object. \item {\tt umfpack\_*\_report\_perm}: Verifies and prints a permutation vector. \item {\tt umfpack\_*\_report\_vector}: Verifies and prints a real or complex vector. \end{itemize} The {\tt umfpack\_*\_report\_*} routines behave slightly differently when compiled into the C-callable UMFPACK library than when used in the MATLAB mexFunction. MATLAB stores its sparse matrices using the same compressed column data structure discussed above, where row and column indices of an $m$-by-$n$ matrix are in the range 0 to $m-1$ or $n-1$, respectively\footnote{Complex matrices in MATLAB use the split array form, with one {\tt double} array for the real part and another array for the imaginary part. UMFPACK supports that format, as well as the packed complex format (new to Version 4.4).} It prints them as if they are in the range 1 to $m$ or $n$. The UMFPACK mexFunction behaves the same way. You can control how much the {\tt umfpack\_*\_report\_*} routines print by modifying the {\tt Control [UMFPACK\_PRL]} parameter. Its default value is 1. Here is a summary of how the routines use this print level parameter: \begin{itemize} \item {\tt umfpack\_*\_report\_status}: No output if the print level is 0 or less, even when an error occurs. If 1, then error messages are printed, and nothing is printed if the status is {\tt UMFPACK\_OK}. A warning message is printed if the matrix is singular. If 2 or more, then the status is always printed. If 4 or more, then the UMFPACK Copyright is printed. If 6 or more, then the UMFPACK License is printed. See also the first page of this User Guide for the Copyright and License. \item {\tt umfpack\_*\_report\_control}: No output if the print level is 1 or less. If 2 or more, all of {\tt Control} is printed. \item {\tt umfpack\_*\_report\_info}: No output if the print level is 1 or less. If 2 or more, all of {\tt Info} is printed. \item all other {\tt umfpack\_*\_report\_*} routines: If the print level is 2 or less, then these routines return silently without checking their inputs. If 3 or more, the inputs are fully verified and a short status summary is printed. If 4, then the first few entries of the input arguments are printed. If 5, then all of the input arguments are printed. \end{itemize} This print level parameter has an additional effect on the MATLAB mexFunction. If zero, then no warnings of singular or nearly singular matrices are printed (similar to the MATLAB commands {\tt warning off MATLAB:singularMatrix} and {\tt warning off MATLAB:nearlySingularMatrix}). %------------------------------------------------------------------------------- \subsection{Utility routines} %------------------------------------------------------------------------------- UMFPACK v4.0 included a routine that returns the time used by the process, {\tt umfpack\_timer}. The routine uses either {\tt getrusage} (which is preferred), or the ANSI C {\tt clock} routine if that is not available. It is fully described in Section~\ref{Utility}. It is still available in UMFPACK v4.1 and following, but not used internally. Two new timing routines are provided in UMFPACK Version 4.1 and following, {\tt umfpack\_tic} and {\tt umfpack\_toc}. They use POSIX-compliant {\tt sysconf} and {\tt times} routines to find both the CPU time and wallclock time. These three routines are the only user-callable routine that is identical in all four {\tt int}/{\tt UF\_long}, real/complex versions (there is no {\tt umfpack\_di\_timer} routine, for example). %------------------------------------------------------------------------------- \subsection{Control parameters} \label{control_param} %------------------------------------------------------------------------------- UMFPACK uses an optional {\tt double} array (currently of size 20) to modify its control parameters. If you pass {\tt (double *) NULL} instead of a {\tt Control} array, then defaults are used. These defaults provide nearly optimal performance (both speed, memory usage, and numerical accuracy) for a wide range of matrices from real applications. This array will almost certainly grow in size in future releases, so be sure to dimension your {\tt Control} array to be of size {\tt UMFPACK\_CONTROL}. That constant is currently defined to be 20, but may increase in future versions, since all 20 entries are in use. The contents of this array may be modified by the user (see {\tt umfpack\_*\_defaults}). Each user-callable routine includes a complete description of how each control setting modifies its behavior. Table~\ref{control} summarizes the entire contents of the {\tt Control} array. Note that ANSI C uses 0-based indexing, while MATLAB uses 1-based indexing. Thus, {\tt Control(1)} in MATLAB is the same as {\tt Control[0]} or {\tt Control[UMFPACK\_PRL]} in ANSI C. \begin{table} \caption{UMFPACK Control parameters} \label{control} {\footnotesize \begin{tabular}{llll} \hline MATLAB & ANSI C & default & description \\ \hline {\tt Control(1)} & {\tt Control[UMFPACK\_PRL]} & 1 & printing level \\ {\tt Control(2)} & {\tt Control[UMFPACK\_DENSE\_ROW]} & 0.2 & dense row parameter \\ {\tt Control(3)} & {\tt Control[UMFPACK\_DENSE\_COL]} & 0.2 & dense column parameter \\ {\tt Control(4)} & {\tt Control[UMFPACK\_PIVOT\_TOLERANCE]} & 0.1 & partial pivoting tolerance \\ {\tt Control(5)} & {\tt Control[UMFPACK\_BLOCK\_SIZE]} & 32 & BLAS block size \\ {\tt Control(6)} & {\tt Control[UMFPACK\_STRATEGY]} & 0 (auto) & select strategy \\ {\tt Control(7)} & {\tt Control[UMFPACK\_ALLOC\_INIT]} & 0.7 & initial memory allocation \\ {\tt Control(8)} & {\tt Control[UMFPACK\_IRSTEP]} & 2 & max iter. refinement steps \\ {\tt Control(13)} & ignored & & \\ {\tt Control(14)} & {\tt Control[UMFPACK\_FIXQ]} & 0 (auto) & fix or modify Q \\ {\tt Control(15)} & {\tt Control[UMFPACK\_AMD\_DENSE]} & 10 & AMD dense row/column parameter \\ {\tt Control(16)} & {\tt Control[UMFPACK\_SYM\_PIVOT\_TOLERANCE]} & 0.001 & for diagonal entries \\ {\tt Control(17)} & {\tt Control[UMFPACK\_SCALE]} & 1 (sum) & row scaling (none, sum, or max) \\ {\tt Control(18)} & {\tt Control[UMFPACK\_FRONT\_ALLOC\_INIT]} & 0.5 & frontal matrix allocation ratio \\ {\tt Control(19)} & {\tt Control[UMFPACK\_DROPTOL]} & 0 & drop tolerance \\ {\tt Control(20)} & {\tt Control[UMFPACK\_AGGRESSIVE]} & 1 (yes) & aggressive absorption \\ & & & in AMD and COLAMD \\ % \hline \multicolumn{4}{l}{Can only be changed at compile time:} \\ {\tt Control(9)} & {\tt Control[UMFPACK\_COMPILED\_WITH\_BLAS]} & - & true if BLAS is used \\ {\tt Control(10)} & {\tt Control[UMFPACK\_COMPILED\_FOR\_MATLAB]} & - & true for mexFunction \\ {\tt Control(11)} & {\tt Control[UMFPACK\_COMPILED\_WITH\_GETRUSAGE]} & - & 1 if {\tt getrusage} used \\ {\tt Control(12)} & {\tt Control[UMFPACK\_COMPILED\_IN\_DEBUG\_MODE]} & - & true if debug mode enabled \\ \hline \end{tabular} } \end{table} Let $\alpha_r = ${\tt Control [UMFPACK\_DENSE\_ROW]}, $\alpha_c = ${\tt Control [UMFPACK\_DENSE\_COL]}, and $\alpha = ${\tt Control [UMFPACK\_AMD\_DENSE]}. Suppose the submatrix $\m{S}$, obtained after eliminating pivots with zero Markowitz cost, is $m$-by-$n$. Then a row is considered ``dense'' if it has more than $\max (16, 16 \alpha_r \sqrt{n})$ entries. A column is considered ``dense'' if it has more than $\max (16, 16 \alpha_c \sqrt{m})$ entries. These rows and columns are treated different in COLAMD and during numerical factorization. In COLAMD, dense columns are placed last in their natural order, and dense rows are ignored. During numerical factorization, dense rows are stored differently. In AMD, a row/column of the square matrix $\m{S}+\m{S}\tr$ is considered ``dense'' if it has more than $\max (16, \alpha \sqrt{n})$ entries. These rows/columns are placed last in AMD's output ordering. For more details on the control parameters, refer to the documentation of {\tt umfpack\_*\_qsymbolic}, {\tt umfpack\_*\_numeric}, {\tt umfpack\_*\_solve}, and the {\tt umfpack\_*\_report\_*} routines, in Sections~\ref{Primary}~through~\ref{Report}, below. %------------------------------------------------------------------------------- \subsection{Error codes} \label{error_codes} %------------------------------------------------------------------------------- Many of the routines return a {\tt status} value. This is also returned as the first entry in the {\tt Info} array, for those routines with that argument. The following list summarizes all of the error codes in UMFPACK. Each error code is given a specific name in the {\tt umfpack.h} include file, so you can use those constants instead of hard-coded values in your program. Future versions may report additional error codes. A value of zero means everything was successful, and the matrix is non-singular. A value greater than zero means the routine was successful, but a warning occurred. A negative value means the routine was not successful. In this case, no {\tt Symbolic} or {\tt Numeric} object was created. \begin{itemize} \item {\tt UMFPACK\_OK}, (0): UMFPACK was successful. \item {\tt UMFPACK\_WARNING\_singular\_matrix}, (1): Matrix is singular. There are exact zeros on the diagonal of $\m{U}$. \item {\tt UMFPACK\_WARNING\_determinant\_underflow}, (2): The determinant is nonzero, but smaller in magnitude than the smallest positive floating-point number. \item {\tt UMFPACK\_WARNING\_determinant\_overflow}, (3): The determinant is larger in magnitude than the largest positive floating-point number (IEEE Inf). \item {\tt UMFPACK\_ERROR\_out\_of\_memory}, (-1): Not enough memory. The ANSI C {\tt malloc} or {\tt realloc} routine failed. \item {\tt UMFPACK\_ERROR\_invalid\_Numeric\_object}, (-3): Routines that take a {\tt Numeric} object as input (or load it from a file) check this object and return this error code if it is invalid. This can be caused by a memory leak or overrun in your program, which can overwrite part of the Numeric object. It can also be caused by passing a Symbolic object by mistake, or some other pointer. If you try to factorize a matrix using one version of UMFPACK and then use the factors in another version, this error code will trigger as well. You cannot factor your matrix using version 4.0 and then solve with version 4.1, for example.\footnote{ Exception: v4.3, v4.3.1, and v4.4 use identical data structures for the {\tt Numeric} and {\tt Symbolic} objects}. You cannot use different precisions of the same version (real and complex, for example). It is possible for the {\tt Numeric} object to be corrupted by your program in subtle ways that are not detectable by this quick check. In this case, you may see an {\tt UMFPACK\_ERROR\_different\_pattern} error code, or even an {\tt UMFPACK\_ERROR\_internal\_error}. \item {\tt UMFPACK\_ERROR\_invalid\_Symbolic\_object}, (-4): Routines that take a {\tt Symbolic} object as input (or load it from a file) check this object and return this error code if it is invalid. The causes of this error are analogous to the {\tt UMFPACK\_ERROR\_invalid\_Numeric\_object} error described above. \item {\tt UMFPACK\_ERROR\_argument\_missing}, (-5): Some arguments of some are optional (you can pass a {\tt NULL} pointer instead of an array). This error code occurs if you pass a {\tt NULL} pointer when that argument is required to be present. \item {\tt UMFPACK\_ERROR\_n\_nonpositive} (-6): The number of rows or columns of the matrix must be greater than zero. \item {\tt UMFPACK\_ERROR\_invalid\_matrix} (-8): The matrix is invalid. For the column-oriented input, this error code will occur if the contents of {\tt Ap} and/or {\tt Ai} are invalid. {\tt Ap} is an integer array of size {\tt n\_col+1}. On input, it holds the ``pointers'' for the column form of the sparse matrix $\m{A}$. Column {\tt j} of the matrix A is held in {\tt Ai [(Ap [j])} \ldots {\tt (Ap [j+1]-1)]}. The first entry, {\tt Ap [0]}, must be zero, and {\tt Ap [j]} $\le$ {\tt Ap [j+1]} must hold for all {\tt j} in the range 0 to {\tt n\_col-1}. The value {\tt nz = Ap [n\_col]} is thus the total number of entries in the pattern of the matrix A. {\tt nz} must be greater than or equal to zero. The nonzero pattern (row indices) for column {\tt j} is stored in {\tt Ai [(Ap [j])} \ldots {\tt (Ap [j+1]-1)]}. The row indices in a given column {\tt j} must be in ascending order, and no duplicate row indices may be present. Row indices must be in the range 0 to {\tt n\_row-1} (the matrix is 0-based). Some routines take a triplet-form input, with arguments {\tt nz}, {\tt Ti}, and {\tt Tj}. This error code is returned if {\tt nz} is less than zero, if any row index in {\tt Ti} is outside the range 0 to {\tt n\_col-1}, or if any column index in {\tt Tj} is outside the range 0 to {\tt n\_row-1}. \item {\tt UMFPACK\_ERROR\_different\_pattern}, (-11): The most common cause of this error is that the pattern of the matrix has changed between the symbolic and numeric factorization. It can also occur if the {\tt Numeric} or {\tt Symbolic} object has been subtly corrupted by your program. \item {\tt UMFPACK\_ERROR\_invalid\_system}, (-13): The {\tt sys} argument provided to one of the solve routines is invalid. \item {\tt UMFPACK\_ERROR\_invalid\_permutation}, (-15): The permutation vector provided as input is invalid. \item {\tt UMFPACK\_ERROR\_file\_IO}, (-17): This error code is returned by the routines that save and load the {\tt Numeric} or {\tt Symbolic} objects to/from a file, if a file I/O error has occurred. The file may not exist or may not be readable, you may be trying to create a file that you don't have permission to create, or you may be out of disk space. The file you are trying to read might be the wrong one, and an earlier end-of-file condition would then result in this error. \item {\tt UMFPACK\_ERROR\_internal\_error}, (-911): An internal error has occurred, of unknown cause. This is either a bug in UMFPACK, or the result of a memory overrun from your program. Try modifying the file {\tt AMD/Include/amd\_internal.h} and adding the statement {\tt \#undef NDEBUG}, to enable the debugging mode. Recompile UMFPACK and rerun your program. A failed assertion might occur which can give you a better indication as to what is going wrong. Be aware that UMFPACK will be extraordinarily slow when running in debug mode. If all else fails, contact the developer (davis@cise.ufl.edu) with as many details as possible. \end{itemize} %------------------------------------------------------------------------------- \subsection{Larger examples} %------------------------------------------------------------------------------- Full examples of all user-callable UMFPACK routines are available in four stand-alone C main programs, {\tt umfpack\_*\_demo.c}. Another example is the UMFPACK mexFunction, {\tt umfpackmex.c}. The mexFunction accesses only the user-callable C interface to UMFPACK. The only features that it does not use are the support for the triplet form (MATLAB's sparse arrays are already in the compressed column form) and the ability to reuse the {\tt Symbolic} object to numerically factorize a matrix whose pattern is the same as a prior matrix analyzed by {\tt umfpack\_*\_symbolic} or {\tt umfpack\_*\_qsymbolic}. The latter is an important feature, but the mexFunction does not return its opaque {\tt Symbolic} and {\tt Numeric} objects to MATLAB. Instead, it gets the contents of these objects after extracting them via the {\tt umfpack\_*\_get\_*} routines, and returns them as MATLAB sparse matrices. The {\tt umf4.c} program for reading matrices in Harwell/Boeing format \cite{DuffGrimesLewis87b} is provided. It requires three Fortran 77 programs ({\tt readhb.f}, {\tt readhb\_nozeros.f}, and {\tt readhb\_size.f}) for reading in the sample Harwell/Boeing files in the {\tt UMFPACK/Demo/HB} directory. More matrices are available at http://www.cise.ufl.edu/research/sparse/matrices. Type {\tt make hb} in the {\tt UMFPACK/Demo/HB} directory to compile and run this demo. This program was used for the experimental results in \cite{Davis03}. %------------------------------------------------------------------------------- \section{Synopsis of C-callable routines} \label{Synopsis} %------------------------------------------------------------------------------- Each subsection, below, summarizes the input variables, output variables, return values, and calling sequences of the routines in one category. Variables with the same name as those already listed in a prior category have the same size and type. The real, {\tt UF\_long} integer {\tt umfpack\_dl\_*} routines are identical to the real, {\tt int} routines, except that {\tt \_di\_} is replaced with {\tt \_dl\_} in the name, and all {\tt int} arguments become {\tt UF\_long}. Similarly, the complex, {\tt UF\_long} integer {\tt umfpack\_zl\_*} routines are identical to the complex, {\tt int} routines, except that {\tt \_zi\_} is replaced with {\tt \_zl\_} in the name, and all {\tt int} arguments become {\tt UF\_long}. Only the real and complex {\tt int} versions are listed in the synopsis below. The matrix $\m{A}$ is {\tt m}-by-{\tt n} with {\tt nz} entries. The {\tt sys} argument of {\tt umfpack\_*\_solve} is an integer in the range 0 to 14 which defines which linear system is to be solved. \footnote{Integer values for {\tt sys} are used instead of strings (as in LINPACK and LAPACK) to avoid C-to-Fortran portability issues.} Valid values are listed in Table~\ref{sys}. The notation $\m{A}\he$ refers to the matrix transpose, which is the complex conjugate transpose for complex matrices ({\tt A'} in MATLAB). The array transpose is $\m{A}\tr$, which is {\tt A.'} in MATLAB. \begin{table} \begin{center} \caption{UMFPACK {\tt sys} parameter} \label{sys} {\footnotesize \begin{tabular}{ll|l} \hline Value & & system \\ \hline & & \\ {\tt UMFPACK\_A} & (0) & $\m{Ax}=\m{b}$ \\ {\tt UMFPACK\_At} & (1) & $\m{A}\he\m{x}=\m{b}$ \\ {\tt UMFPACK\_Aat} & (2) & $\m{A}\tr\m{x}=\m{b}$ \\ & & \\ \hline & & \\ {\tt UMFPACK\_Pt\_L} & (3) & $\m{P}\tr\m{Lx}=\m{b}$ \\ {\tt UMFPACK\_L} & (4) & $\m{Lx}=\m{b}$ \\ {\tt UMFPACK\_Lt\_P} & (5) & $\m{L}\he\m{Px}=\m{b}$ \\ {\tt UMFPACK\_Lat\_P} & (6) & $\m{L}\tr\m{Px}=\m{b}$ \\ {\tt UMFPACK\_Lt} & (7) & $\m{L}\he\m{x}=\m{b}$ \\ {\tt UMFPACK\_Lat} & (8) & $\m{L}\tr\m{x}=\m{b}$ \\ & & \\ \hline & & \\ {\tt UMFPACK\_U\_Qt} & (9) & $\m{UQ}\tr\m{x}=\m{b}$ \\ {\tt UMFPACK\_U} & (10) & $\m{Ux}=\m{b}$ \\ {\tt UMFPACK\_Q\_Ut} & (11) & $\m{QU}\he\m{x}=\m{b}$ \\ {\tt UMFPACK\_Q\_Uat} & (12) & $\m{QU}\tr\m{x}=\m{b}$ \\ {\tt UMFPACK\_Ut} & (13) & $\m{U}\he\m{x}=\m{b}$ \\ {\tt UMFPACK\_Uat} & (14) & $\m{U}\tr\m{x}=\m{b}$ \\ & & \\ \hline \end{tabular} } \end{center} \end{table} %------------------------------------------------------------------------------- \subsection{Primary routines: real/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} #include "umfpack.h" int status, sys, n, m, nz, Ap [n+1], Ai [nz] ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], Ax [nz], X [n], B [n] ; void *Symbolic, *Numeric ; status = umfpack_di_symbolic (m, n, Ap, Ai, Ax, &Symbolic, Control, Info) ; status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ; status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ; umfpack_di_free_symbolic (&Symbolic) ; umfpack_di_free_numeric (&Numeric) ; \end{verbatim} } %------------------------------------------------------------------------------- \subsection{Alternative routines: real/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} int Qinit [n], Wi [n] ; double W [5*n] ; umfpack_di_defaults (Control) ; status = umfpack_di_qsymbolic (m, n, Ap, Ai, Ax, Qinit, &Symbolic, Control, Info) ; status = umfpack_di_wsolve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info, Wi, W) ; \end{verbatim} } %------------------------------------------------------------------------------- \subsection{Matrix manipulation routines: real/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} int Ti [nz], Tj [nz], P [m], Q [n], Rp [m+1], Ri [nz], Map [nz] ; double Tx [nz], Rx [nz], Y [m], Z [m] ; status = umfpack_di_col_to_triplet (n, Ap, Tj) ; status = umfpack_di_triplet_to_col (m, n, nz, Ti, Tj, Tx, Ap, Ai, Ax, Map) ; status = umfpack_di_transpose (m, n, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ; status = umfpack_di_scale (Y, Z, Numeric) ; \end{verbatim} } %------------------------------------------------------------------------------- \subsection{Getting the contents of opaque objects: real/{\tt int}} %------------------------------------------------------------------------------- The {\tt filename} string should be large enough to hold the name of a file. {\footnotesize \begin{verbatim} int lnz, unz, Lp [m+1], Lj [lnz], Up [n+1], Ui [unz], do_recip ; double Lx [lnz], Ux [unz], D [min (m,n)], Rs [m], Mx [1], Ex [1] ; int nfr, nchains, P1 [m], Q1 [n], Front_npivcol [n+1], Front_parent [n+1], Front_1strow [n+1], Front_leftmostdesc [n+1], Chain_start [n+1], Chain_maxrows [n+1], Chain_maxcols [n+1] ; char filename [100] ; status = umfpack_di_get_lunz (&lnz, &unz, &m, &n, &nz_udiag, Numeric) ; status = umfpack_di_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, D, &do_recip, Rs, Numeric) ; status = umfpack_di_get_symbolic (&m, &n, &n1, &nz, &nfr, &nchains, P1, Q1, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ; status = umfpack_di_load_numeric (&Numeric, filename) ; status = umfpack_di_save_numeric (Numeric, filename) ; status = umfpack_di_load_symbolic (&Symbolic, filename) ; status = umfpack_di_save_symbolic (Symbolic, filename) ; status = umfapck_di_get_determinant (Mx, Ex, Numeric, Info) ; \end{verbatim} } %------------------------------------------------------------------------------- \subsection{Reporting routines: real/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} umfpack_di_report_status (Control, status) ; umfpack_di_report_control (Control) ; umfpack_di_report_info (Control, Info) ; status = umfpack_di_report_matrix (m, n, Ap, Ai, Ax, 1, Control) ; status = umfpack_di_report_matrix (m, n, Rp, Ri, Rx, 0, Control) ; status = umfpack_di_report_numeric (Numeric, Control) ; status = umfpack_di_report_perm (m, P, Control) ; status = umfpack_di_report_perm (n, Q, Control) ; status = umfpack_di_report_symbolic (Symbolic, Control) ; status = umfpack_di_report_triplet (m, n, nz, Ti, Tj, Tx, Control) ; status = umfpack_di_report_vector (n, X, Control) ; \end{verbatim} } %------------------------------------------------------------------------------- \subsection{Primary routines: complex/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} double Az [nz], Xx [n], Xz [n], Bx [n], Bz [n] ; status = umfpack_zi_symbolic (m, n, Ap, Ai, Ax, Az, &Symbolic, Control, Info) ; status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric, Control, Info) ; status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info) ; umfpack_zi_free_symbolic (&Symbolic) ; umfpack_zi_free_numeric (&Numeric) ; \end{verbatim} } The arrays {\tt Ax}, {\tt Bx}, and {\tt Xx} double in size if any imaginary argument ({\tt Az}, {\tt Xz}, or {\tt Bz}) is {\tt NULL}. %------------------------------------------------------------------------------- \subsection{Alternative routines: complex/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} double Wz [10*n] ; umfpack_zi_defaults (Control) ; status = umfpack_zi_qsymbolic (m, n, Ap, Ai, Ax, Az, Qinit, &Symbolic, Control, Info) ; status = umfpack_zi_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info, Wi, Wz) ; \end{verbatim} } %------------------------------------------------------------------------------- \subsection{Matrix manipulation routines: complex/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} double Tz [nz], Rz [nz], Yx [m], Yz [m], Zx [m], Zz [m] ; status = umfpack_zi_col_to_triplet (n, Ap, Tj) ; status = umfpack_zi_triplet_to_col (m, n, nz, Ti, Tj, Tx, Tz, Ap, Ai, Ax, Az, Map) ; status = umfpack_zi_transpose (m, n, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, 1) ; status = umfpack_zi_transpose (m, n, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, 0) ; status = umfpack_zi_scale (Yx, Yz, Zx, Zz, Numeric) ; \end{verbatim} } The arrays {\tt Tx}, {\tt Rx}, {\tt Yx}, and {\tt Zx} double in size if any imaginary argument ({\tt Tz}, {\tt Rz}, {\tt Yz}, or {\tt Zz}) is {\tt NULL}. %------------------------------------------------------------------------------- \subsection{Getting the contents of opaque objects: complex/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} double Lz [lnz], Uz [unz], Dx [min (m,n)], Dz [min (m,n)], Mz [1] ; status = umfpack_zi_get_lunz (&lnz, &unz, &m, &n, &nz_udiag, Numeric) ; status = umfpack_zi_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q, Dx, Dz, &do_recip, Rs, Numeric) ; status = umfpack_zi_get_symbolic (&m, &n, &n1, &nz, &nfr, &nchains, P1, Q1, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ; status = umfpack_zi_load_numeric (&Numeric, filename) ; status = umfpack_zi_save_numeric (Numeric, filename) ; status = umfpack_zi_load_symbolic (&Symbolic, filename) ; status = umfpack_zi_save_symbolic (Symbolic, filename) ; status = umfapck_zi_get_determinant (Mx, Mz, Ex, Numeric, Info) ; \end{verbatim} } The arrays {\tt Lx}, {\tt Ux}, {\tt Dx}, and {\tt Mx} double in size if any imaginary argument ({\tt Lz}, {\tt Uz}, {\tt Dz}, or {\tt Mz}) is {\tt NULL}. %------------------------------------------------------------------------------- \subsection{Reporting routines: complex/{\tt int}} %------------------------------------------------------------------------------- {\footnotesize \begin{verbatim} umfpack_zi_report_status (Control, status) ; umfpack_zi_report_control (Control) ; umfpack_zi_report_info (Control, Info) ; status = umfpack_zi_report_matrix (m, n, Ap, Ai, Ax, Az, 1, Control) ; status = umfpack_zi_report_matrix (m, n, Rp, Ri, Rx, Rz, 0, Control) ; status = umfpack_zi_report_numeric (Numeric, Control) ; status = umfpack_zi_report_perm (m, P, Control) ; status = umfpack_zi_report_perm (n, Q, Control) ; status = umfpack_zi_report_symbolic (Symbolic, Control) ; status = umfpack_zi_report_triplet (m, n, nz, Ti, Tj, Tx, Tz, Control) ; status = umfpack_zi_report_vector (n, Xx, Xz, Control) ; \end{verbatim} } The arrays {\tt Ax}, {\tt Rx}, {\tt Tx}, and {\tt Xx} double in size if any imaginary argument ({\tt Az}, {\tt Rz}, {\tt Tz}, or {\tt Xz}) is {\tt NULL}. %------------------------------------------------------------------------------- \subsection{Utility routines} %------------------------------------------------------------------------------- These routines are the same in all four versions of UMFPACK. {\footnotesize \begin{verbatim} double t, s [2] ; t = umfpack_timer ( ) ; umfpack_tic (s) ; umfpack_toc (s) ; \end{verbatim} } %------------------------------------------------------------------------------- \subsection{AMD ordering routines} %------------------------------------------------------------------------------- UMFPACK makes use of the AMD ordering package for its symmetric ordering strategy. You may also use these four user-callable routines in your own C programs. You need to include the {\tt amd.h} file only if you make direct calls to the AMD routines themselves. The {\tt int} versions are summarized below; {\tt UF\_long} versions are also available. Refer to the AMD User Guide for more information, or to the file {\tt amd.h} which documents these routines. {\footnotesize \begin{verbatim} #include "amd.h" double amd_control [AMD_CONTROL], amd_info [AMD_INFO] ; amd_defaults (amd_control) ; status = amd_order (n, Ap, Ai, P, amd_control, amd_info) ; amd_control (amd_control) ; amd_info (amd_info) ; \end{verbatim} } %------------------------------------------------------------------------------- \section{Using UMFPACK in a Fortran program} %------------------------------------------------------------------------------- UMFPACK includes a basic Fortran 77 interface to some of the C-callable UMFPACK routines. Since interfacing C and Fortran programs is not portable, this interface might not work with all C and Fortran compilers. Refer to Section~\ref{Install} for more details. The following Fortran routines are provided. The list includes the C-callable routines that the Fortran interface routine calls. Refer to the corresponding C routines in Section~\ref{C} for more details on what the Fortran routine does. \begin{itemize} \item {\tt umf4def}: sets the default control parameters ({\tt umfpack\_di\_defaults}). \item {\tt umf4sym}: pre-ordering and symbolic factorization ({\tt umfpack\_di\_symbolic}). \item {\tt umf4num}: numeric factorization ({\tt umfpack\_di\_numeric}). \item {\tt umf4solr}: solve a linear system with iterative refinement ({\tt umfpack\_di\_solve}). \item {\tt umf4sol}: solve a linear system without iterative refinement ({\tt umfpack\_di\_solve}). Sets {\tt Control [UMFPACK\_IRSTEP]} to zero, and does not require the matrix $\m{A}$. \item {\tt umf4scal}: scales a vector using UMFPACK's scale factors ({\tt umfpack\_di\_scale}). \item {\tt umf4fnum}: free the {\tt Numeric} object ({\tt umfpack\_di\_free\_numeric}). \item {\tt umf4fsym}: free the {\tt Symbolic} object ({\tt umfpack\_di\_free\_symbolic}). \item {\tt umf4pcon}: prints the control parameters ({\tt umfpack\_di\_report\_control}). \item {\tt umf4pinf}: print statistics ({\tt umfpack\_di\_report\_info}). \item {\tt umf4snum}: save the {\tt Numeric} object to a file ({\tt umfpack\_di\_save\_numeric}). \item {\tt umf4ssym}: save the {\tt Symbolic} object to a file ({\tt umfpack\_di\_save\_symbolic}). \item {\tt umf4lnum}: load the {\tt Numeric} object from a file ({\tt umfpack\_di\_load\_numeric}). \item {\tt umf4lsym}: load the {\tt Symbolic} object from a file ({\tt umfpack\_di\_load\_symbolic}). \end{itemize} The matrix $\m{A}$ is passed to UMFPACK in compressed column form, with 0-based indices. In Fortran, for an {\tt m}-by-{\tt n} matrix $\m{A}$ with {\tt nz} entries, the row indices of the first column (column 1) are in {\tt Ai (Ap(1)+1} \ldots {\tt Ap(2))}, with values in {\tt Ax (Ap(1)+1} \ldots {\tt Ap(2))}. The last column (column {\tt n}) is in {\tt Ai (Ap(n)+1} \ldots {\tt Ap(n+1))} and {\tt Ax (Ap(n)+1} \ldots {\tt Ap(n+1))}. The number of entries in the matrix is thus {\tt nz = Ap (n+1)}. The row indices in {\tt Ai} are in the range 0 to {\tt m}-1. They must be sorted, with no duplicate entries allowed. None of the UMFPACK routines modify the input matrix $\m{A}$. The following definitions apply for the Fortran routines: {\footnotesize \begin{verbatim} integer m, n, Ap (n+1), Ai (nz), symbolic, numeric, filenum, status double precision Ax (nz), control (20), info (90), x (n), b (n) \end{verbatim} } UMFPACK's status is returned in either a {\tt status} argument, or in {\tt info (1)}. It is zero if UMFPACK was successful, 1 if the matrix is singular (this is a warning, not an error), and negative if an error occurred. Section~\ref{error_codes} summarizes the possible values of {\tt status} and {\tt info (1)}. See Table~\ref{sys} for a list of the values of the {\tt sys} argument. See Table~\ref{control} for a list of the control parameters (the Fortran usage is the same as the MATLAB usage for this array). For the {\tt Numeric} and {\tt Symbolic} handles, it is probably safe to assume that a Fortran {\tt integer} is sufficient to store a C pointer. If that does not work, try defining {\tt numeric} and {\tt symbolic} in your Fortran program as integer arrays of size 2. You will need to define them as {\tt integer*8} if you compile UMFPACK in the 64-bit mode. To avoid passing strings between C and Fortran in the load/save routines, a file number is passed instead, and the C interface constructs a file name (if {\tt filenum} is 42, the {\tt Numeric} file name is {\tt n42.umf}, and the {\tt Symbolic} file name is {\tt s42.umf}). The following is a summary of the calling sequence of each Fortran interface routine. An example of their use is in the {\tt Demo/umf4hb.f} file. That routine also includes an example of how to convert a 1-based sparse matrix into 0-based form. For more details on the arguments of each routine, refer to the arguments of the same name in the corresponding C-callable routine, in Sections~\ref{Primary}~through~\ref{Utility}. The only exception is the {\tt control} argument of {\tt umf4sol}, which sets {\tt control (8)} to zero to disable iterative refinement. Note that the solve routines do not overwrite {\tt b} with the solution, but return their solution in a different array, {\tt x}. {\footnotesize \begin{verbatim} call umf4def (control) call umf4sym (m, n, Ap, Ai, Ax, symbolic, control, info) call umf4num (Ap, Ai, Ax, symbolic, numeric, control, info) call umf4solr (sys, Ap, Ai, Ax, x, b, numeric, control, info) call umf4sol (sys, x, b, numeric, control, info) call umf4scal (x, b, numeric, status) call umf4fnum (numeric) call umf4fsym (symbolic) call umf4pcon (control) call umf4pinf (control) call umf4snum (numeric, filenum, status) call umf4ssym (symbolic, filenum, status) call umf4lnum (numeric, filenum, status) call umf4lsym (symbolic, filenum, status) \end{verbatim} } Access to the complex routines in UMFPACK is provided by the interface routines in {\tt umf4\_f77zwrapper.c}. The following is a synopsis of each routine. All the arguments are the same as the real versions, except {\tt Az}, {\tt xz}, and {\tt bz} are the imaginary parts of the matrix, solution, and right-hand side, respectively. The {\tt Ax}, {\tt x}, and {\tt b} are the real parts. {\footnotesize \begin{verbatim} call umf4zdef (control) call umf4zsym (m, n, Ap, Ai, Ax, Az, symbolic, control, info) call umf4znum (Ap, Ai, Ax, Az, symbolic, numeric, control, info) call umf4zsolr (sys, Ap, Ai, Ax, Az, x, xz, b, bz, numeric, control, info) call umf4zsol (sys, x, xz, b, bz, numeric, control, info) call umf4zscal (x, xz, b, bz, numeric, status) call umf4zfnum (numeric) call umf4zfsym (symbolic) call umf4zpcon (control) call umf4zpinf (control) call umf4zsnum (numeric, filenum, status) call umf4zssym (symbolic, filenum, status) call umf4zlnum (numeric, filenum, status) call umf4zlsym (symbolic, filenum, status) \end{verbatim} } The Fortran interface does not support the packed complex case. %------------------------------------------------------------------------------- \section{Installation} \label{Install} %------------------------------------------------------------------------------- %------------------------------------------------------------------------------- \subsection{Installing the C library} %------------------------------------------------------------------------------- The following discussion assumes you have the {\tt make} program, either in Unix, or in Windows with Cygwin\footnote{www.cygwin.com}. You can skip this section and go to next one if all you want to use is the UMFPACK and AMD mexFunctions in MATLAB. You will need to install both UMFPACK and AMD to use UMFPACK. The {\tt UMFPACK} and {\tt AMD} subdirectories must be placed side-by-side within the same directory. AMD is a stand-alone package that is required by UMFPACK. UMFPACK can be compiled without the BLAS \cite{DaydeDuff99,ACM679a,ATLAS,GotoVandeGeijn02}, but your performance will be much less than what it should be. System-dependent configurations are in the {\tt UFconfig/UFconfig.mk} file. The default settings will work on most systems, except that UMFPACK will be compiled so that it does not use the BLAS. Sample configurations are provided for Linux, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha. To compile and install both packages, go to the {\tt UMFPACK} directory and type {\tt make}. This will compile the libraries ({\tt AMD/Lib/libamd.a} and {\tt UMFPACK/Lib/libumfpack.a}). A demo of the AMD ordering routine will be compiled and tested in the {\tt AMD/Demo} directory, and five demo programs will then be compiled and tested in the {\tt UMFPACK/Demo} directory. The outputs of these demo programs will then be compared with output files in the distribution. Expect to see a few differences, such as residual norms, compile-time control settings, and perhaps memory usage differences. To use {\tt make} to compile the MATLAB mexFunctions for MATLAB and AMD, you can either type {\tt make mex} in the UMFPACK directory. You may first need to edit the {\tt UFconfig/UFconfig.mk} file to modify the definition of the {\tt MEX}, if you have a version of MATLAB older than Version 7.2. Remove the {\tt -largeArrayDims} definition. If you use the MATLAB command {\tt umfpack\_make} in the MATLAB directory, then this case is handled for you automatically. If you have the GNU version of {\tt make}, the {\tt Lib/GNUmakefile} and {\tt MATLAB/GNUmakefile} files are used. These are much more concise than what the ``old'' version of {\tt make} can handle. If you do not have GNU {\tt make}, the {\tt Lib/Makefile} and {\tt MATLAB/Makefile} files are used instead. Each UMFPACK source file is compiled into four versions ({\tt double} / complex, and {\tt int} / {\tt UF\_long}). A proper old-style {\tt Makefile} is cumbersome in this case, so these two {\tt Makefile}'s have been constructed by brute force. They ignore dependencies, and simply compile everything. I highly recommend using GNU {\tt make} if you wish to modify UMFPACK. If you compile UMFPACK and AMD and then later change the {\tt UFconfig/UFconfig.mk} file then you should type {\tt make purge} and then {\tt make} to recompile. Here are the various parameters that you can control in your {\tt UFconfig/UFconfig.mk} file: \begin{itemize} \item {\tt CC = } your C compiler, such as {\tt cc}. \item {\tt RANLIB = } your system's {\tt ranlib} program, if needed. \item {\tt CFLAGS = } optimization flags, such as {\tt -O}. \item {\tt UMFPACK\_CONFIG = } configuration settings for the BLAS, memory allocation routines, and timing routines. \item {\tt LIB = } your libraries, such as {\tt -lm} or {\tt -lblas}. \item {\tt RM =} the command to delete a file. \item {\tt MV =} the command to rename a file. \item {\tt MEX =} the command to compile a MATLAB mexFunction. If you are using MATLAB 5, you need to add {\tt -DNBLAS} and {\tt -DNUTIL} to this command. \item {\tt F77 =} the command to compile a Fortran program (optional). \item {\tt F77FLAGS =} the Fortran compiler flags (optional). \item {\tt F77LIB =} the Fortran libraries (optional). \end{itemize} The {\tt UMFPACK\_CONFIG} string can include combinations of the following; most deal with how the BLAS are called: \begin{itemize} \item {\tt -DNBLAS} if you do not have any BLAS at all. \item {\tt -DNSUNPERF} if you are on Solaris but do not have the Sun Performance Library (for the BLAS). \item {\tt -DLONGBLAS} if your BLAS takes non-{\tt int} integer arguments. \item {\tt -DBLAS\_INT = } the integer used by the BLAS. \item {\tt -DBLAS\_NO\_UNDERSCORE} for controlling how C calls the Fortran BLAS. This is set automatically for Windows, Sun Solaris, SGI Irix, Red Hat Linux, Compaq Alpha, and AIX (the IBM RS 6000). \item {\tt -DGETRUSAGE} if you have the {\tt getrusage} function. \item {\tt -DNPOSIX} if you do not have the POSIX-compliant {\tt sysconf} and {\tt times} routines used by {\tt umfpack\_tic} and {\tt umfpack\_toc}. \item {\tt -DNRECIPROCAL} controls a trade-off between speed and accuracy. If defined (or if the pivot value itself is less than $10^{-12}$), then the pivot column is divided by the pivot value during numeric factorization. Otherwise, it is multiplied by the reciprocal of the pivot, which is faster but can be less accurate. The default is to multiply by the reciprocal unless the pivot value is small. This option also modifies how the rows of the matrix $\m{A}$ are scaled. If {\tt -DNRECIPROCAL} is defined (or if any scale factor is less than $10^{-12}$), entries in the rows of $\m{A}$ are divided by the scale factors. Otherwise, they are multiplied by the reciprocal. When compiling the complex routines with the GNU {\tt gcc} compiler, the pivot column is always divided by the pivot entry, because of a numerical accuracy issue encountered with {\tt gcc} version 3.2 with a few complex matrices on a Pentium 4M (running Linux). You can still use {\tt -DNRECIPROCAL} to control how the scale factors for the rows of $\m{A}$ are applied. \item {\tt -DNO\_DIVIDE\_BY\_ZERO} controls how UMFPACK treats zeros on the diagonal of $\m{U}$, for a singular matrix $\m{A}$. If defined, then no division by zero is performed (a zero entry on the diagonal of $\m{U}$ is treated as if it were equal to one). By default, UMFPACK will divide by zero. \item {\tt -DNO\_TIMER} controls whether or not timing routines are to be called. If defined, no timers are used. Timers are included by default. \end{itemize} If a Fortran BLAS package is used you may see compiler warnings. The BLAS routines {\tt dgemm}, {\tt dgemv}, {\tt dger}, {\tt dtrsm}, {\tt dtrsv}, {\tt dscal} and their corresponding complex versions are used. Header files are not provided for the Fortran BLAS. You may safely ignore all of these warnings. I highly recommend the recent BLAS by Goto and van de Geijn \cite{GotoVandeGeijn02}. Using this BLAS increased the performance of UMFPACK by up to 50\% on a Dell Latitude C840 laptop (2GHz Pentium 4M, 512K L2 cache, 1GB main memory). The peak performance of {\tt umfpack\_di\_numeric} with Goto and van de Geijn's BLAS is 1.6 Gflops on this computer. In MATLAB, the peak performance of UMFPACK on a dense matrix (stored in sparse format) is 900 Mflops, as compared to 1 Gflop for {\tt x = A}$\backslash${\tt b} when {\tt A} is stored as a regular full matrix. When you compile your program that uses the C-callable UMFPACK library, you need to link your program with both libraries ({\tt UMFPACK/Lib/libumfpack.a} and {\tt AMD/Lib/libamd.a}) and you need to tell your compiler to look in the directories {\tt UMFPACK/Include} and {\tt AMD/Include} for include files. See {\tt UMFPACK/Demo/Makefile} for an example. You do not need to directly include any AMD include files in your program, unless you directly call AMD routines. You only need the \begin{verbatim} #include "umfpack.h" \end{verbatim} statement, as described in Section~\ref{Synopsis}. If you would like to compile both 32-bit and 64-bit versions of the libraries, you will need to do it in two steps. Modify your {\tt UFconfig/UFconfig.mk} file, and select the 32-bit option. Type {\tt make} in the {\tt UMFPACK} directory, which creates the {\tt UMFPACK/Lib/libumfpack.a} and {\tt AMD/Lib/libamd.a} libraries. Rename those two files. Edit your {\tt UFconfig/UFconfig.mk} file and select the 64-bit option. Type {\tt make purge}, and then {\tt make}, and you will create the 64-bit libraries. You can use the same {\tt umfpack.h} include file for both 32-bit and 64-bit versions. Simply link your program with the appropriate 32-bit or 64-bit compiled version of the UMFPACK and AMD libraries. Type {\tt make hb} in the {\tt UMFPACK/Demo/HB} directory to compile and run a C program that reads in and factorizes Harwell/Boeing matrices. Note that this uses a stand-alone Fortran program to read in the Fortran-formatted Harwell/Boeing matrices and write them to a file which can be read by a C program. The {\tt umf\_multicompile.c} file has been added to assist in the compilation of UMFPACK in Microsoft Visual Studio, for Windows. %------------------------------------------------------------------------------- \subsection{Installing the MATLAB interface} %------------------------------------------------------------------------------- If all you want to do is use the UMFPACK mexFunction in MATLAB, you can skip the use of the {\tt make} command described above. Simply type {\tt umfpack\_make} in MATLAB while in the {\tt UMFPACK/MATLAB} directory. You can also type {\tt amd\_make} in the {\tt AMD/MATLAB} directory to compile the stand-alone AMD mexFunction (this is not required to compile the UMFPACK mexFunction). This works on any computer with MATLAB, including Windows. If you are using Windows and the {\tt lcc} compiler bundled with MATLAB 6.1, then you may need to copy the {\tt UMFPACK}$\backslash${\tt MATLAB}$\backslash${\tt lcc\_lib}$\backslash${\tt libmwlapack.lib} file into the {\tt }$\backslash${\tt extern}$\backslash${\tt lib}$\backslash${\tt win32}$\backslash${\tt lcc}$\backslash$ directory. Next, type {\tt mex -setup} at the MATLAB prompt, and ask MATLAB to select the {\tt lcc} compiler. MATLAB 6.1 has built-in BLAS, but in that version of MATLAB the BLAS cannot be accessed by a mexFunction compiled by {\tt lcc} without first copying this file to the location listed above. If you have MATLAB 6.5 or later, you can probably skip this step. %------------------------------------------------------------------------------- \subsection{Installing the Fortran interface} %------------------------------------------------------------------------------- Once the 32-bit C-callable UMFPACK library is compiled, you can also compile the Fortran interface, by typing {\tt make fortran}. This will create the {\tt umf4hb} program, test it, and compare the output with the file {\tt umf4hb.out} in the distribution. If you compiled UMFPACK in 64-bit mode, you need to use {\tt make fortran64} instead, which compiles the {\tt umf4hb64} program and compares its output with the file {\tt umf4hb64.out}. Refer to the comments in the {\tt Demo/umf4\_f77wrapper.c} file for more details. This interface is {\bf highly} non-portable, since it depends on how C and Fortran are interfaced. Because of this issue, the interface is included in the {\tt Demo} directory, and not as a primary part of the UMFPACK library. The interface routines are not included in the compiled {\tt UMFPACK/Lib/libumfpack.a} library, but left as stand-alone compiled files ({\tt umf4\_f77wrapper.o} and {\tt umf4\_f77wrapper64.o} in the {\tt Demo} directory). You may need to modify the interface routines in the file {\tt umf4\_f77wrapper.c} if you are using compilers for which this interface has not been tested. %------------------------------------------------------------------------------- \subsection{Known Issues} %------------------------------------------------------------------------------- The Microsoft C or C++ compilers on a Pentium badly break the IEEE 754 standard, and do not treat NaN's properly. According to IEEE 754, the expression {\tt (x != x)} is supposed to be true if and only if {\tt x} is NaN. For non-compliant compilers in Windows that expression is always false, and another test must be used: {\tt (x < x)} is true if and only if {\tt x} is NaN. For compliant compilers, {\tt (x < x)} is always false, for any value of {\tt x} (including NaN). To cover both cases, UMFPACK when running under Microsoft Windows defines the following macro, which is true if and only if {\tt x} is NaN, regardless of whether your compiler is compliant or not: \begin{verbatim} #define SCALAR_IS_NAN(x) (((x) != (x)) || ((x) < (x))) \end{verbatim} If your compiler breaks this test, then UMFPACK will fail catastrophically if it encounters a NaN. You will not just see NaN's in your output; UMFPACK will probably crash with a segmentation fault. In that case, you might try to see if the common (but non-ANSI C) routine {\tt isnan} is available, and modify the macro {\tt SCALAR\_IS\_NAN} in {\tt umf\_version.h} accordingly. The simpler (and IEEE 754-compliant) test {\tt (x != x)} is always true with Linux on a PC, and on every Unix compiler I have tested. Some compilers will complain about the Fortran BLAS being defined implicitly. C prototypes for the BLAS are not used, except the C-BLAS. Some compilers will complain about unrecognized {\tt \#pragma}'s. You may safely ignore all of these warnings. %------------------------------------------------------------------------------- \section{Future work} \label{Future} %------------------------------------------------------------------------------- Here are a few features that are not in the current version of UMFPACK, in no particular order. They may appear in a future release of UMFPACK. If you are interested, let me know and I could consider including them: \begin{enumerate} \item Remove the restriction that the column-oriented form be given with sorted columns. This has already been done in AMD Version 2.0. \item Future versions may have different default {\tt Control} parameters. Future versions may return more statistics in the {\tt Info} array, and they may use more entries in the {\tt Control} array. These two arrays will probably become larger, since there are very few unused entries. If they change in size, the constants {\tt UMFPACK\_CONTROL} and {\tt UMFPACK\_INFO} defined in {\tt umfpack.h} will be changed to reflect their new size. Your C program should use these constants when declaring the size of these two arrays. Do not define them as {\tt Control [20]} and {\tt Info [90]}. \item Forward/back solvers for the conventional row or column-form data structure for $\m{L}$ and $\m{U}$ (the output of {\tt umfpack\_*\_di\_get\_numeric}). This would enable a separate solver that could be used to write a MATLAB mexFunction {\tt x = lu\_refine (A, b, L, U, P, Q, R)} that gives MATLAB access to the iterative refinement algorithm with sparse backward error analysis. It would also be easier to handle sparse right-hand sides in this data structure, and end up with good asymptotic run-time in this case (particularly for $\m{Lx}=\m{b}$; see \cite{GilbertPeierls88}). See also CSparse and CXSparse for software for handling sparse right-hand sides. \item Complex absolute value computations could be based on FDLIBM (see \newline http://www.netlib.org/fdlibm), using the {\tt hypot(x,y)} routine. \item When using iterative refinement, the residual $\m{Ax}-\m{b}$ could be returned by {\tt umfpack\_solve}. \item The solve routines could handle multiple right-hand sides, and sparse right-hand sides. See {\tt umfpack\_solve} for the MATLAB version of this feature. See also CSparse and CXSparse for software for handling sparse right-hand sides. \item An option to redirect the error and diagnostic output. \item Permutation to block-triangular-form \cite{Duff78a} for the C-callable interface. There are two routines in the ACM Collected Algorithms (529 and 575) \cite{Duff81b,Duff78b} that could be translated from Fortran to C and included in UMFPACK. This would result in better performance for matrices from circuit simulation and chemical process engineering. See {\tt umfpack\_btf.m} for the MATLAB version of this feature. KLU includes this feature. See also {\tt cs\_dmperm} in CSparse and CXSparse. \item The ability to use user-provided work arrays, so that {\tt malloc}, {\tt free}, and {\tt realloc} realloc are not called. The {\tt umfpack\_*\_wsolve} routine is one example. \item A method that takes time proportional to the number of nonzeros in $\m{A}$ to compute the symbolic factorization \cite{GilbertNgPeyton94}. This would improve the performance of the symmetric strategy, and the unsymmetric strategy when dense rows are present. The current method takes time proportional to the number of nonzeros in the upper bound of $\m{U}$. The method used in UMFPACK exploits super-columns, however, so this bound is rarely reached. See {\tt cs\_counts} in CSparse and CXSparse, and {\tt cholmod\_analyze} in CHOLMOD. \item Other basic sparse matrix operations, such as sparse matrix multiplication, could be included. \item A more complete Fortran interface. \item A C++ interface. \item A parallel version using MPI. This would require a large amount of effort. \end{enumerate} %------------------------------------------------------------------------------- \newpage \section{The primary UMFPACK routines} \label{Primary} %------------------------------------------------------------------------------- The include files are the same for all four versions of UMFPACK. The generic integer type is {\tt Int}, which is an {\tt int} or {\tt UF\_long}, depending on which version of UMFPACK you are using. \subsection{umfpack\_*\_symbolic} {\footnotesize \begin{verbatim} INCLUDE umfpack_symbolic.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_numeric} {\footnotesize \begin{verbatim} INCLUDE umfpack_numeric.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_solve} {\footnotesize \begin{verbatim} INCLUDE umfpack_solve.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_free\_symbolic} {\footnotesize \begin{verbatim} INCLUDE umfpack_free_symbolic.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_free\_numeric} {\footnotesize \begin{verbatim} INCLUDE umfpack_free_numeric.h via sed \end{verbatim} } %------------------------------------------------------------------------------- \newpage \section{Alternative routines} \label{Alternative} %------------------------------------------------------------------------------- \subsection{umfpack\_*\_defaults} {\footnotesize \begin{verbatim} INCLUDE umfpack_defaults.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_qsymbolic} {\footnotesize \begin{verbatim} INCLUDE umfpack_qsymbolic.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_wsolve} {\footnotesize \begin{verbatim} INCLUDE umfpack_wsolve.h via sed \end{verbatim} } %------------------------------------------------------------------------------- \newpage \section{Matrix manipulation routines} \label{Manipulate} %------------------------------------------------------------------------------- \subsection{umfpack\_*\_col\_to\_triplet} {\footnotesize \begin{verbatim} INCLUDE umfpack_col_to_triplet.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_triplet\_to\_col} {\footnotesize \begin{verbatim} INCLUDE umfpack_triplet_to_col.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_transpose} {\footnotesize \begin{verbatim} INCLUDE umfpack_transpose.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_scale} {\footnotesize \begin{verbatim} INCLUDE umfpack_scale.h via sed \end{verbatim} } %------------------------------------------------------------------------------- \newpage \section{Getting the contents of opaque objects} \label{Get} %------------------------------------------------------------------------------- \subsection{umfpack\_*\_get\_lunz} {\footnotesize \begin{verbatim} INCLUDE umfpack_get_lunz.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_get\_numeric} {\footnotesize \begin{verbatim} INCLUDE umfpack_get_numeric.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_get\_symbolic} {\footnotesize \begin{verbatim} INCLUDE umfpack_get_symbolic.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_save\_numeric} {\footnotesize \begin{verbatim} INCLUDE umfpack_save_numeric.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_load\_numeric} {\footnotesize \begin{verbatim} INCLUDE umfpack_load_numeric.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_save\_symbolic} {\footnotesize \begin{verbatim} INCLUDE umfpack_save_symbolic.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_load\_symbolic} {\footnotesize \begin{verbatim} INCLUDE umfpack_load_symbolic.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_get\_determinant} {\footnotesize \begin{verbatim} INCLUDE umfpack_get_determinant.h via sed \end{verbatim} } %------------------------------------------------------------------------------- \newpage \section{Reporting routines} \label{Report} %------------------------------------------------------------------------------- \subsection{umfpack\_*\_report\_status} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_status.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_control} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_control.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_info} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_info.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_matrix} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_matrix.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_numeric} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_numeric.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_perm} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_perm.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_symbolic} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_symbolic.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_triplet} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_triplet.h via sed \end{verbatim} } \newpage \subsection{umfpack\_*\_report\_vector} {\footnotesize \begin{verbatim} INCLUDE umfpack_report_vector.h via sed \end{verbatim} } %------------------------------------------------------------------------------- \newpage \section{Utility routines} \label{Utility} %------------------------------------------------------------------------------- \subsection{umfpack\_timer} {\footnotesize \begin{verbatim} INCLUDE umfpack_timer.h via sed \end{verbatim} } \newpage \subsection{umfpack\_tic and umfpack\_toc} {\footnotesize \begin{verbatim} INCLUDE umfpack_tictoc.h via sed \end{verbatim} } %------------------------------------------------------------------------------- \newpage % References %------------------------------------------------------------------------------- \bibliographystyle{plain} \bibliography{UserGuide} \end{document} cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/0000755000175000017500000000000011674452555017775 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_numeric.h0000644000175000017500000005525711674452555023334 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_numeric ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_numeric ( const int Ap [ ], const int Ai [ ], const double Ax [ ], void *Symbolic, void **Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_dl_numeric ( const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], void *Symbolic, void **Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; int umfpack_zi_numeric ( const int Ap [ ], const int Ai [ ], const double Ax [ ], const double Az [ ], void *Symbolic, void **Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_zl_numeric ( const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const double Az [ ], void *Symbolic, void **Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; /* double int Syntax: #include "umfpack.h" void *Symbolic, *Numeric ; int *Ap, *Ai, status ; double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info); double UF_long Syntax: #include "umfpack.h" void *Symbolic, *Numeric ; UF_long *Ap, *Ai, status ; double *Ax, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; status = umfpack_dl_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info); complex int Syntax: #include "umfpack.h" void *Symbolic, *Numeric ; int *Ap, *Ai, status ; double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; status = umfpack_zi_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric, Control, Info) ; complex UF_long Syntax: #include "umfpack.h" void *Symbolic, *Numeric ; UF_long *Ap, *Ai, status ; double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; status = umfpack_zl_numeric (Ap, Ai, Ax, Az, Symbolic, &Numeric, Control, Info) ; packed complex Syntax: Same as above, except that Az is NULL. Purpose: Given a sparse matrix A in column-oriented form, and a symbolic analysis computed by umfpack_*_*symbolic, the umfpack_*_numeric routine performs the numerical factorization, PAQ=LU, PRAQ=LU, or P(R\A)Q=LU, where P and Q are permutation matrices (represented as permutation vectors), R is the row scaling, L is unit-lower triangular, and U is upper triangular. This is required before the system Ax=b (or other related linear systems) can be solved. umfpack_*_numeric can be called multiple times for each call to umfpack_*_*symbolic, to factorize a sequence of matrices with identical nonzero pattern. Simply compute the Symbolic object once, with umfpack_*_*symbolic, and reuse it for subsequent matrices. This routine safely detects if the pattern changes, and sets an appropriate error code. Returns: The status code is returned. See Info [UMFPACK_STATUS], below. Arguments: Int Ap [n_col+1] ; Input argument, not modified. This must be identical to the Ap array passed to umfpack_*_*symbolic. The value of n_col is what was passed to umfpack_*_*symbolic (this is held in the Symbolic object). Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col]. This must be identical to the Ai array passed to umfpack_*_*symbolic. double Ax [nz] ; Input argument, not modified, of size nz = Ap [n_col]. Size 2*nz for packed complex case. The numerical values of the sparse matrix A. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. double Az [nz] ; Input argument, not modified, for complex versions. For the complex versions, this holds the imaginary part of A. The imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)]. If Az is NULL, then both real and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k] and Ax[2*k+1] being the real and imaginary part of the kth entry. void *Symbolic ; Input argument, not modified. The Symbolic object, which holds the symbolic factorization computed by umfpack_*_*symbolic. The Symbolic object is not modified by umfpack_*_numeric. void **Numeric ; Output argument. **Numeric is the address of a (void *) pointer variable in the user's calling routine (see Syntax, above). On input, the contents of this variable are not defined. On output, this variable holds a (void *) pointer to the Numeric object (if successful), or (void *) NULL if a failure occurred. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PIVOT_TOLERANCE]: relative pivot tolerance for threshold partial pivoting with row interchanges. In any given column, an entry is numerically acceptable if its absolute value is greater than or equal to Control [UMFPACK_PIVOT_TOLERANCE] times the largest absolute value in the column. A value of 1.0 gives true partial pivoting. If less than or equal to zero, then any nonzero entry is numerically acceptable as a pivot. Default: 0.1. Smaller values tend to lead to sparser LU factors, but the solution to the linear system can become inaccurate. Larger values can lead to a more accurate solution (but not always), and usually an increase in the total work. For complex matrices, a cheap approximate of the absolute value is used for the threshold partial pivoting test (|a_real| + |a_imag| instead of the more expensive-to-compute exact absolute value sqrt (a_real^2 + a_imag^2)). Control [UMFPACK_SYM_PIVOT_TOLERANCE]: If diagonal pivoting is attempted (the symmetric or symmetric-2by2 strategies are used) then this parameter is used to control when the diagonal entry is selected in a given pivot column. The absolute value of the entry must be >= Control [UMFPACK_SYM_PIVOT_TOLERANCE] times the largest absolute value in the column. A value of zero will ensure that no off-diagonal pivoting is performed, except that zero diagonal entries are not selected if there are any off-diagonal nonzero entries. If an off-diagonal pivot is selected, an attempt is made to restore symmetry later on. Suppose A (i,j) is selected, where i != j. If column i has not yet been selected as a pivot column, then the entry A (j,i) is redefined as a "diagonal" entry, except that the tighter tolerance (Control [UMFPACK_PIVOT_TOLERANCE]) is applied. This strategy has an effect similar to 2-by-2 pivoting for symmetric indefinite matrices. If a 2-by-2 block pivot with nonzero structure i j i: 0 x j: x 0 is selected in a symmetric indefinite factorization method, the 2-by-2 block is inverted and a rank-2 update is applied. In UMFPACK, this 2-by-2 block would be reordered as j i i: x 0 j: 0 x In both cases, the symmetry of the Schur complement is preserved. Control [UMFPACK_SCALE]: Note that the user's input matrix is never modified, only an internal copy is scaled. There are three valid settings for this parameter. If any other value is provided, the default is used. UMFPACK_SCALE_NONE: no scaling is performed. UMFPACK_SCALE_SUM: each row of the input matrix A is divided by the sum of the absolute values of the entries in that row. The scaled matrix has an infinity norm of 1. UMFPACK_SCALE_MAX: each row of the input matrix A is divided by the maximum the absolute values of the entries in that row. In the scaled matrix the largest entry in each row has a magnitude exactly equal to 1. Note that for complex matrices, a cheap approximate absolute value is used, |a_real| + |a_imag|, instead of the exact absolute value sqrt ((a_real)^2 + (a_imag)^2). Scaling is very important for the "symmetric" strategy when diagonal pivoting is attempted. It also improves the performance of the "unsymmetric" strategy. Default: UMFPACK_SCALE_SUM. Control [UMFPACK_ALLOC_INIT]: When umfpack_*_numeric starts, it allocates memory for the Numeric object. Part of this is of fixed size (approximately n double's + 12*n integers). The remainder is of variable size, which grows to hold the LU factors and the frontal matrices created during factorization. A estimate of the upper bound is computed by umfpack_*_*symbolic, and returned by umfpack_*_*symbolic in Info [UMFPACK_VARIABLE_PEAK_ESTIMATE] (in Units). If Control [UMFPACK_ALLOC_INIT] is >= 0, umfpack_*_numeric initially allocates space for the variable-sized part equal to this estimate times Control [UMFPACK_ALLOC_INIT]. Typically, for matrices for which the "unsymmetric" strategy applies, umfpack_*_numeric needs only about half the estimated memory space, so a setting of 0.5 or 0.6 often provides enough memory for umfpack_*_numeric to factorize the matrix with no subsequent increases in the size of this block. If the matrix is ordered via AMD, then this non-negative parameter is ignored. The initial allocation ratio computed automatically, as 1.2 * (nz + Info [UMFPACK_SYMMETRIC_LUNZ]) / (Info [UMFPACK_LNZ_ESTIMATE] + Info [UMFPACK_UNZ_ESTIMATE] - min (n_row, n_col)). If Control [UMFPACK_ALLOC_INIT] is negative, then umfpack_*_numeric allocates a space with initial size (in Units) equal to (-Control [UMFPACK_ALLOC_INIT]). Regardless of the value of this parameter, a space equal to or greater than the the bare minimum amount of memory needed to start the factorization is always initially allocated. The bare initial memory required is returned by umfpack_*_*symbolic in Info [UMFPACK_VARIABLE_INIT_ESTIMATE] (an exact value, not an estimate). If the variable-size part of the Numeric object is found to be too small sometime after numerical factorization has started, the memory is increased in size by a factor of 1.2. If this fails, the request is reduced by a factor of 0.95 until it succeeds, or until it determines that no increase in size is possible. Garbage collection then occurs. The strategy of attempting to "malloc" a working space, and re-trying with a smaller space, may not work when UMFPACK is used as a mexFunction MATLAB, since mxMalloc aborts the mexFunction if it fails. This issue does not affect the use of UMFPACK as a part of the built-in x=A\b in MATLAB 6.5 and later. If you are using the umfpack mexFunction, decrease the magnitude of Control [UMFPACK_ALLOC_INIT] if you run out of memory in MATLAB. Default initial allocation size: 0.7. Thus, with the default control settings and the "unsymmetric" strategy, the upper-bound is reached after two reallocations (0.7 * 1.2 * 1.2 = 1.008). Changing this parameter has little effect on fill-in or operation count. It has a small impact on run-time (the extra time required to do the garbage collection and memory reallocation). Control [UMFPACK_FRONT_ALLOC_INIT]: When UMFPACK starts the factorization of each "chain" of frontal matrices, it allocates a working array to hold the frontal matrices as they are factorized. The symbolic factorization computes the size of the largest possible frontal matrix that could occur during the factorization of each chain. If Control [UMFPACK_FRONT_ALLOC_INIT] is >= 0, the following strategy is used. If the AMD ordering was used, this non-negative parameter is ignored. A front of size (d+2)*(d+2) is allocated, where d = Info [UMFPACK_SYMMETRIC_DMAX]. Otherwise, a front of size Control [UMFPACK_FRONT_ALLOC_INIT] times the largest front possible for this chain is allocated. If Control [UMFPACK_FRONT_ALLOC_INIT] is negative, then a front of size (-Control [UMFPACK_FRONT_ALLOC_INIT]) is allocated (where the size is in terms of the number of numerical entries). This is done regardless of the ordering method or ordering strategy used. Default: 0.5. Control [UMFPACK_DROPTOL]: Entries in L and U with absolute value less than or equal to the drop tolerance are removed from the data structures (unless leaving them there reduces memory usage by reducing the space required for the nonzero pattern of L and U). Default: 0.0. double Info [UMFPACK_INFO] ; Output argument. Contains statistics about the numeric factorization. If a (double *) NULL pointer is passed, then no statistics are returned in Info (this is not an error condition). The following statistics are computed in umfpack_*_numeric: Info [UMFPACK_STATUS]: status code. This is also the return value, whether or not Info is present. UMFPACK_OK Numeric factorization was successful. umfpack_*_numeric computed a valid numeric factorization. UMFPACK_WARNING_singular_matrix Numeric factorization was successful, but the matrix is singular. umfpack_*_numeric computed a valid numeric factorization, but you will get a divide by zero in umfpack_*_*solve. For the other cases below, no Numeric object is created (*Numeric is (void *) NULL). UMFPACK_ERROR_out_of_memory Insufficient memory to complete the numeric factorization. UMFPACK_ERROR_argument_missing One or more required arguments are missing. UMFPACK_ERROR_invalid_Symbolic_object Symbolic object provided as input is invalid. UMFPACK_ERROR_different_pattern The pattern (Ap and/or Ai) has changed since the call to umfpack_*_*symbolic which produced the Symbolic object. Info [UMFPACK_NROW]: the value of n_row stored in the Symbolic object. Info [UMFPACK_NCOL]: the value of n_col stored in the Symbolic object. Info [UMFPACK_NZ]: the number of entries in the input matrix. This value is obtained from the Symbolic object. Info [UMFPACK_SIZE_OF_UNIT]: the number of bytes in a Unit, for memory usage statistics below. Info [UMFPACK_VARIABLE_INIT]: the initial size (in Units) of the variable-sized part of the Numeric object. If this differs from Info [UMFPACK_VARIABLE_INIT_ESTIMATE], then the pattern (Ap and/or Ai) has changed since the last call to umfpack_*_*symbolic, which is an error condition. Info [UMFPACK_VARIABLE_PEAK]: the peak size (in Units) of the variable-sized part of the Numeric object. This size is the amount of space actually used inside the block of memory, not the space allocated via UMF_malloc. You can reduce UMFPACK's memory requirements by setting Control [UMFPACK_ALLOC_INIT] to the ratio Info [UMFPACK_VARIABLE_PEAK] / Info[UMFPACK_VARIABLE_PEAK_ESTIMATE]. This will ensure that no memory reallocations occur (you may want to add 0.001 to make sure that integer roundoff does not lead to a memory size that is 1 Unit too small; otherwise, garbage collection and reallocation will occur). Info [UMFPACK_VARIABLE_FINAL]: the final size (in Units) of the variable-sized part of the Numeric object. It holds just the sparse LU factors. Info [UMFPACK_NUMERIC_SIZE]: the actual final size (in Units) of the entire Numeric object, including the final size of the variable part of the object. Info [UMFPACK_NUMERIC_SIZE_ESTIMATE], an estimate, was computed by umfpack_*_*symbolic. The estimate is normally an upper bound on the actual final size, but this is not guaranteed. Info [UMFPACK_PEAK_MEMORY]: the actual peak memory usage (in Units) of both umfpack_*_*symbolic and umfpack_*_numeric. An estimate, Info [UMFPACK_PEAK_MEMORY_ESTIMATE], was computed by umfpack_*_*symbolic. The estimate is normally an upper bound on the actual peak usage, but this is not guaranteed. With testing on hundreds of matrix arising in real applications, I have never observed a matrix where this estimate or the Numeric size estimate was less than the actual result, but this is theoretically possible. Please send me one if you find such a matrix. Info [UMFPACK_FLOPS]: the actual count of the (useful) floating-point operations performed. An estimate, Info [UMFPACK_FLOPS_ESTIMATE], was computed by umfpack_*_*symbolic. The estimate is guaranteed to be an upper bound on this flop count. The flop count excludes "useless" flops on zero values, flops performed during the pivot search (for tentative updates and assembly of candidate columns), and flops performed to add frontal matrices together. For the real version, only (+ - * /) are counted. For the complex version, the following counts are used: operation flops c = 1/b 6 c = a*b 6 c -= a*b 8 Info [UMFPACK_LNZ]: the actual nonzero entries in final factor L, including the diagonal. This excludes any zero entries in L, although some of these are stored in the Numeric object. The Info [UMFPACK_LU_ENTRIES] statistic does account for all explicitly stored zeros, however. Info [UMFPACK_LNZ_ESTIMATE], an estimate, was computed by umfpack_*_*symbolic. The estimate is guaranteed to be an upper bound on Info [UMFPACK_LNZ]. Info [UMFPACK_UNZ]: the actual nonzero entries in final factor U, including the diagonal. This excludes any zero entries in U, although some of these are stored in the Numeric object. The Info [UMFPACK_LU_ENTRIES] statistic does account for all explicitly stored zeros, however. Info [UMFPACK_UNZ_ESTIMATE], an estimate, was computed by umfpack_*_*symbolic. The estimate is guaranteed to be an upper bound on Info [UMFPACK_UNZ]. Info [UMFPACK_NUMERIC_DEFRAG]: The number of garbage collections performed during umfpack_*_numeric, to compact the contents of the variable-sized workspace used by umfpack_*_numeric. No estimate was computed by umfpack_*_*symbolic. In the current version of UMFPACK, garbage collection is performed and then the memory is reallocated, so this statistic is the same as Info [UMFPACK_NUMERIC_REALLOC], below. It may differ in future releases. Info [UMFPACK_NUMERIC_REALLOC]: The number of times that the Numeric object was increased in size from its initial size. A rough upper bound on the peak size of the Numeric object was computed by umfpack_*_*symbolic, so reallocations should be rare. However, if umfpack_*_numeric is unable to allocate that much storage, it reduces its request until either the allocation succeeds, or until it gets too small to do anything with. If the memory that it finally got was small, but usable, then the reallocation count could be high. No estimate of this count was computed by umfpack_*_*symbolic. Info [UMFPACK_NUMERIC_COSTLY_REALLOC]: The number of times that the system realloc library routine (or mxRealloc for the mexFunction) had to move the workspace. Realloc can sometimes increase the size of a block of memory without moving it, which is much faster. This statistic will always be <= Info [UMFPACK_NUMERIC_REALLOC]. If your memory space is fragmented, then the number of "costly" realloc's will be equal to Info [UMFPACK_NUMERIC_REALLOC]. Info [UMFPACK_COMPRESSED_PATTERN]: The number of integers used to represent the pattern of L and U. Info [UMFPACK_LU_ENTRIES]: The total number of numerical values that are stored for the LU factors. Some of the values may be explicitly zero in order to save space (allowing for a smaller compressed pattern). Info [UMFPACK_NUMERIC_TIME]: The CPU time taken, in seconds. Info [UMFPACK_RCOND]: A rough estimate of the condition number, equal to min (abs (diag (U))) / max (abs (diag (U))), or zero if the diagonal of U is all zero. Info [UMFPACK_UDIAG_NZ]: The number of numerically nonzero values on the diagonal of U. Info [UMFPACK_UMIN]: the smallest absolute value on the diagonal of U. Info [UMFPACK_UMAX]: the smallest absolute value on the diagonal of U. Info [UMFPACK_MAX_FRONT_SIZE]: the size of the largest frontal matrix (number of entries). Info [UMFPACK_NUMERIC_WALLTIME]: The wallclock time taken, in seconds. Info [UMFPACK_MAX_FRONT_NROWS]: the max number of rows in any frontal matrix. Info [UMFPACK_MAX_FRONT_NCOLS]: the max number of columns in any frontal matrix. Info [UMFPACK_WAS_SCALED]: the scaling used, either UMFPACK_SCALE_NONE, UMFPACK_SCALE_SUM, or UMFPACK_SCALE_MAX. Info [UMFPACK_RSMIN]: if scaling is performed, the smallest scale factor for any row (either the smallest sum of absolute entries, or the smallest maximum of absolute entries). Info [UMFPACK_RSMAX]: if scaling is performed, the largest scale factor for any row (either the largest sum of absolute entries, or the largest maximum of absolute entries). Info [UMFPACK_ALLOC_INIT_USED]: the initial allocation parameter used. Info [UMFPACK_FORCED_UPDATES]: the number of BLAS-3 updates to the frontal matrices that were required because the frontal matrix grew larger than its current working array. Info [UMFPACK_NOFF_DIAG]: number of off-diagonal pivots selected, if the symmetric or 2-by-2 strategies are used. Info [UMFPACK_NZDROPPED]: the number of entries smaller in absolute value than Control [UMFPACK_DROPTOL] that were dropped from L and U. Note that entries on the diagonal of U are never dropped. Info [UMFPACK_ALL_LNZ]: the number of entries in L, including the diagonal, if no small entries are dropped. Info [UMFPACK_ALL_UNZ]: the number of entries in U, including the diagonal, if no small entries are dropped. Only the above listed Info [...] entries are accessed. The remaining entries of Info are not accessed or modified by umfpack_*_numeric. Future versions might modify different parts of Info. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_scale.h0000644000175000017500000000613111674452555022744 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_scale ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_scale ( double X [ ], const double B [ ], void *Numeric ) ; UF_long umfpack_dl_scale ( double X [ ], const double B [ ], void *Numeric ) ; int umfpack_zi_scale ( double Xx [ ], double Xz [ ], const double Bx [ ], const double Bz [ ], void *Numeric ) ; UF_long umfpack_zl_scale ( double Xx [ ], double Xz [ ], const double Bx [ ], const double Bz [ ], void *Numeric ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; double *B, *X ; status = umfpack_di_scale (X, B, Numeric) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; double *B, *X ; status = umfpack_dl_scale (X, B, Numeric) ; complex int Syntax: #include "umfpack.h" void *Numeric ; double *Bx, *Bz, *Xx, *Xz ; status = umfpack_zi_scale (Xx, Xz, Bx, Bz, Numeric) ; complex UF_long Syntax: #include "umfpack.h" void *Numeric ; double *Bx, *Bz, *Xx, *Xz ; status = umfpack_zl_scale (Xx, Xz, Bx, Bz, Numeric) ; packed complex Syntax: Same as above, except both Xz and Bz are NULL. Purpose: Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or P(R\A)Q=LU), and a vector B, this routine computes X = B, X = R*B, or X = R\B, as appropriate. X and B must be vectors equal in length to the number of rows of A. Returns: The status code is returned. UMFPACK_OK is returned if successful. UMFPACK_ERROR_invalid_Numeric_object is returned in the Numeric object is invalid. UMFPACK_ERROR_argument_missing is returned if any of the input vectors are missing (X and B for the real version, and Xx and Bx for the complex version). Arguments: double X [n_row] ; Output argument. or: double Xx [n_row] ; Output argument, real part. Size 2*n_row for packed complex case. double Xz [n_row] ; Output argument, imaginary part. The output vector X. If either Xz or Bz are NULL, the vector X is in packed complex form, with the kth entry in Xx [2*k] and Xx [2*k+1], and likewise for B. double B [n_row] ; Input argument, not modified. or: double Bx [n_row] ; Input argument, not modified, real part. Size 2*n_row for packed complex case. double Bz [n_row] ; Input argument, not modified, imaginary part. The input vector B. See above if either Xz or Bz are NULL. void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_info.h0000644000175000017500000000511711674452555024206 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_info ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ void umfpack_di_report_info ( const double Control [UMFPACK_CONTROL], const double Info [UMFPACK_INFO] ) ; void umfpack_dl_report_info ( const double Control [UMFPACK_CONTROL], const double Info [UMFPACK_INFO] ) ; void umfpack_zi_report_info ( const double Control [UMFPACK_CONTROL], const double Info [UMFPACK_INFO] ) ; void umfpack_zl_report_info ( const double Control [UMFPACK_CONTROL], const double Info [UMFPACK_INFO] ) ; /* double int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; umfpack_di_report_info (Control, Info) ; double UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; umfpack_dl_report_info (Control, Info) ; complex int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; umfpack_zi_report_info (Control, Info) ; complex UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; umfpack_zl_report_info (Control, Info) ; Purpose: Reports statistics from the umfpack_*_*symbolic, umfpack_*_numeric, and umfpack_*_*solve routines. Arguments: double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 0 or less: no output, even when an error occurs 1: error messages only 2 or more: error messages, and print all of Info Default: 1 double Info [UMFPACK_INFO] ; Input argument, not modified. Info is an output argument of several UMFPACK routines. The contents of Info are printed on standard output. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_numeric.h0000644000175000017500000002147311674452555024164 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_get_numeric ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_get_numeric ( int Lp [ ], int Lj [ ], double Lx [ ], int Up [ ], int Ui [ ], double Ux [ ], int P [ ], int Q [ ], double Dx [ ], int *do_recip, double Rs [ ], void *Numeric ) ; UF_long umfpack_dl_get_numeric ( UF_long Lp [ ], UF_long Lj [ ], double Lx [ ], UF_long Up [ ], UF_long Ui [ ], double Ux [ ], UF_long P [ ], UF_long Q [ ], double Dx [ ], UF_long *do_recip, double Rs [ ], void *Numeric ) ; int umfpack_zi_get_numeric ( int Lp [ ], int Lj [ ], double Lx [ ], double Lz [ ], int Up [ ], int Ui [ ], double Ux [ ], double Uz [ ], int P [ ], int Q [ ], double Dx [ ], double Dz [ ], int *do_recip, double Rs [ ], void *Numeric ) ; UF_long umfpack_zl_get_numeric ( UF_long Lp [ ], UF_long Lj [ ], double Lx [ ], double Lz [ ], UF_long Up [ ], UF_long Ui [ ], double Ux [ ], double Uz [ ], UF_long P [ ], UF_long Q [ ], double Dx [ ], double Dz [ ], UF_long *do_recip, double Rs [ ], void *Numeric ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ; double *Lx, *Ux, *Dx, *Rs ; status = umfpack_di_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx, &do_recip, Rs, Numeric) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ; double *Lx, *Ux, *Dx, *Rs ; status = umfpack_dl_get_numeric (Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx, &do_recip, Rs, Numeric) ; complex int Syntax: #include "umfpack.h" void *Numeric ; int *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ; double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ; status = umfpack_zi_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q, Dx, Dz, &do_recip, Rs, Numeric) ; complex UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long *Lp, *Lj, *Up, *Ui, *P, *Q, status, do_recip ; double *Lx, *Lz, *Ux, *Uz, *Dx, *Dz, *Rs ; status = umfpack_zl_get_numeric (Lp, Lj, Lx, Lz, Up, Ui, Ux, Uz, P, Q, Dx, Dz, &do_recip, Rs, Numeric) ; packed complex int/UF_long Syntax: Same as above, except Lz, Uz, and Dz are all NULL. Purpose: This routine copies the LU factors and permutation vectors from the Numeric object into user-accessible arrays. This routine is not needed to solve a linear system. Note that the output arrays Lp, Lj, Lx, Up, Ui, Ux, P, Q, Dx, and Rs are not allocated by umfpack_*_get_numeric; they must exist on input. All output arguments are optional. If any of them are NULL on input, then that part of the LU factorization is not copied. You can use this routine to extract just the parts of the LU factorization that you want. For example, to retrieve just the column permutation Q, use: #define noD (double *) NULL #define noI (int *) NULL status = umfpack_di_get_numeric (noI, noI, noD, noI, noI, noD, noI, Q, noD, noI, noD, Numeric) ; Returns: Returns UMFPACK_OK if successful. Returns UMFPACK_ERROR_out_of_memory if insufficient memory is available for the 2*max(n_row,n_col) integer workspace that umfpack_*_get_numeric allocates to construct L and/or U. Returns UMFPACK_ERROR_invalid_Numeric_object if the Numeric object provided as input is invalid. Arguments: Int Lp [n_row+1] ; Output argument. Int Lj [lnz] ; Output argument. double Lx [lnz] ; Output argument. Size 2*lnz for packed complex case. double Lz [lnz] ; Output argument for complex versions. The n_row-by-min(n_row,n_col) matrix L is returned in compressed-row form. The column indices of row i and corresponding numerical values are in: Lj [Lp [i] ... Lp [i+1]-1] Lx [Lp [i] ... Lp [i+1]-1] real part Lz [Lp [i] ... Lp [i+1]-1] imaginary part (complex versions) respectively. Each row is stored in sorted order, from low column indices to higher. The last entry in each row is the diagonal, which is numerically equal to one. The sizes of Lp, Lj, Lx, and Lz are returned by umfpack_*_get_lunz. If Lp, Lj, or Lx are not present, then the matrix L is not returned. This is not an error condition. The L matrix can be printed if n_row, Lp, Lj, Lx (and Lz for the split complex case) are passed to umfpack_*_report_matrix (using the "row" form). If Lx is present and Lz is NULL, then both real and imaginary parts are returned in Lx[0..2*lnz-1], with Lx[2*k] and Lx[2*k+1] being the real and imaginary part of the kth entry. Int Up [n_col+1] ; Output argument. Int Ui [unz] ; Output argument. double Ux [unz] ; Output argument. Size 2*unz for packed complex case. double Uz [unz] ; Output argument for complex versions. The min(n_row,n_col)-by-n_col matrix U is returned in compressed-column form. The row indices of column j and corresponding numerical values are in Ui [Up [j] ... Up [j+1]-1] Ux [Up [j] ... Up [j+1]-1] real part Uz [Up [j] ... Up [j+1]-1] imaginary part (complex versions) respectively. Each column is stored in sorted order, from low row indices to higher. The last entry in each column is the diagonal (assuming that it is nonzero). The sizes of Up, Ui, Ux, and Uz are returned by umfpack_*_get_lunz. If Up, Ui, or Ux are not present, then the matrix U is not returned. This is not an error condition. The U matrix can be printed if n_col, Up, Ui, Ux (and Uz for the split complex case) are passed to umfpack_*_report_matrix (using the "column" form). If Ux is present and Uz is NULL, then both real and imaginary parts are returned in Ux[0..2*unz-1], with Ux[2*k] and Ux[2*k+1] being the real and imaginary part of the kth entry. Int P [n_row] ; Output argument. The permutation vector P is defined as P [k] = i, where the original row i of A is the kth pivot row in PAQ. If you do not want the P vector to be returned, simply pass (Int *) NULL for P. This is not an error condition. You can print P and Q with umfpack_*_report_perm. Int Q [n_col] ; Output argument. The permutation vector Q is defined as Q [k] = j, where the original column j of A is the kth pivot column in PAQ. If you not want the Q vector to be returned, simply pass (Int *) NULL for Q. This is not an error condition. Note that Q is not necessarily identical to Qtree, the column pre-ordering held in the Symbolic object. Refer to the description of Qtree and Front_npivcol in umfpack_*_get_symbolic for details. double Dx [min(n_row,n_col)] ; Output argument. Size 2*n for the packed complex case. double Dz [min(n_row,n_col)] ; Output argument for complex versions. The diagonal of U is also returned in Dx and Dz. You can extract the diagonal of U without getting all of U by passing a non-NULL Dx (and Dz for the complex version) and passing Up, Ui, and Ux as NULL. Dx is the real part of the diagonal, and Dz is the imaginary part. If Dx is present and Dz is NULL, then both real and imaginary parts are returned in Dx[0..2*min(n_row,n_col)-1], with Dx[2*k] and Dx[2*k+1] being the real and imaginary part of the kth entry. Int *do_recip ; Output argument. This argument defines how the scale factors Rs are to be interpretted. If do_recip is TRUE (one), then the scale factors Rs [i] are to be used by multiplying row i by Rs [i]. Otherwise, the entries in row i are to be divided by Rs [i]. If UMFPACK has been compiled with gcc, or for MATLAB as either a built-in routine or as a mexFunction, then the NRECIPROCAL flag is set, and do_recip will always be FALSE (zero). double Rs [n_row] ; Output argument. The row scale factors are returned in Rs [0..n_row-1]. Row i of A is scaled by dividing or multiplying its values by Rs [i]. If default scaling is in use, Rs [i] is the sum of the absolute values of row i (or its reciprocal). If max row scaling is in use, then Rs [i] is the maximum absolute value in row i (or its reciprocal). Otherwise, Rs [i] = 1. If row i is all zero, Rs [i] = 1 as well. For the complex version, an approximate absolute value is used (|x_real|+|x_imag|). void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_determinant.h0000644000175000017500000001417611674452555025036 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_get_determinant ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* UMFPACK_get_determinant contributed by David Bateman, Motorola, Paris. */ /* -------------------------------------------------------------------------- */ int umfpack_di_get_determinant ( double *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO] ) ; UF_long umfpack_dl_get_determinant ( double *Mx, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO] ) ; int umfpack_zi_get_determinant ( double *Mx, double *Mz, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO] ) ; UF_long umfpack_zl_get_determinant ( double *Mx, double *Mz, double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO] ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; int status ; double Mx, Ex, Info [UMFPACK_INFO] ; status = umfpack_di_get_determinant (&Mx, &Ex, Numeric, Info) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long status ; double Mx, Ex, Info [UMFPACK_INFO] ; status = umfpack_dl_get_determinant (&Mx, &Ex, Numeric, Info) ; complex int Syntax: #include "umfpack.h" void *Numeric ; int status ; double Mx, Mz, Ex, Info [UMFPACK_INFO] ; status = umfpack_zi_get_determinant (&Mx, &Mz, &Ex, Numeric, Info) ; complex int Syntax: #include "umfpack.h" void *Numeric ; UF_long status ; double *Mx, *Mz, *Ex, Info [UMFPACK_INFO] ; status = umfpack_zl_get_determinant (&Mx, &Mz, &Ex, Numeric, Info) ; packed complex int Syntax: Same as above, except Mz is NULL. Author: Contributed by David Bateman, Motorola, Paris Purpose: Using the LU factors and the permutation vectors contained in the Numeric object, calculate the determinant of the matrix A. The value of the determinant can be returned in two forms, depending on whether Ex is NULL or not. If Ex is NULL then the value of the determinant is returned on Mx and Mz for the real and imaginary parts. However, to avoid over- or underflows, the determinant can be split into a mantissa and exponent, and the parts returned separately, in which case Ex is not NULL. The actual determinant is then given by double det ; det = Mx * pow (10.0, Ex) ; for the double case, or double det [2] ; det [0] = Mx * pow (10.0, Ex) ; // real part det [1] = Mz * pow (10.0, Ex) ; // imaginary part for the complex case. Information on if the determinant will or has over or under-flowed is given by Info [UMFPACK_STATUS]. In the "packed complex" syntax, Mx [0] holds the real part and Mx [1] holds the imaginary part. Mz is not used (it is NULL). Returns: Returns UMFPACK_OK if sucessful. Returns UMFPACK_ERROR_out_of_memory if insufficient memory is available for the n_row integer workspace that umfpack_*_get_determinant allocates to construct pivots from the permutation vectors. Returns UMFPACK_ERROR_invalid_Numeric_object if the Numeric object provided as input is invalid. Returns UMFPACK_WARNING_singular_matrix if the determinant is zero. Returns UMFPACK_WARNING_determinant_underflow or UMFPACK_WARNING_determinant_overflow if the determinant has underflowed overflowed (for the case when Ex is NULL), or will overflow if Ex is not NULL and det is computed (see above) in the user program. Arguments: double *Mx ; Output argument (array of size 1, or size 2 if Mz is NULL) double *Mz ; Output argument (optional) double *Ex ; Output argument (optional) The determinant returned in mantissa/exponent form, as discussed above. If Mz is NULL, then both the original and imaginary parts will be returned in Mx. If Ex is NULL then the determinant is returned directly in Mx and Mz (or Mx [0] and Mx [1] if Mz is NULL), rather than in mantissa/exponent form. void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric. double Info [UMFPACK_INFO] ; Output argument. Contains information about the calculation of the determinant. If a (double *) NULL pointer is passed, then no statistics are returned in Info (this is not an error condition). The following statistics are computed in umfpack_*_determinant: Info [UMFPACK_STATUS]: status code. This is also the return value, whether or not Info is present. UMFPACK_OK The determinant was successfully found. UMFPACK_ERROR_out_of_memory Insufficient memory to solve the linear system. UMFPACK_ERROR_argument_missing Mx is missing (NULL). UMFPACK_ERROR_invalid_Numeric_object The Numeric object is not valid. UMFPACK_ERROR_invalid_system The matrix is rectangular. Only square systems can be handled. UMFPACK_WARNING_singluar_matrix The determinant is zero or NaN. The matrix is singular. UMFPACK_WARNING_determinant_underflow When passing from mantissa/exponent form to the determinant an underflow has or will occur. If the mantissa/exponent from of obtaining the determinant is used, the underflow will occur in the user program. If the single argument method of obtaining the determinant is used, the underflow has already occurred. UMFPACK_WARNING_determinant_overflow When passing from mantissa/exponent form to the determinant an overflow has or will occur. If the mantissa/exponent from of obtaining the determinant is used, the overflow will occur in the user program. If the single argument method of obtaining the determinant is used, the overflow has already occurred. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_global.h0000644000175000017500000000200511674452555023111 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_global ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* prototypes for global variables, and basic operators for complex values */ #ifndef EXTERN #define EXTERN extern #endif EXTERN double (*umfpack_hypot) (double, double) ; EXTERN int (*umfpack_divcomplex) (double, double, double, double, double *, double *) ; double umf_hypot (double x, double y) ; int umf_divcomplex (double, double, double, double, double *, double *) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_matrix.h0000644000175000017500000001552511674452555024563 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_matrix ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_matrix ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], int col_form, const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_dl_report_matrix ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], UF_long col_form, const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_matrix ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], const double Az [ ], int col_form, const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_zl_report_matrix ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const double Az [ ], UF_long col_form, const double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" int n_row, n_col, *Ap, *Ai, status ; double *Ax, Control [UMFPACK_CONTROL] ; status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ; or: status = umfpack_di_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ; double UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, *Ap, *Ai, status ; double *Ax, Control [UMFPACK_CONTROL] ; status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 1, Control) ; or: status = umfpack_dl_report_matrix (n_row, n_col, Ap, Ai, Ax, 0, Control) ; complex int Syntax: #include "umfpack.h" int n_row, n_col, *Ap, *Ai, status ; double *Ax, *Az, Control [UMFPACK_CONTROL] ; status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1, Control) ; or: status = umfpack_zi_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0, Control) ; complex UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, *Ap, *Ai, status ; double *Ax, Control [UMFPACK_CONTROL] ; status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 1, Control) ; or: status = umfpack_zl_report_matrix (n_row, n_col, Ap, Ai, Ax, Az, 0, Control) ; packed complex Syntax: Same as above, except Az is NULL. Purpose: Verifies and prints a row or column-oriented sparse matrix. Returns: UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked). Otherwise (where n is n_col for the column form and n_row for row and let ni be n_row for the column form and n_col for row): UMFPACK_OK if the matrix is valid. UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0. UMFPACK_ERROR_argument_missing if Ap and/or Ai are missing. UMFPACK_ERROR_invalid_matrix if Ap [n] < 0, if Ap [0] is not zero, if Ap [j+1] < Ap [j] for any j in the range 0 to n-1, if any row index in Ai is not in the range 0 to ni-1, or if the row indices in any column are not in ascending order, or contain duplicates. UMFPACK_ERROR_out_of_memory if out of memory. Arguments: Int n_row ; Input argument, not modified. Int n_col ; Input argument, not modified. A is an n_row-by-n_row matrix. Restriction: n_row > 0 and n_col > 0. Int Ap [n+1] ; Input argument, not modified. n is n_row for a row-form matrix, and n_col for a column-form matrix. Ap is an integer array of size n+1. If col_form is true (nonzero), then on input, it holds the "pointers" for the column form of the sparse matrix A. The row indices of column j of the matrix A are held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. Otherwise, Ap holds the row pointers, and the column indices of row j of the matrix are held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The first entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all j in the range 0 to n-1. The value nz = Ap [n] is thus the total number of entries in the pattern of the matrix A. Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n]. If col_form is true (nonzero), then the nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)]. Row indices must be in the range 0 to n_row-1 (the matrix is 0-based). Otherwise, the nonzero pattern (column indices) for row j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)]. Column indices must be in the range 0 to n_col-1 (the matrix is 0-based). double Ax [nz] ; Input argument, not modified, of size nz = Ap [n]. Size 2*nz for packed complex case. The numerical values of the sparse matrix A. If col_form is true (nonzero), then the nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding (real) numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. The imaginary parts are stored in Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions (see below if Az is NULL). Otherwise, the nonzero pattern (column indices) for row j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding (real) numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. The imaginary parts are stored in Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions (see below if Az is NULL). No numerical values are printed if Ax is NULL. double Az [nz] ; Input argument, not modified, for complex versions. The imaginary values of the sparse matrix A. See the description of Ax, above. If Az is NULL, then both real and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k] and Ax[2*k+1] being the real and imaginary part of the kth entry. Int col_form ; Input argument, not modified. The matrix is in row-oriented form if form is col_form is false (0). Otherwise, the matrix is in column-oriented form. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 2 or less: no output. returns silently without checking anything. 3: fully check input, and print a short summary of its status 4: as 3, but print first few entries of the input 5: as 3, but print all of the input Default: 1 */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_col_to_triplet.h0000644000175000017500000000720011674452555024675 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_col_to_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_col_to_triplet ( int n_col, const int Ap [ ], int Tj [ ] ) ; UF_long umfpack_dl_col_to_triplet ( UF_long n_col, const UF_long Ap [ ], UF_long Tj [ ] ) ; int umfpack_zi_col_to_triplet ( int n_col, const int Ap [ ], int Tj [ ] ) ; UF_long umfpack_zl_col_to_triplet ( UF_long n_col, const UF_long Ap [ ], UF_long Tj [ ] ) ; /* double int Syntax: #include "umfpack.h" int n_col, *Tj, *Ap, status ; status = umfpack_di_col_to_triplet (n_col, Ap, Tj) ; double UF_long Syntax: #include "umfpack.h" UF_long n_col, *Tj, *Ap, status ; status = umfpack_dl_col_to_triplet (n_col, Ap, Tj) ; complex int Syntax: #include "umfpack.h" int n_col, *Tj, *Ap, status ; status = umfpack_zi_col_to_triplet (n_col, Ap, Tj) ; complex UF_long Syntax: #include "umfpack.h" UF_long n_col, *Tj, *Ap, status ; status = umfpack_zl_col_to_triplet (n_col, Ap, Tj) ; Purpose: Converts a column-oriented matrix to a triplet form. Only the column pointers, Ap, are required, and only the column indices of the triplet form are constructed. This routine is the opposite of umfpack_*_triplet_to_col. The matrix may be singular and/or rectangular. Analogous to [i, Tj, x] = find (A) in MATLAB, except that zero entries present in the column-form of A are present in the output, and i and x are not created (those are just Ai and Ax+Az*1i, respectively, for a column-form matrix A). Returns: UMFPACK_OK if successful UMFPACK_ERROR_argument_missing if Ap or Tj is missing UMFPACK_ERROR_n_nonpositive if n_col <= 0 UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, Ap [0] != 0, or Ap [j] > Ap [j+1] for any j in the range 0 to n-1. Unsorted columns and duplicate entries do not cause an error (these would only be evident by examining Ai). Empty rows and columns are OK. Arguments: Int n_col ; Input argument, not modified. A is an n_row-by-n_col matrix. Restriction: n_col > 0. (n_row is not required) Int Ap [n_col+1] ; Input argument, not modified. The column pointers of the column-oriented form of the matrix. See umfpack_*_*symbolic for a description. The number of entries in the matrix is nz = Ap [n_col]. Restrictions on Ap are the same as those for umfpack_*_transpose. Ap [0] must be zero, nz must be >= 0, and Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for all j in the range 0 to n_col-1. Empty columns are OK (that is, Ap [j] may equal Ap [j+1] for any j in the range 0 to n_col-1). Int Tj [nz] ; Output argument. Tj is an integer array of size nz on input, where nz = Ap [n_col]. Suppose the column-form of the matrix is held in Ap, Ai, Ax, and Az (see umfpack_*_*symbolic for a description). Then on output, the triplet form of the same matrix is held in Ai (row indices), Tj (column indices), and Ax (numerical values). Note, however, that this routine does not require Ai and Ax (or Az for the complex version) in order to do the conversion. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_solve.h0000644000175000017500000002470511674452555023014 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_solve ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_solve ( int sys, const int Ap [ ], const int Ai [ ], const double Ax [ ], double X [ ], const double B [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_dl_solve ( UF_long sys, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], double X [ ], const double B [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; int umfpack_zi_solve ( int sys, const int Ap [ ], const int Ai [ ], const double Ax [ ], const double Az [ ], double Xx [ ], double Xz [ ], const double Bx [ ], const double Bz [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_zl_solve ( UF_long sys, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const double Az [ ], double Xx [ ], double Xz [ ], const double Bx [ ], const double Bz [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; int status, *Ap, *Ai, sys ; double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_di_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long status, *Ap, *Ai, sys ; double *B, *X, *Ax, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_dl_solve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info) ; complex int Syntax: #include "umfpack.h" void *Numeric ; int status, *Ap, *Ai, sys ; double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_zi_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info) ; complex UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long status, *Ap, *Ai, sys ; double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_zl_solve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info) ; packed complex Syntax: Same as above, Xz, Bz, and Az are NULL. Purpose: Given LU factors computed by umfpack_*_numeric (PAQ=LU, PRAQ=LU, or P(R\A)Q=LU) and the right-hand-side, B, solve a linear system for the solution X. Iterative refinement is optionally performed. Only square systems are handled. Singular matrices result in a divide-by-zero for all systems except those involving just the matrix L. Iterative refinement is not performed for singular matrices. In the discussion below, n is equal to n_row and n_col, because only square systems are handled. Returns: The status code is returned. See Info [UMFPACK_STATUS], below. Arguments: Int sys ; Input argument, not modified. Defines which system to solve. (') is the linear algebraic transpose (complex conjugate if A is complex), and (.') is the array transpose. sys value system solved UMFPACK_A Ax=b UMFPACK_At A'x=b UMFPACK_Aat A.'x=b UMFPACK_Pt_L P'Lx=b UMFPACK_L Lx=b UMFPACK_Lt_P L'Px=b UMFPACK_Lat_P L.'Px=b UMFPACK_Lt L'x=b UMFPACK_U_Qt UQ'x=b UMFPACK_U Ux=b UMFPACK_Q_Ut QU'x=b UMFPACK_Q_Uat QU.'x=b UMFPACK_Ut U'x=b UMFPACK_Uat U.'x=b Iterative refinement can be optionally performed when sys is any of the following: UMFPACK_A Ax=b UMFPACK_At A'x=b UMFPACK_Aat A.'x=b For the other values of the sys argument, iterative refinement is not performed (Control [UMFPACK_IRSTEP], Ap, Ai, Ax, and Az are ignored). Int Ap [n+1] ; Input argument, not modified. Int Ai [nz] ; Input argument, not modified. double Ax [nz] ; Input argument, not modified. Size 2*nz for packed complex case. double Az [nz] ; Input argument, not modified, for complex versions. If iterative refinement is requested (Control [UMFPACK_IRSTEP] >= 1, Ax=b, A'x=b, or A.'x=b is being solved, and A is nonsingular), then these arrays must be identical to the same ones passed to umfpack_*_numeric. The umfpack_*_solve routine does not check the contents of these arguments, so the results are undefined if Ap, Ai, Ax, and/or Az are modified between the calls the umfpack_*_numeric and umfpack_*_solve. These three arrays do not need to be present (NULL pointers can be passed) if Control [UMFPACK_IRSTEP] is zero, or if a system other than Ax=b, A'x=b, or A.'x=b is being solved, or if A is singular, since in each of these cases A is not accessed. If Az, Xz, or Bz are NULL, then both real and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k] and Ax[2*k+1] being the real and imaginary part of the kth entry. double X [n] ; Output argument. or: double Xx [n] ; Output argument, real part Size 2*n for packed complex case. double Xz [n] ; Output argument, imaginary part. The solution to the linear system, where n = n_row = n_col is the dimension of the matrices A, L, and U. If Az, Xz, or Bz are NULL, then both real and imaginary parts are returned in Xx[0..2*n-1], with Xx[2*k] and Xx[2*k+1] being the real and imaginary part of the kth entry. double B [n] ; Input argument, not modified. or: double Bx [n] ; Input argument, not modified, real part. Size 2*n for packed complex case. double Bz [n] ; Input argument, not modified, imaginary part. The right-hand side vector, b, stored as a conventional array of size n (or two arrays of size n for complex versions). This routine does not solve for multiple right-hand-sides, nor does it allow b to be stored in a sparse-column form. If Az, Xz, or Bz are NULL, then both real and imaginary parts are contained in Bx[0..2*n-1], with Bx[2*k] and Bx[2*k+1] being the real and imaginary part of the kth entry. void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_IRSTEP]: The maximum number of iterative refinement steps to attempt. A value less than zero is treated as zero. If less than 1, or if Ax=b, A'x=b, or A.'x=b is not being solved, or if A is singular, then the Ap, Ai, Ax, and Az arguments are not accessed. Default: 2. double Info [UMFPACK_INFO] ; Output argument. Contains statistics about the solution factorization. If a (double *) NULL pointer is passed, then no statistics are returned in Info (this is not an error condition). The following statistics are computed in umfpack_*_solve: Info [UMFPACK_STATUS]: status code. This is also the return value, whether or not Info is present. UMFPACK_OK The linear system was successfully solved. UMFPACK_WARNING_singular_matrix A divide-by-zero occurred. Your solution will contain Inf's and/or NaN's. Some parts of the solution may be valid. For example, solving Ax=b with A = [2 0] b = [ 1 ] returns x = [ 0.5 ] [0 0] [ 0 ] [ Inf ] UMFPACK_ERROR_out_of_memory Insufficient memory to solve the linear system. UMFPACK_ERROR_argument_missing One or more required arguments are missing. The B, X, (or Bx and Xx for the complex versions) arguments are always required. Info and Control are not required. Ap, Ai, Ax are required if Ax=b, A'x=b, A.'x=b is to be solved, the (default) iterative refinement is requested, and the matrix A is nonsingular. UMFPACK_ERROR_invalid_system The sys argument is not valid, or the matrix A is not square. UMFPACK_ERROR_invalid_Numeric_object The Numeric object is not valid. Info [UMFPACK_NROW], Info [UMFPACK_NCOL]: The dimensions of the matrix A (L is n_row-by-n_inner and U is n_inner-by-n_col, with n_inner = min(n_row,n_col)). Info [UMFPACK_NZ]: the number of entries in the input matrix, Ap [n], if iterative refinement is requested (Ax=b, A'x=b, or A.'x=b is being solved, Control [UMFPACK_IRSTEP] >= 1, and A is nonsingular). Info [UMFPACK_IR_TAKEN]: The number of iterative refinement steps effectively taken. The number of steps attempted may be one more than this; the refinement algorithm backtracks if the last refinement step worsens the solution. Info [UMFPACK_IR_ATTEMPTED]: The number of iterative refinement steps attempted. The number of times a linear system was solved is one more than this (once for the initial Ax=b, and once for each Ay=r solved for each iterative refinement step attempted). Info [UMFPACK_OMEGA1]: sparse backward error estimate, omega1, if iterative refinement was performed, or -1 if iterative refinement not performed. Info [UMFPACK_OMEGA2]: sparse backward error estimate, omega2, if iterative refinement was performed, or -1 if iterative refinement not performed. Info [UMFPACK_SOLVE_FLOPS]: the number of floating point operations performed to solve the linear system. This includes the work taken for all iterative refinement steps, including the backtrack (if any). Info [UMFPACK_SOLVE_TIME]: The time taken, in seconds. Info [UMFPACK_SOLVE_WALLTIME]: The wallclock time taken, in seconds. Only the above listed Info [...] entries are accessed. The remaining entries of Info are not accessed or modified by umfpack_*_solve. Future versions might modify different parts of Info. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_symbolic.h0000644000175000017500000003154211674452555024341 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_get_symbolic ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_get_symbolic ( int *n_row, int *n_col, int *n1, int *nz, int *nfr, int *nchains, int P [ ], int Q [ ], int Front_npivcol [ ], int Front_parent [ ], int Front_1strow [ ], int Front_leftmostdesc [ ], int Chain_start [ ], int Chain_maxrows [ ], int Chain_maxcols [ ], void *Symbolic ) ; UF_long umfpack_dl_get_symbolic ( UF_long *n_row, UF_long *n_col, UF_long *n1, UF_long *nz, UF_long *nfr, UF_long *nchains, UF_long P [ ], UF_long Q [ ], UF_long Front_npivcol [ ], UF_long Front_parent [ ], UF_long Front_1strow [ ], UF_long Front_leftmostdesc [ ], UF_long Chain_start [ ], UF_long Chain_maxrows [ ], UF_long Chain_maxcols [ ], void *Symbolic ) ; int umfpack_zi_get_symbolic ( int *n_row, int *n_col, int *n1, int *nz, int *nfr, int *nchains, int P [ ], int Q [ ], int Front_npivcol [ ], int Front_parent [ ], int Front_1strow [ ], int Front_leftmostdesc [ ], int Chain_start [ ], int Chain_maxrows [ ], int Chain_maxcols [ ], void *Symbolic ) ; UF_long umfpack_zl_get_symbolic ( UF_long *n_row, UF_long *n_col, UF_long *n1, UF_long *nz, UF_long *nfr, UF_long *nchains, UF_long P [ ], UF_long Q [ ], UF_long Front_npivcol [ ], UF_long Front_parent [ ], UF_long Front_1strow [ ], UF_long Front_leftmostdesc [ ], UF_long Chain_start [ ], UF_long Chain_maxrows [ ], UF_long Chain_maxcols [ ], void *Symbolic ) ; /* double int Syntax: #include "umfpack.h" int status, n_row, n_col, nz, nfr, nchains, *P, *Q, *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc, *Chain_start, *Chain_maxrows, *Chain_maxcols ; void *Symbolic ; status = umfpack_di_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains, P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ; double UF_long Syntax: #include "umfpack.h" UF_long status, n_row, n_col, nz, nfr, nchains, *P, *Q, *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc, *Chain_start, *Chain_maxrows, *Chain_maxcols ; void *Symbolic ; status = umfpack_dl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains, P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ; complex int Syntax: #include "umfpack.h" int status, n_row, n_col, nz, nfr, nchains, *P, *Q, *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc, *Chain_start, *Chain_maxrows, *Chain_maxcols ; void *Symbolic ; status = umfpack_zi_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains, P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ; complex UF_long Syntax: #include "umfpack.h" UF_long status, n_row, n_col, nz, nfr, nchains, *P, *Q, *Front_npivcol, *Front_parent, *Front_1strow, *Front_leftmostdesc, *Chain_start, *Chain_maxrows, *Chain_maxcols ; void *Symbolic ; status = umfpack_zl_get_symbolic (&n_row, &n_col, &nz, &nfr, &nchains, P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc, Chain_start, Chain_maxrows, Chain_maxcols, Symbolic) ; Purpose: Copies the contents of the Symbolic object into simple integer arrays accessible to the user. This routine is not needed to factorize and/or solve a sparse linear system using UMFPACK. Note that the output arrays P, Q, Front_npivcol, Front_parent, Front_1strow, Front_leftmostdesc, Chain_start, Chain_maxrows, and Chain_maxcols are not allocated by umfpack_*_get_symbolic; they must exist on input. All output arguments are optional. If any of them are NULL on input, then that part of the symbolic analysis is not copied. You can use this routine to extract just the parts of the symbolic analysis that you want. For example, to retrieve just the column permutation Q, use: #define noI (int *) NULL status = umfpack_di_get_symbolic (noI, noI, noI, noI, noI, noI, noI, Q, noI, noI, noI, noI, noI, noI, noI, Symbolic) ; The only required argument the last one, the pointer to the Symbolic object. The Symbolic object is small. Its size for an n-by-n square matrix varies from 4*n to 13*n, depending on the matrix. The object holds the initial column permutation, the supernodal column elimination tree, and information about each frontal matrix. You can print it with umfpack_*_report_symbolic. Returns: Returns UMFPACK_OK if successful, UMFPACK_ERROR_invalid_Symbolic_object if Symbolic is an invalid object. Arguments: Int *n_row ; Output argument. Int *n_col ; Output argument. The dimensions of the matrix A analyzed by the call to umfpack_*_symbolic that generated the Symbolic object. Int *n1 ; Output argument. The number of pivots with zero Markowitz cost (they have just one entry in the pivot row, or the pivot column, or both). These appear first in the output permutations P and Q. Int *nz ; Output argument. The number of nonzeros in A. Int *nfr ; Output argument. The number of frontal matrices that will be used by umfpack_*_numeric to factorize the matrix A. It is in the range 0 to n_col. Int *nchains ; Output argument. The frontal matrices are related to one another by the supernodal column elimination tree. Each node in this tree is one frontal matrix. The tree is partitioned into a set of disjoint paths, and a frontal matrix chain is one path in this tree. Each chain is factorized using a unifrontal technique, with a single working array that holds each frontal matrix in the chain, one at a time. nchains is in the range 0 to nfr. Int P [n_row] ; Output argument. The initial row permutation. If P [k] = i, then this means that row i is the kth row in the pre-ordered matrix. In general, this P is not the same as the final row permutation computed by umfpack_*_numeric. For the unsymmetric strategy, P defines the row-merge order. Let j be the column index of the leftmost nonzero entry in row i of A*Q. Then P defines a sort of the rows according to this value. A row can appear earlier in this ordering if it is aggressively absorbed before it can become a pivot row. If P [k] = i, row i typically will not be the kth pivot row. For the symmetric strategy, P = Q. For the 2-by-2 strategy, P is the row permutation that places large entries on the diagonal of P*A*Q. If no pivoting occurs during numerical factorization, P [k] = i also defines the final permutation of umfpack_*_numeric, for either the symmetric or 2-by-2 strategies. Int Q [n_col] ; Output argument. The initial column permutation. If Q [k] = j, then this means that column j is the kth pivot column in the pre-ordered matrix. Q is not necessarily the same as the final column permutation Q, computed by umfpack_*_numeric. The numeric factorization may reorder the pivot columns within each frontal matrix to reduce fill-in. If the matrix is structurally singular, and if the symmetric or 2-by-2 strategies or used (or if Control [UMFPACK_FIXQ] > 0), then this Q will be the same as the final column permutation computed in umfpack_*_numeric. Int Front_npivcol [n_col+1] ; Output argument. This array should be of size at least n_col+1, in order to guarantee that it will be large enough to hold the output. Only the first nfr+1 entries are used, however. The kth frontal matrix holds Front_npivcol [k] pivot columns. Thus, the first frontal matrix, front 0, is used to factorize the first Front_npivcol [0] columns; these correspond to the original columns Q [0] through Q [Front_npivcol [0]-1]. The next frontal matrix is used to factorize the next Front_npivcol [1] columns, which are thus the original columns Q [Front_npivcol [0]] through Q [Front_npivcol [0] + Front_npivcol [1] - 1], and so on. Columns with no entries at all are put in a placeholder "front", Front_npivcol [nfr]. The sum of Front_npivcol [0..nfr] is equal to n_col. Any modifications that umfpack_*_numeric makes to the initial column permutation are constrained to within each frontal matrix. Thus, for the first frontal matrix, Q [0] through Q [Front_npivcol [0]-1] is some permutation of the columns Q [0] through Q [Front_npivcol [0]-1]. For second frontal matrix, Q [Front_npivcol [0]] through Q [Front_npivcol [0] + Front_npivcol[1]-1] is some permutation of the same portion of Q, and so on. All pivot columns are numerically factorized within the frontal matrix originally determined by the symbolic factorization; there is no delayed pivoting across frontal matrices. Int Front_parent [n_col+1] ; Output argument. This array should be of size at least n_col+1, in order to guarantee that it will be large enough to hold the output. Only the first nfr+1 entries are used, however. Front_parent [0..nfr] holds the supernodal column elimination tree (including the placeholder front nfr, which may be empty). Each node in the tree corresponds to a single frontal matrix. The parent of node f is Front_parent [f]. Int Front_1strow [n_col+1] ; Output argument. This array should be of size at least n_col+1, in order to guarantee that it will be large enough to hold the output. Only the first nfr+1 entries are used, however. Front_1strow [k] is the row index of the first row in A (P,Q) whose leftmost entry is in a pivot column for the kth front. This is necessary only to properly factorize singular matrices. Rows in the range Front_1strow [k] to Front_1strow [k+1]-1 first become pivot row candidates at the kth front. Any rows not eliminated in the kth front may be selected as pivot rows in the parent of k (Front_parent [k]) and so on up the tree. Int Front_leftmostdesc [n_col+1] ; Output argument. This array should be of size at least n_col+1, in order to guarantee that it will be large enough to hold the output. Only the first nfr+1 entries are used, however. Front_leftmostdesc [k] is the leftmost descendant of front k, or k if the front has no children in the tree. Since the rows and columns (P and Q) have been post-ordered via a depth-first-search of the tree, rows in the range Front_1strow [Front_leftmostdesc [k]] to Front_1strow [k+1]-1 form the entire set of candidate pivot rows for the kth front (some of these will typically have already been selected by fronts in the range Front_leftmostdesc [k] to front k-1, before the factorization reaches front k). Chain_start [n_col+1] ; Output argument. This array should be of size at least n_col+1, in order to guarantee that it will be large enough to hold the output. Only the first nchains+1 entries are used, however. The kth frontal matrix chain consists of frontal matrices Chain_start[k] through Chain_start [k+1]-1. Thus, Chain_start [0] is always 0, and Chain_start [nchains] is the total number of frontal matrices, nfr. For two adjacent fronts f and f+1 within a single chain, f+1 is always the parent of f (that is, Front_parent [f] = f+1). Int Chain_maxrows [n_col+1] ; Output argument. Int Chain_maxcols [n_col+1] ; Output argument. These arrays should be of size at least n_col+1, in order to guarantee that they will be large enough to hold the output. Only the first nchains entries are used, however. The kth frontal matrix chain requires a single working array of dimension Chain_maxrows [k] by Chain_maxcols [k], for the unifrontal technique that factorizes the frontal matrix chain. Since the symbolic factorization only provides an upper bound on the size of each frontal matrix, not all of the working array is necessarily used during the numerical factorization. Note that the upper bound on the number of rows and columns of each frontal matrix is computed by umfpack_*_symbolic, but all that is required by umfpack_*_numeric is the maximum of these two sets of values for each frontal matrix chain. Thus, the size of each individual frontal matrix is not preserved in the Symbolic object. void *Symbolic ; Input argument, not modified. The Symbolic object, which holds the symbolic factorization computed by umfpack_*_symbolic. The Symbolic object is not modified by umfpack_*_get_symbolic. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_numeric.h0000644000175000017500000000503111674452555024314 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_load_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_load_numeric ( void **Numeric, char *filename ) ; UF_long umfpack_dl_load_numeric ( void **Numeric, char *filename ) ; int umfpack_zi_load_numeric ( void **Numeric, char *filename ) ; UF_long umfpack_zl_load_numeric ( void **Numeric, char *filename ) ; /* double int Syntax: #include "umfpack.h" int status ; char *filename ; void *Numeric ; status = umfpack_di_load_numeric (&Numeric, filename) ; double UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Numeric ; status = umfpack_dl_load_numeric (&Numeric, filename) ; complex int Syntax: #include "umfpack.h" int status ; char *filename ; void *Numeric ; status = umfpack_zi_load_numeric (&Numeric, filename) ; complex UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Numeric ; status = umfpack_zl_load_numeric (&Numeric, filename) ; Purpose: Loads a Numeric object from a file created by umfpack_*_save_numeric. The Numeric handle passed to this routine is overwritten with the new object. If that object exists prior to calling this routine, a memory leak will occur. The contents of Numeric are ignored on input. Returns: UMFPACK_OK if successful. UMFPACK_ERROR_out_of_memory if not enough memory is available. UMFPACK_ERROR_file_IO if an I/O error occurred. Arguments: void **Numeric ; Output argument. **Numeric is the address of a (void *) pointer variable in the user's calling routine (see Syntax, above). On input, the contents of this variable are not defined. On output, this variable holds a (void *) pointer to the Numeric object (if successful), or (void *) NULL if a failure occurred. char *filename ; Input argument, not modified. A string that contains the filename from which to read the Numeric object. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_triplet.h0000644000175000017500000001143511674452555024736 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_triplet ( int n_row, int n_col, int nz, const int Ti [ ], const int Tj [ ], const double Tx [ ], const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_dl_report_triplet ( UF_long n_row, UF_long n_col, UF_long nz, const UF_long Ti [ ], const UF_long Tj [ ], const double Tx [ ], const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_triplet ( int n_row, int n_col, int nz, const int Ti [ ], const int Tj [ ], const double Tx [ ], const double Tz [ ], const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_zl_report_triplet ( UF_long n_row, UF_long n_col, UF_long nz, const UF_long Ti [ ], const UF_long Tj [ ], const double Tx [ ], const double Tz [ ], const double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" int n_row, n_col, nz, *Ti, *Tj, status ; double *Tx, Control [UMFPACK_CONTROL] ; status = umfpack_di_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ; double UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, nz, *Ti, *Tj, status ; double *Tx, Control [UMFPACK_CONTROL] ; status = umfpack_dl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Control) ; complex int Syntax: #include "umfpack.h" int n_row, n_col, nz, *Ti, *Tj, status ; double *Tx, *Tz, Control [UMFPACK_CONTROL] ; status = umfpack_zi_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz, Control) ; complex UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, nz, *Ti, *Tj, status ; double *Tx, *Tz, Control [UMFPACK_CONTROL] ; status = umfpack_zl_report_triplet (n_row, n_col, nz, Ti, Tj, Tx, Tz, Control) ; packed complex Syntax: Same as above, except Tz is NULL. Purpose: Verifies and prints a matrix in triplet form. Returns: UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked). Otherwise: UMFPACK_OK if the Triplet matrix is OK. UMFPACK_ERROR_argument_missing if Ti and/or Tj are missing. UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0. UMFPACK_ERROR_invalid_matrix if nz < 0, or if any row or column index in Ti and/or Tj is not in the range 0 to n_row-1 or 0 to n_col-1, respectively. Arguments: Int n_row ; Input argument, not modified. Int n_col ; Input argument, not modified. A is an n_row-by-n_col matrix. Int nz ; Input argument, not modified. The number of entries in the triplet form of the matrix. Int Ti [nz] ; Input argument, not modified. Int Tj [nz] ; Input argument, not modified. double Tx [nz] ; Input argument, not modified. Size 2*nz for packed complex case. double Tz [nz] ; Input argument, not modified, for complex versions. Ti, Tj, Tx (and Tz for complex versions) hold the "triplet" form of a sparse matrix. The kth nonzero entry is in row i = Ti [k], column j = Tj [k], the real numerical value of a_ij is Tx [k], and the imaginary part of a_ij is Tz [k] (for complex versions). The row and column indices i and j must be in the range 0 to n_row-1 or 0 to n_col-1, respectively. Duplicate entries may be present. The "triplets" may be in any order. Tx and Tz are optional; if Tx is not present ((double *) NULL), then the numerical values are not printed. If Tx is present and Tz is NULL, then both real and imaginary parts are contained in Tx[0..2*nz-1], with Tx[2*k] and Tx[2*k+1] being the real and imaginary part of the kth entry. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 2 or less: no output. returns silently without checking anything. 3: fully check input, and print a short summary of its status 4: as 3, but print first few entries of the input 5: as 3, but print all of the input Default: 1 */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_tictoc.h0000644000175000017500000000426111674452555023144 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_tictoc ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ void umfpack_tic (double stats [2]) ; void umfpack_toc (double stats [2]) ; /* Syntax (for all versions: di, dl, zi, and zl): #include "umfpack.h" double stats [2] ; umfpack_tic (stats) ; ... umfpack_toc (stats) ; Purpose: umfpack_tic returns the CPU time and wall clock time used by the process. The CPU time includes both "user" and "system" time (the latter is time spent by the system on behalf of the process, and is thus charged to the process). umfpack_toc returns the CPU time and wall clock time since the last call to umfpack_tic with the same stats array. Typical usage: umfpack_tic (stats) ; ... do some work ... umfpack_toc (stats) ; then stats [1] contains the time in seconds used by the code between umfpack_tic and umfpack_toc, and stats [0] contains the wall clock time elapsed between the umfpack_tic and umfpack_toc. These two routines act just like tic and toc in MATLAB, except that the both process time and wall clock time are returned. This routine normally uses the sysconf and times routines in the POSIX standard. If -DNPOSIX is defined at compile time, then the ANSI C clock routine is used instead, and only the CPU time is returned (stats [0] is set to zero). umfpack_tic and umfpack_toc are the routines used internally in UMFPACK to time the symbolic analysis, numerical factorization, and the forward/ backward solve. Arguments: double stats [2]: stats [0]: wall clock time, in seconds stats [1]: CPU time, in seconds */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_numeric.h0000644000175000017500000000323211674452555024317 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_free_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ void umfpack_di_free_numeric ( void **Numeric ) ; void umfpack_dl_free_numeric ( void **Numeric ) ; void umfpack_zi_free_numeric ( void **Numeric ) ; void umfpack_zl_free_numeric ( void **Numeric ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; umfpack_di_free_numeric (&Numeric) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; umfpack_dl_free_numeric (&Numeric) ; complex int Syntax: #include "umfpack.h" void *Numeric ; umfpack_zi_free_numeric (&Numeric) ; complex UF_long Syntax: #include "umfpack.h" void *Numeric ; umfpack_zl_free_numeric (&Numeric) ; Purpose: Deallocates the Numeric object and sets the Numeric handle to NULL. This routine is the only valid way of destroying the Numeric object. Arguments: void **Numeric ; Input argument, set to (void *) NULL on output. Numeric points to a valid Numeric object, computed by umfpack_*_numeric. No action is taken if Numeric is a (void *) NULL pointer. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_numeric.h0000644000175000017500000000430311674452555024334 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_save_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_save_numeric ( void *Numeric, char *filename ) ; UF_long umfpack_dl_save_numeric ( void *Numeric, char *filename ) ; int umfpack_zi_save_numeric ( void *Numeric, char *filename ) ; UF_long umfpack_zl_save_numeric ( void *Numeric, char *filename ) ; /* double int Syntax: #include "umfpack.h" int status ; char *filename ; void *Numeric ; status = umfpack_di_save_numeric (Numeric, filename) ; double UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Numeric ; status = umfpack_dl_save_numeric (Numeric, filename) ; complex int Syntax: #include "umfpack.h" int status ; char *filename ; void *Numeric ; status = umfpack_zi_save_numeric (Numeric, filename) ; complex UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Numeric ; status = umfpack_zl_save_numeric (Numeric, filename) ; Purpose: Saves a Numeric object to a file, which can later be read by umfpack_*_load_numeric. The Numeric object is not modified. Returns: UMFPACK_OK if successful. UMFPACK_ERROR_invalid_Numeric_object if Numeric is not valid. UMFPACK_ERROR_file_IO if an I/O error occurred. Arguments: void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric or loaded by umfpack_*_load_numeric. char *filename ; Input argument, not modified. A string that contains the filename to which the Numeric object is written. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_save_symbolic.h0000644000175000017500000000434211674452555024516 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_save_symbolic================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_save_symbolic ( void *Symbolic, char *filename ) ; UF_long umfpack_dl_save_symbolic ( void *Symbolic, char *filename ) ; int umfpack_zi_save_symbolic ( void *Symbolic, char *filename ) ; UF_long umfpack_zl_save_symbolic ( void *Symbolic, char *filename ) ; /* double int Syntax: #include "umfpack.h" int status ; char *filename ; void *Symbolic ; status = umfpack_di_save_symbolic (Symbolic, filename) ; double UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Symbolic ; status = umfpack_dl_save_symbolic (Symbolic, filename) ; complex int Syntax: #include "umfpack.h" int status ; char *filename ; void *Symbolic ; status = umfpack_zi_save_symbolic (Symbolic, filename) ; complex UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Symbolic ; status = umfpack_zl_save_symbolic (Symbolic, filename) ; Purpose: Saves a Symbolic object to a file, which can later be read by umfpack_*_load_symbolic. The Symbolic object is not modified. Returns: UMFPACK_OK if successful. UMFPACK_ERROR_invalid_Symbolic_object if Symbolic is not valid. UMFPACK_ERROR_file_IO if an I/O error occurred. Arguments: void *Symbolic ; Input argument, not modified. Symbolic must point to a valid Symbolic object, computed by umfpack_*_symbolic or loaded by umfpack_*_load_symbolic. char *filename ; Input argument, not modified. A string that contains the filename to which the Symbolic object is written. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack.h0000644000175000017500000004602111674452555021577 0ustar sonnesonne/* ========================================================================== */ /* === umfpack.h ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* This is the umfpack.h include file, and should be included in all user code that uses UMFPACK. Do not include any of the umf_* header files in user code. All routines in UMFPACK starting with "umfpack_" are user-callable. All other routines are prefixed "umf_XY_", (where X is d or z, and Y is i or l) and are not user-callable. */ #ifndef UMFPACK_H #define UMFPACK_H /* -------------------------------------------------------------------------- */ /* Make it easy for C++ programs to include UMFPACK */ /* -------------------------------------------------------------------------- */ #ifdef __cplusplus extern "C" { #endif /* define UF_long */ #include "UFconfig.h" /* -------------------------------------------------------------------------- */ /* size of Info and Control arrays */ /* -------------------------------------------------------------------------- */ /* These might be larger in future versions, since there are only 3 unused * entries in Info, and no unused entries in Control. */ #define UMFPACK_INFO 90 #define UMFPACK_CONTROL 20 /* -------------------------------------------------------------------------- */ /* User-callable routines */ /* -------------------------------------------------------------------------- */ /* Primary routines: */ #include "umfpack_symbolic.h" #include "umfpack_numeric.h" #include "umfpack_solve.h" #include "umfpack_free_symbolic.h" #include "umfpack_free_numeric.h" /* Alternative routines: */ #include "umfpack_defaults.h" #include "umfpack_qsymbolic.h" #include "umfpack_wsolve.h" /* Matrix manipulation routines: */ #include "umfpack_triplet_to_col.h" #include "umfpack_col_to_triplet.h" #include "umfpack_transpose.h" #include "umfpack_scale.h" /* Getting the contents of the Symbolic and Numeric opaque objects: */ #include "umfpack_get_lunz.h" #include "umfpack_get_numeric.h" #include "umfpack_get_symbolic.h" #include "umfpack_save_numeric.h" #include "umfpack_load_numeric.h" #include "umfpack_save_symbolic.h" #include "umfpack_load_symbolic.h" #include "umfpack_get_determinant.h" /* Reporting routines (the above 14 routines print nothing): */ #include "umfpack_report_status.h" #include "umfpack_report_info.h" #include "umfpack_report_control.h" #include "umfpack_report_matrix.h" #include "umfpack_report_triplet.h" #include "umfpack_report_vector.h" #include "umfpack_report_symbolic.h" #include "umfpack_report_numeric.h" #include "umfpack_report_perm.h" /* Utility routines: */ #include "umfpack_timer.h" #include "umfpack_tictoc.h" /* AMD */ #include "amd.h" /* global function pointers */ #include "umfpack_global.h" /* -------------------------------------------------------------------------- */ /* Version, copyright, and license */ /* -------------------------------------------------------------------------- */ #define UMFPACK_VERSION "UMFPACK V5.4.0 (May 20, 2009)" #define UMFPACK_COPYRIGHT \ "UMFPACK: Copyright (c) 2005-2009 by Timothy A. Davis. All Rights Reserved.\n" #define UMFPACK_LICENSE_PART1 \ "\nUMFPACK License:\n" \ "\n" \ " UMFPACK is available under alternate licenses,\n" \ " contact T. Davis for details.\n" \ "\n" \ " Your use or distribution of UMFPACK or any modified version of\n" \ " UMFPACK implies that you agree to this License.\n" \ "\n" \ " This library is free software; you can redistribute it and/or\n" \ " modify it under the terms of the GNU General Public\n" \ " License as published by the Free Software Foundation; either\n" \ " version 2 of the License, or (at your option) any later version.\n" \ "\n" \ " This library is distributed in the hope that it will be useful,\n" \ " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \ " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" \ " General Public License for more details.\n" \ "\n" \ " You should have received a copy of the GNU General Public\n" \ " License along with this library; if not, write to the Free Software\n" \ " Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301\n" \ " USA\n" \ #define UMFPACK_LICENSE_PART2 \ "\n" \ " Permission is hereby granted to use or copy this program under the\n" \ " terms of the GNU GPL, provided that the Copyright, this License,\n" \ " and the Availability of the original version is retained on all copies.\n" \ " User documentation of any code that uses this code or any modified\n" \ " version of this code must cite the Copyright, this License, the\n" \ " Availability note, and \"Used by permission.\" Permission to modify\n" \ " the code and to distribute modified code is granted, provided the\n" \ " Copyright, this License, and the Availability note are retained,\n" \ " and a notice that the code was modified is included.\n" #define UMFPACK_LICENSE_PART3 \ "\n" \ "Availability: http://www.cise.ufl.edu/research/sparse/umfpack\n" \ "\n" /* UMFPACK Version 4.5 and later will include the following definitions. * As an example, to test if the version you are using is 4.5 or later: * * #ifdef UMFPACK_VER * if (UMFPACK_VER >= UMFPACK_VER_CODE (4,5)) ... * #endif * * This also works during compile-time: * * #if defined(UMFPACK_VER) && (UMFPACK >= UMFPACK_VER_CODE (4,5)) * printf ("This is version 4.5 or later\n") ; * #else * printf ("This is an early version\n") ; * #endif * * Versions 4.4 and earlier of UMFPACK do not include a #define'd version * number, although they do include the UMFPACK_VERSION string, defined * above. */ #define UMFPACK_DATE "May 20, 2009" #define UMFPACK_VER_CODE(main,sub) ((main) * 1000 + (sub)) #define UMFPACK_MAIN_VERSION 5 #define UMFPACK_SUB_VERSION 4 #define UMFPACK_SUBSUB_VERSION 0 #define UMFPACK_VER UMFPACK_VER_CODE(UMFPACK_MAIN_VERSION,UMFPACK_SUB_VERSION) /* -------------------------------------------------------------------------- */ /* contents of Info */ /* -------------------------------------------------------------------------- */ /* Note that umfpack_report.m must coincide with these definitions. S is * the submatrix of A after removing row/col singletons and empty rows/cols. */ /* returned by all routines that use Info: */ #define UMFPACK_STATUS 0 /* UMFPACK_OK, or other result */ #define UMFPACK_NROW 1 /* n_row input value */ #define UMFPACK_NCOL 16 /* n_col input value */ #define UMFPACK_NZ 2 /* # of entries in A */ /* computed in UMFPACK_*symbolic and UMFPACK_numeric: */ #define UMFPACK_SIZE_OF_UNIT 3 /* sizeof (Unit) */ /* computed in UMFPACK_*symbolic: */ #define UMFPACK_SIZE_OF_INT 4 /* sizeof (int) */ #define UMFPACK_SIZE_OF_LONG 5 /* sizeof (UF_long) */ #define UMFPACK_SIZE_OF_POINTER 6 /* sizeof (void *) */ #define UMFPACK_SIZE_OF_ENTRY 7 /* sizeof (Entry), real or complex */ #define UMFPACK_NDENSE_ROW 8 /* number of dense rows */ #define UMFPACK_NEMPTY_ROW 9 /* number of empty rows */ #define UMFPACK_NDENSE_COL 10 /* number of dense rows */ #define UMFPACK_NEMPTY_COL 11 /* number of empty rows */ #define UMFPACK_SYMBOLIC_DEFRAG 12 /* # of memory compactions */ #define UMFPACK_SYMBOLIC_PEAK_MEMORY 13 /* memory used by symbolic analysis */ #define UMFPACK_SYMBOLIC_SIZE 14 /* size of Symbolic object, in Units */ #define UMFPACK_SYMBOLIC_TIME 15 /* time (sec.) for symbolic analysis */ #define UMFPACK_SYMBOLIC_WALLTIME 17 /* wall clock time for sym. analysis */ #define UMFPACK_STRATEGY_USED 18 /* strategy used: sym, unsym, 2by2 */ #define UMFPACK_ORDERING_USED 19 /* ordering used: colamd, amd, given */ #define UMFPACK_QFIXED 31 /* whether Q is fixed or refined */ #define UMFPACK_DIAG_PREFERRED 32 /* whether diagonal pivoting attempted*/ #define UMFPACK_PATTERN_SYMMETRY 33 /* symmetry of pattern of S */ #define UMFPACK_NZ_A_PLUS_AT 34 /* nnz (S+S'), excl. diagonal */ #define UMFPACK_NZDIAG 35 /* nnz (diag (S)) */ /* AMD statistics, computed in UMFPACK_*symbolic: */ #define UMFPACK_SYMMETRIC_LUNZ 36 /* nz in L+U, if AMD ordering used */ #define UMFPACK_SYMMETRIC_FLOPS 37 /* flops for LU, if AMD ordering used */ #define UMFPACK_SYMMETRIC_NDENSE 38 /* # of "dense" rows/cols in S+S' */ #define UMFPACK_SYMMETRIC_DMAX 39 /* max nz in cols of L, for AMD */ /* statistics for 2-by-2 strategy */ #define UMFPACK_2BY2_NWEAK 51 /* number of weak diagonal entries*/ #define UMFPACK_2BY2_UNMATCHED 52 /* # of weak diagonals not matched*/ #define UMFPACK_2BY2_PATTERN_SYMMETRY 53 /* symmetry of pattern of P*S */ #define UMFPACK_2BY2_NZ_PA_PLUS_PAT 54 /* nz in PS+(PS)' */ #define UMFPACK_2BY2_NZDIAG 55 /* nz on diagonal of PS+(PS)' */ /* statistcs for singleton pruning */ #define UMFPACK_COL_SINGLETONS 56 /* # of column singletons */ #define UMFPACK_ROW_SINGLETONS 57 /* # of row singletons */ #define UMFPACK_N2 58 /* size of S */ #define UMFPACK_S_SYMMETRIC 59 /* 1 if S square and symmetricly perm.*/ /* estimates computed in UMFPACK_*symbolic: */ #define UMFPACK_NUMERIC_SIZE_ESTIMATE 20 /* final size of Numeric->Memory */ #define UMFPACK_PEAK_MEMORY_ESTIMATE 21 /* for symbolic & numeric */ #define UMFPACK_FLOPS_ESTIMATE 22 /* flop count */ #define UMFPACK_LNZ_ESTIMATE 23 /* nz in L, incl. diagonal */ #define UMFPACK_UNZ_ESTIMATE 24 /* nz in U, incl. diagonal */ #define UMFPACK_VARIABLE_INIT_ESTIMATE 25 /* initial size of Numeric->Memory*/ #define UMFPACK_VARIABLE_PEAK_ESTIMATE 26 /* peak size of Numeric->Memory */ #define UMFPACK_VARIABLE_FINAL_ESTIMATE 27 /* final size of Numeric->Memory */ #define UMFPACK_MAX_FRONT_SIZE_ESTIMATE 28 /* max frontal matrix size */ #define UMFPACK_MAX_FRONT_NROWS_ESTIMATE 29 /* max # rows in any front */ #define UMFPACK_MAX_FRONT_NCOLS_ESTIMATE 30 /* max # columns in any front */ /* exact values, (estimates shown above) computed in UMFPACK_numeric: */ #define UMFPACK_NUMERIC_SIZE 40 /* final size of Numeric->Memory */ #define UMFPACK_PEAK_MEMORY 41 /* for symbolic & numeric */ #define UMFPACK_FLOPS 42 /* flop count */ #define UMFPACK_LNZ 43 /* nz in L, incl. diagonal */ #define UMFPACK_UNZ 44 /* nz in U, incl. diagonal */ #define UMFPACK_VARIABLE_INIT 45 /* initial size of Numeric->Memory*/ #define UMFPACK_VARIABLE_PEAK 46 /* peak size of Numeric->Memory */ #define UMFPACK_VARIABLE_FINAL 47 /* final size of Numeric->Memory */ #define UMFPACK_MAX_FRONT_SIZE 48 /* max frontal matrix size */ #define UMFPACK_MAX_FRONT_NROWS 49 /* max # rows in any front */ #define UMFPACK_MAX_FRONT_NCOLS 50 /* max # columns in any front */ /* computed in UMFPACK_numeric: */ #define UMFPACK_NUMERIC_DEFRAG 60 /* # of garbage collections */ #define UMFPACK_NUMERIC_REALLOC 61 /* # of memory reallocations */ #define UMFPACK_NUMERIC_COSTLY_REALLOC 62 /* # of costlly memory realloc's */ #define UMFPACK_COMPRESSED_PATTERN 63 /* # of integers in LU pattern */ #define UMFPACK_LU_ENTRIES 64 /* # of reals in LU factors */ #define UMFPACK_NUMERIC_TIME 65 /* numeric factorization time */ #define UMFPACK_UDIAG_NZ 66 /* nz on diagonal of U */ #define UMFPACK_RCOND 67 /* est. reciprocal condition # */ #define UMFPACK_WAS_SCALED 68 /* none, max row, or sum row */ #define UMFPACK_RSMIN 69 /* min (max row) or min (sum row) */ #define UMFPACK_RSMAX 70 /* max (max row) or max (sum row) */ #define UMFPACK_UMIN 71 /* min abs diagonal entry of U */ #define UMFPACK_UMAX 72 /* max abs diagonal entry of U */ #define UMFPACK_ALLOC_INIT_USED 73 /* alloc_init parameter used */ #define UMFPACK_FORCED_UPDATES 74 /* # of forced updates */ #define UMFPACK_NUMERIC_WALLTIME 75 /* numeric wall clock time */ #define UMFPACK_NOFF_DIAG 76 /* number of off-diagonal pivots */ #define UMFPACK_ALL_LNZ 77 /* nz in L, if no dropped entries */ #define UMFPACK_ALL_UNZ 78 /* nz in U, if no dropped entries */ #define UMFPACK_NZDROPPED 79 /* # of dropped small entries */ /* computed in UMFPACK_solve: */ #define UMFPACK_IR_TAKEN 80 /* # of iterative refinement steps taken */ #define UMFPACK_IR_ATTEMPTED 81 /* # of iter. refinement steps attempted */ #define UMFPACK_OMEGA1 82 /* omega1, sparse backward error estimate */ #define UMFPACK_OMEGA2 83 /* omega2, sparse backward error estimate */ #define UMFPACK_SOLVE_FLOPS 84 /* flop count for solve */ #define UMFPACK_SOLVE_TIME 85 /* solve time (seconds) */ #define UMFPACK_SOLVE_WALLTIME 86 /* solve time (wall clock, seconds) */ /* Info [87, 88, 89] unused */ /* Unused parts of Info may be used in future versions of UMFPACK. */ /* -------------------------------------------------------------------------- */ /* Info [UMFPACK_ORDERING_USED] is one of the following: */ #define UMFPACK_ORDERING_COLAMD 0 /* COLAMD(A) */ #define UMFPACK_ORDERING_AMD 1 /* AMD(A+A') */ #define UMFPACK_ORDERING_GIVEN 2 /* Q is provided on input */ /* -------------------------------------------------------------------------- */ /* contents of Control */ /* -------------------------------------------------------------------------- */ /* used in all UMFPACK_report_* routines: */ #define UMFPACK_PRL 0 /* print level */ /* used in UMFPACK_*symbolic only: */ #define UMFPACK_DENSE_ROW 1 /* dense row parameter */ #define UMFPACK_DENSE_COL 2 /* dense col parameter */ #define UMFPACK_BLOCK_SIZE 4 /* BLAS-3 block size */ #define UMFPACK_STRATEGY 5 /* auto, symmetric, unsym., or 2by2 */ #define UMFPACK_2BY2_TOLERANCE 12 /* 2-by-2 pivot tolerance */ #define UMFPACK_FIXQ 13 /* -1: no fixQ, 0: default, 1: fixQ */ #define UMFPACK_AMD_DENSE 14 /* for AMD ordering */ #define UMFPACK_AGGRESSIVE 19 /* whether or not to use aggressive * absorption in AMD and COLAMD */ /* used in UMFPACK_numeric only: */ #define UMFPACK_PIVOT_TOLERANCE 3 /* threshold partial pivoting setting */ #define UMFPACK_ALLOC_INIT 6 /* initial allocation ratio */ #define UMFPACK_SYM_PIVOT_TOLERANCE 15 /* threshold, only for diag. entries */ #define UMFPACK_SCALE 16 /* what row scaling to do */ #define UMFPACK_FRONT_ALLOC_INIT 17 /* frontal matrix allocation ratio */ #define UMFPACK_DROPTOL 18 /* drop tolerance for entries in L,U */ /* used in UMFPACK_*solve only: */ #define UMFPACK_IRSTEP 7 /* max # of iterative refinements */ /* compile-time settings - Control [8..11] cannot be changed at run time: */ #define UMFPACK_COMPILED_WITH_BLAS 8 /* uses the BLAS */ #define UMFPACK_COMPILED_FOR_MATLAB 9 /* 1 if MATLAB mexFunction, etc. */ #define UMFPACK_COMPILED_WITH_GETRUSAGE 10 /* uses getrusage timer, or not */ #define UMFPACK_COMPILED_IN_DEBUG_MODE 11 /* debugging enabled (very slow!) */ /* -------------------------------------------------------------------------- */ /* Control [UMFPACK_STRATEGY] is one of the following: */ #define UMFPACK_STRATEGY_AUTO 0 /* use sym. or unsym. strategy */ #define UMFPACK_STRATEGY_UNSYMMETRIC 1 /* COLAMD(A), coletree postorder, not prefer diag*/ #define UMFPACK_STRATEGY_2BY2 2 /* AMD(PA+PA'), no coletree postorder, prefer diag(PA) where P is pseudo max transversal */ #define UMFPACK_STRATEGY_SYMMETRIC 3 /* AMD(A+A'), no coletree postorder, prefer diagonal */ /* Control [UMFPACK_SCALE] is one of the following: */ #define UMFPACK_SCALE_NONE 0 /* no scaling */ #define UMFPACK_SCALE_SUM 1 /* default: divide each row by sum (abs (row))*/ #define UMFPACK_SCALE_MAX 2 /* divide each row by max (abs (row)) */ /* -------------------------------------------------------------------------- */ /* default values of Control: */ /* -------------------------------------------------------------------------- */ #define UMFPACK_DEFAULT_PRL 1 #define UMFPACK_DEFAULT_DENSE_ROW 0.2 #define UMFPACK_DEFAULT_DENSE_COL 0.2 #define UMFPACK_DEFAULT_PIVOT_TOLERANCE 0.1 #define UMFPACK_DEFAULT_2BY2_TOLERANCE 0.01 #define UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE 0.001 #define UMFPACK_DEFAULT_BLOCK_SIZE 32 #define UMFPACK_DEFAULT_ALLOC_INIT 0.7 #define UMFPACK_DEFAULT_FRONT_ALLOC_INIT 0.5 #define UMFPACK_DEFAULT_IRSTEP 2 #define UMFPACK_DEFAULT_SCALE UMFPACK_SCALE_SUM #define UMFPACK_DEFAULT_STRATEGY UMFPACK_STRATEGY_AUTO #define UMFPACK_DEFAULT_AMD_DENSE AMD_DEFAULT_DENSE #define UMFPACK_DEFAULT_FIXQ 0 #define UMFPACK_DEFAULT_AGGRESSIVE 1 #define UMFPACK_DEFAULT_DROPTOL 0 /* default values of Control may change in future versions of UMFPACK. */ /* -------------------------------------------------------------------------- */ /* status codes */ /* -------------------------------------------------------------------------- */ #define UMFPACK_OK (0) /* status > 0 means a warning, but the method was successful anyway. */ /* A Symbolic or Numeric object was still created. */ #define UMFPACK_WARNING_singular_matrix (1) /* The following warnings were added in umfpack_*_get_determinant */ #define UMFPACK_WARNING_determinant_underflow (2) #define UMFPACK_WARNING_determinant_overflow (3) /* status < 0 means an error, and the method was not successful. */ /* No Symbolic of Numeric object was created. */ #define UMFPACK_ERROR_out_of_memory (-1) #define UMFPACK_ERROR_invalid_Numeric_object (-3) #define UMFPACK_ERROR_invalid_Symbolic_object (-4) #define UMFPACK_ERROR_argument_missing (-5) #define UMFPACK_ERROR_n_nonpositive (-6) #define UMFPACK_ERROR_invalid_matrix (-8) #define UMFPACK_ERROR_different_pattern (-11) #define UMFPACK_ERROR_invalid_system (-13) #define UMFPACK_ERROR_invalid_permutation (-15) #define UMFPACK_ERROR_internal_error (-911) /* yes, call me if you get this! */ #define UMFPACK_ERROR_file_IO (-17) /* -------------------------------------------------------------------------- */ /* solve codes */ /* -------------------------------------------------------------------------- */ /* Solve the system ( )x=b, where ( ) is defined below. "t" refers to the */ /* linear algebraic transpose (complex conjugate if A is complex), or the (') */ /* operator in MATLAB. "at" refers to the array transpose, or the (.') */ /* operator in MATLAB. */ #define UMFPACK_A (0) /* Ax=b */ #define UMFPACK_At (1) /* A'x=b */ #define UMFPACK_Aat (2) /* A.'x=b */ #define UMFPACK_Pt_L (3) /* P'Lx=b */ #define UMFPACK_L (4) /* Lx=b */ #define UMFPACK_Lt_P (5) /* L'Px=b */ #define UMFPACK_Lat_P (6) /* L.'Px=b */ #define UMFPACK_Lt (7) /* L'x=b */ #define UMFPACK_Lat (8) /* L.'x=b */ #define UMFPACK_U_Qt (9) /* UQ'x=b */ #define UMFPACK_U (10) /* Ux=b */ #define UMFPACK_Q_Ut (11) /* QU'x=b */ #define UMFPACK_Q_Uat (12) /* QU.'x=b */ #define UMFPACK_Ut (13) /* U'x=b */ #define UMFPACK_Uat (14) /* U.'x=b */ /* -------------------------------------------------------------------------- */ /* Integer constants are used for status and solve codes instead of enum */ /* to make it easier for a Fortran code to call UMFPACK. */ #ifdef __cplusplus } #endif #endif /* UMFPACK_H */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_defaults.h0000644000175000017500000000354411674452555023471 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_defaults ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ void umfpack_di_defaults ( double Control [UMFPACK_CONTROL] ) ; void umfpack_dl_defaults ( double Control [UMFPACK_CONTROL] ) ; void umfpack_zi_defaults ( double Control [UMFPACK_CONTROL] ) ; void umfpack_zl_defaults ( double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_di_defaults (Control) ; double UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_dl_defaults (Control) ; complex int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_zi_defaults (Control) ; complex UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_zl_defaults (Control) ; Purpose: Sets the default control parameter settings. Arguments: double Control [UMFPACK_CONTROL] ; Output argument. Control is set to the default control parameter settings. You can then modify individual settings by changing specific entries in the Control array. If Control is a (double *) NULL pointer, then umfpack_*_defaults returns silently (no error is generated, since passing a NULL pointer for Control to any UMFPACK routine is valid). */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_free_symbolic.h0000644000175000017500000000325411674452555024502 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_free_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ void umfpack_di_free_symbolic ( void **Symbolic ) ; void umfpack_dl_free_symbolic ( void **Symbolic ) ; void umfpack_zi_free_symbolic ( void **Symbolic ) ; void umfpack_zl_free_symbolic ( void **Symbolic ) ; /* double int Syntax: #include "umfpack.h" void *Symbolic ; umfpack_di_free_symbolic (&Symbolic) ; double UF_long Syntax: #include "umfpack.h" void *Symbolic ; umfpack_dl_free_symbolic (&Symbolic) ; complex int Syntax: #include "umfpack.h" void *Symbolic ; umfpack_zi_free_symbolic (&Symbolic) ; complex UF_long Syntax: #include "umfpack.h" void *Symbolic ; umfpack_zl_free_symbolic (&Symbolic) ; Purpose: Deallocates the Symbolic object and sets the Symbolic handle to NULL. This routine is the only valid way of destroying the Symbolic object. Arguments: void **Symbolic ; Input argument, set to (void *) NULL on output. Points to a valid Symbolic object computed by umfpack_*_symbolic. No action is taken if Symbolic is a (void *) NULL pointer. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_perm.h0000644000175000017500000000670011674452555024215 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_perm ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_perm ( int np, const int Perm [ ], const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_dl_report_perm ( UF_long np, const UF_long Perm [ ], const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_perm ( int np, const int Perm [ ], const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_zl_report_perm ( UF_long np, const UF_long Perm [ ], const double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" int np, *Perm, status ; double Control [UMFPACK_CONTROL] ; status = umfpack_di_report_perm (np, Perm, Control) ; double UF_long Syntax: #include "umfpack.h" UF_long np, *Perm, status ; double Control [UMFPACK_CONTROL] ; status = umfpack_dl_report_perm (np, Perm, Control) ; complex int Syntax: #include "umfpack.h" int np, *Perm, status ; double Control [UMFPACK_CONTROL] ; status = umfpack_zi_report_perm (np, Perm, Control) ; complex UF_long Syntax: #include "umfpack.h" UF_long np, *Perm, status ; double Control [UMFPACK_CONTROL] ; status = umfpack_zl_report_perm (np, Perm, Control) ; Purpose: Verifies and prints a permutation vector. Returns: UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked). Otherwise: UMFPACK_OK if the permutation vector is valid (this includes that case when Perm is (Int *) NULL, which is not an error condition). UMFPACK_ERROR_n_nonpositive if np <= 0. UMFPACK_ERROR_out_of_memory if out of memory. UMFPACK_ERROR_invalid_permutation if Perm is not a valid permutation vector. Arguments: Int np ; Input argument, not modified. Perm is an integer vector of size np. Restriction: np > 0. Int Perm [np] ; Input argument, not modified. A permutation vector of size np. If Perm is not present (an (Int *) NULL pointer), then it is assumed to be the identity permutation. This is consistent with its use as an input argument to umfpack_*_qsymbolic, and is not an error condition. If Perm is present, the entries in Perm must range between 0 and np-1, and no duplicates may exist. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 2 or less: no output. returns silently without checking anything. 3: fully check input, and print a short summary of its status 4: as 3, but print first few entries of the input 5: as 3, but print all of the input Default: 1 */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_triplet_to_col.h0000644000175000017500000002431211674452555024700 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_triplet_to_col =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_triplet_to_col ( int n_row, int n_col, int nz, const int Ti [ ], const int Tj [ ], const double Tx [ ], int Ap [ ], int Ai [ ], double Ax [ ], int Map [ ] ) ; UF_long umfpack_dl_triplet_to_col ( UF_long n_row, UF_long n_col, UF_long nz, const UF_long Ti [ ], const UF_long Tj [ ], const double Tx [ ], UF_long Ap [ ], UF_long Ai [ ], double Ax [ ], UF_long Map [ ] ) ; int umfpack_zi_triplet_to_col ( int n_row, int n_col, int nz, const int Ti [ ], const int Tj [ ], const double Tx [ ], const double Tz [ ], int Ap [ ], int Ai [ ], double Ax [ ], double Az [ ], int Map [ ] ) ; UF_long umfpack_zl_triplet_to_col ( UF_long n_row, UF_long n_col, UF_long nz, const UF_long Ti [ ], const UF_long Tj [ ], const double Tx [ ], const double Tz [ ], UF_long Ap [ ], UF_long Ai [ ], double Ax [ ], double Az [ ], UF_long Map [ ] ) ; /* double int Syntax: #include "umfpack.h" int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ; double *Tx, *Ax ; status = umfpack_di_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Ap, Ai, Ax, Map) ; double UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ; double *Tx, *Ax ; status = umfpack_dl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Ap, Ai, Ax, Map) ; complex int Syntax: #include "umfpack.h" int n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ; double *Tx, *Tz, *Ax, *Az ; status = umfpack_zi_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz, Ap, Ai, Ax, Az, Map) ; UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, nz, *Ti, *Tj, *Ap, *Ai, status, *Map ; double *Tx, *Tz, *Ax, *Az ; status = umfpack_zl_triplet_to_col (n_row, n_col, nz, Ti, Tj, Tx, Tz, Ap, Ai, Ax, Az, Map) ; packed complex Syntax: Same as above, except Tz and Az are NULL. Purpose: Converts a sparse matrix from "triplet" form to compressed-column form. Analogous to A = spconvert (Ti, Tj, Tx + Tz*1i) in MATLAB, except that zero entries present in the triplet form are present in A. The triplet form of a matrix is a very simple data structure for basic sparse matrix operations. For example, suppose you wish to factorize a matrix A coming from a finite element method, in which A is a sum of dense submatrices, A = E1 + E2 + E3 + ... . The entries in each element matrix Ei can be concatenated together in the three triplet arrays, and any overlap between the elements will be correctly summed by umfpack_*_triplet_to_col. Transposing a matrix in triplet form is simple; just interchange the use of Ti and Tj. You can construct the complex conjugate transpose by negating Tz, for the complex versions. Permuting a matrix in triplet form is also simple. If you want the matrix PAQ, or A (P,Q) in MATLAB notation, where P [k] = i means that row i of A is the kth row of PAQ and Q [k] = j means that column j of A is the kth column of PAQ, then do the following. First, create inverse permutations Pinv and Qinv such that Pinv [i] = k if P [k] = i and Qinv [j] = k if Q [k] = j. Next, for the mth triplet (Ti [m], Tj [m], Tx [m], Tz [m]), replace Ti [m] with Pinv [Ti [m]] and replace Tj [m] with Qinv [Tj [m]]. If you have a column-form matrix with duplicate entries or unsorted columns, you can sort it and sum up the duplicates by first converting it to triplet form with umfpack_*_col_to_triplet, and then converting it back with umfpack_*_triplet_to_col. Constructing a submatrix is also easy. Just scan the triplets and remove those entries outside the desired subset of 0...n_row-1 and 0...n_col-1, and renumber the indices according to their position in the subset. You can do all these operations on a column-form matrix by first converting it to triplet form with umfpack_*_col_to_triplet, doing the operation on the triplet form, and then converting it back with umfpack_*_triplet_to_col. The only operation not supported easily in the triplet form is the multiplication of two sparse matrices (UMFPACK does not provide this operation). You can print the input triplet form with umfpack_*_report_triplet, and the output matrix with umfpack_*_report_matrix. The matrix may be singular (nz can be zero, and empty rows and/or columns may exist). It may also be rectangular and/or complex. Returns: UMFPACK_OK if successful. UMFPACK_ERROR_argument_missing if Ap, Ai, Ti, and/or Tj are missing. UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0. UMFPACK_ERROR_invalid_matrix if nz < 0, or if for any k, Ti [k] and/or Tj [k] are not in the range 0 to n_row-1 or 0 to n_col-1, respectively. UMFPACK_ERROR_out_of_memory if unable to allocate sufficient workspace. Arguments: Int n_row ; Input argument, not modified. Int n_col ; Input argument, not modified. A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0. All row and column indices in the triplet form must be in the range 0 to n_row-1 and 0 to n_col-1, respectively. Int nz ; Input argument, not modified. The number of entries in the triplet form of the matrix. Restriction: nz >= 0. Int Ti [nz] ; Input argument, not modified. Int Tj [nz] ; Input argument, not modified. double Tx [nz] ; Input argument, not modified. Size 2*nz if Tz or Az are NULL. double Tz [nz] ; Input argument, not modified, for complex versions. Ti, Tj, Tx, and Tz hold the "triplet" form of a sparse matrix. The kth nonzero entry is in row i = Ti [k], column j = Tj [k], and the real part of a_ij is Tx [k]. The imaginary part of a_ij is Tz [k], for complex versions. The row and column indices i and j must be in the range 0 to n_row-1 and 0 to n_col-1, respectively. Duplicate entries may be present; they are summed in the output matrix. This is not an error condition. The "triplets" may be in any order. Tx, Tz, Ax, and Az are optional. Ax is computed only if both Ax and Tx are present (not (double *) NULL). This is not error condition; the routine can create just the pattern of the output matrix from the pattern of the triplets. If Az or Tz are NULL, then both real and imaginary parts are contained in Tx[0..2*nz-1], with Tx[2*k] and Tx[2*k+1] being the real and imaginary part of the kth entry. Int Ap [n_col+1] ; Output argument. Ap is an integer array of size n_col+1 on input. On output, Ap holds the "pointers" for the column form of the sparse matrix A. Column j of the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The first entry, Ap [0], is zero, and Ap [j] <= Ap [j+1] holds for all j in the range 0 to n_col-1. The value nz2 = Ap [n_col] is thus the total number of entries in the pattern of the matrix A. Equivalently, the number of duplicate triplets is nz - Ap [n_col]. Int Ai [nz] ; Output argument. Ai is an integer array of size nz on input. Note that only the first Ap [n_col] entries are used. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j are in ascending order, and no duplicate row indices are present. Row indices are in the range 0 to n_col-1 (the matrix is 0-based). double Ax [nz] ; Output argument. Size 2*nz if Tz or Az are NULL. double Az [nz] ; Output argument for complex versions. Ax and Az (for the complex versions) are double arrays of size nz on input. Note that only the first Ap [n_col] entries are used in both arrays. Ax is optional; if Tx and/or Ax are not present (a (double *) NULL pointer), then Ax is not computed. If present, Ax holds the numerical values of the the real part of the sparse matrix A and Az holds the imaginary parts. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. The imaginary parts are stored in Az [(Ap [j]) ... (Ap [j+1]-1)], for the complex versions. If Az or Tz are NULL, then both real and imaginary parts are returned in Ax[0..2*nz2-1], with Ax[2*k] and Ax[2*k+1] being the real and imaginary part of the kth entry. int Map [nz] ; Optional output argument. If Map is present (a non-NULL pointer to an Int array of size nz), then on output it holds the position of the triplets in the column-form matrix. That is, suppose p = Map [k], and the k-th triplet is i=Ti[k], j=Tj[k], and aij=Tx[k]. Then i=Ai[p], and aij will have been summed into Ax[p] (or simply aij=Ax[p] if there were no duplicate entries also in row i and column j). Also, Ap[j] <= p < Ap[j+1]. The Map array is not computed if it is (Int *) NULL. The Map array is useful for converting a subsequent triplet form matrix with the same pattern as the first one, without calling this routine. If Ti and Tj do not change, then Ap, and Ai can be reused from the prior call to umfpack_*_triplet_to_col. You only need to recompute Ax (and Az for the split complex version). This code excerpt properly sums up all duplicate values (for the real version): for (p = 0 ; p < Ap [n_col] ; p++) Ax [p] = 0 ; for (k = 0 ; k < nz ; k++) Ax [Map [k]] += Tx [k] ; This feature is useful (along with the reuse of the Symbolic object) if you need to factorize a sequence of triplet matrices with identical nonzero pattern (the order of the triplets in the Ti,Tj,Tx arrays must also remain unchanged). It is faster than calling this routine for each matrix, and requires no workspace. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_load_symbolic.h0000644000175000017500000000506411674452555024501 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_load_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_load_symbolic ( void **Symbolic, char *filename ) ; UF_long umfpack_dl_load_symbolic ( void **Symbolic, char *filename ) ; int umfpack_zi_load_symbolic ( void **Symbolic, char *filename ) ; UF_long umfpack_zl_load_symbolic ( void **Symbolic, char *filename ) ; /* double int Syntax: #include "umfpack.h" int status ; char *filename ; void *Symbolic ; status = umfpack_di_load_symbolic (&Symbolic, filename) ; double UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Symbolic ; status = umfpack_dl_load_symbolic (&Symbolic, filename) ; complex int Syntax: #include "umfpack.h" int status ; char *filename ; void *Symbolic ; status = umfpack_zi_load_symbolic (&Symbolic, filename) ; complex UF_long Syntax: #include "umfpack.h" UF_long status ; char *filename ; void *Symbolic ; status = umfpack_zl_load_symbolic (&Symbolic, filename) ; Purpose: Loads a Symbolic object from a file created by umfpack_*_save_symbolic. The Symbolic handle passed to this routine is overwritten with the new object. If that object exists prior to calling this routine, a memory leak will occur. The contents of Symbolic are ignored on input. Returns: UMFPACK_OK if successful. UMFPACK_ERROR_out_of_memory if not enough memory is available. UMFPACK_ERROR_file_IO if an I/O error occurred. Arguments: void **Symbolic ; Output argument. **Symbolic is the address of a (void *) pointer variable in the user's calling routine (see Syntax, above). On input, the contents of this variable are not defined. On output, this variable holds a (void *) pointer to the Symbolic object (if successful), or (void *) NULL if a failure occurred. char *filename ; Input argument, not modified. A string that contains the filename from which to read the Symbolic object. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_vector.h0000644000175000017500000001063311674452555024554 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_vector ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_vector ( int n, const double X [ ], const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_dl_report_vector ( UF_long n, const double X [ ], const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_vector ( int n, const double Xx [ ], const double Xz [ ], const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_zl_report_vector ( UF_long n, const double Xx [ ], const double Xz [ ], const double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" int n, status ; double *X, Control [UMFPACK_CONTROL] ; status = umfpack_di_report_vector (n, X, Control) ; double UF_long Syntax: #include "umfpack.h" UF_long n, status ; double *X, Control [UMFPACK_CONTROL] ; status = umfpack_dl_report_vector (n, X, Control) ; complex int Syntax: #include "umfpack.h" int n, status ; double *Xx, *Xz, Control [UMFPACK_CONTROL] ; status = umfpack_zi_report_vector (n, Xx, Xz, Control) ; complex UF_long Syntax: #include "umfpack.h" UF_long n, status ; double *Xx, *Xz, Control [UMFPACK_CONTROL] ; status = umfpack_zl_report_vector (n, Xx, Xz, Control) ; Purpose: Verifies and prints a dense vector. Returns: UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked). Otherwise: UMFPACK_OK if the vector is valid. UMFPACK_ERROR_argument_missing if X or Xx is missing. UMFPACK_ERROR_n_nonpositive if n <= 0. Arguments: Int n ; Input argument, not modified. X is a real or complex vector of size n. Restriction: n > 0. double X [n] ; Input argument, not modified. For real versions. A real vector of size n. X must not be (double *) NULL. double Xx [n or 2*n] ; Input argument, not modified. For complex versions. double Xz [n or 0] ; Input argument, not modified. For complex versions. A complex vector of size n, in one of two storage formats. Xx must not be (double *) NULL. If Xz is not (double *) NULL, then Xx [i] is the real part of X (i) and Xz [i] is the imaginary part of X (i). Both vectors are of length n. This is the "split" form of the complex vector X. If Xz is (double *) NULL, then Xx holds both real and imaginary parts, where Xx [2*i] is the real part of X (i) and Xx [2*i+1] is the imaginary part of X (i). Xx is of length 2*n doubles. If you have an ANSI C99 compiler with the intrinsic double _Complex type, then Xx can be of type double _Complex in the calling routine and typecast to (double *) when passed to umfpack_*_report_vector (this is untested, however). This is the "merged" form of the complex vector X. Note that all complex routines in UMFPACK V4.4 and later use this same strategy for their complex arguments. The split format is useful for MATLAB, which holds its real and imaginary parts in seperate arrays. The packed format is compatible with the intrinsic double _Complex type in ANSI C99, and is also compatible with SuperLU's method of storing complex matrices. In Version 4.3, this routine was the only one that allowed for packed complex arguments. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 2 or less: no output. returns silently without checking anything. 3: fully check input, and print a short summary of its status 4: as 3, but print first few entries of the input 5: as 3, but print all of the input Default: 1 */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_qsymbolic.h0000644000175000017500000001204511674452555023660 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_qsymbolic ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_qsymbolic ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], const int Qinit [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_dl_qsymbolic ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const UF_long Qinit [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; int umfpack_zi_qsymbolic ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], const double Az [ ], const int Qinit [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_zl_qsymbolic ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const double Az [ ], const UF_long Qinit [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; /* double int Syntax: #include "umfpack.h" void *Symbolic ; int n_row, n_col, *Ap, *Ai, *Qinit, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ; status = umfpack_di_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit, &Symbolic, Control, Info) ; double UF_long Syntax: #include "umfpack.h" void *Symbolic ; UF_long n_row, n_col, *Ap, *Ai, *Qinit, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ; status = umfpack_dl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Qinit, &Symbolic, Control, Info) ; complex int Syntax: #include "umfpack.h" void *Symbolic ; int n_row, n_col, *Ap, *Ai, *Qinit, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ; status = umfpack_zi_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit, &Symbolic, Control, Info) ; complex UF_long Syntax: #include "umfpack.h" void *Symbolic ; UF_long n_row, n_col, *Ap, *Ai, *Qinit, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ; status = umfpack_zl_qsymbolic (n_row, n_col, Ap, Ai, Ax, Az, Qinit, &Symbolic, Control, Info) ; packed complex Syntax: Same as above, except Az is NULL. Purpose: Given the nonzero pattern of a sparse matrix A in column-oriented form, and a sparsity preserving column pre-ordering Qinit, umfpack_*_qsymbolic performs the symbolic factorization of A*Qinit (or A (:,Qinit) in MATLAB notation). This is identical to umfpack_*_symbolic, except that neither COLAMD nor AMD are called and the user input column order Qinit is used instead. Note that in general, the Qinit passed to umfpack_*_qsymbolic can differ from the final Q found in umfpack_*_numeric. The unsymmetric strategy will perform a column etree postordering done in umfpack_*_qsymbolic and sparsity-preserving modifications are made within each frontal matrix during umfpack_*_numeric. The symmetric and 2-by-2 strategies will preserve Qinit, unless the matrix is structurally singular. See umfpack_*_symbolic for more information. *** WARNING *** A poor choice of Qinit can easily cause umfpack_*_numeric to use a huge amount of memory and do a lot of work. The "default" symbolic analysis method is umfpack_*_symbolic, not this routine. If you use this routine, the performance of UMFPACK is your responsibility; UMFPACK will not try to second-guess a poor choice of Qinit. Returns: The value of Info [UMFPACK_STATUS]; see umfpack_*_symbolic. Also returns UMFPACK_ERROR_invalid_permuation if Qinit is not a valid permutation vector. Arguments: All arguments are the same as umfpack_*_symbolic, except for the following: Int Qinit [n_col] ; Input argument, not modified. The user's fill-reducing initial column pre-ordering. This must be a permutation of 0..n_col-1. If Qinit [k] = j, then column j is the kth column of the matrix A (:,Qinit) to be factorized. If Qinit is an (Int *) NULL pointer, then COLAMD or AMD are called instead. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If Qinit is not NULL, then only two strategies are recognized: the unsymmetric strategy and the symmetric strategy. If Control [UMFPACK_STRATEGY] is UMFPACK_STRATEGY_SYMMETRIC, then the symmetric strategy is used. Otherwise the unsymmetric strategy is used. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_symbolic.h0000644000175000017500000005152211674452555023502 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_symbolic ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_symbolic ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_dl_symbolic ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; int umfpack_zi_symbolic ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], const double Az [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; UF_long umfpack_zl_symbolic ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const double Az [ ], void **Symbolic, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) ; /* double int Syntax: #include "umfpack.h" void *Symbolic ; int n_row, n_col, *Ap, *Ai, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ; status = umfpack_di_symbolic (n_row, n_col, Ap, Ai, Ax, &Symbolic, Control, Info) ; double UF_long Syntax: #include "umfpack.h" void *Symbolic ; UF_long n_row, n_col, *Ap, *Ai, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax ; status = umfpack_dl_symbolic (n_row, n_col, Ap, Ai, Ax, &Symbolic, Control, Info) ; complex int Syntax: #include "umfpack.h" void *Symbolic ; int n_row, n_col, *Ap, *Ai, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ; status = umfpack_zi_symbolic (n_row, n_col, Ap, Ai, Ax, Az, &Symbolic, Control, Info) ; complex UF_long Syntax: #include "umfpack.h" void *Symbolic ; UF_long n_row, n_col, *Ap, *Ai, status ; double Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], *Ax, *Az ; status = umfpack_zl_symbolic (n_row, n_col, Ap, Ai, Ax, Az, &Symbolic, Control, Info) ; packed complex Syntax: Same as above, except Az is NULL. Purpose: Given nonzero pattern of a sparse matrix A in column-oriented form, umfpack_*_symbolic performs a column pre-ordering to reduce fill-in (using COLAMD or AMD) and a symbolic factorization. This is required before the matrix can be numerically factorized with umfpack_*_numeric. If you wish to bypass the COLAMD or AMD pre-ordering and provide your own ordering, use umfpack_*_qsymbolic instead. Since umfpack_*_symbolic and umfpack_*_qsymbolic are very similar, options for both routines are discussed below. For the following discussion, let S be the submatrix of A obtained after eliminating all pivots of zero Markowitz cost. S has dimension (n_row-n1-nempty_row) -by- (n_col-n1-nempty_col), where n1 = Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS], nempty_row = Info [UMFPACK_NEMPTY_ROW] and nempty_col = Info [UMFPACK_NEMPTY_COL]. Returns: The status code is returned. See Info [UMFPACK_STATUS], below. Arguments: Int n_row ; Input argument, not modified. Int n_col ; Input argument, not modified. A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0. Int Ap [n_col+1] ; Input argument, not modified. Ap is an integer array of size n_col+1. On input, it holds the "pointers" for the column form of the sparse matrix A. Column j of the matrix A is held in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The first entry, Ap [0], must be zero, and Ap [j] <= Ap [j+1] must hold for all j in the range 0 to n_col-1. The value nz = Ap [n_col] is thus the total number of entries in the pattern of the matrix A. nz must be greater than or equal to zero. Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col]. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j must be in ascending order, and no duplicate row indices may be present. Row indices must be in the range 0 to n_row-1 (the matrix is 0-based). See umfpack_*_triplet_to_col for how to sort the columns of a matrix and sum up the duplicate entries. See umfpack_*_report_matrix for how to print the matrix A. double Ax [nz] ; Optional input argument, not modified. Size 2*nz for packed complex case. The numerical values of the sparse matrix A. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. Used only by the 2-by-2 strategy to determine whether entries are "large" or "small". You do not have to pass the same numerical values to umfpack_*_numeric. If Ax is not present (a (double *) NULL pointer), then any entry in A is assumed to be "large". double Az [nz] ; Optional input argument, not modified, for complex versions. For the complex versions, this holds the imaginary part of A. The imaginary part of column j is held in Az [(Ap [j]) ... (Ap [j+1]-1)]. If Az is NULL, then both real and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k] and Ax[2*k+1] being the real and imaginary part of the kth entry. Used by the 2-by-2 strategy only. See the description of Ax, above. void **Symbolic ; Output argument. **Symbolic is the address of a (void *) pointer variable in the user's calling routine (see Syntax, above). On input, the contents of this variable are not defined. On output, this variable holds a (void *) pointer to the Symbolic object (if successful), or (void *) NULL if a failure occurred. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used (the defaults are suitable for all matrices, ranging from those with highly unsymmetric nonzero pattern, to symmetric matrices). Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_STRATEGY]: This is the most important control parameter. It determines what kind of ordering and pivoting strategy that UMFPACK should use. There are 4 options: UMFPACK_STRATEGY_AUTO: This is the default. The input matrix is analyzed to determine how symmetric the nonzero pattern is, and how many entries there are on the diagonal. It then selects one of the following strategies. Refer to the User Guide for a description of how the strategy is automatically selected. UMFPACK_STRATEGY_UNSYMMETRIC: Use the unsymmetric strategy. COLAMD is used to order the columns of A, followed by a postorder of the column elimination tree. No attempt is made to perform diagonal pivoting. The column ordering is refined during factorization. In the numerical factorization, the Control [UMFPACK_SYM_PIVOT_TOLERANCE] parameter is ignored. A pivot is selected if its magnitude is >= Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry in its column. UMFPACK_STRATEGY_SYMMETRIC: Use the symmetric strategy In this method, the approximate minimum degree ordering (AMD) is applied to A+A', followed by a postorder of the elimination tree of A+A'. UMFPACK attempts to perform diagonal pivoting during numerical factorization. No refinement of the column pre-ordering is performed during factorization. In the numerical factorization, a nonzero entry on the diagonal is selected as the pivot if its magnitude is >= Control [UMFPACK_SYM_PIVOT_TOLERANCE] (default 0.001) times the largest entry in its column. If this is not acceptable, then an off-diagonal pivot is selected with magnitude >= Control [UMFPACK_PIVOT_TOLERANCE] (default 0.1) times the largest entry in its column. UMFPACK_STRATEGY_2BY2: disabled (exists in earlier versions) If requested, the symmetric strategy is used instead. Control [UMFPACK_DENSE_COL]: If COLAMD is used, columns with more than max (16, Control [UMFPACK_DENSE_COL] * 16 * sqrt (n_row)) entries are placed placed last in the column pre-ordering. Default: 0.2. Control [UMFPACK_DENSE_ROW]: Rows with more than max (16, Control [UMFPACK_DENSE_ROW] * 16 * sqrt (n_col)) entries are treated differently in the COLAMD pre-ordering, and in the internal data structures during the subsequent numeric factorization. Default: 0.2. Control [UMFPACK_AMD_DENSE]: rows/columns in A+A' with more than max (16, Control [UMFPACK_AMD_DENSE] * sqrt (n)) entries (where n = n_row = n_col) are ignored in the AMD pre-ordering. Default: 10. Control [UMFPACK_BLOCK_SIZE]: the block size to use for Level-3 BLAS in the subsequent numerical factorization (umfpack_*_numeric). A value less than 1 is treated as 1. Default: 32. Modifying this parameter affects when updates are applied to the working frontal matrix, and can indirectly affect fill-in and operation count. Assuming the block size is large enough (8 or so), this parameter has a modest effect on performance. Control [UMFPACK_2BY2_TOLERANCE]: no longer used Control [UMFPACK_SCALE]: See umfpack_numeric.h for a description. Only affects the 2-by-2 strategy. Default: UMFPACK_SCALE_SUM. Control [UMFPACK_FIXQ]: If > 0, then the pre-ordering Q is not modified during numeric factorization. If < 0, then Q may be modified. If zero, then this is controlled automatically (the unsymmetric strategy modifies Q, the others do not). Default: 0. Control [UMFPACK_AGGRESSIVE]: If nonzero, aggressive absorption is used in COLAMD and AMD. Default: 1. double Info [UMFPACK_INFO] ; Output argument, not defined on input. Contains statistics about the symbolic analysis. If a (double *) NULL pointer is passed, then no statistics are returned in Info (this is not an error condition). The entire Info array is cleared (all entries set to -1) and then the following statistics are computed: Info [UMFPACK_STATUS]: status code. This is also the return value, whether or not Info is present. UMFPACK_OK Each column of the input matrix contained row indices in increasing order, with no duplicates. Only in this case does umfpack_*_symbolic compute a valid symbolic factorization. For the other cases below, no Symbolic object is created (*Symbolic is (void *) NULL). UMFPACK_ERROR_n_nonpositive n is less than or equal to zero. UMFPACK_ERROR_invalid_matrix Number of entries in the matrix is negative, Ap [0] is nonzero, a column has a negative number of entries, a row index is out of bounds, or the columns of input matrix were jumbled (unsorted columns or duplicate entries). UMFPACK_ERROR_out_of_memory Insufficient memory to perform the symbolic analysis. If the analysis requires more than 2GB of memory and you are using the 32-bit ("int") version of UMFPACK, then you are guaranteed to run out of memory. Try using the 64-bit version of UMFPACK. UMFPACK_ERROR_argument_missing One or more required arguments is missing. UMFPACK_ERROR_internal_error Something very serious went wrong. This is a bug. Please contact the author (davis@cise.ufl.edu). Info [UMFPACK_NROW]: the value of the input argument n_row. Info [UMFPACK_NCOL]: the value of the input argument n_col. Info [UMFPACK_NZ]: the number of entries in the input matrix (Ap [n_col]). Info [UMFPACK_SIZE_OF_UNIT]: the number of bytes in a Unit, for memory usage statistics below. Info [UMFPACK_SIZE_OF_INT]: the number of bytes in an int. Info [UMFPACK_SIZE_OF_LONG]: the number of bytes in a UF_long. Info [UMFPACK_SIZE_OF_POINTER]: the number of bytes in a void * pointer. Info [UMFPACK_SIZE_OF_ENTRY]: the number of bytes in a numerical entry. Info [UMFPACK_NDENSE_ROW]: number of "dense" rows in A. These rows are ignored when the column pre-ordering is computed in COLAMD. They are also treated differently during numeric factorization. If > 0, then the matrix had to be re-analyzed by UMF_analyze, which does not ignore these rows. Info [UMFPACK_NEMPTY_ROW]: number of "empty" rows in A, as determined These are rows that either have no entries, or whose entries are all in pivot columns of zero-Markowitz-cost pivots. Info [UMFPACK_NDENSE_COL]: number of "dense" columns in A. COLAMD orders these columns are ordered last in the factorization, but before "empty" columns. Info [UMFPACK_NEMPTY_COL]: number of "empty" columns in A. These are columns that either have no entries, or whose entries are all in pivot rows of zero-Markowitz-cost pivots. These columns are ordered last in the factorization, to the right of "dense" columns. Info [UMFPACK_SYMBOLIC_DEFRAG]: number of garbage collections performed during ordering and symbolic pre-analysis. Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]: the amount of memory (in Units) required for umfpack_*_symbolic to complete. This count includes the size of the Symbolic object itself, which is also reported in Info [UMFPACK_SYMBOLIC_SIZE]. Info [UMFPACK_SYMBOLIC_SIZE]: the final size of the Symbolic object (in Units). This is fairly small, roughly 2*n to 13*n integers, depending on the matrix. Info [UMFPACK_VARIABLE_INIT_ESTIMATE]: the Numeric object contains two parts. The first is fixed in size (O (n_row+n_col)). The second part holds the sparse LU factors and the contribution blocks from factorized frontal matrices. This part changes in size during factorization. Info [UMFPACK_VARIABLE_INIT_ESTIMATE] is the exact size (in Units) required for this second variable-sized part in order for the numerical factorization to start. Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]: the estimated peak size (in Units) of the variable-sized part of the Numeric object. This is usually an upper bound, but that is not guaranteed. Info [UMFPACK_VARIABLE_FINAL_ESTIMATE]: the estimated final size (in Units) of the variable-sized part of the Numeric object. This is usually an upper bound, but that is not guaranteed. It holds just the sparse LU factors. Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]: an estimate of the final size (in Units) of the entire Numeric object (both fixed-size and variable- sized parts), which holds the LU factorization (including the L, U, P and Q matrices). Info [UMFPACK_PEAK_MEMORY_ESTIMATE]: an estimate of the total amount of memory (in Units) required by umfpack_*_symbolic and umfpack_*_numeric to perform both the symbolic and numeric factorization. This is the larger of the amount of memory needed in umfpack_*_numeric itself, and the amount of memory needed in umfpack_*_symbolic (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]). The count includes the size of both the Symbolic and Numeric objects themselves. It can be a very loose upper bound, particularly when the symmetric or 2-by-2 strategies are used. Info [UMFPACK_FLOPS_ESTIMATE]: an estimate of the total floating-point operations required to factorize the matrix. This is a "true" theoretical estimate of the number of flops that would be performed by a flop-parsimonious sparse LU algorithm. It assumes that no extra flops are performed except for what is strictly required to compute the LU factorization. It ignores, for example, the flops performed by umfpack_di_numeric to add contribution blocks of frontal matrices together. If L and U are the upper bound on the pattern of the factors, then this flop count estimate can be represented in MATLAB (for real matrices, not complex) as: Lnz = full (sum (spones (L))) - 1 ; % nz in each col of L Unz = full (sum (spones (U')))' - 1 ; % nz in each row of U flops = 2*Lnz*Unz + sum (Lnz) ; The actual "true flop" count found by umfpack_*_numeric will be less than this estimate. For the real version, only (+ - * /) are counted. For the complex version, the following counts are used: operation flops c = 1/b 6 c = a*b 6 c -= a*b 8 Info [UMFPACK_LNZ_ESTIMATE]: an estimate of the number of nonzeros in L, including the diagonal. Since L is unit-diagonal, the diagonal of L is not stored. This estimate is a strict upper bound on the actual nonzeros in L to be computed by umfpack_*_numeric. Info [UMFPACK_UNZ_ESTIMATE]: an estimate of the number of nonzeros in U, including the diagonal. This estimate is a strict upper bound on the actual nonzeros in U to be computed by umfpack_*_numeric. Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE]: estimate of the size of the largest frontal matrix (# of entries), for arbitrary partial pivoting during numerical factorization. Info [UMFPACK_SYMBOLIC_TIME]: The CPU time taken, in seconds. Info [UMFPACK_SYMBOLIC_WALLTIME]: The wallclock time taken, in seconds. Info [UMFPACK_STRATEGY_USED]: The ordering strategy used: UMFPACK_STRATEGY_SYMMETRIC or UMFPACK_STRATEGY_UNSYMMETRIC Info [UMFPACK_ORDERING_USED]: The ordering method used: UMFPACK_ORDERING_COLAMD or UMFPACK_ORDERING_AMD. It can be UMFPACK_ORDERING_GIVEN for umfpack_*_qsymbolic. Info [UMFPACK_QFIXED]: 1 if the column pre-ordering will be refined during numerical factorization, 0 if not. Info [UMFPACK_DIAG_PREFERED]: 1 if diagonal pivoting will be attempted, 0 if not. Info [UMFPACK_COL_SINGLETONS]: the matrix A is analyzed by first eliminating all pivots with zero Markowitz cost. This count is the number of these pivots with exactly one nonzero in their pivot column. Info [UMFPACK_ROW_SINGLETONS]: the number of zero-Markowitz-cost pivots with exactly one nonzero in their pivot row. Info [UMFPACK_PATTERN_SYMMETRY]: the symmetry of the pattern of S. Info [UMFPACK_NZ_A_PLUS_AT]: the number of off-diagonal entries in S+S'. Info [UMFPACK_NZDIAG]: the number of entries on the diagonal of S. Info [UMFPACK_N2]: if S is square, and nempty_row = nempty_col, this is equal to n_row - n1 - nempty_row. Info [UMFPACK_S_SYMMETRIC]: 1 if S is square and its diagonal has been preserved, 0 otherwise. Info [UMFPACK_MAX_FRONT_NROWS_ESTIMATE]: estimate of the max number of rows in any frontal matrix, for arbitrary partial pivoting. Info [UMFPACK_MAX_FRONT_NCOLS_ESTIMATE]: estimate of the max number of columns in any frontal matrix, for arbitrary partial pivoting. ------------------------------------------------------------------------ The next four statistics are computed only if AMD is used: ------------------------------------------------------------------------ Info [UMFPACK_SYMMETRIC_LUNZ]: The number of nonzeros in L and U, assuming no pivoting during numerical factorization, and assuming a zero-free diagonal of U. Excludes the entries on the diagonal of L. If the matrix has a purely symmetric nonzero pattern, this is often a lower bound on the nonzeros in the actual L and U computed in the numerical factorization, for matrices that fit the criteria for the "symmetric" strategy. Info [UMFPACK_SYMMETRIC_FLOPS]: The floating-point operation count in the numerical factorization phase, assuming no pivoting. If the pattern of the matrix is symmetric, this is normally a lower bound on the floating-point operation count in the actual numerical factorization, for matrices that fit the criteria for the symmetric or 2-by-2 strategies Info [UMFPACK_SYMMETRIC_NDENSE]: The number of "dense" rows/columns of S+S' that were ignored during the AMD ordering. These are placed last in the output order. If > 0, then the Info [UMFPACK_SYMMETRIC_*] statistics, above are rough upper bounds. Info [UMFPACK_SYMMETRIC_DMAX]: The maximum number of nonzeros in any column of L, if no pivoting is performed during numerical factorization. Excludes the part of the LU factorization for pivots with zero Markowitz cost. At the start of umfpack_*_symbolic, all of Info is set of -1, and then after that only the above listed Info [...] entries are accessed. Future versions might modify different parts of Info. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_symbolic.h0000644000175000017500000000673711674452555025105 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_symbolic ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_symbolic ( void *Symbolic, const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_dl_report_symbolic ( void *Symbolic, const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_symbolic ( void *Symbolic, const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_zl_report_symbolic ( void *Symbolic, const double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" void *Symbolic ; double Control [UMFPACK_CONTROL] ; int status ; status = umfpack_di_report_symbolic (Symbolic, Control) ; double UF_long Syntax: #include "umfpack.h" void *Symbolic ; double Control [UMFPACK_CONTROL] ; UF_long status ; status = umfpack_dl_report_symbolic (Symbolic, Control) ; complex int Syntax: #include "umfpack.h" void *Symbolic ; double Control [UMFPACK_CONTROL] ; int status ; status = umfpack_zi_report_symbolic (Symbolic, Control) ; complex UF_long Syntax: #include "umfpack.h" void *Symbolic ; double Control [UMFPACK_CONTROL] ; UF_long status ; status = umfpack_zl_report_symbolic (Symbolic, Control) ; Purpose: Verifies and prints a Symbolic object. This routine checks the object more carefully than the computational routines. Normally, this check is not required, since umfpack_*_*symbolic either returns (void *) NULL, or a valid Symbolic object. However, if you suspect that your own code has corrupted the Symbolic object (by overruning memory bounds, for example), then this routine might be able to detect a corrupted Symbolic object. Since this is a complex object, not all such user-generated errors are guaranteed to be caught by this routine. Returns: UMFPACK_OK if Control [UMFPACK_PRL] is <= 2 (no inputs are checked). Otherwise: UMFPACK_OK if the Symbolic object is valid. UMFPACK_ERROR_invalid_Symbolic_object if the Symbolic object is invalid. UMFPACK_ERROR_out_of_memory if out of memory. Arguments: void *Symbolic ; Input argument, not modified. The Symbolic object, which holds the symbolic factorization computed by umfpack_*_*symbolic. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 2 or less: no output. returns silently without checking anything. 3: fully check input, and print a short summary of its status 4: as 3, but print first few entries of the input 5: as 3, but print all of the input Default: 1 */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_get_lunz.h0000644000175000017500000000762511674452555023515 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_get_lunz ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_get_lunz ( int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric ) ; UF_long umfpack_dl_get_lunz ( UF_long *lnz, UF_long *unz, UF_long *n_row, UF_long *n_col, UF_long *nz_udiag, void *Numeric ) ; int umfpack_zi_get_lunz ( int *lnz, int *unz, int *n_row, int *n_col, int *nz_udiag, void *Numeric ) ; UF_long umfpack_zl_get_lunz ( UF_long *lnz, UF_long *unz, UF_long *n_row, UF_long *n_col, UF_long *nz_udiag, void *Numeric ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; int status, lnz, unz, n_row, n_col, nz_udiag ; status = umfpack_di_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag, Numeric) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long status, lnz, unz, n_row, n_col, nz_udiag ; status = umfpack_dl_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag, Numeric) ; complex int Syntax: #include "umfpack.h" void *Numeric ; int status, lnz, unz, n_row, n_col, nz_udiag ; status = umfpack_zi_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag, Numeric) ; complex UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long status, lnz, unz, n_row, n_col, nz_udiag ; status = umfpack_zl_get_lunz (&lnz, &unz, &n_row, &n_col, &nz_udiag, Numeric) ; Purpose: Determines the size and number of nonzeros in the LU factors held by the Numeric object. These are also the sizes of the output arrays required by umfpack_*_get_numeric. The matrix L is n_row -by- min(n_row,n_col), with lnz nonzeros, including the entries on the unit diagonal of L. The matrix U is min(n_row,n_col) -by- n_col, with unz nonzeros, including nonzeros on the diagonal of U. Returns: UMFPACK_OK if successful. UMFPACK_ERROR_invalid_Numeric_object if Numeric is not a valid object. UMFPACK_ERROR_argument_missing if any other argument is (Int *) NULL. Arguments: Int *lnz ; Output argument. The number of nonzeros in L, including the diagonal (which is all one's). This value is the required size of the Lj and Lx arrays as computed by umfpack_*_get_numeric. The value of lnz is identical to Info [UMFPACK_LNZ], if that value was returned by umfpack_*_numeric. Int *unz ; Output argument. The number of nonzeros in U, including the diagonal. This value is the required size of the Ui and Ux arrays as computed by umfpack_*_get_numeric. The value of unz is identical to Info [UMFPACK_UNZ], if that value was returned by umfpack_*_numeric. Int *n_row ; Output argument. Int *n_col ; Output argument. The order of the L and U matrices. L is n_row -by- min(n_row,n_col) and U is min(n_row,n_col) -by- n_col. Int *nz_udiag ; Output argument. The number of numerically nonzero values on the diagonal of U. The matrix is singular if nz_diag < min(n_row,n_col). A divide-by-zero will occur if nz_diag < n_row == n_col when solving a sparse system involving the matrix U in umfpack_*_*solve. The value of nz_udiag is identical to Info [UMFPACK_UDIAG_NZ] if that value was returned by umfpack_*_numeric. void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_status.h0000644000175000017500000000500311674452555024570 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_status ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ void umfpack_di_report_status ( const double Control [UMFPACK_CONTROL], int status ) ; void umfpack_dl_report_status ( const double Control [UMFPACK_CONTROL], UF_long status ) ; void umfpack_zi_report_status ( const double Control [UMFPACK_CONTROL], int status ) ; void umfpack_zl_report_status ( const double Control [UMFPACK_CONTROL], UF_long status ) ; /* double int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; int status ; umfpack_di_report_status (Control, status) ; double UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; UF_long status ; umfpack_dl_report_status (Control, status) ; complex int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; int status ; umfpack_zi_report_status (Control, status) ; complex UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; UF_long status ; umfpack_zl_report_status (Control, status) ; Purpose: Prints the status (return value) of other umfpack_* routines. Arguments: double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 0 or less: no output, even when an error occurs 1: error messages only 2 or more: print status, whether or not an error occurred 4 or more: also print the UMFPACK Copyright 6 or more: also print the UMFPACK License Default: 1 Int status ; Input argument, not modified. The return value from another umfpack_* routine. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_transpose.h0000644000175000017500000001740211674452555023676 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_transpose ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_transpose ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], const int P [ ], const int Q [ ], int Rp [ ], int Ri [ ], double Rx [ ] ) ; UF_long umfpack_dl_transpose ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const UF_long P [ ], const UF_long Q [ ], UF_long Rp [ ], UF_long Ri [ ], double Rx [ ] ) ; int umfpack_zi_transpose ( int n_row, int n_col, const int Ap [ ], const int Ai [ ], const double Ax [ ], const double Az [ ], const int P [ ], const int Q [ ], int Rp [ ], int Ri [ ], double Rx [ ], double Rz [ ], int do_conjugate ) ; UF_long umfpack_zl_transpose ( UF_long n_row, UF_long n_col, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const double Az [ ], const UF_long P [ ], const UF_long Q [ ], UF_long Rp [ ], UF_long Ri [ ], double Rx [ ], double Rz [ ], UF_long do_conjugate ) ; /* double int Syntax: #include "umfpack.h" int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ; double *Ax, *Rx ; status = umfpack_di_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ; double UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri ; double *Ax, *Rx ; status = umfpack_dl_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, Rp, Ri, Rx) ; complex int Syntax: #include "umfpack.h" int n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ; double *Ax, *Az, *Rx, *Rz ; status = umfpack_zi_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, do_conjugate) ; complex UF_long Syntax: #include "umfpack.h" UF_long n_row, n_col, status, *Ap, *Ai, *P, *Q, *Rp, *Ri, do_conjugate ; double *Ax, *Az, *Rx, *Rz ; status = umfpack_zl_transpose (n_row, n_col, Ap, Ai, Ax, Az, P, Q, Rp, Ri, Rx, Rz, do_conjugate) ; packed complex Syntax: Same as above, except Az are Rz are NULL. Purpose: Transposes and optionally permutes a sparse matrix in row or column-form, R = (PAQ)'. In MATLAB notation, R = (A (P,Q))' or R = (A (P,Q)).' doing either the linear algebraic transpose or the array transpose. Alternatively, this routine can be viewed as converting A (P,Q) from column-form to row-form, or visa versa (for the array transpose). Empty rows and columns may exist. The matrix A may be singular and/or rectangular. umfpack_*_transpose is useful if you want to factorize A' or A.' instead of A. Factorizing A' or A.' instead of A can be much better, particularly if AA' is much sparser than A'A. You can still solve Ax=b if you factorize A' or A.', by solving with the sys argument UMFPACK_At or UMFPACK_Aat, respectively, in umfpack_*_*solve. Returns: UMFPACK_OK if successful. UMFPACK_ERROR_out_of_memory if umfpack_*_transpose fails to allocate a size-max (n_row,n_col) workspace. UMFPACK_ERROR_argument_missing if Ai, Ap, Ri, and/or Rp are missing. UMFPACK_ERROR_n_nonpositive if n_row <= 0 or n_col <= 0 UMFPACK_ERROR_invalid_permutation if P and/or Q are invalid. UMFPACK_ERROR_invalid_matrix if Ap [n_col] < 0, if Ap [0] != 0, if Ap [j] > Ap [j+1] for any j in the range 0 to n_col-1, if any row index i is < 0 or >= n_row, or if the row indices in any column are not in ascending order. Arguments: Int n_row ; Input argument, not modified. Int n_col ; Input argument, not modified. A is an n_row-by-n_col matrix. Restriction: n_row > 0 and n_col > 0. Int Ap [n_col+1] ; Input argument, not modified. The column pointers of the column-oriented form of the matrix A. See umfpack_*_symbolic for a description. The number of entries in the matrix is nz = Ap [n_col]. Ap [0] must be zero, Ap [n_col] must be => 0, and Ap [j] <= Ap [j+1] and Ap [j] <= Ap [n_col] must be true for all j in the range 0 to n_col-1. Empty columns are OK (that is, Ap [j] may equal Ap [j+1] for any j in the range 0 to n_col-1). Int Ai [nz] ; Input argument, not modified, of size nz = Ap [n_col]. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)]. The row indices in a given column j must be in ascending order, and no duplicate row indices may be present. Row indices must be in the range 0 to n_row-1 (the matrix is 0-based). double Ax [nz] ; Input argument, not modified, of size nz = Ap [n_col]. Size 2*nz if Az or Rz are NULL. double Az [nz] ; Input argument, not modified, for complex versions. If present, these are the numerical values of the sparse matrix A. The nonzero pattern (row indices) for column j is stored in Ai [(Ap [j]) ... (Ap [j+1]-1)], and the corresponding real numerical values are stored in Ax [(Ap [j]) ... (Ap [j+1]-1)]. The imaginary values are stored in Az [(Ap [j]) ... (Ap [j+1]-1)]. The values are transposed only if Ax and Rx are present. This is not an error conditions; you are able to transpose and permute just the pattern of a matrix. If Az or Rz are NULL, then both real and imaginary parts are contained in Ax[0..2*nz-1], with Ax[2*k] and Ax[2*k+1] being the real and imaginary part of the kth entry. Int P [n_row] ; Input argument, not modified. The permutation vector P is defined as P [k] = i, where the original row i of A is the kth row of PAQ. If you want to use the identity permutation for P, simply pass (Int *) NULL for P. This is not an error condition. P is a complete permutation of all the rows of A; this routine does not support the creation of a transposed submatrix of A (R = A (1:3,:)' where A has more than 3 rows, for example, cannot be done; a future version might support this operation). Int Q [n_col] ; Input argument, not modified. The permutation vector Q is defined as Q [k] = j, where the original column j of A is the kth column of PAQ. If you want to use the identity permutation for Q, simply pass (Int *) NULL for Q. This is not an error condition. Q is a complete permutation of all the columns of A; this routine does not support the creation of a transposed submatrix of A. Int Rp [n_row+1] ; Output argument. The column pointers of the matrix R = (A (P,Q))' or (A (P,Q)).', in the same form as the column pointers Ap for the matrix A. Int Ri [nz] ; Output argument. The row indices of the matrix R = (A (P,Q))' or (A (P,Q)).' , in the same form as the row indices Ai for the matrix A. double Rx [nz] ; Output argument. Size 2*nz if Az or Rz are NULL. double Rz [nz] ; Output argument, imaginary part for complex versions. If present, these are the numerical values of the sparse matrix R, in the same form as the values Ax and Az of the matrix A. If Az or Rz are NULL, then both real and imaginary parts are contained in Rx[0..2*nz-1], with Rx[2*k] and Rx[2*k+1] being the real and imaginary part of the kth entry. Int do_conjugate ; Input argument for complex versions only. If true, and if Ax and Rx are present, then the linear algebraic transpose is computed (complex conjugate). If false, the array transpose is computed instead. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_control.h0000644000175000017500000000422511674452555024732 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_control =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ void umfpack_di_report_control ( const double Control [UMFPACK_CONTROL] ) ; void umfpack_dl_report_control ( const double Control [UMFPACK_CONTROL] ) ; void umfpack_zi_report_control ( const double Control [UMFPACK_CONTROL] ) ; void umfpack_zl_report_control ( const double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_di_report_control (Control) ; double UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_dl_report_control (Control) ; complex int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_zi_report_control (Control) ; double UF_long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_zl_report_control (Control) ; Purpose: Prints the current control settings. Note that with the default print level, nothing is printed. Does nothing if Control is (double *) NULL. Arguments: double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 1 or less: no output 2 or more: print all of Control Default: 1 */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_report_numeric.h0000644000175000017500000000703411674452555024715 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_report_numeric =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_numeric ( void *Numeric, const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_dl_report_numeric ( void *Numeric, const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_numeric ( void *Numeric, const double Control [UMFPACK_CONTROL] ) ; UF_long umfpack_zl_report_numeric ( void *Numeric, const double Control [UMFPACK_CONTROL] ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; double Control [UMFPACK_CONTROL] ; int status ; status = umfpack_di_report_numeric (Numeric, Control) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; double Control [UMFPACK_CONTROL] ; UF_long status ; status = umfpack_dl_report_numeric (Numeric, Control) ; complex int Syntax: #include "umfpack.h" void *Numeric ; double Control [UMFPACK_CONTROL] ; int status ; status = umfpack_zi_report_numeric (Numeric, Control) ; complex UF_long Syntax: #include "umfpack.h" void *Numeric ; double Control [UMFPACK_CONTROL] ; UF_long status ; status = umfpack_zl_report_numeric (Numeric, Control) ; Purpose: Verifies and prints a Numeric object (the LU factorization, both its pattern numerical values, and permutation vectors P and Q). This routine checks the object more carefully than the computational routines. Normally, this check is not required, since umfpack_*_numeric either returns (void *) NULL, or a valid Numeric object. However, if you suspect that your own code has corrupted the Numeric object (by overruning memory bounds, for example), then this routine might be able to detect a corrupted Numeric object. Since this is a complex object, not all such user-generated errors are guaranteed to be caught by this routine. Returns: UMFPACK_OK if Control [UMFPACK_PRL] <= 2 (the input is not checked). Otherwise: UMFPACK_OK if the Numeric object is valid. UMFPACK_ERROR_invalid_Numeric_object if the Numeric object is invalid. UMFPACK_ERROR_out_of_memory if out of memory. Arguments: void *Numeric ; Input argument, not modified. The Numeric object, which holds the numeric factorization computed by umfpack_*_numeric. double Control [UMFPACK_CONTROL] ; Input argument, not modified. If a (double *) NULL pointer is passed, then the default control settings are used. Otherwise, the settings are determined from the Control array. See umfpack_*_defaults on how to fill the Control array with the default settings. If Control contains NaN's, the defaults are used. The following Control parameters are used: Control [UMFPACK_PRL]: printing level. 2 or less: no output. returns silently without checking anything. 3: fully check input, and print a short summary of its status 4: as 3, but print first few entries of the input 5: as 3, but print all of the input Default: 1 */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_timer.h0000644000175000017500000000326711674452555023004 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_timer ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ double umfpack_timer ( void ) ; /* Syntax (for all versions: di, dl, zi, and zl): #include "umfpack.h" double t ; t = umfpack_timer ( ) ; Purpose: Returns the CPU time used by the process. Includes both "user" and "system" time (the latter is time spent by the system on behalf of the process, and is thus charged to the process). It does not return the wall clock time. See umfpack_tic and umfpack_toc (the file umfpack_tictoc.h) for the timer used internally by UMFPACK. This routine uses the Unix getrusage routine, if available. It is less subject to overflow than the ANSI C clock routine. If getrusage is not available, the portable ANSI C clock routine is used instead. Unfortunately, clock ( ) overflows if the CPU time exceeds 2147 seconds (about 36 minutes) when sizeof (clock_t) is 4 bytes. If you have getrusage, be sure to compile UMFPACK with the -DGETRUSAGE flag set; see umf_config.h and the User Guide for details. Even the getrusage routine can overlow. Arguments: None. */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Include/umfpack_wsolve.h0000644000175000017500000001264611674452555023204 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_wsolve ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_wsolve ( int sys, const int Ap [ ], const int Ai [ ], const double Ax [ ], double X [ ], const double B [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO], int Wi [ ], double W [ ] ) ; UF_long umfpack_dl_wsolve ( UF_long sys, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], double X [ ], const double B [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO], UF_long Wi [ ], double W [ ] ) ; int umfpack_zi_wsolve ( int sys, const int Ap [ ], const int Ai [ ], const double Ax [ ], const double Az [ ], double Xx [ ], double Xz [ ], const double Bx [ ], const double Bz [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO], int Wi [ ], double W [ ] ) ; UF_long umfpack_zl_wsolve ( UF_long sys, const UF_long Ap [ ], const UF_long Ai [ ], const double Ax [ ], const double Az [ ], double Xx [ ], double Xz [ ], const double Bx [ ], const double Bz [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO], UF_long Wi [ ], double W [ ] ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; int status, *Ap, *Ai, *Wi, sys ; double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_di_wsolve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info, Wi, W) ; double UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long status, *Ap, *Ai, *Wi, sys ; double *B, *X, *Ax, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_dl_wsolve (sys, Ap, Ai, Ax, X, B, Numeric, Control, Info, Wi, W) ; complex int Syntax: #include "umfpack.h" void *Numeric ; int status, *Ap, *Ai, *Wi, sys ; double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_zi_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info, Wi, W) ; complex UF_long Syntax: #include "umfpack.h" void *Numeric ; UF_long status, *Ap, *Ai, *Wi, sys ; double *Bx, *Bz, *Xx, *Xz, *Ax, *Az, *W, Info [UMFPACK_INFO], Control [UMFPACK_CONTROL] ; status = umfpack_zl_wsolve (sys, Ap, Ai, Ax, Az, Xx, Xz, Bx, Bz, Numeric, Control, Info, Wi, W) ; packed complex Syntax: Same as above, except Az, Xz, and Bz are NULL. Purpose: Given LU factors computed by umfpack_*_numeric (PAQ=LU) and the right-hand-side, B, solve a linear system for the solution X. Iterative refinement is optionally performed. This routine is identical to umfpack_*_solve, except that it does not dynamically allocate any workspace. When you have many linear systems to solve, this routine is faster than umfpack_*_solve, since the workspace (Wi, W) needs to be allocated only once, prior to calling umfpack_*_wsolve. Returns: The status code is returned. See Info [UMFPACK_STATUS], below. Arguments: Int sys ; Input argument, not modified. Int Ap [n+1] ; Input argument, not modified. Int Ai [nz] ; Input argument, not modified. double Ax [nz] ; Input argument, not modified. Size 2*nz in packed complex case. double X [n] ; Output argument. double B [n] ; Input argument, not modified. void *Numeric ; Input argument, not modified. double Control [UMFPACK_CONTROL] ; Input argument, not modified. double Info [UMFPACK_INFO] ; Output argument. for complex versions: double Az [nz] ; Input argument, not modified, imaginary part double Xx [n] ; Output argument, real part. Size 2*n in packed complex case. double Xz [n] ; Output argument, imaginary part double Bx [n] ; Input argument, not modified, real part. Size 2*n in packed complex case. double Bz [n] ; Input argument, not modified, imaginary part The above arguments are identical to umfpack_*_solve, except that the error code UMFPACK_ERROR_out_of_memory will not be returned in Info [UMFPACK_STATUS], since umfpack_*_wsolve does not allocate any memory. Int Wi [n] ; Workspace. double W [c*n] ; Workspace, where c is defined below. The Wi and W arguments are workspace used by umfpack_*_wsolve. They need not be initialized on input, and their contents are undefined on output. The size of W depends on whether or not iterative refinement is used, and which version (real or complex) is called. Iterative refinement is performed if Ax=b, A'x=b, or A.'x=b is being solved, Control [UMFPACK_IRSTEP] > 0, and A is nonsingular. The size of W is given below: no iter. with iter. refinement refinement umfpack_di_wsolve n 5*n umfpack_dl_wsolve n 5*n umfpack_zi_wsolve 4*n 10*n umfpack_zl_wsolve 4*n 10*n */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/0000755000175000017500000000000011674452555017652 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.c0000644000175000017500000006331411674452555022530 0ustar sonnesonne/* ========================================================================== */ /* === UMF_store_lu ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Store the LU factors. Called by the kernel. Returns TRUE if successful, FALSE if out of memory. */ #include "umf_internal.h" #include "umf_store_lu.h" #include "umf_mem_alloc_head_block.h" #include "umf_get_memory.h" /* ========================================================================== */ #ifdef DROP GLOBAL Int UMF_store_lu_drop #else GLOBAL Int UMF_store_lu #endif ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry pivot_value ; #ifdef DROP double droptol ; #endif Entry *D, *Lval, *Uval, *Fl1, *Fl2, *Fu1, *Fu2, *Flublock, *Flblock, *Fublock ; Int i, k, fnr_curr, fnrows, fncols, row, col, pivrow, pivcol, *Frows, *Fcols, *Lpattern, *Upattern, *Lpos, *Upos, llen, ulen, fnc_curr, fnpiv, uilen, lnz, unz, nb, *Lilen, *Uilen, *Lip, *Uip, *Li, *Ui, pivcol_position, newLchain, newUchain, pivrow_position, p, size, lip, uip, lnzi, lnzx, unzx, lnz2i, lnz2x, unz2i, unz2x, zero_pivot, *Pivrow, *Pivcol, kk, Lnz [MAXNB] ; #ifndef NDEBUG Int *Col_degree, *Row_degree ; #endif #ifdef DROP Int all_lnz, all_unz ; droptol = Numeric->droptol ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ fnrows = Work->fnrows ; fncols = Work->fncols ; fnpiv = Work->fnpiv ; Lpos = Numeric->Lpos ; Upos = Numeric->Upos ; Lilen = Numeric->Lilen ; Uilen = Numeric->Uilen ; Lip = Numeric->Lip ; Uip = Numeric->Uip ; D = Numeric->D ; Flublock = Work->Flublock ; Flblock = Work->Flblock ; Fublock = Work->Fublock ; fnr_curr = Work->fnr_curr ; fnc_curr = Work->fnc_curr ; Frows = Work->Frows ; Fcols = Work->Fcols ; #ifndef NDEBUG Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */ #endif Lpattern = Work->Lpattern ; llen = Work->llen ; Upattern = Work->Upattern ; ulen = Work->ulen ; nb = Work->nb ; #ifndef NDEBUG DEBUG1 (("\nSTORE LU: fnrows "ID " fncols "ID"\n", fnrows, fncols)) ; DEBUG2 (("\nFrontal matrix, including all space:\n" "fnr_curr "ID" fnc_curr "ID" nb "ID"\n" "fnrows "ID" fncols "ID" fnpiv "ID"\n", fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ; DEBUG2 (("\nJust the active part:\n")) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Work->Fcblock, fnr_curr, fnrows, fncols) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Work->Flblock, fnr_curr, fnrows, fnpiv); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Work->Fublock, fnc_curr, fncols, fnpiv) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Work->Flublock, nb, fnpiv, fnpiv) ; DEBUG7 (("Current frontal matrix: (prior to store LU)\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif Pivrow = Work->Pivrow ; Pivcol = Work->Pivcol ; /* ---------------------------------------------------------------------- */ /* store the columns of L */ /* ---------------------------------------------------------------------- */ for (kk = 0 ; kk < fnpiv ; kk++) { /* ------------------------------------------------------------------ */ /* one more pivot row and column is being stored into L and U */ /* ------------------------------------------------------------------ */ k = Work->npiv + kk ; /* ------------------------------------------------------------------ */ /* find the kth pivot row and pivot column */ /* ------------------------------------------------------------------ */ pivrow = Pivrow [kk] ; pivcol = Pivcol [kk] ; #ifndef NDEBUG ASSERT (pivrow >= 0 && pivrow < Work->n_row) ; ASSERT (pivcol >= 0 && pivcol < Work->n_col) ; DEBUGm4 (( "\n -------------------------------------------------------------" "Store LU: step " ID"\n", k)) ; ASSERT (k < MIN (Work->n_row, Work->n_col)) ; DEBUG2 (("Store column of L, k = "ID", llen "ID"\n", k, llen)) ; for (i = 0 ; i < llen ; i++) { row = Lpattern [i] ; ASSERT (row >= 0 && row < Work->n_row) ; DEBUG2 ((" Lpattern["ID"] "ID" Lpos "ID, i, row, Lpos [row])) ; if (row == pivrow) DEBUG2 ((" <- pivot row")) ; DEBUG2 (("\n")) ; ASSERT (i == Lpos [row]) ; } #endif /* ------------------------------------------------------------------ */ /* remove pivot row from L */ /* ------------------------------------------------------------------ */ /* remove pivot row index from current column of L */ /* if a new Lchain starts, then all entries are removed later */ DEBUG2 (("Removing pivrow from Lpattern, k = "ID"\n", k)) ; ASSERT (!NON_PIVOTAL_ROW (pivrow)) ; pivrow_position = Lpos [pivrow] ; if (pivrow_position != EMPTY) { /* place the last entry in the column in the */ /* position of the pivot row index */ ASSERT (pivrow == Lpattern [pivrow_position]) ; row = Lpattern [--llen] ; /* ASSERT (NON_PIVOTAL_ROW (row)) ; */ Lpattern [pivrow_position] = row ; Lpos [row] = pivrow_position ; Lpos [pivrow] = EMPTY ; } /* ------------------------------------------------------------------ */ /* store the pivot value, for the diagonal matrix D */ /* ------------------------------------------------------------------ */ /* kk-th column of LU block */ Fl1 = Flublock + kk * nb ; /* kk-th column of L in the L block */ Fl2 = Flblock + kk * fnr_curr ; /* kk-th pivot in frontal matrix located in Flublock [kk, kk] */ pivot_value = Fl1 [kk] ; D [k] = pivot_value ; zero_pivot = IS_ZERO (pivot_value) ; DEBUG4 (("Pivot D["ID"]=", k)) ; EDEBUG4 (pivot_value) ; DEBUG4 (("\n")) ; /* ------------------------------------------------------------------ */ /* count nonzeros in kth column of L */ /* ------------------------------------------------------------------ */ lnz = 0 ; lnz2i = 0 ; lnz2x = llen ; #ifdef DROP all_lnz = 0 ; for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; double s ; x = Fl1 [i] ; if (IS_ZERO (x)) continue ; all_lnz++ ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; lnz++ ; if (Lpos [Pivrow [i]] == EMPTY) lnz2i++ ; } for (i = 0 ; i < fnrows ; i++) { Entry x ; double s ; x = Fl2 [i] ; if (IS_ZERO (x)) continue ; all_lnz++ ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; lnz++ ; if (Lpos [Frows [i]] == EMPTY) lnz2i++ ; } #else for (i = kk + 1 ; i < fnpiv ; i++) { if (IS_ZERO (Fl1 [i])) continue ; lnz++ ; if (Lpos [Pivrow [i]] == EMPTY) lnz2i++ ; } for (i = 0 ; i < fnrows ; i++) { if (IS_ZERO (Fl2 [i])) continue ; lnz++ ; if (Lpos [Frows [i]] == EMPTY) lnz2i++ ; } #endif lnz2x += lnz2i ; /* determine if we start a new Lchain or continue the old one */ if (llen == 0 || zero_pivot) { /* llen == 0 means there is no prior Lchain */ /* D [k] == 0 means the pivot column is empty */ newLchain = TRUE ; } else { newLchain = /* storage for starting a new Lchain */ UNITS (Entry, lnz) + UNITS (Int, lnz) <= /* storage for continuing a prior Lchain */ UNITS (Entry, lnz2x) + UNITS (Int, lnz2i) ; } if (newLchain) { /* start a new chain for column k of L */ DEBUG2 (("Start new Lchain, k = "ID"\n", k)) ; pivrow_position = EMPTY ; /* clear the prior Lpattern */ for (i = 0 ; i < llen ; i++) { row = Lpattern [i] ; Lpos [row] = EMPTY ; } llen = 0 ; lnzi = lnz ; lnzx = lnz ; } else { /* continue the prior Lchain */ DEBUG2 (("Continue Lchain, k = "ID"\n", k)) ; lnzi = lnz2i ; lnzx = lnz2x ; } /* ------------------------------------------------------------------ */ /* allocate space for the column of L */ /* ------------------------------------------------------------------ */ size = UNITS (Int, lnzi) + UNITS (Entry, lnzx) ; #ifndef NDEBUG UMF_allocfail = FALSE ; if (UMF_gprob > 0) { double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ; UMF_allocfail = rrr < UMF_gprob ; if (UMF_allocfail) DEBUGm2 (("Random garbage coll. (store LU)\n")); } #endif p = UMF_mem_alloc_head_block (Numeric, size) ; if (!p) { Int r2, c2 ; /* Do garbage collection, realloc, and try again. */ /* Note that there are pivot rows/columns in current front. */ if (Work->do_grow) { /* full compaction of current frontal matrix, since * UMF_grow_front will be called next anyway. */ r2 = fnrows ; c2 = fncols ; } else { /* partial compaction. */ r2 = MAX (fnrows, Work->fnrows_new + 1) ; c2 = MAX (fncols, Work->fncols_new + 1) ; } DEBUGm3 (("get_memory from umf_store_lu:\n")) ; if (!UMF_get_memory (Numeric, Work, size, r2, c2, TRUE)) { DEBUGm4 (("out of memory: store LU (1)\n")) ; return (FALSE) ; /* out of memory */ } p = UMF_mem_alloc_head_block (Numeric, size) ; if (!p) { DEBUGm4 (("out of memory: store LU (2)\n")) ; return (FALSE) ; /* out of memory */ } /* garbage collection may have moved the current front */ fnc_curr = Work->fnc_curr ; fnr_curr = Work->fnr_curr ; Flublock = Work->Flublock ; Flblock = Work->Flblock ; Fublock = Work->Fublock ; Fl1 = Flublock + kk * nb ; Fl2 = Flblock + kk * fnr_curr ; } /* ------------------------------------------------------------------ */ /* store the column of L */ /* ------------------------------------------------------------------ */ lip = p ; Li = (Int *) (Numeric->Memory + p) ; p += UNITS (Int, lnzi) ; Lval = (Entry *) (Numeric->Memory + p) ; p += UNITS (Entry, lnzx) ; for (i = 0 ; i < lnzx ; i++) { CLEAR (Lval [i]) ; } /* store the numerical entries */ if (newLchain) { /* flag the first column in the Lchain by negating Lip [k] */ lip = -lip ; ASSERT (llen == 0) ; #ifdef DROP for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; double s ; Int row2, pos ; x = Fl1 [i] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; row2 = Pivrow [i] ; pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; Li [pos] = row2 ; Lval [pos] = x ; } for (i = 0 ; i < fnrows ; i++) { Entry x ; double s ; Int row2, pos ; x = Fl2 [i] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; row2 = Frows [i] ; pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; Li [pos] = row2 ; Lval [pos] = x ; } #else for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; Int row2, pos ; x = Fl1 [i] ; if (IS_ZERO (x)) continue ; row2 = Pivrow [i] ; pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; Li [pos] = row2 ; Lval [pos] = x ; } for (i = 0 ; i < fnrows ; i++) { Entry x ; Int row2, pos ; x = Fl2 [i] ; if (IS_ZERO (x)) continue ; row2 = Frows [i] ; pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; Li [pos] = row2 ; Lval [pos] = x ; } #endif } else { ASSERT (llen > 0) ; #ifdef DROP for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; double s ; Int row2, pos ; x = Fl1 [i] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; row2 = Pivrow [i] ; pos = Lpos [row2] ; if (pos == EMPTY) { pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; *Li++ = row2 ; } Lval [pos] = x ; } for (i = 0 ; i < fnrows ; i++) { Entry x ; double s ; Int row2, pos ; x = Fl2 [i] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; row2 = Frows [i] ; pos = Lpos [row2] ; if (pos == EMPTY) { pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; *Li++ = row2 ; } Lval [pos] = x ; } #else for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; Int row2, pos ; x = Fl1 [i] ; if (IS_ZERO (x)) continue ; row2 = Pivrow [i] ; pos = Lpos [row2] ; if (pos == EMPTY) { pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; *Li++ = row2 ; } Lval [pos] = x ; } for (i = 0 ; i < fnrows ; i++) { Entry x ; Int row2, pos ; x = Fl2 [i] ; if (IS_ZERO (x)) continue ; row2 = Frows [i] ; pos = Lpos [row2] ; if (pos == EMPTY) { pos = llen++ ; Lpattern [pos] = row2 ; Lpos [row2] = pos ; *Li++ = row2 ; } Lval [pos] = x ; } #endif } DEBUG4 (("llen "ID" lnzx "ID"\n", llen, lnzx)) ; ASSERT (llen == lnzx) ; ASSERT (lnz <= llen) ; DEBUG4 (("lnz "ID" \n", lnz)) ; #ifdef DROP DEBUG4 (("all_lnz "ID" \n", all_lnz)) ; ASSERT (lnz <= all_lnz) ; Numeric->lnz += lnz ; Numeric->all_lnz += all_lnz ; Lnz [kk] = all_lnz ; #else Numeric->lnz += lnz ; Numeric->all_lnz += lnz ; Lnz [kk] = lnz ; #endif Numeric->nLentries += lnzx ; Work->llen = llen ; Numeric->isize += lnzi ; /* ------------------------------------------------------------------ */ /* the pivot column is fully assembled and scaled, and is now the */ /* k-th column of L */ /* ------------------------------------------------------------------ */ Lpos [pivrow] = pivrow_position ; /* not aliased */ Lip [pivcol] = lip ; /* aliased with Col_tuples */ Lilen [pivcol] = lnzi ; /* aliased with Col_tlen */ } /* ---------------------------------------------------------------------- */ /* store the rows of U */ /* ---------------------------------------------------------------------- */ for (kk = 0 ; kk < fnpiv ; kk++) { /* ------------------------------------------------------------------ */ /* one more pivot row and column is being stored into L and U */ /* ------------------------------------------------------------------ */ k = Work->npiv + kk ; /* ------------------------------------------------------------------ */ /* find the kth pivot row and pivot column */ /* ------------------------------------------------------------------ */ pivrow = Pivrow [kk] ; pivcol = Pivcol [kk] ; #ifndef NDEBUG ASSERT (pivrow >= 0 && pivrow < Work->n_row) ; ASSERT (pivcol >= 0 && pivcol < Work->n_col) ; DEBUG2 (("Store row of U, k = "ID", ulen "ID"\n", k, ulen)) ; for (i = 0 ; i < ulen ; i++) { col = Upattern [i] ; DEBUG2 ((" Upattern["ID"] "ID, i, col)) ; if (col == pivcol) DEBUG2 ((" <- pivot col")) ; DEBUG2 (("\n")) ; ASSERT (col >= 0 && col < Work->n_col) ; ASSERT (i == Upos [col]) ; } #endif /* ------------------------------------------------------------------ */ /* get the pivot value, for the diagonal matrix D */ /* ------------------------------------------------------------------ */ zero_pivot = IS_ZERO (D [k]) ; /* ------------------------------------------------------------------ */ /* count the nonzeros in the row of U */ /* ------------------------------------------------------------------ */ /* kk-th row of U in the LU block */ Fu1 = Flublock + kk ; /* kk-th row of U in the U block */ Fu2 = Fublock + kk * fnc_curr ; unz = 0 ; unz2i = 0 ; unz2x = ulen ; DEBUG2 (("unz2x is "ID", lnzx "ID"\n", unz2x, lnzx)) ; /* if row k does not end a Uchain, pivcol not included in ulen */ ASSERT (!NON_PIVOTAL_COL (pivcol)) ; pivcol_position = Upos [pivcol] ; if (pivcol_position != EMPTY) { unz2x-- ; DEBUG2 (("(exclude pivcol) unz2x is now "ID"\n", unz2x)) ; } ASSERT (unz2x >= 0) ; #ifdef DROP all_unz = 0 ; for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; double s ; x = Fu1 [i*nb] ; if (IS_ZERO (x)) continue ; all_unz++ ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; unz++ ; if (Upos [Pivcol [i]] == EMPTY) unz2i++ ; } for (i = 0 ; i < fncols ; i++) { Entry x ; double s ; x = Fu2 [i] ; if (IS_ZERO (x)) continue ; all_unz++ ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; unz++ ; if (Upos [Fcols [i]] == EMPTY) unz2i++ ; } #else for (i = kk + 1 ; i < fnpiv ; i++) { if (IS_ZERO (Fu1 [i*nb])) continue ; unz++ ; if (Upos [Pivcol [i]] == EMPTY) unz2i++ ; } for (i = 0 ; i < fncols ; i++) { if (IS_ZERO (Fu2 [i])) continue ; unz++ ; if (Upos [Fcols [i]] == EMPTY) unz2i++ ; } #endif unz2x += unz2i ; ASSERT (IMPLIES (k == 0, ulen == 0)) ; /* determine if we start a new Uchain or continue the old one */ if (ulen == 0 || zero_pivot) { /* ulen == 0 means there is no prior Uchain */ /* D [k] == 0 means the matrix is singular (pivot row might */ /* not be empty, however, but start a new Uchain to prune zero */ /* entries for the deg > 0 test in UMF_u*solve) */ newUchain = TRUE ; } else { newUchain = /* approximate storage for starting a new Uchain */ UNITS (Entry, unz) + UNITS (Int, unz) <= /* approximate storage for continuing a prior Uchain */ UNITS (Entry, unz2x) + UNITS (Int, unz2i) ; /* this would be exact, except for the Int to Unit rounding, */ /* because the Upattern is stored only at the end of the Uchain */ } /* ------------------------------------------------------------------ */ /* allocate space for the row of U */ /* ------------------------------------------------------------------ */ size = 0 ; if (newUchain) { /* store the pattern of the last row in the prior Uchain */ size += UNITS (Int, ulen) ; unzx = unz ; } else { unzx = unz2x ; } size += UNITS (Entry, unzx) ; #ifndef NDEBUG UMF_allocfail = FALSE ; if (UMF_gprob > 0) { double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ; UMF_allocfail = rrr < UMF_gprob ; if (UMF_allocfail) DEBUGm2 (("Random garbage coll. (store LU)\n")); } #endif p = UMF_mem_alloc_head_block (Numeric, size) ; if (!p) { Int r2, c2 ; /* Do garbage collection, realloc, and try again. */ /* Note that there are pivot rows/columns in current front. */ if (Work->do_grow) { /* full compaction of current frontal matrix, since * UMF_grow_front will be called next anyway. */ r2 = fnrows ; c2 = fncols ; } else { /* partial compaction. */ r2 = MAX (fnrows, Work->fnrows_new + 1) ; c2 = MAX (fncols, Work->fncols_new + 1) ; } DEBUGm3 (("get_memory from umf_store_lu:\n")) ; if (!UMF_get_memory (Numeric, Work, size, r2, c2, TRUE)) { /* :: get memory, column of L :: */ DEBUGm4 (("out of memory: store LU (1)\n")) ; return (FALSE) ; /* out of memory */ } p = UMF_mem_alloc_head_block (Numeric, size) ; if (!p) { /* :: out of memory, column of U :: */ DEBUGm4 (("out of memory: store LU (2)\n")) ; return (FALSE) ; /* out of memory */ } /* garbage collection may have moved the current front */ fnc_curr = Work->fnc_curr ; fnr_curr = Work->fnr_curr ; Flublock = Work->Flublock ; Flblock = Work->Flblock ; Fublock = Work->Fublock ; Fu1 = Flublock + kk ; Fu2 = Fublock + kk * fnc_curr ; } /* ------------------------------------------------------------------ */ /* store the row of U */ /* ------------------------------------------------------------------ */ uip = p ; if (newUchain) { /* starting a new Uchain - flag this by negating Uip [k] */ uip = -uip ; DEBUG2 (("Start new Uchain, k = "ID"\n", k)) ; pivcol_position = EMPTY ; /* end the prior Uchain */ /* save the current Upattern, and then */ /* clear it and start a new Upattern */ DEBUG2 (("Ending prior chain, k-1 = "ID"\n", k-1)) ; uilen = ulen ; Ui = (Int *) (Numeric->Memory + p) ; Numeric->isize += ulen ; p += UNITS (Int, ulen) ; for (i = 0 ; i < ulen ; i++) { col = Upattern [i] ; ASSERT (col >= 0 && col < Work->n_col) ; Upos [col] = EMPTY ; Ui [i] = col ; } ulen = 0 ; } else { /* continue the prior Uchain */ DEBUG2 (("Continue Uchain, k = "ID"\n", k)) ; ASSERT (k > 0) ; /* remove pivot col index from current row of U */ /* if a new Uchain starts, then all entries are removed later */ DEBUG2 (("Removing pivcol from Upattern, k = "ID"\n", k)) ; if (pivcol_position != EMPTY) { /* place the last entry in the row in the */ /* position of the pivot col index */ ASSERT (pivcol == Upattern [pivcol_position]) ; col = Upattern [--ulen] ; ASSERT (col >= 0 && col < Work->n_col) ; Upattern [pivcol_position] = col ; Upos [col] = pivcol_position ; Upos [pivcol] = EMPTY ; } /* this row continues the Uchain. Keep track of how much */ /* to trim from the k-th length to get the length of the */ /* (k-1)st row of U */ uilen = unz2i ; } Uval = (Entry *) (Numeric->Memory + p) ; /* p += UNITS (Entry, unzx), no need to increment p */ for (i = 0 ; i < unzx ; i++) { CLEAR (Uval [i]) ; } if (newUchain) { ASSERT (ulen == 0) ; #ifdef DROP for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; double s ; Int col2, pos ; x = Fu1 [i*nb] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; col2 = Pivcol [i] ; pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; Uval [pos] = x ; } for (i = 0 ; i < fncols ; i++) { Entry x ; double s ; Int col2, pos ; x = Fu2 [i] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; col2 = Fcols [i] ; pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; Uval [pos] = x ; } #else for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; Int col2, pos ; x = Fu1 [i*nb] ; if (IS_ZERO (x)) continue ; col2 = Pivcol [i] ; pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; Uval [pos] = x ; } for (i = 0 ; i < fncols ; i++) { Entry x ; Int col2, pos ; x = Fu2 [i] ; if (IS_ZERO (x)) continue ; col2 = Fcols [i] ; pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; Uval [pos] = x ; } #endif } else { ASSERT (ulen > 0) ; /* store the numerical entries and find new nonzeros */ #ifdef DROP for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; double s ; Int col2, pos ; x = Fu1 [i*nb] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; col2 = Pivcol [i] ; pos = Upos [col2] ; if (pos == EMPTY) { pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; } Uval [pos] = x ; } for (i = 0 ; i < fncols ; i++) { Entry x ; double s ; Int col2, pos ; x = Fu2 [i] ; APPROX_ABS (s, x) ; if (s <= droptol) continue ; col2 = Fcols [i] ; pos = Upos [col2] ; if (pos == EMPTY) { pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; } Uval [pos] = x ; } #else for (i = kk + 1 ; i < fnpiv ; i++) { Entry x ; Int col2, pos ; x = Fu1 [i*nb] ; if (IS_ZERO (x)) continue ; col2 = Pivcol [i] ; pos = Upos [col2] ; if (pos == EMPTY) { pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; } Uval [pos] = x ; } for (i = 0 ; i < fncols ; i++) { Entry x ; Int col2, pos ; x = Fu2 [i] ; if (IS_ZERO (x)) continue ; col2 = Fcols [i] ; pos = Upos [col2] ; if (pos == EMPTY) { pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; } Uval [pos] = x ; } #endif } ASSERT (ulen == unzx) ; ASSERT (unz <= ulen) ; DEBUG4 (("unz "ID" \n", unz)) ; #ifdef DROP DEBUG4 (("all_unz "ID" \n", all_unz)) ; ASSERT (unz <= all_unz) ; Numeric->unz += unz ; Numeric->all_unz += all_unz ; /* count the "true" flops, based on LU pattern only */ Numeric->flops += DIV_FLOPS * Lnz [kk] /* scale pivot column */ + MULTSUB_FLOPS * (Lnz [kk] * all_unz) ; /* outer product */ #else Numeric->unz += unz ; Numeric->all_unz += unz ; /* count the "true" flops, based on LU pattern only */ Numeric->flops += DIV_FLOPS * Lnz [kk] /* scale pivot column */ + MULTSUB_FLOPS * (Lnz [kk] * unz) ; /* outer product */ #endif Numeric->nUentries += unzx ; Work->ulen = ulen ; DEBUG1 (("Work->ulen = "ID" at end of pivot step, k: "ID"\n", ulen, k)); /* ------------------------------------------------------------------ */ /* the pivot row is the k-th row of U */ /* ------------------------------------------------------------------ */ Upos [pivcol] = pivcol_position ; /* not aliased */ Uip [pivrow] = uip ; /* aliased with Row_tuples */ Uilen [pivrow] = uilen ; /* aliased with Row_tlen */ } /* ---------------------------------------------------------------------- */ /* no more pivots in frontal working array */ /* ---------------------------------------------------------------------- */ Work->npiv += fnpiv ; Work->fnpiv = 0 ; Work->fnzeros = 0 ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_triplet.c0000644000175000017500000000457111674452555024611 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints a matrix in triplet form. See umfpack_report_triplet.h for details. */ #include "umf_internal.h" GLOBAL Int UMFPACK_report_triplet ( Int n_row, Int n_col, Int nz, const Int Ti [ ], const Int Tj [ ], const double Tx [ ], #ifdef COMPLEX const double Tz [ ], #endif const double Control [UMFPACK_CONTROL] ) { Entry t ; Int prl, prl1, k, i, j, do_values ; #ifdef COMPLEX Int split = SPLIT (Tz) ; #endif prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl <= 2) { return (UMFPACK_OK) ; } PRINTF (("triplet-form matrix, n_row = "ID", n_col = "ID" nz = "ID". ", n_row, n_col, nz)) ; if (!Ti || !Tj) { PRINTF (("ERROR: indices not present\n\n")) ; return (UMFPACK_ERROR_argument_missing) ; } if (n_row <= 0 || n_col <= 0) { PRINTF (("ERROR: n_row or n_col is <= 0\n\n")) ; return (UMFPACK_ERROR_n_nonpositive) ; } if (nz < 0) { PRINTF (("ERROR: nz is < 0\n\n")) ; return (UMFPACK_ERROR_invalid_matrix) ; } PRINTF4 (("\n")) ; do_values = Tx != (double *) NULL ; prl1 = prl ; for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; PRINTF4 ((" "ID" : "ID" "ID" ", INDEX (k), INDEX (i), INDEX (j))) ; if (do_values && prl >= 4) { ASSIGN (t, Tx, Tz, k, split) ; PRINT_ENTRY (t) ; } PRINTF4 (("\n")) ; if (i < 0 || i >= n_row || j < 0 || j >= n_col) { /* invalid triplet */ PRINTF (("ERROR: invalid triplet\n\n")) ; return (UMFPACK_ERROR_invalid_matrix) ; } if (prl == 4 && k == 9 && nz > 10) { PRINTF ((" ...\n")) ; prl-- ; } } prl = prl1 ; PRINTF4 ((" triplet-form matrix ")) ; PRINTF (("OK\n\n")) ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.h0000644000175000017500000000112611674452555022373 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL double UMF_utsolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; GLOBAL double UMF_uhsolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_numeric.c0000644000175000017500000004161711674452555024572 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_numeric =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints the Numeric object. See umfpack_report_numeric.h for details. Dynamic memory usage: Allocates a size n*sizeof(Int) workspace via a single call to UMF_malloc and then frees all of it via UMF_free on return. The workspace is not allocated if an early error return occurs before the workspace is needed. */ #include "umf_internal.h" #include "umf_valid_numeric.h" #include "umf_report_perm.h" #include "umf_report_vector.h" #include "umf_malloc.h" #include "umf_free.h" PRIVATE Int report_L ( NumericType *Numeric, Int Pattern [ ], Int prl ) ; PRIVATE Int report_U ( NumericType *Numeric, Int Pattern [ ], Int prl ) ; /* ========================================================================== */ /* === UMFPACK_report_numeric =============================================== */ /* ========================================================================== */ GLOBAL Int UMFPACK_report_numeric ( void *NumericHandle, const double Control [UMFPACK_CONTROL] ) { Int prl, *W, nn, n_row, n_col, n_inner, num_fixed_size, numeric_size, npiv ; NumericType *Numeric ; prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl <= 2) { return (UMFPACK_OK) ; } PRINTF (("Numeric object: ")) ; Numeric = (NumericType *) NumericHandle ; if (!UMF_valid_numeric (Numeric)) { PRINTF (("ERROR: LU factors invalid\n\n")) ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } n_row = Numeric->n_row ; n_col = Numeric->n_col ; nn = MAX (n_row, n_col) ; n_inner = MIN (n_row, n_col) ; npiv = Numeric->npiv ; DEBUG1 (("n_row "ID" n_col "ID" nn "ID" n_inner "ID" npiv "ID"\n", n_row, n_col, nn, n_inner, npiv)) ; /* size of Numeric object, except Numeric->Memory and Numeric->Upattern */ /* see also UMF_set_stats */ num_fixed_size = UNITS (NumericType, 1) /* Numeric structure */ + UNITS (Entry, n_inner+1) /* D */ + UNITS (Int, n_row+1) /* Rperm */ + UNITS (Int, n_col+1) /* Cperm */ + 6 * UNITS (Int, npiv+1) /* Lpos, Uilen, Uip, Upos, Lilen, Lip */ + ((Numeric->scale != UMFPACK_SCALE_NONE) ? UNITS (Entry, n_row) : 0) ; /* Rs */ DEBUG1 (("num fixed size: "ID"\n", num_fixed_size)) ; DEBUG1 (("Numeric->size "ID"\n", Numeric->size)) ; DEBUG1 (("ulen units "ID"\n", UNITS (Int, Numeric->ulen))) ; /* size of Numeric->Memory is Numeric->size */ /* size of Numeric->Upattern is Numeric->ulen */ numeric_size = num_fixed_size + Numeric->size + UNITS (Int, Numeric->ulen) ; DEBUG1 (("numeric total size "ID"\n", numeric_size)) ; if (prl >= 4) { PRINTF (("\n n_row: "ID" n_col: "ID"\n", n_row, n_col)) ; PRINTF ((" relative pivot tolerance used: %g\n", Numeric->relpt)) ; PRINTF ((" relative symmetric pivot tolerance used: %g\n", Numeric->relpt2)) ; PRINTF ((" matrix scaled: ")) ; if (Numeric->scale == UMFPACK_SCALE_NONE) { PRINTF (("no")) ; } else if (Numeric->scale == UMFPACK_SCALE_SUM) { PRINTF (("yes (divided each row by sum abs value in each row)\n")) ; PRINTF ((" minimum sum (abs (rows of A)): %.5e\n", Numeric->rsmin)) ; PRINTF ((" maximum sum (abs (rows of A)): %.5e", Numeric->rsmax)) ; } else if (Numeric->scale == UMFPACK_SCALE_MAX) { PRINTF (("yes (divided each row by max abs value in each row)\n")) ; PRINTF ((" minimum max (abs (rows of A)): %.5e\n", Numeric->rsmin)) ; PRINTF ((" maximum max (abs (rows of A)): %.5e", Numeric->rsmax)) ; } PRINTF (("\n")) ; PRINTF ((" initial allocation parameter used: %g\n", Numeric->alloc_init)) ; PRINTF ((" frontal matrix allocation parameter used: %g\n", Numeric->front_alloc_init)) ; PRINTF ((" final total size of Numeric object (Units): "ID"\n", numeric_size)) ; PRINTF ((" final total size of Numeric object (MBytes): %.1f\n", MBYTES (numeric_size))) ; PRINTF ((" peak size of variable-size part (Units): "ID"\n", Numeric->max_usage)) ; PRINTF ((" peak size of variable-size part (MBytes): %.1f\n", MBYTES (Numeric->max_usage))) ; PRINTF ((" largest actual frontal matrix size: "ID"\n", Numeric->maxfrsize)) ; PRINTF ((" memory defragmentations: "ID"\n", Numeric->ngarbage)) ; PRINTF ((" memory reallocations: "ID"\n", Numeric->nrealloc)) ; PRINTF ((" costly memory reallocations: "ID"\n", Numeric->ncostly)) ; PRINTF ((" entries in compressed pattern (L and U): "ID"\n", Numeric->isize)) ; PRINTF ((" number of nonzeros in L (excl diag): "ID"\n", Numeric->lnz)) ; PRINTF ((" number of entries stored in L (excl diag): "ID"\n", Numeric->nLentries)) ; PRINTF ((" number of nonzeros in U (excl diag): "ID"\n", Numeric->unz)) ; PRINTF ((" number of entries stored in U (excl diag): "ID"\n", Numeric->nUentries)) ; PRINTF ((" factorization floating-point operations: %g\n", Numeric->flops)) ; PRINTF ((" number of nonzeros on diagonal of U: "ID"\n", Numeric->nnzpiv)) ; PRINTF ((" min abs. value on diagonal of U: %.5e\n", Numeric->min_udiag)) ; PRINTF ((" max abs. value on diagonal of U: %.5e\n", Numeric->max_udiag)) ; PRINTF ((" reciprocal condition number estimate: %.2e\n", Numeric->rcond)) ; } W = (Int *) UMF_malloc (nn, sizeof (Int)) ; if (!W) { PRINTF ((" ERROR: out of memory to check Numeric object\n\n")) ; return (UMFPACK_ERROR_out_of_memory) ; } if (Numeric->Rs) { #ifndef NRECIPROCAL if (Numeric->do_recip) { PRINTF4 (("\nScale factors applied via multiplication\n")) ; } else #endif { PRINTF4 (("\nScale factors applied via division\n")) ; } PRINTF4 (("Scale factors, Rs: ")) ; (void) UMF_report_vector (n_row, Numeric->Rs, (double *) NULL, prl, FALSE, TRUE) ; } else { PRINTF4 (("Scale factors, Rs: (not present)\n")) ; } PRINTF4 (("\nP: row ")) ; if (UMF_report_perm (n_row, Numeric->Rperm, W, prl, 0) != UMFPACK_OK) { (void) UMF_free ((void *) W) ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } PRINTF4 (("\nQ: column ")) ; if (UMF_report_perm (n_col, Numeric->Cperm, W, prl, 0) != UMFPACK_OK) { (void) UMF_free ((void *) W) ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } if (!report_L (Numeric, W, prl)) { (void) UMF_free ((void *) W) ; PRINTF ((" ERROR: L factor invalid\n\n")) ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } if (!report_U (Numeric, W, prl)) { (void) UMF_free ((void *) W) ; PRINTF ((" ERROR: U factor invalid\n\n")) ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } /* The diagonal of U is in "merged" (Entry) form, not "split" form. */ PRINTF4 (("\ndiagonal of U: ")) ; (void) UMF_report_vector (n_inner, (double *) Numeric->D, (double *) NULL, prl, FALSE, FALSE) ; (void) UMF_free ((void *) W) ; PRINTF4 ((" Numeric object: ")) ; PRINTF (("OK\n\n")) ; return (UMFPACK_OK) ; } /* ========================================================================== */ /* === report_L ============================================================= */ /* ========================================================================== */ PRIVATE Int report_L ( NumericType *Numeric, Int Pattern [ ], Int prl ) { Int k, deg, *ip, j, row, n_row, *Lpos, *Lilen, valid, k1, *Lip, newLchain, llen, prl1, pos, lp, p, npiv, n1, *Li ; Entry *xp, *Lval ; /* ---------------------------------------------------------------------- */ ASSERT (prl >= 3) ; n_row = Numeric->n_row ; npiv = Numeric->npiv ; n1 = Numeric->n1 ; Lpos = Numeric->Lpos ; Lilen = Numeric->Lilen ; Lip = Numeric->Lip ; prl1 = prl ; deg = 0 ; PRINTF4 (( "\nL in Numeric object, in column-oriented compressed-pattern form:\n" " Diagonal entries are all equal to 1.0 (not stored)\n")) ; ASSERT (Pattern != (Int *) NULL) ; /* ---------------------------------------------------------------------- */ /* print L */ /* ---------------------------------------------------------------------- */ k1 = 12 ; /* ---------------------------------------------------------------------- */ /* print the singleton columns of L */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n1 ; k++) { if (k1 > 0) { prl = prl1 ; } lp = Lip [k] ; deg = Lilen [k] ; Li = (Int *) (Numeric->Memory + lp) ; lp += UNITS (Int, deg) ; Lval = (Entry *) (Numeric->Memory + lp) ; if (k1-- > 0) { prl = prl1 ; } else if (prl == 4) { PRINTF ((" ...\n")) ; prl-- ; } PRINTF4 (("\n column "ID":", INDEX (k))) ; PRINTF4 ((" length "ID".\n", deg)) ; for (j = 0 ; j < deg ; j++) { row = Li [j] ; PRINTF4 (("\trow "ID" : ", INDEX (row))) ; if (prl >= 4) PRINT_ENTRY (Lval [j]) ; if (row <= k || row >= n_row) { return (FALSE) ; } PRINTF4 (("\n")) ; /* truncate printout, but continue to check L */ if (prl == 4 && j == 9 && deg > 10) { PRINTF (("\t...\n")) ; prl-- ; } } } /* ---------------------------------------------------------------------- */ /* print the regular columns of L */ /* ---------------------------------------------------------------------- */ for (k = n1 ; k < npiv ; k++) { /* if prl is 4, print the first 10 entries of the first 10 columns */ if (k1 > 0) { prl = prl1 ; } lp = Lip [k] ; newLchain = (lp < 0) ; if (newLchain) { lp = -lp ; deg = 0 ; } if (k1-- > 0) { prl = prl1 ; } else if (prl == 4) { PRINTF ((" ...\n")) ; prl-- ; } PRINTF4 (("\n column "ID":", INDEX (k))) ; /* ------------------------------------------------------------------ */ /* make column of L in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ /* remove pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { PRINTF4 ((" remove row "ID" at position "ID".", INDEX (Pattern [pos]), INDEX (pos))) ; valid = (!newLchain) && (deg > 0) && (pos < deg) && (pos >= 0) && (Pattern [pos] == k) ; if (!valid) { return (FALSE) ; } Pattern [pos] = Pattern [--deg] ; } /* concatenate the pattern */ llen = Lilen [k] ; if (llen < 0) { return (FALSE) ; } p = lp + UNITS (Int, llen) ; xp = (Entry *) (Numeric->Memory + p) ; if ((llen > 0 || deg > 0) && (p + (Int) UNITS (Entry, deg) > Numeric->size)) { return (FALSE) ; } if (llen > 0) { PRINTF4 ((" add "ID" entries.", llen)) ; ip = (Int *) (Numeric->Memory + lp) ; for (j = 0 ; j < llen ; j++) { Pattern [deg++] = *ip++ ; } } /* ------------------------------------------------------------------ */ /* print column k of L */ /* ------------------------------------------------------------------ */ PRINTF4 ((" length "ID".", deg)) ; if (newLchain) { PRINTF4 ((" Start of Lchain.")) ; } PRINTF4 (("\n")) ; for (j = 0 ; j < deg ; j++) { row = Pattern [j] ; PRINTF4 (("\trow "ID" : ", INDEX (row))) ; if (prl >= 4) PRINT_ENTRY (*xp) ; if (row <= k || row >= n_row) { return (FALSE) ; } PRINTF4 (("\n")) ; xp++ ; /* truncate printout, but continue to check L */ if (prl == 4 && j == 9 && deg > 10) { PRINTF (("\t...\n")) ; prl-- ; } } } PRINTF4 (("\n")) ; return (TRUE) ; } /* ========================================================================== */ /* === report_U ============================================================= */ /* ========================================================================== */ PRIVATE Int report_U ( NumericType *Numeric, Int Pattern [ ], Int prl ) { /* ---------------------------------------------------------------------- */ Int k, deg, j, *ip, col, *Upos, *Uilen, k1, prl1, pos, *Uip, n_col, ulen, p, newUchain, up, npiv, n1, *Ui ; Entry *xp, *Uval ; /* ---------------------------------------------------------------------- */ ASSERT (prl >= 3) ; n_col = Numeric->n_col ; npiv = Numeric->npiv ; n1 = Numeric->n1 ; Upos = Numeric->Upos ; Uilen = Numeric->Uilen ; Uip = Numeric->Uip ; prl1 = prl ; PRINTF4 (( "\nU in Numeric object, in row-oriented compressed-pattern form:\n" " Diagonal is stored separately.\n")) ; ASSERT (Pattern != (Int *) NULL) ; k1 = 12 ; /* ---------------------------------------------------------------------- */ /* print the sparse part of U */ /* ---------------------------------------------------------------------- */ deg = Numeric->ulen ; if (deg > 0) { /* make last pivot row of U (singular matrices only) */ for (j = 0 ; j < deg ; j++) { Pattern [j] = Numeric->Upattern [j] ; } } PRINTF4 (("\n row "ID": length "ID". End of Uchain.\n", INDEX (npiv-1), deg)) ; for (k = npiv-1 ; k >= n1 ; k--) { /* ------------------------------------------------------------------ */ /* print row k of U */ /* ------------------------------------------------------------------ */ /* if prl is 3, print the first 10 entries of the first 10 columns */ if (k1 > 0) { prl = prl1 ; } up = Uip [k] ; ulen = Uilen [k] ; if (ulen < 0) { return (FALSE) ; } newUchain = (up < 0) ; if (newUchain) { up = -up ; p = up + UNITS (Int, ulen) ; } else { p = up ; } xp = (Entry *) (Numeric->Memory + p) ; if (deg > 0 && (p + (Int) UNITS (Entry, deg) > Numeric->size)) { return (FALSE) ; } for (j = 0 ; j < deg ; j++) { col = Pattern [j] ; PRINTF4 (("\tcol "ID" :", INDEX (col))) ; if (prl >= 4) PRINT_ENTRY (*xp) ; if (col <= k || col >= n_col) { return (FALSE) ; } PRINTF4 (("\n")) ; xp++ ; /* truncate printout, but continue to check U */ if (prl == 4 && j == 9 && deg > 10) { PRINTF (("\t...\n")) ; prl-- ; } } /* ------------------------------------------------------------------ */ /* make row k-1 of U in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ if (k1-- > 0) { prl = prl1 ; } else if (prl == 4) { PRINTF ((" ...\n")) ; prl-- ; } if (k > 0) { PRINTF4 (("\n row "ID": ", INDEX (k-1))) ; } if (newUchain) { /* next row is a new Uchain */ if (k > 0) { deg = ulen ; PRINTF4 (("length "ID". End of Uchain.\n", deg)) ; if (up + (Int) UNITS (Int, ulen) > Numeric->size) { return (FALSE) ; } ip = (Int *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { Pattern [j] = *ip++ ; } } } else { if (ulen > 0) { PRINTF4 (("remove "ID" entries. ", ulen)) ; } deg -= ulen ; if (deg < 0) { return (FALSE) ; } pos = Upos [k] ; if (pos != EMPTY) { /* add the pivot column */ PRINTF4 (("add column "ID" at position "ID". ", INDEX (k), INDEX (pos))) ; if (pos < 0 || pos > deg) { return (FALSE) ; } Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } PRINTF4 (("length "ID".\n", deg)) ; } } /* ---------------------------------------------------------------------- */ /* print the singleton rows of U */ /* ---------------------------------------------------------------------- */ for (k = n1 - 1 ; k >= 0 ; k--) { if (k1 > 0) { prl = prl1 ; } up = Uip [k] ; deg = Uilen [k] ; Ui = (Int *) (Numeric->Memory + up) ; up += UNITS (Int, deg) ; Uval = (Entry *) (Numeric->Memory + up) ; if (k1-- > 0) { prl = prl1 ; } else if (prl == 4) { PRINTF ((" ...\n")) ; prl-- ; } PRINTF4 (("\n row "ID":", INDEX (k))) ; PRINTF4 ((" length "ID".\n", deg)) ; for (j = 0 ; j < deg ; j++) { col = Ui [j] ; PRINTF4 (("\tcol "ID" : ", INDEX (col))) ; if (prl >= 4) PRINT_ENTRY (Uval [j]) ; if (col <= k || col >= n_col) { return (FALSE) ; } PRINTF4 (("\n")) ; /* truncate printout, but continue to check U */ if (prl == 4 && j == 9 && deg > 10) { PRINTF (("\t...\n")) ; prl-- ; } } } prl = prl1 ; PRINTF4 (("\n")) ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_perm.c0000644000175000017500000000263711674452555024072 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_perm ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints a permutation vector. See umfpack_report_perm.h for details. Dynamic memory usage: Allocates a size max(np,1)*sizeof(Int) workspace via a single call to UMF_malloc and then frees all of it via UMF_free on return. */ #include "umf_internal.h" #include "umf_report_perm.h" #include "umf_malloc.h" #include "umf_free.h" GLOBAL Int UMFPACK_report_perm ( Int np, const Int Perm [ ], const double Control [UMFPACK_CONTROL] ) { Int prl, *W, status ; prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl <= 2) { return (UMFPACK_OK) ; } W = (Int *) UMF_malloc (MAX (np,1), sizeof (Int)) ; status = UMF_report_perm (np, Perm, W, prl, 1) ; (void) UMF_free ((void *) W) ; return (status) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.h0000644000175000017500000000074511674452555023377 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_extend_front ( NumericType *Numeric, WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.c0000644000175000017500000000274111674452555023733 0ustar sonnesonne/* ========================================================================== */ /* === UMF_is_permutation =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Return TRUE if P is a r-permutation vector, FALSE otherwise */ /* P [0..r-1] must be an r-permutation of 0..n-1 */ #include "umf_internal.h" #include "umf_is_permutation.h" GLOBAL Int UMF_is_permutation ( const Int P [ ], /* permutation of size r */ Int W [ ], /* workspace of size n */ Int n, Int r ) { Int i, k ; if (!P) { /* if P is (Int *) NULL, this is the identity permutation */ return (TRUE) ; } ASSERT (W != (Int *) NULL) ; for (i = 0 ; i < n ; i++) { W [i] = FALSE ; } for (k = 0 ; k < r ; k++) { i = P [k] ; DEBUG5 (("k "ID" i "ID"\n", k, i)) ; if (i < 0 || i >= n) { DEBUG0 (("i out of range "ID" "ID"\n", i, n)) ; return (FALSE) ; } if (W [i]) { DEBUG0 (("i duplicate "ID"\n", i)) ; return (FALSE) ; } W [i] = TRUE ; } return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_scale.h0000644000175000017500000000073611674452555021767 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_scale ( Int n, Entry alpha, Entry X [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_symbolic.c0000644000175000017500000001565311674452555024752 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_symbolic ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints the Symbolic object. See umfpack_report_symbolic.h for details. Not all of the object is printed. Dynamic memory usage: Allocates a size MAX (n_row,n_col)*sizeof(Int) workspace via a single call to UMF_malloc and then frees all of it via UMF_free on return. The workspace is not allocated if an early error return occurs before the workspace is needed. */ #include "umf_internal.h" #include "umf_valid_symbolic.h" #include "umf_report_perm.h" #include "umf_malloc.h" #include "umf_free.h" GLOBAL Int UMFPACK_report_symbolic ( void *SymbolicHandle, const double Control [UMFPACK_CONTROL] ) { Int n_row, n_col, nz, nchains, nfr, maxnrows, maxncols, prl, k, chain, frontid, frontid1, frontid2, kk, *Chain_start, *W, *Chain_maxrows, *Chain_maxcols, *Front_npivcol, *Front_1strow, *Front_leftmostdesc, *Front_parent, done, status1, status2 ; SymbolicType *Symbolic ; prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl <= 2) { return (UMFPACK_OK) ; } PRINTF (("Symbolic object: ")) ; Symbolic = (SymbolicType *) SymbolicHandle ; if (!UMF_valid_symbolic (Symbolic)) { PRINTF (("ERROR: invalid\n")) ; return (UMFPACK_ERROR_invalid_Symbolic_object) ; } n_row = Symbolic->n_row ; n_col = Symbolic->n_col ; nz = Symbolic->nz ; nchains = Symbolic->nchains ; nfr = Symbolic->nfr ; maxnrows = Symbolic->maxnrows ; maxncols = Symbolic->maxncols ; Chain_start = Symbolic->Chain_start ; Chain_maxrows = Symbolic->Chain_maxrows ; Chain_maxcols = Symbolic->Chain_maxcols ; Front_npivcol = Symbolic->Front_npivcol ; Front_1strow = Symbolic->Front_1strow ; Front_leftmostdesc = Symbolic->Front_leftmostdesc ; Front_parent = Symbolic->Front_parent ; if (prl >= 4) { PRINTF (("\n matrix to be factorized:\n")) ; PRINTF (("\tn_row: "ID" n_col: "ID"\n", n_row, n_col)) ; PRINTF (("\tnumber of entries: "ID"\n", nz)) ; PRINTF ((" block size used for dense matrix kernels: "ID"\n", Symbolic->nb)) ; PRINTF ((" strategy used: ")) ; /* strategy cannot be auto */ if (Symbolic->strategy == UMFPACK_STRATEGY_SYMMETRIC) { PRINTF (("symmetric")) ; } else /* if (Symbolic->strategy == UMFPACK_STRATEGY_UNSYMMETRIC) */ { PRINTF (("unsymmetric")) ; } #if 0 else if (Symbolic->strategy == UMFPACK_STRATEGY_2BY2) { PRINTF (("symmetric 2-by-2")) ; } #endif PRINTF (("\n")) ; PRINTF ((" ordering used: ")) ; if (Symbolic->ordering == UMFPACK_ORDERING_COLAMD) { PRINTF (("colamd on A\n")) ; } else if (Symbolic->ordering == UMFPACK_ORDERING_AMD) { PRINTF (("amd on A+A'\n")) ; } else if (Symbolic->ordering == UMFPACK_ORDERING_GIVEN) { PRINTF (("provided by user")) ; } PRINTF (("\n")) ; PRINTF ((" performn column etree postorder: ")) ; if (Symbolic->fixQ) { PRINTF (("no\n")) ; } else { PRINTF (("yes\n")) ; } PRINTF ((" prefer diagonal pivoting (attempt P=Q): ")) ; if (Symbolic->prefer_diagonal) { PRINTF (("yes\n")) ; } else { PRINTF (("no\n")) ; } PRINTF ((" variable-size part of Numeric object:\n")) ; PRINTF (("\tminimum initial size (Units): %.20g (MBytes): %.1f\n", Symbolic->dnum_mem_init_usage, MBYTES (Symbolic->dnum_mem_init_usage))) ; PRINTF (("\testimated peak size (Units): %.20g (MBytes): %.1f\n", Symbolic->num_mem_usage_est, MBYTES (Symbolic->num_mem_usage_est))) ; PRINTF (("\testimated final size (Units): %.20g (MBytes): %.1f\n", Symbolic->num_mem_size_est, MBYTES (Symbolic->num_mem_size_est))) ; PRINTF ((" symbolic factorization memory usage (Units):" " %.20g (MBytes): %.1f\n", Symbolic->peak_sym_usage, MBYTES (Symbolic->peak_sym_usage))) ; PRINTF ((" frontal matrices / supercolumns:\n")) ; PRINTF (("\tnumber of frontal chains: "ID"\n", nchains)) ; PRINTF (("\tnumber of frontal matrices: "ID"\n", nfr)) ; PRINTF (("\tlargest frontal matrix row dimension: "ID"\n", maxnrows)) ; PRINTF (("\tlargest frontal matrix column dimension: "ID"\n",maxncols)); } k = 0 ; done = FALSE ; for (chain = 0 ; chain < nchains ; chain++) { frontid1 = Chain_start [chain] ; frontid2 = Chain_start [chain+1] - 1 ; PRINTF4 (("\n Frontal chain: "ID". Frontal matrices "ID" to "ID"\n", INDEX (chain), INDEX (frontid1), INDEX (frontid2))) ; PRINTF4 (("\tLargest frontal matrix in Frontal chain: "ID"-by-"ID"\n", Chain_maxrows [chain], Chain_maxcols [chain])) ; for (frontid = frontid1 ; frontid <= frontid2 ; frontid++) { kk = Front_npivcol [frontid] ; PRINTF4 (("\tFront: "ID" pivot cols: "ID" (pivot columns "ID" to " ID")\n", INDEX (frontid), kk, INDEX (k), INDEX (k+kk-1))) ; PRINTF4 (("\t pivot row candidates: "ID" to "ID"\n", INDEX (Front_1strow [Front_leftmostdesc [frontid]]), INDEX (Front_1strow [frontid+1]-1))) ; PRINTF4 (("\t leftmost descendant: "ID"\n", INDEX (Front_leftmostdesc [frontid]))) ; PRINTF4 (("\t 1st new candidate row : "ID"\n", INDEX (Front_1strow [frontid]))) ; PRINTF4 (("\t parent:")) ; if (Front_parent [frontid] == EMPTY) { PRINTF4 ((" (none)\n")) ; } else { PRINTF4 ((" "ID"\n", INDEX (Front_parent [frontid]))) ; } done = (frontid == 20 && frontid < nfr-1 && prl == 4) ; if (done) { PRINTF4 (("\t...\n")) ; break ; } k += kk ; } if (Front_npivcol [nfr] != 0) { PRINTF4 (("\tFront: "ID" placeholder for "ID" empty columns\n", INDEX (nfr), Front_npivcol [nfr])) ; } if (done) { break ; } } W = (Int *) UMF_malloc (MAX (n_row, n_col), sizeof (Int)) ; if (!W) { PRINTF (("ERROR: out of memory to check Symbolic object\n\n")) ; return (UMFPACK_ERROR_out_of_memory) ; } PRINTF4 (("\nInitial column permutation, Q1: ")) ; status1 = UMF_report_perm (n_col, Symbolic->Cperm_init, W, prl, 0) ; PRINTF4 (("\nInitial row permutation, P1: ")) ; status2 = UMF_report_perm (n_row, Symbolic->Rperm_init, W, prl, 0) ; (void) UMF_free ((void *) W) ; if (status1 != UMFPACK_OK || status2 != UMFPACK_OK) { return (UMFPACK_ERROR_invalid_Symbolic_object) ; } PRINTF4 ((" Symbolic object: ")) ; PRINTF (("OK\n\n")) ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.h0000644000175000017500000000077211674452555023555 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_tuple_lengths ( NumericType *Numeric, WorkType *Work, double *dusage ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.h0000644000175000017500000000074611674452555023345 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_scale_column ( NumericType *Numeric, WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.h0000644000175000017500000000071411674452555023242 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_blas3_update ( WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_multicompile.c0000644000175000017500000000421711674452555023374 0ustar sonnesonne/* ========================================================================== */ /* === UMF_multicompile ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* This file is not needed if you have the Unix/Linux "make" command for * compiling UMFPACK. Microsoft Visual Studio cannot be configured to compile * one file multiple times, with different -D flags. In this case, you can * use this file instead. To use this file, see the Demo/simple_compile file. * * This file includes the following source files: * * umf_ltsolve.c * umf_utsolve.c * umf_triplet.c * umf_assemble.c * umf_store_lu.c * umfpack_solve.c * * This file simply compiles the above files with different pre-#define'd flags, * by defining the flags and then #include'ing the source files themselves. * This is a rather unconventional approach, since by convention #include is * supposed to be used with *.h files not *.c. However, it is one way of * working around the limitations of Microsoft Visual Studio. * * You still need to compile all files separately as well, with none of the * pre-#define'd terms listed below. */ /* compile the complex conjugate forward/backsolves */ #define CONJUGATE_SOLVE #include "umf_ltsolve.c" #include "umf_utsolve.c" /* compile umf_triplet with DO_MAP, DO_VALUES and DO_MAP, and just DO_VALUES */ #define DO_MAP #include "umf_triplet.c" #define DO_VALUES #include "umf_triplet.c" #undef DO_MAP #include "umf_triplet.c" /* compile the FIXQ version of umf_assemble */ #define FIXQ #include "umf_assemble.c" /* compile the DROP version of umf_store_lu */ #define DROP #include "umf_store_lu.c" /* compile umfpack_wsolve */ #define WSOLVE #include "umfpack_solve.c" cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.c0000644000175000017500000005630011674452555021447 0ustar sonnesonne/* ========================================================================== */ /* === UMF_2by2 ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* NOTE: this code is currently disabled */ /* Not user-callable. Computes a row permutation P so that A (P,:) has a * mostly zero-free diagonal, with large entries on the diagonal. It does this * by swapping pairs of rows. Once a row is swapped it is not swapped again. * This is a "cheap" assignment, not a complete max. transversal or * bi-partite matching. It is only a partial matching. For most matrices * for which this algorithm is used, however, the matching is complete (in * UMFPACK this algorithm is used for matrices with roughly symmetric pattern, * and these matrices typically have a mostly-zero-free diagonal to begin with. * This algorithm is not meant to be used on arbitrary unsymmetric matrices * (for those matrices, UMFPACK uses its unsymmetric strategy and does not * use this algorithm). * * Even if incomplete, the matching is usually good enough for UMFPACK's * symmetric strategy, which can easily pivot off the diagonal during numerical * factorization if it finds a weak diagonal entry. * * The algorithms works as follows. First, row scaling factors are computed, * and weak diagonal entries are found. A weak entry is a value A(k,k) whose * absolute value is < tol * max (abs (A (:,k))). For each weak diagonal k in * increasing order of degree in A+A', the algorithm finds an index j such * that A (k,j) and A (j,k) are "large" (greater than or equal to tol times * the largest magnitude in their columns). Row j must also not have already * been swapped. Rows j and k are then swapped. If we come to a diagonal k * that has already been swapped, then it is not modified. This case occurs * for "oxo" pivots: * * k j * k o x * j x o * * which are swapped once to obtain * * k j * j x o * k o x * * These two rows are then not modified any further (A (j,j) was weak, but * after one swap the permuted the jth diagonal entry is strong. * * This algorithm only works on square matrices (real, complex, or pattern- * only). The numerical values are optional. If not present, each entry is * treated as numerically acceptable (tol is ignored), and the algorithm * operates by just using the pattern, not the values. Each column of the * input matrix A must be sorted, with no duplicate entries. The matrix A * can be optionally scaled prior to the numerical test. The matrix A (:,P) * has the same diagonal entries as A (:,P), except in different order. So * the output permutation P can also be used to swap the columns of A. */ #if 0 #include "umf_internal.h" #include "umf_2by2.h" #ifndef NDEBUG #include "umf_is_permutation.h" #endif /* x is "weak" if it is less than ctol. If x or ctol are NaN, then define * x as not "weak". This is a rather arbitrary choice, made to simplify the * computation. On all but a PC with Microsoft C/C++, this test becomes * ((x) - ctol < 0). */ #define WEAK(x,ctol) (SCALAR_IS_LTZERO ((x)-(ctol))) /* For flag value in Next [col] */ #define IS_WEAK -2 /* ========================================================================== */ /* === two_by_two =========================================================== */ /* ========================================================================== */ PRIVATE Int two_by_two /* returns # unmatched weak diagonals */ ( /* input, not modified */ Int n2, /* C is n2-by-n2 */ Int Cp [ ], /* size n2+1, column pointers for C */ Int Ci [ ], /* size snz = Cp [n2], row indices for C */ Int Degree [ ], /* Degree [i] = degree of row i of C+C' */ /* input, not defined on output */ Int Next [ ], /* Next [k] == IS_WEAK if k is a weak diagonal */ Int Ri [ ], /* Ri [i] is the length of row i in C */ /* output, not defined on input */ Int P [ ], /* workspace, not defined on input or output */ Int Rp [ ], Int Head [ ] ) { Int deg, newcol, row, col, p, p2, unmatched, k, j, j2, j_best, best, jdiff, jdiff_best, jdeg, jdeg_best, cp, cp1, cp2, rp, rp1, rp2, maxdeg, mindeg ; /* ---------------------------------------------------------------------- */ /* place weak diagonals in the degree lists */ /* ---------------------------------------------------------------------- */ for (deg = 0 ; deg < n2 ; deg++) { Head [deg] = EMPTY ; } maxdeg = 0 ; mindeg = Int_MAX ; for (newcol = n2-1 ; newcol >= 0 ; newcol--) { if (Next [newcol] == IS_WEAK) { /* add this column to the list of weak nodes */ DEBUGm1 ((" newcol "ID" has a weak diagonal deg "ID"\n", newcol, deg)) ; deg = Degree [newcol] ; ASSERT (deg >= 0 && deg < n2) ; Next [newcol] = Head [deg] ; Head [deg] = newcol ; maxdeg = MAX (maxdeg, deg) ; mindeg = MIN (mindeg, deg) ; } } /* ---------------------------------------------------------------------- */ /* construct R = C' (C = strong entries in pruned submatrix) */ /* ---------------------------------------------------------------------- */ /* Ri [0..n2-1] is the length of each row of R */ /* use P as temporary pointer into the row form of R [ */ Rp [0] = 0 ; for (row = 0 ; row < n2 ; row++) { Rp [row+1] = Rp [row] + Ri [row] ; P [row] = Rp [row] ; } /* Ri no longer needed for row counts */ /* all entries in C are strong */ for (col = 0 ; col < n2 ; col++) { p2 = Cp [col+1] ; for (p = Cp [col] ; p < p2 ; p++) { /* place the column index in row = Ci [p] */ Ri [P [Ci [p]]++] = col ; } } /* contents of P no longer needed ] */ #ifndef NDEBUG DEBUG0 (("==================R: row form of strong entries in A:\n")) ; UMF_dump_col_matrix ((double *) NULL, #ifdef COMPLEX (double *) NULL, #endif Ri, Rp, n2, n2, Rp [n2]) ; #endif ASSERT (AMD_valid (n2, n2, Rp, Ri) == AMD_OK) ; /* ---------------------------------------------------------------------- */ /* for each weak diagonal, find a pair of strong off-diagonal entries */ /* ---------------------------------------------------------------------- */ for (row = 0 ; row < n2 ; row++) { P [row] = EMPTY ; } unmatched = 0 ; best = EMPTY ; jdiff = EMPTY ; jdeg = EMPTY ; for (deg = mindeg ; deg <= maxdeg ; deg++) { /* find the next weak diagonal of lowest degree */ DEBUGm2 (("---------------------------------- Deg: "ID"\n", deg)) ; for (k = Head [deg] ; k != EMPTY ; k = Next [k]) { DEBUGm2 (("k: "ID"\n", k)) ; if (P [k] == EMPTY) { /* C (k,k) is a weak diagonal entry. Find an index j != k such * that C (j,k) and C (k,j) are both strong, and also such * that Degree [j] is minimized. In case of a tie, pick * the smallest index j. C and R contain the pattern of * strong entries only. * * Note that row k of R and column k of C are both sorted. */ DEBUGm4 (("===== Weak diagonal k = "ID"\n", k)) ; DEBUG1 (("Column k of C:\n")) ; for (p = Cp [k] ; p < Cp [k+1] ; p++) { DEBUG1 ((" "ID": deg "ID"\n", Ci [p], Degree [Ci [p]])); } DEBUG1 (("Row k of R (strong entries only):\n")) ; for (p = Rp [k] ; p < Rp [k+1] ; p++) { DEBUG1 ((" "ID": deg "ID"\n", Ri [p], Degree [Ri [p]])); } /* no (C (k,j), C (j,k)) pair exists yet */ j_best = EMPTY ; jdiff_best = Int_MAX ; jdeg_best = Int_MAX ; /* pointers into column k (including values) */ cp1 = Cp [k] ; cp2 = Cp [k+1] ; cp = cp1 ; /* pointers into row k (strong entries only, no values) */ rp1 = Rp [k] ; rp2 = Rp [k+1] ; rp = rp1 ; /* while entries searched in column k and row k */ while (TRUE) { if (cp >= cp2) { /* no more entries in this column */ break ; } /* get C (j,k), which is strong */ j = Ci [cp] ; if (rp >= rp2) { /* no more entries in this column */ break ; } /* get R (k,j2), which is strong */ j2 = Ri [rp] ; if (j < j2) { /* C (j,k) is strong, but R (k,j) is not strong */ cp++ ; continue ; } if (j2 < j) { /* C (k,j2) is strong, but R (j2,k) is not strong */ rp++ ; continue ; } /* j == j2: C (j,k) is strong and R (k,j) is strong */ best = FALSE ; if (P [j] == EMPTY) { /* j has not yet been matched */ jdeg = Degree [j] ; jdiff = SCALAR_ABS (k-j) ; DEBUG1 (("Try candidate j "ID" deg "ID" diff "ID "\n", j, jdeg, jdiff)) ; if (j_best == EMPTY) { /* this is the first candidate seen */ DEBUG1 ((" first\n")) ; best = TRUE ; } else { if (jdeg < jdeg_best) { /* the degree of j is best seen so far. */ DEBUG1 ((" least degree\n")) ; best = TRUE ; } else if (jdeg == jdeg_best) { /* degree of j and j_best are the same */ /* tie break by nearest node number */ if (jdiff < jdiff_best) { DEBUG1 ((" tie degree, closer\n")) ; best = TRUE ; } else if (jdiff == jdiff_best) { /* |j-k| = |j_best-k|. For any given k * and j_best there is only one other j * than can be just as close as j_best. * Tie break by picking the smaller of * j and j_best */ DEBUG1 ((" tie degree, as close\n")); best = j < j_best ; } } else { /* j has higher degree than best so far */ best = FALSE ; } } } if (best) { /* j is best match for k */ /* found a strong pair, A (j,k) and A (k,j) */ DEBUG1 ((" --- Found pair k: "ID" j: " ID " jdeg: "ID" jdiff: "ID"\n", k, j, jdeg, jdiff)) ; ASSERT (jdiff != EMPTY) ; ASSERT (jdeg != EMPTY) ; j_best = j ; jdeg_best = jdeg ; jdiff_best = jdiff ; } /* get the next entries in column k and row k */ cp++ ; rp++ ; } /* save the pair (j,k), if we found one */ if (j_best != EMPTY) { j = j_best ; DEBUGm4 ((" --- best pair j: "ID" for k: "ID"\n", j, k)) ; P [k] = j ; P [j] = k ; } else { /* no match was found for k */ unmatched++ ; } } } } /* ---------------------------------------------------------------------- */ /* finalize the row permutation, P */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n2 ; k++) { if (P [k] == EMPTY) { P [k] = k ; } } ASSERT (UMF_is_permutation (P, Rp, n2, n2)) ; return (unmatched) ; } /* ========================================================================== */ /* === UMF_2by2 ============================================================= */ /* ========================================================================== */ GLOBAL void UMF_2by2 ( /* input, not modified: */ Int n, /* A is n-by-n */ const Int Ap [ ], /* size n+1 */ const Int Ai [ ], /* size nz = Ap [n] */ const double Ax [ ], /* size nz if present */ #ifdef COMPLEX const double Az [ ], /* size nz if present */ #endif double tol, /* tolerance for determining whether or not an * entry is numerically acceptable. If tol <= 0 * then all numerical values ignored. */ Int scale, /* scaling to perform (none, sum, or max) */ Int Cperm1 [ ], /* singleton permutations */ #ifndef NDEBUG Int Rperm1 [ ], /* not needed, since Rperm1 = Cperm1 for submatrix S */ #endif Int InvRperm1 [ ], /* inverse of Rperm1 */ Int n1, /* number of singletons */ Int nempty, /* number of empty rows/cols */ /* input, contents undefined on output: */ Int Degree [ ], /* Degree [j] is the number of off-diagonal * entries in row/column j of S+S', where * where S = A (Cperm1 [n1..], Rperm1 [n1..]). * Note that S is not used, nor formed. */ /* output: */ Int P [ ], /* P [k] = i means original row i is kth row in S(P,:) * where S = A (Cperm1 [n1..], Rperm1 [n1..]) */ Int *p_nweak, Int *p_unmatched, /* workspace (not defined on input or output): */ Int Ri [ ], /* of size >= max (nz, n) */ Int Rp [ ], /* of size n+1 */ double Rs [ ], /* of size n if present. Rs = sum (abs (A),2) or * max (abs (A),2), the sum or max of each row. Unused * if scale is equal to UMFPACK_SCALE_NONE. */ Int Head [ ], /* of size n. Head pointers for bucket sort */ Int Next [ ], /* of size n. Next pointers for bucket sort */ Int Ci [ ], /* size nz */ Int Cp [ ] /* size n+1 */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry aij ; double cmax, value, rs, ctol, dvalue ; Int k, p, row, col, do_values, do_sum, do_max, do_scale, nweak, weak, p1, p2, dfound, unmatched, n2, oldrow, newrow, oldcol, newcol, pp ; #ifdef COMPLEX Int split = SPLIT (Az) ; #endif #ifndef NRECIPROCAL Int do_recip = FALSE ; #endif #ifndef NDEBUG /* UMF_debug += 99 ; */ DEBUGm3 (("\n ==================================UMF_2by2: tol %g\n", tol)) ; ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ; for (k = n1 ; k < n - nempty ; k++) { ASSERT (Cperm1 [k] == Rperm1 [k]) ; } #endif /* ---------------------------------------------------------------------- */ /* determine scaling options */ /* ---------------------------------------------------------------------- */ /* use the values, but only if they are present */ /* ignore the values if tol <= 0 */ do_values = (tol > 0) && (Ax != (double *) NULL) ; if (do_values && (Rs != (double *) NULL)) { do_sum = (scale == UMFPACK_SCALE_SUM) ; do_max = (scale == UMFPACK_SCALE_MAX) ; } else { /* no scaling */ do_sum = FALSE ; do_max = FALSE ; } do_scale = do_max || do_sum ; DEBUGm3 (("do_values "ID" do_sum "ID" do_max "ID" do_scale "ID"\n", do_values, do_sum, do_max, do_scale)) ; /* ---------------------------------------------------------------------- */ /* compute the row scaling, if requested */ /* ---------------------------------------------------------------------- */ /* see also umf_kernel_init */ if (do_scale) { #ifndef NRECIPROCAL double rsmin ; #endif for (row = 0 ; row < n ; row++) { Rs [row] = 0.0 ; } for (col = 0 ; col < n ; col++) { p2 = Ap [col+1] ; for (p = Ap [col] ; p < p2 ; p++) { row = Ai [p] ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; rs = Rs [row] ; if (!SCALAR_IS_NAN (rs)) { if (SCALAR_IS_NAN (value)) { /* if any entry in a row is NaN, then the scale factor * for the row is NaN. It will be set to 1 later. */ Rs [row] = value ; } else if (do_max) { Rs [row] = MAX (rs, value) ; } else { Rs [row] += value ; } } } } #ifndef NRECIPROCAL rsmin = Rs [0] ; if (SCALAR_IS_ZERO (rsmin) || SCALAR_IS_NAN (rsmin)) { rsmin = 1.0 ; } #endif for (row = 0 ; row < n ; row++) { /* do not scale an empty row, or a row with a NaN */ rs = Rs [row] ; if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs)) { Rs [row] = 1.0 ; } #ifndef NRECIPROCAL rsmin = MIN (rsmin, Rs [row]) ; #endif } #ifndef NRECIPROCAL /* multiply by the reciprocal if Rs is not too small */ do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ; if (do_recip) { /* invert the scale factors */ for (row = 0 ; row < n ; row++) { Rs [row] = 1.0 / Rs [row] ; } } #endif } /* ---------------------------------------------------------------------- */ /* compute the max in each column and find diagonal */ /* ---------------------------------------------------------------------- */ nweak = 0 ; #ifndef NDEBUG for (k = 0 ; k < n ; k++) { ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n) ; ASSERT (InvRperm1 [Rperm1 [k]] == k) ; } #endif n2 = n - n1 - nempty ; /* use Ri to count the number of strong entries in each row */ for (row = 0 ; row < n2 ; row++) { Ri [row] = 0 ; } pp = 0 ; ctol = 0 ; dvalue = 1 ; /* construct C = pruned submatrix, strong values only, column form */ for (k = n1 ; k < n - nempty ; k++) { oldcol = Cperm1 [k] ; newcol = k - n1 ; Next [newcol] = EMPTY ; DEBUGm1 (("Column "ID" newcol "ID" oldcol "ID"\n", k, newcol, oldcol)) ; Cp [newcol] = pp ; dfound = FALSE ; p1 = Ap [oldcol] ; p2 = Ap [oldcol+1] ; if (do_values) { cmax = 0 ; dvalue = 0 ; if (!do_scale) { /* no scaling */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; /* if either cmax or value is NaN, define cmax as NaN */ if (!SCALAR_IS_NAN (cmax)) { if (SCALAR_IS_NAN (value)) { cmax = value ; } else { cmax = MAX (cmax, value) ; } } if (oldrow == oldcol) { /* we found the diagonal entry in this column */ dvalue = value ; dfound = TRUE ; ASSERT (newrow == newcol) ; } } } #ifndef NRECIPROCAL else if (do_recip) { /* multiply by the reciprocal */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value *= Rs [oldrow] ; /* if either cmax or value is NaN, define cmax as NaN */ if (!SCALAR_IS_NAN (cmax)) { if (SCALAR_IS_NAN (value)) { cmax = value ; } else { cmax = MAX (cmax, value) ; } } if (oldrow == oldcol) { /* we found the diagonal entry in this column */ dvalue = value ; dfound = TRUE ; ASSERT (newrow == newcol) ; } } } #endif else { /* divide instead */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value /= Rs [oldrow] ; /* if either cmax or value is NaN, define cmax as NaN */ if (!SCALAR_IS_NAN (cmax)) { if (SCALAR_IS_NAN (value)) { cmax = value ; } else { cmax = MAX (cmax, value) ; } } if (oldrow == oldcol) { /* we found the diagonal entry in this column */ dvalue = value ; dfound = TRUE ; ASSERT (newrow == newcol) ; } } } ctol = tol * cmax ; DEBUGm1 ((" cmax col "ID" %g ctol %g\n", oldcol, cmax, ctol)) ; } else { for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; ASSERT (oldrow >= 0 && oldrow < n) ; newrow = InvRperm1 [oldrow] - n1 ; ASSERT (newrow >= -n1 && newrow < n2) ; if (newrow < 0) continue ; Ci [pp++] = newrow ; if (oldrow == oldcol) { /* we found the diagonal entry in this column */ ASSERT (newrow == newcol) ; dfound = TRUE ; } /* count the entries in each column */ Ri [newrow]++ ; } } /* ------------------------------------------------------------------ */ /* flag the weak diagonals */ /* ------------------------------------------------------------------ */ if (!dfound) { /* no diagonal entry present */ weak = TRUE ; } else { /* diagonal entry is present, check its value */ weak = (do_values) ? WEAK (dvalue, ctol) : FALSE ; } if (weak) { /* flag this column as weak */ DEBUG0 (("Weak!\n")) ; Next [newcol] = IS_WEAK ; nweak++ ; } /* ------------------------------------------------------------------ */ /* count entries in each row that are not numerically weak */ /* ------------------------------------------------------------------ */ if (do_values) { if (!do_scale) { /* no scaling */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; newrow = InvRperm1 [oldrow] - n1 ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; weak = WEAK (value, ctol) ; if (!weak) { DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ; Ci [pp++] = newrow ; Ri [newrow]++ ; } } } #ifndef NRECIPROCAL else if (do_recip) { /* multiply by the reciprocal */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; newrow = InvRperm1 [oldrow] - n1 ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value *= Rs [oldrow] ; weak = WEAK (value, ctol) ; if (!weak) { DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ; Ci [pp++] = newrow ; Ri [newrow]++ ; } } } #endif else { /* divide instead */ for (p = p1 ; p < p2 ; p++) { oldrow = Ai [p] ; newrow = InvRperm1 [oldrow] - n1 ; if (newrow < 0) continue ; ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; value /= Rs [oldrow] ; weak = WEAK (value, ctol) ; if (!weak) { DEBUG0 ((" strong: row "ID": %g\n", oldrow, value)) ; Ci [pp++] = newrow ; Ri [newrow]++ ; } } } } } Cp [n2] = pp ; ASSERT (AMD_valid (n2, n2, Cp, Ci) == AMD_OK) ; if (nweak == 0) { /* nothing to do, quick return */ DEBUGm2 (("\n =============================UMF_2by2: quick return\n")) ; for (k = 0 ; k < n ; k++) { P [k] = k ; } *p_nweak = 0 ; *p_unmatched = 0 ; return ; } #ifndef NDEBUG for (k = 0 ; k < n2 ; k++) { P [k] = EMPTY ; } for (k = 0 ; k < n2 ; k++) { ASSERT (Degree [k] >= 0 && Degree [k] < n2) ; } #endif /* ---------------------------------------------------------------------- */ /* find the 2-by-2 permutation */ /* ---------------------------------------------------------------------- */ /* The matrix S is now mapped to the index range 0 to n2-1. We have * S = A (Rperm [n1 .. n-nempty-1], Cperm [n1 .. n-nempty-1]), and then * C = pattern of strong entries in S. A weak diagonal k in S is marked * with Next [k] = IS_WEAK. */ unmatched = two_by_two (n2, Cp, Ci, Degree, Next, Ri, P, Rp, Head) ; /* ---------------------------------------------------------------------- */ *p_nweak = nweak ; *p_unmatched = unmatched ; #ifndef NDEBUG DEBUGm4 (("UMF_2by2: weak "ID" unmatched "ID"\n", nweak, unmatched)) ; for (row = 0 ; row < n ; row++) { DEBUGm2 (("P ["ID"] = "ID"\n", row, P [row])) ; } DEBUGm2 (("\n =============================UMF_2by2: done\n\n")) ; #endif } #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.h0000644000175000017500000000100111674452555023301 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_local_search ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.c0000644000175000017500000002306011674452555022351 0ustar sonnesonne/* ========================================================================== */ /* === UMF_triplet ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Not user callable. Converts triplet input to column-oriented form. Duplicate entries may exist (they are summed in the output). The columns of the column-oriented form are in sorted order. The input is not modified. Returns 1 if OK, 0 if an error occurred. Compiled into four different routines for each version (di, dl, zi, zl), for a total of 16 different routines. */ #include "umf_internal.h" #include "umf_triplet.h" #ifdef DO_MAP #ifdef DO_VALUES GLOBAL Int UMF_triplet_map_x #else GLOBAL Int UMF_triplet_map_nox #endif #else #ifdef DO_VALUES GLOBAL Int UMF_triplet_nomap_x #else GLOBAL Int UMF_triplet_nomap_nox #endif #endif ( Int n_row, Int n_col, Int nz, const Int Ti [ ], /* size nz */ const Int Tj [ ], /* size nz */ Int Ap [ ], /* size n_col + 1 */ Int Ai [ ], /* size nz */ Int Rp [ ], /* size n_row + 1 */ Int Rj [ ], /* size nz */ Int W [ ], /* size max (n_row, n_col) */ Int RowCount [ ] /* size n_row */ #ifdef DO_VALUES , const double Tx [ ] /* size nz */ , double Ax [ ] /* size nz */ , double Rx [ ] /* size nz */ #ifdef COMPLEX , const double Tz [ ] /* size nz */ , double Az [ ] /* size nz */ , double Rz [ ] /* size nz */ #endif #endif #ifdef DO_MAP , Int Map [ ] /* size nz */ , Int Map2 [ ] /* size nz */ #endif ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int i, j, k, p, cp, p1, p2, pdest, pj ; #ifdef DO_MAP Int duplicates ; #endif #ifdef DO_VALUES #ifdef COMPLEX Int split = SPLIT (Tz) && SPLIT (Az) && SPLIT (Rz) ; #endif #endif /* ---------------------------------------------------------------------- */ /* count the entries in each row (also counting duplicates) */ /* ---------------------------------------------------------------------- */ /* use W as workspace for row counts (including duplicates) */ for (i = 0 ; i < n_row ; i++) { W [i] = 0 ; } for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i < 0 || i >= n_row || j < 0 || j >= n_col) { return (UMFPACK_ERROR_invalid_matrix) ; } W [i]++ ; #ifndef NDEBUG DEBUG1 ((ID " triplet: "ID" "ID" ", k, i, j)) ; #ifdef DO_VALUES { Entry tt ; ASSIGN (tt, Tx, Tz, k, split) ; EDEBUG2 (tt) ; DEBUG1 (("\n")) ; } #endif #endif } /* ---------------------------------------------------------------------- */ /* compute the row pointers */ /* ---------------------------------------------------------------------- */ Rp [0] = 0 ; for (i = 0 ; i < n_row ; i++) { Rp [i+1] = Rp [i] + W [i] ; W [i] = Rp [i] ; } /* W is now equal to the row pointers */ /* ---------------------------------------------------------------------- */ /* construct the row form */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < nz ; k++) { p = W [Ti [k]]++ ; #ifdef DO_MAP Map [k] = p ; #endif Rj [p] = Tj [k] ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Rx [p] = Tx [k] ; Rz [p] = Tz [k] ; } else { Rx [2*p ] = Tx [2*k ] ; Rx [2*p+1] = Tx [2*k+1] ; } #else Rx [p] = Tx [k] ; #endif #endif } /* Rp stays the same, but W [i] is advanced to the start of row i+1 */ #ifndef NDEBUG for (i = 0 ; i < n_row ; i++) { ASSERT (W [i] == Rp [i+1]) ; } #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("First row map: Map ["ID"] = "ID"\n", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (j == Rj [p]) ; ASSERT (Rp [i] <= p && p < Rp [i+1]) ; } #endif #endif /* ---------------------------------------------------------------------- */ /* sum up duplicates */ /* ---------------------------------------------------------------------- */ /* use W [j] to hold position in Ri/Rx/Rz of a_ij, for row i [ */ for (j = 0 ; j < n_col ; j++) { W [j] = EMPTY ; } #ifdef DO_MAP duplicates = FALSE ; #endif for (i = 0 ; i < n_row ; i++) { p1 = Rp [i] ; p2 = Rp [i+1] ; pdest = p1 ; /* At this point, W [j] < p1 holds true for all columns j, */ /* because Ri/Rx/Rz is stored in row oriented order. */ #ifndef NDEBUG if (UMF_debug >= -2) { for (j = 0 ; j < n_col ; j++) { ASSERT (W [j] < p1) ; } } #endif for (p = p1 ; p < p2 ; p++) { j = Rj [p] ; ASSERT (j >= 0 && j < n_col) ; pj = W [j] ; if (pj >= p1) { /* this column index, j, is already in row i, at position pj */ ASSERT (pj < p) ; ASSERT (Rj [pj] == j) ; #ifdef DO_MAP Map2 [p] = pj ; duplicates = TRUE ; #endif #ifdef DO_VALUES /* sum the entry */ #ifdef COMPLEX if (split) { Rx [pj] += Rx [p] ; Rz [pj] += Rz [p] ; } else { Rx[2*pj ] += Rx[2*p ] ; Rx[2*pj+1] += Rx[2*p+1] ; } #else Rx [pj] += Rx [p] ; #endif #endif } else { /* keep the entry */ /* also keep track in W[j] of position of a_ij for case above */ W [j] = pdest ; #ifdef DO_MAP Map2 [p] = pdest ; #endif /* no need to move the entry if pdest is equal to p */ if (pdest != p) { Rj [pdest] = j ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Rx [pdest] = Rx [p] ; Rz [pdest] = Rz [p] ; } else { Rx [2*pdest ] = Rx [2*p ] ; Rx [2*pdest+1] = Rx [2*p+1] ; } #else Rx [pdest] = Rx [p] ; #endif #endif } pdest++ ; } } RowCount [i] = pdest - p1 ; } /* done using W for position of a_ij ] */ /* ---------------------------------------------------------------------- */ /* merge Map and Map2 into a single Map */ /* ---------------------------------------------------------------------- */ #ifdef DO_MAP if (duplicates) { for (k = 0 ; k < nz ; k++) { Map [k] = Map2 [Map [k]] ; } } #ifndef NDEBUG else { /* no duplicates, so no need to recompute Map */ for (k = 0 ; k < nz ; k++) { ASSERT (Map2 [k] == k) ; } } for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("Second row map: Map ["ID"] = "ID"\n", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (j == Rj [p]) ; ASSERT (Rp [i] <= p && p < Rp [i+1]) ; } #endif #endif /* now the kth triplet maps to p = Map [k], and thus to Rj/Rx [p] */ /* ---------------------------------------------------------------------- */ /* count the entries in each column */ /* ---------------------------------------------------------------------- */ /* [ use W as work space for column counts of A */ for (j = 0 ; j < n_col ; j++) { W [j] = 0 ; } for (i = 0 ; i < n_row ; i++) { for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++) { j = Rj [p] ; ASSERT (j >= 0 && j < n_col) ; W [j]++ ; } } /* ---------------------------------------------------------------------- */ /* create the column pointers */ /* ---------------------------------------------------------------------- */ Ap [0] = 0 ; for (j = 0 ; j < n_col ; j++) { Ap [j+1] = Ap [j] + W [j] ; } /* done using W as workspace for column counts of A ] */ for (j = 0 ; j < n_col ; j++) { W [j] = Ap [j] ; } /* ---------------------------------------------------------------------- */ /* construct the column form */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i < n_row ; i++) { for (p = Rp [i] ; p < Rp [i] + RowCount [i] ; p++) { cp = W [Rj [p]]++ ; #ifdef DO_MAP Map2 [p] = cp ; #endif Ai [cp] = i ; #ifdef DO_VALUES #ifdef COMPLEX if (split) { Ax [cp] = Rx [p] ; Az [cp] = Rz [p] ; } else { Ax [2*cp ] = Rx [2*p ] ; Ax [2*cp+1] = Rx [2*p+1] ; } #else Ax [cp] = Rx [p] ; #endif #endif } } /* ---------------------------------------------------------------------- */ /* merge Map and Map2 into a single Map */ /* ---------------------------------------------------------------------- */ #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { Map [k] = Map2 [Map [k]] ; } #endif /* now the kth triplet maps to p = Map [k], and thus to Ai/Ax [p] */ #ifndef NDEBUG for (j = 0 ; j < n_col ; j++) { ASSERT (W [j] == Ap [j+1]) ; } UMF_dump_col_matrix ( #ifdef DO_VALUES Ax, #ifdef COMPLEX Az, #endif #else (double *) NULL, #ifdef COMPLEX (double *) NULL, #endif #endif Ai, Ap, n_row, n_col, nz) ; #ifdef DO_MAP for (k = 0 ; k < nz ; k++) { /* make sure that kth triplet is mapped correctly */ p = Map [k] ; DEBUG1 (("Col map: Map ["ID"] = "ID"\t", k, p)) ; i = Ti [k] ; j = Tj [k] ; ASSERT (i == Ai [p]) ; DEBUG1 ((" i "ID" j "ID" Ap[j] "ID" p "ID" Ap[j+1] "ID"\n", i, j, Ap [j], p, Ap [j+1])) ; ASSERT (Ap [j] <= p && p < Ap [j+1]) ; } #endif #endif return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_version.h0000644000175000017500000010121711674452555022361 0ustar sonnesonne/* ========================================================================== */ /* === umf_version.h ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Define routine names, depending on version being compiled. DINT: double precision, int's as integers DLONG: double precision, UF_long's as integers ZLONG: complex double precision, UF_long's as integers ZINT: complex double precision, int's as integers */ /* Set DINT as the default, if nothing is defined */ #if !defined (DLONG) && !defined (DINT) && !defined (ZLONG) && !defined (ZINT) #define DINT #endif /* Determine if this is a real or complex version */ #if defined (ZLONG) || defined (ZINT) #define COMPLEX #endif /* -------------------------------------------------------------------------- */ /* integer type (Int is int or UF_long) now defined in amd_internal.h */ /* -------------------------------------------------------------------------- */ #if defined (DLONG) || defined (ZLONG) #define LONG_INTEGER #endif /* -------------------------------------------------------------------------- */ /* Numerical relop macros for correctly handling the NaN case */ /* -------------------------------------------------------------------------- */ /* SCALAR_IS_NAN(x): True if x is NaN. False otherwise. The commonly-existing isnan(x) function could be used, but it's not in Kernighan & Ritchie 2nd edition (ANSI C). It may appear in , but I'm not certain about portability. The expression x != x is true if and only if x is NaN, according to the IEEE 754 floating-point standard. SCALAR_IS_ZERO(x): True if x is zero. False if x is nonzero, NaN, or +/- Inf. This is (x == 0) if the compiler is IEEE 754 compliant. SCALAR_IS_NONZERO(x): True if x is nonzero, NaN, or +/- Inf. False if x zero. This is (x != 0) if the compiler is IEEE 754 compliant. SCALAR_IS_LTZERO(x): True if x is < zero or -Inf. False if x is >= 0, NaN, or +Inf. This is (x < 0) if the compiler is IEEE 754 compliant. */ #if defined (UMF_WINDOWS) && !defined (MATHWORKS) /* Yes, this is exceedingly ugly. Blame Microsoft, which hopelessly */ /* violates the IEEE 754 floating-point standard in a bizarre way. */ /* If you're using an IEEE 754-compliant compiler, then x != x is true */ /* iff x is NaN. For Microsoft, (x < x) is true iff x is NaN. */ /* So either way, this macro safely detects a NaN. */ #define SCALAR_IS_NAN(x) (((x) != (x)) || (((x) < (x)))) #define SCALAR_IS_ZERO(x) (((x) == 0.) && !SCALAR_IS_NAN(x)) #define SCALAR_IS_NONZERO(x) (((x) != 0.) || SCALAR_IS_NAN(x)) #define SCALAR_IS_LTZERO(x) (((x) < 0.) && !SCALAR_IS_NAN(x)) #else /* These all work properly, according to the IEEE 754 standard ... except on */ /* a PC with windows. Works fine in Linux on the same PC... */ #define SCALAR_IS_NAN(x) ((x) != (x)) #define SCALAR_IS_ZERO(x) ((x) == 0.) #define SCALAR_IS_NONZERO(x) ((x) != 0.) #define SCALAR_IS_LTZERO(x) ((x) < 0.) #endif /* scalar absolute value macro. If x is NaN, the result is NaN: */ #define SCALAR_ABS(x) ((SCALAR_IS_LTZERO (x)) ? -(x) : (x)) /* true if an integer (stored in double x) would overflow (or if x is NaN) */ #define INT_OVERFLOW(x) ((!((x) * (1.0+1e-8) <= (double) Int_MAX)) \ || SCALAR_IS_NAN (x)) /* print a scalar (avoid printing "-0" for negative zero). */ #define PRINT_SCALAR(a) \ { \ if (SCALAR_IS_NONZERO (a)) \ { \ PRINTF ((" (%g)", (a))) ; \ } \ else \ { \ PRINTF ((" (0)")) ; \ } \ } /* -------------------------------------------------------------------------- */ /* Real floating-point arithmetic */ /* -------------------------------------------------------------------------- */ #ifndef COMPLEX #define Entry double #define SPLIT(s) (1) #define REAL_COMPONENT(c) (c) #define IMAG_COMPONENT(c) (0.) #define ASSIGN(c,s1,s2,p,split) { (c) = (s1)[p] ; } #define CLEAR(c) { (c) = 0. ; } #define CLEAR_AND_INCREMENT(p) { *p++ = 0. ; } #define IS_NAN(a) SCALAR_IS_NAN (a) #define IS_ZERO(a) SCALAR_IS_ZERO (a) #define IS_NONZERO(a) SCALAR_IS_NONZERO (a) #define SCALE_DIV(c,s) { (c) /= (s) ; } #define SCALE(c,s) { (c) *= (s) ; } #define ASSEMBLE(c,a) { (c) += (a) ; } #define ASSEMBLE_AND_INCREMENT(c,p) { (c) += *p++ ; } #define DECREMENT(c,a) { (c) -= (a) ; } #define MULT(c,a,b) { (c) = (a) * (b) ; } #define MULT_CONJ(c,a,b) { (c) = (a) * (b) ; } #define MULT_SUB(c,a,b) { (c) -= (a) * (b) ; } #define MULT_SUB_CONJ(c,a,b) { (c) -= (a) * (b) ; } #define DIV(c,a,b) { (c) = (a) / (b) ; } #define DIV_CONJ(c,a,b) { (c) = (a) / (b) ; } #define APPROX_ABS(s,a) { (s) = SCALAR_ABS (a) ; } #define ABS(s,a) { (s) = SCALAR_ABS (a) ; } #define PRINT_ENTRY(a) PRINT_SCALAR (a) /* for flop counts */ #define MULTSUB_FLOPS 2. /* c -= a*b */ #define DIV_FLOPS 1. /* c = a/b */ #define ABS_FLOPS 0. /* c = abs (a) */ #define ASSEMBLE_FLOPS 1. /* c += a */ #define DECREMENT_FLOPS 1. /* c -= a */ #define MULT_FLOPS 1. /* c = a*b */ #define SCALE_FLOPS 1. /* c = a/s */ #else /* -------------------------------------------------------------------------- */ /* Complex floating-point arithmetic */ /* -------------------------------------------------------------------------- */ /* Note: An alternative to this DoubleComplex type would be to use a struct { double r ; double i ; }. The problem with that method (used by the Sun Performance Library, for example) is that ANSI C provides no guarantee about the layout of a struct. It is possible that the sizeof the struct above would be greater than 2 * sizeof (double). This would mean that the complex BLAS could not be used. The method used here avoids that possibility. ANSI C *does* guarantee that an array of structs has the same size as n times the size of one struct. The ANSI C99 version of the C language includes a "double _Complex" type. It should be possible in that case to do the following: #define Entry double _Complex and remove the DoubleComplex struct. The macros, below, could then be replaced with instrinsic operators. Note that the #define Real and #define Imag should also be removed (they only appear in this file). For the MULT, MULT_SUB, MULT_SUB_CONJ, and MULT_CONJ macros, the output argument c cannot be the same as any input argument. */ typedef struct { double component [2] ; /* real and imaginary parts */ } DoubleComplex ; #define Entry DoubleComplex #define Real component [0] #define Imag component [1] /* for flop counts */ #define MULTSUB_FLOPS 8. /* c -= a*b */ #define DIV_FLOPS 9. /* c = a/b */ #define ABS_FLOPS 6. /* c = abs (a), count sqrt as one flop */ #define ASSEMBLE_FLOPS 2. /* c += a */ #define DECREMENT_FLOPS 2. /* c -= a */ #define MULT_FLOPS 6. /* c = a*b */ #define SCALE_FLOPS 2. /* c = a/s or c = a*s */ /* -------------------------------------------------------------------------- */ /* real part of c */ #define REAL_COMPONENT(c) ((c).Real) /* -------------------------------------------------------------------------- */ /* imag part of c */ #define IMAG_COMPONENT(c) ((c).Imag) /* -------------------------------------------------------------------------- */ /* Return TRUE if a complex number is in split form, FALSE if in packed form */ #define SPLIT(sz) ((sz) != (double *) NULL) /* -------------------------------------------------------------------------- */ /* c = (s1) + (s2)*i, if s2 is null, then X is in "packed" format (compatible * with Entry and ANSI C99 double _Complex type). */ #define ASSIGN(c,s1,s2,p,split) \ { \ if (split) \ { \ (c).Real = (s1)[p] ; \ (c).Imag = (s2)[p] ; \ } \ else \ { \ (c) = ((Entry *)(s1))[p] ; \ } \ } /* -------------------------------------------------------------------------- */ /* c = 0 */ #define CLEAR(c) \ { \ (c).Real = 0. ; \ (c).Imag = 0. ; \ } /* -------------------------------------------------------------------------- */ /* *p++ = 0 */ #define CLEAR_AND_INCREMENT(p) \ { \ p->Real = 0. ; \ p->Imag = 0. ; \ p++ ; \ } /* -------------------------------------------------------------------------- */ /* True if a == 0 */ #define IS_ZERO(a) \ (SCALAR_IS_ZERO ((a).Real) && SCALAR_IS_ZERO ((a).Imag)) /* -------------------------------------------------------------------------- */ /* True if a is NaN */ #define IS_NAN(a) \ (SCALAR_IS_NAN ((a).Real) || SCALAR_IS_NAN ((a).Imag)) /* -------------------------------------------------------------------------- */ /* True if a != 0 */ #define IS_NONZERO(a) \ (SCALAR_IS_NONZERO ((a).Real) || SCALAR_IS_NONZERO ((a).Imag)) /* -------------------------------------------------------------------------- */ /* c /= s */ #define SCALE_DIV(c,s) \ { \ (c).Real /= (s) ; \ (c).Imag /= (s) ; \ } /* -------------------------------------------------------------------------- */ /* c *= s */ #define SCALE(c,s) \ { \ (c).Real *= (s) ; \ (c).Imag *= (s) ; \ } /* -------------------------------------------------------------------------- */ /* c += a */ #define ASSEMBLE(c,a) \ { \ (c).Real += (a).Real ; \ (c).Imag += (a).Imag ; \ } /* -------------------------------------------------------------------------- */ /* c += *p++ */ #define ASSEMBLE_AND_INCREMENT(c,p) \ { \ (c).Real += p->Real ; \ (c).Imag += p->Imag ; \ p++ ; \ } /* -------------------------------------------------------------------------- */ /* c -= a */ #define DECREMENT(c,a) \ { \ (c).Real -= (a).Real ; \ (c).Imag -= (a).Imag ; \ } /* -------------------------------------------------------------------------- */ /* c = a*b, assert because c cannot be the same as a or b */ #define MULT(c,a,b) \ { \ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ (c).Real = (a).Real * (b).Real - (a).Imag * (b).Imag ; \ (c).Imag = (a).Imag * (b).Real + (a).Real * (b).Imag ; \ } /* -------------------------------------------------------------------------- */ /* c = a*conjugate(b), assert because c cannot be the same as a or b */ #define MULT_CONJ(c,a,b) \ { \ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ (c).Real = (a).Real * (b).Real + (a).Imag * (b).Imag ; \ (c).Imag = (a).Imag * (b).Real - (a).Real * (b).Imag ; \ } /* -------------------------------------------------------------------------- */ /* c -= a*b, assert because c cannot be the same as a or b */ #define MULT_SUB(c,a,b) \ { \ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ (c).Real -= (a).Real * (b).Real - (a).Imag * (b).Imag ; \ (c).Imag -= (a).Imag * (b).Real + (a).Real * (b).Imag ; \ } /* -------------------------------------------------------------------------- */ /* c -= a*conjugate(b), assert because c cannot be the same as a or b */ #define MULT_SUB_CONJ(c,a,b) \ { \ ASSERT (&(c) != &(a) && &(c) != &(b)) ; \ (c).Real -= (a).Real * (b).Real + (a).Imag * (b).Imag ; \ (c).Imag -= (a).Imag * (b).Real - (a).Real * (b).Imag ; \ } /* -------------------------------------------------------------------------- */ /* c = a/b, using function pointer */ #define DIV(c,a,b) \ { \ (void) umfpack_divcomplex ((a).Real, (a).Imag, (b).Real, (b).Imag, \ &((c).Real), &((c).Imag)) ; \ } /* -------------------------------------------------------------------------- */ /* c = a/conjugate(b), using function pointer */ #define DIV_CONJ(c,a,b) \ { \ (void) umfpack_divcomplex ((a).Real, (a).Imag, (b).Real, (-(b).Imag), \ &((c).Real), &((c).Imag)) ; \ } /* -------------------------------------------------------------------------- */ /* approximate absolute value, s = |r|+|i| */ #define APPROX_ABS(s,a) \ { \ (s) = SCALAR_ABS ((a).Real) + SCALAR_ABS ((a).Imag) ; \ } /* -------------------------------------------------------------------------- */ /* exact absolute value, s = sqrt (a.real^2 + a.imag^2) */ #define ABS(s,a) \ { \ (s) = umfpack_hypot ((a).Real, (a).Imag) ; \ } /* -------------------------------------------------------------------------- */ /* print an entry (avoid printing "-0" for negative zero). */ #define PRINT_ENTRY(a) \ { \ if (SCALAR_IS_NONZERO ((a).Real)) \ { \ PRINTF ((" (%g", (a).Real)) ; \ } \ else \ { \ PRINTF ((" (0")) ; \ } \ if (SCALAR_IS_LTZERO ((a).Imag)) \ { \ PRINTF ((" - %gi)", -(a).Imag)) ; \ } \ else if (SCALAR_IS_ZERO ((a).Imag)) \ { \ PRINTF ((" + 0i)")) ; \ } \ else \ { \ PRINTF ((" + %gi)", (a).Imag)) ; \ } \ } /* -------------------------------------------------------------------------- */ #endif /* #ifndef COMPLEX */ /* -------------------------------------------------------------------------- */ /* Double precision, with int's as integers */ /* -------------------------------------------------------------------------- */ #ifdef DINT #define UMF_analyze umf_i_analyze #define UMF_apply_order umf_i_apply_order #define UMF_assemble umfdi_assemble #define UMF_assemble_fixq umfdi_assemble_fixq #define UMF_blas3_update umfdi_blas3_update #define UMF_build_tuples umfdi_build_tuples #define UMF_build_tuples_usage umfdi_build_tuples_usage #define UMF_colamd umf_i_colamd #define UMF_colamd_set_defaults umf_i_colamd_set_defaults #define UMF_create_element umfdi_create_element #define UMF_extend_front umfdi_extend_front #define UMF_free umf_i_free #define UMF_fsize umf_i_fsize #define UMF_garbage_collection umfdi_garbage_collection #define UMF_get_memory umfdi_get_memory #define UMF_grow_front umfdi_grow_front #define UMF_init_front umfdi_init_front #define UMF_is_permutation umf_i_is_permutation #define UMF_kernel umfdi_kernel #define UMF_kernel_init umfdi_kernel_init #define UMF_kernel_init_usage umfdi_kernel_init_usage #define UMF_kernel_wrapup umfdi_kernel_wrapup #define UMF_local_search umfdi_local_search #define UMF_lsolve umfdi_lsolve #define UMF_ltsolve umfdi_ltsolve #define UMF_lhsolve umfdi_lhsolve #define UMF_malloc umf_i_malloc #define UMF_mem_alloc_element umfdi_mem_alloc_element #define UMF_mem_alloc_head_block umfdi_mem_alloc_head_block #define UMF_mem_alloc_tail_block umfdi_mem_alloc_tail_block #define UMF_mem_free_tail_block umfdi_mem_free_tail_block #define UMF_mem_init_memoryspace umfdi_mem_init_memoryspace #define UMF_realloc umf_i_realloc #define UMF_report_perm umf_i_report_perm #define UMF_report_vector umfdi_report_vector #define UMF_row_search umfdi_row_search #define UMF_scale umfdi_scale #define UMF_scale_column umfdi_scale_column #define UMF_set_stats umf_i_set_stats #define UMF_singletons umf_i_singletons #define UMF_solve umfdi_solve #define UMF_start_front umfdi_start_front #define UMF_store_lu umfdi_store_lu #define UMF_store_lu_drop umfdi_store_lu_drop #define UMF_symbolic_usage umfdi_symbolic_usage #define UMF_transpose umfdi_transpose #define UMF_tuple_lengths umfdi_tuple_lengths #define UMF_usolve umfdi_usolve #define UMF_utsolve umfdi_utsolve #define UMF_uhsolve umfdi_uhsolve #define UMF_valid_numeric umfdi_valid_numeric #define UMF_valid_symbolic umfdi_valid_symbolic #define UMF_triplet_map_x umfdi_triplet_map_x #define UMF_triplet_map_nox umfdi_triplet_map_nox #define UMF_triplet_nomap_x umfdi_triplet_nomap_x #define UMF_triplet_nomap_nox umfdi_triplet_nomap_nox #define UMF_2by2 umfdi_2by2 #define UMFPACK_col_to_triplet umfpack_di_col_to_triplet #define UMFPACK_defaults umfpack_di_defaults #define UMFPACK_free_numeric umfpack_di_free_numeric #define UMFPACK_free_symbolic umfpack_di_free_symbolic #define UMFPACK_get_lunz umfpack_di_get_lunz #define UMFPACK_get_numeric umfpack_di_get_numeric #define UMFPACK_get_symbolic umfpack_di_get_symbolic #define UMFPACK_get_determinant umfpack_di_get_determinant #define UMFPACK_numeric umfpack_di_numeric #define UMFPACK_qsymbolic umfpack_di_qsymbolic #define UMFPACK_report_control umfpack_di_report_control #define UMFPACK_report_info umfpack_di_report_info #define UMFPACK_report_matrix umfpack_di_report_matrix #define UMFPACK_report_numeric umfpack_di_report_numeric #define UMFPACK_report_perm umfpack_di_report_perm #define UMFPACK_report_status umfpack_di_report_status #define UMFPACK_report_symbolic umfpack_di_report_symbolic #define UMFPACK_report_triplet umfpack_di_report_triplet #define UMFPACK_report_vector umfpack_di_report_vector #define UMFPACK_save_numeric umfpack_di_save_numeric #define UMFPACK_save_symbolic umfpack_di_save_symbolic #define UMFPACK_load_numeric umfpack_di_load_numeric #define UMFPACK_load_symbolic umfpack_di_load_symbolic #define UMFPACK_scale umfpack_di_scale #define UMFPACK_solve umfpack_di_solve #define UMFPACK_symbolic umfpack_di_symbolic #define UMFPACK_transpose umfpack_di_transpose #define UMFPACK_triplet_to_col umfpack_di_triplet_to_col #define UMFPACK_wsolve umfpack_di_wsolve /* for debugging only: */ #define UMF_malloc_count umf_i_malloc_count #define UMF_debug umfdi_debug #define UMF_allocfail umfdi_allocfail #define UMF_gprob umfdi_gprob #define UMF_dump_dense umfdi_dump_dense #define UMF_dump_element umfdi_dump_element #define UMF_dump_rowcol umfdi_dump_rowcol #define UMF_dump_matrix umfdi_dump_matrix #define UMF_dump_current_front umfdi_dump_current_front #define UMF_dump_lu umfdi_dump_lu #define UMF_dump_memory umfdi_dump_memory #define UMF_dump_packed_memory umfdi_dump_packed_memory #define UMF_dump_col_matrix umfdi_dump_col_matrix #define UMF_dump_chain umfdi_dump_chain #define UMF_dump_start umfdi_dump_start #define UMF_dump_rowmerge umfdi_dump_rowmerge #define UMF_dump_diagonal_map umfdi_dump_diagonal_map #endif /* -------------------------------------------------------------------------- */ /* Double precision, with UF_long's as integers */ /* -------------------------------------------------------------------------- */ #ifdef DLONG #define UMF_analyze umf_l_analyze #define UMF_apply_order umf_l_apply_order #define UMF_assemble umfdl_assemble #define UMF_assemble_fixq umfdl_assemble_fixq #define UMF_blas3_update umfdl_blas3_update #define UMF_build_tuples umfdl_build_tuples #define UMF_build_tuples_usage umfdl_build_tuples_usage #define UMF_colamd umf_l_colamd #define UMF_colamd_set_defaults umf_l_colamd_set_defaults #define UMF_create_element umfdl_create_element #define UMF_extend_front umfdl_extend_front #define UMF_free umf_l_free #define UMF_fsize umf_l_fsize #define UMF_garbage_collection umfdl_garbage_collection #define UMF_get_memory umfdl_get_memory #define UMF_grow_front umfdl_grow_front #define UMF_init_front umfdl_init_front #define UMF_is_permutation umf_l_is_permutation #define UMF_kernel umfdl_kernel #define UMF_kernel_init umfdl_kernel_init #define UMF_kernel_init_usage umfdl_kernel_init_usage #define UMF_kernel_wrapup umfdl_kernel_wrapup #define UMF_local_search umfdl_local_search #define UMF_lsolve umfdl_lsolve #define UMF_ltsolve umfdl_ltsolve #define UMF_lhsolve umfdl_lhsolve #define UMF_malloc umf_l_malloc #define UMF_mem_alloc_element umfdl_mem_alloc_element #define UMF_mem_alloc_head_block umfdl_mem_alloc_head_block #define UMF_mem_alloc_tail_block umfdl_mem_alloc_tail_block #define UMF_mem_free_tail_block umfdl_mem_free_tail_block #define UMF_mem_init_memoryspace umfdl_mem_init_memoryspace #define UMF_realloc umf_l_realloc #define UMF_report_perm umf_l_report_perm #define UMF_report_vector umfdl_report_vector #define UMF_row_search umfdl_row_search #define UMF_scale umfdl_scale #define UMF_scale_column umfdl_scale_column #define UMF_set_stats umf_l_set_stats #define UMF_singletons umf_l_singletons #define UMF_solve umfdl_solve #define UMF_start_front umfdl_start_front #define UMF_store_lu umfdl_store_lu #define UMF_store_lu_drop umfdl_store_lu_drop #define UMF_symbolic_usage umfdl_symbolic_usage #define UMF_transpose umfdl_transpose #define UMF_tuple_lengths umfdl_tuple_lengths #define UMF_usolve umfdl_usolve #define UMF_utsolve umfdl_utsolve #define UMF_uhsolve umfdl_uhsolve #define UMF_valid_numeric umfdl_valid_numeric #define UMF_valid_symbolic umfdl_valid_symbolic #define UMF_triplet_map_x umfdl_triplet_map_x #define UMF_triplet_map_nox umfdl_triplet_map_nox #define UMF_triplet_nomap_x umfdl_triplet_nomap_x #define UMF_triplet_nomap_nox umfdl_triplet_nomap_nox #define UMF_2by2 umfdl_2by2 #define UMFPACK_col_to_triplet umfpack_dl_col_to_triplet #define UMFPACK_defaults umfpack_dl_defaults #define UMFPACK_free_numeric umfpack_dl_free_numeric #define UMFPACK_free_symbolic umfpack_dl_free_symbolic #define UMFPACK_get_lunz umfpack_dl_get_lunz #define UMFPACK_get_numeric umfpack_dl_get_numeric #define UMFPACK_get_symbolic umfpack_dl_get_symbolic #define UMFPACK_get_determinant umfpack_dl_get_determinant #define UMFPACK_numeric umfpack_dl_numeric #define UMFPACK_qsymbolic umfpack_dl_qsymbolic #define UMFPACK_report_control umfpack_dl_report_control #define UMFPACK_report_info umfpack_dl_report_info #define UMFPACK_report_matrix umfpack_dl_report_matrix #define UMFPACK_report_numeric umfpack_dl_report_numeric #define UMFPACK_report_perm umfpack_dl_report_perm #define UMFPACK_report_status umfpack_dl_report_status #define UMFPACK_report_symbolic umfpack_dl_report_symbolic #define UMFPACK_report_triplet umfpack_dl_report_triplet #define UMFPACK_report_vector umfpack_dl_report_vector #define UMFPACK_save_numeric umfpack_dl_save_numeric #define UMFPACK_save_symbolic umfpack_dl_save_symbolic #define UMFPACK_load_numeric umfpack_dl_load_numeric #define UMFPACK_load_symbolic umfpack_dl_load_symbolic #define UMFPACK_scale umfpack_dl_scale #define UMFPACK_solve umfpack_dl_solve #define UMFPACK_symbolic umfpack_dl_symbolic #define UMFPACK_transpose umfpack_dl_transpose #define UMFPACK_triplet_to_col umfpack_dl_triplet_to_col #define UMFPACK_wsolve umfpack_dl_wsolve /* for debugging only: */ #define UMF_malloc_count umf_l_malloc_count #define UMF_debug umfdl_debug #define UMF_allocfail umfdl_allocfail #define UMF_gprob umfdl_gprob #define UMF_dump_dense umfdl_dump_dense #define UMF_dump_element umfdl_dump_element #define UMF_dump_rowcol umfdl_dump_rowcol #define UMF_dump_matrix umfdl_dump_matrix #define UMF_dump_current_front umfdl_dump_current_front #define UMF_dump_lu umfdl_dump_lu #define UMF_dump_memory umfdl_dump_memory #define UMF_dump_packed_memory umfdl_dump_packed_memory #define UMF_dump_col_matrix umfdl_dump_col_matrix #define UMF_dump_chain umfdl_dump_chain #define UMF_dump_start umfdl_dump_start #define UMF_dump_rowmerge umfdl_dump_rowmerge #define UMF_dump_diagonal_map umfdl_dump_diagonal_map #endif /* -------------------------------------------------------------------------- */ /* Complex double precision, with int's as integers */ /* -------------------------------------------------------------------------- */ #ifdef ZINT #define UMF_analyze umf_i_analyze #define UMF_apply_order umf_i_apply_order #define UMF_assemble umfzi_assemble #define UMF_assemble_fixq umfzi_assemble_fixq #define UMF_blas3_update umfzi_blas3_update #define UMF_build_tuples umfzi_build_tuples #define UMF_build_tuples_usage umfzi_build_tuples_usage #define UMF_colamd umf_i_colamd #define UMF_colamd_set_defaults umf_i_colamd_set_defaults #define UMF_create_element umfzi_create_element #define UMF_extend_front umfzi_extend_front #define UMF_free umf_i_free #define UMF_fsize umf_i_fsize #define UMF_garbage_collection umfzi_garbage_collection #define UMF_get_memory umfzi_get_memory #define UMF_grow_front umfzi_grow_front #define UMF_init_front umfzi_init_front #define UMF_is_permutation umf_i_is_permutation #define UMF_kernel umfzi_kernel #define UMF_kernel_init umfzi_kernel_init #define UMF_kernel_init_usage umfzi_kernel_init_usage #define UMF_kernel_wrapup umfzi_kernel_wrapup #define UMF_local_search umfzi_local_search #define UMF_lsolve umfzi_lsolve #define UMF_ltsolve umfzi_ltsolve #define UMF_lhsolve umfzi_lhsolve #define UMF_malloc umf_i_malloc #define UMF_mem_alloc_element umfzi_mem_alloc_element #define UMF_mem_alloc_head_block umfzi_mem_alloc_head_block #define UMF_mem_alloc_tail_block umfzi_mem_alloc_tail_block #define UMF_mem_free_tail_block umfzi_mem_free_tail_block #define UMF_mem_init_memoryspace umfzi_mem_init_memoryspace #define UMF_realloc umf_i_realloc #define UMF_report_perm umf_i_report_perm #define UMF_report_vector umfzi_report_vector #define UMF_row_search umfzi_row_search #define UMF_scale umfzi_scale #define UMF_scale_column umfzi_scale_column #define UMF_set_stats umfzi_set_stats #define UMF_singletons umf_i_singletons #define UMF_solve umfzi_solve #define UMF_start_front umfzi_start_front #define UMF_store_lu umfzi_store_lu #define UMF_store_lu_drop umfzi_store_lu_drop #define UMF_symbolic_usage umfzi_symbolic_usage #define UMF_transpose umfzi_transpose #define UMF_tuple_lengths umfzi_tuple_lengths #define UMF_usolve umfzi_usolve #define UMF_utsolve umfzi_utsolve #define UMF_uhsolve umfzi_uhsolve #define UMF_valid_numeric umfzi_valid_numeric #define UMF_valid_symbolic umfzi_valid_symbolic #define UMF_triplet_map_x umfzi_triplet_map_x #define UMF_triplet_map_nox umfzi_triplet_map_nox #define UMF_triplet_nomap_x umfzi_triplet_nomap_x #define UMF_triplet_nomap_nox umfzi_triplet_nomap_nox #define UMF_2by2 umfzi_2by2 #define UMFPACK_col_to_triplet umfpack_zi_col_to_triplet #define UMFPACK_defaults umfpack_zi_defaults #define UMFPACK_free_numeric umfpack_zi_free_numeric #define UMFPACK_free_symbolic umfpack_zi_free_symbolic #define UMFPACK_get_lunz umfpack_zi_get_lunz #define UMFPACK_get_numeric umfpack_zi_get_numeric #define UMFPACK_get_symbolic umfpack_zi_get_symbolic #define UMFPACK_get_determinant umfpack_zi_get_determinant #define UMFPACK_numeric umfpack_zi_numeric #define UMFPACK_qsymbolic umfpack_zi_qsymbolic #define UMFPACK_report_control umfpack_zi_report_control #define UMFPACK_report_info umfpack_zi_report_info #define UMFPACK_report_matrix umfpack_zi_report_matrix #define UMFPACK_report_numeric umfpack_zi_report_numeric #define UMFPACK_report_perm umfpack_zi_report_perm #define UMFPACK_report_status umfpack_zi_report_status #define UMFPACK_report_symbolic umfpack_zi_report_symbolic #define UMFPACK_report_triplet umfpack_zi_report_triplet #define UMFPACK_report_vector umfpack_zi_report_vector #define UMFPACK_save_numeric umfpack_zi_save_numeric #define UMFPACK_save_symbolic umfpack_zi_save_symbolic #define UMFPACK_load_numeric umfpack_zi_load_numeric #define UMFPACK_load_symbolic umfpack_zi_load_symbolic #define UMFPACK_scale umfpack_zi_scale #define UMFPACK_solve umfpack_zi_solve #define UMFPACK_symbolic umfpack_zi_symbolic #define UMFPACK_transpose umfpack_zi_transpose #define UMFPACK_triplet_to_col umfpack_zi_triplet_to_col #define UMFPACK_wsolve umfpack_zi_wsolve /* for debugging only: */ #define UMF_malloc_count umf_i_malloc_count #define UMF_debug umfzi_debug #define UMF_allocfail umfzi_allocfail #define UMF_gprob umfzi_gprob #define UMF_dump_dense umfzi_dump_dense #define UMF_dump_element umfzi_dump_element #define UMF_dump_rowcol umfzi_dump_rowcol #define UMF_dump_matrix umfzi_dump_matrix #define UMF_dump_current_front umfzi_dump_current_front #define UMF_dump_lu umfzi_dump_lu #define UMF_dump_memory umfzi_dump_memory #define UMF_dump_packed_memory umfzi_dump_packed_memory #define UMF_dump_col_matrix umfzi_dump_col_matrix #define UMF_dump_chain umfzi_dump_chain #define UMF_dump_start umfzi_dump_start #define UMF_dump_rowmerge umfzi_dump_rowmerge #define UMF_dump_diagonal_map umfzi_dump_diagonal_map #endif /* -------------------------------------------------------------------------- */ /* Complex double precision, with UF_long's as integers */ /* -------------------------------------------------------------------------- */ #ifdef ZLONG #define UMF_analyze umf_l_analyze #define UMF_apply_order umf_l_apply_order #define UMF_assemble umfzl_assemble #define UMF_assemble_fixq umfzl_assemble_fixq #define UMF_blas3_update umfzl_blas3_update #define UMF_build_tuples umfzl_build_tuples #define UMF_build_tuples_usage umfzl_build_tuples_usage #define UMF_colamd umf_l_colamd #define UMF_colamd_set_defaults umf_l_colamd_set_defaults #define UMF_create_element umfzl_create_element #define UMF_extend_front umfzl_extend_front #define UMF_free umf_l_free #define UMF_fsize umf_l_fsize #define UMF_garbage_collection umfzl_garbage_collection #define UMF_get_memory umfzl_get_memory #define UMF_grow_front umfzl_grow_front #define UMF_init_front umfzl_init_front #define UMF_is_permutation umf_l_is_permutation #define UMF_kernel umfzl_kernel #define UMF_kernel_init umfzl_kernel_init #define UMF_kernel_init_usage umfzl_kernel_init_usage #define UMF_kernel_wrapup umfzl_kernel_wrapup #define UMF_local_search umfzl_local_search #define UMF_lsolve umfzl_lsolve #define UMF_ltsolve umfzl_ltsolve #define UMF_lhsolve umfzl_lhsolve #define UMF_malloc umf_l_malloc #define UMF_mem_alloc_element umfzl_mem_alloc_element #define UMF_mem_alloc_head_block umfzl_mem_alloc_head_block #define UMF_mem_alloc_tail_block umfzl_mem_alloc_tail_block #define UMF_mem_free_tail_block umfzl_mem_free_tail_block #define UMF_mem_init_memoryspace umfzl_mem_init_memoryspace #define UMF_realloc umf_l_realloc #define UMF_report_perm umf_l_report_perm #define UMF_report_vector umfzl_report_vector #define UMF_row_search umfzl_row_search #define UMF_scale umfzl_scale #define UMF_scale_column umfzl_scale_column #define UMF_set_stats umfzl_set_stats #define UMF_singletons umf_l_singletons #define UMF_solve umfzl_solve #define UMF_start_front umfzl_start_front #define UMF_store_lu umfzl_store_lu #define UMF_store_lu_drop umfzl_store_lu_drop #define UMF_symbolic_usage umfzl_symbolic_usage #define UMF_transpose umfzl_transpose #define UMF_tuple_lengths umfzl_tuple_lengths #define UMF_usolve umfzl_usolve #define UMF_utsolve umfzl_utsolve #define UMF_uhsolve umfzl_uhsolve #define UMF_valid_numeric umfzl_valid_numeric #define UMF_valid_symbolic umfzl_valid_symbolic #define UMF_triplet_map_x umfzl_triplet_map_x #define UMF_triplet_map_nox umfzl_triplet_map_nox #define UMF_triplet_nomap_x umfzl_triplet_nomap_x #define UMF_triplet_nomap_nox umfzl_triplet_nomap_nox #define UMF_2by2 umfzl_2by2 #define UMFPACK_col_to_triplet umfpack_zl_col_to_triplet #define UMFPACK_defaults umfpack_zl_defaults #define UMFPACK_free_numeric umfpack_zl_free_numeric #define UMFPACK_free_symbolic umfpack_zl_free_symbolic #define UMFPACK_get_lunz umfpack_zl_get_lunz #define UMFPACK_get_numeric umfpack_zl_get_numeric #define UMFPACK_get_symbolic umfpack_zl_get_symbolic #define UMFPACK_get_determinant umfpack_zl_get_determinant #define UMFPACK_numeric umfpack_zl_numeric #define UMFPACK_qsymbolic umfpack_zl_qsymbolic #define UMFPACK_report_control umfpack_zl_report_control #define UMFPACK_report_info umfpack_zl_report_info #define UMFPACK_report_matrix umfpack_zl_report_matrix #define UMFPACK_report_numeric umfpack_zl_report_numeric #define UMFPACK_report_perm umfpack_zl_report_perm #define UMFPACK_report_status umfpack_zl_report_status #define UMFPACK_report_symbolic umfpack_zl_report_symbolic #define UMFPACK_report_triplet umfpack_zl_report_triplet #define UMFPACK_report_vector umfpack_zl_report_vector #define UMFPACK_save_numeric umfpack_zl_save_numeric #define UMFPACK_save_symbolic umfpack_zl_save_symbolic #define UMFPACK_load_numeric umfpack_zl_load_numeric #define UMFPACK_load_symbolic umfpack_zl_load_symbolic #define UMFPACK_scale umfpack_zl_scale #define UMFPACK_solve umfpack_zl_solve #define UMFPACK_symbolic umfpack_zl_symbolic #define UMFPACK_transpose umfpack_zl_transpose #define UMFPACK_triplet_to_col umfpack_zl_triplet_to_col #define UMFPACK_wsolve umfpack_zl_wsolve /* for debugging only: */ #define UMF_malloc_count umf_l_malloc_count #define UMF_debug umfzl_debug #define UMF_allocfail umfzl_allocfail #define UMF_gprob umfzl_gprob #define UMF_dump_dense umfzl_dump_dense #define UMF_dump_element umfzl_dump_element #define UMF_dump_rowcol umfzl_dump_rowcol #define UMF_dump_matrix umfzl_dump_matrix #define UMF_dump_current_front umfzl_dump_current_front #define UMF_dump_lu umfzl_dump_lu #define UMF_dump_memory umfzl_dump_memory #define UMF_dump_packed_memory umfzl_dump_packed_memory #define UMF_dump_col_matrix umfzl_dump_col_matrix #define UMF_dump_chain umfzl_dump_chain #define UMF_dump_start umfzl_dump_start #define UMF_dump_rowmerge umfzl_dump_rowmerge #define UMF_dump_diagonal_map umfzl_dump_diagonal_map #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.c0000644000175000017500000000533111674452555023564 0ustar sonnesonne/* ========================================================================== */ /* === UMF_report_vector ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.h" #include "umf_report_vector.h" /* ========================================================================== */ /* === print_value ========================================================== */ /* ========================================================================== */ PRIVATE void print_value ( Int i, const double Xx [ ], const double Xz [ ], /* used for complex case only */ Int scalar /* if true, then print real part only */ ) { Entry xi ; /* if Xz is null, then X is in "merged" format (compatible with Entry, */ /* and ANSI C99 double _Complex type). */ PRINTF ((" "ID" :", INDEX (i))) ; if (scalar) { PRINT_SCALAR (Xx [i]) ; } else { ASSIGN (xi, Xx, Xz, i, SPLIT (Xz)) ; PRINT_ENTRY (xi) ; } PRINTF (("\n")) ; } /* ========================================================================== */ /* === UMF_report_vector ==================================================== */ /* ========================================================================== */ GLOBAL Int UMF_report_vector ( Int n, const double Xx [ ], const double Xz [ ], Int prl, Int user, Int scalar ) { Int n2, i ; if (user || prl >= 4) { PRINTF (("dense vector, n = "ID". ", n)) ; } if (user) { if (!Xx) { PRINTF (("ERROR: vector not present\n\n")) ; return (UMFPACK_ERROR_argument_missing) ; } if (n < 0) { PRINTF (("ERROR: length of vector is < 0\n\n")) ; return (UMFPACK_ERROR_n_nonpositive) ; } } if (user || prl >= 4) { PRINTF4 (("\n")) ; } if (prl == 4) { /* print level of 4 */ n2 = MIN (10, n) ; for (i = 0 ; i < n2 ; i++) { print_value (i, Xx, Xz, scalar) ; } if (n2 < n) { PRINTF ((" ...\n")) ; print_value (n-1, Xx, Xz, scalar) ; } } else if (prl > 4) { /* print level 4 or more */ for (i = 0 ; i < n ; i++) { print_value (i, Xx, Xz, scalar) ; } } PRINTF4 ((" dense vector ")) ; if (user || prl >= 4) { PRINTF (("OK\n\n")) ; } return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.h0000644000175000017500000000075711674452555022324 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void *UMF_realloc ( void *p, Int n_objects, size_t size_of_object ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.c0000644000175000017500000000507011674452555024330 0ustar sonnesonne/* ========================================================================== */ /* === UMF_mem_alloc_element ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ /* Allocate a nrows-by-ncols element, and initialize it. */ /* Returns the index into Numeric->Memory if successful, or 0 on failure. */ #include "umf_internal.h" #include "umf_mem_alloc_element.h" #include "umf_mem_alloc_tail_block.h" GLOBAL Int UMF_mem_alloc_element ( NumericType *Numeric, Int nrows, Int ncols, Int **Rows, Int **Cols, Entry **C, Int *size, Element **epout ) { Element *ep ; Unit *p ; Int i ; ASSERT (Numeric != (NumericType *) NULL) ; ASSERT (Numeric->Memory != (Unit *) NULL) ; *size = GET_ELEMENT_SIZE (nrows, ncols) ; if (INT_OVERFLOW (DGET_ELEMENT_SIZE (nrows, ncols) + 1)) { /* :: allocate element, int overflow :: */ return (0) ; /* problem is too large */ } i = UMF_mem_alloc_tail_block (Numeric, *size) ; (*size)++ ; if (!i) { DEBUG0 (("alloc element failed - out of memory\n")) ; return (0) ; /* out of memory */ } p = Numeric->Memory + i ; ep = (Element *) p ; DEBUG2 (("alloc_element done ("ID" x "ID"): p: "ID" i "ID"\n", nrows, ncols, (Int) (p-Numeric->Memory), i)) ; /* Element data structure, in order: */ p += UNITS (Element, 1) ; /* (1) Element header */ *Cols = (Int *) p ; /* (2) col [0..ncols-1] indices */ *Rows = *Cols + ncols ; /* (3) row [0..nrows-1] indices */ p += UNITS (Int, ncols + nrows) ; *C = (Entry *) p ; /* (4) C [0..nrows-1, 0..ncols-1] */ ep->nrows = nrows ; /* initialize the header information */ ep->ncols = ncols ; ep->nrowsleft = nrows ; ep->ncolsleft = ncols ; ep->cdeg = 0 ; ep->rdeg = 0 ; ep->next = EMPTY ; DEBUG2 (("new block size: "ID" ", GET_BLOCK_SIZE (Numeric->Memory + i))) ; DEBUG2 (("Element size needed "ID"\n", GET_ELEMENT_SIZE (nrows, ncols))) ; *epout = ep ; /* return the offset into Numeric->Memory */ return (i) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_col_to_triplet.c0000644000175000017500000000372011674452555024550 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_col_to_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User callable. Converts a column-oriented input matrix to triplet form by constructing the column indices Tj from the column pointers Ap. The matrix may be singular. See umfpack_col_to_triplet.h for details. */ #include "umf_internal.h" GLOBAL Int UMFPACK_col_to_triplet ( Int n_col, const Int Ap [ ], Int Tj [ ] ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int nz, j, p, p1, p2, length ; /* ---------------------------------------------------------------------- */ /* construct the column indices */ /* ---------------------------------------------------------------------- */ if (!Ap || !Tj) { return (UMFPACK_ERROR_argument_missing) ; } if (n_col <= 0) { return (UMFPACK_ERROR_n_nonpositive) ; } if (Ap [0] != 0) { return (UMFPACK_ERROR_invalid_matrix) ; } nz = Ap [n_col] ; if (nz < 0) { return (UMFPACK_ERROR_invalid_matrix) ; } for (j = 0 ; j < n_col ; j++) { p1 = Ap [j] ; p2 = Ap [j+1] ; length = p2 - p1 ; if (length < 0 || p2 > nz) { return (UMFPACK_ERROR_invalid_matrix) ; } for (p = p1 ; p < p2 ; p++) { Tj [p] = j ; } } return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.c0000644000175000017500000010220211674452555022455 0ustar sonnesonne/* ========================================================================== */ /* === UMF_assemble ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Degree update and numerical assembly. This is compiled twice (with and * without FIXQ) for each real/complex int/UF_long version, for a total of 8 * versions.*/ #include "umf_internal.h" #include "umf_assemble.h" #include "umf_mem_free_tail_block.h" /* ========================================================================== */ /* === row_assemble ========================================================= */ /* ========================================================================== */ PRIVATE void row_assemble ( Int row, NumericType *Numeric, WorkType *Work ) { Entry *S, *Fcblock, *Frow ; Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Row_tuples, *Row_tlen, rdeg0, f, nrows, ncols, *Rows, *Cols, col, ncolsleft, j ; Tuple *tp, *tp1, *tp2, *tpend ; Unit *Memory, *p ; Element *ep ; #ifndef FIXQ Int *Col_degree ; Col_degree = Numeric->Cperm ; #endif Row_tuples = Numeric->Uip ; tpi = Row_tuples [row] ; if (!tpi) return ; Memory = Numeric->Memory ; E = Work->E ; Fcpos = Work->Fcpos ; Frpos = Work->Frpos ; Row_degree = Numeric->Rperm ; Row_tlen = Numeric->Uilen ; E = Work->E ; Memory = Numeric->Memory ; rdeg0 = Work->rdeg0 ; Fcblock = Work->Fcblock ; #ifndef NDEBUG DEBUG6 (("SCAN2-row: "ID"\n", row)) ; UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ; #endif ASSERT (NON_PIVOTAL_ROW (row)) ; tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Row_tlen [row] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; Rows = Cols + ep->ncols ; if (Rows [f] == EMPTY) continue ; /* row already assembled */ ASSERT (row == Rows [f] && row >= 0 && row < Work->n_row) ; if (ep->rdeg == rdeg0) { /* ------------------------------------------------------ */ /* this is an old Lson - assemble just one row */ /* ------------------------------------------------------ */ /* flag the row as assembled from the Lson */ Rows [f] = EMPTY ; nrows = ep->nrows ; ncols = ep->ncols ; p += UNITS (Int, ncols + nrows) ; S = ((Entry *) p) + f ; DEBUG6 (("Old LSON: "ID"\n", e)) ; #ifndef NDEBUG UMF_dump_element (Numeric, Work, e, FALSE) ; #endif ncolsleft = ep->ncolsleft ; Frow = Fcblock + Frpos [row] ; DEBUG6 (("LSON found (in scan2-row): "ID"\n", e)) ; Row_degree [row] -= ncolsleft ; if (ncols == ncolsleft) { /* -------------------------------------------------- */ /* no columns assembled out this Lson yet */ /* -------------------------------------------------- */ #pragma ivdep for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; ASSERT (col >= 0 && col < Work->n_col) ; #ifndef FIXQ Col_degree [col] -- ; #endif /* Frow [Fcpos [col]] += *S ; */ ASSEMBLE (Frow [Fcpos [col]], *S) ; S += nrows ; } } else { /* -------------------------------------------------- */ /* some columns have been assembled out of this Lson */ /* -------------------------------------------------- */ #pragma ivdep for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; if (col >= 0) { ASSERT (col < Work->n_col) ; #ifndef FIXQ Col_degree [col] -- ; #endif /* Frow [Fcpos [col]] += *S ; */ ASSEMBLE (Frow [Fcpos [col]], *S) ; } S += nrows ; } } ep->nrowsleft-- ; ASSERT (ep->nrowsleft > 0) ; } else { *tp2++ = *tp ; /* leave the tuple in the list */ } } Row_tlen [row] = tp2 - tp1 ; #ifndef NDEBUG DEBUG7 (("row assembled in scan2-row: "ID"\n", row)) ; UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ; DEBUG7 (("Current frontal matrix: (scan 1b)\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif } /* ========================================================================== */ /* === col_assemble ========================================================= */ /* ========================================================================== */ PRIVATE void col_assemble ( Int col, NumericType *Numeric, WorkType *Work ) { Entry *S, *Fcblock, *Fcol ; Int tpi, e, *E, *Fcpos, *Frpos, *Row_degree, *Col_tuples, *Col_tlen, cdeg0, f, nrows, ncols, *Rows, *Cols, row, nrowsleft, i ; Tuple *tp, *tp1, *tp2, *tpend ; Unit *Memory, *p ; Element *ep ; #if !defined (FIXQ) || !defined (NDEBUG) Int *Col_degree ; Col_degree = Numeric->Cperm ; #endif Col_tuples = Numeric->Lip ; tpi = Col_tuples [col] ; if (!tpi) return ; Memory = Numeric->Memory ; E = Work->E ; Fcpos = Work->Fcpos ; Frpos = Work->Frpos ; Row_degree = Numeric->Rperm ; Col_tlen = Numeric->Lilen ; E = Work->E ; Memory = Numeric->Memory ; cdeg0 = Work->cdeg0 ; Fcblock = Work->Fcblock ; DEBUG6 (("SCAN2-col: "ID"\n", col)) ; #ifndef NDEBUG UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; #endif ASSERT (NON_PIVOTAL_COL (col)) ; tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Col_tlen [col] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; if (Cols [f] == EMPTY) continue ; /* col already assembled */ ASSERT (col == Cols [f] && col >= 0 && col < Work->n_col) ; if (ep->cdeg == cdeg0) { /* ------------------------------------------------------ */ /* this is an old Uson - assemble just one col */ /* ------------------------------------------------------ */ /* flag the col as assembled from the Uson */ Cols [f] = EMPTY ; nrows = ep->nrows ; ncols = ep->ncols ; Rows = Cols + ncols ; p += UNITS (Int, ncols + nrows) ; S = ((Entry *) p) + f * nrows ; DEBUG6 (("Old USON: "ID"\n", e)) ; #ifndef NDEBUG UMF_dump_element (Numeric, Work, e, FALSE) ; #endif nrowsleft = ep->nrowsleft ; Fcol = Fcblock + Fcpos [col] ; DEBUG6 (("USON found (in scan2-col): "ID"\n", e)) ; #ifndef FIXQ Col_degree [col] -= nrowsleft ; #endif if (nrows == nrowsleft) { /* -------------------------------------------------- */ /* no rows assembled out of this Uson yet */ /* -------------------------------------------------- */ #pragma ivdep for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; ASSERT (row >= 0 && row < Work->n_row) ; Row_degree [row]-- ; /* Fcol [Frpos [row]] += S [i] ; */ ASSEMBLE (Fcol [Frpos [row]], S [i]) ; } } else { /* -------------------------------------------------- */ /* some rows have been assembled out of this Uson */ /* -------------------------------------------------- */ #pragma ivdep for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; if (row >= 0) { ASSERT (row < Work->n_row) ; Row_degree [row]-- ; /* Fcol [Frpos [row]] += S [i] ; */ ASSEMBLE (Fcol [Frpos [row]], S [i]) ; } } } ep->ncolsleft-- ; ASSERT (ep->ncolsleft > 0) ; } else { *tp2++ = *tp ; /* leave the tuple in the list */ } } Col_tlen [col] = tp2 - tp1 ; #ifndef NDEBUG DEBUG7 (("Column assembled in scan2-col: "ID"\n", col)) ; UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; DEBUG7 (("Current frontal matrix: after scan2-col\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif } /* ========================================================================== */ /* === UMF_assemble / UMF_assemble_fixq ===================================== */ /* ========================================================================== */ #ifndef FIXQ GLOBAL void UMF_assemble #else GLOBAL void UMF_assemble_fixq #endif ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int e, i, row, col, i2, nrows, ncols, f, tpi, extcdeg, extrdeg, rdeg0, cdeg0, son_list, next, nrows_to_assemble, ncols_to_assemble, ngetrows, j, j2, nrowsleft, /* number of rows remaining in S */ ncolsleft, /* number of columns remaining in S */ prior_Lson, prior_Uson, *E, *Cols, *Rows, *Wm, *Woo, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, *Col_tlen ; Unit *Memory, *p ; Element *ep ; Tuple *tp, *tp1, *tp2, *tpend ; Entry *S, /* a pointer into the contribution block of a son */ *Fcblock, /* current contribution block */ *Fcol ; /* a column of FC */ Int *Frpos, *Fcpos, fnrows, /* number of rows in contribution block in F */ fncols ; /* number of columns in contribution block in F */ #if !defined (FIXQ) || !defined (NDEBUG) Int *Col_degree ; #endif #ifndef NDEBUG Int n_row, n_col ; n_row = Work->n_row ; n_col = Work->n_col ; DEBUG3 (("::Assemble SCANS 1-4\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif #if !defined (FIXQ) || !defined (NDEBUG) Col_degree = Numeric->Cperm ; /* not updated if FIXQ is true */ #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ fncols = Work->fncols ; fnrows = Work->fnrows ; Fcpos = Work->Fcpos ; Frpos = Work->Frpos ; Row_degree = Numeric->Rperm ; Row_tuples = Numeric->Uip ; Row_tlen = Numeric->Uilen ; Col_tuples = Numeric->Lip ; Col_tlen = Numeric->Lilen ; E = Work->E ; Memory = Numeric->Memory ; Wm = Work->Wm ; Woo = Work->Woo ; rdeg0 = Work->rdeg0 ; cdeg0 = Work->cdeg0 ; #ifndef NDEBUG DEBUG6 (("============================================\n")) ; DEBUG6 (("Degree update, assembly.\n")) ; DEBUG6 (("pivot row pattern: fncols="ID"\n", fncols)) ; for (j = 0 ; j < fncols ; j++) { col = Work->Fcols [j] ; DEBUG6 ((ID" ", col)) ; ASSERT (Fcpos [col] == j * Work->fnr_curr) ; ASSERT (NON_PIVOTAL_COL (col)) ; } ASSERT (Fcpos [Work->pivcol] >= 0) ; DEBUG6 (("pivcol: "ID" pos "ID" fnr_curr "ID" fncols "ID"\n", Work->pivcol, Fcpos [Work->pivcol], Work->fnr_curr, fncols)) ; ASSERT (Fcpos [Work->pivcol] < fncols * Work->fnr_curr) ; DEBUG6 (("\npivot col pattern: fnrows="ID"\n", fnrows)) ; for (i = 0 ; i < fnrows ; i++) { row = Work->Frows [i] ; DEBUG6 ((ID" ", row)) ; ASSERT (Frpos [row] == i) ; ASSERT (NON_PIVOTAL_ROW (row)) ; } DEBUG6 (("\n")) ; ASSERT (Frpos [Work->pivrow] >= 0) ; ASSERT (Frpos [Work->pivrow] < fnrows) ; ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ; ASSERT (Work->Fcblock == Work->Flublock + Work->nb * (Work->nb + Work->fnr_curr + Work->fnc_curr)) ; #endif Fcblock = Work->Fcblock ; /* ---------------------------------------------------------------------- */ /* determine the largest actual frontal matrix size (for Info only) */ /* ---------------------------------------------------------------------- */ ASSERT (fnrows == Work->fnrows_new + 1) ; ASSERT (fncols == Work->fncols_new + 1) ; Numeric->maxnrows = MAX (Numeric->maxnrows, fnrows) ; Numeric->maxncols = MAX (Numeric->maxncols, fncols) ; /* this is safe from integer overflow, since the current frontal matrix * is already allocated. */ Numeric->maxfrsize = MAX (Numeric->maxfrsize, fnrows * fncols) ; /* ---------------------------------------------------------------------- */ /* assemble from prior elements into the current frontal matrix */ /* ---------------------------------------------------------------------- */ DEBUG2 (("New assemble start [prior_element:"ID"\n", Work->prior_element)) ; /* Currently no rows or columns are marked. No elements are scanned, */ /* that is, (ep->next == EMPTY) is true for all elements */ son_list = 0 ; /* start creating son_list [ */ /* ---------------------------------------------------------------------- */ /* determine if most recent element is Lson or Uson of current front */ /* ---------------------------------------------------------------------- */ if (!Work->do_extend) { prior_Uson = ( Work->pivcol_in_front && !Work->pivrow_in_front) ; prior_Lson = (!Work->pivcol_in_front && Work->pivrow_in_front) ; if (prior_Uson || prior_Lson) { e = Work->prior_element ; if (e != EMPTY) { ASSERT (E [e]) ; p = Memory + E [e] ; ep = (Element *) p ; ep->next = son_list ; son_list = e ; #ifndef NDEBUG DEBUG2 (("e "ID" is Prior son "ID" "ID"\n", e, prior_Uson, prior_Lson)) ; UMF_dump_element (Numeric, Work, e, FALSE) ; #endif ASSERT (E [e]) ; } } } Work->prior_element = EMPTY ; /* ---------------------------------------------------------------------- */ /* SCAN1-row: scan the element lists of each new row in the pivot col */ /* and compute the external column degree for each frontal */ /* ---------------------------------------------------------------------- */ for (i2 = Work->fscan_row ; i2 < fnrows ; i2++) { /* Get a row */ row = Work->NewRows [i2] ; if (row < 0) row = FLIP (row) ; ASSERT (row >= 0 && row < n_row) ; DEBUG6 (("SCAN1-row: "ID"\n", row)) ; #ifndef NDEBUG UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ; #endif ASSERT (NON_PIVOTAL_ROW (row)) ; tpi = Row_tuples [row] ; if (!tpi) continue ; tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Row_tlen [row] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Rows = ((Int *) p) + ep->ncols ; if (Rows [f] == EMPTY) continue ; /* row already assembled */ ASSERT (row == Rows [f]) ; if (ep->cdeg < cdeg0) { /* first time seen in scan1-row */ ep->cdeg = ep->nrowsleft + cdeg0 ; DEBUG6 (("e "ID" First seen: cdeg: "ID" ", e, ep->cdeg-cdeg0)) ; ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ; } ep->cdeg-- ; /* decrement external column degree */ DEBUG6 (("e "ID" New ext col deg: "ID"\n", e, ep->cdeg - cdeg0)) ; /* this element is not yet in the new son list */ if (ep->cdeg == cdeg0 && ep->next == EMPTY) { /* A new LUson or Uson has been found */ ep->next = son_list ; son_list = e ; } ASSERT (ep->cdeg >= cdeg0) ; *tp2++ = *tp ; /* leave the tuple in the list */ } Row_tlen [row] = tp2 - tp1 ; } /* ---------------------------------------------------------------------- */ /* SCAN1-col: scan the element lists of each new col in the pivot row */ /* and compute the external row degree for each frontal */ /* ---------------------------------------------------------------------- */ for (j2 = Work->fscan_col ; j2 < fncols ; j2++) { /* Get a column */ col = Work->NewCols [j2] ; if (col < 0) col = FLIP (col) ; ASSERT (col >= 0 && col < n_col) ; DEBUG6 (("SCAN 1-col: "ID"\n", col)) ; #ifndef NDEBUG UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; #endif ASSERT (NON_PIVOTAL_COL (col)) ; tpi = Col_tuples [col] ; if (!tpi) continue ; tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Col_tlen [col] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; if (Cols [f] == EMPTY) continue ; /* column already assembled */ ASSERT (col == Cols [f]) ; if (ep->rdeg < rdeg0) { /* first time seen in scan1-col */ ep->rdeg = ep->ncolsleft + rdeg0 ; DEBUG6 (("e "ID" First seen: rdeg: "ID" ", e, ep->rdeg-rdeg0)) ; ASSERT (ep->ncolsleft > 0 && ep->nrowsleft > 0) ; } ep->rdeg-- ; /* decrement external row degree */ DEBUG6 (("e "ID" New ext row degree: "ID"\n", e, ep->rdeg-rdeg0)) ; if (ep->rdeg == rdeg0 && ep->next == EMPTY) { /* A new LUson or Lson has been found */ ep->next = son_list ; son_list = e ; } ASSERT (ep->rdeg >= rdeg0) ; *tp2++ = *tp ; /* leave the tuple in the list */ } Col_tlen [col] = tp2 - tp1 ; } /* ---------------------------------------------------------------------- */ /* assemble new sons via full scans */ /* ---------------------------------------------------------------------- */ next = EMPTY ; for (e = son_list ; e > 0 ; e = next) { ASSERT (e > 0 && e <= Work->nel && E [e]) ; p = Memory + E [e] ; DEBUG2 (("New son: "ID"\n", e)) ; #ifndef NDEBUG UMF_dump_element (Numeric, Work, e, FALSE) ; #endif GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, S) ; nrowsleft = ep->nrowsleft ; ncolsleft = ep->ncolsleft ; next = ep->next ; ep->next = EMPTY ; extrdeg = (ep->rdeg < rdeg0) ? ncolsleft : (ep->rdeg - rdeg0) ; extcdeg = (ep->cdeg < cdeg0) ? nrowsleft : (ep->cdeg - cdeg0) ; ncols_to_assemble = ncolsleft - extrdeg ; nrows_to_assemble = nrowsleft - extcdeg ; DEBUG2 (("extrdeg "ID" extcdeg "ID"\n", extrdeg, extcdeg)) ; if (extrdeg == 0 && extcdeg == 0) { /* -------------------------------------------------------------- */ /* this is an LUson - assemble an entire contribution block */ /* -------------------------------------------------------------- */ DEBUG6 (("LUson found: "ID"\n", e)) ; if (nrows == nrowsleft) { /* ---------------------------------------------------------- */ /* no rows assembled out of this LUson yet */ /* ---------------------------------------------------------- */ /* compute the compressed column offset vector*/ /* [ use Wm [0..nrows-1] for offsets */ #pragma ivdep for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; Row_degree [row] -= ncolsleft ; Wm [i] = Frpos [row] ; } if (ncols == ncolsleft) { /* ------------------------------------------------------ */ /* no rows or cols assembled out of LUson yet */ /* ------------------------------------------------------ */ for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; #ifndef FIXQ Col_degree [col] -= nrowsleft ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrows ; i++) { /* Fcol [Wm [i]] += S [i] ; */ ASSEMBLE (Fcol [Wm [i]], S [i]) ; } S += nrows ; } } else { /* ------------------------------------------------------ */ /* only cols have been assembled out of LUson */ /* ------------------------------------------------------ */ for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; if (col >= 0) { #ifndef FIXQ Col_degree [col] -= nrowsleft ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrows ; i++) { /* Fcol [Wm [i]] += S [i] ; */ ASSEMBLE (Fcol [Wm [i]], S [i]) ; } } S += nrows ; } } /* ] done using Wm [0..nrows-1] for offsets */ } else { /* ---------------------------------------------------------- */ /* some rows have been assembled out of this LUson */ /* ---------------------------------------------------------- */ /* compute the compressed column offset vector*/ /* [ use Woo,Wm [0..nrowsleft-1] for offsets */ ngetrows = 0 ; for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; if (row >= 0) { Row_degree [row] -= ncolsleft ; Woo [ngetrows] = i ; Wm [ngetrows++] = Frpos [row] ; } } ASSERT (ngetrows == nrowsleft) ; if (ncols == ncolsleft) { /* ------------------------------------------------------ */ /* only rows have been assembled out of this LUson */ /* ------------------------------------------------------ */ for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; #ifndef FIXQ Col_degree [col] -= nrowsleft ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrowsleft ; i++) { /* Fcol [Wm [i]] += S [Woo [i]] ; */ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ; } S += nrows ; } } else { /* ------------------------------------------------------ */ /* both rows and columns have been assembled out of LUson */ /* ------------------------------------------------------ */ for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; if (col >= 0) { #ifndef FIXQ Col_degree [col] -= nrowsleft ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrowsleft ; i++) { /* Fcol [Wm [i]] += S [Woo [i]] ; */ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ; } } S += nrows ; } } /* ] done using Woo,Wm [0..nrowsleft-1] */ } /* deallocate the element: remove from ordered list */ UMF_mem_free_tail_block (Numeric, E [e]) ; E [e] = 0 ; } else if (extcdeg == 0) { /* -------------------------------------------------------------- */ /* this is a Uson - assemble all possible columns */ /* -------------------------------------------------------------- */ DEBUG6 (("New USON: "ID"\n", e)) ; ASSERT (extrdeg > 0) ; DEBUG6 (("New uson "ID" cols to do "ID"\n", e, ncols_to_assemble)) ; if (ncols_to_assemble > 0) { Int skip = FALSE ; if (ncols_to_assemble * 16 < ncols && nrows == 1) { /* this is a tall and thin frontal matrix consisting of * only one column (most likely an original column). Do * not assemble it. It cannot be the pivot column, since * the pivot column element would be an LU son, not an Lson, * of the current frontal matrix. */ ASSERT (nrowsleft == 1) ; ASSERT (Rows [0] >= 0 && Rows [0] < Work->n_row) ; skip = TRUE ; Work->any_skip = TRUE ; } if (!skip) { if (nrows == nrowsleft) { /* -------------------------------------------------- */ /* no rows have been assembled out of this Uson yet */ /* -------------------------------------------------- */ /* compute the compressed column offset vector */ /* [ use Wm [0..nrows-1] for offsets */ #pragma ivdep for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; ASSERT (row >= 0 && row < n_row) ; Row_degree [row] -= ncols_to_assemble ; Wm [i] = Frpos [row] ; } for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; if ((col >= 0) && (Fcpos [col] >= 0)) { #ifndef FIXQ Col_degree [col] -= nrowsleft ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrows ; i++) { /* Fcol [Wm [i]] += S [i] ; */ ASSEMBLE (Fcol [Wm [i]], S [i]) ; } /* flag the column as assembled from Uson */ Cols [j] = EMPTY ; } S += nrows ; } /* ] done using Wm [0..nrows-1] for offsets */ } else { /* -------------------------------------------------- */ /* some rows have been assembled out of this Uson */ /* -------------------------------------------------- */ /* compute the compressed column offset vector*/ /* [ use Woo,Wm [0..nrows-1] for offsets */ ngetrows = 0 ; for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; if (row >= 0) { Row_degree [row] -= ncols_to_assemble ; ASSERT (row < n_row && Frpos [row] >= 0) ; Woo [ngetrows] = i ; Wm [ngetrows++] = Frpos [row] ; } } ASSERT (ngetrows == nrowsleft) ; for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; if ((col >= 0) && (Fcpos [col] >= 0)) { #ifndef FIXQ Col_degree [col] -= nrowsleft ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrowsleft ; i++) { /* Fcol [Wm [i]] += S [Woo [i]] ; */ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ; } /* flag the column as assembled from Uson */ Cols [j] = EMPTY ; } S += nrows ; } /* ] done using Woo,Wm */ } ep->ncolsleft = extrdeg ; } } } else { /* -------------------------------------------------------------- */ /* this is an Lson - assemble all possible rows */ /* -------------------------------------------------------------- */ DEBUG6 (("New LSON: "ID"\n", e)) ; ASSERT (extrdeg == 0 && extcdeg > 0) ; DEBUG6 (("New lson "ID" rows to do "ID"\n", e, nrows_to_assemble)) ; if (nrows_to_assemble > 0) { Int skip = FALSE ; if (nrows_to_assemble * 16 < nrows && ncols == 1) { /* this is a tall and thin frontal matrix consisting of * only one column (most likely an original column). Do * not assemble it. It cannot be the pivot column, since * the pivot column element would be an LU son, not an Lson, * of the current frontal matrix. */ ASSERT (ncolsleft == 1) ; ASSERT (Cols [0] >= 0 && Cols [0] < Work->n_col) ; Work->any_skip = TRUE ; skip = TRUE ; } if (!skip) { /* compute the compressed column offset vector */ /* [ use Woo,Wm [0..nrows-1] for offsets */ ngetrows = 0 ; for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; if ((row >= 0) && (Frpos [row] >= 0)) { ASSERT (row < n_row) ; Row_degree [row] -= ncolsleft ; Woo [ngetrows] = i ; Wm [ngetrows++] = Frpos [row] ; /* flag the row as assembled from the Lson */ Rows [i] = EMPTY ; } } ASSERT (nrowsleft - ngetrows == extcdeg) ; ASSERT (ngetrows == nrows_to_assemble) ; if (ncols == ncolsleft) { /* -------------------------------------------------- */ /* no columns assembled out this Lson yet */ /* -------------------------------------------------- */ for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; ASSERT (col >= 0 && col < n_col) ; #ifndef FIXQ Col_degree [col] -= nrows_to_assemble ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrows_to_assemble ; i++) { /* Fcol [Wm [i]] += S [Woo [i]] ; */ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ; } S += nrows ; } } else { /* -------------------------------------------------- */ /* some columns have been assembled out of this Lson */ /* -------------------------------------------------- */ for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; ASSERT (col < n_col) ; if (col >= 0) { #ifndef FIXQ Col_degree [col] -= nrows_to_assemble ; #endif Fcol = Fcblock + Fcpos [col] ; #pragma ivdep for (i = 0 ; i < nrows_to_assemble ; i++) { /* Fcol [Wm [i]] += S [Woo [i]] ; */ ASSEMBLE (Fcol [Wm [i]], S [Woo [i]]) ; } } S += nrows ; } } /* ] done using Woo,Wm */ ep->nrowsleft = extcdeg ; } } } } /* Note that garbage collection, and build tuples */ /* both destroy the son list. */ /* ] son_list now empty */ /* ---------------------------------------------------------------------- */ /* If frontal matrix extended, assemble old L/Usons from new rows/cols */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* SCAN2-row: assemble rows of old Lsons from the new rows */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG7 (("Current frontal matrix: (prior to scan2-row)\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif /* rescan the pivot row */ if (Work->any_skip) { row_assemble (Work->pivrow, Numeric, Work) ; } if (Work->do_scan2row) { for (i2 = Work->fscan_row ; i2 < fnrows ; i2++) { /* Get a row */ row = Work->NewRows [i2] ; if (row < 0) row = FLIP (row) ; ASSERT (row >= 0 && row < n_row) ; if (!(row == Work->pivrow && Work->any_skip)) { /* assemble it */ row_assemble (row, Numeric, Work) ; } } } /* ---------------------------------------------------------------------- */ /* SCAN2-col: assemble columns of old Usons from the new columns */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG7 (("Current frontal matrix: (prior to scan2-col)\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif /* rescan the pivot col */ if (Work->any_skip) { col_assemble (Work->pivcol, Numeric, Work) ; } if (Work->do_scan2col) { for (j2 = Work->fscan_col ; j2 < fncols ; j2++) { /* Get a column */ col = Work->NewCols [j2] ; if (col < 0) col = FLIP (col) ; ASSERT (col >= 0 && col < n_col) ; if (!(col == Work->pivcol && Work->any_skip)) { /* assemble it */ col_assemble (col, Numeric, Work) ; } } } /* ---------------------------------------------------------------------- */ /* done. the remainder of this routine is used only when in debug mode */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG /* ---------------------------------------------------------------------- */ /* when debugging: make sure the assembly did everything that it could */ /* ---------------------------------------------------------------------- */ DEBUG3 (("::Assemble done\n")) ; for (i2 = 0 ; i2 < fnrows ; i2++) { /* Get a row */ row = Work->Frows [i2] ; ASSERT (row >= 0 && row < n_row) ; DEBUG6 (("DEBUG SCAN 1: "ID"\n", row)) ; UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ; ASSERT (NON_PIVOTAL_ROW (row)) ; tpi = Row_tuples [row] ; if (!tpi) continue ; tp = (Tuple *) (Memory + tpi) ; tpend = tp + Row_tlen [row] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; Rows = ((Int *) p) + ep->ncols ; if (Rows [f] == EMPTY) continue ; /* row already assembled */ ASSERT (row == Rows [f]) ; extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ; extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ; DEBUG6 (( "e "ID" After assembly ext row deg: "ID" ext col degree "ID"\n", e, extrdeg, extcdeg)) ; if (Work->any_skip) { /* no Lsons in any row, except for very tall and thin ones */ ASSERT (extrdeg >= 0) ; if (extrdeg == 0) { /* this is an unassemble Lson */ ASSERT (ep->ncols == 1) ; ASSERT (ep->ncolsleft == 1) ; col = Cols [0] ; ASSERT (col != Work->pivcol) ; } } else { /* no Lsons in any row */ ASSERT (extrdeg > 0) ; /* Uson external row degree is = number of cols left */ ASSERT (IMPLIES (extcdeg == 0, extrdeg == ep->ncolsleft)) ; } } } /* ---------------------------------------------------------------------- */ for (j2 = 0 ; j2 < fncols ; j2++) { /* Get a column */ col = Work->Fcols [j2] ; ASSERT (col >= 0 && col < n_col) ; DEBUG6 (("DEBUG SCAN 2: "ID"\n", col)) ; #ifndef FIXQ UMF_dump_rowcol (1, Numeric, Work, col, TRUE) ; #else UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; #endif ASSERT (NON_PIVOTAL_COL (col)) ; tpi = Col_tuples [col] ; if (!tpi) continue ; tp = (Tuple *) (Memory + tpi) ; tpend = tp + Col_tlen [col] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; Rows = ((Int *) p) + ep->ncols ; if (Cols [f] == EMPTY) continue ; /* column already assembled */ ASSERT (col == Cols [f]) ; extrdeg = (ep->rdeg < rdeg0) ? ep->ncolsleft : (ep->rdeg - rdeg0) ; extcdeg = (ep->cdeg < cdeg0) ? ep->nrowsleft : (ep->cdeg - cdeg0) ; DEBUG6 (("e "ID" After assembly ext col deg: "ID"\n", e, extcdeg)) ; if (Work->any_skip) { /* no Usons in any column, except for very tall and thin ones */ ASSERT (extcdeg >= 0) ; if (extcdeg == 0) { /* this is an unassemble Uson */ ASSERT (ep->nrows == 1) ; ASSERT (ep->nrowsleft == 1) ; row = Rows [0] ; ASSERT (row != Work->pivrow) ; } } else { /* no Usons in any column */ ASSERT (extcdeg > 0) ; /* Lson external column degree is = number of rows left */ ASSERT (IMPLIES (extrdeg == 0, extcdeg == ep->nrowsleft)) ; } } } #endif /* NDEBUG */ } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.c0000644000175000017500000005520411674452555023027 0ustar sonnesonne/* ========================================================================== */ /* === UMF_row_search ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Find two candidate pivot rows in a column: the best one in the front, and the best one not in the front. Return the two pivot row patterns and their exact degrees. Called by UMF_local_search. Returns UMFPACK_OK if successful, or UMFPACK_WARNING_singular_matrix or UMFPACK_ERROR_different_pattern if not. */ #include "umf_internal.h" #include "umf_row_search.h" GLOBAL Int UMF_row_search ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic, Int cdeg0, /* length of column in Front */ Int cdeg1, /* length of column outside Front */ const Int Pattern [ ], /* pattern of column, Pattern [0..cdeg1 -1] */ const Int Pos [ ], /* Pos [Pattern [0..cdeg1 -1]] = 0..cdeg1 -1 */ Int pivrow [2], /* pivrow [IN] and pivrow [OUT] */ Int rdeg [2], /* rdeg [IN] and rdeg [OUT] */ Int W_i [ ], /* pattern of pivrow [IN], */ /* either Fcols or Woi */ Int W_o [ ], /* pattern of pivrow [OUT], */ /* either Wio or Woo */ Int prior_pivrow [2], /* the two other rows just scanned, if any */ const Entry Wxy [ ], /* numerical values Wxy [0..cdeg1-1], either Wx or Wy */ Int pivcol, /* the candidate column being searched */ Int freebie [ ] ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ double maxval, toler, toler2, value, pivot [2] ; Int i, row, deg, col, *Frpos, fnrows, *E, j, ncols, *Cols, *Rows, e, f, Wrpflag, *Fcpos, fncols, tpi, max_rdeg, nans_in_col, was_offdiag, diag_row, prefer_diagonal, *Wrp, found, *Diagonal_map ; Tuple *tp, *tpend, *tp1, *tp2 ; Unit *Memory, *p ; Element *ep ; Int *Row_tuples, *Row_degree, *Row_tlen ; #ifndef NDEBUG Int *Col_degree ; DEBUG2 (("Row_search:\n")) ; for (i = 0 ; i < cdeg1 ; i++) { row = Pattern [i] ; DEBUG4 ((" row: "ID"\n", row)) ; ASSERT (row >= 0 && row < Numeric->n_row) ; ASSERT (i == Pos [row]) ; } /* If row is not in Pattern [0..cdeg1-1], then Pos [row] == EMPTY */ if (UMF_debug > 0 || Numeric->n_row < 1000) { Int cnt = cdeg1 ; DEBUG4 (("Scan all rows:\n")) ; for (row = 0 ; row < Numeric->n_row ; row++) { if (Pos [row] < 0) { cnt++ ; } else { DEBUG4 ((" row: "ID" pos "ID"\n", row, Pos [row])) ; } } ASSERT (cnt == Numeric->n_row) ; } Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro only */ ASSERT (pivcol >= 0 && pivcol < Work->n_col) ; ASSERT (NON_PIVOTAL_COL (pivcol)) ; #endif pivot [IN] = 0. ; pivot [OUT] = 0. ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ Row_degree = Numeric->Rperm ; Row_tuples = Numeric->Uip ; Row_tlen = Numeric->Uilen ; Wrp = Work->Wrp ; Frpos = Work->Frpos ; E = Work->E ; Memory = Numeric->Memory ; fnrows = Work->fnrows ; prefer_diagonal = Symbolic->prefer_diagonal ; Diagonal_map = Work->Diagonal_map ; if (Diagonal_map) { diag_row = Diagonal_map [pivcol] ; was_offdiag = diag_row < 0 ; if (was_offdiag) { /* the "diagonal" entry in this column was permuted here by an * earlier pivot choice. The tighter off-diagonal tolerance will * be used instead of the symmetric tolerance. */ diag_row = FLIP (diag_row) ; } ASSERT (diag_row >= 0 && diag_row < Numeric->n_row) ; } else { diag_row = EMPTY ; /* unused */ was_offdiag = EMPTY ; /* unused */ } /* pivot row degree cannot exceed max_rdeg */ max_rdeg = Work->fncols_max ; /* ---------------------------------------------------------------------- */ /* scan pivot column for candidate rows */ /* ---------------------------------------------------------------------- */ maxval = 0.0 ; nans_in_col = FALSE ; for (i = 0 ; i < cdeg1 ; i++) { APPROX_ABS (value, Wxy [i]) ; if (SCALAR_IS_NAN (value)) { nans_in_col = TRUE ; maxval = value ; break ; } /* This test can now ignore the NaN case: */ maxval = MAX (maxval, value) ; } /* if maxval is zero, the matrix is numerically singular */ toler = Numeric->relpt * maxval ; toler2 = Numeric->relpt2 * maxval ; toler2 = was_offdiag ? toler : toler2 ; DEBUG5 (("Row_search begins [ maxval %g toler %g %g\n", maxval, toler, toler2)) ; if (SCALAR_IS_NAN (toler) || SCALAR_IS_NAN (toler2)) { nans_in_col = TRUE ; } if (!nans_in_col) { /* look for the diagonal entry, if it exists */ found = FALSE ; ASSERT (!SCALAR_IS_NAN (toler)) ; if (prefer_diagonal) { ASSERT (diag_row != EMPTY) ; i = Pos [diag_row] ; if (i >= 0) { double a ; ASSERT (i < cdeg1) ; ASSERT (diag_row == Pattern [i]) ; APPROX_ABS (a, Wxy [i]) ; ASSERT (!SCALAR_IS_NAN (a)) ; ASSERT (!SCALAR_IS_NAN (toler2)) ; if (SCALAR_IS_NONZERO (a) && a >= toler2) { /* found it! */ DEBUG3 (("Symmetric pivot: "ID" "ID"\n", pivcol, diag_row)); found = TRUE ; if (Frpos [diag_row] >= 0 && Frpos [diag_row] < fnrows) { pivrow [IN] = diag_row ; pivrow [OUT] = EMPTY ; } else { pivrow [IN] = EMPTY ; pivrow [OUT] = diag_row ; } } } } /* either no diagonal found, or we didn't look for it */ if (!found) { if (cdeg0 > 0) { /* this is a column in the front */ for (i = 0 ; i < cdeg0 ; i++) { double a ; APPROX_ABS (a, Wxy [i]) ; ASSERT (!SCALAR_IS_NAN (a)) ; ASSERT (!SCALAR_IS_NAN (toler)) ; if (SCALAR_IS_NONZERO (a) && a >= toler) { row = Pattern [i] ; deg = Row_degree [row] ; #ifndef NDEBUG DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n", i, row, deg, a)) ; UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ; #endif ASSERT (Frpos [row] >= 0 && Frpos [row] < fnrows) ; ASSERT (Frpos [row] == i) ; /* row is in the current front */ DEBUG4 ((" in front\n")) ; if (deg < rdeg [IN] /* break ties by picking the largest entry: */ || (deg == rdeg [IN] && a > pivot [IN]) /* break ties by picking the diagonal entry: */ /* || (deg == rdeg [IN] && row == diag_row) */ ) { /* best row in front, so far */ pivrow [IN] = row ; rdeg [IN] = deg ; pivot [IN] = a ; } } } for ( ; i < cdeg1 ; i++) { double a ; APPROX_ABS (a, Wxy [i]) ; ASSERT (!SCALAR_IS_NAN (a)) ; ASSERT (!SCALAR_IS_NAN (toler)) ; if (SCALAR_IS_NONZERO (a) && a >= toler) { row = Pattern [i] ; deg = Row_degree [row] ; #ifndef NDEBUG DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n", i, row, deg, a)) ; UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ; #endif ASSERT (Frpos [row] == i) ; /* row is not in the current front */ DEBUG4 ((" NOT in front\n")) ; if (deg < rdeg [OUT] /* break ties by picking the largest entry: */ || (deg == rdeg [OUT] && a > pivot [OUT]) /* break ties by picking the diagonal entry: */ /* || (deg == rdeg [OUT] && row == diag_row) */ ) { /* best row not in front, so far */ pivrow [OUT] = row ; rdeg [OUT] = deg ; pivot [OUT] = a ; } } } } else { /* this column is not in the front */ for (i = 0 ; i < cdeg1 ; i++) { double a ; APPROX_ABS (a, Wxy [i]) ; ASSERT (!SCALAR_IS_NAN (a)) ; ASSERT (!SCALAR_IS_NAN (toler)) ; if (SCALAR_IS_NONZERO (a) && a >= toler) { row = Pattern [i] ; deg = Row_degree [row] ; #ifndef NDEBUG DEBUG6 ((ID" candidate row "ID" deg "ID" absval %g\n", i, row, deg, a)) ; UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ; #endif if (Frpos [row] >= 0 && Frpos [row] < fnrows) { /* row is in the current front */ DEBUG4 ((" in front\n")) ; if (deg < rdeg [IN] /* break ties by picking the largest entry: */ || (deg == rdeg [IN] && a > pivot [IN]) /* break ties by picking the diagonal entry: */ /* || (deg == rdeg [IN] && row == diag_row) */ ) { /* best row in front, so far */ pivrow [IN] = row ; rdeg [IN] = deg ; pivot [IN] = a ; } } else { /* row is not in the current front */ DEBUG4 ((" NOT in front\n")) ; if (deg < rdeg [OUT] /* break ties by picking the largest entry: */ || (deg == rdeg[OUT] && a > pivot [OUT]) /* break ties by picking the diagonal entry: */ /* || (deg == rdeg[OUT] && row == diag_row) */ ) { /* best row not in front, so far */ pivrow [OUT] = row ; rdeg [OUT] = deg ; pivot [OUT] = a ; } } } } } } } /* ---------------------------------------------------------------------- */ /* NaN handling */ /* ---------------------------------------------------------------------- */ /* if cdeg1 > 0 then we must have found a pivot row ... unless NaN's */ /* exist. Try with no numerical tests if no pivot found. */ if (cdeg1 > 0 && pivrow [IN] == EMPTY && pivrow [OUT] == EMPTY) { /* cleanup for the NaN case */ DEBUG0 (("Found a NaN in pivot column!\n")) ; /* grab the first entry in the pivot column, ignoring degree, */ /* numerical stability, and symmetric preference */ row = Pattern [0] ; deg = Row_degree [row] ; if (Frpos [row] >= 0 && Frpos [row] < fnrows) { /* row is in the current front */ DEBUG4 ((" in front\n")) ; pivrow [IN] = row ; rdeg [IN] = deg ; } else { /* row is not in the current front */ DEBUG4 ((" NOT in front\n")) ; pivrow [OUT] = row ; rdeg [OUT] = deg ; } /* We are now guaranteed to have a pivot, no matter how broken */ /* (non-IEEE compliant) the underlying numerical operators are. */ /* This is particularly a problem for Microsoft compilers (they do */ /* not handle NaN's properly). Now try to find a sparser pivot, if */ /* possible. */ for (i = 1 ; i < cdeg1 ; i++) { row = Pattern [i] ; deg = Row_degree [row] ; if (Frpos [row] >= 0 && Frpos [row] < fnrows) { /* row is in the current front */ DEBUG4 ((" in front\n")) ; if (deg < rdeg [IN] || (deg == rdeg [IN] && row == diag_row)) { /* best row in front, so far */ pivrow [IN] = row ; rdeg [IN] = deg ; } } else { /* row is not in the current front */ DEBUG4 ((" NOT in front\n")) ; if (deg < rdeg [OUT] || (deg == rdeg [OUT] && row == diag_row)) { /* best row not in front, so far */ pivrow [OUT] = row ; rdeg [OUT] = deg ; } } } } /* We found a pivot if there are entries (even zero ones) in pivot col */ ASSERT (IMPLIES (cdeg1 > 0, pivrow[IN] != EMPTY || pivrow[OUT] != EMPTY)) ; /* If there are no entries in the pivot column, then no pivot is found */ ASSERT (IMPLIES (cdeg1 == 0, pivrow[IN] == EMPTY && pivrow[OUT] == EMPTY)) ; /* ---------------------------------------------------------------------- */ /* check for singular matrix */ /* ---------------------------------------------------------------------- */ if (cdeg1 == 0) { if (fnrows > 0) { /* Get the pivrow [OUT][IN] from the current front. The frontal matrix looks like this: pivcol[OUT] | v x x x x 0 <- so grab this row as the pivrow [OUT][IN]. x x x x 0 x x x x 0 0 0 0 0 0 The current frontal matrix has some rows in it. The degree of the pivcol[OUT] is zero. The column is empty, and the current front does not contribute to it. */ pivrow [IN] = Work->Frows [0] ; DEBUGm4 (("Got zero pivrow[OUT][IN] "ID" from current front\n", pivrow [IN])) ; } else { /* Get a pivot row from the row-merge tree, use as pivrow [OUT][OUT]. pivrow [IN] remains EMPTY. This can only happen if the current front is 0-by-0. */ Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1, row2, fleftmost, nfr, n_row, frontid ; ASSERT (Work->fncols == 0) ; Front_leftmostdesc = Symbolic->Front_leftmostdesc ; Front_1strow = Symbolic->Front_1strow ; Front_new1strow = Work->Front_new1strow ; nfr = Symbolic->nfr ; n_row = Numeric->n_row ; frontid = Work->frontid ; DEBUGm4 (("Note: pivcol: "ID" is empty front "ID"\n", pivcol, frontid)) ; #ifndef NDEBUG DEBUG1 (("Calling dump rowmerge\n")) ; UMF_dump_rowmerge (Numeric, Symbolic, Work) ; #endif /* Row-merge set is the non-pivotal rows in the range */ /* Front_new1strow [Front_leftmostdesc [frontid]] to */ /* Front_1strow [frontid+1] - 1. */ /* If this is empty, then use the empty rows, in the range */ /* Front_new1strow [nfr] to n_row-1. */ /* If this too is empty, then pivrow [OUT] will be empty. */ /* In both cases, update Front_new1strow [...]. */ fleftmost = Front_leftmostdesc [frontid] ; row1 = Front_new1strow [fleftmost] ; row2 = Front_1strow [frontid+1] - 1 ; DEBUG1 (("Leftmost: "ID" Rows ["ID" to "ID"] srch ["ID" to "ID"]\n", fleftmost, Front_1strow [frontid], row2, row1, row2)) ; /* look in the range row1 ... row2 */ for (row = row1 ; row <= row2 ; row++) { DEBUG3 ((" Row: "ID"\n", row)) ; if (NON_PIVOTAL_ROW (row)) { /* found it */ DEBUG3 ((" Row: "ID" found\n", row)) ; ASSERT (Frpos [row] == EMPTY) ; pivrow [OUT] = row ; DEBUGm4 (("got row merge pivrow %d\n", pivrow [OUT])) ; break ; } } Front_new1strow [fleftmost] = row ; if (pivrow [OUT] == EMPTY) { /* not found, look in empty row set in "dummy" front */ row1 = Front_new1strow [nfr] ; row2 = n_row-1 ; DEBUG3 (("Empty: "ID" Rows ["ID" to "ID"] srch["ID" to "ID"]\n", nfr, Front_1strow [nfr], row2, row1, row2)) ; /* look in the range row1 ... row2 */ for (row = row1 ; row <= row2 ; row++) { DEBUG3 ((" Empty Row: "ID"\n", row)) ; if (NON_PIVOTAL_ROW (row)) { /* found it */ DEBUG3 ((" Empty Row: "ID" found\n", row)) ; ASSERT (Frpos [row] == EMPTY) ; pivrow [OUT] = row ; DEBUGm4 (("got dummy row pivrow %d\n", pivrow [OUT])) ; break ; } } Front_new1strow [nfr] = row ; } if (pivrow [OUT] == EMPTY) { /* Row-merge set is empty. We can just discard */ /* the candidate pivot column. */ DEBUG0 (("Note: row-merge set empty\n")) ; DEBUGm4 (("got no pivrow \n")) ; return (UMFPACK_WARNING_singular_matrix) ; } } } /* ---------------------------------------------------------------------- */ /* construct the candidate row in the front, if any */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG /* check Wrp */ ASSERT (Work->Wrpflag > 0) ; if (UMF_debug > 0 || Work->n_col < 1000) { for (i = 0 ; i < Work->n_col ; i++) { ASSERT (Wrp [i] < Work->Wrpflag) ; } } #endif #ifndef NDEBUG DEBUG4 (("pivrow [IN]: "ID"\n", pivrow [IN])) ; UMF_dump_rowcol (0, Numeric, Work, pivrow [IN], TRUE) ; #endif if (pivrow [IN] != EMPTY) { /* the row merge candidate row is not pivrow [IN] */ freebie [IN] = (pivrow [IN] == prior_pivrow [IN]) && (cdeg1 > 0) ; ASSERT (cdeg1 >= 0) ; if (!freebie [IN]) { /* include current front in the degree of this row */ Fcpos = Work->Fcpos ; fncols = Work->fncols ; Wrpflag = Work->Wrpflag ; /* -------------------------------------------------------------- */ /* construct the pattern of the IN row */ /* -------------------------------------------------------------- */ #ifndef NDEBUG /* check Fcols */ DEBUG5 (("ROW ASSEMBLE: rdeg "ID"\nREDUCE ROW "ID"\n", fncols, pivrow [IN])) ; for (j = 0 ; j < fncols ; j++) { col = Work->Fcols [j] ; ASSERT (col >= 0 && col < Work->n_col) ; ASSERT (Fcpos [col] >= 0) ; } if (UMF_debug > 0 || Work->n_col < 1000) { Int cnt = fncols ; for (col = 0 ; col < Work->n_col ; col++) { if (Fcpos [col] < 0) cnt++ ; } ASSERT (cnt == Work->n_col) ; } #endif rdeg [IN] = fncols ; ASSERT (pivrow [IN] >= 0 && pivrow [IN] < Work->n_row) ; ASSERT (NON_PIVOTAL_ROW (pivrow [IN])) ; /* add the pivot column itself */ ASSERT (Wrp [pivcol] != Wrpflag) ; if (Fcpos [pivcol] < 0) { DEBUG3 (("Adding pivot col to pivrow [IN] pattern\n")) ; if (rdeg [IN] >= max_rdeg) { /* :: pattern change (in) :: */ return (UMFPACK_ERROR_different_pattern) ; } Wrp [pivcol] = Wrpflag ; W_i [rdeg [IN]++] = pivcol ; } tpi = Row_tuples [pivrow [IN]] ; if (tpi) { tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Row_tlen [pivrow [IN]] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) { continue ; /* element already deallocated */ } f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; ncols = ep->ncols ; Rows = Cols + ncols ; if (Rows [f] == EMPTY) { continue ; /* row already assembled */ } ASSERT (pivrow [IN] == Rows [f]) ; for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; ASSERT (col >= EMPTY && col < Work->n_col) ; if ((col >= 0) && (Wrp [col] != Wrpflag) && Fcpos [col] <0) { ASSERT (NON_PIVOTAL_COL (col)) ; if (rdeg [IN] >= max_rdeg) { /* :: pattern change (rdeg in failure) :: */ DEBUGm4 (("rdeg [IN] >= max_rdeg failure\n")) ; return (UMFPACK_ERROR_different_pattern) ; } Wrp [col] = Wrpflag ; W_i [rdeg [IN]++] = col ; } } *tp2++ = *tp ; /* leave the tuple in the list */ } Row_tlen [pivrow [IN]] = tp2 - tp1 ; } #ifndef NDEBUG DEBUG4 (("Reduced IN row:\n")) ; for (j = 0 ; j < fncols ; j++) { DEBUG6 ((" "ID" "ID" "ID"\n", j, Work->Fcols [j], Fcpos [Work->Fcols [j]])) ; ASSERT (Fcpos [Work->Fcols [j]] >= 0) ; } for (j = fncols ; j < rdeg [IN] ; j++) { DEBUG6 ((" "ID" "ID" "ID"\n", j, W_i [j], Wrp [W_i [j]])); ASSERT (W_i [j] >= 0 && W_i [j] < Work->n_col) ; ASSERT (Wrp [W_i [j]] == Wrpflag) ; } /* mark the end of the pattern in case we scan it by mistake */ /* Note that this means W_i must be of size >= fncols_max + 1 */ W_i [rdeg [IN]] = EMPTY ; #endif /* rdeg [IN] is now the exact degree of the IN row */ /* clear Work->Wrp. */ Work->Wrpflag++ ; /* All Wrp [0..n_col] is now < Wrpflag */ } } #ifndef NDEBUG /* check Wrp */ if (UMF_debug > 0 || Work->n_col < 1000) { for (i = 0 ; i < Work->n_col ; i++) { ASSERT (Wrp [i] < Work->Wrpflag) ; } } #endif /* ---------------------------------------------------------------------- */ /* construct the candidate row not in the front, if any */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG4 (("pivrow [OUT]: "ID"\n", pivrow [OUT])) ; UMF_dump_rowcol (0, Numeric, Work, pivrow [OUT], TRUE) ; #endif /* If this is a candidate row from the row merge set, force it to be */ /* scanned (ignore prior_pivrow [OUT]). */ if (pivrow [OUT] != EMPTY) { freebie [OUT] = (pivrow [OUT] == prior_pivrow [OUT]) && cdeg1 > 0 ; ASSERT (cdeg1 >= 0) ; if (!freebie [OUT]) { Wrpflag = Work->Wrpflag ; /* -------------------------------------------------------------- */ /* construct the pattern of the row */ /* -------------------------------------------------------------- */ rdeg [OUT] = 0 ; ASSERT (pivrow [OUT] >= 0 && pivrow [OUT] < Work->n_row) ; ASSERT (NON_PIVOTAL_ROW (pivrow [OUT])) ; /* add the pivot column itself */ ASSERT (Wrp [pivcol] != Wrpflag) ; DEBUG3 (("Adding pivot col to pivrow [OUT] pattern\n")) ; if (rdeg [OUT] >= max_rdeg) { /* :: pattern change (out) :: */ return (UMFPACK_ERROR_different_pattern) ; } Wrp [pivcol] = Wrpflag ; W_o [rdeg [OUT]++] = pivcol ; tpi = Row_tuples [pivrow [OUT]] ; if (tpi) { tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Row_tlen [pivrow [OUT]] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) { continue ; /* element already deallocated */ } f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; ncols = ep->ncols ; Rows = Cols + ncols ; if (Rows [f] == EMPTY) { continue ; /* row already assembled */ } ASSERT (pivrow [OUT] == Rows [f]) ; for (j = 0 ; j < ncols ; j++) { col = Cols [j] ; ASSERT (col >= EMPTY && col < Work->n_col) ; if ((col >= 0) && (Wrp [col] != Wrpflag)) { ASSERT (NON_PIVOTAL_COL (col)) ; if (rdeg [OUT] >= max_rdeg) { /* :: pattern change (rdeg out failure) :: */ DEBUGm4 (("rdeg [OUT] failure\n")) ; return (UMFPACK_ERROR_different_pattern) ; } Wrp [col] = Wrpflag ; W_o [rdeg [OUT]++] = col ; } } *tp2++ = *tp ; /* leave the tuple in the list */ } Row_tlen [pivrow [OUT]] = tp2 - tp1 ; } #ifndef NDEBUG DEBUG4 (("Reduced row OUT:\n")) ; for (j = 0 ; j < rdeg [OUT] ; j++) { DEBUG6 ((" "ID" "ID" "ID"\n", j, W_o [j], Wrp [W_o [j]])) ; ASSERT (W_o [j] >= 0 && W_o [j] < Work->n_col) ; ASSERT (Wrp [W_o [j]] == Wrpflag) ; } /* mark the end of the pattern in case we scan it by mistake */ /* Note that this means W_o must be of size >= fncols_max + 1 */ W_o [rdeg [OUT]] = EMPTY ; #endif /* rdeg [OUT] is now the exact degree of the row */ /* clear Work->Wrp. */ Work->Wrpflag++ ; /* All Wrp [0..n] is now < Wrpflag */ } } DEBUG5 (("Row_search end ] \n")) ; #ifndef NDEBUG /* check Wrp */ if (UMF_debug > 0 || Work->n_col < 1000) { for (i = 0 ; i < Work->n_col ; i++) { ASSERT (Wrp [i] < Work->Wrpflag) ; } } #endif return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_determinant.c0000644000175000017500000001776511674452555024715 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_get_determinant ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* UMFPACK_get_determinant contributed by David Bateman, Motorola, Paris. */ /* -------------------------------------------------------------------------- */ /* User-callable. From the LU factors, scale factor, and permutation vectors held in the Numeric object, calculates the determinant of the matrix A. See umfpack_get_determinant.h for a more detailed description. Dynamic memory usage: calls UMF_malloc once, for a total space of n integers, and then frees all of it via UMF_free when done. Contributed by David Bateman, Motorola, Nov. 2004. Modified for V4.4, Jan. 2005. */ #include "umf_internal.h" #include "umf_valid_numeric.h" #include "umf_malloc.h" #include "umf_free.h" /* ========================================================================== */ /* === rescale_determinant ================================================== */ /* ========================================================================== */ /* If the mantissa is too big or too small, rescale it and change exponent */ PRIVATE Int rescale_determinant ( Entry *d_mantissa, double *d_exponent ) { double d_abs ; ABS (d_abs, *d_mantissa) ; if (SCALAR_IS_ZERO (d_abs)) { /* the determinant is zero */ *d_exponent = 0 ; return (FALSE) ; } if (SCALAR_IS_NAN (d_abs)) { /* the determinant is NaN */ return (FALSE) ; } while (d_abs < 1.) { SCALE (*d_mantissa, 10.0) ; *d_exponent = *d_exponent - 1.0 ; ABS (d_abs, *d_mantissa) ; } while (d_abs >= 10.) { SCALE (*d_mantissa, 0.1) ; *d_exponent = *d_exponent + 1.0 ; ABS (d_abs, *d_mantissa) ; } return (TRUE) ; } /* ========================================================================== */ /* === UMFPACK_get_determinant ============================================== */ /* ========================================================================== */ GLOBAL Int UMFPACK_get_determinant ( double *Mx, #ifdef COMPLEX double *Mz, #endif double *Ex, void *NumericHandle, double User_Info [UMFPACK_INFO] ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry d_mantissa, d_tmp ; double d_exponent, Info2 [UMFPACK_INFO], one [2] = {1.0, 0.0}, d_sign ; Entry *D ; double *Info, *Rs ; NumericType *Numeric ; Int i, n, itmp, npiv, *Wi, *Rperm, *Cperm, do_scale ; #ifndef NRECIPROCAL Int do_recip ; #endif /* ---------------------------------------------------------------------- */ /* check input parameters */ /* ---------------------------------------------------------------------- */ if (User_Info != (double *) NULL) { /* return Info in user's array */ Info = User_Info ; } else { /* no Info array passed - use local one instead */ Info = Info2 ; for (i = 0 ; i < UMFPACK_INFO ; i++) { Info [i] = EMPTY ; } } Info [UMFPACK_STATUS] = UMFPACK_OK ; Numeric = (NumericType *) NumericHandle ; if (!UMF_valid_numeric (Numeric)) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } if (Numeric->n_row != Numeric->n_col) { /* only square systems can be handled */ Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_system ; return (UMFPACK_ERROR_invalid_system) ; } if (Mx == (double *) NULL) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ; return (UMFPACK_ERROR_argument_missing) ; } n = Numeric->n_row ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ Wi = (Int *) UMF_malloc (n, sizeof (Int)) ; if (!Wi) { DEBUGm4 (("out of memory: get determinant\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; return (UMFPACK_ERROR_out_of_memory) ; } /* ---------------------------------------------------------------------- */ /* compute the determinant */ /* ---------------------------------------------------------------------- */ Rs = Numeric->Rs ; /* row scale factors */ do_scale = (Rs != (double *) NULL) ; #ifndef NRECIPROCAL do_recip = Numeric->do_recip ; #endif d_mantissa = ((Entry *) one) [0] ; d_exponent = 0.0 ; D = Numeric->D ; /* compute product of diagonal entries of U */ for (i = 0 ; i < n ; i++) { MULT (d_tmp, d_mantissa, D [i]) ; d_mantissa = d_tmp ; if (!rescale_determinant (&d_mantissa, &d_exponent)) { /* the determinant is zero or NaN */ Info [UMFPACK_STATUS] = UMFPACK_WARNING_singular_matrix ; /* no need to compute the determinant of R */ do_scale = FALSE ; break ; } } /* compute product of diagonal entries of R (or its inverse) */ if (do_scale) { for (i = 0 ; i < n ; i++) { #ifndef NRECIPROCAL if (do_recip) { /* compute determinant of R inverse */ SCALE_DIV (d_mantissa, Rs [i]) ; } else #endif { /* compute determinant of R */ SCALE (d_mantissa, Rs [i]) ; } if (!rescale_determinant (&d_mantissa, &d_exponent)) { /* the determinant is zero or NaN. This is very unlikey to * occur here, since the scale factors for a tiny or zero row * are set to 1. */ Info [UMFPACK_STATUS] = UMFPACK_WARNING_singular_matrix ; break ; } } } /* ---------------------------------------------------------------------- */ /* determine if P and Q are odd or even permutations */ /* ---------------------------------------------------------------------- */ npiv = 0 ; Rperm = Numeric->Rperm ; for (i = 0 ; i < n ; i++) { Wi [i] = Rperm [i] ; } for (i = 0 ; i < n ; i++) { while (Wi [i] != i) { itmp = Wi [Wi [i]] ; Wi [Wi [i]] = Wi [i] ; Wi [i] = itmp ; npiv++ ; } } Cperm = Numeric->Cperm ; for (i = 0 ; i < n ; i++) { Wi [i] = Cperm [i] ; } for (i = 0 ; i < n ; i++) { while (Wi [i] != i) { itmp = Wi [Wi [i]] ; Wi [Wi [i]] = Wi [i] ; Wi [i] = itmp ; npiv++ ; } } /* if npiv is odd, the sign is -1. if it is even, the sign is +1 */ d_sign = (npiv % 2) ? -1. : 1. ; /* ---------------------------------------------------------------------- */ /* free workspace */ /* ---------------------------------------------------------------------- */ (void) UMF_free ((void *) Wi) ; /* ---------------------------------------------------------------------- */ /* compute the magnitude and exponent of the determinant */ /* ---------------------------------------------------------------------- */ if (Ex == (double *) NULL) { /* Ex is not provided, so return the entire determinant in d_mantissa */ SCALE (d_mantissa, pow (10.0, d_exponent)) ; } else { Ex [0] = d_exponent ; } Mx [0] = d_sign * REAL_COMPONENT (d_mantissa) ; #ifdef COMPLEX if (SPLIT (Mz)) { Mz [0] = d_sign * IMAG_COMPONENT (d_mantissa) ; } else { Mx [1] = d_sign * IMAG_COMPONENT (d_mantissa) ; } #endif /* determine if the determinant has (or will) overflow or underflow */ if (d_exponent + 1.0 > log10 (DBL_MAX)) { Info [UMFPACK_STATUS] = UMFPACK_WARNING_determinant_overflow ; } else if (d_exponent - 1.0 < log10 (DBL_MIN)) { Info [UMFPACK_STATUS] = UMFPACK_WARNING_determinant_underflow ; } return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_is_permutation.h0000644000175000017500000000076311674452555023742 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_is_permutation ( const Int P [ ], Int W [ ], Int n, Int r ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.h0000644000175000017500000000137111674452555022712 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_transpose ( Int n_row, Int n_col, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], const Int P [ ], const Int Q [ ], Int nq, Int Rp [ ], Int Ri [ ], double Rx [ ], Int W [ ], Int check #ifdef COMPLEX , const double Az [ ] , double Rz [ ] , Int do_conjugate #endif ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_store_lu.h0000644000175000017500000000106211674452555022525 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_store_lu ( NumericType *Numeric, WorkType *Work ) ; GLOBAL Int UMF_store_lu_drop ( NumericType *Numeric, WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.h0000644000175000017500000000100311674452555023542 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_kernel_wrapup ( NumericType *Numeric, SymbolicType *Symbolic, WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.h0000644000175000017500000000103411674452555024473 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_garbage_collection ( NumericType *Numeric, WorkType *Work, Int drnew, Int dcnew, Int do_Fcpos ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.h0000644000175000017500000000104011674452555023034 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_get_memory ( NumericType *Numeric, WorkType *Work, Int needunits, Int r2, Int c2, Int do_Fcpos ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.c0000644000175000017500000000266011674452555023211 0ustar sonnesonne/* ========================================================================== */ /* === UMF_apply_order ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Apply post-ordering of supernodal elimination tree. */ #include "umf_internal.h" #include "umf_apply_order.h" GLOBAL void UMF_apply_order ( Int Front [ ], /* of size nn on input, size nfr on output */ const Int Order [ ], /* Order [i] = k, i in the range 0..nn-1, * and k in the range 0..nfr-1, means that node * i is the kth node in the postordered tree. */ Int Temp [ ], /* workspace of size nfr */ Int nn, /* nodes are numbered in the range 0..nn-1 */ Int nfr /* the number of nodes actually in use */ ) { Int i, k ; for (i = 0 ; i < nn ; i++) { k = Order [i] ; ASSERT (k >= EMPTY && k < nfr) ; if (k != EMPTY) { Temp [k] = Front [i] ; } } for (k = 0 ; k < nfr ; k++) { Front [k] = Temp [k] ; } } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_symbolic.c0000644000175000017500000000365711674452555024361 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_free_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. See umfpack_free_symbolic.h for details. All 10 objects comprising the Symbolic object are free'd via UMF_free. */ #include "umf_internal.h" #include "umf_free.h" GLOBAL void UMFPACK_free_symbolic ( void **SymbolicHandle ) { SymbolicType *Symbolic ; if (!SymbolicHandle) { return ; } Symbolic = *((SymbolicType **) SymbolicHandle) ; if (!Symbolic) { return ; } (void) UMF_free ((void *) Symbolic->Cperm_init) ; (void) UMF_free ((void *) Symbolic->Rperm_init) ; (void) UMF_free ((void *) Symbolic->Front_npivcol) ; (void) UMF_free ((void *) Symbolic->Front_parent) ; (void) UMF_free ((void *) Symbolic->Front_1strow) ; (void) UMF_free ((void *) Symbolic->Front_leftmostdesc) ; (void) UMF_free ((void *) Symbolic->Chain_start) ; (void) UMF_free ((void *) Symbolic->Chain_maxrows) ; (void) UMF_free ((void *) Symbolic->Chain_maxcols) ; (void) UMF_free ((void *) Symbolic->Cdeg) ; (void) UMF_free ((void *) Symbolic->Rdeg) ; /* only when dense rows are present */ (void) UMF_free ((void *) Symbolic->Esize) ; /* only when diagonal pivoting is prefered */ (void) UMF_free ((void *) Symbolic->Diagonal_map) ; (void) UMF_free ((void *) Symbolic) ; *SymbolicHandle = (void *) NULL ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_symbolic.c0000644000175000017500000000230511674452555023345 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_symbolic ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Performs a symbolic factorization. See umfpack_symbolic.h for details. */ #include "umf_internal.h" GLOBAL Int UMFPACK_symbolic ( Int n_row, Int n_col, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif void **SymbolicHandle, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO] ) { Int *Qinit = (Int *) NULL ; return (UMFPACK_qsymbolic (n_row, n_col, Ap, Ai, Ax, #ifdef COMPLEX Az, #endif Qinit, SymbolicHandle, Control, Info)) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_solve.c0000644000175000017500000001515411674452555022662 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_solve ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Solves a linear system using the numerical factorization computed by UMFPACK_numeric. See umfpack_solve.h for more details. For umfpack_*_solve: Dynamic memory usage: UMFPACK_solve calls UMF_malloc twice, for workspace of size c*n*sizeof(double) + n*sizeof(Int), where c is defined below. On return, all of this workspace is free'd via UMF_free. For umfpack_*_wsolve: No dynamic memory usage. Input arrays are used for workspace instead. Pattern is a workspace of size n Integers. The double array W must be at least of size c*n, where c is defined below. If iterative refinement is requested, and Ax=b, A'x=b or A.'x=b is being solved, and the matrix A is not singular, then c is 5 for the real version and 10 for the complex version. Otherwise, c is 1 for the real version and 4 for the complex version. */ #include "umf_internal.h" #include "umf_valid_numeric.h" #include "umf_solve.h" #ifndef WSOLVE #include "umf_malloc.h" #include "umf_free.h" #ifndef NDEBUG PRIVATE Int init_count ; #endif #endif GLOBAL Int #ifdef WSOLVE UMFPACK_wsolve #else UMFPACK_solve #endif ( Int sys, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif double Xx [ ], #ifdef COMPLEX double Xz [ ], #endif const double Bx [ ], #ifdef COMPLEX const double Bz [ ], #endif void *NumericHandle, const double Control [UMFPACK_CONTROL], double User_Info [UMFPACK_INFO] #ifdef WSOLVE , Int Pattern [ ], double W [ ] #endif ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ double Info2 [UMFPACK_INFO], stats [2] ; double *Info ; NumericType *Numeric ; Int n, i, irstep, status ; #ifndef WSOLVE Int *Pattern, wsize ; double *W ; #endif /* ---------------------------------------------------------------------- */ /* get the amount of time used by the process so far */ /* ---------------------------------------------------------------------- */ umfpack_tic (stats) ; #ifndef WSOLVE #ifndef NDEBUG init_count = UMF_malloc_count ; #endif #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ irstep = GET_CONTROL (UMFPACK_IRSTEP, UMFPACK_DEFAULT_IRSTEP) ; if (User_Info != (double *) NULL) { /* return Info in user's array */ Info = User_Info ; /* clear the parts of Info that are set by UMFPACK_solve */ for (i = UMFPACK_IR_TAKEN ; i <= UMFPACK_SOLVE_TIME ; i++) { Info [i] = EMPTY ; } } else { /* no Info array passed - use local one instead */ Info = Info2 ; for (i = 0 ; i < UMFPACK_INFO ; i++) { Info [i] = EMPTY ; } } Info [UMFPACK_STATUS] = UMFPACK_OK ; Info [UMFPACK_SOLVE_FLOPS] = 0 ; Numeric = (NumericType *) NumericHandle ; if (!UMF_valid_numeric (Numeric)) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Numeric_object ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } Info [UMFPACK_NROW] = Numeric->n_row ; Info [UMFPACK_NCOL] = Numeric->n_col ; if (Numeric->n_row != Numeric->n_col) { /* only square systems can be handled */ Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_system ; return (UMFPACK_ERROR_invalid_system) ; } n = Numeric->n_row ; if (Numeric->nnzpiv < n || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond)) { /* turn off iterative refinement if A is singular */ /* or if U has NaN's on the diagonal. */ irstep = 0 ; } if (!Xx || !Bx) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ; return (UMFPACK_ERROR_argument_missing) ; } if (sys >= UMFPACK_Pt_L) { /* no iterative refinement except for nonsingular Ax=b, A'x=b, A.'x=b */ irstep = 0 ; } /* ---------------------------------------------------------------------- */ /* allocate or check the workspace */ /* ---------------------------------------------------------------------- */ #ifdef WSOLVE if (!W || !Pattern) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ; return (UMFPACK_ERROR_argument_missing) ; } #else #ifdef COMPLEX if (irstep > 0) { wsize = 10*n ; /* W, X, Z, S, Y, B2 */ } else { wsize = 4*n ; /* W, X */ } #else if (irstep > 0) { wsize = 5*n ; /* W, Z, S, Y, B2 */ } else { wsize = n ; /* W */ } #endif Pattern = (Int *) UMF_malloc (n, sizeof (Int)) ; W = (double *) UMF_malloc (wsize, sizeof (double)) ; if (!W || !Pattern) { DEBUGm4 (("out of memory: solve work\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; (void) UMF_free ((void *) W) ; (void) UMF_free ((void *) Pattern) ; return (UMFPACK_ERROR_out_of_memory) ; } #endif /* WSOLVE */ /* ---------------------------------------------------------------------- */ /* solve the system */ /* ---------------------------------------------------------------------- */ status = UMF_solve (sys, Ap, Ai, Ax, Xx, Bx, #ifdef COMPLEX Az, Xz, Bz, #endif Numeric, irstep, Info, Pattern, W) ; /* ---------------------------------------------------------------------- */ /* free the workspace (if allocated) */ /* ---------------------------------------------------------------------- */ #ifndef WSOLVE (void) UMF_free ((void *) W) ; (void) UMF_free ((void *) Pattern) ; ASSERT (UMF_malloc_count == init_count) ; #endif /* ---------------------------------------------------------------------- */ /* get the time used by UMFPACK_*solve */ /* ---------------------------------------------------------------------- */ Info [UMFPACK_STATUS] = status ; if (status >= 0) { umfpack_toc (stats) ; Info [UMFPACK_SOLVE_WALLTIME] = stats [0] ; Info [UMFPACK_SOLVE_TIME] = stats [1] ; } return (status) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.h0000644000175000017500000000075111674452555025010 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_mem_alloc_tail_block ( NumericType *Numeric, Int nunits ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.h0000644000175000017500000000072211674452555023514 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_valid_numeric ( NumericType *Numeric ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_tail_block.c0000644000175000017500000001004411674452555024777 0ustar sonnesonne/* ========================================================================== */ /* === UMF_mem_alloc_tail_block ============================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ #include "umf_internal.h" #include "umf_mem_alloc_tail_block.h" /* allocate nunits from tail of Numeric->Memory */ /* (requires nunits+1, for header). */ /* Returns the index into Numeric->Memory if successful, or 0 on failure. */ GLOBAL Int UMF_mem_alloc_tail_block ( NumericType *Numeric, Int nunits ) { Int bigsize, usage ; Unit *p, *pnext, *pbig ; ASSERT (Numeric != (NumericType *) NULL) ; ASSERT (Numeric->Memory != (Unit *) NULL) ; #ifndef NDEBUG if (UMF_allocfail) { /* pretend to fail, to test garbage_collection */ DEBUGm2 (("UMF_mem_alloc_tail_block: pretend to fail\n")) ; UMF_allocfail = FALSE ; /* don't fail the next time */ return (0) ; } DEBUG2 (("UMF_mem_alloc_tail_block, size: "ID" + 1 = "ID": ", nunits, nunits+1)) ; #endif bigsize = 0 ; pbig = (Unit *) NULL ; ASSERT (nunits > 0) ; /* size must be positive */ if (Numeric->ibig != EMPTY) { ASSERT (Numeric->ibig > Numeric->itail) ; ASSERT (Numeric->ibig < Numeric->size) ; pbig = Numeric->Memory + Numeric->ibig ; bigsize = -pbig->header.size ; ASSERT (bigsize > 0) ; /* Numeric->ibig is free */ ASSERT (pbig->header.prevsize >= 0) ; /* prev. is not free */ } if (pbig && bigsize >= nunits) { /* use the biggest block, somewhere in middle of memory */ p = pbig ; pnext = p + 1 + bigsize ; /* next is in range */ ASSERT (pnext < Numeric->Memory + Numeric->size) ; /* prevsize of next = this size */ ASSERT (pnext->header.prevsize == bigsize) ; /* next is not free */ ASSERT (pnext->header.size > 0) ; bigsize -= nunits + 1 ; if (bigsize < 4) { /* internal fragmentation would be too small */ /* allocate the entire free block */ p->header.size = -p->header.size ; DEBUG2 (("GET BLOCK: p: "ID" size: "ID", all of big: "ID" size: " ID"\n", (Int) (p-Numeric->Memory), nunits, Numeric->ibig, p->header.size)) ; /* no more biggest block */ Numeric->ibig = EMPTY ; } else { /* allocate just the first nunits Units of the free block */ p->header.size = nunits ; /* make a new free block */ Numeric->ibig += nunits + 1 ; pbig = Numeric->Memory + Numeric->ibig ; pbig->header.size = -bigsize ; pbig->header.prevsize = nunits ; pnext->header.prevsize = bigsize ; DEBUG2 (("GET BLOCK: p: "ID" size: "ID", some of big: "ID" left: " ID"\n", (Int) (p-Numeric->Memory), nunits, Numeric->ibig, bigsize)) ; } } else { /* allocate from the top of tail */ pnext = Numeric->Memory + Numeric->itail ; DEBUG2 (("GET BLOCK: from tail ")) ; if ((nunits + 1) > (Numeric->itail - Numeric->ihead)) { DEBUG2 (("\n")) ; return (0) ; } Numeric->itail -= (nunits + 1) ; p = Numeric->Memory + Numeric->itail ; p->header.size = nunits ; p->header.prevsize = 0 ; pnext->header.prevsize = nunits ; DEBUG2 (("p: "ID" size: "ID", new tail "ID"\n", (Int) (p-Numeric->Memory), nunits, Numeric->itail)) ; } Numeric->tail_usage += p->header.size + 1 ; usage = Numeric->ihead + Numeric->tail_usage ; Numeric->max_usage = MAX (Numeric->max_usage, usage) ; #ifndef NDEBUG UMF_debug -= 10 ; UMF_dump_memory (Numeric) ; UMF_debug += 10 ; #endif /* p points to the header. Add one to point to the usable block itself. */ /* return the offset into Numeric->Memory */ return ((p - Numeric->Memory) + 1) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_solve.c0000644000175000017500000010174611674452555022026 0ustar sonnesonne/* ========================================================================== */ /* === UMF_solve ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Not user-callable. Solves a linear system using the numerical factorization computed by UMFPACK_numeric. No workspace is dynamically allocated. Counts flops, but excludes floating-point comparisons (thus real abs (...) are zero flops, but complex abs (...) takes 6 flops). Returns UMFPACK_OK if successful, UMFPACK_ERROR_argument_missing if required arguments are missing, UMFPACK_ERROR_invalid_system if the sys string is not valid or if the matrix A is not square. Uses the sparse backward error method of Arioli, Demmel, and Duff (Solving sparse linear systems with sparse backward error, SIAM J. Matrix Analysis and Applic., vol 10, pp. 165-190). Added on option that allows the complex A and X to be split differently than B, Oct 10, 2005. Contributed by David Bateman. */ #include "umf_internal.h" #include "umf_solve.h" #include "umf_lsolve.h" #include "umf_usolve.h" #include "umf_ltsolve.h" #include "umf_utsolve.h" #include "umf_report_vector.h" PRIVATE Int do_step ( double omega [3], Int step, const double B2 [ ], Entry X [ ], const Entry W [ ], const double Y [ ], const double Z2 [ ], Entry S [ ], Int n, double Info [UMFPACK_INFO] ) ; /* ========================================================================== */ /* === UMF_solve ============================================================ */ /* ========================================================================== */ GLOBAL Int UMF_solve ( Int sys, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], double Xx [ ], const double Bx [ ], #ifdef COMPLEX const double Az [ ], double Xz [ ], const double Bz [ ], #endif NumericType *Numeric, Int irstep, double Info [UMFPACK_INFO], Int Pattern [ ], /* size n */ double SolveWork [ ] /* if irstep>0 real: size 5*n. complex:10*n */ /* otherwise real: size n. complex: 4*n */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry axx, wi, xj, zi, xi, aij, bi ; double omega [3], d, z2i, yi, flops ; Entry *W, *Z, *S, *X ; double *Z2, *Y, *B2, *Rs ; Int *Rperm, *Cperm, i, n, p, step, j, nz, status, p2, do_scale ; #ifdef COMPLEX Int AXsplit ; Int Bsplit ; #endif #ifndef NRECIPROCAL Int do_recip = Numeric->do_recip ; #endif /* ---------------------------------------------------------------------- */ /* initializations */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG UMF_dump_lu (Numeric) ; ASSERT (Numeric && Xx && Bx && Pattern && SolveWork && Info) ; #endif nz = 0 ; omega [0] = 0. ; omega [1] = 0. ; omega [2] = 0. ; Rperm = Numeric->Rperm ; Cperm = Numeric->Cperm ; Rs = Numeric->Rs ; /* row scale factors */ do_scale = (Rs != (double *) NULL) ; flops = 0 ; Info [UMFPACK_SOLVE_FLOPS] = 0 ; Info [UMFPACK_IR_TAKEN] = 0 ; Info [UMFPACK_IR_ATTEMPTED] = 0 ; /* UMFPACK_solve does not call this routine if A is rectangular */ ASSERT (Numeric->n_row == Numeric->n_col) ; n = Numeric->n_row ; if (Numeric->nnzpiv < n || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond)) { /* Note that systems involving just L return UMFPACK_OK, even if */ /* A is singular (L is always has a unit diagonal). */ DEBUGm4 (("Note, matrix is singular in umf_solve\n")) ; status = UMFPACK_WARNING_singular_matrix ; irstep = 0 ; } else { status = UMFPACK_OK ; } irstep = MAX (0, irstep) ; /* make sure irstep is >= 0 */ W = (Entry *) SolveWork ; /* Entry W [0..n-1] */ Z = (Entry *) NULL ; /* unused if no iterative refinement */ S = (Entry *) NULL ; Y = (double *) NULL ; Z2 = (double *) NULL ; B2 = (double *) NULL ; #ifdef COMPLEX if (irstep > 0) { if (!Ap || !Ai || !Ax) { return (UMFPACK_ERROR_argument_missing) ; } /* A, B, and X in split format if Az, Bz, and Xz present */ AXsplit = SPLIT (Az) || SPLIT(Xz); Z = (Entry *) (SolveWork + 4*n) ; /* Entry Z [0..n-1] */ S = (Entry *) (SolveWork + 6*n) ; /* Entry S [0..n-1] */ Y = (double *) (SolveWork + 8*n) ; /* double Y [0..n-1] */ B2 = (double *) (SolveWork + 9*n) ; /* double B2 [0..n-1] */ Z2 = (double *) Z ; /* double Z2 [0..n-1], equiv. to Z */ } else { /* A is ignored, only look at X for split/packed cases */ AXsplit = SPLIT(Xz); } Bsplit = SPLIT (Bz); if (AXsplit) { X = (Entry *) (SolveWork + 2*n) ; /* Entry X [0..n-1] */ } else { X = (Entry *) Xx ; /* Entry X [0..n-1] */ } #else X = (Entry *) Xx ; /* Entry X [0..n-1] */ if (irstep > 0) { if (!Ap || !Ai || !Ax) { return (UMFPACK_ERROR_argument_missing) ; } Z = (Entry *) (SolveWork + n) ; /* Entry Z [0..n-1] */ S = (Entry *) (SolveWork + 2*n) ; /* Entry S [0..n-1] */ Y = (double *) (SolveWork + 3*n) ; /* double Y [0..n-1] */ B2 = (double *) (SolveWork + 4*n) ; /* double B2 [0..n-1] */ Z2 = (double *) Z ; /* double Z2 [0..n-1], equiv. to Z */ } #endif /* ---------------------------------------------------------------------- */ /* determine which system to solve */ /* ---------------------------------------------------------------------- */ if (sys == UMFPACK_A) { /* ------------------------------------------------------------------ */ /* solve A x = b with optional iterative refinement */ /* ------------------------------------------------------------------ */ if (irstep > 0) { /* -------------------------------------------------------------- */ /* using iterative refinement: compute Y and B2 */ /* -------------------------------------------------------------- */ nz = Ap [n] ; Info [UMFPACK_NZ] = nz ; /* A is stored by column */ /* Y (i) = ||R A_i||, 1-norm of row i of R A */ for (i = 0 ; i < n ; i++) { Y [i] = 0. ; } flops += (ABS_FLOPS + 1) * nz ; p2 = Ap [n] ; for (p = 0 ; p < p2 ; p++) { /* Y [Ai [p]] += ABS (Ax [p]) ; */ ASSIGN (aij, Ax, Az, p, AXsplit) ; ABS (d, aij) ; Y [Ai [p]] += d ; } /* B2 = abs (B) */ flops += ABS_FLOPS * n ; for (i = 0 ; i < n ; i++) { /* B2 [i] = ABS (B [i]) ; */ ASSIGN (bi, Bx, Bz, i, Bsplit) ; ABS (B2 [i], bi) ; } /* scale Y and B2. */ if (do_scale) { /* Y = R Y */ /* B2 = R B2 */ #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { Y [i] *= Rs [i] ; B2 [i] *= Rs [i] ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { Y [i] /= Rs [i] ; B2 [i] /= Rs [i] ; } } flops += 2 * n ; } } for (step = 0 ; step <= irstep ; step++) { /* -------------------------------------------------------------- */ /* Solve A x = b (step 0): */ /* x = Q (U \ (L \ (P R b))) */ /* and then perform iterative refinement (step > 0): */ /* x = x + Q (U \ (L \ (P R (b - A x)))) */ /* -------------------------------------------------------------- */ if (step == 0) { if (do_scale) { /* W = P R b, using X as workspace, since Z is not * allocated if irstep = 0. */ #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { ASSIGN (X [i], Bx, Bz, i, Bsplit) ; SCALE (X [i], Rs [i]) ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { ASSIGN (X [i], Bx, Bz, i, Bsplit) ; SCALE_DIV (X [i], Rs [i]) ; } } flops += SCALE_FLOPS * n ; for (i = 0 ; i < n ; i++) { W [i] = X [Rperm [i]] ; } } else { /* W = P b, since the row scaling R = I */ for (i = 0 ; i < n ; i++) { /* W [i] = B [Rperm [i]] ; */ ASSIGN (W [i], Bx, Bz, Rperm [i], Bsplit) ; } } } else { for (i = 0 ; i < n ; i++) { /* Z [i] = B [i] ; */ ASSIGN (Z [i], Bx, Bz, i, Bsplit) ; } flops += MULTSUB_FLOPS * nz ; for (i = 0 ; i < n ; i++) { xi = X [i] ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* Z [Ai [p]] -= Ax [p] * xi ; */ ASSIGN (aij, Ax, Az, p, AXsplit) ; MULT_SUB (Z [Ai [p]], aij, xi) ; } } /* scale, Z = R Z */ if (do_scale) { #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE (Z [i], Rs [i]) ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE_DIV (Z [i], Rs [i]) ; } } flops += SCALE_FLOPS * n ; } for (i = 0 ; i < n ; i++) { W [i] = Z [Rperm [i]] ; } } flops += UMF_lsolve (Numeric, W, Pattern) ; flops += UMF_usolve (Numeric, W, Pattern) ; if (step == 0) { for (i = 0 ; i < n ; i++) { X [Cperm [i]] = W [i] ; } } else { flops += ASSEMBLE_FLOPS * n ; for (i = 0 ; i < n ; i++) { /* X [Cperm [i]] += W [i] ; */ ASSEMBLE (X [Cperm [i]], W [i]) ; } } /* -------------------------------------------------------------- */ /* sparse backward error estimate */ /* -------------------------------------------------------------- */ if (irstep > 0) { /* ---------------------------------------------------------- */ /* A is stored by column */ /* W (i) = R (b - A x)_i, residual */ /* Z2 (i) = R (|A||x|)_i */ /* ---------------------------------------------------------- */ for (i = 0 ; i < n ; i++) { /* W [i] = B [i] ; */ ASSIGN (W [i], Bx, Bz, i, Bsplit) ; Z2 [i] = 0. ; } flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ; for (j = 0 ; j < n ; j++) { xj = X [j] ; p2 = Ap [j+1] ; for (p = Ap [j] ; p < p2 ; p++) { i = Ai [p] ; /* axx = Ax [p] * xj ; */ ASSIGN (aij, Ax, Az, p, AXsplit) ; MULT (axx, aij, xj) ; /* W [i] -= axx ; */ DECREMENT (W [i], axx) ; /* Z2 [i] += ABS (axx) ; */ ABS (d, axx) ; Z2 [i] += d ; } } /* scale W and Z2 */ if (do_scale) { /* Z2 = R Z2 */ /* W = R W */ #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE (W [i], Rs [i]) ; Z2 [i] *= Rs [i] ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE_DIV (W [i], Rs [i]) ; Z2 [i] /= Rs [i] ; } } flops += (SCALE_FLOPS + 1) * n ; } flops += (2*ABS_FLOPS + 5) * n ; if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info)) { /* iterative refinement is done */ break ; } } } } else if (sys == UMFPACK_At) { /* ------------------------------------------------------------------ */ /* solve A' x = b with optional iterative refinement */ /* ------------------------------------------------------------------ */ /* A' is the complex conjugate transpose */ if (irstep > 0) { /* -------------------------------------------------------------- */ /* using iterative refinement: compute Y */ /* -------------------------------------------------------------- */ nz = Ap [n] ; Info [UMFPACK_NZ] = nz ; /* A' is stored by row */ /* Y (i) = ||(A' R)_i||, 1-norm of row i of A' R */ if (do_scale) { flops += (ABS_FLOPS + 2) * nz ; #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { yi = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */ /* note that abs (aij) is the same as * abs (conj (aij)) */ ASSIGN (aij, Ax, Az, p, AXsplit) ; ABS (d, aij) ; yi += (d * Rs [Ai [p]]) ; } Y [i] = yi ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { yi = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */ /* note that abs (aij) is the same as * abs (conj (aij)) */ ASSIGN (aij, Ax, Az, p, AXsplit) ; ABS (d, aij) ; yi += (d / Rs [Ai [p]]) ; } Y [i] = yi ; } } } else { /* no scaling */ flops += (ABS_FLOPS + 1) * nz ; for (i = 0 ; i < n ; i++) { yi = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* yi += ABS (Ax [p]) ; */ /* note that abs (aij) is the same as * abs (conj (aij)) */ ASSIGN (aij, Ax, Az, p, AXsplit) ; ABS (d, aij) ; yi += d ; } Y [i] = yi ; } } /* B2 = abs (B) */ for (i = 0 ; i < n ; i++) { /* B2 [i] = ABS (B [i]) ; */ ASSIGN (bi, Bx, Bz, i, Bsplit) ; ABS (B2 [i], bi) ; } } for (step = 0 ; step <= irstep ; step++) { /* -------------------------------------------------------------- */ /* Solve A' x = b (step 0): */ /* x = R P' (L' \ (U' \ (Q' b))) */ /* and then perform iterative refinement (step > 0): */ /* x = x + R P' (L' \ (U' \ (Q' (b - A' x)))) */ /* -------------------------------------------------------------- */ if (step == 0) { /* W = Q' b */ for (i = 0 ; i < n ; i++) { /* W [i] = B [Cperm [i]] ; */ ASSIGN (W [i], Bx, Bz, Cperm [i], Bsplit) ; } } else { /* Z = b - A' x */ for (i = 0 ; i < n ; i++) { /* Z [i] = B [i] ; */ ASSIGN (Z [i], Bx, Bz, i, Bsplit) ; } flops += MULTSUB_FLOPS * nz ; for (i = 0 ; i < n ; i++) { zi = Z [i] ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* zi -= conjugate (Ax [p]) * X [Ai [p]] ; */ ASSIGN (aij, Ax, Az, p, Bsplit) ; MULT_SUB_CONJ (zi, X [Ai [p]], aij) ; } Z [i] = zi ; } /* W = Q' Z */ for (i = 0 ; i < n ; i++) { W [i] = Z [Cperm [i]] ; } } flops += UMF_uhsolve (Numeric, W, Pattern) ; flops += UMF_lhsolve (Numeric, W, Pattern) ; if (step == 0) { /* X = R P' W */ /* do not use Z, since it isn't allocated if irstep = 0 */ /* X = P' W */ for (i = 0 ; i < n ; i++) { X [Rperm [i]] = W [i] ; } if (do_scale) { /* X = R X */ #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE (X [i], Rs [i]) ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE_DIV (X [i], Rs [i]) ; } } flops += SCALE_FLOPS * n ; } } else { /* Z = P' W */ for (i = 0 ; i < n ; i++) { Z [Rperm [i]] = W [i] ; } if (do_scale) { /* Z = R Z */ #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE (Z [i], Rs [i]) ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE_DIV (Z [i], Rs [i]) ; } } flops += SCALE_FLOPS * n ; } flops += ASSEMBLE_FLOPS * n ; /* X += Z */ for (i = 0 ; i < n ; i++) { /* X [i] += Z [i] ; was +=W[i] in v4.3, which is wrong */ ASSEMBLE (X [i], Z [i]) ; /* bug fix, v4.3.1 */ } } /* -------------------------------------------------------------- */ /* sparse backward error estimate */ /* -------------------------------------------------------------- */ if (irstep > 0) { /* ---------------------------------------------------------- */ /* A' is stored by row */ /* W (i) = (b - A' x)_i, residual */ /* Z2 (i) = (|A'||x|)_i */ /* ---------------------------------------------------------- */ flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ; for (i = 0 ; i < n ; i++) { /* wi = B [i] ; */ ASSIGN (wi, Bx, Bz, i, Bsplit) ; z2i = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* axx = conjugate (Ax [p]) * X [Ai [p]] ; */ ASSIGN (aij, Ax, Az, p, AXsplit) ; MULT_CONJ (axx, X [Ai [p]], aij) ; /* wi -= axx ; */ DECREMENT (wi, axx) ; /* z2i += ABS (axx) ; */ ABS (d, axx) ; z2i += d ; } W [i] = wi ; Z2 [i] = z2i ; } flops += (2*ABS_FLOPS + 5) * n ; if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info)) { /* iterative refinement is done */ break ; } } } } else if (sys == UMFPACK_Aat) { /* ------------------------------------------------------------------ */ /* solve A.' x = b with optional iterative refinement */ /* ------------------------------------------------------------------ */ /* A' is the array transpose */ if (irstep > 0) { /* -------------------------------------------------------------- */ /* using iterative refinement: compute Y */ /* -------------------------------------------------------------- */ nz = Ap [n] ; Info [UMFPACK_NZ] = nz ; /* A.' is stored by row */ /* Y (i) = ||(A.' R)_i||, 1-norm of row i of A.' R */ if (do_scale) { flops += (ABS_FLOPS + 2) * nz ; #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { yi = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* yi += ABS (Ax [p]) * Rs [Ai [p]] ; */ /* note that A.' is the array transpose, * so no conjugate */ ASSIGN (aij, Ax, Az, p, AXsplit) ; ABS (d, aij) ; yi += (d * Rs [Ai [p]]) ; } Y [i] = yi ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { yi = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* yi += ABS (Ax [p]) / Rs [Ai [p]] ; */ /* note that A.' is the array transpose, * so no conjugate */ ASSIGN (aij, Ax, Az, p, AXsplit) ; ABS (d, aij) ; yi += (d / Rs [Ai [p]]) ; } Y [i] = yi ; } } } else { /* no scaling */ flops += (ABS_FLOPS + 1) * nz ; for (i = 0 ; i < n ; i++) { yi = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* yi += ABS (Ax [p]) */ /* note that A.' is the array transpose, * so no conjugate */ ASSIGN (aij, Ax, Az, p, AXsplit) ; ABS (d, aij) ; yi += d ; } Y [i] = yi ; } } /* B2 = abs (B) */ for (i = 0 ; i < n ; i++) { /* B2 [i] = ABS (B [i]) ; */ ASSIGN (bi, Bx, Bz, i, Bsplit) ; ABS (B2 [i], bi) ; } } for (step = 0 ; step <= irstep ; step++) { /* -------------------------------------------------------------- */ /* Solve A.' x = b (step 0): */ /* x = R P' (L.' \ (U.' \ (Q' b))) */ /* and then perform iterative refinement (step > 0): */ /* x = x + R P' (L.' \ (U.' \ (Q' (b - A.' x)))) */ /* -------------------------------------------------------------- */ if (step == 0) { /* W = Q' b */ for (i = 0 ; i < n ; i++) { /* W [i] = B [Cperm [i]] ; */ ASSIGN (W [i], Bx, Bz, Cperm [i], Bsplit) ; } } else { /* Z = b - A.' x */ for (i = 0 ; i < n ; i++) { /* Z [i] = B [i] ; */ ASSIGN (Z [i], Bx, Bz, i, Bsplit) ; } flops += MULTSUB_FLOPS * nz ; for (i = 0 ; i < n ; i++) { zi = Z [i] ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* zi -= Ax [p] * X [Ai [p]] ; */ ASSIGN (aij, Ax, Az, p, AXsplit) ; MULT_SUB (zi, aij, X [Ai [p]]) ; } Z [i] = zi ; } /* W = Q' Z */ for (i = 0 ; i < n ; i++) { W [i] = Z [Cperm [i]] ; } } flops += UMF_utsolve (Numeric, W, Pattern) ; flops += UMF_ltsolve (Numeric, W, Pattern) ; if (step == 0) { /* X = R P' W */ /* do not use Z, since it isn't allocated if irstep = 0 */ /* X = P' W */ for (i = 0 ; i < n ; i++) { X [Rperm [i]] = W [i] ; } if (do_scale) { /* X = R X */ #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE (X [i], Rs [i]) ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE_DIV (X [i], Rs [i]) ; } } flops += SCALE_FLOPS * n ; } } else { /* Z = P' W */ for (i = 0 ; i < n ; i++) { Z [Rperm [i]] = W [i] ; } if (do_scale) { /* Z = R Z */ #ifndef NRECIPROCAL if (do_recip) { /* multiply by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE (Z [i], Rs [i]) ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { SCALE_DIV (Z [i], Rs [i]) ; } } flops += SCALE_FLOPS * n ; } flops += ASSEMBLE_FLOPS * n ; /* X += Z */ for (i = 0 ; i < n ; i++) { /* X [i] += Z [i] ; was +=W[i] in v4.3, which is wrong */ ASSEMBLE (X [i], Z [i]) ; /* bug fix, v4.3.1 */ } } /* -------------------------------------------------------------- */ /* sparse backward error estimate */ /* -------------------------------------------------------------- */ if (irstep > 0) { /* ---------------------------------------------------------- */ /* A.' is stored by row */ /* W (i) = (b - A.' x)_i, residual */ /* Z (i) = (|A.'||x|)_i */ /* ---------------------------------------------------------- */ flops += (MULT_FLOPS + DECREMENT_FLOPS + ABS_FLOPS + 1) * nz ; for (i = 0 ; i < n ; i++) { /* wi = B [i] ; */ ASSIGN (wi, Bx, Bz, i, Bsplit) ; z2i = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* axx = Ax [p] * X [Ai [p]] ; */ ASSIGN (aij, Ax, Az, p, AXsplit) ; MULT (axx, aij, X [Ai [p]]) ; /* wi -= axx ; */ DECREMENT (wi, axx) ; /* z2i += ABS (axx) ; */ ABS (d, axx) ; z2i += d ; } W [i] = wi ; Z2 [i] = z2i ; } flops += (2*ABS_FLOPS + 5) * n ; if (do_step (omega, step, B2, X, W, Y, Z2, S, n, Info)) { /* iterative refinement is done */ break ; } } } } else if (sys == UMFPACK_Pt_L) { /* ------------------------------------------------------------------ */ /* Solve P'Lx=b: x = L \ Pb */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [Rperm [i]] ; */ ASSIGN (X [i], Bx, Bz, Rperm [i], Bsplit) ; } flops = UMF_lsolve (Numeric, X, Pattern) ; status = UMFPACK_OK ; } else if (sys == UMFPACK_L) { /* ------------------------------------------------------------------ */ /* Solve Lx=b: x = L \ b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [i] ; */ ASSIGN (X [i], Bx, Bz, i, Bsplit) ; } flops = UMF_lsolve (Numeric, X, Pattern) ; status = UMFPACK_OK ; } else if (sys == UMFPACK_Lt_P) { /* ------------------------------------------------------------------ */ /* Solve L'Px=b: x = P' (L' \ b) */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* W [i] = B [i] ; */ ASSIGN (W [i], Bx, Bz, i, Bsplit) ; } flops = UMF_lhsolve (Numeric, W, Pattern) ; for (i = 0 ; i < n ; i++) { X [Rperm [i]] = W [i] ; } status = UMFPACK_OK ; } else if (sys == UMFPACK_Lat_P) { /* ------------------------------------------------------------------ */ /* Solve L.'Px=b: x = P' (L.' \ b) */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* W [i] = B [i] ; */ ASSIGN (W [i], Bx, Bz, i, Bsplit) ; } flops = UMF_ltsolve (Numeric, W, Pattern) ; for (i = 0 ; i < n ; i++) { X [Rperm [i]] = W [i] ; } status = UMFPACK_OK ; } else if (sys == UMFPACK_Lt) { /* ------------------------------------------------------------------ */ /* Solve L'x=b: x = L' \ b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [i] ; */ ASSIGN (X [i], Bx, Bz, i, Bsplit) ; } flops = UMF_lhsolve (Numeric, X, Pattern) ; status = UMFPACK_OK ; } else if (sys == UMFPACK_Lat) { /* ------------------------------------------------------------------ */ /* Solve L.'x=b: x = L.' \ b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [i] ; */ ASSIGN (X [i], Bx, Bz, i, Bsplit) ; } flops = UMF_ltsolve (Numeric, X, Pattern) ; status = UMFPACK_OK ; } else if (sys == UMFPACK_U_Qt) { /* ------------------------------------------------------------------ */ /* Solve UQ'x=b: x = Q (U \ b) */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* W [i] = B [i] ; */ ASSIGN (W [i], Bx, Bz, i, Bsplit) ; } flops = UMF_usolve (Numeric, W, Pattern) ; for (i = 0 ; i < n ; i++) { X [Cperm [i]] = W [i] ; } } else if (sys == UMFPACK_U) { /* ------------------------------------------------------------------ */ /* Solve Ux=b: x = U \ b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [i] ; */ ASSIGN (X [i], Bx, Bz, i, Bsplit) ; } flops = UMF_usolve (Numeric, X, Pattern) ; } else if (sys == UMFPACK_Q_Ut) { /* ------------------------------------------------------------------ */ /* Solve QU'x=b: x = U' \ Q'b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [Cperm [i]] ; */ ASSIGN (X [i], Bx, Bz, Cperm [i], Bsplit) ; } flops = UMF_uhsolve (Numeric, X, Pattern) ; } else if (sys == UMFPACK_Q_Uat) { /* ------------------------------------------------------------------ */ /* Solve QU.'x=b: x = U.' \ Q'b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [Cperm [i]] ; */ ASSIGN (X [i], Bx, Bz, Cperm [i], Bsplit) ; } flops = UMF_utsolve (Numeric, X, Pattern) ; } else if (sys == UMFPACK_Ut) { /* ------------------------------------------------------------------ */ /* Solve U'x=b: x = U' \ b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [i] ; */ ASSIGN (X [i], Bx, Bz, i, Bsplit) ; } flops = UMF_uhsolve (Numeric, X, Pattern) ; } else if (sys == UMFPACK_Uat) { /* ------------------------------------------------------------------ */ /* Solve U'x=b: x = U' \ b */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < n ; i++) { /* X [i] = B [i] ; */ ASSIGN (X [i], Bx, Bz, i, Bsplit) ; } flops = UMF_utsolve (Numeric, X, Pattern) ; } else { return (UMFPACK_ERROR_invalid_system) ; } #ifdef COMPLEX /* copy the solution back, from Entry X [ ] to double Xx [ ] and Xz [ ] */ if (AXsplit) { for (i = 0 ; i < n ; i++) { Xx [i] = REAL_COMPONENT (X [i]) ; Xz [i] = IMAG_COMPONENT (X [i]) ; } } #endif /* return UMFPACK_OK, or UMFPACK_WARNING_singular_matrix */ /* Note that systems involving just L will return UMFPACK_OK */ Info [UMFPACK_SOLVE_FLOPS] = flops ; return (status) ; } /* ========================================================================== */ /* === do_step ============================================================== */ /* ========================================================================== */ /* Perform one step of iterative refinement, for A x = b or A' x = b */ PRIVATE Int do_step /* return TRUE if iterative refinement done */ ( double omega [3], Int step, /* which step of iterative refinement to do */ const double B2 [ ], /* abs (B) */ Entry X [ ], const Entry W [ ], const double Y [ ], const double Z2 [ ], Entry S [ ], Int n, double Info [UMFPACK_INFO] ) { double last_omega [3], tau, nctau, d1, wd1, d2, wd2, xi, yix, wi, xnorm ; Int i ; /* DBL_EPSILON is a standard ANSI C term defined in */ /* It is the smallest positive x such that 1.0+x != 1.0 */ nctau = 1000 * n * DBL_EPSILON ; DEBUG0 (("do_step start: nctau = %30.20e\n", nctau)) ; ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug, FALSE, FALSE) == UMFPACK_OK) ; /* for approximate flop count, assume d1 > tau is always true */ /* flops += (2*ABS_FLOPS + 5) * n ; (done in UMF_solve, above) */ /* ---------------------------------------------------------------------- */ /* save the last iteration in case we need to reinstate it */ /* ---------------------------------------------------------------------- */ last_omega [0] = omega [0] ; last_omega [1] = omega [1] ; last_omega [2] = omega [2] ; /* ---------------------------------------------------------------------- */ /* compute sparse backward errors: omega [1] and omega [2] */ /* ---------------------------------------------------------------------- */ /* xnorm = ||x|| maxnorm */ xnorm = 0.0 ; for (i = 0 ; i < n ; i++) { /* xi = ABS (X [i]) ; */ ABS (xi, X [i]) ; if (SCALAR_IS_NAN (xi)) { xnorm = xi ; break ; } /* no NaN's to consider here: */ xnorm = MAX (xnorm, xi) ; } omega [1] = 0. ; omega [2] = 0. ; for (i = 0 ; i < n ; i++) { yix = Y [i] * xnorm ; tau = (yix + B2 [i]) * nctau ; d1 = Z2 [i] + B2 [i] ; /* wi = ABS (W [i]) ; */ ABS (wi, W [i]) ; if (SCALAR_IS_NAN (d1)) { omega [1] = d1 ; omega [2] = d1 ; break ; } if (SCALAR_IS_NAN (tau)) { omega [1] = tau ; omega [2] = tau ; break ; } if (d1 > tau) /* a double relop, but no NaN's here */ { wd1 = wi / d1 ; omega [1] = MAX (omega [1], wd1) ; } else if (tau > 0.0) /* a double relop, but no NaN's here */ { d2 = Z2 [i] + yix ; wd2 = wi / d2 ; omega [2] = MAX (omega [2], wd2) ; } } omega [0] = omega [1] + omega [2] ; Info [UMFPACK_OMEGA1] = omega [1] ; Info [UMFPACK_OMEGA2] = omega [2] ; /* ---------------------------------------------------------------------- */ /* stop the iterations if the backward error is small, or NaN */ /* ---------------------------------------------------------------------- */ Info [UMFPACK_IR_TAKEN] = step ; Info [UMFPACK_IR_ATTEMPTED] = step ; if (SCALAR_IS_NAN (omega [0])) { DEBUG0 (("omega[0] is NaN - done.\n")) ; ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug, FALSE, FALSE) == UMFPACK_OK) ; return (TRUE) ; } if (omega [0] < DBL_EPSILON) /* double relop, but no NaN case here */ { DEBUG0 (("omega[0] too small - done.\n")) ; ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug, FALSE, FALSE) == UMFPACK_OK) ; return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* stop if insufficient decrease in omega */ /* ---------------------------------------------------------------------- */ /* double relop, but no NaN case here: */ if (step > 0 && omega [0] > last_omega [0] / 2) { DEBUG0 (("stop refinement\n")) ; if (omega [0] > last_omega [0]) { /* last iteration better than this one, reinstate it */ DEBUG0 (("last iteration better\n")) ; for (i = 0 ; i < n ; i++) { X [i] = S [i] ; } Info [UMFPACK_OMEGA1] = last_omega [1] ; Info [UMFPACK_OMEGA2] = last_omega [2] ; } Info [UMFPACK_IR_TAKEN] = step - 1 ; ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug, FALSE, FALSE) == UMFPACK_OK) ; return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* save current solution in case we need to reinstate */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i < n ; i++) { S [i] = X [i] ; } /* ---------------------------------------------------------------------- */ /* iterative refinement continues */ /* ---------------------------------------------------------------------- */ ASSERT (UMF_report_vector (n, (double *) X, (double *) NULL, UMF_debug, FALSE, FALSE) == UMFPACK_OK) ; return (FALSE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_tuple_lengths.c0000644000175000017500000001054011674452555023542 0ustar sonnesonne/* ========================================================================== */ /* === UMF_tuple_lengths ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Determine the tuple list lengths, and the amount of memory required for */ /* them. Return the amount of memory needed to store all the tuples. */ /* This routine assumes that the tuple lists themselves are either already */ /* deallocated, or will be shortly (so Row[ ].tlen and Col[ ].tlen are */ /* overwritten) */ #include "umf_internal.h" #include "umf_tuple_lengths.h" GLOBAL Int UMF_tuple_lengths /* return memory usage */ ( NumericType *Numeric, WorkType *Work, double *p_dusage /* output argument */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ double dusage ; Int e, nrows, ncols, nel, i, *Rows, *Cols, row, col, n_row, n_col, *E, *Row_degree, *Row_tlen, *Col_degree, *Col_tlen, usage, n1 ; Element *ep ; Unit *p ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ E = Work->E ; Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro only */ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro only */ Row_tlen = Numeric->Uilen ; Col_tlen = Numeric->Lilen ; n_row = Work->n_row ; n_col = Work->n_col ; n1 = Work->n1 ; nel = Work->nel ; DEBUG3 (("TUPLE_LENGTHS: n_row "ID" n_col "ID" nel "ID"\n", n_row, n_col, nel)) ; ASSERT (nel < Work->elen) ; /* tuple list lengths already initialized to zero */ /* ---------------------------------------------------------------------- */ /* scan each element: count tuple list lengths (include element 0) */ /* ---------------------------------------------------------------------- */ for (e = 1 ; e <= nel ; e++) /* for all elements, in any order */ { if (E [e]) { #ifndef NDEBUG UMF_dump_element (Numeric, Work, e, FALSE) ; #endif p = Numeric->Memory + E [e] ; GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncols) ; nrows = ep->nrows ; for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; ASSERT (row == EMPTY || (row >= n1 && row < n_row)) ; if (row >= n1) { ASSERT (NON_PIVOTAL_ROW (row)) ; Row_tlen [row] ++ ; } } for (i = 0 ; i < ncols ; i++) { col = Cols [i] ; ASSERT (col == EMPTY || (col >= n1 && col < n_col)) ; if (col >= n1) { ASSERT (NON_PIVOTAL_COL (col)) ; Col_tlen [col] ++ ; } } } } /* note: tuple lengths are now modified, but the tuple lists are not */ /* updated to reflect that fact. */ /* ---------------------------------------------------------------------- */ /* determine the required memory to hold all the tuple lists */ /* ---------------------------------------------------------------------- */ DEBUG0 (("UMF_build_tuples_usage\n")) ; usage = 0 ; dusage = 0 ; ASSERT (Col_tlen && Col_degree) ; for (col = n1 ; col < n_col ; col++) { if (NON_PIVOTAL_COL (col)) { usage += 1 + UNITS (Tuple, TUPLES (Col_tlen [col])) ; dusage += 1 + DUNITS (Tuple, TUPLES (Col_tlen [col])) ; DEBUG0 ((" col: "ID" tlen "ID" usage so far: "ID"\n", col, Col_tlen [col], usage)) ; } } ASSERT (Row_tlen && Row_degree) ; for (row = n1 ; row < n_row ; row++) { if (NON_PIVOTAL_ROW (row)) { usage += 1 + UNITS (Tuple, TUPLES (Row_tlen [row])) ; dusage += 1 + DUNITS (Tuple, TUPLES (Row_tlen [row])) ; DEBUG0 ((" row: "ID" tlen "ID" usage so far: "ID"\n", row, Row_tlen [row], usage)) ; } } DEBUG0 (("UMF_build_tuples_usage "ID" %g\n", usage, dusage)) ; *p_dusage = dusage ; return (usage) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.h0000644000175000017500000000076411674452555022205 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL double UMF_lsolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_blas3_update.c0000644000175000017500000001031611674452555023234 0ustar sonnesonne/* ========================================================================== */ /* === UMF_blas3_update ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.h" #include "umf_blas3_update.h" GLOBAL void UMF_blas3_update ( WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry *L, *U, *C, *LU ; Int i, j, s, k, m, n, d, nb, dc ; #ifndef NBLAS Int blas_ok = TRUE ; #else #define blas_ok FALSE #endif DEBUG5 (("In UMF_blas3_update "ID" "ID" "ID"\n", Work->fnpiv, Work->fnrows, Work->fncols)) ; k = Work->fnpiv ; if (k == 0) { /* no work to do */ return ; } m = Work->fnrows ; n = Work->fncols ; d = Work->fnr_curr ; dc = Work->fnc_curr ; nb = Work->nb ; ASSERT (d >= 0 && (d % 2) == 1) ; C = Work->Fcblock ; /* ldc is fnr_curr */ L = Work->Flblock ; /* ldl is fnr_curr */ U = Work->Fublock ; /* ldu is fnc_curr, stored by rows */ LU = Work->Flublock ; /* nb-by-nb */ #ifndef NDEBUG DEBUG5 (("DO RANK-NB UPDATE of frontal:\n")) ; DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (C, d, m, n) ; DEBUG7 (("A block: ")) ; UMF_dump_dense (L, d, m, k) ; DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ; #endif if (k == 1) { #ifndef NBLAS BLAS_GER (m, n, L, U, C, d) ; #endif if (!blas_ok) { /* rank-1 outer product to update the C block */ for (j = 0 ; j < n ; j++) { Entry u_j = U [j] ; if (IS_NONZERO (u_j)) { Entry *c_ij, *l_is ; c_ij = & C [j*d] ; l_is = & L [0] ; #pragma ivdep for (i = 0 ; i < m ; i++) { /* C [i+j*d]-= L [i] * U [j] */ MULT_SUB (*c_ij, *l_is, u_j) ; c_ij++ ; l_is++ ; } } } } } else { /* triangular solve to update the U block */ #ifndef NBLAS BLAS_TRSM_RIGHT (n, k, LU, nb, U, dc) ; #endif if (!blas_ok) { /* use plain C code if no BLAS at compile time, or if integer * overflow has occurred */ for (s = 0 ; s < k ; s++) { for (i = s+1 ; i < k ; i++) { Entry l_is = LU [i+s*nb] ; if (IS_NONZERO (l_is)) { Entry *u_ij, *u_sj ; u_ij = & U [i*dc] ; u_sj = & U [s*dc] ; #pragma ivdep for (j = 0 ; j < n ; j++) { /* U [i*dc+j] -= LU [i+s*nb] * U [s*dc+j] ; */ MULT_SUB (*u_ij, l_is, *u_sj) ; u_ij++ ; u_sj++ ; } } } } } /* rank-k outer product to update the C block */ /* C = C - L*U' (U is stored by rows, not columns) */ #ifndef NBLAS BLAS_GEMM (m, n, k, L, U, dc, C, d) ; #endif if (!blas_ok) { /* use plain C code if no BLAS at compile time, or if integer * overflow has occurred */ for (s = 0 ; s < k ; s++) { for (j = 0 ; j < n ; j++) { Entry u_sj = U [j+s*dc] ; if (IS_NONZERO (u_sj)) { Entry *c_ij, *l_is ; c_ij = & C [j*d] ; l_is = & L [s*d] ; #pragma ivdep for (i = 0 ; i < m ; i++) { /* C [i+j*d]-= L [i+s*d] * U [s*dc+j] */ MULT_SUB (*c_ij, *l_is, u_sj) ; c_ij++ ; l_is++ ; } } } } } } #ifndef NDEBUG DEBUG5 (("RANK-NB UPDATE of frontal done:\n")) ; DEBUG5 (("DGEMM : "ID" "ID" "ID"\n", k, m, n)) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (C, d, m, n) ; DEBUG7 (("A block: ")) ; UMF_dump_dense (L, d, m, k) ; DEBUG7 (("B' block: ")) ; UMF_dump_dense (U, dc, n, k) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (LU, nb, k, k) ; #endif DEBUG2 (("blas3 "ID" "ID" "ID"\n", k, Work->fnrows, Work->fncols)) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.c0000644000175000017500000000546711674452555022150 0ustar sonnesonne/* ========================================================================== */ /* === UMF_malloc =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Allocate a block of n objects, each of a given size. This routine does not handle the case when the size is 1 (allocating char's) because of potential integer overflow. UMFPACK never does that. Also maintains the UMFPACK malloc count. */ #include "umf_internal.h" #include "umf_malloc.h" #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) /* UMF_malloc_count is a count of the objects malloc'd by UMFPACK. If you suspect a memory leak in your program (caused by not properly destroying the Symbolic and Numeric objects) then compile with -DUMF_MALLOC_COUNT and check value of UMF_malloc_count. By default, UMF_MALLOC_COUNT is not defined, and thus UMFPACK has no global variables. */ GLOBAL Int UMF_malloc_count = 0 ; #endif #ifdef UMF_TCOV_TEST /* For exhaustive statement coverage testing only! */ GLOBAL int umf_fail, umf_fail_lo, umf_fail_hi ; GLOBAL int umf_realloc_fail, umf_realloc_lo, umf_realloc_hi ; #endif GLOBAL void *UMF_malloc ( Int n_objects, size_t size_of_object ) { size_t size ; void *p ; #ifdef UMF_TCOV_TEST /* For exhaustive statement coverage testing only! */ /* Pretend to fail, to test out-of-memory conditions. */ umf_fail-- ; if (umf_fail <= umf_fail_hi && umf_fail >= umf_fail_lo) { DEBUG0 (("umf_malloc: Pretend to fail %d %d %d\n", umf_fail, umf_fail_hi, umf_fail_lo)) ; return ((void *) NULL) ; } #endif DEBUG0 (("UMF_malloc: ")) ; /* make sure that we allocate something */ n_objects = MAX (1, n_objects) ; size = (size_t) n_objects ; ASSERT (size_of_object > 1) ; if (size > Int_MAX / size_of_object) { /* object is too big for integer pointer arithmetic */ return ((void *) NULL) ; } size *= size_of_object ; /* see AMD/Source/amd_global.c for the memory allocator selection */ p = amd_malloc (size) ; DEBUG0 ((ID"\n", (Int) p)) ; #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) if (p) { /* One more object has been malloc'ed. Keep track of the count. */ /* (purely for sanity checks). */ UMF_malloc_count++ ; DEBUG0 ((" successful, new malloc count: "ID"\n", UMF_malloc_count)) ; } #endif return (p) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.c0000644000175000017500000001324111674452555022677 0ustar sonnesonne/* ========================================================================== */ /* === UMF_set_stats ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Sets statistics in Info array. Calculates everything in double precision, rather than Int or size_t, so that usage estimates can be computed even if the problem is so large that it would cause integer overflow. This routine has many double relop's, but the NaN case is ignored. */ #include "umf_internal.h" #include "umf_set_stats.h" #include "umf_symbolic_usage.h" GLOBAL void UMF_set_stats ( double Info [ ], SymbolicType *Symbolic, double max_usage, /* peak size of Numeric->Memory, in Units */ double num_mem_size, /* final size of Numeric->Memory, in Units */ double flops, /* "true flops" */ double lnz, /* nz in L */ double unz, /* nz in U */ double maxfrsize, /* largest front size */ double ulen, /* size of Numeric->Upattern */ double npiv, /* number of pivots found */ double maxnrows, /* largest #rows in front */ double maxncols, /* largest #cols in front */ Int scale, /* true if scaling the rows of A */ Int prefer_diagonal, /* true if diagonal pivoting (only square A) */ Int what /* ESTIMATE or ACTUAL */ ) { double sym_size, work_usage, nn, n_row, n_col, n_inner, num_On_size1, num_On_size2, num_usage, sym_maxncols, sym_maxnrows, elen, n1 ; n_col = Symbolic->n_col ; n_row = Symbolic->n_row ; n1 = Symbolic->n1 ; nn = MAX (n_row, n_col) ; n_inner = MIN (n_row, n_col) ; sym_maxncols = MIN (Symbolic->maxncols + Symbolic->nb, n_col) ; sym_maxnrows = MIN (Symbolic->maxnrows + Symbolic->nb, n_row) ; elen = (n_col - n1) + (n_row - n1) + MIN (n_col - n1, n_row - n1) + 1 ; /* final Symbolic object size */ sym_size = UMF_symbolic_usage (Symbolic->n_row, Symbolic->n_col, Symbolic->nchains, Symbolic->nfr, Symbolic->esize, prefer_diagonal) ; /* size of O(n) part of Numeric object during factorization, */ /* except Numeric->Memory and Numeric->Upattern */ num_On_size1 = DUNITS (NumericType, 1) /* Numeric structure */ + DUNITS (Entry, n_inner+1) /* D */ + 4 * DUNITS (Int, n_row+1) /* Rperm, Lpos, Uilen, Uip */ + 4 * DUNITS (Int, n_col+1) /* Cperm, Upos, Lilen, Lip */ + (scale ? DUNITS (Entry, n_row) : 0) ; /* Rs, row scale factors */ /* size of O(n) part of Numeric object after factorization, */ /* except Numeric->Memory and Numeric->Upattern */ num_On_size2 = DUNITS (NumericType, 1) /* Numeric structure */ + DUNITS (Entry, n_inner+1) /* D */ + DUNITS (Int, n_row+1) /* Rperm */ + DUNITS (Int, n_col+1) /* Cperm */ + 6 * DUNITS (Int, npiv+1) /* Lpos, Uilen, Uip, Upos, Lilen, Lip */ + (scale ? DUNITS (Entry, n_row) : 0) ; /* Rs, row scale factors */ DEBUG1 (("num O(n) size2: %g\n", num_On_size2)) ; /* peak size of Numeric->Memory, including LU factors, current frontal * matrix, elements, and tuple lists. */ Info [UMFPACK_VARIABLE_PEAK + what] = max_usage ; /* final size of Numeric->Memory (LU factors only) */ Info [UMFPACK_VARIABLE_FINAL + what] = num_mem_size ; /* final size of Numeric object, including Numeric->Memory and ->Upattern */ Info [UMFPACK_NUMERIC_SIZE + what] = num_On_size2 + num_mem_size /* final Numeric->Memory size */ + DUNITS (Int, ulen+1) ;/* Numeric->Upattern (from Work->Upattern) */ DEBUG1 (("num mem size: %g\n", num_mem_size)) ; DEBUG1 (("ulen units %g\n", DUNITS (Int, ulen))) ; DEBUG1 (("numeric size %g\n", Info [UMFPACK_NUMERIC_SIZE + what])) ; /* largest front size (working array size, or actual size used) */ Info [UMFPACK_MAX_FRONT_SIZE + what] = maxfrsize ; Info [UMFPACK_MAX_FRONT_NROWS + what] = maxnrows ; Info [UMFPACK_MAX_FRONT_NCOLS + what] = maxncols ; DEBUGm4 (("maxnrows %g maxncols %g\n", maxnrows, maxncols)) ; DEBUGm4 (("maxfrsize %g\n", maxfrsize)) ; /* UMF_kernel usage, from work_alloc routine in umf_kernel.c */ work_usage = /* Work-> arrays, except for current frontal matrix which is allocated * inside Numeric->Memory. */ 2 * DUNITS (Entry, sym_maxnrows + 1) /* Wx, Wy */ + 2 * DUNITS (Int, n_row+1) /* Frpos, Lpattern */ + 2 * DUNITS (Int, n_col+1) /* Fcpos, Upattern */ + DUNITS (Int, nn + 1) /* Wp */ + DUNITS (Int, MAX (n_col, sym_maxnrows) + 1) /* Wrp */ + 2 * DUNITS (Int, sym_maxnrows + 1) /* Frows, Wm */ + 3 * DUNITS (Int, sym_maxncols + 1) /* Fcols, Wio, Woi */ + DUNITS (Int, MAX (sym_maxnrows, sym_maxncols) + 1) /* Woo */ + DUNITS (Int, elen) /* E */ + DUNITS (Int, Symbolic->nfr + 1) /* Front_new1strow */ + ((n_row == n_col) ? (2 * DUNITS (Int, nn)) : 0) ; /* Diag map,imap */ /* Peak memory for just UMFPACK_numeric. */ num_usage = sym_size /* size of Symbolic object */ + num_On_size1 /* O(n) part of Numeric object (excl. Upattern) */ + work_usage /* Work-> arrays (including Upattern) */ + max_usage ; /* peak size of Numeric->Memory */ /* peak memory usage for both UMFPACK_*symbolic and UMFPACK_numeric. */ Info [UMFPACK_PEAK_MEMORY + what] = MAX (Symbolic->peak_sym_usage, num_usage) ; Info [UMFPACK_FLOPS + what] = flops ; Info [UMFPACK_LNZ + what] = lnz ; Info [UMFPACK_UNZ + what] = unz ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.c0000644000175000017500000001442511674452555022363 0ustar sonnesonne/* ========================================================================== */ /* === UMF_ltsolve ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Solves L'x = b or L.'x=b, where L is the lower triangular factor of a */ /* matrix. B is overwritten with the solution X. */ /* Returns the floating point operation count */ #include "umf_internal.h" #include "umf_ltsolve.h" GLOBAL double #ifdef CONJUGATE_SOLVE UMF_lhsolve /* solve L'x=b (complex conjugate transpose) */ #else UMF_ltsolve /* solve L.'x=b (array transpose) */ #endif ( NumericType *Numeric, Entry X [ ], /* b on input, solution x on output */ Int Pattern [ ] /* a work array of size n */ ) { Entry xk ; Entry *xp, *Lval ; Int k, deg, *ip, j, row, *Lpos, *Lilen, kstart, kend, *Lip, llen, lp, pos, npiv, n1, *Li ; /* ---------------------------------------------------------------------- */ if (Numeric->n_row != Numeric->n_col) return (0.) ; npiv = Numeric->npiv ; Lpos = Numeric->Lpos ; Lilen = Numeric->Lilen ; Lip = Numeric->Lip ; kstart = npiv ; n1 = Numeric->n1 ; #ifndef NDEBUG DEBUG4 (("Ltsolve start:\n")) ; for (j = 0 ; j < Numeric->n_row ; j++) { DEBUG4 (("Ltsolve start "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } #endif /* ---------------------------------------------------------------------- */ /* non-singletons */ /* ---------------------------------------------------------------------- */ for (kend = npiv-1 ; kend >= n1 ; kend = kstart-1) { /* ------------------------------------------------------------------ */ /* find the start of this Lchain */ /* ------------------------------------------------------------------ */ /* for (kstart = kend ; kstart >= 0 && Lip [kstart] > 0 ; kstart--) ; */ kstart = kend ; while (kstart >= 0 && Lip [kstart] > 0) { kstart-- ; } /* the Lchain goes from kstart to kend */ /* ------------------------------------------------------------------ */ /* scan the whole chain to find the pattern of the last column of L */ /* ------------------------------------------------------------------ */ deg = 0 ; DEBUG4 (("start of chain for column of L\n")) ; for (k = kstart ; k <= kend ; k++) { ASSERT (k >= 0 && k < npiv) ; /* -------------------------------------------------------------- */ /* make column k of L in Pattern [0..deg-1] */ /* -------------------------------------------------------------- */ /* remove pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n", k, Pattern [pos], pos)) ; ASSERT (k != kstart) ; ASSERT (deg > 0) ; ASSERT (pos >= 0 && pos < deg) ; ASSERT (Pattern [pos] == k) ; Pattern [pos] = Pattern [--deg] ; } /* concatenate the pattern */ lp = Lip [k] ; if (k == kstart) { lp = -lp ; } ASSERT (lp > 0) ; ip = (Int *) (Numeric->Memory + lp) ; llen = Lilen [k] ; for (j = 0 ; j < llen ; j++) { row = *ip++ ; DEBUG4 ((" row "ID" k "ID"\n", row, k)) ; ASSERT (row > k) ; Pattern [deg++] = row ; } } /* Pattern [0..deg-1] is now the pattern of column kend */ /* ------------------------------------------------------------------ */ /* solve using this chain, in reverse order */ /* ------------------------------------------------------------------ */ DEBUG4 (("Unwinding Lchain\n")) ; for (k = kend ; k >= kstart ; k--) { /* -------------------------------------------------------------- */ /* use column k of L */ /* -------------------------------------------------------------- */ ASSERT (k >= 0 && k < npiv) ; lp = Lip [k] ; if (k == kstart) { lp = -lp ; } ASSERT (lp > 0) ; llen = Lilen [k] ; xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ; xk = X [k] ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ; EDEBUG4 (*xp) ; DEBUG4 (("\n")) ; #ifdef CONJUGATE_SOLVE /* xk -= X [Pattern [j]] * conjugate (*xp) ; */ MULT_SUB_CONJ (xk, X [Pattern [j]], *xp) ; #else /* xk -= X [Pattern [j]] * (*xp) ; */ MULT_SUB (xk, X [Pattern [j]], *xp) ; #endif xp++ ; } X [k] = xk ; /* -------------------------------------------------------------- */ /* construct column k-1 of L */ /* -------------------------------------------------------------- */ /* un-concatenate the pattern */ deg -= llen ; /* add pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { DEBUG4 ((" k "ID" adding row "ID" at position "ID"\n", k, k, pos)) ; ASSERT (k != kstart) ; ASSERT (pos >= 0 && pos <= deg) ; Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } } } /* ---------------------------------------------------------------------- */ /* singletons */ /* ---------------------------------------------------------------------- */ for (k = n1 - 1 ; k >= 0 ; k--) { DEBUG4 (("Singleton k "ID"\n", k)) ; deg = Lilen [k] ; if (deg > 0) { xk = X [k] ; lp = Lip [k] ; Li = (Int *) (Numeric->Memory + lp) ; lp += UNITS (Int, deg) ; Lval = (Entry *) (Numeric->Memory + lp) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Li [j], k)) ; EDEBUG4 (Lval [j]) ; DEBUG4 (("\n")) ; #ifdef CONJUGATE_SOLVE /* xk -= X [Li [j]] * conjugate (Lval [j]) ; */ MULT_SUB_CONJ (xk, X [Li [j]], Lval [j]) ; #else /* xk -= X [Li [j]] * Lval [j] ; */ MULT_SUB (xk, X [Li [j]], Lval [j]) ; #endif } X [k] = xk ; } } #ifndef NDEBUG for (j = 0 ; j < Numeric->n_row ; j++) { DEBUG4 (("Ltsolve done "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } DEBUG4 (("Ltsolve done.\n")) ; #endif return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.c0000644000175000017500000006366211674452555023067 0ustar sonnesonne/* ========================================================================== */ /* === UMF_singletons ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Find and order the row and column singletons of a matrix A. If there are * row and column singletons, the output is a row and column permutation such * that the matrix is in the following form: * * x x x x x x x x x * . x x x x x x x x * . . x x x x x x x * . . . x . . . . . * . . . x x . . . . * . . . x x s s s s * . . . x x s s s s * . . . x x s s s s * . . . x x s s s s * * The above example has 3 column singletons (the first three columns and * their corresponding pivot rows) and 2 row singletons. The singletons are * ordered first, because they have zero Markowitz cost. The LU factorization * for these first five rows and columns is free - there is no work to do * (except to scale the pivot columns for the 2 row singletons), and no * fill-in occurs. The remaining submatrix (4-by-4 in the above example) * has no rows or columns with degree one. It may have empty rows or columns. * * This algorithm does not perform a full permutation to block triangular * form. If there are one or more singletons, then the matrix can be * permuted to block triangular form, but UMFPACK does not perform the full * BTF permutation (see also "dmperm" in MATLAB, CSparse cs_dmperm, * and SuiteSparse/BTF). */ #include "umf_internal.h" #include "umf_singletons.h" #ifndef NDEBUG /* ========================================================================== */ /* === debug routines ======================================================= */ /* ========================================================================== */ /* Dump the singleton queue */ PRIVATE void dump_singletons ( Int head, /* head of the queue */ Int tail, /* tail of the queue */ Int Next [ ], /* Next [i] is the next object after i */ char *name, /* "row" or "col" */ Int Deg [ ], /* Deg [i] is the degree of object i */ Int n /* objects are in the range 0 to n-1 */ ) { Int i, next, cnt ; DEBUG6 (("%s Singleton list: head "ID" tail "ID"\n", name, head, tail)) ; i = head ; ASSERT (head >= EMPTY && head < n) ; ASSERT (tail >= EMPTY && tail < n) ; cnt = 0 ; while (i != EMPTY) { DEBUG7 ((" "ID": "ID" deg: "ID"\n", cnt, i, Deg [i])) ; ASSERT (i >= 0 && i < n) ; next = Next [i] ; if (i == tail) ASSERT (next == EMPTY) ; i = next ; cnt++ ; ASSERT (cnt <= n) ; } } PRIVATE void dump_mat ( char *xname, char *yname, Int nx, Int ny, const Int Xp [ ], const Int Xi [ ], Int Xdeg [ ], Int Ydeg [ ] ) { Int x, y, p, p1, p2, xdeg, do_xdeg, ydeg ; DEBUG6 (("\n ==== Dump %s mat:\n", xname)) ; for (x = 0 ; x < nx ; x++) { p1 = Xp [x] ; p2 = Xp [x+1] ; xdeg = Xdeg [x] ; DEBUG6 (("Dump %s "ID" p1 "ID" p2 "ID" deg "ID"\n", xname, x, p1, p2, xdeg)) ; do_xdeg = (xdeg >= 0) ; for (p = p1 ; p < p2 ; p++) { y = Xi [p] ; DEBUG7 ((" %s "ID" deg: ", yname, y)) ; ASSERT (y >= 0 && y < ny) ; ydeg = Ydeg [y] ; DEBUG7 ((ID"\n", ydeg)) ; if (do_xdeg && ydeg >= 0) { xdeg-- ; } } ASSERT (IMPLIES (do_xdeg, xdeg == 0)) ; } } #endif /* ========================================================================== */ /* === create_row_form ====================================================== */ /* ========================================================================== */ /* Create the row-form R of the column-form input matrix A. This could be done * by UMF_transpose, except that Rdeg has already been computed. */ PRIVATE void create_row_form ( /* input, not modified: */ Int n_row, /* A is n_row-by-n_col, nz = Ap [n_col] */ Int n_col, const Int Ap [ ], /* Ap [0..n_col]: column pointers for A */ const Int Ai [ ], /* Ai [0..nz-1]: row indices for A */ Int Rdeg [ ], /* Rdeg [0..n_row-1]: row degrees */ /* output, not defined on input: */ Int Rp [ ], /* Rp [0..n_row]: row pointers for R */ Int Ri [ ], /* Ri [0..nz-1]: column indices for R */ /* workspace, not defined on input or output */ Int W [ ] /* size n_row */ ) { Int row, col, p, p2 ; /* create the row pointers */ Rp [0] = 0 ; W [0] = 0 ; for (row = 0 ; row < n_row ; row++) { Rp [row+1] = Rp [row] + Rdeg [row] ; W [row] = Rp [row] ; } /* create the indices for the row-form */ for (col = 0 ; col < n_col ; col++) { p2 = Ap [col+1] ; for (p = Ap [col] ; p < p2 ; p++) { Ri [W [Ai [p]]++] = col ; } } } /* ========================================================================== */ /* === order_singletons ===================================================== */ /* ========================================================================== */ PRIVATE int order_singletons /* return new number of singletons */ ( Int k, /* the number of singletons so far */ Int head, Int tail, Int Next [ ], Int Xdeg [ ], Int Xperm [ ], const Int Xp [ ], const Int Xi [ ], Int Ydeg [ ], Int Yperm [ ], const Int Yp [ ], const Int Yi [ ] #ifndef NDEBUG , char *xname, char *yname, Int nx, Int ny #endif ) { Int xpivot, x, y, ypivot, p, p2, deg ; #ifndef NDEBUG Int i, k1 = k ; dump_singletons (head, tail, Next, xname, Xdeg, nx) ; dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ; dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ; #endif while (head != EMPTY) { /* remove the singleton at the head of the queue */ xpivot = head ; DEBUG1 (("------ Order %s singleton: "ID"\n", xname, xpivot)) ; head = Next [xpivot] ; if (head == EMPTY) tail = EMPTY ; #ifndef NDEBUG if (k % 100 == 0) dump_singletons (head, tail, Next, xname, Xdeg, nx) ; #endif ASSERT (Xdeg [xpivot] >= 0) ; if (Xdeg [xpivot] != 1) { /* This row/column x is empty. The matrix is singular. * x will be ordered last in Xperm. */ DEBUG1 (("empty %s, after singletons removed\n", xname)) ; continue ; } /* find the ypivot to match with this xpivot */ #ifndef NDEBUG /* there can only be one ypivot, since the degree of x is 1 */ deg = 0 ; p2 = Xp [xpivot+1] ; for (p = Xp [xpivot] ; p < p2 ; p++) { y = Xi [p] ; DEBUG1 (("%s: "ID"\n", yname, y)) ; if (Ydeg [y] >= 0) { /* this is a live index in this xpivot vector */ deg++ ; } } ASSERT (deg == 1) ; #endif ypivot = EMPTY ; p2 = Xp [xpivot+1] ; for (p = Xp [xpivot] ; p < p2 ; p++) { y = Xi [p] ; DEBUG1 (("%s: "ID"\n", yname, y)) ; if (Ydeg [y] >= 0) { /* this is a live index in this xpivot vector */ ypivot = y ; break ; } } DEBUG1 (("Pivot %s: "ID"\n", yname, ypivot)) ; ASSERT (ypivot != EMPTY) ; DEBUG1 (("deg "ID"\n", Ydeg [ypivot])) ; ASSERT (Ydeg [ypivot] >= 0) ; /* decrement the degrees after removing this singleton */ DEBUG1 (("p1 "ID"\n", Yp [ypivot])) ; DEBUG1 (("p2 "ID"\n", Yp [ypivot+1])) ; p2 = Yp [ypivot+1] ; for (p = Yp [ypivot] ; p < p2 ; p++) { x = Yi [p] ; DEBUG1 ((" %s: "ID" deg: "ID"\n", xname, x, Xdeg [x])) ; if (Xdeg [x] < 0) continue ; ASSERT (Xdeg [x] > 0) ; if (x == xpivot) continue ; deg = --(Xdeg [x]) ; ASSERT (Xdeg [x] >= 0) ; if (deg == 1) { /* this is a new singleton, put at the end of the queue */ Next [x] = EMPTY ; if (head == EMPTY) { head = x ; } else { ASSERT (tail != EMPTY) ; Next [tail] = x ; } tail = x ; DEBUG1 ((" New %s singleton: "ID"\n", xname, x)) ; #ifndef NDEBUG if (k % 100 == 0) { dump_singletons (head, tail, Next, xname, Xdeg, nx) ; } #endif } } /* flag the xpivot and ypivot by FLIP'ing the degrees */ Xdeg [xpivot] = FLIP (1) ; Ydeg [ypivot] = FLIP (Ydeg [ypivot]) ; /* keep track of the pivot row and column */ Xperm [k] = xpivot ; Yperm [k] = ypivot ; k++ ; #ifndef NDEBUG if (k % 1000 == 0) { dump_mat (xname, yname, nx, ny, Xp, Xi, Xdeg, Ydeg) ; dump_mat (yname, xname, ny, nx, Yp, Yi, Ydeg, Xdeg) ; } #endif } #ifndef NDEBUG DEBUGm4 (("%s singletons: k = "ID"\n", xname, k)) ; for (i = k1 ; i < k ; i++) { DEBUG1 ((" %s: "ID" %s: "ID"\n", xname, Xperm [i], yname, Yperm [i])) ; } ASSERT (k > 0) ; #endif return (k) ; } /* ========================================================================== */ /* === find_any_singletons ================================================== */ /* ========================================================================== */ PRIVATE Int find_any_singletons /* returns # of singletons found */ ( /* input, not modified: */ Int n_row, Int n_col, const Int Ap [ ], /* size n_col+1 */ const Int Ai [ ], /* size nz = Ap [n_col] */ /* input, modified on output: */ Int Cdeg [ ], /* size n_col */ Int Rdeg [ ], /* size n_row */ /* output, not defined on input: */ Int Cperm [ ], /* size n_col */ Int Rperm [ ], /* size n_row */ Int *p_n1r, /* # of row singletons */ Int *p_n1c, /* # of col singletons */ /* workspace, not defined on input or output */ Int Rp [ ], /* size n_row+1 */ Int Ri [ ], /* size nz */ Int W [ ], /* size n_row */ Int Next [ ] /* size MAX (n_row, n_col) */ ) { Int n1, col, row, row_form, head, tail, n1r, n1c ; /* ---------------------------------------------------------------------- */ /* eliminate column singletons */ /* ---------------------------------------------------------------------- */ n1 = 0 ; n1r = 0 ; n1c = 0 ; row_form = FALSE ; head = EMPTY ; tail = EMPTY ; for (col = n_col-1 ; col >= 0 ; col--) { if (Cdeg [col] == 1) { /* put the column singleton in the queue */ if (head == EMPTY) tail = col ; Next [col] = head ; head = col ; DEBUG1 (("Column singleton: "ID"\n", col)) ; } } if (head != EMPTY) { /* ------------------------------------------------------------------ */ /* create the row-form of A */ /* ------------------------------------------------------------------ */ create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ; row_form = TRUE ; /* ------------------------------------------------------------------ */ /* find and order the column singletons */ /* ------------------------------------------------------------------ */ n1 = order_singletons (0, head, tail, Next, Cdeg, Cperm, Ap, Ai, Rdeg, Rperm, Rp, Ri #ifndef NDEBUG , "col", "row", n_col, n_row #endif ) ; n1c = n1 ; } /* ---------------------------------------------------------------------- */ /* eliminate row singletons */ /* ---------------------------------------------------------------------- */ head = EMPTY ; tail = EMPTY ; for (row = n_row-1 ; row >= 0 ; row--) { if (Rdeg [row] == 1) { /* put the row singleton in the queue */ if (head == EMPTY) tail = row ; Next [row] = head ; head = row ; DEBUG1 (("Row singleton: "ID"\n", row)) ; } } if (head != EMPTY) { /* ------------------------------------------------------------------ */ /* create the row-form of A, if not already created */ /* ------------------------------------------------------------------ */ if (!row_form) { create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ; } /* ------------------------------------------------------------------ */ /* find and order the row singletons */ /* ------------------------------------------------------------------ */ n1 = order_singletons (n1, head, tail, Next, Rdeg, Rperm, Rp, Ri, Cdeg, Cperm, Ap, Ai #ifndef NDEBUG , "row", "col", n_row, n_col #endif ) ; n1r = n1 - n1c ; } DEBUG0 (("n1 "ID"\n", n1)) ; *p_n1r = n1r ; *p_n1c = n1c ; return (n1) ; } /* ========================================================================== */ /* === find_user_singletons ================================================= */ /* ========================================================================== */ PRIVATE Int find_user_singletons /* returns # singletons found */ ( /* input, not modified: */ Int n_row, Int n_col, const Int Ap [ ], /* size n_col+1 */ const Int Ai [ ], /* size nz = Ap [n_col] */ const Int Quser [ ], /* size n_col if present */ /* input, modified on output: */ Int Cdeg [ ], /* size n_col */ Int Rdeg [ ], /* size n_row */ /* output, not defined on input */ Int Cperm [ ], /* size n_col */ Int Rperm [ ], /* size n_row */ Int *p_n1r, /* # of row singletons */ Int *p_n1c, /* # of col singletons */ /* workspace, not defined on input or output */ Int Rp [ ], /* size n_row+1 */ Int Ri [ ], /* size nz */ Int W [ ] /* size n_row */ ) { Int n1, col, row, p, p2, pivcol, pivrow, found, k, n1r, n1c ; n1 = 0 ; n1r = 0 ; n1c = 0 ; *p_n1r = 0 ; *p_n1c = 0 ; /* find singletons in the user column permutation, Quser */ pivcol = Quser [0] ; found = (Cdeg [pivcol] == 1) ; DEBUG0 (("Is first col: "ID" a col singleton?: "ID"\n", pivcol, found)) ; if (!found) { /* the first column is not a column singleton, check for a row * singleton in the first column. */ for (p = Ap [pivcol] ; p < Ap [pivcol+1] ; p++) { if (Rdeg [Ai [p]] == 1) { DEBUG0 (("Row singleton in first col: "ID" row: "ID"\n", pivcol, Ai [p])) ; found = TRUE ; break ; } } } if (!found) { /* no singletons in the leading part of A (:,Quser) */ return (0) ; } /* there is at least one row or column singleton. Look for more. */ create_row_form (n_row, n_col, Ap, Ai, Rdeg, Rp, Ri, W) ; n1 = 0 ; for (k = 0 ; k < n_col ; k++) { pivcol = Quser [k] ; pivrow = EMPTY ; /* ------------------------------------------------------------------ */ /* check if col is a column singleton, or contains a row singleton */ /* ------------------------------------------------------------------ */ found = (Cdeg [pivcol] == 1) ; if (found) { /* -------------------------------------------------------------- */ /* pivcol is a column singleton */ /* -------------------------------------------------------------- */ DEBUG0 (("Found a col singleton: k "ID" pivcol "ID"\n", k, pivcol)); /* find the pivrow to match with this pivcol */ #ifndef NDEBUG /* there can only be one pivrow, since the degree of pivcol is 1 */ { Int deg = 0 ; p2 = Ap [pivcol+1] ; for (p = Ap [pivcol] ; p < p2 ; p++) { row = Ai [p] ; DEBUG1 (("row: "ID"\n", row)) ; if (Rdeg [row] >= 0) { /* this is a live index in this column vector */ deg++ ; } } ASSERT (deg == 1) ; } #endif p2 = Ap [pivcol+1] ; for (p = Ap [pivcol] ; p < p2 ; p++) { row = Ai [p] ; DEBUG1 (("row: "ID"\n", row)) ; if (Rdeg [row] >= 0) { /* this is a live index in this pivcol vector */ pivrow = row ; break ; } } DEBUG1 (("Pivot row: "ID"\n", pivrow)) ; ASSERT (pivrow != EMPTY) ; DEBUG1 (("deg "ID"\n", Rdeg [pivrow])) ; ASSERT (Rdeg [pivrow] >= 0) ; /* decrement the degrees after removing this col singleton */ DEBUG1 (("p1 "ID"\n", Rp [pivrow])) ; DEBUG1 (("p2 "ID"\n", Rp [pivrow+1])) ; p2 = Rp [pivrow+1] ; for (p = Rp [pivrow] ; p < p2 ; p++) { col = Ri [p] ; DEBUG1 ((" col: "ID" deg: "ID"\n", col, Cdeg [col])) ; if (Cdeg [col] < 0) continue ; ASSERT (Cdeg [col] > 0) ; Cdeg [col]-- ; ASSERT (Cdeg [col] >= 0) ; } /* flag the pivcol and pivrow by FLIP'ing the degrees */ Cdeg [pivcol] = FLIP (1) ; Rdeg [pivrow] = FLIP (Rdeg [pivrow]) ; n1c++ ; } else { /* -------------------------------------------------------------- */ /* pivcol may contain a row singleton */ /* -------------------------------------------------------------- */ p2 = Ap [pivcol+1] ; for (p = Ap [pivcol] ; p < p2 ; p++) { pivrow = Ai [p] ; if (Rdeg [pivrow] == 1) { DEBUG0 (("Row singleton in pivcol: "ID" row: "ID"\n", pivcol, pivrow)) ; found = TRUE ; break ; } } if (!found) { DEBUG0 (("End of user singletons\n")) ; break ; } #ifndef NDEBUG /* there can only be one pivrow, since the degree of pivcol is 1 */ { Int deg = 0 ; p2 = Rp [pivrow+1] ; for (p = Rp [pivrow] ; p < p2 ; p++) { col = Ri [p] ; DEBUG1 (("col: "ID" cdeg::: "ID"\n", col, Cdeg [col])) ; if (Cdeg [col] >= 0) { /* this is a live index in this column vector */ ASSERT (col == pivcol) ; deg++ ; } } ASSERT (deg == 1) ; } #endif DEBUG1 (("Pivot row: "ID"\n", pivrow)) ; DEBUG1 (("pivcol deg "ID"\n", Cdeg [pivcol])) ; ASSERT (Cdeg [pivcol] > 1) ; /* decrement the degrees after removing this row singleton */ DEBUG1 (("p1 "ID"\n", Ap [pivcol])) ; DEBUG1 (("p2 "ID"\n", Ap [pivcol+1])) ; p2 = Ap [pivcol+1] ; for (p = Ap [pivcol] ; p < p2 ; p++) { row = Ai [p] ; DEBUG1 ((" row: "ID" deg: "ID"\n", row, Rdeg [row])) ; if (Rdeg [row] < 0) continue ; ASSERT (Rdeg [row] > 0) ; Rdeg [row]-- ; ASSERT (Rdeg [row] >= 0) ; } /* flag the pivcol and pivrow by FLIP'ing the degrees */ Cdeg [pivcol] = FLIP (Cdeg [pivcol]) ; Rdeg [pivrow] = FLIP (1) ; n1r++ ; } /* keep track of the pivot row and column */ Cperm [k] = pivcol ; Rperm [k] = pivrow ; n1++ ; #ifndef NDEBUG dump_mat ("col", "row", n_col, n_row, Ap, Ai, Cdeg, Rdeg) ; dump_mat ("row", "col", n_row, n_col, Rp, Ri, Rdeg, Cdeg) ; #endif } DEBUGm4 (("User singletons found: "ID"\n", n1)) ; ASSERT (n1 > 0) ; *p_n1r = n1r ; *p_n1c = n1c ; return (n1) ; } /* ========================================================================== */ /* === finish_permutation =================================================== */ /* ========================================================================== */ /* Complete the permutation for the pruned submatrix. The singletons are * already ordered, but remove their flags. Place rows/columns that are empty * in the pruned submatrix at the end of the output permutation. This can only * occur if the matrix is singular. */ PRIVATE Int finish_permutation ( Int n1, Int nx, Int Xdeg [ ], const Int Xuser [ ], Int Xperm [ ], Int *p_max_deg ) { Int nempty, x, deg, s, max_deg, k ; nempty = 0 ; s = n1 ; max_deg = 0 ; DEBUG0 (("n1 "ID" nempty "ID"\n", n1, nempty)) ; for (k = 0 ; k < nx ; k++) { x = (Xuser != (Int *) NULL) ? Xuser [k] : k ; DEBUG0 (("finish perm k "ID" x "ID" nx "ID"\n", k, x, nx)) ; deg = Xdeg [x] ; if (deg == 0) { /* this row/col is empty in the pruned submatrix */ ASSERT (s < nx - nempty) ; DEBUG0 (("empty k "ID"\n", k)) ; nempty++ ; Xperm [nx - nempty] = x ; } else if (deg > 0) { /* this row/col is nonempty in the pruned submatrix */ ASSERT (s < nx - nempty) ; Xperm [s++] = x ; max_deg = MAX (max_deg, deg) ; } else { /* This is a singleton row/column - it is already ordered. * Just clear the flag. */ Xdeg [x] = FLIP (deg) ; } } ASSERT (s == nx - nempty) ; *p_max_deg = max_deg ; return (nempty) ; } /* ========================================================================== */ /* === UMF_singletons ======================================================= */ /* ========================================================================== */ GLOBAL Int UMF_singletons ( /* input, not modified: */ Int n_row, Int n_col, const Int Ap [ ], /* size n_col+1 */ const Int Ai [ ], /* size nz = Ap [n_col] */ const Int Quser [ ], /* size n_col if present */ Int strategy, /* strategy requested by user */ /* output, not defined on input: */ Int Cdeg [ ], /* size n_col */ Int Cperm [ ], /* size n_col */ Int Rdeg [ ], /* size n_row */ Int Rperm [ ], /* size n_row */ Int InvRperm [ ], /* size n_row, the inverse of Rperm */ Int *p_n1, /* # of col and row singletons */ Int *p_n1c, /* # of col singletons */ Int *p_n1r, /* # of row singletons */ Int *p_nempty_col, /* # of empty columns in pruned submatrix */ Int *p_nempty_row, /* # of empty columns in pruned submatrix */ Int *p_is_sym, /* TRUE if pruned submatrix is square and has been * symmetrically permuted by Cperm and Rperm */ Int *p_max_rdeg, /* maximum Rdeg in pruned submatrix */ /* workspace, not defined on input or output */ Int Rp [ ], /* size n_row+1 */ Int Ri [ ], /* size nz */ Int W [ ], /* size n_row */ Int Next [ ] /* size MAX (n_row, n_col) */ ) { Int n1, s, col, row, p, p1, p2, cdeg, last_row, is_sym, k, nempty_row, nempty_col, max_cdeg, max_rdeg, n1c, n1r ; /* ---------------------------------------------------------------------- */ /* initializations */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG UMF_dump_start ( ) ; DEBUGm4 (("Starting umf_singletons\n")) ; #endif /* ---------------------------------------------------------------------- */ /* scan the columns, check for errors and count row degrees */ /* ---------------------------------------------------------------------- */ if (Ap [0] != 0 || Ap [n_col] < 0) { return (UMFPACK_ERROR_invalid_matrix) ; } for (row = 0 ; row < n_row ; row++) { Rdeg [row] = 0 ; } for (col = 0 ; col < n_col ; col++) { p1 = Ap [col] ; p2 = Ap [col+1] ; cdeg = p2 - p1 ; if (cdeg < 0) { return (UMFPACK_ERROR_invalid_matrix) ; } last_row = EMPTY ; for (p = p1 ; p < p2 ; p++) { row = Ai [p] ; if (row <= last_row || row >= n_row) { return (UMFPACK_ERROR_invalid_matrix) ; } Rdeg [row]++ ; last_row = row ; } Cdeg [col] = cdeg ; } /* ---------------------------------------------------------------------- */ /* find singletons */ /* ---------------------------------------------------------------------- */ if (Quser != (Int *) NULL) { /* user has provided an input column ordering */ if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC) { /* look for singletons, but respect the user's input permutation */ n1 = find_user_singletons (n_row, n_col, Ap, Ai, Quser, Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W) ; } else { /* do not look for singletons if Quser given and strategy is * not unsymmetric */ n1 = 0 ; n1r = 0 ; n1c = 0 ; } } else { /* look for singletons anywhere */ n1 = find_any_singletons (n_row, n_col, Ap, Ai, Cdeg, Rdeg, Cperm, Rperm, &n1r, &n1c, Rp, Ri, W, Next) ; } /* ---------------------------------------------------------------------- */ /* eliminate empty columns and complete the column permutation */ /* ---------------------------------------------------------------------- */ nempty_col = finish_permutation (n1, n_col, Cdeg, Quser, Cperm, &max_cdeg) ; /* ---------------------------------------------------------------------- */ /* eliminate empty rows and complete the row permutation */ /* ---------------------------------------------------------------------- */ if (Quser != (Int *) NULL && strategy == UMFPACK_STRATEGY_SYMMETRIC) { /* rows should be symmetrically permuted according to Quser */ ASSERT (n_row == n_col) ; nempty_row = finish_permutation (n1, n_row, Rdeg, Quser, Rperm, &max_rdeg) ; } else { /* rows should not be symmetrically permuted according to Quser */ nempty_row = finish_permutation (n1, n_row, Rdeg, (Int *) NULL, Rperm, &max_rdeg) ; } /* ---------------------------------------------------------------------- */ /* compute the inverse of Rperm */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n_row ; k++) { ASSERT (Rperm [k] >= 0 && Rperm [k] < n_row) ; InvRperm [Rperm [k]] = k ; } /* ---------------------------------------------------------------------- */ /* see if pruned submatrix is square and has been symmetrically permuted */ /* ---------------------------------------------------------------------- */ /* The prior version of this code (with a "break" statement; UMFPACK 5.2) * causes UMFPACK to fail when optimization is enabled with gcc version * 4.2.4 in a 64-bit Linux environment. The bug is a compiler bug, not a * an UMFPACK bug. It is fixed in gcc version 4.3.2. However, as a * workaround for the compiler, the code below has been "fixed". */ if (n_row == n_col && nempty_row == nempty_col) { /* is_sym is true if the submatrix is square, and * Rperm [n1..n_row-nempty_row-1] = Cperm [n1..n_col-nempty_col-1] */ is_sym = TRUE ; for (s = n1 ; /* replaced the break with this test: */ is_sym && /* the remainder of this test is unchanged from v5.2.0: */ s < n_col - nempty_col ; s++) { if (Cperm [s] != Rperm [s]) { is_sym = FALSE ; /* removed a break statement here, which is OK but it tickles * the gcc 4.2.{3,4} compiler bug */ } } } else { is_sym = FALSE ; } DEBUGm4 (("Submatrix square and symmetrically permuted? "ID"\n", is_sym)) ; DEBUGm4 (("singletons "ID" row "ID" col "ID"\n", n1, n1r, n1c)) ; DEBUGm4 (("Empty cols "ID" rows "ID"\n", nempty_col, nempty_row)) ; *p_n1 = n1 ; *p_n1r = n1r ; *p_n1c = n1c ; *p_is_sym = is_sym ; *p_nempty_col = nempty_col ; *p_nempty_row = nempty_row ; *p_max_rdeg = max_rdeg ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_defaults.c0000644000175000017500000000772411674452555023345 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_defaults ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Sets default control parameters. See umfpack_defaults.h for details. */ #include "umf_internal.h" GLOBAL void UMFPACK_defaults ( double Control [UMFPACK_CONTROL] ) { Int i ; if (!Control) { /* silently return if no Control array */ return ; } for (i = 0 ; i < UMFPACK_CONTROL ; i++) { Control [i] = 0 ; } /* ---------------------------------------------------------------------- */ /* default control settings: can be modified at run-time */ /* ---------------------------------------------------------------------- */ /* used in UMFPACK_report_* routines: */ Control [UMFPACK_PRL] = UMFPACK_DEFAULT_PRL ; /* used in UMFPACK_*symbolic: */ Control [UMFPACK_DENSE_ROW] = UMFPACK_DEFAULT_DENSE_ROW ; Control [UMFPACK_DENSE_COL] = UMFPACK_DEFAULT_DENSE_COL ; Control [UMFPACK_AMD_DENSE] = UMFPACK_DEFAULT_AMD_DENSE ; Control [UMFPACK_STRATEGY] = UMFPACK_DEFAULT_STRATEGY ; Control [UMFPACK_2BY2_TOLERANCE] = UMFPACK_DEFAULT_2BY2_TOLERANCE ; Control [UMFPACK_AGGRESSIVE] = UMFPACK_DEFAULT_AGGRESSIVE ; /* used in UMFPACK_numeric: */ Control [UMFPACK_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_PIVOT_TOLERANCE ; Control [UMFPACK_SYM_PIVOT_TOLERANCE] = UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE; Control [UMFPACK_BLOCK_SIZE] = UMFPACK_DEFAULT_BLOCK_SIZE ; Control [UMFPACK_ALLOC_INIT] = UMFPACK_DEFAULT_ALLOC_INIT ; Control [UMFPACK_FRONT_ALLOC_INIT] = UMFPACK_DEFAULT_FRONT_ALLOC_INIT ; Control [UMFPACK_SCALE] = UMFPACK_DEFAULT_SCALE ; /* used in UMFPACK_*solve: */ Control [UMFPACK_IRSTEP] = UMFPACK_DEFAULT_IRSTEP ; /* ---------------------------------------------------------------------- */ /* compile-time settings: cannot be modified at run-time */ /* ---------------------------------------------------------------------- */ #ifdef NBLAS /* do not use the BLAS - use in-line C code instead */ Control [UMFPACK_COMPILED_WITH_BLAS] = 0 ; #else /* use externally-provided BLAS (dgemm, dger, dgemv, zgemm, zgeru, zgemv) */ Control [UMFPACK_COMPILED_WITH_BLAS] = 1 ; #endif #ifdef MATLAB_MEX_FILE /* compiled as a MATLAB mexFunction */ Control [UMFPACK_COMPILED_FOR_MATLAB] = 1 ; #else #ifdef MATHWORKS /* compiled for internal use in MATLAB */ Control [UMFPACK_COMPILED_FOR_MATLAB] = 2 ; #else /* use ANSI C malloc, free, realloc, and printf */ Control [UMFPACK_COMPILED_FOR_MATLAB] = 0 ; #endif #endif #ifdef NO_TIMER /* no timer used */ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 3 ; #ifndef NPOSIX /* uses the POSIX sysconf ( ) and times ( ) routines in UMFPACK_tic, toc */ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 2 ; #else #ifdef GETRUSAGE /* uses the non-standard getrusage to get CPU time (Solaris) */ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 1 ; #else /* uses the ANSI standard clock routine to get CPU time */ /* this may wrap around */ Control [UMFPACK_COMPILED_WITH_GETRUSAGE] = 0 ; #endif #endif #endif #ifndef NDEBUG /* UMFPACK is compiled in debug mode. */ /* This is exceedingly slow. */ DEBUG0 (("UMFPACK is running in debug mode. This is very slow!\n")) ; Control [UMFPACK_COMPILED_IN_DEBUG_MODE] = 1 ; #else /* UMFPACK is compiled in normal (non-debug) mode */ Control [UMFPACK_COMPILED_IN_DEBUG_MODE] = 0 ; #endif } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_realloc.c0000644000175000017500000000440511674452555022311 0ustar sonnesonne/* ========================================================================== */ /* === UMF_realloc ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Realloc a block previously allocated by UMF_malloc. Return NULL on failure (in which case the block is still allocated, and will be kept at is present size). This routine is only used for Numeric->Memory. */ #include "umf_internal.h" #include "umf_realloc.h" #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) #include "umf_malloc.h" #endif GLOBAL void *UMF_realloc ( void *p, Int n_objects, size_t size_of_object ) { size_t size ; void *p2 ; #ifdef UMF_TCOV_TEST /* For exhaustive statement coverage testing only! */ /* Pretend to fail, to test out-of-memory conditions. */ umf_realloc_fail-- ; if (umf_realloc_fail <= umf_realloc_hi && umf_realloc_fail >= umf_realloc_lo) { return ((void *) NULL) ; } #endif /* make sure that we allocate something */ n_objects = MAX (1, n_objects) ; size = (size_t) n_objects ; ASSERT (size_of_object > 1) ; if (size > Int_MAX / size_of_object) { /* :: int overflow in umf_realloc :: */ return ((void *) NULL) ; } size *= size_of_object ; DEBUG0 (("UMF_realloc: "ID" n_objects "ID" size_of_object "ID"\n", (Int) p, n_objects, (Int) size_of_object)) ; /* see AMD/Source/amd_global.c for the memory allocator selection */ p2 = amd_realloc (p, size) ; #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) /* If p didn't exist on input, and p2 exists, then a new object has been * allocated. */ if (p == (void *) NULL && p2 != (void *) NULL) { UMF_malloc_count++ ; } #endif DEBUG0 (("UMF_realloc: "ID" new malloc count "ID"\n", (Int) p2, UMF_malloc_count)) ; return (p2) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.h0000644000175000017500000000104011674452555023672 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL double UMF_symbolic_usage ( Int n_row, Int n_col, Int nchains, Int nfr, Int esize, Int prefer_diagonal ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_dump.c0000644000175000017500000007731411674452555021646 0ustar sonnesonne/* ========================================================================== */ /* === UMF_dump ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* These routines, and external variables, are used only when debugging. */ /* If debugging is disabled (for normal operation) then this entire file */ /* becomes empty */ #include "umf_internal.h" #ifndef NDEBUG /* These global debugging variables and arrays do not exist if debugging */ /* is disabled at compile time (which is the default). */ GLOBAL Int UMF_debug = -999 ; GLOBAL Int UMF_allocfail = FALSE ; GLOBAL double UMF_gprob = -1.0 ; /* static debugging arrays used only in UMF_dump_rowcol */ PRIVATE Int UMF_DBflag = 0 ; PRIVATE Int UMF_DBpacked [UMF_DBMAX+1] ; PRIVATE Int UMF_DBscatter [UMF_DBMAX+1] ; /* ========================================================================== */ /* === UMF_DBinit =========================================================== */ /* ========================================================================== */ /* clear the debugging arrays */ PRIVATE void UMF_DBinit ( void ) { Int i ; /* Int_MAX is defined in umfpack.h */ if (UMF_DBflag < 1 || UMF_DBflag == Int_MAX) { /* clear the debugging arrays */ UMF_DBflag = 0 ; for (i = 0 ; i <= UMF_DBMAX ; i++) { UMF_DBscatter [i] = 0 ; UMF_DBpacked [i] = 0 ; } } UMF_DBflag++ ; /* UMF_DBflag > UMF_DBscatter [0...UMF_DBmax] is now true */ } /* ========================================================================== */ /* === UMF_dump_dense ======================================================= */ /* ========================================================================== */ GLOBAL void UMF_dump_dense ( Entry *C, Int dim, Int m, Int n ) { /* dump C [1..m,1..n], with column dimenstion dim */ Int i, j; if (UMF_debug < 7) return ; if (C == (Entry *) NULL) { DEBUG7 (("No dense matrix allocated\n")) ; return ; } DEBUG8 ((" dimension= "ID" rows= "ID" cols= "ID"\n", dim, m, n)) ; for (i = 0 ; i < m ; i++) { DEBUG9 ((ID": ", i)) ; for (j = 0 ; j < n ; j++) { EDEBUG9 (C [i+j*dim]) ; if (j % 6 == 5) DEBUG9 (("\n ")) ; } DEBUG9 (("\n")) ; } for (i = 0 ; i < m ; i++) { for (j = 0 ; j < n ; j++) { if (IS_ZERO (C [i+j*dim])) { DEBUG8 ((".")) ; } else { DEBUG8 (("X")) ; } } DEBUG8 (("\n")) ; } } /* ========================================================================== */ /* === UMF_dump_element ===================================================== */ /* ========================================================================== */ GLOBAL void UMF_dump_element ( NumericType *Numeric, WorkType *Work, Int e, Int clean ) { Int i, j, k, *Rows, *Cols, nrows, ncols, *E, row, col, *Row_degree, *Col_degree ; Entry *C ; Element *ep ; Unit *p ; if (UMF_debug < 7) return ; if (e == 0) { UMF_dump_current_front (Numeric, Work, FALSE) ; return ; } DEBUG7 (("\n====================ELEMENT: "ID" ", e)) ; if (!Numeric || !Work || !Numeric->Memory) { DEBUG7 ((" No Numeric, Work\n")) ; return ; } DEBUG7 ((" nel: "ID" of "ID, e, Work->nel)) ; E = Work->E ; if (!E) { DEBUG7 ((" No elements\n")) ; return ; } if (e < 0 || e > Work->nel) { DEBUG7 (("e out of range!\n")) ; return ; } if (!E [e]) { DEBUG7 ((" deallocated\n")) ; return ; } DEBUG7 (("\n")) ; Col_degree = Numeric->Cperm ; Row_degree = Numeric->Rperm ; p = Numeric->Memory + E [e] ; DEBUG7 (("ep "ID"\n", (Int) (p-Numeric->Memory))) ; GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ; DEBUG7 (("nrows "ID" nrowsleft "ID"\n", nrows, ep->nrowsleft)) ; DEBUG7 (("ncols "ID" ncolsleft "ID"\n", ncols, ep->ncolsleft)) ; DEBUG7 (("cdeg-cdeg0 "ID" rdeg-rdeg0 "ID" next "ID"\n", ep->cdeg - Work->cdeg0, ep->rdeg - Work->rdeg0, ep->next)) ; DEBUG8 (("rows: ")) ; k = 0 ; for (i = 0 ; i < ep->nrows ; i++) { row = Rows [i] ; if (row >= 0) { DEBUG8 ((" "ID, row)) ; ASSERT (row < Work->n_row) ; if ((k++ % 10) == 9) DEBUG8 (("\n")) ; ASSERT (IMPLIES (clean, NON_PIVOTAL_ROW (row))) ; } } DEBUG8 (("\ncols: ")) ; k = 0 ; for (j = 0 ; j < ep->ncols ; j++) { col = Cols [j] ; if (col >= 0) { DEBUG8 ((" "ID, col)) ; ASSERT (col < Work->n_col) ; if ((k++ % 10) == 9) DEBUG8 (("\n")) ; ASSERT (IMPLIES (clean, NON_PIVOTAL_COL (col))) ; } } DEBUG8 (("\nvalues:\n")) ; if (UMF_debug >= 9) { for (i = 0 ; i < ep->nrows ; i++) { row = Rows [i] ; if (row >= 0) { DEBUG9 ((ID": ", row)) ; k = 0 ; for (j = 0 ; j < ep->ncols ; j++) { col = Cols [j] ; if (col >= 0) { EDEBUG9 (C [i+j*ep->nrows]) ; if (k++ % 6 == 5) DEBUG9 (("\n ")) ; } } DEBUG9 (("\n")) ; } } } DEBUG7 (("====================\n")) ; } /* ========================================================================== */ /* === UMF_dump_rowcol ====================================================== */ /* ========================================================================== */ /* dump a row or a column, from one or more memory spaces */ /* return exact degree */ GLOBAL void UMF_dump_rowcol ( Int dumpwhich, /* 0 for row, 1 for column */ NumericType *Numeric, WorkType *Work, Int dumpindex, /* row or column index to dump */ Int check_degree /* true if degree is to be checked */ ) { Entry value ; Entry *C ; Int f, nrows, j, jj, len, e, deg, index, n_row, n_col, *Cols, *Rows, nn, dumpdeg, ncols, preve, *E, tpi, *Pattern, approx_deg, not_in_use ; Tuple *tp, *tend ; Element *ep ; Int *Row_tuples, *Row_degree, *Row_tlen ; Int *Col_tuples, *Col_degree, *Col_tlen ; Unit *p ; Int is_there ; /* clear the debugging arrays */ UMF_DBinit () ; if (dumpwhich == 0) { DEBUG7 (("\n====================ROW: "ID, dumpindex)) ; } else { DEBUG7 (("\n====================COL: "ID, dumpindex)) ; } if (dumpindex == EMPTY) { DEBUG7 ((" (EMPTY)\n")) ; return ; } deg = 0 ; approx_deg = 0 ; if (!Numeric || !Work) { DEBUG7 ((" No Numeric, Work\n")) ; return ; } n_row = Work->n_row ; n_col = Work->n_col ; nn = MAX (n_row, n_col) ; E = Work->E ; Col_degree = Numeric->Cperm ; Row_degree = Numeric->Rperm ; Row_tuples = Numeric->Uip ; Row_tlen = Numeric->Uilen ; Col_tuples = Numeric->Lip ; Col_tlen = Numeric->Lilen ; if (!E || !Row_tuples || !Row_degree || !Row_tlen || !Col_tuples || !Col_degree || !Col_tlen) { DEBUG7 ((" No E, Rows, Cols\n")) ; return ; } if (dumpwhich == 0) { /* dump a row */ ASSERT (dumpindex >= 0 && dumpindex < n_row) ; if (!NON_PIVOTAL_ROW (dumpindex)) { DEBUG7 ((" Pivotal\n")) ; return ; } len = Row_tlen [dumpindex] ; dumpdeg = Row_degree [dumpindex] ; tpi = Row_tuples [dumpindex] ; } else { /* dump a column */ ASSERT (dumpindex >= 0 && dumpindex < n_col) ; if (!NON_PIVOTAL_COL (dumpindex)) { DEBUG7 ((" Pivotal\n")) ; return ; } len = Col_tlen [dumpindex] ; dumpdeg = Col_degree [dumpindex] ; tpi = Col_tuples [dumpindex] ; } p = Numeric->Memory + tpi ; tp = (Tuple *) p ; if (!tpi) { DEBUG7 ((" Nonpivotal, No tuple list tuples "ID" tlen "ID"\n", tpi, len)) ; return ; } ASSERT (p >= Numeric->Memory + Numeric->itail) ; ASSERT (p < Numeric->Memory + Numeric->size) ; DEBUG7 ((" degree: "ID" len: "ID"\n", dumpdeg, len)) ; not_in_use = (p-1)->header.size - UNITS (Tuple, len) ; DEBUG7 ((" Tuple list: p+1: "ID" size: "ID" units, "ID" not in use\n", (Int) (p-Numeric->Memory), (p-1)->header.size, not_in_use)) ; ASSERT (not_in_use >= 0) ; tend = tp + len ; preve = 0 ; for ( ; tp < tend ; tp++) { /* row/col of element e, offset is f: */ /* DEBUG8 ((" (tp="ID")\n", tp)) ; */ e = tp->e ; f = tp->f ; DEBUG8 ((" (e="ID", f="ID")\n", e, f)) ; ASSERT (e > 0 && e <= Work->nel) ; /* dump the pattern and values */ if (E [e]) { p = Numeric->Memory + E [e] ; GET_ELEMENT (ep, p, Cols, Rows, ncols, nrows, C) ; if (dumpwhich == 0) { Pattern = Cols ; jj = ep->ncols ; is_there = Rows [f] >= 0 ; if (is_there) approx_deg += ep->ncolsleft ; } else { Pattern = Rows ; jj = ep->nrows ; is_there = Cols [f] >= 0 ; if (is_there) approx_deg += ep->nrowsleft ; } if (!is_there) { DEBUG8 (("\t\tnot present\n")) ; } else { for (j = 0 ; j < jj ; j++) { index = Pattern [j] ; value = C [ (dumpwhich == 0) ? (f+nrows*j) : (j+nrows*f) ] ; if (index >= 0) { DEBUG8 (("\t\t"ID":", index)) ; EDEBUG8 (value) ; DEBUG8 (("\n")) ; if (dumpwhich == 0) { /* col must be in the range 0..n_col-1 */ ASSERT (index < n_col) ; } else { /* row must be in the range 0..n_row-1 */ ASSERT (index < n_row) ; } if (nn <= UMF_DBMAX) { if (UMF_DBscatter [index] != UMF_DBflag) { UMF_DBpacked [deg++] = index ; UMF_DBscatter [index] = UMF_DBflag ; } } } } } /* the (e,f) tuples should be in order of their creation */ /* this means that garbage collection will not jumble them */ ASSERT (preve < e) ; preve = e ; } else { DEBUG8 (("\t\tdeallocated\n")) ; } } if (nn <= UMF_DBMAX) { if (deg > 0) { DEBUG7 ((" Assembled, actual deg: "ID" : ", deg)) ; for (j = 0 ; j < deg ; j++) { index = UMF_DBpacked [j] ; DEBUG8 ((ID" ", index)) ; if (j % 20 == 19) DEBUG8 (("\n ")) ; ASSERT (UMF_DBscatter [index] == UMF_DBflag) ; } DEBUG7 (("\n")) ; } } /* Col_degree is not maintained when fixQ is true */ if (check_degree) { DEBUG8 ((" approx_deg "ID" dumpdeg "ID"\n", approx_deg, dumpdeg)) ; ASSERT (approx_deg == dumpdeg) ; } DEBUG7 (("====================\n")) ; /* deg is now the exact degree */ /* if nn <= UMF_DBMAX, then UMF_DBscatter [i] == UMF_DBflag for every i */ /* in the row or col, and != UMF_DBflag if not */ return ; } /* ========================================================================== */ /* === UMF_dump_matrix ====================================================== */ /* ========================================================================== */ GLOBAL void UMF_dump_matrix ( NumericType *Numeric, WorkType *Work, Int check_degree ) { Int e, row, col, intfrag, frag, n_row, n_col, *E, fullsize, actualsize ; Element *ep ; Unit *p ; DEBUG6 (("=================================================== MATRIX:\n")) ; if (!Numeric || !Work) { DEBUG6 (("No Numeric or Work allocated\n")) ; return ; } if (!Numeric->Memory) { DEBUG6 (("No Numeric->Memory\n")) ; return ; } n_row = Work->n_row ; n_col = Work->n_col ; DEBUG6 (("n_row "ID" n_col "ID" nz "ID"\n", n_row, n_col, Work->nz)) ; DEBUG6 (("============================ ELEMENTS: "ID" \n", Work->nel)) ; intfrag = 0 ; E = Work->E ; if (!E) { DEBUG6 (("No elements allocated\n")) ; } else { for (e = 0 ; e <= Work->nel ; e++) { UMF_dump_element (Numeric, Work, e, FALSE) ; if (e > 0 && E [e]) { p = Numeric->Memory + E [e] ; ep = (Element *) p ; ASSERT (ep->nrowsleft > 0 || ep->ncolsleft > 0) ; fullsize = GET_BLOCK_SIZE (p) ; actualsize = GET_ELEMENT_SIZE (ep->nrowsleft,ep->ncolsleft); frag = fullsize - actualsize ; intfrag += frag ; DEBUG7 (("dump el: "ID", full "ID" actual "ID" frag: "ID " intfrag: "ID"\n", e, fullsize, actualsize, frag, intfrag)) ; } } } DEBUG6 (("CURRENT INTERNAL FRAG in elements: "ID" \n", intfrag)) ; DEBUG6 (("======================================== ROWS: "ID"\n", n_row)) ; UMF_debug -= 2 ; for (row = 0 ; row < n_row ; row++) { UMF_dump_rowcol (0, Numeric, Work, row, check_degree) ; } UMF_debug += 2 ; DEBUG6 (("======================================== COLS: "ID"\n", n_col)) ; UMF_debug -= 2 ; for (col = 0 ; col < n_col ; col++) { UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; } UMF_debug += 2 ; DEBUG6 (("============================================= END OF MATRIX:\n")); } /* ========================================================================== */ /* === UMF_dump_current_front =============================================== */ /* ========================================================================== */ GLOBAL void UMF_dump_current_front ( NumericType *Numeric, WorkType *Work, Int check ) { Entry *Flublock, *Flblock, *Fublock, *Fcblock ; Int fnrows_max, fncols_max, fnrows, fncols, fnpiv, *Frows, *Fcols, i, j, *Fcpos, *Frpos, fnr_curr, fnc_curr, *E ; if (!Work) return ; DEBUG7 (("\n\n========CURRENT FRONTAL MATRIX:\n")) ; Flublock = Work->Flublock ; Flblock = Work->Flblock ; Fublock = Work->Fublock ; Fcblock = Work->Fcblock ; Frows = Work->Frows ; Fcols = Work->Fcols ; Frpos = Work->Frpos ; Fcpos = Work->Fcpos ; fnrows_max = Work->fnrows_max ; fncols_max = Work->fncols_max ; fnr_curr = Work->fnr_curr ; fnc_curr = Work->fnc_curr ; fnrows = Work->fnrows ; fncols = Work->fncols ; fnpiv = Work->fnpiv ; E = Work->E ; DEBUG6 (("=== fnpiv= "ID"\n", fnpiv)) ; DEBUG6 (("fnrows_max fncols_max "ID" "ID"\n",fnrows_max, fncols_max)) ; DEBUG6 (("fnr_curr fnc_curr "ID" "ID"\n",fnr_curr, fnc_curr)) ; DEBUG6 (("fnrows fncols "ID" "ID"\n",fnrows, fncols)) ; ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ; DEBUG6 (("Pivot row pattern:\n")) ; for (j = 0 ; j < fncols ; j++) { DEBUG7 ((ID" "ID" "ID" %d\n", j, Fcols [j], Fcpos [Fcols [j]], j < fncols)) ; if (check) { ASSERT (Fcols [j] >= 0 && Fcols [j] < Work->n_col) ; ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ; } } DEBUG6 (("Pivot col pattern:\n")) ; for (i = 0 ; i < fnrows ; i++) { DEBUG7 ((ID" "ID" "ID" %d\n", i, Frows [i], Frpos [Frows [i]], i < fnrows)) ; if (check) { ASSERT (Frows [i] >= 0 && Frows [i] < Work->n_row) ; ASSERT (Frpos [Frows [i]] == i) ; } } if (UMF_debug < 7) return ; if (!E [0]) { DEBUG6 (("current front not allocated\n")) ; ASSERT (!Work->Flublock) ; return ; } ASSERT (Work->Flublock == (Entry *) (Numeric->Memory + E [0])) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv) ; DEBUG7 (("U' block: ")) ; UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Flublock, Work->nb, fnpiv, fnpiv) ; if (fnpiv > 0) { DEBUG7 (("Pivot entry: ")) ; EDEBUG7 (Flublock [(fnpiv-1)+(fnpiv-1)*Work->nb]) ; DEBUG7 (("\n")) ; } } /* ========================================================================== */ /* === UMF_dump_lu ========================================================== */ /* ========================================================================== */ GLOBAL void UMF_dump_lu ( NumericType *Numeric ) { Int i, n_row, n_col, *Cperm, *Rperm ; DEBUG6 (("=============================================== LU factors:\n")) ; if (!Numeric) { DEBUG6 (("No LU factors allocated\n")) ; return ; } n_row = Numeric->n_row ; n_col = Numeric->n_col ; DEBUG6 (("n_row: "ID" n_col: "ID"\n", n_row, n_col)) ; DEBUG6 (("nLentries: "ID" nUentries: "ID"\n", Numeric->nLentries, Numeric->nUentries)) ; if (Numeric->Cperm) { Cperm = Numeric->Cperm ; DEBUG7 (("Column permutations: (new: old)\n")) ; for (i = 0 ; i < n_col ; i++) { if (Cperm [i] != EMPTY) { DEBUG7 ((ID": "ID"\n", i, Cperm [i])) ; } } } else { DEBUG7 (("No Numeric->Cperm allocatated\n")) ; } if (Numeric->Rperm) { Rperm = Numeric->Rperm ; DEBUG7 (("row permutations: (new: old)\n")) ; for (i = 0 ; i < n_row ; i++) { if (Rperm [i] != EMPTY) { DEBUG7 ((ID": "ID"\n", i, Rperm [i])) ; } } } else { DEBUG7 (("No Numeric->Rperm allocatated\n")) ; } DEBUG6 (("========================================= END OF LU factors:\n")); } /* ========================================================================== */ /* === UMF_dump_memory ====================================================== */ /* ========================================================================== */ GLOBAL void UMF_dump_memory ( NumericType *Numeric ) { Unit *p ; Int prevsize, s ; Int found ; if (!Numeric) { DEBUG6 (("No memory space S allocated\n")) ; return ; } DEBUG6 (("\n ============================================== MEMORY:\n")) ; if (!Numeric || !Numeric->Memory) { DEBUG6 (("No memory space Numeric allocated\n")) ; return ; } DEBUG6 (("S: "ID"\n", (Int) Numeric)) ; DEBUG6 (("S->ihead : "ID"\n", Numeric->ihead)) ; DEBUG6 (("S->itail : "ID"\n", Numeric->itail)) ; DEBUG6 (("S->size : "ID"\n", Numeric->size)) ; DEBUG6 (("S->ngarbage : "ID"\n", Numeric->ngarbage)) ; DEBUG6 (("S->nrealloc : "ID"\n", Numeric->nrealloc)) ; DEBUG6 ((" in use at head : "ID"\n", Numeric->ihead)) ; DEBUG6 ((" free space : "ID"\n", Numeric->itail - Numeric->ihead)) ; DEBUG6 ((" blocks in use at tail : "ID"\n", Numeric->size - Numeric->itail)) ; DEBUG6 ((" total in use : "ID"\n", Numeric->size - (Numeric->itail - Numeric->ihead))) ; prevsize = 0 ; found = FALSE ; ASSERT (0 <= Numeric->ihead) ; ASSERT (Numeric->ihead <= Numeric->itail) ; ASSERT (Numeric->itail <= Numeric->size) ; p = Numeric->Memory + Numeric->itail ; while (p < Numeric->Memory + Numeric->size) { DEBUG8 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID, (Int) (p-Numeric->Memory), (Int) (p+1-Numeric->Memory), p->header.prevsize, p->header.size)) ; if (p->header.size < 0) { DEBUG8 ((" free")) ; } if (p == Numeric->Memory + Numeric->itail) { ASSERT (p->header.prevsize == 0) ; } else { ASSERT (p->header.prevsize > 0) ; } ASSERT (p->header.size != 0) ; s = prevsize >= 0 ? prevsize : -prevsize ; ASSERT (p->header.prevsize == s) ; /* no adjacent free blocks */ ASSERT (p->header.size > 0 || prevsize > 0) ; if (Numeric->ibig != EMPTY) { if (p == Numeric->Memory + Numeric->ibig) { ASSERT (p->header.size < 0) ; DEBUG8 ((" <===== Numeric->ibig")) ; found = TRUE ; } } s = p->header.size ; prevsize = s ; s = s >= 0 ? s : -s ; p = p + 1 + s ; DEBUG8 (("\n")) ; } ASSERT (p == Numeric->Memory + Numeric->size) ; ASSERT (IMPLIES (Numeric->ibig != EMPTY, found)) ; DEBUG6 (("============================================= END OF MEMORY:\n")); } /* ========================================================================== */ /* === UMF_dump_packed_memory =============================================== */ /* ========================================================================== */ GLOBAL void UMF_dump_packed_memory ( NumericType *Numeric, WorkType *Work ) { Unit *p, *p3 ; Int prevsize, col, row, *Rows, *Cols, ncols, nrows, k, esize, *Row_tuples, *Row_degree, *Col_tuples, *Col_degree ; Entry *C ; Element *ep ; Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */ Row_tuples = Numeric->Uip ; Col_tuples = Numeric->Lip ; DEBUG6 (("============================================ PACKED MEMORY:\n")) ; if (!Numeric || !Numeric->Memory) { DEBUG6 (("No memory space S allocated\n")) ; return ; } DEBUG6 (("S: "ID"\n", (Int) Numeric)) ; DEBUG6 (("S->ihead : "ID"\n", Numeric->ihead)) ; DEBUG6 (("S->itail : "ID"\n", Numeric->itail)) ; DEBUG6 (("S->size : "ID"\n", Numeric->size)) ; DEBUG6 (("S->ngarbage : "ID"\n", Numeric->ngarbage)) ; DEBUG6 (("S->nrealloc : "ID"\n", Numeric->nrealloc)) ; DEBUG6 ((" in use at head : "ID"\n", Numeric->ihead)) ; DEBUG6 ((" free space : "ID"\n", Numeric->itail - Numeric->ihead)) ; DEBUG6 ((" blocks in use at tail : "ID"\n", Numeric->size - Numeric->itail)) ; DEBUG6 ((" total in use : "ID"\n", Numeric->size - (Numeric->itail - Numeric->ihead))) ; ASSERT (0 <= Numeric->ihead) ; ASSERT (Numeric->ihead <= Numeric->itail) ; ASSERT (Numeric->itail <= Numeric->size) ; for (row = 0 ; row < Work->n_row ; row++) { ASSERT (IMPLIES (NON_PIVOTAL_ROW (row), !Row_tuples [row])) ; } for (col = 0 ; col < Work->n_col ; col++) { ASSERT (IMPLIES (NON_PIVOTAL_COL (col), !Col_tuples [col])) ; } prevsize = 0 ; p = Numeric->Memory + Numeric->itail ; while (p < Numeric->Memory + Numeric->size) { DEBUG9 (("====================\n")) ; DEBUG7 (("p: "ID" p+1: "ID" prevsize: "ID" size: "ID"\n", (Int) (p-Numeric->Memory), (Int) (p+1-Numeric->Memory), p->header.prevsize, p->header.size)) ; ASSERT (p->header.size > 0) ; if (p == Numeric->Memory + Numeric->itail) { ASSERT (p->header.prevsize == 0) ; } else { ASSERT (p->header.prevsize > 0) ; } ASSERT (p->header.prevsize == prevsize) ; prevsize = p->header.size ; if (p != Numeric->Memory + Numeric->size - 2) { p3 = p + 1 ; if (p3 == Numeric->Memory + Work->E [0]) { /* this is the current frontal matrix */ UMF_dump_current_front (Numeric, Work, FALSE) ; } else { /* this is a packed element */ GET_ELEMENT (ep, p3, Cols, Rows, ncols, nrows, C) ; DEBUG9 (("ep "ID"\n nrows "ID" ncols "ID"\n", (Int) ((p+1)-Numeric->Memory), ep->nrows, ep->ncols)) ; DEBUG9 (("rows:")) ; for (k = 0 ; k < ep->nrows; k++) { row = Rows [k] ; DEBUG9 ((" "ID, row)) ; ASSERT (row >= 0 && row <= Work->n_row) ; if ((k % 10) == 9) DEBUG9 (("\n")) ; } DEBUG9 (("\ncols:")) ; for (k = 0 ; k < ep->ncols; k++) { col = Cols [k] ; DEBUG9 ((" "ID, col)) ; ASSERT (col >= 0 && col <= Work->n_col) ; if ((k % 10) == 9) DEBUG9 (("\n")) ; } DEBUG9 (("\nvalues: ")) ; if (UMF_debug >= 9) { UMF_dump_dense (C, ep->nrows, ep->nrows, ep->ncols) ; } esize = GET_ELEMENT_SIZE (ep->nrows, ep->ncols) ; DEBUG9 (("esize: "ID"\n", esize)) ; ASSERT (esize <= p->header.size) ; } } else { /* this is the final marker block */ ASSERT (p->header.size == 1) ; } p = p + 1 + p->header.size ; } ASSERT (Numeric->ibig == EMPTY) ; ASSERT (p == Numeric->Memory + Numeric->size) ; DEBUG6 (("======================================END OF PACKED MEMORY:\n")) ; } /* ========================================================================== */ /* === UMF_dump_col_matrix ================================================== */ /* ========================================================================== */ /* This code is the same for real or complex matrices. */ GLOBAL void UMF_dump_col_matrix ( const double Ax [ ], /* Ax [0..nz-1]: real values, in column order */ #ifdef COMPLEX const double Az [ ], /* Az [0..nz-1]: imag values, in column order */ #endif const Int Ai [ ], /* Ai [0..nz-1]: row indices, in column order */ const Int Ap [ ], /* Ap [0..n_col]: column pointers */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Int nz /* number of entries */ ) { Int col, p, p1, p2, row ; #ifdef COMPLEX Int split = SPLIT (Az) ; #endif if (!Ai || !Ap) return ; DEBUG6 (("============================================ COLUMN FORM:\n")) ; ASSERT (n_col >= 0) ; nz = Ap [n_col] ; DEBUG2 (("UMF_dump_col: nz "ID"\n", nz)) ; DEBUG2 (("n_row "ID" \n", n_row)) ; DEBUG2 (("n_col "ID" \n", n_col)) ; DEBUG6 ((" n_row = "ID", n_col ="ID" nz = "ID" Ap [0] "ID", Ap [n] "ID"\n", n_row, n_col, nz, Ap [0], Ap [n_col])) ; ASSERT (Ap [0] == 0) ; ASSERT (Ap [n_col] == nz) ; for (col = 0 ; col < n_col ; col++) { p1 = Ap [col] ; p2 = Ap [col+1] ; DEBUG6 (("col: "ID", length "ID"\n", col, p2 - p1)) ; ASSERT (p2 >= p1) ; for (p = p1 ; p < p2 ; p++) { row = Ai [p] ; ASSERT (row >= 0 && row < n_row) ; DEBUG6 (("\t"ID" ", row)) ; if (Ax != (double *) NULL) { #ifdef COMPLEX if (split) { DEBUG6 ((" (%e+%ei) ", Ax [p], Az [p])) ; } else { DEBUG6 ((" (%e+%ei) ", Ax [2*p], Ax [2*p+1])) ; } #else DEBUG6 ((" %e", Ax [p])) ; #endif } DEBUG6 (("\n")) ; } } DEBUG6 (("========================================== COLUMN FORM done\n")) ; } /* ========================================================================== */ /* === UMF_dump_chain ======================================================= */ /* ========================================================================== */ GLOBAL void UMF_dump_chain ( Int frontid, Int Front_parent [ ], Int Front_npivcol [ ], Int Front_nrows [ ], Int Front_ncols [ ], Int nfr ) { Int i, len = 0 ; /* print a list of contiguous parents */ i = frontid ; ASSERT (Front_parent [i] == EMPTY || (Front_parent [i] > i && Front_parent [i] < nfr)) ; len++ ; DEBUG3 (("Chain:\n "ID" ["ID","ID"]("ID"-by-"ID")\n", i, Front_npivcol [i], MIN (Front_npivcol [i], Front_nrows [i]), Front_nrows [i], Front_ncols [i])) ; for (i = frontid ; i < nfr ; i++) { ASSERT (Front_parent [i] == EMPTY || (Front_parent [i] > i && Front_parent [i] < nfr)) ; if (Front_parent [i] == i+1) { len++ ; DEBUG3 (("\t"ID" ["ID","ID"]("ID"-by-"ID")\n", i+1, Front_npivcol [i+1], MIN (Front_npivcol [i+1], Front_nrows [i+1]), Front_nrows [i+1], Front_ncols [i+1])) ; } else { DEBUG2 (("Length of chain: "ID"\n", len)) ; return ; } } } /* ========================================================================== */ /* === UMF_dump_start ======================================================= */ /* ========================================================================== */ GLOBAL void UMF_dump_start ( void ) { FILE *ff ; AMD_debug_init ("from umfpack") ; /* get the debug print level from the "debug.umf" file, if it exists */ UMF_debug = -999 ; ff = fopen ("debug.umf", "r") ; if (ff) { (void) fscanf (ff, ID, &UMF_debug) ; (void) fclose (ff) ; } DEBUG0 (("umfpack: debug version (SLOW!) ")) ; DEBUG0 ((" MATLAB: ")) ; #ifdef MATLAB_MEX_FILE DEBUG0 (("mexFunction.\n")) ; #else #ifdef MATHWORKS DEBUG0 (("yes.\n")) ; #else DEBUG0 (("no.\n")) ; #endif #endif UMF_gprob = -1.0 ; ff = fopen ("gprob.umf", "r") ; if (ff) { (void) fscanf (ff, "%lg", &UMF_gprob) ; (void) fclose (ff) ; srand (1) ; /* restart the random number generator */ } if (UMF_gprob > 1.0) UMF_gprob = 1.0 ; DEBUG1 (("factor: UMF_gprob: %e UMF_debug "ID"\n", UMF_gprob, UMF_debug)) ; DEBUG2 (("sizeof: (bytes / int / Units) \n")) ; DEBUG2 (("sizeof (Int) %u %u %u\n", sizeof (Int), sizeof (Int) / sizeof (int), UNITS (Int, 1) )) ; DEBUG2 (("sizeof (int) %u %u %u\n", sizeof (int), sizeof (int) / sizeof (int), UNITS (int, 1) )) ; DEBUG2 (("sizeof (size_t) %u %u %u\n", sizeof (size_t), sizeof (size_t) / sizeof (size_t), UNITS (size_t, 1) )) ; DEBUG2 (("sizeof (UF_long) %u %u %u\n", sizeof (UF_long), sizeof (UF_long) / sizeof (UF_long), UNITS (UF_long, 1))); DEBUG2 (("sizeof (double) %u %u %u\n", sizeof (double), sizeof (double) / sizeof (int), UNITS (double, 1) )) ; DEBUG2 (("sizeof (Unit) %u %u %u\n", sizeof (Unit), sizeof (Unit) / sizeof (int), UNITS (Unit, 1) )) ; DEBUG2 (("sizeof (Entry) %u %u %u\n", sizeof (Entry), sizeof (Entry) / sizeof (int), UNITS (Entry, 1) )) ; DEBUG2 (("sizeof (Tuple) %u %u %u\n", sizeof (Tuple), sizeof (Tuple) / sizeof (int), UNITS (Tuple, 1) )) ; DEBUG2 (("sizeof (Tuple *) %u %u %u\n", sizeof (Tuple *), sizeof (Tuple *) / sizeof (int), UNITS (Tuple *, 1) )) ; DEBUG2 (("sizeof (Element) %u %u %u\n", sizeof (Element), sizeof (Element) / sizeof (int), UNITS (Element, 1) )) ; DEBUG2 (("sizeof (Element *) %u %u %u\n", sizeof (Element *), sizeof (Element *) / sizeof (int), UNITS (Element *, 1) )) ; DEBUG2 (("sizeof (WorkType) %u %u %u\n", sizeof (WorkType), sizeof (WorkType) / sizeof (int), UNITS (WorkType, 1) )) ; DEBUG2 (("sizeof (NumericType) %u %u %u\n", sizeof (NumericType), sizeof (NumericType) / sizeof (int), UNITS (NumericType, 1) )) ; DEBUG2 (("sizeof (SymbolicType) %u %u %u\n", sizeof (SymbolicType), sizeof (SymbolicType) / sizeof (int), UNITS (SymbolicType, 1) )) ; } /* ========================================================================== */ /* === UMF_dump_rowmerge ==================================================== */ /* ========================================================================== */ GLOBAL void UMF_dump_rowmerge ( NumericType *Numeric, SymbolicType *Symbolic, WorkType *Work ) { Int *Front_leftmostdesc, *Front_1strow, *Front_new1strow, row1, row2, fleftmost, nfr, n_row, *Row_degree, i, frontid, row ; nfr = Symbolic->nfr ; DEBUG3 (("\n================== Row merge sets: nfr "ID"\n", nfr)) ; Front_leftmostdesc = Symbolic->Front_leftmostdesc ; Front_1strow = Symbolic->Front_1strow ; Front_new1strow = Work->Front_new1strow ; n_row = Symbolic->n_row ; Row_degree = Numeric->Rperm ; frontid = Work->frontid ; for (i = frontid ; i <= nfr ; i++) { DEBUG3 (("----------------------\n")) ; if (i == nfr) DEBUG3 (("Dummy: ")) ; DEBUG3 (("Front "ID" 1strow "ID" new1strow "ID" leftmostdesc "ID, i, Front_1strow [i], Front_new1strow [i], Front_leftmostdesc [i])) ; DEBUG3 ((" parent "ID" pivcol "ID"\n", Symbolic->Front_parent [i], Symbolic->Front_npivcol [i])) ; if (i == nfr) { fleftmost = -1 ; row1 = Front_new1strow [i] ; row2 = n_row-1 ; } else { fleftmost = Front_leftmostdesc [i] ; row1 = Front_new1strow [fleftmost] ; row2 = Front_1strow [i+1] - 1 ; } DEBUG3 (("Leftmost: "ID" Rows ["ID" to "ID"], search ["ID" to "ID"]\n", fleftmost, Front_1strow [i], row2, row1, row2)) ; for (row = row1 ; row <= row2 ; row++) { ASSERT (row >= 0 && row < n_row) ; DEBUG3 ((" Row "ID" live: %d\n", row, NON_PIVOTAL_ROW (row))) ; } } } /* ========================================================================== */ /* === UMF_dump_diagonal_map ================================================ */ /* ========================================================================== */ GLOBAL void UMF_dump_diagonal_map ( Int Diagonal_map [ ], Int Diagonal_imap [ ], Int nn ) { Int row, col ; if (Diagonal_map != (Int *) NULL) { DEBUG2 (("\nDump the Diagonal_map: nn "ID"\n", nn)) ; for (col = 0 ; col < nn ; col++) { row = Diagonal_map [col] ; DEBUG2 ((" Diagonal_map [col = "ID"] gives "ID": ", col, row)) ; row = UNFLIP (row) ; DEBUG2 ((" row "ID"\n", row)) ; ASSERT (Diagonal_imap [row] == col) ; } } } #endif /* NDEBUG */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.c0000644000175000017500000001103611674452555024630 0ustar sonnesonne/* ========================================================================== */ /* === UMF_mem_free_tail_block ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ /* free a block from the tail of Numeric->memory */ #include "umf_internal.h" #include "umf_mem_free_tail_block.h" GLOBAL void UMF_mem_free_tail_block ( NumericType *Numeric, Int i ) { Unit *pprev, *pnext, *p, *pbig ; Int sprev ; ASSERT (Numeric != (NumericType *) NULL) ; ASSERT (Numeric->Memory != (Unit *) NULL) ; if (i == EMPTY || i == 0) return ; /* already deallocated */ /* ---------------------------------------------------------------------- */ /* get the block */ /* ---------------------------------------------------------------------- */ p = Numeric->Memory + i ; p-- ; /* get the corresponding header */ DEBUG2 (("free block: p: "ID, (Int) (p-Numeric->Memory))) ; ASSERT (p >= Numeric->Memory + Numeric->itail) ; ASSERT (p < Numeric->Memory + Numeric->size) ; ASSERT (p->header.size > 0) ; /* block not already free */ ASSERT (p->header.prevsize >= 0) ; Numeric->tail_usage -= p->header.size + 1 ; /* ---------------------------------------------------------------------- */ /* merge with next free block, if any */ /* ---------------------------------------------------------------------- */ pnext = p + 1 + p->header.size ; DEBUG2 (("size: "ID" next: "ID" ", p->header.size, (Int) (pnext-Numeric->Memory))) ; ASSERT (pnext < Numeric->Memory + Numeric->size) ; ASSERT (pnext->header.prevsize == p->header.size) ; ASSERT (pnext->header.size != 0) ; if (pnext->header.size < 0) { /* next block is also free - merge with current block */ p->header.size += (-(pnext->header.size)) + 1 ; DEBUG2 ((" NEXT FREE ")) ; } /* ---------------------------------------------------------------------- */ /* merge with previous free block, if any */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG if (p == Numeric->Memory + Numeric->itail) { DEBUG2 ((" at top of tail ")) ; ASSERT (p->header.prevsize == 0) ; } #endif if (p > Numeric->Memory + Numeric->itail) { ASSERT (p->header.prevsize > 0) ; pprev = p - 1 - p->header.prevsize ; DEBUG2 ((" prev: "ID" ", (Int) (pprev-Numeric->Memory))) ; ASSERT (pprev >= Numeric->Memory + Numeric->itail) ; sprev = pprev->header.size ; if (sprev < 0) { /* previous block is also free - merge it with current block */ ASSERT (p->header.prevsize == -sprev) ; pprev->header.size = p->header.size + (-sprev) + 1 ; p = pprev ; DEBUG2 ((" PREV FREE ")) ; /* note that p may now point to Numeric->itail */ } #ifndef NDEBUG else { ASSERT (p->header.prevsize == sprev) ; } #endif } /* ---------------------------------------------------------------------- */ /* free the block, p */ /* ---------------------------------------------------------------------- */ pnext = p + 1 + p->header.size ; ASSERT (pnext < Numeric->Memory + Numeric->size) ; if (p == Numeric->Memory + Numeric->itail) { /* top block in list is freed */ Numeric->itail = pnext - Numeric->Memory ; pnext->header.prevsize = 0 ; DEBUG2 ((" NEW TAIL : "ID" ", Numeric->itail)) ; ASSERT (pnext->header.size > 0) ; if (Numeric->ibig != EMPTY && Numeric->ibig <= Numeric->itail) { /* the big free block is now above the tail */ Numeric->ibig = EMPTY ; } } else { /* keep track of the biggest free block seen */ if (Numeric->ibig == EMPTY) { Numeric->ibig = p - Numeric->Memory ; } else { pbig = Numeric->Memory + Numeric->ibig ; if (-(pbig->header.size) < p->header.size) { Numeric->ibig = p - Numeric->Memory ; } } /* flag the block as free, somewhere in the middle of the tail */ pnext->header.prevsize = p->header.size ; p->header.size = -(p->header.size) ; } DEBUG2 (("new p: "ID" freesize: "ID"\n", (Int) (p-Numeric->Memory), -(p->header.size))) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.h0000644000175000017500000000130111674452555022330 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_analyze ( Int n_row, Int n_col, Int Ai [ ], Int Ap [ ], Int Up [ ], Int fixQ, Int Front_ncols [ ], Int W [ ], Int Link [ ], Int Front_nrows [ ], Int Front_npivcol [ ], Int Front_parent [ ], Int *nfr_out, Int *p_ncompactions ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_transpose.c0000644000175000017500000000705411674452555023550 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_transpose ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User callable. Computes a permuted transpose, R = (A (P,Q))' in MATLAB notation. See umfpack_transpose.h for details. A and R can be rectangular. The matrix A may be singular. The complex version can do transpose (') or array transpose (.'). Dynamic memory usage: A single call to UMF_malloc is made, for a workspace of size max (n_row,n_col,1) * sizeof(Int). This is then free'd on return, via UMF_free. */ #include "umf_internal.h" #include "umf_transpose.h" #include "umf_malloc.h" #include "umf_free.h" #ifndef NDEBUG PRIVATE Int init_count ; #endif /* ========================================================================== */ GLOBAL Int UMFPACK_transpose ( Int n_row, Int n_col, const Int Ap [ ], /* size n_col+1 */ const Int Ai [ ], /* size nz = Ap [n_col] */ const double Ax [ ], /* size nz, if present */ #ifdef COMPLEX const double Az [ ], /* size nz, if present */ #endif const Int P [ ], /* P [k] = i means original row i is kth row in A(P,Q)*/ /* P is identity if not present */ /* size n_row, if present */ const Int Q [ ], /* Q [k] = j means original col j is kth col in A(P,Q)*/ /* Q is identity if not present */ /* size n_col, if present */ Int Rp [ ], /* size n_row+1 */ Int Ri [ ], /* size nz */ double Rx [ ] /* size nz, if present */ #ifdef COMPLEX , double Rz [ ] /* size nz, if present */ , Int do_conjugate /* if true, then to conjugate transpose */ /* otherwise, do array transpose */ #endif ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int status, *W, nn ; #ifndef NDEBUG init_count = UMF_malloc_count ; UMF_dump_start ( ) ; #endif /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nn = MAX (n_row, n_col) ; nn = MAX (nn, 1) ; W = (Int *) UMF_malloc (nn, sizeof (Int)) ; if (!W) { DEBUGm4 (("out of memory: transpose work\n")) ; ASSERT (UMF_malloc_count == init_count) ; return (UMFPACK_ERROR_out_of_memory) ; } ASSERT (UMF_malloc_count == init_count + 1) ; /* ---------------------------------------------------------------------- */ /* C = (A (P,Q))' or (A (P,Q)).' */ /* ---------------------------------------------------------------------- */ status = UMF_transpose (n_row, n_col, Ap, Ai, Ax, P, Q, n_col, Rp, Ri, Rx, W, TRUE #ifdef COMPLEX , Az, Rz, do_conjugate #endif ) ; /* ---------------------------------------------------------------------- */ /* free the workspace */ /* ---------------------------------------------------------------------- */ (void) UMF_free ((void *) W) ; ASSERT (UMF_malloc_count == init_count) ; return (status) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_tictoc.c0000644000175000017500000000644611674452555023023 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_tictoc ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Returns the time in seconds used by the process, and the current wall clock time. BE CAREFUL: if you compare the run time of UMFPACK with other sparse matrix packages, be sure to use the same timer. See umfpack_tictoc.h for details. These routines conform to the POSIX standard. See umf_config.h for more details. */ #include "umf_internal.h" #ifdef NO_TIMER /* -------------------------------------------------------------------------- */ /* no timer used if -DNO_TIMER is defined at compile time */ /* -------------------------------------------------------------------------- */ void umfpack_tic (double stats [2]) { stats [0] = 0 ; stats [1] = 0 ; } void umfpack_toc (double stats [2]) { stats [0] = 0 ; stats [1] = 0 ; } #else /* -------------------------------------------------------------------------- */ /* timer routines, using either times() or clock() */ /* -------------------------------------------------------------------------- */ #ifdef LIBRT /* Linux/Unix, must compile with -lrt */ #include void umfpack_tic (double stats [2]) { /* get the current real time and return as a double */ stats [0] = umfpack_timer ( ) ; stats [1] = stats [0] ; } #else #define TINY_TIME 1e-4 #ifndef NPOSIX #include #include void umfpack_tic (double stats [2]) { /* Return the current time */ /* stats [0]: current wallclock time, in seconds */ /* stats [1]: user + system time for the process, in seconds */ double ticks ; struct tms t ; ticks = (double) sysconf (_SC_CLK_TCK) ; stats [0] = (double) times (&t) / ticks ; stats [1] = (double) (t.tms_utime + t.tms_stime) / ticks ; /* if time is tiny, just return zero */ if (stats [0] < TINY_TIME) stats [0] = 0 ; if (stats [1] < TINY_TIME) stats [1] = 0 ; } #else /* Generic ANSI C: use the ANSI clock function. No wallclock time. */ #include void umfpack_tic (double stats [2]) { stats [0] = 0 ; stats [1] = ((double) (clock ( ))) / ((double) (CLOCKS_PER_SEC)) ; if (stats [1] < TINY_TIME) stats [1] = 0 ; } #endif #endif /* -------------------------------------------------------------------------- */ void umfpack_toc (double stats [2]) { /* Return the current time since the last call to umfpack_tic. */ /* On input, stats holds the values returned by umfpack_tic. */ /* On ouput, stats holds the time since the last umfpack_tic. */ double done [2] ; umfpack_tic (done) ; stats [0] = done [0] - stats [0] ; stats [1] = done [1] - stats [1] ; if (stats [0] < 0) stats [0] = 0 ; if (stats [1] < 0) stats [1] = 0 ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_utsolve.c0000644000175000017500000002213611674452555022372 0ustar sonnesonne/* ========================================================================== */ /* === UMF_utsolve ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* solves U'x = b or U.'x=b, where U is the upper triangular factor of a */ /* matrix. B is overwritten with the solution X. */ /* Returns the floating point operation count */ #include "umf_internal.h" #include "umf_utsolve.h" GLOBAL double #ifdef CONJUGATE_SOLVE UMF_uhsolve /* solve U'x=b (complex conjugate transpose) */ #else UMF_utsolve /* solve U.'x=b (array transpose) */ #endif ( NumericType *Numeric, Entry X [ ], /* b on input, solution x on output */ Int Pattern [ ] /* a work array of size n */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry xk ; Entry *xp, *D, *Uval ; Int k, deg, j, *ip, col, *Upos, *Uilen, kstart, kend, up, *Uip, n, uhead, ulen, pos, npiv, n1, *Ui ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ if (Numeric->n_row != Numeric->n_col) return (0.) ; n = Numeric->n_row ; npiv = Numeric->npiv ; Upos = Numeric->Upos ; Uilen = Numeric->Uilen ; Uip = Numeric->Uip ; D = Numeric->D ; kend = 0 ; n1 = Numeric->n1 ; #ifndef NDEBUG DEBUG4 (("Utsolve start: npiv "ID" n "ID"\n", npiv, n)) ; for (j = 0 ; j < n ; j++) { DEBUG4 (("Utsolve start "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } #endif /* ---------------------------------------------------------------------- */ /* singletons */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n1 ; k++) { DEBUG4 (("Singleton k "ID"\n", k)) ; #ifndef NO_DIVIDE_BY_ZERO /* Go ahead and divide by zero if D [k] is zero. */ #ifdef CONJUGATE_SOLVE /* xk = X [k] / conjugate (D [k]) ; */ DIV_CONJ (xk, X [k], D [k]) ; #else /* xk = X [k] / D [k] ; */ DIV (xk, X [k], D [k]) ; #endif #else /* Do not divide by zero */ if (IS_NONZERO (D [k])) { #ifdef CONJUGATE_SOLVE /* xk = X [k] / conjugate (D [k]) ; */ DIV_CONJ (xk, X [k], D [k]) ; #else /* xk = X [k] / D [k] ; */ DIV (xk, X [k], D [k]) ; #endif } #endif X [k] = xk ; deg = Uilen [k] ; if (deg > 0 && IS_NONZERO (xk)) { up = Uip [k] ; Ui = (Int *) (Numeric->Memory + up) ; up += UNITS (Int, deg) ; Uval = (Entry *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" k "ID" col "ID" value", k, Ui [j])) ; EDEBUG4 (Uval [j]) ; DEBUG4 (("\n")) ; #ifdef CONJUGATE_SOLVE /* X [Ui [j]] -= xk * conjugate (Uval [j]) ; */ MULT_SUB_CONJ (X [Ui [j]], xk, Uval [j]) ; #else /* X [Ui [j]] -= xk * Uval [j] ; */ MULT_SUB (X [Ui [j]], xk, Uval [j]) ; #endif } } } /* ---------------------------------------------------------------------- */ /* nonsingletons */ /* ---------------------------------------------------------------------- */ for (kstart = n1 ; kstart < npiv ; kstart = kend + 1) { /* ------------------------------------------------------------------ */ /* find the end of this Uchain */ /* ------------------------------------------------------------------ */ DEBUG4 (("kstart "ID" kend "ID"\n", kstart, kend)) ; /* for (kend = kstart ; kend < npiv && Uip [kend+1] > 0 ; kend++) ; */ kend = kstart ; while (kend < npiv && Uip [kend+1] > 0) { kend++ ; } /* ------------------------------------------------------------------ */ /* scan the whole Uchain to find the pattern of the first row of U */ /* ------------------------------------------------------------------ */ k = kend+1 ; DEBUG4 (("\nKend "ID" K "ID"\n", kend, k)) ; /* ------------------------------------------------------------------ */ /* start with last row in Uchain of U in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ if (k == npiv) { deg = Numeric->ulen ; if (deg > 0) { /* :: make last pivot row of U (singular matrices only) :: */ for (j = 0 ; j < deg ; j++) { Pattern [j] = Numeric->Upattern [j] ; } } } else { ASSERT (k >= 0 && k < npiv) ; up = -Uip [k] ; ASSERT (up > 0) ; deg = Uilen [k] ; DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ; ip = (Int *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = *ip++ ; DEBUG4 ((" k "ID" col "ID"\n", k-1, col)) ; ASSERT (k <= col) ; Pattern [j] = col ; } } /* empty the stack at the bottom of Pattern */ uhead = n ; for (k = kend ; k > kstart ; k--) { /* Pattern [0..deg-1] is the pattern of row k of U */ /* -------------------------------------------------------------- */ /* make row k-1 of U in Pattern [0..deg-1] */ /* -------------------------------------------------------------- */ ASSERT (k >= 0 && k < npiv) ; ulen = Uilen [k] ; /* delete, and push on the stack */ for (j = 0 ; j < ulen ; j++) { ASSERT (uhead >= deg) ; Pattern [--uhead] = Pattern [--deg] ; } DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k, deg)) ; ASSERT (deg >= 0) ; pos = Upos [k] ; if (pos != EMPTY) { /* add the pivot column */ DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ; ASSERT (pos >= 0 && pos <= deg) ; Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } } /* Pattern [0..deg-1] is now the pattern of the first row in Uchain */ /* ------------------------------------------------------------------ */ /* solve using this Uchain, in reverse order */ /* ------------------------------------------------------------------ */ DEBUG4 (("Unwinding Uchain\n")) ; for (k = kstart ; k <= kend ; k++) { /* -------------------------------------------------------------- */ /* construct row k */ /* -------------------------------------------------------------- */ ASSERT (k >= 0 && k < npiv) ; pos = Upos [k] ; if (pos != EMPTY) { /* remove the pivot column */ DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ; ASSERT (k > kstart) ; ASSERT (pos >= 0 && pos < deg) ; ASSERT (Pattern [pos] == k) ; Pattern [pos] = Pattern [--deg] ; } up = Uip [k] ; ulen = Uilen [k] ; if (k > kstart) { /* concatenate the deleted pattern; pop from the stack */ for (j = 0 ; j < ulen ; j++) { ASSERT (deg <= uhead && uhead < n) ; Pattern [deg++] = Pattern [uhead++] ; } DEBUG4 (("middle of chain, row of U "ID" deg "ID"\n", k, deg)) ; ASSERT (deg >= 0) ; } /* -------------------------------------------------------------- */ /* use row k of U */ /* -------------------------------------------------------------- */ #ifndef NO_DIVIDE_BY_ZERO /* Go ahead and divide by zero if D [k] is zero. */ #ifdef CONJUGATE_SOLVE /* xk = X [k] / conjugate (D [k]) ; */ DIV_CONJ (xk, X [k], D [k]) ; #else /* xk = X [k] / D [k] ; */ DIV (xk, X [k], D [k]) ; #endif #else /* Do not divide by zero */ if (IS_NONZERO (D [k])) { #ifdef CONJUGATE_SOLVE /* xk = X [k] / conjugate (D [k]) ; */ DIV_CONJ (xk, X [k], D [k]) ; #else /* xk = X [k] / D [k] ; */ DIV (xk, X [k], D [k]) ; #endif } #endif X [k] = xk ; if (IS_NONZERO (xk)) { if (k == kstart) { up = -up ; xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ; } else { xp = (Entry *) (Numeric->Memory + up) ; } for (j = 0 ; j < deg ; j++) { DEBUG4 ((" k "ID" col "ID" value", k, Pattern [j])) ; EDEBUG4 (*xp) ; DEBUG4 (("\n")) ; #ifdef CONJUGATE_SOLVE /* X [Pattern [j]] -= xk * conjugate (*xp) ; */ MULT_SUB_CONJ (X [Pattern [j]], xk, *xp) ; #else /* X [Pattern [j]] -= xk * (*xp) ; */ MULT_SUB (X [Pattern [j]], xk, *xp) ; #endif xp++ ; } } } ASSERT (uhead == n) ; } #ifndef NO_DIVIDE_BY_ZERO for (k = npiv ; k < n ; k++) { /* This is an *** intentional *** divide-by-zero, to get Inf or Nan, * as appropriate. It is not a bug. */ ASSERT (IS_ZERO (D [k])) ; /* For conjugate solve, D [k] == conjugate (D [k]), in this case */ /* xk = X [k] / D [k] ; */ DIV (xk, X [k], D [k]) ; X [k] = xk ; } #endif #ifndef NDEBUG for (j = 0 ; j < n ; j++) { DEBUG4 (("Utsolve done "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } DEBUG4 (("Utsolve done.\n")) ; #endif return (DIV_FLOPS * ((double) n) + MULTSUB_FLOPS * ((double) Numeric->unz)); } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.c0000644000175000017500000000432611674452555022012 0ustar sonnesonne/* ========================================================================== */ /* === UMF_fsize ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Determine the largest frontal matrix size for each subtree. Called by * UMF_colamd and UMF_analyze. Only required to sort the children of each * node prior to AMD_postorder. */ #include "umf_internal.h" #include "umf_fsize.h" GLOBAL void UMF_fsize ( Int nn, Int Fsize [ ], Int Fnrows [ ], Int Fncols [ ], Int Parent [ ], Int Npiv [ ] ) { Int j, parent, frsize, r, c ; for (j = 0 ; j < nn ; j++) { Fsize [j] = EMPTY ; } /* ---------------------------------------------------------------------- */ /* find max front size for tree rooted at node j, for each front j */ /* ---------------------------------------------------------------------- */ DEBUG1 (("\n\n========================================FRONTS:\n")) ; for (j = 0 ; j < nn ; j++) { if (Npiv [j] > 0) { /* this is a frontal matrix */ parent = Parent [j] ; r = Fnrows [j] ; c = Fncols [j] ; frsize = r * c ; /* avoid integer overflow */ if (INT_OVERFLOW (((double) r) * ((double) c))) { /* :: frsize int overflow :: */ frsize = Int_MAX ; } DEBUG1 ((""ID" : npiv "ID" size "ID" parent "ID" ", j, Npiv [j], frsize, parent)) ; Fsize [j] = MAX (Fsize [j], frsize) ; DEBUG1 (("Fsize [j = "ID"] = "ID"\n", j, Fsize [j])) ; if (parent != EMPTY) { /* find the maximum frontsize of self and children */ ASSERT (Npiv [parent] > 0) ; ASSERT (parent > j) ; Fsize [parent] = MAX (Fsize [parent], Fsize [j]) ; DEBUG1 (("Fsize [parent = "ID"] = "ID"\n", parent, Fsize [parent])); } } } } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_local_search.c0000644000175000017500000016305011674452555023311 0ustar sonnesonne/* ========================================================================== */ /* === UMF_local_search ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Perform pivot search to find pivot row and pivot column. The pivot column is selected from the candidate set. The candidate set corresponds to a supercolumn from colamd or UMF_analyze. The pivot column is then removed from that set. Constructs the pivot column pattern and values. Called by umf_kernel. Returns UMFPACK_OK if successful, or UMFPACK_WARNING_singular_matrix or UMFPACK_ERROR_different_pattern if not. */ #include "umf_internal.h" #include "umf_local_search.h" #include "umf_row_search.h" #include "umf_mem_free_tail_block.h" /* relaxed amalgamation control parameters are fixed at compile time */ #define RELAX1 0.25 #define SYM_RELAX1 0.0 #define RELAX2 0.1 #define RELAX3 0.125 /* ========================================================================== */ /* === remove_candidate ===================================================== */ /* ========================================================================== */ /* Remove a column from the set of candidate pivot columns. */ PRIVATE void remove_candidate (Int jj, WorkType *Work, SymbolicType *Symbolic) { #ifndef NDEBUG Int j ; DEBUGm2 (("pivot column Candidates before remove: nCand "ID" ncand "ID " lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand, Work->lo, Work->hi, jj)) ; for (j = 0 ; j < Work->nCandidates ; j++) { Int col = Work->Candidates [j] ; DEBUGm2 ((ID" ", col)); ASSERT (col >= 0 && col < Work->n_col) ; /* ASSERT (NON_PIVOTAL_COL (col)) ; */ ASSERT (col >= Work->lo && col <= Work->hi) ; } DEBUGm2 (("\n")) ; #endif if (Symbolic->fixQ) { DEBUGm2 (("FixQ\n")) ; /* do not modify the column ordering */ ASSERT (Work->nCandidates == 1) ; ASSERT (jj == 0) ; if (Work->ncand > 1) { Work->Candidates [0] = Work->nextcand++ ; } else { Work->nCandidates = 0 ; } } else { /* place the next candidate in the set */ if (Work->ncand > MAX_CANDIDATES) { Work->Candidates [jj] = Work->nextcand++ ; } else { ASSERT (Work->nCandidates == Work->ncand) ; Work->Candidates [jj] = Work->Candidates [Work->ncand - 1] ; Work->Candidates [Work->ncand - 1] = EMPTY ; Work->nCandidates-- ; } } Work->ncand-- ; #ifndef NDEBUG DEBUGm2 (("pivot column Candidates after remove: nCand "ID" ncand "ID " lo "ID" hi "ID" jj "ID"\n", Work->nCandidates, Work->ncand, Work->lo, Work->hi, jj)) ; for (j = 0 ; j < Work->nCandidates ; j++) { Int col = Work->Candidates [j] ; DEBUGm2 ((ID" ", col)); ASSERT (col >= 0 && col < Work->n_col) ; /* ASSERT (NON_PIVOTAL_COL (col)) ; */ ASSERT (col >= Work->lo && col <= Work->hi) ; } DEBUGm2 (("\n")) ; ASSERT (Work->ncand >= 0) ; ASSERT (Work->nCandidates <= Work->ncand) ; #endif } /* ========================================================================== */ /* === UMF_local_search ===================================================== */ /* ========================================================================== */ GLOBAL Int UMF_local_search ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ double relax1 ; Entry *Flblock, *Fublock, *Fs, *Fcblock, *C, *Wx, *Wy, *Fu, *Flublock, *Flu ; Int pos, nrows, *Cols, *Rows, e, f, status, max_cdeg, fnzeros, nb, j, col, i, row, cdeg_in, rdeg [2][2], fnpiv, nothing [2], new_LUsize, pivrow [2][2], pivcol [2], *Wp, *Fcpos, *Frpos, new_fnzeros, cdeg_out, *Wm, *Wio, *Woi, *Woo, *Frows, *Fcols, fnrows, fncols, *E, deg, nr_in, nc, thiscost, bestcost, nr_out, do_update, extra_cols, extra_rows, extra_zeros, relaxed_front, do_extend, fnr_curr, fnc_curr, tpi, *Col_tuples, *Col_degree, *Col_tlen, jj, jcand [2], freebie [2], did_rowmerge, fnrows_new [2][2], fncols_new [2][2], search_pivcol_out, *Diagonal_map, *Diagonal_imap, row2, col2 ; Unit *Memory, *p ; Tuple *tp, *tpend, *tp1, *tp2 ; Element *ep ; #ifndef NBLAS Int blas_ok = TRUE ; #else #define blas_ok FALSE #endif #ifndef NDEBUG Int debug_ok, n_row, n_col, *Row_degree ; Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro only */ #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ Memory = Numeric->Memory ; E = Work->E ; Col_degree = Numeric->Cperm ; Col_tuples = Numeric->Lip ; Col_tlen = Numeric->Lilen ; Wx = Work->Wx ; Wy = Work->Wy ; Wp = Work->Wp ; Wm = Work->Wm ; Woi = Work->Woi ; Wio = Work->Wio ; Woo = Work->Woo ; Fcpos = Work->Fcpos ; Frpos = Work->Frpos ; Frows = Work->Frows ; Fcols = Work->Fcols ; fnrows = Work->fnrows ; fncols = Work->fncols ; nb = Work->nb ; fnr_curr = Work->fnr_curr ; fnc_curr = Work->fnc_curr ; fnpiv = Work->fnpiv ; nothing [0] = EMPTY ; nothing [1] = EMPTY ; relax1 = (Symbolic->prefer_diagonal) ? SYM_RELAX1 : RELAX1 ; fnzeros = Work->fnzeros ; new_fnzeros = fnzeros ; jj = EMPTY ; Fcblock = Work->Fcblock ; /* current contribution block */ Flblock = Work->Flblock ; /* current L block */ Fublock = Work->Fublock ; /* current U block */ Flublock = Work->Flublock ; /* current LU block */ /* The pivot column degree cannot exceed max_cdeg */ max_cdeg = Work->fnrows_max ; ASSERT (Work->fnrows_max <= Symbolic->maxnrows) ; ASSERT (Work->fncols_max <= Symbolic->maxncols) ; if (fnrows == 0 && fncols == 0) { /* frontal matrix is empty */ Work->firstsuper = Work->ksuper ; } #ifndef NDEBUG n_row = Work->n_row ; n_col = Work->n_col ; DEBUG2 (("\n========LOCAL SEARCH: current frontal matrix: ========= \n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; if (UMF_debug > 0 || MAX (n_row, n_col) < 1000) { for (i = 0 ; i < MAX (n_row, n_col) ; i++) { ASSERT (Wp [i] < 0) ; } } DEBUGm2 ((ID" pivot column Candidates: lo "ID" hi "ID"\n", Work->nCandidates, Work->lo, Work->hi)) ; for (j = 0 ; j < Work->nCandidates ; j++) { col = Work->Candidates [j] ; DEBUGm2 ((ID" ", col)); ASSERT (col >= 0 && col < n_col) ; ASSERT (NON_PIVOTAL_COL (col)) ; ASSERT (col >= Work->lo && col <= Work->hi) ; } DEBUGm2 (("\n")) ; /* there are no 0-by-c or r-by-0 fronts, where c and r are > 0 */ /* a front is either 0-by-0, or r-by-c */ DEBUG2 (("\n\n::: "ID" : Npiv: "ID" + fnpiv "ID" = "ID". " "size "ID"-by-"ID"\n", Work->frontid, Work->npiv, Work->fnpiv, Work->npiv + Work->fnpiv, fnrows, fncols)) ; ASSERT ((fnrows == 0 && fncols == 0) ||(fnrows != 0 && fncols != 0)) ; #endif /* ====================================================================== */ /* === PIVOT SEARCH ===================================================== */ /* ====================================================================== */ /* initialize */ pivcol [IN] = EMPTY ; pivcol [OUT] = EMPTY ; cdeg_in = Int_MAX ; cdeg_out = Int_MAX ; pivrow [IN][IN] = EMPTY ; pivrow [IN][OUT] = EMPTY ; pivrow [OUT][IN] = EMPTY ; pivrow [OUT][OUT] = EMPTY ; rdeg [IN][IN] = Int_MAX ; rdeg [IN][OUT] = Int_MAX ; rdeg [OUT][IN] = Int_MAX ; rdeg [OUT][OUT] = Int_MAX ; freebie [IN] = FALSE ; freebie [OUT] = FALSE ; Work->pivot_case = EMPTY ; bestcost = EMPTY ; nr_out = EMPTY ; nr_in = EMPTY ; jcand [IN] = EMPTY ; jcand [OUT] = EMPTY ; fnrows_new [IN][IN] = EMPTY ; fnrows_new [IN][OUT] = EMPTY ; fnrows_new [OUT][IN] = EMPTY ; fnrows_new [OUT][OUT] = EMPTY ; fncols_new [IN][IN] = EMPTY ; fncols_new [IN][OUT] = EMPTY ; fncols_new [OUT][IN] = EMPTY ; fncols_new [OUT][OUT] = EMPTY ; #ifndef NDEBUG /* check Frpos */ DEBUG4 (("Check Frpos : fnrows "ID" col "ID" maxcdeg "ID"\n", fnrows, pivcol [IN], max_cdeg)) ; for (i = 0 ; i < fnrows ; i++) { row = Frows [i] ; DEBUG4 ((" row: "ID"\n", row)) ; ASSERT (row >= 0 && row < n_row) ; ASSERT (Frpos [row] == i) ; } DEBUG4 (("All:\n")) ; if (UMF_debug > 0 || n_row < 1000) { Int cnt = fnrows ; for (row = 0 ; row < n_row ; row++) { if (Frpos [row] == EMPTY) { cnt++ ; } else { DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ; } } ASSERT (cnt == n_row) ; } #endif /* ---------------------------------------------------------------------- */ /* find shortest column in the front, and shortest column not in the */ /* front, from the candidate pivot column set */ /* ---------------------------------------------------------------------- */ /* If there are too many candidates, then only look at the first */ /* MAX_CANDIDATES of them. Otherwise, if there are O(n) candidates, */ /* this code could take O(n^2) time. */ /* ------------------------------------------------------------------ */ /* look in the candidate set for the best column */ /* ------------------------------------------------------------------ */ DEBUG2 (("Max candidates %d, Work->ncand "ID" jmax "ID"\n", MAX_CANDIDATES, Work->ncand, Work->nCandidates)) ; col = Work->Candidates [0] ; ASSERT (Work->nCandidates > 0) ; DEBUG3 (("Pivot column candidate: "ID" j = "ID"\n", col, j)) ; ASSERT (col >= 0 && col < n_col) ; /* there is no Col_degree if fixQ is true */ deg = Symbolic->fixQ ? EMPTY : Col_degree [col] ; #ifndef NDEBUG DEBUG3 (("Pivot column candidate: "ID" cost: "ID" Fcpos[col] "ID"\n", col, deg, Fcpos [col])) ; UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ; if (Symbolic->fixQ) { DEBUG1 (("FIXQ: Candidates "ID" pivcol "ID" npiv "ID" fnpiv "ID " ndiscard "ID "\n", Work->nCandidates, col, Work->npiv, Work->fnpiv, Work->ndiscard)) ; ASSERT (Work->nCandidates == 1) ; ASSERT (col == Work->npiv + Work->fnpiv + Work->ndiscard) ; } #endif if (Fcpos [col] >= 0) { /* best column in front, so far */ pivcol [IN] = col ; cdeg_in = deg ; /* ignored, if fixQ is true */ jcand [IN] = 0 ; } else { /* best column not in front, so far */ pivcol [OUT] = col ; cdeg_out = deg ; /* ignored, if fixQ is true */ jcand [OUT] = 0 ; } /* look at the rest of the candidates */ for (j = 1 ; j < Work->nCandidates ; j++) { col = Work->Candidates [j] ; DEBUG3 (("Pivot col candidate: "ID" j = "ID"\n", col, j)) ; ASSERT (col >= 0 && col < n_col) ; ASSERT (!Symbolic->fixQ) ; deg = Col_degree [col] ; #ifndef NDEBUG DEBUG3 (("Pivot col candidate: "ID" cost: "ID" Fcpos[col] "ID"\n", col, deg, Fcpos [col])) ; UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ; #endif if (Fcpos [col] >= 0) { #ifndef NDEBUG Int fs ; fs = Fcpos [col] / fnr_curr ; ASSERT (fs >= 0 && fs < fncols) ; #endif if (deg < cdeg_in || (deg == cdeg_in && col < pivcol [IN])) { /* best column in front, so far */ pivcol [IN] = col ; cdeg_in = deg ; jcand [IN] = j ; } } else { if (deg < cdeg_out || (deg == cdeg_out && col < pivcol [OUT])) { /* best column not in front, so far */ pivcol [OUT] = col ; cdeg_out = deg ; jcand [OUT] = j ; } } } DEBUG2 (("Pivcol in "ID" out "ID"\n", pivcol [IN], pivcol [OUT])) ; ASSERT ((pivcol [IN] >= 0 && pivcol [IN] < n_col) || (pivcol [OUT] >= 0 && pivcol [OUT] < n_col)) ; cdeg_in = EMPTY ; cdeg_out = EMPTY ; /* ---------------------------------------------------------------------- */ /* construct candidate column in front, and search for pivot rows */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG /* check Frpos */ DEBUG4 (("Prior to col update: fnrows "ID" col "ID" maxcdeg "ID"\n", fnrows, pivcol [IN], max_cdeg)) ; for (i = 0 ; i < fnrows ; i++) { row = Frows [i] ; DEBUG4 ((" row: "ID"\n", row)) ; ASSERT (row >= 0 && row < n_row) ; ASSERT (Frpos [row] == i) ; } DEBUG4 (("All:\n")) ; if (UMF_debug > 0 || n_row < 1000) { Int cnt = fnrows ; for (row = 0 ; row < n_row ; row++) { if (Frpos [row] == EMPTY) { cnt++ ; } else { DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ; } } ASSERT (cnt == n_row) ; } #endif if (pivcol [IN] != EMPTY) { #ifndef NDEBUG DEBUG2 (("col[IN] column "ID" in front at position = "ID"\n", pivcol [IN], Fcpos [pivcol [IN]])) ; UMF_dump_rowcol (1, Numeric, Work, pivcol [IN], !Symbolic->fixQ) ; #endif /* the only way we can have a pivcol[IN] is if the front is not empty */ ASSERT (fnrows > 0 && fncols > 0) ; DEBUG4 (("Update pivot column:\n")) ; Fs = Fcblock + Fcpos [pivcol [IN]] ; Fu = Fublock + (Fcpos [pivcol [IN]] / fnr_curr) ; Flu = Flublock + fnpiv * nb ; /* ------------------------------------------------------------------ */ /* copy the pivot column from the U block into the LU block */ /* ------------------------------------------------------------------ */ /* This copy is permanent if the pivcol [IN] is chosen. */ for (i = 0 ; i < fnpiv ; i++) { Flu [i] = Fu [i*fnc_curr] ; } /* ------------------------------------------------------------------ */ /* update the pivot column in the LU block using a triangular solve */ /* ------------------------------------------------------------------ */ /* This work will be discarded if the pivcol [OUT] is chosen instead. * It is permanent if the pivcol [IN] is chosen. */ if (fnpiv > 1) { /* solve Lx=b, where b = U (:,k), stored in the LU block */ #ifndef NBLAS BLAS_TRSV (fnpiv, Flublock, Flu, nb) ; #endif if (!blas_ok) { /* use plain C code if no BLAS, or on integer overflow */ Entry *Flub = Flublock ; for (j = 0 ; j < fnpiv ; j++) { Entry Fuj = Flu [j] ; #pragma ivdep for (i = j+1 ; i < fnpiv ; i++) { /* Flu [i] -= Flublock [i + j*nb] * Flu [j] ; */ MULT_SUB (Flu [i], Flub [i], Fuj) ; } Flub += nb ; } } } /* ------------------------------------------------------------------ */ /* copy the pivot column from the C block into Wy */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < fnrows ; i++) { Wy [i] = Fs [i] ; } /* ------------------------------------------------------------------ */ /* update the pivot column of L using a matrix-vector multiply */ /* ------------------------------------------------------------------ */ /* this work will be discarded if the pivcol [OUT] is chosen instead */ #ifdef NBLAS /* no BLAS available - use plain C code instead */ for (j = 0 ; j < fnpiv ; j++) { Entry Fuj, *Flub = Flblock + j * fnr_curr ; Fuj = Flu [j] ; if (IS_NONZERO (Fuj)) { #pragma ivdep for (i = 0 ; i < fnrows ; i++) { /* Wy [i] -= Flblock [i+j*fnr_curr] * Fuj ; */ MULT_SUB (Wy [i], Flub [i], Fuj) ; } } /* Flblock += fnr_curr ; */ } #else /* Using 1-based notation: * Wy (1:fnrows) -= Flblock (1:fnrows,1:fnpiv) * Flu (1:fnpiv) */ BLAS_GEMV (fnrows, fnpiv, Flblock, Flu, Wy, fnr_curr) ; #endif /* ------------------------------------------------------------------ */ #ifndef NDEBUG DEBUG2 (("Wy after update: fnrows="ID"\n", fnrows)) ; DEBUG4 ((" fnpiv="ID" \n", fnpiv)) ; for (i = 0 ; i < fnrows ; i++) { DEBUG4 ((ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ; EDEBUG4 (Wy [i]) ; DEBUG4 (("\n")) ; } #endif /* ------------------------------------------------------------------ */ /* construct the candidate column */ /* ------------------------------------------------------------------ */ cdeg_in = fnrows ; #ifndef NDEBUG /* check Frpos */ DEBUG4 (("After col update: fnrows "ID" col "ID" maxcdeg "ID"\n", fnrows, pivcol [IN], max_cdeg)) ; for (i = 0 ; i < fnrows ; i++) { row = Frows [i] ; DEBUG4 ((" row: "ID"\n", row)) ; ASSERT (row >= 0 && row < n_row) ; ASSERT (Frpos [row] == i) ; } DEBUG4 (("All:\n")) ; if (UMF_debug > 0 || n_row < 1000) { Int cnt = fnrows ; for (row = 0 ; row < n_row ; row++) { if (Frpos [row] == EMPTY) { cnt++ ; } else { DEBUG4 ((" row: "ID" pos "ID"\n", row, Frpos [row])) ; } } ASSERT (cnt == n_row) ; } #endif #ifndef NDEBUG /* check Frpos */ DEBUG4 (("COL ASSEMBLE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n", cdeg_in, pivcol [IN], max_cdeg)) ; for (i = 0 ; i < cdeg_in ; i++) { row = Frows [i] ; ASSERT (row >= 0 && row < n_row) ; ASSERT (Frpos [row] == i) ; } if (UMF_debug > 0 || n_row < 1000) { Int cnt = cdeg_in ; for (row = 0 ; row < n_row ; row++) { if (Frpos [row] == EMPTY) cnt++ ; } ASSERT (cnt == n_row) ; } #endif /* assemble column into Wy */ ASSERT (pivcol [IN] >= 0 && pivcol [IN] < n_col) ; ASSERT (NON_PIVOTAL_COL (pivcol [IN])) ; tpi = Col_tuples [pivcol [IN]] ; if (tpi) { tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Col_tlen [pivcol [IN]] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; if (Cols [f] == EMPTY) continue ; /* column already assembled */ ASSERT (pivcol [IN] == Cols [f]) ; Rows = Cols + ep->ncols ; nrows = ep->nrows ; p += UNITS (Int, ep->ncols + nrows) ; C = ((Entry *) p) + f * nrows ; for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; if (row >= 0) /* skip this if already gone from element */ { ASSERT (row < n_row) ; pos = Frpos [row] ; if (pos < 0) { /* new entry in the pattern - save Frpos */ ASSERT (cdeg_in < n_row) ; if (cdeg_in >= max_cdeg) { /* :: pattern change (cdeg in failure) :: */ DEBUGm4 (("cdeg_in failure\n")) ; return (UMFPACK_ERROR_different_pattern) ; } Frpos [row] = cdeg_in ; Frows [cdeg_in] = row ; Wy [cdeg_in++] = C [i] ; } else { /* entry already in pattern - sum values in Wy */ /* Wy [pos] += C [i] ; */ ASSERT (pos < max_cdeg) ; ASSEMBLE (Wy [pos], C [i]) ; } } } *tp2++ = *tp ; /* leave the tuple in the list */ } Col_tlen [pivcol [IN]] = tp2 - tp1 ; } /* ------------------------------------------------------------------ */ #ifndef NDEBUG /* check Frpos again */ DEBUG4 (("COL DONE: cdeg "ID"\nREDUCE COL in "ID" max_cdeg "ID"\n", cdeg_in, pivcol [IN], max_cdeg)) ; for (i = 0 ; i < cdeg_in ; i++) { row = Frows [i] ; ASSERT (row >= 0 && row < n_row) ; ASSERT (Frpos [row] == i) ; } if (UMF_debug > 0 || n_row < 1000) { Int cnt = cdeg_in ; for (row = 0 ; row < n_row ; row++) { if (Frpos [row] == EMPTY) cnt++ ; } ASSERT (cnt == n_row) ; } #endif #ifndef NDEBUG DEBUG4 (("Reduced column: cdeg in "ID" fnrows_max "ID"\n", cdeg_in, Work->fnrows_max)) ; for (i = 0 ; i < cdeg_in ; i++) { DEBUG4 ((" "ID" "ID" "ID, i, Frows [i], Frpos [Frows [i]])) ; EDEBUG4 (Wy [i]) ; DEBUG4 (("\n")) ; ASSERT (i == Frpos [Frows [i]]) ; } ASSERT (cdeg_in <= Work->fnrows_max) ; #endif /* ------------------------------------------------------------------ */ /* cdeg_in is now the exact degree of this column */ /* ------------------------------------------------------------------ */ nr_in = cdeg_in - fnrows ; /* since there are no 0-by-x fronts, if there is a pivcol [IN] the */ /* front must have at least one row. */ ASSERT (cdeg_in > 0) ; /* new degree of pivcol [IN], excluding current front is nr_in */ /* column expands by nr_in rows */ /* ------------------------------------------------------------------ */ /* search for two candidate pivot rows */ /* ------------------------------------------------------------------ */ /* for the IN_IN pivot row (if any), */ /* extend the pattern in place, using Fcols */ status = UMF_row_search (Numeric, Work, Symbolic, fnrows, cdeg_in, Frows, Frpos, /* pattern of column to search */ pivrow [IN], rdeg [IN], Fcols, Wio, nothing, Wy, pivcol [IN], freebie) ; ASSERT (!freebie [IN] && !freebie [OUT]) ; /* ------------------------------------------------------------------ */ /* fatal error if matrix pattern has changed since symbolic analysis */ /* ------------------------------------------------------------------ */ if (status == UMFPACK_ERROR_different_pattern) { /* :: pattern change (row search IN failure) :: */ DEBUGm4 (("row search IN failure\n")) ; return (UMFPACK_ERROR_different_pattern) ; } /* ------------------------------------------------------------------ */ /* we now must have a structural pivot */ /* ------------------------------------------------------------------ */ /* Since the pivcol[IN] exists, there must be at least one row in the */ /* current frontal matrix, and so we must have found a structural */ /* pivot. The numerical value might be zero, of course. */ ASSERT (status != UMFPACK_WARNING_singular_matrix) ; /* ------------------------------------------------------------------ */ /* evaluate IN_IN option */ /* ------------------------------------------------------------------ */ if (pivrow [IN][IN] != EMPTY) { /* The current front would become an (implicit) LUson. * Both candidate pivot row and column are in the current front. * Cost is how much the current front would expand */ /* pivrow[IN][IN] candidates are not found via row merge search */ ASSERT (fnrows >= 0 && fncols >= 0) ; ASSERT (cdeg_in > 0) ; nc = rdeg [IN][IN] - fncols ; thiscost = /* each column in front (except pivot column) grows by nr_in: */ (nr_in * (fncols - 1)) + /* new columns not in old front: */ (nc * (cdeg_in - 1)) ; /* no extra cost to relaxed amalgamation */ ASSERT (fnrows + nr_in == cdeg_in) ; ASSERT (fncols + nc == rdeg [IN][IN]) ; /* size of relaxed front (after pivot row column removed): */ fnrows_new [IN][IN] = (fnrows-1) + nr_in ; fncols_new [IN][IN] = (fncols-1) + nc ; /* relaxed_front = fnrows_new [IN][IN] * fncols_new [IN][IN] ; */ do_extend = TRUE ; DEBUG2 (("Evaluating option IN-IN:\n")) ; DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n", Work->fnzeros, fnpiv, nr_in, nc)) ; DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ; /* determine if BLAS-3 update should be applied before extending. */ /* update if too many zero entries accumulate in the LU block */ fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ; DEBUG2 (("fnzeros "ID"\n", fnzeros)) ; new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ; DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ; /* There are fnpiv pivots currently in the front. This one * will be the (fnpiv+1)st pivot, if it is extended. */ /* RELAX2 parameter uses a double relop, but ignore NaN case: */ do_update = fnpiv > 0 && (((double) fnzeros) / ((double) new_LUsize)) > RELAX2 ; DEBUG2 (("do_update "ID"\n", do_update)) DEBUG2 (("option IN IN : nr "ID" nc "ID" cost "ID"(0) relax "ID "\n", nr_in, nc, thiscost, do_extend)) ; /* this is the best option seen so far */ Work->pivot_case = IN_IN ; bestcost = thiscost ; /* do the amalgamation and extend the front */ Work->do_extend = do_extend ; Work->do_update = do_update ; new_fnzeros = fnzeros ; } /* ------------------------------------------------------------------ */ /* evaluate IN_OUT option */ /* ------------------------------------------------------------------ */ if (pivrow [IN][OUT] != EMPTY) { /* The current front would become a Uson of the new front. * Candidate pivot column is in the current front, but the * candidate pivot row is not. */ ASSERT (fnrows >= 0 && fncols > 0) ; ASSERT (cdeg_in > 0) ; /* must be at least one row outside the front */ /* (the pivrow [IN][OUT] itself) */ ASSERT (nr_in >= 1) ; /* count columns not in current front */ nc = 0 ; #ifndef NDEBUG debug_ok = FALSE ; #endif for (i = 0 ; i < rdeg [IN][OUT] ; i++) { col = Wio [i] ; DEBUG4 (("counting col "ID" Fcpos[] = "ID"\n", col, Fcpos [col])) ; ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ; if (Fcpos [col] < 0) nc++ ; #ifndef NDEBUG /* we must see the pivot column somewhere */ if (col == pivcol [IN]) { ASSERT (Fcpos [col] >= 0) ; debug_ok = TRUE ; } #endif } ASSERT (debug_ok) ; thiscost = /* each row in front grows by nc: */ (nc * fnrows) + /* new rows not affected by front: */ ((nr_in-1) * (rdeg [IN][OUT]-1)) ; /* check the cost of relaxed IN_OUT amalgamation */ extra_cols = ((fncols-1) + nc ) - (rdeg [IN][OUT] - 1) ; ASSERT (extra_cols >= 0) ; ASSERT (fncols + nc == extra_cols + rdeg [IN][OUT]) ; extra_zeros = (nr_in-1) * extra_cols ; /* symbolic fill-in */ ASSERT (fnrows + nr_in == cdeg_in) ; ASSERT (fncols + nc == rdeg [IN][OUT] + extra_cols) ; /* size of relaxed front (after pivot column removed): */ fnrows_new [IN][OUT] = fnrows + (nr_in-1) ; fncols_new [IN][OUT] = (fncols-1) + nc ; relaxed_front = fnrows_new [IN][OUT] * fncols_new [IN][OUT] ; /* do relaxed amalgamation if the extra zeros are no more */ /* than a fraction (default 0.25) of the relaxed front */ /* if relax = 0: no extra zeros allowed */ /* if relax = +inf: always amalgamate */ /* relax parameter uses a double relop, but ignore NaN case: */ if (extra_zeros == 0) { do_extend = TRUE ; } else { do_extend = ((double) extra_zeros) < (relax1 * (double) relaxed_front) ; } if (do_extend) { /* count the cost of relaxed amalgamation */ thiscost += extra_zeros ; DEBUG2 (("Evaluating option IN-OUT:\n")) ; DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_in "ID" nc "ID"\n", Work->fnzeros, fnpiv, nr_in, nc)) ; DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ; /* determine if BLAS-3 update to be applied before extending. */ /* update if too many zero entries accumulate in the LU block */ fnzeros = Work->fnzeros + fnpiv * (nr_in + nc) ; DEBUG2 (("fnzeros "ID"\n", fnzeros)) ; new_LUsize = (fnpiv+1) * (fnrows + nr_in + fncols + nc) ; DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ; /* RELAX3 parameter uses a double relop, ignore NaN case: */ do_update = fnpiv > 0 && (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ; DEBUG2 (("do_update "ID"\n", do_update)) } else { /* the current front would not be extended */ do_update = fnpiv > 0 ; fnzeros = 0 ; DEBUG2 (("IN-OUT do_update forced true: "ID"\n", do_update)) ; /* The new front would be just big enough to hold the new * pivot row and column. */ fnrows_new [IN][OUT] = cdeg_in - 1 ; fncols_new [IN][OUT] = rdeg [IN][OUT] - 1 ; } DEBUG2 (("option IN OUT: nr "ID" nc "ID" cost "ID"("ID") relax "ID "\n", nr_in, nc, thiscost, extra_zeros, do_extend)) ; if (bestcost == EMPTY || thiscost < bestcost) { /* this is the best option seen so far */ Work->pivot_case = IN_OUT ; bestcost = thiscost ; Work->do_extend = do_extend ; Work->do_update = do_update ; new_fnzeros = fnzeros ; } } } /* ---------------------------------------------------------------------- */ /* construct candidate column not in front, and search for pivot rows */ /* ---------------------------------------------------------------------- */ search_pivcol_out = (bestcost != 0 && pivcol [OUT] != EMPTY) ; if (Symbolic->prefer_diagonal) { search_pivcol_out = search_pivcol_out && (pivrow [IN][IN] == EMPTY) ; } if (search_pivcol_out) { #ifndef NDEBUG DEBUG2 (("out_col column "ID" NOT in front at position = "ID"\n", pivcol [OUT], Fcpos [pivcol [OUT]])) ; UMF_dump_rowcol (1, Numeric, Work, pivcol [OUT], !Symbolic->fixQ) ; DEBUG2 (("fncols "ID" fncols_max "ID"\n", fncols, Work->fncols_max)) ; ASSERT (fncols < Work->fncols_max) ; #endif /* Use Wx as temporary workspace to construct the pivcol [OUT] */ /* ------------------------------------------------------------------ */ /* construct the candidate column (currently not in the front) */ /* ------------------------------------------------------------------ */ /* Construct the column in Wx, Wm, using Wp for the positions: */ /* Wm [0..cdeg_out-1] list of row indices in the column */ /* Wx [0..cdeg_out-1] list of corresponding numerical values */ /* Wp [0..n-1] starts as all negative, and ends that way too. */ cdeg_out = 0 ; #ifndef NDEBUG /* check Wp */ DEBUG4 (("COL ASSEMBLE: cdeg 0\nREDUCE COL out "ID"\n", pivcol [OUT])) ; if (UMF_debug > 0 || MAX (n_row, n_col) < 1000) { for (i = 0 ; i < MAX (n_row, n_col) ; i++) { ASSERT (Wp [i] < 0) ; } } DEBUG4 (("max_cdeg: "ID"\n", max_cdeg)) ; #endif ASSERT (pivcol [OUT] >= 0 && pivcol [OUT] < n_col) ; ASSERT (NON_PIVOTAL_COL (pivcol [OUT])) ; tpi = Col_tuples [pivcol [OUT]] ; if (tpi) { tp = (Tuple *) (Memory + tpi) ; tp1 = tp ; tp2 = tp ; tpend = tp + Col_tlen [pivcol [OUT]] ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; if (Cols [f] == EMPTY) continue ; /* column already assembled */ ASSERT (pivcol [OUT] == Cols [f]) ; Rows = Cols + ep->ncols ; nrows = ep->nrows ; p += UNITS (Int, ep->ncols + nrows) ; C = ((Entry *) p) + f * nrows ; for (i = 0 ; i < nrows ; i++) { row = Rows [i] ; if (row >= 0) /* skip this if already gone from element */ { ASSERT (row < n_row) ; pos = Wp [row] ; if (pos < 0) { /* new entry in the pattern - save Wp */ ASSERT (cdeg_out < n_row) ; if (cdeg_out >= max_cdeg) { /* :: pattern change (cdeg out failure) :: */ DEBUGm4 (("cdeg out failure\n")) ; return (UMFPACK_ERROR_different_pattern) ; } Wp [row] = cdeg_out ; Wm [cdeg_out] = row ; Wx [cdeg_out++] = C [i] ; } else { /* entry already in pattern - sum the values */ /* Wx [pos] += C [i] ; */ ASSEMBLE (Wx [pos], C [i]) ; } } } *tp2++ = *tp ; /* leave the tuple in the list */ } Col_tlen [pivcol [OUT]] = tp2 - tp1 ; } /* ------------------------------------------------------------------ */ #ifndef NDEBUG DEBUG4 (("Reduced column: cdeg out "ID"\n", cdeg_out)) ; for (i = 0 ; i < cdeg_out ; i++) { DEBUG4 ((" "ID" "ID" "ID, i, Wm [i], Wp [Wm [i]])) ; EDEBUG4 (Wx [i]) ; DEBUG4 (("\n")) ; ASSERT (i == Wp [Wm [i]]) ; } #endif /* ------------------------------------------------------------------ */ /* new degree of pivcol [OUT] is cdeg_out */ /* ------------------------------------------------------------------ */ /* search for two candidate pivot rows */ status = UMF_row_search (Numeric, Work, Symbolic, 0, cdeg_out, Wm, Wp, /* pattern of column to search */ pivrow [OUT], rdeg [OUT], Woi, Woo, pivrow [IN], Wx, pivcol [OUT], freebie) ; /* ------------------------------------------------------------------ */ /* fatal error if matrix pattern has changed since symbolic analysis */ /* ------------------------------------------------------------------ */ if (status == UMFPACK_ERROR_different_pattern) { /* :: pattern change detected in umf_local_search :: */ return (UMFPACK_ERROR_different_pattern) ; } /* ------------------------------------------------------------------ */ /* Clear Wp */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < cdeg_out ; i++) { Wp [Wm [i]] = EMPTY ; /* clear Wp */ } /* ------------------------------------------------------------------ */ /* check for rectangular, singular matrix */ /* ------------------------------------------------------------------ */ if (status == UMFPACK_WARNING_singular_matrix) { /* Pivot column is empty, and row-merge set is empty too. The * matrix is structurally singular. The current frontal matrix must * be empty, too. It it weren't, and pivcol [OUT] exists, then * there would be at least one row that could be selected. Since * the current front is empty, pivcol [IN] must also be EMPTY. */ DEBUGm4 (("Note: pivcol [OUT]: "ID" discard\n", pivcol [OUT])) ; ASSERT ((Work->fnrows == 0 && Work->fncols == 0)) ; ASSERT (pivcol [IN] == EMPTY) ; /* remove the failed pivcol [OUT] from candidate set */ ASSERT (pivcol [OUT] == Work->Candidates [jcand [OUT]]) ; remove_candidate (jcand [OUT], Work, Symbolic) ; Work->ndiscard++ ; /* delete all of the tuples, and all contributions to this column */ DEBUG1 (("Prune tuples of dead outcol: "ID"\n", pivcol [OUT])) ; Col_tlen [pivcol [OUT]] = 0 ; UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol [OUT]]) ; Col_tuples [pivcol [OUT]] = 0 ; /* no pivot found at all */ return (UMFPACK_WARNING_singular_matrix) ; } /* ------------------------------------------------------------------ */ if (freebie [IN]) { /* the "in" row is the same as the "in" row for the "in" column */ Woi = Fcols ; rdeg [OUT][IN] = rdeg [IN][IN] ; DEBUG4 (("Freebie in, row "ID"\n", pivrow [IN][IN])) ; } if (freebie [OUT]) { /* the "out" row is the same as the "out" row for the "in" column */ Woo = Wio ; rdeg [OUT][OUT] = rdeg [IN][OUT] ; DEBUG4 (("Freebie out, row "ID"\n", pivrow [IN][OUT])) ; } /* ------------------------------------------------------------------ */ /* evaluate OUT_IN option */ /* ------------------------------------------------------------------ */ if (pivrow [OUT][IN] != EMPTY) { /* The current front would become an Lson of the new front. * The candidate pivot row is in the current front, but the * candidate pivot column is not. */ ASSERT (fnrows > 0 && fncols >= 0) ; did_rowmerge = (cdeg_out == 0) ; if (did_rowmerge) { /* pivrow [OUT][IN] was found via row merge search */ /* it is not (yet) in the pivot column pattern (add it now) */ DEBUGm4 (("did row merge OUT col, IN row\n")) ; Wm [0] = pivrow [OUT][IN] ; CLEAR (Wx [0]) ; cdeg_out = 1 ; ASSERT (nr_out == EMPTY) ; } nc = rdeg [OUT][IN] - fncols ; ASSERT (nc >= 1) ; /* count rows not in current front */ nr_out = 0 ; #ifndef NDEBUG debug_ok = FALSE ; #endif for (i = 0 ; i < cdeg_out ; i++) { row = Wm [i] ; ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ; if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ; #ifndef NDEBUG /* we must see the pivot row somewhere */ if (row == pivrow [OUT][IN]) { ASSERT (Frpos [row] >= 0) ; debug_ok = TRUE ; } #endif } ASSERT (debug_ok) ; thiscost = /* each column in front grows by nr_out: */ (nr_out * fncols) + /* new cols not affected by front: */ ((nc-1) * (cdeg_out-1)) ; /* check the cost of relaxed OUT_IN amalgamation */ extra_rows = ((fnrows-1) + nr_out) - (cdeg_out - 1) ; ASSERT (extra_rows >= 0) ; ASSERT (fnrows + nr_out == extra_rows + cdeg_out) ; extra_zeros = (nc-1) * extra_rows ; /* symbolic fill-in */ ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ; ASSERT (fncols + nc == rdeg [OUT][IN]) ; /* size of relaxed front (after pivot row removed): */ fnrows_new [OUT][IN] = (fnrows-1) + nr_out ; fncols_new [OUT][IN] = fncols + (nc-1) ; relaxed_front = fnrows_new [OUT][IN] * fncols_new [OUT][IN] ; /* do relaxed amalgamation if the extra zeros are no more */ /* than a fraction (default 0.25) of the relaxed front */ /* if relax = 0: no extra zeros allowed */ /* if relax = +inf: always amalgamate */ if (did_rowmerge) { do_extend = FALSE ; } else { /* relax parameter uses a double relop, but ignore NaN case: */ if (extra_zeros == 0) { do_extend = TRUE ; } else { do_extend = ((double) extra_zeros) < (relax1 * (double) relaxed_front) ; } } if (do_extend) { /* count the cost of relaxed amalgamation */ thiscost += extra_zeros ; DEBUG2 (("Evaluating option OUT-IN:\n")) ; DEBUG2 ((" Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n", Work->fnzeros, fnpiv, nr_out, nc)) ; DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ; /* determine if BLAS-3 update to be applied before extending. */ /* update if too many zero entries accumulate in the LU block */ fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ; DEBUG2 (("fnzeros "ID"\n", fnzeros)) ; new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ; DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ; /* RELAX3 parameter uses a double relop, ignore NaN case: */ do_update = fnpiv > 0 && (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ; DEBUG2 (("do_update "ID"\n", do_update)) } else { /* the current front would not be extended */ do_update = fnpiv > 0 ; fnzeros = 0 ; DEBUG2 (("OUT-IN do_update forced true: "ID"\n", do_update)) ; /* The new front would be just big enough to hold the new * pivot row and column. */ fnrows_new [OUT][IN] = cdeg_out - 1 ; fncols_new [OUT][IN] = rdeg [OUT][IN] - 1 ; } DEBUG2 (("option OUT IN : nr "ID" nc "ID" cost "ID"("ID") relax "ID "\n", nr_out, nc, thiscost, extra_zeros, do_extend)) ; if (bestcost == EMPTY || thiscost < bestcost) { /* this is the best option seen so far */ Work->pivot_case = OUT_IN ; bestcost = thiscost ; Work->do_extend = do_extend ; Work->do_update = do_update ; new_fnzeros = fnzeros ; } } /* ------------------------------------------------------------------ */ /* evaluate OUT_OUT option */ /* ------------------------------------------------------------------ */ if (pivrow [OUT][OUT] != EMPTY) { /* Neither the candidate pivot row nor the candidate pivot column * are in the current front. */ ASSERT (fnrows >= 0 && fncols >= 0) ; did_rowmerge = (cdeg_out == 0) ; if (did_rowmerge) { /* pivrow [OUT][OUT] was found via row merge search */ /* it is not (yet) in the pivot column pattern (add it now) */ DEBUGm4 (("did row merge OUT col, OUT row\n")) ; Wm [0] = pivrow [OUT][OUT] ; CLEAR (Wx [0]) ; cdeg_out = 1 ; ASSERT (nr_out == EMPTY) ; nr_out = 1 ; } if (fnrows == 0 && fncols == 0) { /* the current front is completely empty */ ASSERT (fnpiv == 0) ; nc = rdeg [OUT][OUT] ; extra_cols = 0 ; nr_out = cdeg_out ; extra_rows = 0 ; extra_zeros = 0 ; thiscost = (nc-1) * (cdeg_out-1) ; /* new columns only */ /* size of new front: */ fnrows_new [OUT][OUT] = nr_out-1 ; fncols_new [OUT][OUT] = nc-1 ; relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ; } else { /* count rows not in current front */ if (nr_out == EMPTY) { nr_out = 0 ; #ifndef NDEBUG debug_ok = FALSE ; #endif for (i = 0 ; i < cdeg_out ; i++) { row = Wm [i] ; ASSERT (row >= 0 && row < n_row) ; ASSERT (NON_PIVOTAL_ROW (row)) ; if (Frpos [row] < 0 || Frpos [row] >= fnrows) nr_out++ ; #ifndef NDEBUG /* we must see the pivot row somewhere */ if (row == pivrow [OUT][OUT]) { ASSERT (Frpos [row] < 0 || Frpos [row] >= fnrows) ; debug_ok = TRUE ; } #endif } ASSERT (debug_ok) ; } /* count columns not in current front */ nc = 0 ; #ifndef NDEBUG debug_ok = FALSE ; #endif for (i = 0 ; i < rdeg [OUT][OUT] ; i++) { col = Woo [i] ; ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ; if (Fcpos [col] < 0) nc++ ; #ifndef NDEBUG /* we must see the pivot column somewhere */ if (col == pivcol [OUT]) { ASSERT (Fcpos [col] < 0) ; debug_ok = TRUE ; } #endif } ASSERT (debug_ok) ; extra_cols = (fncols + (nc-1)) - (rdeg [OUT][OUT] - 1) ; extra_rows = (fnrows + (nr_out-1)) - (cdeg_out - 1) ; ASSERT (extra_rows >= 0) ; ASSERT (extra_cols >= 0) ; extra_zeros = ((nc-1) * extra_rows) + ((nr_out-1) * extra_cols); ASSERT (fnrows + nr_out == cdeg_out + extra_rows) ; ASSERT (fncols + nc == rdeg [OUT][OUT] + extra_cols) ; thiscost = /* new columns: */ ((nc-1) * (cdeg_out-1)) + /* old columns in front grow by nr_out-1: */ ((nr_out-1) * (fncols - extra_cols)) ; /* size of relaxed front: */ fnrows_new [OUT][OUT] = fnrows + (nr_out-1) ; fncols_new [OUT][OUT] = fncols + (nc-1) ; relaxed_front = fnrows_new [OUT][OUT] * fncols_new [OUT][OUT] ; } /* do relaxed amalgamation if the extra zeros are no more */ /* than a fraction (default 0.25) of the relaxed front */ /* if relax = 0: no extra zeros allowed */ /* if relax = +inf: always amalgamate */ if (did_rowmerge) { do_extend = FALSE ; } else { /* relax parameter uses a double relop, but ignore NaN case: */ if (extra_zeros == 0) { do_extend = TRUE ; } else { do_extend = ((double) extra_zeros) < (relax1 * (double) relaxed_front) ; } } if (do_extend) { /* count the cost of relaxed amalgamation */ thiscost += extra_zeros ; DEBUG2 (("Evaluating option OUT-OUT:\n")) ; DEBUG2 (("Work->fnzeros "ID" fnpiv "ID" nr_out "ID" nc "ID"\n", Work->fnzeros, fnpiv, nr_out, nc)) ; DEBUG2 (("fncols "ID" fnrows "ID"\n", fncols, fnrows)) ; /* determine if BLAS-3 update to be applied before extending. */ /* update if too many zero entries accumulate in the LU block */ fnzeros = Work->fnzeros + fnpiv * (nr_out + nc) ; DEBUG2 (("fnzeros "ID"\n", fnzeros)) ; new_LUsize = (fnpiv+1) * (fnrows + nr_out + fncols + nc) ; DEBUG2 (("new_LUsize "ID"\n", new_LUsize)) ; /* RELAX3 parameter uses a double relop, ignore NaN case: */ do_update = fnpiv > 0 && (((double) fnzeros) / ((double) new_LUsize)) > RELAX3 ; DEBUG2 (("do_update "ID"\n", do_update)) } else { /* the current front would not be extended */ do_update = fnpiv > 0 ; fnzeros = 0 ; DEBUG2 (("OUT-OUT do_update forced true: "ID"\n", do_update)) ; /* The new front would be just big enough to hold the new * pivot row and column. */ fnrows_new [OUT][OUT] = cdeg_out - 1 ; fncols_new [OUT][OUT] = rdeg [OUT][OUT] - 1 ; } DEBUG2 (("option OUT OUT: nr "ID" nc "ID" cost "ID"\n", rdeg [OUT][OUT], cdeg_out, thiscost)) ; if (bestcost == EMPTY || thiscost < bestcost) { /* this is the best option seen so far */ Work->pivot_case = OUT_OUT ; bestcost = thiscost ; Work->do_extend = do_extend ; Work->do_update = do_update ; new_fnzeros = fnzeros ; } } } /* At this point, a structural pivot has been found. */ /* It may be numerically zero, however. */ ASSERT (Work->pivot_case != EMPTY) ; DEBUG2 (("local search, best option "ID", best cost "ID"\n", Work->pivot_case, bestcost)) ; /* ====================================================================== */ /* Pivot row and column, and extension, now determined */ /* ====================================================================== */ Work->fnzeros = new_fnzeros ; /* ---------------------------------------------------------------------- */ /* finalize the pivot row and column */ /* ---------------------------------------------------------------------- */ switch (Work->pivot_case) { case IN_IN: DEBUG2 (("IN-IN option selected\n")) ; ASSERT (fnrows > 0 && fncols > 0) ; Work->pivcol_in_front = TRUE ; Work->pivrow_in_front = TRUE ; Work->pivcol = pivcol [IN] ; Work->pivrow = pivrow [IN][IN] ; Work->ccdeg = nr_in ; Work->Wrow = Fcols ; Work->rrdeg = rdeg [IN][IN] ; jj = jcand [IN] ; Work->fnrows_new = fnrows_new [IN][IN] ; Work->fncols_new = fncols_new [IN][IN] ; break ; case IN_OUT: DEBUG2 (("IN-OUT option selected\n")) ; ASSERT (fnrows >= 0 && fncols > 0) ; Work->pivcol_in_front = TRUE ; Work->pivrow_in_front = FALSE ; Work->pivcol = pivcol [IN] ; Work->pivrow = pivrow [IN][OUT] ; Work->ccdeg = nr_in ; Work->Wrow = Wio ; Work->rrdeg = rdeg [IN][OUT] ; jj = jcand [IN] ; Work->fnrows_new = fnrows_new [IN][OUT] ; Work->fncols_new = fncols_new [IN][OUT] ; break ; case OUT_IN: DEBUG2 (("OUT-IN option selected\n")) ; ASSERT (fnrows > 0 && fncols >= 0) ; Work->pivcol_in_front = FALSE ; Work->pivrow_in_front = TRUE ; Work->pivcol = pivcol [OUT] ; Work->pivrow = pivrow [OUT][IN] ; Work->ccdeg = cdeg_out ; /* Wrow might be equivalenced to Fcols (Freebie in): */ Work->Wrow = Woi ; Work->rrdeg = rdeg [OUT][IN] ; /* Work->Wrow[0..fncols-1] is not there. See Fcols instead */ jj = jcand [OUT] ; Work->fnrows_new = fnrows_new [OUT][IN] ; Work->fncols_new = fncols_new [OUT][IN] ; break ; case OUT_OUT: DEBUG2 (("OUT-OUT option selected\n")) ; ASSERT (fnrows >= 0 && fncols >= 0) ; Work->pivcol_in_front = FALSE ; Work->pivrow_in_front = FALSE ; Work->pivcol = pivcol [OUT] ; Work->pivrow = pivrow [OUT][OUT] ; Work->ccdeg = cdeg_out ; /* Wrow might be equivalenced to Wio (Freebie out): */ Work->Wrow = Woo ; Work->rrdeg = rdeg [OUT][OUT] ; jj = jcand [OUT] ; Work->fnrows_new = fnrows_new [OUT][OUT] ; Work->fncols_new = fncols_new [OUT][OUT] ; break ; } ASSERT (IMPLIES (fnrows == 0 && fncols == 0, Work->pivot_case == OUT_OUT)) ; if (!Work->pivcol_in_front && pivcol [IN] != EMPTY) { /* clear Frpos if pivcol [IN] was searched, but not selected */ for (i = fnrows ; i < cdeg_in ; i++) { Frpos [Frows [i]] = EMPTY; } } /* ---------------------------------------------------------------------- */ /* Pivot row and column have been found */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* remove pivot column from candidate pivot column set */ /* ---------------------------------------------------------------------- */ ASSERT (jj >= 0 && jj < Work->nCandidates) ; ASSERT (Work->pivcol == Work->Candidates [jj]) ; remove_candidate (jj, Work, Symbolic) ; /* ---------------------------------------------------------------------- */ /* check for frontal matrix growth */ /* ---------------------------------------------------------------------- */ DEBUG1 (("Check frontal growth:\n")) ; DEBUG1 (("fnrows_new "ID" + 1 = "ID", fnr_curr "ID"\n", Work->fnrows_new, Work->fnrows_new + 1, fnr_curr)) ; DEBUG1 (("fncols_new "ID" + 1 = "ID", fnc_curr "ID"\n", Work->fncols_new, Work->fncols_new + 1, fnc_curr)) ; Work->do_grow = (Work->fnrows_new + 1 > fnr_curr || Work->fncols_new + 1 > fnc_curr) ; if (Work->do_grow) { DEBUG0 (("\nNeed to grow frontal matrix, force do_update true\n")) ; /* If the front must grow, then apply the pending updates and remove * the current pivot rows/columns from the front prior to growing the * front. This frees up as much space as possible for the new front. */ if (!Work->do_update && fnpiv > 0) { /* This update would not have to be done if the current front * was big enough. */ Work->nforced++ ; Work->do_update = TRUE ; } } /* ---------------------------------------------------------------------- */ /* current pivot column */ /* ---------------------------------------------------------------------- */ /* c1) If pivot column index is in the current front: The pivot column pattern is in Frows [0 .. fnrows-1] and the extension is in Frows [fnrows ... fnrows+ccdeg-1]. Frpos [Frows [0 .. fnrows+ccdeg-1]] is equal to 0 .. fnrows+ccdeg-1. Wm is not needed. The values are in Wy [0 .. fnrows+ccdeg-1]. c2) Otherwise, if the pivot column index is not in the current front: c2a) If the front is being extended, old row indices in the the pivot column pattern are in Frows [0 .. fnrows-1]. All entries are in Wm [0 ... ccdeg-1], with values in Wx [0 .. ccdeg-1]. These may include entries already in Frows [0 .. fnrows-1]. Frpos [Frows [0 .. fnrows-1]] is equal to 0 .. fnrows-1. Frpos [Wm [0 .. ccdeg-1]] for new entries is < 0. c2b) If the front is not being extended, then the entire pivot column pattern is in Wm [0 .. ccdeg-1]. It includes the pivot row index. It is does not contain the pattern Frows [0..fnrows-1]. The intersection of these two sets may or may not be empty. The values are in Wx [0..ccdeg-1] In both cases c1 and c2, Frpos [Frows [0 .. fnrows-1]] is equal to 0 .. fnrows-1, which is the pattern of the current front. Any entry of Frpos that is not specified above is < 0. */ #ifndef NDEBUG DEBUG2 (("\n\nSEARCH DONE: Pivot col "ID" in: ("ID") pivot row "ID" in: ("ID ") extend: "ID"\n\n", Work->pivcol, Work->pivcol_in_front, Work->pivrow, Work->pivrow_in_front, Work->do_extend)) ; UMF_dump_rowcol (1, Numeric, Work, Work->pivcol, !Symbolic->fixQ) ; DEBUG2 (("Pivot col "ID": fnrows "ID" ccdeg "ID"\n", Work->pivcol, fnrows, Work->ccdeg)) ; if (Work->pivcol_in_front) /* case c1 */ { Int found = FALSE ; DEBUG3 (("Pivcol in front\n")) ; for (i = 0 ; i < fnrows ; i++) { row = Frows [i] ; DEBUG3 ((ID": row:: "ID" in front ", i, row)) ; ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ; ASSERT (Frpos [row] == i) ; EDEBUG3 (Wy [i]) ; if (row == Work->pivrow) { DEBUG3 ((" <- pivrow")) ; found = TRUE ; } DEBUG3 (("\n")) ; } ASSERT (found == Work->pivrow_in_front) ; found = FALSE ; for (i = fnrows ; i < fnrows + Work->ccdeg ; i++) { row = Frows [i] ; DEBUG3 ((ID": row:: "ID" (new)", i, row)) ; ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ; ASSERT (Frpos [row] == i) ; EDEBUG3 (Wy [i]) ; if (row == Work->pivrow) { DEBUG3 ((" <- pivrow")) ; found = TRUE ; } DEBUG3 (("\n")) ; } ASSERT (found == !Work->pivrow_in_front) ; } else { if (Work->do_extend) { Int found = FALSE ; DEBUG3 (("Pivcol not in front (extend)\n")) ; for (i = 0 ; i < fnrows ; i++) { row = Frows [i] ; DEBUG3 ((ID": row:: "ID" in front ", i, row)) ; ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ; ASSERT (Frpos [row] == i) ; if (row == Work->pivrow) { DEBUG3 ((" <- pivrow")) ; found = TRUE ; } DEBUG3 (("\n")) ; } ASSERT (found == Work->pivrow_in_front) ; found = FALSE ; DEBUG3 (("----\n")) ; for (i = 0 ; i < Work->ccdeg ; i++) { row = Wm [i] ; ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ; DEBUG3 ((ID": row:: "ID" ", i, row)) ; EDEBUG3 (Wx [i]) ; if (Frpos [row] < 0) { DEBUG3 ((" (new) ")) ; } if (row == Work->pivrow) { DEBUG3 ((" <- pivrow")) ; found = TRUE ; /* ... */ if (Work->pivrow_in_front) ASSERT (Frpos [row] >= 0) ; else ASSERT (Frpos [row] < 0) ; } DEBUG3 (("\n")) ; } ASSERT (found) ; } else { Int found = FALSE ; DEBUG3 (("Pivcol not in front (no extend)\n")) ; for (i = 0 ; i < Work->ccdeg ; i++) { row = Wm [i] ; ASSERT (row >= 0 && row < n_row && NON_PIVOTAL_ROW (row)) ; DEBUG3 ((ID": row:: "ID" ", i, row)) ; EDEBUG3 (Wx [i]) ; DEBUG3 ((" (new) ")) ; if (row == Work->pivrow) { DEBUG3 ((" <- pivrow")) ; found = TRUE ; } DEBUG3 (("\n")) ; } ASSERT (found) ; } } #endif /* ---------------------------------------------------------------------- */ /* current pivot row */ /* ---------------------------------------------------------------------- */ /* r1) If the pivot row index is in the current front: The pivot row pattern is in Fcols [0..fncols-1] and the extenson is in Wrow [fncols .. rrdeg-1]. If the pivot column is in the current front, then Fcols and Wrow are equivalenced. r2) If the pivot row index is not in the current front: r2a) If the front is being extended, the pivot row pattern is in Fcols [0 .. fncols-1]. New entries are in Wrow [0 .. rrdeg-1], but these may include entries already in Fcols [0 .. fncols-1]. r2b) Otherwise, the pivot row pattern is Wrow [0 .. rrdeg-1]. Fcpos [Fcols [0..fncols-1]] is (0..fncols-1) * fnr_curr. All other entries in Fcpos are < 0. These conditions are asserted below. ------------------------------------------------------------------------ Other items in Work structure that are relevant: pivcol: the pivot column index pivrow: the pivot column index rrdeg: ccdeg: fnrows: the number of rows in the currnt contribution block fncols: the number of columns in the current contribution block fnrows_new: the number of rows in the new contribution block fncols_new: the number of rows in the new contribution block ------------------------------------------------------------------------ */ #ifndef NDEBUG UMF_dump_rowcol (0, Numeric, Work, Work->pivrow, TRUE) ; DEBUG2 (("Pivot row "ID":\n", Work->pivrow)) ; if (Work->pivrow_in_front) { Int found = FALSE ; for (i = 0 ; i < fncols ; i++) { col = Fcols [i] ; DEBUG3 ((" col:: "ID" in front\n", col)) ; ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ; ASSERT (Fcpos [col] == i * fnr_curr) ; if (col == Work->pivcol) found = TRUE ; } ASSERT (found == Work->pivcol_in_front) ; found = FALSE ; ASSERT (IMPLIES (Work->pivcol_in_front, Fcols == Work->Wrow)) ; for (i = fncols ; i < Work->rrdeg ; i++) { col = Work->Wrow [i] ; ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ; ASSERT (Fcpos [col] < 0) ; if (col == Work->pivcol) found = TRUE ; else DEBUG3 ((" col:: "ID" (new)\n", col)) ; } ASSERT (found == !Work->pivcol_in_front) ; } else { if (Work->do_extend) { Int found = FALSE ; for (i = 0 ; i < fncols ; i++) { col = Fcols [i] ; DEBUG3 ((" col:: "ID" in front\n", col)) ; ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ; ASSERT (Fcpos [col] == i * fnr_curr) ; if (col == Work->pivcol) found = TRUE ; } ASSERT (found == Work->pivcol_in_front) ; found = FALSE ; for (i = 0 ; i < Work->rrdeg ; i++) { col = Work->Wrow [i] ; ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ; if (Fcpos [col] >= 0) continue ; if (col == Work->pivcol) found = TRUE ; else DEBUG3 ((" col:: "ID" (new, extend)\n", col)) ; } ASSERT (found == !Work->pivcol_in_front) ; } else { Int found = FALSE ; for (i = 0 ; i < Work->rrdeg ; i++) { col = Work->Wrow [i] ; ASSERT (col >= 0 && col < n_col && NON_PIVOTAL_COL (col)) ; if (col == Work->pivcol) found = TRUE ; else DEBUG3 ((" col:: "ID" (all new)\n", col)) ; } ASSERT (found) ; } } #endif /* ---------------------------------------------------------------------- */ /* determine whether to do scan2-row and scan2-col */ /* ---------------------------------------------------------------------- */ if (Work->do_extend) { Work->do_scan2row = (fncols > 0) ; Work->do_scan2col = (fnrows > 0) ; } else { Work->do_scan2row = (fncols > 0) && Work->pivrow_in_front ; Work->do_scan2col = (fnrows > 0) && Work->pivcol_in_front ; } /* ---------------------------------------------------------------------- */ DEBUG2 (("LOCAL SEARCH DONE: pivot column "ID" pivot row: "ID"\n", Work->pivcol, Work->pivrow)) ; DEBUG2 (("do_extend: "ID"\n", Work->do_extend)) ; DEBUG2 (("do_update: "ID"\n", Work->do_update)) ; DEBUG2 (("do_grow: "ID"\n", Work->do_grow)) ; /* ---------------------------------------------------------------------- */ /* keep track of the diagonal */ /* ---------------------------------------------------------------------- */ if (Symbolic->prefer_diagonal) { Diagonal_map = Work->Diagonal_map ; Diagonal_imap = Work->Diagonal_imap ; ASSERT (Diagonal_map != (Int *) NULL) ; ASSERT (Diagonal_imap != (Int *) NULL) ; #ifndef NDEBUG UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, Symbolic->n_col) ; #endif row2 = Diagonal_map [Work->pivcol] ; col2 = Diagonal_imap [Work->pivrow] ; if (row2 < 0) { /* this was an off-diagonal pivot row */ Work->noff_diagonal++ ; row2 = UNFLIP (row2) ; } ASSERT (Diagonal_imap [row2] == Work->pivcol) ; ASSERT (UNFLIP (Diagonal_map [col2]) == Work->pivrow) ; if (row2 != Work->pivrow) { /* swap the diagonal map to attempt to maintain symmetry later on. * Also mark the map for col2 (via FLIP) to denote that the entry * now on the diagonal is not the original entry on the diagonal. */ DEBUG0 (("Unsymmetric pivot\n")) ; Diagonal_map [Work->pivcol] = FLIP (Work->pivrow) ; Diagonal_imap [Work->pivrow] = Work->pivcol ; Diagonal_map [col2] = FLIP (row2) ; Diagonal_imap [row2] = col2 ; } ASSERT (n_row == n_col) ; #ifndef NDEBUG UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, Symbolic->n_col) ; #endif } return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_ltsolve.h0000644000175000017500000000112511674452555022361 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL double UMF_ltsolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; GLOBAL double UMF_lhsolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_element.h0000644000175000017500000000110711674452555024332 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_mem_alloc_element ( NumericType *Numeric, Int nrows, Int ncols, Int **Rows, Int **Cols, Entry **C, Int *size, Element **epout ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_symbolic.c0000644000175000017500000001272511674452555024353 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_load_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Loads a Symbolic object from a file created by umfpack_*_save_symbolic. */ #include "umf_internal.h" #include "umf_valid_symbolic.h" #include "umf_malloc.h" #include "umf_free.h" #define READ(object,type,n) \ { \ object = (type *) UMF_malloc (n, sizeof (type)) ; \ if (object == (type *) NULL) \ { \ UMFPACK_free_symbolic ((void **) &Symbolic) ; \ fclose (f) ; \ return (UMFPACK_ERROR_out_of_memory) ; \ } \ if (fread (object, sizeof (type), n, f) != (size_t) n) \ { \ UMFPACK_free_symbolic ((void **) &Symbolic) ; \ fclose (f) ; \ return (UMFPACK_ERROR_file_IO) ; \ } \ if (ferror (f)) \ { \ UMFPACK_free_symbolic ((void **) &Symbolic) ; \ fclose (f) ; \ return (UMFPACK_ERROR_file_IO) ; \ } \ } /* ========================================================================== */ /* === UMFPACK_load_symbolic ================================================ */ /* ========================================================================== */ GLOBAL Int UMFPACK_load_symbolic ( void **SymbolicHandle, char *user_filename ) { SymbolicType *Symbolic ; char *filename ; FILE *f ; *SymbolicHandle = (void *) NULL ; /* ---------------------------------------------------------------------- */ /* get the filename, or use the default name if filename is NULL */ /* ---------------------------------------------------------------------- */ if (user_filename == (char *) NULL) { filename = "symbolic.umf" ; } else { filename = user_filename ; } f = fopen (filename, "rb") ; if (!f) { return (UMFPACK_ERROR_file_IO) ; } /* ---------------------------------------------------------------------- */ /* read the Symbolic header from the file, in binary */ /* ---------------------------------------------------------------------- */ Symbolic = (SymbolicType *) UMF_malloc (1, sizeof (SymbolicType)) ; if (Symbolic == (SymbolicType *) NULL) { fclose (f) ; return (UMFPACK_ERROR_out_of_memory) ; } if (fread (Symbolic, sizeof (SymbolicType), 1, f) != 1) { (void) UMF_free ((void *) Symbolic) ; fclose (f) ; return (UMFPACK_ERROR_file_IO) ; } if (ferror (f)) { (void) UMF_free ((void *) Symbolic) ; fclose (f) ; return (UMFPACK_ERROR_file_IO) ; } if (Symbolic->valid != SYMBOLIC_VALID || Symbolic->n_row <= 0 || Symbolic->n_col <= 0 || Symbolic->nfr < 0 || Symbolic->nchains < 0 || Symbolic->esize < 0) { /* Symbolic does not point to a Symbolic object */ (void) UMF_free ((void *) Symbolic) ; fclose (f) ; return (UMFPACK_ERROR_invalid_Symbolic_object) ; } Symbolic->Cperm_init = (Int *) NULL ; Symbolic->Rperm_init = (Int *) NULL ; Symbolic->Front_npivcol = (Int *) NULL ; Symbolic->Front_parent = (Int *) NULL ; Symbolic->Front_1strow = (Int *) NULL ; Symbolic->Front_leftmostdesc = (Int *) NULL ; Symbolic->Chain_start = (Int *) NULL ; Symbolic->Chain_maxrows = (Int *) NULL ; Symbolic->Chain_maxcols = (Int *) NULL ; Symbolic->Cdeg = (Int *) NULL ; Symbolic->Rdeg = (Int *) NULL ; Symbolic->Esize = (Int *) NULL ; Symbolic->Diagonal_map = (Int *) NULL ; /* umfpack_free_symbolic can now be safely called if an error occurs */ /* ---------------------------------------------------------------------- */ /* read the rest of the Symbolic object */ /* ---------------------------------------------------------------------- */ READ (Symbolic->Cperm_init, Int, Symbolic->n_col+1) ; READ (Symbolic->Rperm_init, Int, Symbolic->n_row+1) ; READ (Symbolic->Front_npivcol, Int, Symbolic->nfr+1) ; READ (Symbolic->Front_parent, Int, Symbolic->nfr+1) ; READ (Symbolic->Front_1strow, Int, Symbolic->nfr+1) ; READ (Symbolic->Front_leftmostdesc, Int, Symbolic->nfr+1) ; READ (Symbolic->Chain_start, Int, Symbolic->nchains+1) ; READ (Symbolic->Chain_maxrows, Int, Symbolic->nchains+1) ; READ (Symbolic->Chain_maxcols, Int, Symbolic->nchains+1) ; READ (Symbolic->Cdeg, Int, Symbolic->n_col+1) ; READ (Symbolic->Rdeg, Int, Symbolic->n_row+1) ; if (Symbolic->esize > 0) { /* only when dense rows are present */ READ (Symbolic->Esize, Int, Symbolic->esize) ; } if (Symbolic->prefer_diagonal) { /* only when diagonal pivoting is prefered */ READ (Symbolic->Diagonal_map, Int, Symbolic->n_col+1) ; } /* close the file */ fclose (f) ; /* make sure the Symbolic object is valid */ if (!UMF_valid_symbolic (Symbolic)) { UMFPACK_free_symbolic ((void **) &Symbolic) ; return (UMFPACK_ERROR_invalid_Symbolic_object) ; } *SymbolicHandle = (void *) Symbolic ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_load_numeric.c0000644000175000017500000001175511674452555024176 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_load_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Loads a Numeric object from a file created by umfpack_*_save_numeric. */ #include "umf_internal.h" #include "umf_valid_numeric.h" #include "umf_malloc.h" #include "umf_free.h" #define READ(object,type,n) \ { \ object = (type *) UMF_malloc (n, sizeof (type)) ; \ if (object == (type *) NULL) \ { \ UMFPACK_free_numeric ((void **) &Numeric) ; \ fclose (f) ; \ return (UMFPACK_ERROR_out_of_memory) ; \ } \ if (fread (object, sizeof (type), n, f) != (size_t) n) \ { \ UMFPACK_free_numeric ((void **) &Numeric) ; \ fclose (f) ; \ return (UMFPACK_ERROR_file_IO) ; \ } \ if (ferror (f)) \ { \ UMFPACK_free_numeric ((void **) &Numeric) ; \ fclose (f) ; \ return (UMFPACK_ERROR_file_IO) ; \ } \ } /* ========================================================================== */ /* === UMFPACK_load_numeric ================================================= */ /* ========================================================================== */ GLOBAL Int UMFPACK_load_numeric ( void **NumericHandle, char *user_filename ) { NumericType *Numeric ; char *filename ; FILE *f ; *NumericHandle = (void *) NULL ; /* ---------------------------------------------------------------------- */ /* get the filename, or use the default name if filename is NULL */ /* ---------------------------------------------------------------------- */ if (user_filename == (char *) NULL) { filename = "numeric.umf" ; } else { filename = user_filename ; } f = fopen (filename, "rb") ; if (!f) { return (UMFPACK_ERROR_file_IO) ; } /* ---------------------------------------------------------------------- */ /* read the Numeric header from the file, in binary */ /* ---------------------------------------------------------------------- */ Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ; if (Numeric == (NumericType *) NULL) { fclose (f) ; return (UMFPACK_ERROR_out_of_memory) ; } if (fread (Numeric, sizeof (NumericType), 1, f) != 1) { (void) UMF_free ((void *) Numeric) ; fclose (f) ; return (UMFPACK_ERROR_file_IO) ; } if (ferror (f)) { (void) UMF_free ((void *) Numeric) ; fclose (f) ; return (UMFPACK_ERROR_file_IO) ; } if (Numeric->valid != NUMERIC_VALID || Numeric->n_row <= 0 || Numeric->n_col <= 0 || Numeric->npiv < 0 || Numeric->ulen < 0 || Numeric->size <= 0) { /* Numeric does not point to a NumericType object */ (void) UMF_free ((void *) Numeric) ; fclose (f) ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } Numeric->D = (Entry *) NULL ; Numeric->Rperm = (Int *) NULL ; Numeric->Cperm = (Int *) NULL ; Numeric->Lpos = (Int *) NULL ; Numeric->Lilen = (Int *) NULL ; Numeric->Lip = (Int *) NULL ; Numeric->Upos = (Int *) NULL ; Numeric->Uilen = (Int *) NULL ; Numeric->Uip = (Int *) NULL ; Numeric->Rs = (double *) NULL ; Numeric->Memory = (Unit *) NULL ; Numeric->Upattern = (Int *) NULL ; /* umfpack_free_numeric can now be safely called if an error occurs */ /* ---------------------------------------------------------------------- */ /* read the rest of the Numeric object */ /* ---------------------------------------------------------------------- */ READ (Numeric->D, Entry, MIN (Numeric->n_row, Numeric->n_col)+1) ; READ (Numeric->Rperm, Int, Numeric->n_row+1) ; READ (Numeric->Cperm, Int, Numeric->n_col+1) ; READ (Numeric->Lpos, Int, Numeric->npiv+1) ; READ (Numeric->Lilen, Int, Numeric->npiv+1) ; READ (Numeric->Lip, Int, Numeric->npiv+1) ; READ (Numeric->Upos, Int, Numeric->npiv+1) ; READ (Numeric->Uilen, Int, Numeric->npiv+1) ; READ (Numeric->Uip, Int, Numeric->npiv+1) ; if (Numeric->scale != UMFPACK_SCALE_NONE) { READ (Numeric->Rs, double, Numeric->n_row) ; } if (Numeric->ulen > 0) { READ (Numeric->Upattern, Int, Numeric->ulen+1) ; } READ (Numeric->Memory, Unit, Numeric->size) ; /* close the file */ fclose (f) ; /* make sure the Numeric object is valid */ if (!UMF_valid_numeric (Numeric)) { UMFPACK_free_numeric ((void **) &Numeric) ; return (UMFPACK_ERROR_invalid_Numeric_object) ; } *NumericHandle = (void *) Numeric ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_scale.c0000644000175000017500000000672511674452555022625 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_scale ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Applies the scale factors computed during numerical factorization to a vector. See umfpack_scale.h for more details. The LU factorization is L*U = P*R*A*Q, where P and Q are permutation matrices, and R is diagonal. This routine computes X = R * B using the matrix R stored in the Numeric object. Returns FALSE if any argument is invalid, TRUE otherwise. If R not present in the Numeric object, then R = I and no floating-point work is done. B is simply copied into X. */ #include "umf_internal.h" #include "umf_valid_numeric.h" GLOBAL Int UMFPACK_scale ( double Xx [ ], #ifdef COMPLEX double Xz [ ], #endif const double Bx [ ], #ifdef COMPLEX const double Bz [ ], #endif void *NumericHandle ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ NumericType *Numeric ; Int n, i ; double *Rs ; #ifdef COMPLEX Int split = SPLIT (Xz) && SPLIT (Bz) ; #endif Numeric = (NumericType *) NumericHandle ; if (!UMF_valid_numeric (Numeric)) { return (UMFPACK_ERROR_invalid_Numeric_object) ; } n = Numeric->n_row ; Rs = Numeric->Rs ; if (!Xx || !Bx) { return (UMFPACK_ERROR_argument_missing) ; } /* ---------------------------------------------------------------------- */ /* X = R*B or R\B */ /* ---------------------------------------------------------------------- */ if (Rs != (double *) NULL) { #ifndef NRECIPROCAL if (Numeric->do_recip) { /* multiply by the scale factors */ #ifdef COMPLEX if (split) { for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] * Rs [i] ; Xz [i] = Bz [i] * Rs [i] ; } } else { for (i = 0 ; i < n ; i++) { Xx [2*i ] = Bx [2*i ] * Rs [i] ; Xx [2*i+1] = Bx [2*i+1] * Rs [i] ; } } #else for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] * Rs [i] ; } #endif } else #endif { /* divide by the scale factors */ #ifdef COMPLEX if (split) { for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] / Rs [i] ; Xz [i] = Bz [i] / Rs [i] ; } } else { for (i = 0 ; i < n ; i++) { Xx [2*i ] = Bx [2*i ] / Rs [i] ; Xx [2*i+1] = Bx [2*i+1] / Rs [i] ; } } #else for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] / Rs [i] ; } #endif } } else { /* no scale factors, just copy B into X */ #ifdef COMPLEX if (split) { for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] ; Xz [i] = Bz [i] ; } } else { for (i = 0 ; i < n ; i++) { Xx [2*i ] = Bx [2*i ] ; Xx [2*i+1] = Bx [2*i+1] ; } } #else for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] ; } #endif } return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_extend_front.c0000644000175000017500000002670211674452555023373 0ustar sonnesonne/* ========================================================================== */ /* === UMF_extend_front ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Called by kernel. */ #include "umf_internal.h" #include "umf_extend_front.h" #include "umf_grow_front.h" /* ========================================================================== */ /* === zero_front =========================================================== */ /* ========================================================================== */ PRIVATE void zero_front ( Entry *Flblock, Entry *Fublock, Entry *Fcblock, Int fnrows, Int fncols, Int fnr_curr, Int fnc_curr, Int fnpiv, Int fnrows_extended, Int fncols_extended) { Int j, i ; Entry *F, *Fj, *Fi ; Fj = Fcblock + fnrows ; for (j = 0 ; j < fncols ; j++) { /* zero the new rows in the contribution block: */ F = Fj ; Fj += fnr_curr ; #pragma ivdep for (i = fnrows ; i < fnrows_extended ; i++) { /* CLEAR (Fcblock [i + j*fnr_curr]) ; */ CLEAR_AND_INCREMENT (F) ; } } Fj -= fnrows ; for (j = fncols ; j < fncols_extended ; j++) { /* zero the new columns in the contribution block: */ F = Fj ; Fj += fnr_curr ; #pragma ivdep for (i = 0 ; i < fnrows_extended ; i++) { /* CLEAR (Fcblock [i + j*fnr_curr]) ; */ CLEAR_AND_INCREMENT (F) ; } } Fj = Flblock + fnrows ; for (j = 0 ; j < fnpiv ; j++) { /* zero the new rows in L block: */ F = Fj ; Fj += fnr_curr ; #pragma ivdep for (i = fnrows ; i < fnrows_extended ; i++) { /* CLEAR (Flblock [i + j*fnr_curr]) ; */ CLEAR_AND_INCREMENT (F) ; } } Fi = Fublock + fncols ; for (i = 0 ; i < fnpiv ; i++) { /* zero the new columns in U block: */ F = Fi ; Fi += fnc_curr ; #pragma ivdep for (j = fncols ; j < fncols_extended ; j++) { /* CLEAR (Fublock [i*fnc_curr + j]) ; */ CLEAR_AND_INCREMENT (F) ; } } } /* ========================================================================== */ /* === UMF_extend_front ===================================================== */ /* ========================================================================== */ GLOBAL Int UMF_extend_front ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int j, i, *Frows, row, col, *Wrow, fnr2, fnc2, *Frpos, *Fcpos, *Fcols, fnrows_extended, rrdeg, ccdeg, fncols_extended, fnr_curr, fnc_curr, fnrows, fncols, pos, fnpiv, *Wm ; Entry *Wx, *Wy, *Fu, *Fl ; /* ---------------------------------------------------------------------- */ /* get current frontal matrix and check for frontal growth */ /* ---------------------------------------------------------------------- */ fnpiv = Work->fnpiv ; #ifndef NDEBUG DEBUG2 (("EXTEND FRONT\n")) ; DEBUG2 (("Work->fnpiv "ID"\n", fnpiv)) ; ASSERT (Work->Flblock == Work->Flublock + Work->nb*Work->nb) ; ASSERT (Work->Fublock == Work->Flblock + Work->fnr_curr*Work->nb) ; ASSERT (Work->Fcblock == Work->Fublock + Work->nb*Work->fnc_curr) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Work->Fcblock, Work->fnr_curr, Work->fnrows, Work->fncols) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Work->Flblock, Work->fnr_curr, Work->fnrows, fnpiv); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Work->Fublock, Work->fnc_curr, Work->fncols, fnpiv) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Work->Flublock, Work->nb, fnpiv, fnpiv) ; #endif if (Work->do_grow) { fnr2 = UMF_FRONTAL_GROWTH * Work->fnrows_new + 2 ; fnc2 = UMF_FRONTAL_GROWTH * Work->fncols_new + 2 ; if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, 1)) { DEBUGm4 (("out of memory: extend front\n")) ; return (FALSE) ; } } fnr_curr = Work->fnr_curr ; fnc_curr = Work->fnc_curr ; ASSERT (Work->fnrows_new + 1 <= fnr_curr) ; ASSERT (Work->fncols_new + 1 <= fnc_curr) ; ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ Frows = Work->Frows ; Frpos = Work->Frpos ; Fcols = Work->Fcols ; Fcpos = Work->Fcpos ; fnrows = Work->fnrows ; fncols = Work->fncols ; rrdeg = Work->rrdeg ; ccdeg = Work->ccdeg ; /* scan starts at the first new column in Fcols */ /* also scan the pivot column if it was not in the front */ Work->fscan_col = fncols ; Work->NewCols = Fcols ; /* scan1 starts at the first new row in Frows */ /* also scan the pivot row if it was not in the front */ Work->fscan_row = fnrows ; Work->NewRows = Frows ; /* ---------------------------------------------------------------------- */ /* extend row pattern of the front with the new pivot column */ /* ---------------------------------------------------------------------- */ fnrows_extended = fnrows ; fncols_extended = fncols ; #ifndef NDEBUG DEBUG2 (("Pivot col, before extension: "ID"\n", fnrows)) ; for (i = 0 ; i < fnrows ; i++) { DEBUG2 ((" "ID": row "ID"\n", i, Frows [i])) ; ASSERT (Frpos [Frows [i]] == i) ; } DEBUG2 (("Extending pivot column: pivcol_in_front: "ID"\n", Work->pivcol_in_front)) ; #endif Fl = Work->Flblock + fnpiv * fnr_curr ; if (Work->pivcol_in_front) { /* extended pattern and position already in Frows, Frpos. Values above * the diagonal are already in LU block. Values on and below the * diagonal are in Wy [0 .. fnrows_extended-1]. Copy into the L * block. */ fnrows_extended += ccdeg ; Wy = Work->Wy ; for (i = 0 ; i < fnrows_extended ; i++) { Fl [i] = Wy [i] ; #ifndef NDEBUG row = Frows [i] ; DEBUG2 ((" "ID": row "ID" ", i, row)) ; EDEBUG2 (Fl [i]) ; if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ; DEBUG2 (("\n")) ; if (i == fnrows - 1) DEBUG2 ((" :::::::\n")) ; ASSERT (row >= 0 && row < Work->n_row) ; ASSERT (Frpos [row] == i) ; #endif } } else { /* extended pattern,values is in (Wm,Wx), not yet in the front */ Entry *F ; Fu = Work->Flublock + fnpiv * Work->nb ; Wm = Work->Wm ; Wx = Work->Wx ; F = Fu ; for (i = 0 ; i < fnpiv ; i++) { CLEAR_AND_INCREMENT (F) ; } F = Fl ; for (i = 0 ; i < fnrows ; i++) { CLEAR_AND_INCREMENT (F) ; } for (i = 0 ; i < ccdeg ; i++) { row = Wm [i] ; #ifndef NDEBUG DEBUG2 ((" "ID": row "ID" (ext) ", fnrows_extended, row)) ; EDEBUG2 (Wx [i]) ; if (row == Work->pivrow) DEBUG2 ((" <- pivrow")) ; DEBUG2 (("\n")) ; ASSERT (row >= 0 && row < Work->n_row) ; #endif pos = Frpos [row] ; if (pos < 0) { pos = fnrows_extended++ ; Frows [pos] = row ; Frpos [row] = pos ; } Fl [pos] = Wx [i] ; } } ASSERT (fnrows_extended <= fnr_curr) ; /* ---------------------------------------------------------------------- */ /* extend the column pattern of the front with the new pivot row */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG6 (("Pivot row, before extension: "ID"\n", fncols)) ; for (j = 0 ; j < fncols ; j++) { DEBUG7 ((" "ID": col "ID"\n", j, Fcols [j])) ; ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ; } DEBUG6 (("Extending pivot row:\n")) ; #endif if (Work->pivrow_in_front) { if (Work->pivcol_in_front) { ASSERT (Fcols == Work->Wrow) ; for (j = fncols ; j < rrdeg ; j++) { #ifndef NDEBUG col = Fcols [j] ; DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ; ASSERT (col != Work->pivcol) ; ASSERT (col >= 0 && col < Work->n_col) ; ASSERT (Fcpos [col] < 0) ; #endif Fcpos [Fcols [j]] = j * fnr_curr ; } } else { /* OUT-IN option: pivcol not in front, but pivrow is in front */ Wrow = Work->Wrow ; ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ; if (Wrow == Fcols) { /* Wrow and Fcols are equivalenced */ for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ; ASSERT (Fcpos [col] < 0) ; /* Fcols [j] = col ; not needed */ Fcpos [col] = j * fnr_curr ; } } else { for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; DEBUG2 ((" "ID": col "ID" (ext)\n", j, col)) ; ASSERT (Fcpos [col] < 0) ; Fcols [j] = col ; Fcpos [col] = j * fnr_curr ; } } } fncols_extended = rrdeg ; } else { ASSERT (Fcols != Work->Wrow) ; Wrow = Work->Wrow ; for (j = 0 ; j < rrdeg ; j++) { col = Wrow [j] ; ASSERT (col >= 0 && col < Work->n_col) ; if (Fcpos [col] < 0) { DEBUG2 ((" col:: "ID" (ext)\n", col)) ; Fcols [fncols_extended] = col ; Fcpos [col] = fncols_extended * fnr_curr ; fncols_extended++ ; } } } /* ---------------------------------------------------------------------- */ /* pivot row and column have been extended */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG ASSERT (fncols_extended <= fnc_curr) ; ASSERT (fnrows_extended <= fnr_curr) ; DEBUG6 (("Pivot col, after ext: "ID" "ID"\n", fnrows,fnrows_extended)) ; for (i = 0 ; i < fnrows_extended ; i++) { row = Frows [i] ; DEBUG7 ((" "ID": row "ID" pos "ID" old: %d", i, row, Frpos [row], i < fnrows)) ; if (row == Work->pivrow ) DEBUG7 ((" <-- pivrow")) ; DEBUG7 (("\n")) ; ASSERT (Frpos [Frows [i]] == i) ; } DEBUG6 (("Pivot row position: "ID"\n", Frpos [Work->pivrow])) ; ASSERT (Frpos [Work->pivrow] >= 0) ; ASSERT (Frpos [Work->pivrow] < fnrows_extended) ; DEBUG6 (("Pivot row, after ext: "ID" "ID"\n", fncols,fncols_extended)) ; for (j = 0 ; j < fncols_extended ; j++) { col = Fcols [j] ; DEBUG7 ((" "ID": col "ID" pos "ID" old: %d", j, col, Fcpos [col], j < fncols)) ; if (col == Work->pivcol ) DEBUG7 ((" <-- pivcol")) ; DEBUG7 (("\n")) ; ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ; } DEBUG6 (("Pivot col position: "ID"\n", Fcpos [Work->pivcol])) ; ASSERT (Fcpos [Work->pivcol] >= 0) ; ASSERT (Fcpos [Work->pivcol] < fncols_extended * fnr_curr) ; #endif /* ---------------------------------------------------------------------- */ /* Zero the newly extended frontal matrix */ /* ---------------------------------------------------------------------- */ zero_front (Work->Flblock, Work->Fublock, Work->Fcblock, fnrows, fncols, fnr_curr, fnc_curr, fnpiv, fnrows_extended, fncols_extended) ; /* ---------------------------------------------------------------------- */ /* finalize extended row and column pattern of the frontal matrix */ /* ---------------------------------------------------------------------- */ Work->fnrows = fnrows_extended ; Work->fncols = fncols_extended ; ASSERT (fnrows_extended == Work->fnrows_new + 1) ; ASSERT (fncols_extended == Work->fncols_new + 1) ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_scale_column.c0000644000175000017500000003335111674452555023336 0ustar sonnesonne/* ========================================================================== */ /* === UMF_scale_column ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Scale the current pivot column, move the pivot row and column into place, and log the permutation. */ #include "umf_internal.h" #include "umf_scale_column.h" #include "umf_mem_free_tail_block.h" #include "umf_scale.h" /* ========================================================================== */ /* === shift_pivot_row ====================================================== */ /* ========================================================================== */ /* Except for the BLAS, most of the time is typically spent in the following * shift_pivot_row routine. It copies the pivot row into the U block, and * then fills in the whole in the C block by shifting the last row of C into * the row vacated by the pivot row. */ PRIVATE void shift_pivot_row (Entry *Fd, Entry *Fs, Entry *Fe, Int len, Int d) { Int j ; #pragma ivdep for (j = 0 ; j < len ; j++) { Fd [j] = Fs [j*d] ; Fs [j*d] = Fe [j*d] ; } } /* ========================================================================== */ /* === UMF_scale_column ===================================================== */ /* ========================================================================== */ GLOBAL void UMF_scale_column ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry pivot_value ; Entry *Fcol, *Flublock, *Flblock, *Fublock, *Fcblock ; Int k, k1, fnr_curr, fnrows, fncols, *Frpos, *Fcpos, pivrow, pivcol, *Frows, *Fcols, fnc_curr, fnpiv, *Row_tuples, nb, *Col_tuples, *Rperm, *Cperm, fspos, col2, row2 ; #ifndef NDEBUG Int *Col_degree, *Row_degree ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ fnrows = Work->fnrows ; fncols = Work->fncols ; fnpiv = Work->fnpiv ; /* ---------------------------------------------------------------------- */ Rperm = Numeric->Rperm ; Cperm = Numeric->Cperm ; /* ---------------------------------------------------------------------- */ Flublock = Work->Flublock ; Flblock = Work->Flblock ; Fublock = Work->Fublock ; Fcblock = Work->Fcblock ; fnr_curr = Work->fnr_curr ; fnc_curr = Work->fnc_curr ; Frpos = Work->Frpos ; Fcpos = Work->Fcpos ; Frows = Work->Frows ; Fcols = Work->Fcols ; pivrow = Work->pivrow ; pivcol = Work->pivcol ; ASSERT (pivrow >= 0 && pivrow < Work->n_row) ; ASSERT (pivcol >= 0 && pivcol < Work->n_col) ; #ifndef NDEBUG Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */ #endif Row_tuples = Numeric->Uip ; Col_tuples = Numeric->Lip ; nb = Work->nb ; #ifndef NDEBUG ASSERT (fnrows == Work->fnrows_new + 1) ; ASSERT (fncols == Work->fncols_new + 1) ; DEBUG1 (("SCALE COL: fnrows "ID" fncols "ID"\n", fnrows, fncols)) ; DEBUG2 (("\nFrontal matrix, including all space:\n" "fnr_curr "ID" fnc_curr "ID" nb "ID"\n" "fnrows "ID" fncols "ID" fnpiv "ID"\n", fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ; DEBUG2 (("\nJust the active part:\n")) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Flublock, nb, fnpiv, fnpiv) ; #endif /* ====================================================================== */ /* === Shift pivot row and column ======================================= */ /* ====================================================================== */ /* ---------------------------------------------------------------------- */ /* move pivot column into place */ /* ---------------------------------------------------------------------- */ /* Note that the pivot column is already in place. Just shift the last * column into the position vacated by the pivot column. */ fspos = Fcpos [pivcol] ; /* one less column in the contribution block */ fncols = --(Work->fncols) ; if (fspos != fncols * fnr_curr) { Int fs = fspos / fnr_curr ; DEBUG6 (("Shift pivot column in front\n")) ; DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fncols * fnr_curr)) ; /* ------------------------------------------------------------------ */ /* move Fe => Fs */ /* ------------------------------------------------------------------ */ /* column of the contribution block: */ { /* Fs: current position of pivot column in contribution block */ /* Fe: position of last column in contribution block */ Int i ; Entry *Fs, *Fe ; Fs = Fcblock + fspos ; Fe = Fcblock + fncols * fnr_curr ; #pragma ivdep for (i = 0 ; i < fnrows ; i++) { Fs [i] = Fe [i] ; } } /* column of the U2 block */ { /* Fs: current position of pivot column in U block */ /* Fe: last column in U block */ Int i ; Entry *Fs, *Fe ; Fs = Fublock + fs ; Fe = Fublock + fncols ; #pragma ivdep for (i = 0 ; i < fnpiv ; i++) { Fs [i * fnc_curr] = Fe [i * fnc_curr] ; } } /* move column Fe to Fs in the Fcols pattern */ col2 = Fcols [fncols] ; Fcols [fs] = col2 ; Fcpos [col2] = fspos ; } /* pivot column is no longer in the frontal matrix */ Fcpos [pivcol] = EMPTY ; #ifndef NDEBUG DEBUG2 (("\nFrontal matrix after col swap, including all space:\n" "fnr_curr "ID" fnc_curr "ID" nb "ID"\n" "fnrows "ID" fncols "ID" fnpiv "ID"\n", fnr_curr, fnc_curr, nb, fnrows, fncols, fnpiv)) ; DEBUG2 (("\nJust the active part:\n")) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv+1); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Flublock, nb, fnpiv, fnpiv+1) ; #endif /* ---------------------------------------------------------------------- */ /* move pivot row into place */ /* ---------------------------------------------------------------------- */ fspos = Frpos [pivrow] ; /* one less row in the contribution block */ fnrows = --(Work->fnrows) ; DEBUG6 (("Swap/shift pivot row in front:\n")) ; DEBUG6 (("fspos: "ID" flpos: "ID"\n", fspos, fnrows)) ; if (fspos == fnrows) { /* ------------------------------------------------------------------ */ /* move Fs => Fd */ /* ------------------------------------------------------------------ */ DEBUG6 (("row case 1\n")) ; /* row of the contribution block: */ { Int j ; Entry *Fd, *Fs ; Fd = Fublock + fnpiv * fnc_curr ; Fs = Fcblock + fspos ; #pragma ivdep for (j = 0 ; j < fncols ; j++) { Fd [j] = Fs [j * fnr_curr] ; } } /* row of the L2 block: */ if (Work->pivrow_in_front) { Int j ; Entry *Fd, *Fs ; Fd = Flublock + fnpiv ; Fs = Flblock + fspos ; #pragma ivdep for (j = 0 ; j <= fnpiv ; j++) { Fd [j * nb] = Fs [j * fnr_curr] ; } } else { Int j ; Entry *Fd, *Fs ; Fd = Flublock + fnpiv ; Fs = Flblock + fspos ; #pragma ivdep for (j = 0 ; j < fnpiv ; j++) { ASSERT (IS_ZERO (Fs [j * fnr_curr])) ; CLEAR (Fd [j * nb]) ; } Fd [fnpiv * nb] = Fs [fnpiv * fnr_curr] ; } } else { /* ------------------------------------------------------------------ */ /* move Fs => Fd */ /* move Fe => Fs */ /* ------------------------------------------------------------------ */ DEBUG6 (("row case 2\n")) ; /* this is the most common case, by far */ /* row of the contribution block: */ { /* Fd: destination of pivot row on U block */ /* Fs: current position of pivot row in contribution block */ /* Fe: position of last row in contribution block */ Entry *Fd, *Fs, *Fe ; Fd = Fublock + fnpiv * fnc_curr ; Fs = Fcblock + fspos ; Fe = Fcblock + fnrows ; shift_pivot_row (Fd, Fs, Fe, fncols, fnr_curr) ; } /* row of the L2 block: */ if (Work->pivrow_in_front) { /* Fd: destination of pivot row in LU block */ /* Fs: current position of pivot row in L block */ /* Fe: last row in L block */ Int j ; Entry *Fd, *Fs, *Fe ; Fd = Flublock + fnpiv ; Fs = Flblock + fspos ; Fe = Flblock + fnrows ; #pragma ivdep for (j = 0 ; j <= fnpiv ; j++) { Fd [j * nb] = Fs [j * fnr_curr] ; Fs [j * fnr_curr] = Fe [j * fnr_curr] ; } } else { Int j ; Entry *Fd, *Fs, *Fe ; Fd = Flublock + fnpiv ; Fs = Flblock + fspos ; Fe = Flblock + fnrows ; #pragma ivdep for (j = 0 ; j < fnpiv ; j++) { ASSERT (IS_ZERO (Fs [j * fnr_curr])) ; CLEAR (Fd [j * nb]) ; Fs [j * fnr_curr] = Fe [j * fnr_curr] ; } Fd [fnpiv * nb] = Fs [fnpiv * fnr_curr] ; Fs [fnpiv * fnr_curr] = Fe [fnpiv * fnr_curr] ; } /* move row Fe to Fs in the Frows pattern */ row2 = Frows [fnrows] ; Frows [fspos] = row2 ; Frpos [row2] = fspos ; } /* pivot row is no longer in the frontal matrix */ Frpos [pivrow] = EMPTY ; #ifndef NDEBUG DEBUG2 (("\nFrontal matrix after row swap, including all space:\n" "fnr_curr "ID" fnc_curr "ID" nb "ID"\n" "fnrows "ID" fncols "ID" fnpiv "ID"\n", Work->fnr_curr, Work->fnc_curr, Work->nb, Work->fnrows, Work->fncols, Work->fnpiv)) ; DEBUG2 (("\nJust the active part:\n")) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Fcblock, fnr_curr, fnrows, fncols) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Flblock, fnr_curr, fnrows, fnpiv+1); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Fublock, fnc_curr, fncols, fnpiv+1) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Flublock, nb, fnpiv+1, fnpiv+1) ; #endif /* ---------------------------------------------------------------------- */ /* Frpos [row] >= 0 for each row in pivot column pattern. */ /* offset into pattern is given by: */ /* Frpos [row] == offset - 1 */ /* Frpos [pivrow] is EMPTY */ /* Fcpos [col] >= 0 for each col in pivot row pattern. */ /* Fcpos [col] == (offset - 1) * fnr_curr */ /* Fcpos [pivcol] is EMPTY */ /* Fcols [0..fncols-1] is the pivot row pattern (excl pivot cols) */ /* Frows [0..fnrows-1] is the pivot col pattern (excl pivot rows) */ /* ====================================================================== */ /* === scale pivot column =============================================== */ /* ====================================================================== */ /* pivot column (except for pivot entry itself) */ Fcol = Flblock + fnpiv * fnr_curr ; /* fnpiv-th pivot in frontal matrix located in Flublock (fnpiv, fnpiv) */ pivot_value = Flublock [fnpiv + fnpiv * nb] ; /* this is the kth global pivot */ k = Work->npiv + fnpiv ; DEBUG4 (("Pivot value: ")) ; EDEBUG4 (pivot_value) ; DEBUG4 (("\n")) ; UMF_scale (fnrows, pivot_value, Fcol) ; /* ---------------------------------------------------------------------- */ /* deallocate the pivot row and pivot column tuples */ /* ---------------------------------------------------------------------- */ UMF_mem_free_tail_block (Numeric, Row_tuples [pivrow]) ; UMF_mem_free_tail_block (Numeric, Col_tuples [pivcol]) ; Row_tuples [pivrow] = 0 ; Col_tuples [pivcol] = 0 ; DEBUG5 (("number of pivots prior to this one: "ID"\n", k)) ; ASSERT (NON_PIVOTAL_ROW (pivrow)) ; ASSERT (NON_PIVOTAL_COL (pivcol)) ; /* save row and column inverse permutation */ k1 = ONES_COMPLEMENT (k) ; Rperm [pivrow] = k1 ; /* aliased with Row_degree */ Cperm [pivcol] = k1 ; /* aliased with Col_degree */ ASSERT (!NON_PIVOTAL_ROW (pivrow)) ; ASSERT (!NON_PIVOTAL_COL (pivcol)) ; /* ---------------------------------------------------------------------- */ /* Keep track of the pivot order. This is the kth pivot row and column. */ /* ---------------------------------------------------------------------- */ /* keep track of pivot rows and columns in the LU, L, and U blocks */ ASSERT (fnpiv < MAXNB) ; Work->Pivrow [fnpiv] = pivrow ; Work->Pivcol [fnpiv] = pivcol ; /* ====================================================================== */ /* === one step in the factorization is done ============================ */ /* ====================================================================== */ /* One more step is done, except for pending updates to the U and C blocks * of this frontal matrix. Those are saved up, and applied by * UMF_blas3_update when enough pivots have accumulated. Also, the * LU factors for these pending pivots have not yet been stored. */ Work->fnpiv++ ; #ifndef NDEBUG DEBUG7 (("Current frontal matrix: (after pivcol scale)\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.h0000644000175000017500000000115711674452555022156 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_kernel ( const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_symbolic_usage.c0000644000175000017500000000276711674452555023706 0ustar sonnesonne/* ========================================================================== */ /* === UMF_symbolic_usage =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Returns the final size of the Symbolic object, in Units */ #include "umf_internal.h" #include "umf_symbolic_usage.h" GLOBAL double UMF_symbolic_usage ( Int n_row, Int n_col, Int nchains, Int nfr, Int esize, /* zero if no dense rows. Otherwise, equal to the * number of non-singleton, non-empty columns */ Int prefer_diagonal ) { double units ; units = DUNITS (SymbolicType, 1) /* Symbolic structure */ + 2 * DUNITS (Int, n_col+1) /* Cperm_init, Cdeg */ + 2 * DUNITS (Int, n_row+1) /* Rperm_init, Rdeg */ + 3 * DUNITS (Int, nchains+1) /* Chain_ */ + 4 * DUNITS (Int, nfr+1) ; /* Front_ */ /* if dense rows are present */ units += DUNITS (Int, esize) ; /* Esize */ /* for diagonal pivoting */ if (prefer_diagonal) { units += DUNITS (Int, n_col+1) ; /* Diagonal_map */ } return (units) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_garbage_collection.c0000644000175000017500000005143511674452555024500 0ustar sonnesonne/* ========================================================================== */ /* === UMF_garbage_collection =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Compress the elements at the tail of Numeric->Memory, and delete the tuples. Elements are renumbered. The new numbering space is compressed, and in the order of element creation (original elements of A first, followed by the new elements in the order that they were formed). Only called by UMF_get_memory. There are 5 ways in which garbage collection can be performed: Allocate a new working array for the current frontal matrix. In this case, there are never any pivot rows/columns in the current frontal matrix (fnpiv = 0), and the old working array for the current frontal matrix can always be fully compacted, to fnrows-by-fncols. UMF_kernel : UMF_extend : UMF_grow_front : UMF_get_memory UMF_kernel : UMF_init_front : UMF_grow_front : UMF_get_memory UMF_kernel : UMF_start_front : UMF_grow_front : UMF_get_memory Allocate a new element. In this case, UMF_grow_front may or may not be subsequently called, depending on Work->do_grow. There are never any pivot rows/columns in the current frontal matrix (fnpiv=0), but one may be added if UMF_init_front is to be called just after UMF_create_element. If do_grow is true, then the current front can be fully compacted, to fnrows-by-fncols. Otherwise, it can only be partially compacted, to MAX (fnrows, fnrows_new + 1) -by- MAX (fncols, fncols_new + 1). UMF_kernel : UMF_create_element : UMF_get_memory Allocate rows of L and columns of U. In this case, the current frontal matrix is only partially compacted, to (fnrows_new + 1)-by- (fncols_new + 1). There are pivots in the frontal matrix (fnpiv > 0). UMF_kernel : UMF_store_lu : UMF_get_memory */ #include "umf_internal.h" #include "umf_garbage_collection.h" GLOBAL void UMF_garbage_collection ( NumericType *Numeric, WorkType *Work, Int drnew, /* compact current front to drnew-by-dcnew */ Int dcnew, Int do_Fcpos ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int size, e, n_row, n_col, nrows, ncols, nrowsleft, ncolsleft, prevsize, csize, size2, i2, j2, i, j, cdeg, rdeg, *E, row, col, *Rows, *Cols, *Rows2, *Cols2, nel, e2, *Row_tuples, *Col_tuples, *Row_degree, *Col_degree ; Entry *C, *C1, *C3, *C2 ; Unit *psrc, *pdest, *p, *pnext ; Element *epsrc, *epdest ; #ifndef NDEBUG Int nmark ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */ Row_tuples = Numeric->Uip ; Col_tuples = Numeric->Lip ; E = Work->E ; n_row = Work->n_row ; n_col = Work->n_col ; /* note that the tuple lengths (Col_tlen and Row_tlen) are updated, but */ /* the tuple lists themselves are stale and are about to be destroyed */ /* and recreated. Do not attempt to scan them until they are recreated. */ #ifndef NDEBUG DEBUGm1 (("::::GARBAGE COLLECTION::::\n")) ; UMF_dump_memory (Numeric) ; #endif Numeric->ngarbage++ ; /* ---------------------------------------------------------------------- */ /* delete the tuple lists by marking the blocks as free */ /* ---------------------------------------------------------------------- */ /* do not modify Row_tlen and Col_tlen */ /* those are needed for UMF_build_tuples */ for (row = 0 ; row < n_row ; row++) { if (NON_PIVOTAL_ROW (row) && Row_tuples [row]) { DEBUG2 (("row "ID" tuples "ID"\n", row, Row_tuples [row])) ; p = Numeric->Memory + Row_tuples [row] - 1 ; DEBUG2 (("Freeing tuple list row "ID", p-S "ID", size "ID"\n", row, (Int) (p-Numeric->Memory), p->header.size)) ; ASSERT (p->header.size > 0) ; ASSERT (p >= Numeric->Memory + Numeric->itail) ; ASSERT (p < Numeric->Memory + Numeric->size) ; p->header.size = -p->header.size ; Row_tuples [row] = 0 ; } } for (col = 0 ; col < n_col ; col++) { if (NON_PIVOTAL_COL (col) && Col_tuples [col]) { DEBUG2 (("col "ID" tuples "ID"\n", col, Col_tuples [col])) ; p = Numeric->Memory + Col_tuples [col] - 1 ; DEBUG2 (("Freeing tuple list col "ID", p-S "ID", size "ID"\n", col, (Int) (p-Numeric->Memory), p->header.size)) ; ASSERT (p->header.size > 0) ; ASSERT (p >= Numeric->Memory + Numeric->itail) ; ASSERT (p < Numeric->Memory + Numeric->size) ; p->header.size = -p->header.size ; Col_tuples [col] = 0 ; } } /* ---------------------------------------------------------------------- */ /* mark the elements, and compress the name space */ /* ---------------------------------------------------------------------- */ nel = Work->nel ; ASSERT (nel < Work->elen) ; #ifndef NDEBUG nmark = 0 ; UMF_dump_current_front (Numeric, Work, FALSE) ; DEBUGm1 (("E [0] "ID" \n", E [0])) ; ASSERT (IMPLIES (E [0], Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ; ASSERT (IMPLIES (Work->Flublock, Work->Flublock == (Entry *) (Numeric->Memory + E [0]))) ; ASSERT ((E [0] != 0) == (Work->Flublock != (Entry *) NULL)) ; #endif e2 = 0 ; for (e = 0 ; e <= nel ; e++) /* for all elements in order of creation */ { if (E [e]) { psrc = Numeric->Memory + E [e] ; psrc-- ; /* get the header of this block */ if (e > 0) { e2++ ; /* do not renumber element zero */ } ASSERT (psrc->header.size > 0) ; psrc->header.size = e2 ; /* store the new name in the header */ #ifndef NDEBUG nmark++ ; #endif DEBUG7 ((ID":: Mark e "ID" at psrc-S "ID", new e "ID"\n", nmark, e, (Int) (psrc-Numeric->Memory), e2)) ; E [e] = 0 ; if (e == Work->prior_element) { Work->prior_element = e2 ; } } } /* all 1..e2 are now in use (element zero may or may not be in use) */ Work->nel = e2 ; nel = Work->nel ; #ifndef NDEBUG for (e = 0 ; e < Work->elen ; e++) { ASSERT (!E [e]) ; } #endif /* ---------------------------------------------------------------------- */ /* compress the elements */ /* ---------------------------------------------------------------------- */ /* point to tail marker block of size 1 + header */ psrc = Numeric->Memory + Numeric->size - 2 ; pdest = psrc ; prevsize = psrc->header.prevsize ; DEBUG7 (("Starting the compression:\n")) ; while (prevsize > 0) { /* ------------------------------------------------------------------ */ /* move up to the next element above the current header, and */ /* get the element name and size */ /* (if it is an element, the name will be positive) */ /* ------------------------------------------------------------------ */ size = prevsize ; psrc -= (size + 1) ; e = psrc->header.size ; prevsize = psrc->header.prevsize ; /* top block at tail has prevsize of 0 */ /* a free block will have a negative size, so skip it */ /* otherwise, if size >= 0, it holds the element name, not the size */ DEBUG8 (("psrc-S: "ID" prevsize: "ID" size: "ID, (Int) (psrc-Numeric->Memory), prevsize, size)) ; if (e == 0) { /* -------------------------------------------------------------- */ /* this is the current frontal matrix */ /* -------------------------------------------------------------- */ Entry *F1, *F2, *Fsrc, *Fdst ; Int c, r, k, dr, dc, gap, gap1, gap2, nb ; /* shift the frontal matrix down */ F1 = (Entry *) (psrc + 1) ; /* get the size of the current front. r and c could be zero */ k = Work->fnpiv ; dr = Work->fnr_curr ; dc = Work->fnc_curr ; r = Work->fnrows ; c = Work->fncols ; nb = Work->nb ; ASSERT ((dr >= 0 && (dr % 2) == 1) || dr == 0) ; ASSERT (drnew >= 0) ; if (drnew % 2 == 0) { /* make sure leading frontal matrix dimension is always odd */ drnew++ ; } drnew = MIN (dr, drnew) ; ASSERT ((drnew >= 0 && (drnew % 2) == 1) || drnew == 0) ; pnext = pdest ; #ifndef NDEBUG DEBUGm2 (("move front: dr "ID" dc "ID" r "ID" drnew "ID" c "ID " dcnew " ID" k "ID"\n", dr, dc, r, drnew, c, dcnew, k)) ; DEBUG7 (("\n")) ; DEBUG7 ((ID":: Move current frontal matrix from: psrc-S: "ID" \n", nmark, (Int) (psrc-Numeric->Memory))) ; nmark-- ; ASSERT (E [e] == 0) ; ASSERT (Work->Flublock == F1) ; ASSERT (Work->Flblock == Work->Flublock + nb*nb) ; ASSERT (Work->Fublock == Work->Flblock + dr*nb) ; ASSERT (Work->Fcblock == Work->Fublock + nb*dc) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Work->Fcblock, dr, r, c) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Work->Flblock, dr, r, k); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Work->Fublock, dc, c, k) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Work->Flublock, nb, k, k) ; ASSERT (r <= drnew && c <= dcnew && drnew <= dr && dcnew <= dc) ; #endif /* compact frontal matrix to drnew-by-dcnew before moving it */ /* do not compact the LU block (nb-by-nb) */ /* compact the columns of L (from dr-by-nb to drnew-by-nb) */ Fsrc = Work->Flblock ; Fdst = Work->Flblock ; ASSERT (Fdst == F1 + nb*nb) ; gap1 = dr - r ; gap2 = drnew - r ; ASSERT (gap1 >= 0) ; for (j = 0 ; j < k ; j++) { for (i = 0 ; i < r ; i++) { *Fdst++ = *Fsrc++ ; } Fsrc += gap1 ; Fdst += gap2 ; } ASSERT (Fdst == F1 + nb*nb + drnew*k) ; Fdst += drnew * (nb - k) ; /* compact the rows of U (U' from dc-by-nb to dcnew-by-nb) */ Fsrc = Work->Fublock ; ASSERT (Fdst == F1 + nb*nb + drnew*nb) ; gap1 = dc - c ; gap2 = dcnew - c ; for (i = 0 ; i < k ; i++) { for (j = 0 ; j < c ; j++) { *Fdst++ = *Fsrc++ ; } Fsrc += gap1 ; Fdst += gap2 ; } ASSERT (Fdst == F1 + nb*nb + drnew*nb + dcnew*k) ; Fdst += dcnew * (nb - k) ; /* compact the columns of C (from dr-by-dc to drnew-by-dcnew) */ Fsrc = Work->Fcblock ; ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew) ; gap1 = dr - r ; gap2 = drnew - r ; for (j = 0 ; j < c ; j++) { for (i = 0 ; i < r ; i++) { *Fdst++ = *Fsrc++ ; } Fsrc += gap1 ; Fdst += gap2 ; } ASSERT (Fdst == F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c) ; /* recompute Fcpos, if necessary */ if (do_Fcpos) { Int *Fcols, *Fcpos ; Fcols = Work->Fcols ; Fcpos = Work->Fcpos ; for (j = 0 ; j < c ; j++) { col = Fcols [j] ; ASSERT (col >= 0 && col < Work->n_col) ; ASSERT (Fcpos [col] == j * dr) ; Fcpos [col] = j * drnew ; } #ifndef NDEBUG { Int cnt = 0 ; for (j = 0 ; j < Work->n_col ; j++) { if (Fcpos [j] != EMPTY) cnt++ ; } DEBUGm2 (("Recompute Fcpos cnt "ID" c "ID"\n", cnt, c)) ; ASSERT (cnt == c) ; } #endif } #ifndef NDEBUG DEBUGm2 (("Compacted front, drnew "ID" dcnew "ID"\n", drnew, dcnew)) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (F1 + nb*nb + drnew*nb + nb*dcnew, drnew, r, c) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (F1 + nb*nb, drnew, r, k) ; DEBUG7 (("U block: ")) ; UMF_dump_dense (F1 + nb*nb + drnew*nb, nb, k, c) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (F1, nb, k, k) ; #endif /* Compacted dimensions of the new frontal matrix. */ Work->fnr_curr = drnew ; Work->fnc_curr = dcnew ; Work->fcurr_size = (drnew + nb) * (dcnew + nb) ; size = UNITS (Entry, Work->fcurr_size) ; /* make sure the object doesn't evaporate. The front can have * zero size (Work->fcurr_size = 0), but the size of the memory * block containing it cannot have zero size. */ size = MAX (1, size) ; /* get the destination of frontal matrix */ pnext->header.prevsize = size ; pdest -= (size + 1) ; F2 = (Entry *) (pdest + 1) ; ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) pnext) ; ASSERT (psrc <= pdest) ; ASSERT (F1 <= F2) ; /* move the C block first */ Fsrc = F1 + nb*nb + drnew*nb + nb*dcnew + drnew*c ; Fdst = F2 + nb*nb + drnew*nb + nb*dcnew + drnew*c ; gap = drnew - r ; for (j = c-1 ; j >= 0 ; j--) { Fsrc -= gap ; Fdst -= gap ; /* move column j of C */ for (i = r-1 ; i >= 0 ; i--) { *--Fdst = *--Fsrc ; } } ASSERT (Fsrc == F1 + nb*nb + drnew*nb + nb*dcnew) ; ASSERT (Fdst == F2 + nb*nb + drnew*nb + nb*dcnew) ; /* move the U block */ Fsrc -= dcnew * (nb - k) ; Fdst -= dcnew * (nb - k) ; ASSERT (Fsrc == F1 + nb*nb + drnew*nb + dcnew*k) ; ASSERT (Fdst == F2 + nb*nb + drnew*nb + dcnew*k) ; gap = dcnew - c ; for (i = k-1 ; i >= 0 ; i--) { Fsrc -= gap ; Fdst -= gap ; for (j = c-1 ; j >= 0 ; j--) { *--Fdst = *--Fsrc ; } } ASSERT (Fsrc == F1 + nb*nb + drnew*nb) ; ASSERT (Fdst == F2 + nb*nb + drnew*nb) ; /* move the L block */ Fsrc -= drnew * (nb - k) ; Fdst -= drnew * (nb - k) ; ASSERT (Fsrc == F1 + nb*nb + drnew*k) ; ASSERT (Fdst == F2 + nb*nb + drnew*k) ; gap = drnew - r ; for (j = k-1 ; j >= 0 ; j--) { Fsrc -= gap ; Fdst -= gap ; for (i = r-1 ; i >= 0 ; i--) { *--Fdst = *--Fsrc ; } } ASSERT (Fsrc == F1 + nb*nb) ; ASSERT (Fdst == F2 + nb*nb) ; /* move the LU block */ Fsrc -= nb * (nb - k) ; Fdst -= nb * (nb - k) ; ASSERT (Fsrc == F1 + nb*k) ; ASSERT (Fdst == F2 + nb*k) ; gap = nb - k ; for (j = k-1 ; j >= 0 ; j--) { Fsrc -= gap ; Fdst -= gap ; for (i = k-1 ; i >= 0 ; i--) { *--Fdst = *--Fsrc ; } } ASSERT (Fsrc == F1) ; ASSERT (Fdst == F2) ; E [0] = (pdest + 1) - Numeric->Memory ; Work->Flublock = (Entry *) (Numeric->Memory + E [0]) ; ASSERT (Work->Flublock == F2) ; Work->Flblock = Work->Flublock + nb * nb ; Work->Fublock = Work->Flblock + drnew * nb ; Work->Fcblock = Work->Fublock + nb * dcnew ; pdest->header.prevsize = 0 ; pdest->header.size = size ; #ifndef NDEBUG DEBUG7 (("After moving compressed current frontal matrix:\n")) ; DEBUG7 (("C block: ")) ; UMF_dump_dense (Work->Fcblock, drnew, r, c) ; DEBUG7 (("L block: ")) ; UMF_dump_dense (Work->Flblock, drnew, r, k); DEBUG7 (("U' block: ")) ; UMF_dump_dense (Work->Fublock, dcnew, c, k) ; DEBUG7 (("LU block: ")) ; UMF_dump_dense (Work->Flublock, nb, k, k) ; #endif } else if (e > 0) { /* -------------------------------------------------------------- */ /* this is an element, compress and move from psrc down to pdest */ /* -------------------------------------------------------------- */ #ifndef NDEBUG DEBUG7 (("\n")) ; DEBUG7 ((ID":: Move element "ID": from: "ID" \n", nmark, e, (Int) (psrc-Numeric->Memory))) ; nmark-- ; ASSERT (e <= nel) ; ASSERT (E [e] == 0) ; #endif /* -------------------------------------------------------------- */ /* get the element scalars, and pointers to C, Rows, and Cols: */ /* -------------------------------------------------------------- */ p = psrc + 1 ; GET_ELEMENT (epsrc, p, Cols, Rows, ncols, nrows, C) ; nrowsleft = epsrc->nrowsleft ; ncolsleft = epsrc->ncolsleft ; cdeg = epsrc->cdeg ; rdeg = epsrc->rdeg ; #ifndef NDEBUG DEBUG7 ((" nrows "ID" nrowsleft "ID"\n", nrows, nrowsleft)) ; DEBUG7 ((" ncols "ID" ncolsleft "ID"\n", ncols, ncolsleft)) ; DEBUG8 ((" Rows:")) ; for (i = 0 ; i < nrows ; i++) DEBUG8 ((" "ID, Rows [i])) ; DEBUG8 (("\n Cols:")) ; for (j = 0 ; j < ncols ; j++) DEBUG8 ((" "ID, Cols [j])) ; DEBUG8 (("\n")) ; #endif /* -------------------------------------------------------------- */ /* determine the layout of the new element */ /* -------------------------------------------------------------- */ csize = nrowsleft * ncolsleft ; size2 = UNITS (Element, 1) + UNITS (Int, nrowsleft + ncolsleft) + UNITS (Entry, csize) ; DEBUG7 (("Old size "ID" New size "ID"\n", size, size2)) ; pnext = pdest ; pnext->header.prevsize = size2 ; pdest -= (size2 + 1) ; ASSERT (size2 <= size) ; ASSERT ((unsigned Int) psrc + 1 + size <= (unsigned Int) pnext) ; ASSERT (psrc <= pdest) ; p = pdest + 1 ; epdest = (Element *) p ; p += UNITS (Element, 1) ; Cols2 = (Int *) p ; Rows2 = Cols2 + ncolsleft ; p += UNITS (Int, nrowsleft + ncolsleft) ; C2 = (Entry *) p ; ASSERT (epdest >= epsrc) ; ASSERT (Rows2 >= Rows) ; ASSERT (Cols2 >= Cols) ; ASSERT (C2 >= C) ; ASSERT (p + UNITS (Entry, csize) == pnext) ; /* -------------------------------------------------------------- */ /* move the contribution block */ /* -------------------------------------------------------------- */ /* overlap = psrc + size + 1 > pdest ; */ if (nrowsleft < nrows || ncolsleft < ncols) { /* ---------------------------------------------------------- */ /* compress contribution block in place prior to moving it */ /* ---------------------------------------------------------- */ DEBUG7 (("Compress C in place prior to move:\n")); #ifndef NDEBUG UMF_dump_dense (C, nrows, nrows, ncols) ; #endif C1 = C ; C3 = C ; for (j = 0 ; j < ncols ; j++) { if (Cols [j] >= 0) { for (i = 0 ; i < nrows ; i++) { if (Rows [i] >= 0) { *C3++ = C1 [i] ; } } } C1 += nrows ; } ASSERT (C3-C == csize) ; DEBUG8 (("Newly compressed contrib. block (all in use):\n")) ; #ifndef NDEBUG UMF_dump_dense (C, nrowsleft, nrowsleft, ncolsleft) ; #endif } /* shift the contribution block down */ C += csize ; C2 += csize ; for (i = 0 ; i < csize ; i++) { *--C2 = *--C ; } /* -------------------------------------------------------------- */ /* move the row indices */ /* -------------------------------------------------------------- */ i2 = nrowsleft ; for (i = nrows - 1 ; i >= 0 ; i--) { ASSERT (Rows2+i2 >= Rows+i) ; if (Rows [i] >= 0) { Rows2 [--i2] = Rows [i] ; } } ASSERT (i2 == 0) ; j2 = ncolsleft ; for (j = ncols - 1 ; j >= 0 ; j--) { ASSERT (Cols2+j2 >= Cols+j) ; if (Cols [j] >= 0) { Cols2 [--j2] = Cols [j] ; } } ASSERT (j2 == 0) ; /* -------------------------------------------------------------- */ /* construct the new header */ /* -------------------------------------------------------------- */ /* E [0...e] is now valid */ E [e] = (pdest + 1) - Numeric->Memory ; epdest = (Element *) (pdest + 1) ; epdest->next = EMPTY ; /* destroys the son list */ epdest->ncols = ncolsleft ; epdest->nrows = nrowsleft ; epdest->ncolsleft = ncolsleft ; epdest->nrowsleft = nrowsleft ; epdest->rdeg = rdeg ; epdest->cdeg = cdeg ; ASSERT (size2 <= size) ; pdest->header.prevsize = 0 ; pdest->header.size = size2 ; DEBUG7 (("After moving it:\n")) ; #ifndef NDEBUG UMF_dump_element (Numeric, Work, e, FALSE) ; #endif } #ifndef NDEBUG else { DEBUG8 ((" free\n")) ; } #endif DEBUG7 (("psrc "ID" tail "ID"\n", (Int) (psrc-Numeric->Memory), Numeric->itail)) ; } ASSERT (psrc == Numeric->Memory + Numeric->itail) ; ASSERT (nmark == 0) ; /* ---------------------------------------------------------------------- */ /* final tail pointer */ /* ---------------------------------------------------------------------- */ ASSERT (pdest >= Numeric->Memory + Numeric->itail) ; Numeric->itail = pdest - Numeric->Memory ; pdest->header.prevsize = 0 ; Numeric->ibig = EMPTY ; Numeric->tail_usage = Numeric->size - Numeric->itail ; /* ---------------------------------------------------------------------- */ /* clear the unused E [nel+1 .. Work->elen - 1] */ /* ---------------------------------------------------------------------- */ for (e = nel+1 ; e < Work->elen ; e++) { E [e] = 0 ; } #ifndef NDEBUG UMF_dump_packed_memory (Numeric, Work) ; #endif DEBUG8 (("::::GARBAGE COLLECTION DONE::::\n")) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.h0000644000175000017500000000100311674452555023640 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_create_element ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.h0000644000175000017500000000076411674452555022216 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL double UMF_usolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_assemble.h0000644000175000017500000000106411674452555022466 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_assemble ( NumericType *Numeric, WorkType *Work ) ; GLOBAL void UMF_assemble_fixq ( NumericType *Numeric, WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.c0000644000175000017500000000425411674452555025077 0ustar sonnesonne/* ========================================================================== */ /* === UMF_mem_init_memoryspace ============================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ #include "umf_internal.h" #include "umf_mem_init_memoryspace.h" /* initialize the LU and element workspace (Numeric->Memory) */ GLOBAL void UMF_mem_init_memoryspace ( NumericType *Numeric ) { Unit *p ; ASSERT (Numeric != (NumericType *) NULL) ; ASSERT (Numeric->Memory != (Unit *) NULL) ; ASSERT (Numeric->size >= 3) ; DEBUG0 (("Init memory space, size "ID"\n", Numeric->size)) ; Numeric->ngarbage = 0 ; Numeric->nrealloc = 0 ; Numeric->ncostly = 0 ; Numeric->ibig = EMPTY ; Numeric->ihead = 0 ; Numeric->itail = Numeric->size ; #ifndef NDEBUG UMF_allocfail = FALSE ; #endif /* allocate the 2-unit tail marker block and initialize it */ Numeric->itail -= 2 ; p = Numeric->Memory + Numeric->itail ; DEBUG2 (("p "ID" tail "ID"\n", (Int) (p-Numeric->Memory), Numeric->itail)) ; Numeric->tail_usage = 2 ; p->header.prevsize = 0 ; p->header.size = 1 ; /* allocate a 1-unit head marker block at the head of memory */ /* this is done so that an offset of zero is treated as a NULL pointer */ Numeric->ihead++ ; /* initial usage in Numeric->Memory */ Numeric->max_usage = 3 ; Numeric->init_usage = Numeric->max_usage ; /* Note that UMFPACK_*symbolic ensures that Numeric->Memory is of size */ /* at least 3, so this initialization will always succeed. */ #ifndef NDEBUG DEBUG2 (("init_memoryspace, all free (except one unit at head\n")) ; UMF_dump_memory (Numeric) ; #endif } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_config.h0000644000175000017500000002762711674452555022155 0ustar sonnesonne/* ========================================================================== */ /* === umf_config.h ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* This file controls the compile-time configuration of UMFPACK. Modify the UFconfig/UFconfig.mk file and this file if necessary, to control these options. The following flags may be given as options to your C compiler (as in "cc -DNSUNPERF", for example). These flags are normally placed in your UMFPACK_CONFIG string, defined in the UFconfig/UFconfig.mk file. All of these options, except for the timer, are for accessing the BLAS. -DNSUNPERF Applies only to Sun Solaris. If -DNSUNPERF is set, then the Sun Performance Library BLAS will not be used. The Sun Performance Library BLAS is used by default when compiling the C-callable libumfpack.a library on Sun Solaris. -DLONGBLAS -DNPOSIX If -DNPOSIX is set, then your Unix operating system is not POSIX- compliant, and the POSIX routines sysconf ( ) and times ( ) routines are not used. These routines provide CPU time and wallclock time information. If -DNPOSIX is set, then the ANSI C clock ( ) routine is used. If -DNPOSIX is not set, then sysconf ( ) and times ( ) are used in umfpack_tic and umfpack_toc. See umfpack_tictoc.c for more information. The default is to use the POSIX routines, except for Windows, which is not POSIX-compliant. -DGETRUSAGE If -DGETRUSAGE is set, then your system's getrusage ( ) routine will be used for getting the process CPU time. Otherwise the ANSI C clock ( ) routine will be used. The default is to use getrusage ( ) on Unix systems, and to use clock on all other architectures. -DNO_TIMER If -DNO_TIMER is set, then no timing routines are used at all. -DNRECIPROCAL This option controls a tradeoff between speed and accuracy. Using -DNRECIPROCAL can lead to more accurate results, but with perhaps some cost in performance, particularly if floating-point division is much more costly than floating-point multiplication. This option determines the method used to scale the pivot column. If set, or if the absolute value of the pivot is < 1e-12 (or is a NaN), then the pivot column is divided by the pivot value. Otherwise, the reciprocal of the pivot value is computed, and the pivot column is multiplied by (1/pivot). Multiplying by the reciprocal can be slightly less accurate than dividing by the pivot, but it is often faster. See umf_scale.c. This has a small effect on the performance of UMFPACK, at least on a Pentium 4M. It may have a larger effect on other architectures where floating-point division is much more costly than floating- point multiplication. The RS 6000 is one such example. By default, the method chosen is to multiply by the reciprocal (sacrificing accuracy for speed), except when compiling UMFPACK as a built-in routine in MATLAB, or when gcc is being used. When MATHWORKS is defined, -DNRECIPROCAL is forced on, and the pivot column is divided by the pivot value. The only way of using the other method in this case is to edit this file. If -DNRECIPROCAL is enabled, then the row scaling factors are always applied by dividing each row by the scale factor, rather than multiplying by the reciprocal. If -DNRECIPROCAL is not enabled (the default case), then the scale factors are normally applied by multiplying by the reciprocal. If, however, the smallest scale factor is tiny, then the scale factors are applied via division. -DNO_DIVIDE_BY_ZERO If the pivot is zero, and this flag is set, then no divide-by-zero occurs. The following options are controlled by amd_internal.h: -DMATLAB_MEX_FILE This flag is turned on when compiling the umfpack mexFunction for use in MATLAB. The -DNRECIPROCAL flag is forced on (more accurate, slightly slower). The umfpack mexFunction always returns L*U = P*(R\A)*Q. -DMATHWORKS This flag is turned on when compiling umfpack as a built-in routine in MATLAB. The -DNRECIPROCAL flag is forced on. -DNDEBUG Debugging mode (if NDEBUG is not defined). The default, of course, is no debugging. Turning on debugging takes some work (see below). If you do not edit this file, then debugging is turned off anyway, regardless of whether or not -DNDEBUG is specified in your compiler options. */ /* ========================================================================== */ /* === AMD configuration ==================================================== */ /* ========================================================================== */ /* NDEBUG, PRINTF defined in amd_internal.h */ /* ========================================================================== */ /* === reciprocal option ==================================================== */ /* ========================================================================== */ /* Force the definition NRECIPROCAL when MATHWORKS or MATLAB_MEX_FILE * are defined. Do not multiply by the reciprocal in those cases. */ #ifndef NRECIPROCAL #if defined (MATHWORKS) || defined (MATLAB_MEX_FILE) #define NRECIPROCAL #endif #endif /* ========================================================================== */ /* === Microsoft Windows configuration ====================================== */ /* ========================================================================== */ #if defined (UMF_WINDOWS) || defined (UMF_MINGW) /* Windows isn't Unix. Profound. */ #define NPOSIX #endif /* ========================================================================== */ /* === 0-based or 1-based printing ========================================== */ /* ========================================================================== */ #if defined (MATLAB_MEX_FILE) && defined (NDEBUG) /* In MATLAB, matrices are 1-based to the user, but 0-based internally. */ /* One is added to all row and column indices when printing matrices */ /* for the MATLAB user. The +1 shift is turned off when debugging. */ #define INDEX(i) ((i)+1) #else /* In ANSI C, matrices are 0-based and indices are reported as such. */ /* This mode is also used for debug mode, and if MATHWORKS is defined rather */ /* than MATLAB_MEX_FILE. */ #define INDEX(i) (i) #endif /* ========================================================================== */ /* === Timer ================================================================ */ /* ========================================================================== */ /* If you have the getrusage routine (all Unix systems I've test do), then use that. Otherwise, use the ANSI C clock function. Note that on many systems, the ANSI clock function wraps around after only 2147 seconds, or about 36 minutes. BE CAREFUL: if you compare the run time of UMFPACK with other sparse matrix packages, be sure to use the same timer. See umfpack_tictoc.c for the timer used internally by UMFPACK. See also umfpack_timer.c for the timer used in an earlier version of UMFPACK. That timer is still available as a user-callable routine, but it is no longer used internally by UMFPACK. */ /* Sun Solaris, SGI Irix, Linux, Compaq Alpha, and IBM RS 6000 all have */ /* getrusage. It's in BSD unix, so perhaps all unix systems have it. */ #if defined (UMF_SOL2) || defined (UMF_SGI) || defined (UMF_LINUX) \ || defined (UMF_ALPHA) || defined (UMF_AIX) || defined (UMF_CYGWIN) #define GETRUSAGE #endif /* ========================================================================== */ /* === BLAS ================================================================= */ /* ========================================================================== */ #include "cholmod_blas.h" /* -------------------------------------------------------------------------- */ /* DGEMM */ /* -------------------------------------------------------------------------- */ /* C = C - A*B', where: * A is m-by-k with leading dimension ldac * B is k-by-n with leading dimension ldb * C is m-by-n with leading dimension ldac */ #ifdef COMPLEX #define BLAS_GEMM(m,n,k,A,B,ldb,C,ldac) \ { \ double alpha [2] = {-1,0}, beta [2] = {1,0} ; \ BLAS_zgemm ("N", "T", m, n, k, alpha, (double *) A, ldac, \ (double *) B, ldb, beta, (double *) C, ldac) ; \ } #else #define BLAS_GEMM(m,n,k,A,B,ldb,C,ldac) \ { \ double alpha = -1, beta = 1 ; \ BLAS_dgemm ("N", "T", m, n, k, &alpha, A, ldac, B, ldb, &beta, C, ldac) ; \ } #endif /* -------------------------------------------------------------------------- */ /* GER */ /* -------------------------------------------------------------------------- */ /* A = A - x*y', where: * A is m-by-n with leading dimension d x is a column vector with stride 1 y is a column vector with stride 1 */ #ifdef COMPLEX #define BLAS_GER(m,n,x,y,A,d) \ { \ double alpha [2] = {-1,0} ; \ BLAS_zgeru (m, n, alpha, (double *) x, 1, (double *) y, 1, \ (double *) A, d) ; \ } #else #define BLAS_GER(m,n,x,y,A,d) \ { \ double alpha = -1 ; \ BLAS_dger (m, n, &alpha, x, 1, y, 1, A, d) ; \ } #endif /* -------------------------------------------------------------------------- */ /* GEMV */ /* -------------------------------------------------------------------------- */ /* y = y - A*x, where A is m-by-n with leading dimension d, x is a column vector with stride 1 y is a column vector with stride 1 */ #ifdef COMPLEX #define BLAS_GEMV(m,n,A,x,y,d) \ { \ double alpha [2] = {-1,0}, beta [2] = {1,0} ; \ BLAS_zgemv ("N", m, n, alpha, (double *) A, d, (double *) x, 1, beta, \ (double *) y, 1) ; \ } #else #define BLAS_GEMV(m,n,A,x,y,d) \ { \ double alpha = -1, beta = 1 ; \ BLAS_dgemv ("N", m, n, &alpha, A, d, x, 1, &beta, y, 1) ; \ } #endif /* -------------------------------------------------------------------------- */ /* TRSV */ /* -------------------------------------------------------------------------- */ /* solve Lx=b, where: * B is a column vector (m-by-1) with leading dimension d * A is m-by-m with leading dimension d */ #ifdef COMPLEX #define BLAS_TRSV(m,A,b,d) \ { \ BLAS_ztrsv ("L", "N", "U", m, (double *) A, d, (double *) b, 1) ; \ } #else #define BLAS_TRSV(m,A,b,d) \ { \ BLAS_dtrsv ("L", "N", "U", m, A, d, b, 1) ; \ } #endif /* -------------------------------------------------------------------------- */ /* TRSM */ /* -------------------------------------------------------------------------- */ /* solve XL'=B where: * B is m-by-n with leading dimension ldb * A is n-by-n with leading dimension lda */ #ifdef COMPLEX #define BLAS_TRSM_RIGHT(m,n,A,lda,B,ldb) \ { \ double alpha [2] = {1,0} ; \ BLAS_ztrsm ("R", "L", "T", "U", m, n, alpha, (double *) A, lda, \ (double *) B, ldb) ; \ } #else #define BLAS_TRSM_RIGHT(m,n,A,lda,B,ldb) \ { \ double alpha = 1 ; \ BLAS_dtrsm ("R", "L", "T", "U", m, n, &alpha, A, lda, B, ldb) ; \ } #endif /* -------------------------------------------------------------------------- */ /* SCAL */ /* -------------------------------------------------------------------------- */ /* x = s*x, where x is a stride-1 vector of length n */ #ifdef COMPLEX #define BLAS_SCAL(n,s,x) \ { \ double alpha [2] ; \ alpha [0] = REAL_COMPONENT (s) ; \ alpha [1] = IMAG_COMPONENT (s) ; \ BLAS_zscal (n, alpha, (double *) x, 1) ; \ } #else #define BLAS_SCAL(n,s,x) \ { \ double alpha = REAL_COMPONENT (s) ; \ BLAS_dscal (n, &alpha, (double *) x, 1) ; \ } #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_internal.h0000644000175000017500000006330411674452555022514 0ustar sonnesonne/* ========================================================================== */ /* === umf_internal.h ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* This file is for internal use in UMFPACK itself, and should not be included in user code. Use umfpack.h instead. User-accessible file names and routine names all start with the letters "umfpack_". Non-user-accessible file names and routine names all start with "umf_". */ #ifndef _UMF_INTERNAL #define _UMF_INTERNAL /* -------------------------------------------------------------------------- */ /* ANSI standard include files */ /* -------------------------------------------------------------------------- */ /* from float.h: DBL_EPSILON */ #include /* from string.h: strcmp */ #include /* when debugging, assert.h and the assert macro are used (see umf_dump.h) */ /* -------------------------------------------------------------------------- */ /* Architecture */ /* -------------------------------------------------------------------------- */ #if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2) #define UMF_SOL2 #define UMFPACK_ARCHITECTURE "Sun Solaris" #elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI) #define UMF_SGI #define UMFPACK_ARCHITECTURE "SGI Irix" #elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86) #define UMF_LINUX #define UMFPACK_ARCHITECTURE "Linux" #elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS) #define UMF_AIX #define UMFPACK_ARCHITECTURE "IBM AIX" #elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA) #define UMF_ALPHA #define UMFPACK_ARCHITECTURE "Compaq Alpha" #elif defined (_WIN32) || defined (WIN32) #if defined (__MINGW32__) #define UMF_MINGW #elif defined (__CYGWIN32__) #define UMF_CYGWIN #else #define UMF_WINDOWS #endif #define UMFPACK_ARCHITECTURE "Microsoft Windows" #elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX) #define UMF_HP #define UMFPACK_ARCHITECTURE "HP Unix" #elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700) #define UMF_HP #define UMFPACK_ARCHITECTURE "HP 700 Unix" #else /* If the architecture is unknown, and you call the BLAS, you may need to */ /* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */ #define UMFPACK_ARCHITECTURE "unknown" #endif /* -------------------------------------------------------------------------- */ /* basic definitions (see also amd_internal.h) */ /* -------------------------------------------------------------------------- */ #define ONES_COMPLEMENT(r) (-(r)-1) /* -------------------------------------------------------------------------- */ /* AMD include file */ /* -------------------------------------------------------------------------- */ /* stdio.h, stdlib.h, limits.h, and math.h, NDEBUG definition, assert.h */ #include "amd_internal.h" /* -------------------------------------------------------------------------- */ /* MATLAB include files */ /* -------------------------------------------------------------------------- */ /* only used when compiling the UMFPACK mexFunction */ #ifdef MATLAB_MEX_FILE #include "matrix.h" #include "mex.h" #endif /* -------------------------------------------------------------------------- */ /* Real/complex and int/UF_long definitions, double relops */ /* -------------------------------------------------------------------------- */ #include "umf_version.h" /* -------------------------------------------------------------------------- */ /* Compile-time configurations */ /* -------------------------------------------------------------------------- */ #include "umf_config.h" /* -------------------------------------------------------------------------- */ /* umfpack include file */ /* -------------------------------------------------------------------------- */ #include "umfpack.h" /* -------------------------------------------------------------------------- */ /* for contents of Info. This must correlate with umfpack.h */ /* -------------------------------------------------------------------------- */ #define ESTIMATE (UMFPACK_NUMERIC_SIZE_ESTIMATE - UMFPACK_NUMERIC_SIZE) #define ACTUAL 0 /* -------------------------------------------------------------------------- */ /* get a parameter from the Control array */ /* -------------------------------------------------------------------------- */ #define GET_CONTROL(i,default) \ ((Control != (double *) NULL) ? \ (SCALAR_IS_NAN (Control [i]) ? default : Control [i]) \ : default) /* -------------------------------------------------------------------------- */ /* for clearing the external degree counters */ /* -------------------------------------------------------------------------- */ #define MAX_MARK(n) Int_MAX - (2*(n)+1) /* -------------------------------------------------------------------------- */ /* convert number of Units to MBytes */ /* -------------------------------------------------------------------------- */ #define MBYTES(units) (((units) * sizeof (Unit)) / 1048576.0) /* -------------------------------------------------------------------------- */ /* dense row/column macro */ /* -------------------------------------------------------------------------- */ /* In order for a row or column to be treated as "dense", it must have more */ /* entries than the value returned by this macro. n is the dimension of the */ /* matrix, and alpha is the dense row/column control parameter. */ /* Note: this is not defined if alpha is NaN or Inf: */ #define UMFPACK_DENSE_DEGREE_THRESHOLD(alpha,n) \ ((Int) MAX (16.0, (alpha) * 16.0 * sqrt ((double) (n)))) /* -------------------------------------------------------------------------- */ /* PRINTF */ /* -------------------------------------------------------------------------- */ #define PRINTFk(k,params) { if (prl >= (k)) { PRINTF (params) ; } } #define PRINTF1(params) PRINTFk (1, params) #define PRINTF2(params) PRINTFk (2, params) #define PRINTF3(params) PRINTFk (3, params) #define PRINTF4(params) PRINTFk (4, params) #define PRINTF5(params) PRINTFk (5, params) #define PRINTF6(params) PRINTFk (6, params) /* -------------------------------------------------------------------------- */ /* Fixed control parameters */ /* -------------------------------------------------------------------------- */ /* maximum number of columns to consider at one time, in a single front */ #define MAX_CANDIDATES 128 /* reduce Numeric->Memory request by this ratio, if allocation fails */ #define UMF_REALLOC_REDUCTION (0.95) /* increase Numeric->Memory request by this ratio, if we need more */ #define UMF_REALLOC_INCREASE (1.2) /* increase the dimensions of the current frontal matrix by this factor * when it needs to grow. */ #define UMF_FRONTAL_GROWTH (1.2) /* largest BLAS block size permitted */ #define MAXNB 64 /* if abs (y) < RECIPROCAL_TOLERANCE, then compute x/y. Otherwise x*(1/y). * Ignored if NRECIPROCAL is defined */ #define RECIPROCAL_TOLERANCE 1e-12 /* -------------------------------------------------------------------------- */ /* Memory allocator */ /* -------------------------------------------------------------------------- */ /* See AMD/Source/amd_global.c and AMD/Source/amd.h for the * definition of the memory allocator used by UMFPACK. Versions 4.4 and * earlier had their memory allocator definitions here. Other global * function pointers for UMFPACK are located in umf_global.c. * * The MATLAB mexFunction uses MATLAB's memory manager and mexPrintf, while the * C-callable AMD library uses the ANSI C malloc, free, realloc, and printf * routines. */ /* -------------------------------------------------------------------------- */ /* Memory space definitions */ /* -------------------------------------------------------------------------- */ /* for memory alignment - assume double has worst case alignment */ typedef double Align ; /* get number of bytes required to hold n items of a type: */ /* note that this will not overflow, because sizeof (type) is always */ /* greater than or equal to sizeof (Int) >= 2 */ #define BYTES(type,n) (sizeof (type) * (n)) /* ceiling of (b/u). Assumes b >= 0 and u > 0 */ #define CEILING(b,u) (((b) + (u) - 1) / (u)) /* get number of Units required to hold n items of a type: */ #define UNITS(type,n) (CEILING (BYTES (type, n), sizeof (Unit))) /* same as DUNITS, but use double instead of int to avoid overflow */ #define DUNITS(type,n) (ceil (BYTES (type, (double) n) / sizeof (Unit))) union Unit_union { /* memory is allocated in multiples of Unit */ struct { Int size, /* size, in Units, of the block, excl. header block */ /* size >= 0: block is in use */ /* size < 0: block is free, of |size| Units */ prevsize ; /* size, in Units, of preceding block in S->Memory */ /* during garbage_collection, prevsize is set to -e-1 */ /* for element e, or positive (and thus a free block) */ /* otherwise */ } header ; /* block header */ Align xxxxxx ; /* force alignment of blocks (xxxxxx is never used) */ } ; typedef union Unit_union Unit ; /* get the size of an allocated block */ #define GET_BLOCK_SIZE(p) (((p)-1)->header.size) /* -------------------------------------------------------------------------- */ /* Numeric */ /* -------------------------------------------------------------------------- */ /* NUMERIC_VALID and SYMBOLIC_VALID: The different values of SYBOLIC_VALID and NUMERIC_VALID are chosen as a first defense against corrupted *Symbolic or *Numeric pointers passed to an UMFPACK routine. They also ensure that the objects are used only by the same version that created them (umfpack_di_*, umfpack_dl_*, umfpack_zi_*, or umfpack_zl_*). The values have also been changed since prior releases of the code to ensure that all routines that operate on the objects are of the same release. The values themselves are purely arbitrary. The are less than the ANSI C required minimums of INT_MAX and LONG_MAX, respectively. */ #ifdef DINT #define NUMERIC_VALID 15977 #define SYMBOLIC_VALID 41937 #endif #ifdef DLONG #define NUMERIC_VALID 399789720 #define SYMBOLIC_VALID 399192713 #endif #ifdef ZINT #define NUMERIC_VALID 17957 #define SYMBOLIC_VALID 40927 #endif #ifdef ZLONG #define NUMERIC_VALID 129987754 #define SYMBOLIC_VALID 110291734 #endif typedef struct /* NumericType */ { double flops, /* "true" flop count */ relpt, /* relative pivot tolerance used */ relpt2, /* relative pivot tolerance used for sym. */ droptol, alloc_init, /* initial allocation of Numeric->memory */ front_alloc_init, /* frontal matrix allocation parameter */ rsmin, /* smallest row sum */ rsmax, /* largest row sum */ min_udiag, /* smallest abs value on diagonal of D */ max_udiag, /* smallest abs value on diagonal of D */ rcond ; /* min (D) / max (D) */ Int scale ; Int valid ; /* set to NUMERIC_VALID, for validity check */ /* Memory space for A and LU factors */ Unit *Memory ; /* working memory for A and LU factors */ Int ihead, /* pointer to tail of LU factors, in Numeric->Memory */ itail, /* pointer to top of elements & tuples, */ /* in Numeric->Memory */ ibig, /* pointer to largest free block seen in tail */ size ; /* size of Memory, in Units */ Int *Rperm, /* pointer to row perm array, size: n+1 */ /* after UMF_kernel: Rperm [new] = old */ /* during UMF_kernel: Rperm [old] = new */ *Cperm, /* pointer to col perm array, size: n+1 */ /* after UMF_kernel: Cperm [new] = old */ /* during UMF_kernel: Cperm [old] = new */ *Upos, /* see UMFPACK_get_numeric for a description */ *Lpos, *Lip, *Lilen, *Uip, *Uilen, *Upattern ; /* pattern of last row of U (if singular) */ Int ulen, /* length of Upattern */ npiv, /* number of structural pivots found (sprank approx) */ nnzpiv ; /* number of numerical (nonzero) pivots found */ Entry *D ; /* D [i] is the diagonal entry of U */ Int do_recip ; double *Rs ; /* scale factors for the rows of A and b */ /* do_recip FALSE: Divide row i by Rs [i] */ /* do_recip TRUE: Multiply row i by Rs [i] */ Int n_row, n_col, /* A is n_row-by-n_row */ n1 ; /* number of singletons */ /* for information only: */ Int tail_usage, /* amount of memory allocated in tail */ /* head_usage is Numeric->ihead */ init_usage, /* memory usage just after UMF_kernel_init */ max_usage, /* peak memory usage (excludes internal and external */ /* fragmentation in the tail) */ ngarbage, /* number of garbage collections performed */ nrealloc, /* number of reallocations performed */ ncostly, /* number of costly reallocations performed */ isize, /* size of integer pattern of L and U */ nLentries, /* number of entries in L, excluding diagonal */ nUentries, /* number of entries in U, including diagonal */ /* Some entries may be numerically zero. */ lnz, /* number of nonzero entries in L, excl. diagonal */ all_lnz, /* lnz plus entries dropped from L */ unz, /* number of nonzero entries in U, excl. diagonal */ all_unz, /* unz plus entries dropped form U */ maxfrsize ; /* largest actual front size */ Int maxnrows, maxncols ; /* not the same as Symbolic->maxnrows/cols* */ } NumericType ; /* -------------------------------------------------------------------------- */ /* Element tuples for connecting elements together in a matrix */ /* -------------------------------------------------------------------------- */ typedef struct /* Tuple */ { /* The (e,f) tuples for the element lists */ Int e, /* element */ f ; /* contribution to the row/col appears at this offset */ } Tuple ; #define TUPLES(t) MAX (4, (t) + 1) /* Col_degree is aliased with Cperm, and Row_degree with Rperm */ #define NON_PIVOTAL_COL(col) (Col_degree [col] >= 0) #define NON_PIVOTAL_ROW(row) (Row_degree [row] >= 0) /* -------------------------------------------------------------------------- */ /* An element */ /* -------------------------------------------------------------------------- */ typedef struct /* Element */ { Int cdeg, /* external column degree + cdeg0 offset */ rdeg, /* external row degree + rdeg0 offset */ nrowsleft, /* number of rows remaining */ ncolsleft, /* number of columns remaining */ nrows, /* number of rows */ ncols, /* number of columns */ next ; /* for list link of sons, used during assembly only */ /* followed in memory by: Int col [0..ncols-1], column indices of this element row [0..nrows-1] ; row indices of this element Entry (suitably aligned, see macro below) C [0...nrows-1, 0...ncols-1] ; size of C is nrows*ncols Entry's */ } Element ; /* macros for computing pointers to row/col indices, and contribution block: */ #define GET_ELEMENT_SIZE(nr,nc) \ (UNITS (Element, 1) + UNITS (Int, (nc) + (nr)) + UNITS (Entry, (nc) * (nr))) #define DGET_ELEMENT_SIZE(nr,nc) \ (DUNITS (Element, 1) + DUNITS (Int, (nc) + (nr)) + DUNITS (Entry, (nc) * (nr))) #define GET_ELEMENT_COLS(ep,p,Cols) { \ ASSERT (p != (Unit *) NULL) ; \ ASSERT (p >= Numeric->Memory + Numeric->itail) ; \ ASSERT (p <= Numeric->Memory + Numeric->size) ; \ ep = (Element *) p ; \ p += UNITS (Element, 1) ; \ Cols = (Int *) p ; \ } #define GET_ELEMENT_PATTERN(ep,p,Cols,Rows,ncm) { \ GET_ELEMENT_COLS (ep, p, Cols) ; \ ncm = ep->ncols ; \ Rows = Cols + ncm ; \ } #define GET_ELEMENT(ep,p,Cols,Rows,ncm,nrm,C) { \ GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncm) ; \ nrm = ep->nrows ; \ p += UNITS (Int, ncm + nrm) ; \ C = (Entry *) p ; \ } /* -------------------------------------------------------------------------- */ /* Work data structure */ /* -------------------------------------------------------------------------- */ /* This data structure holds items needed only during factorization. All of this is freed when UMFPACK_numeric completes. Note that some of it is stored in the tail end of Numeric->S (namely, the Tuples and the Elements). */ typedef struct /* WorkType */ { /* ---------------------------------------------------------------------- */ /* information about each row and col of A */ /* ---------------------------------------------------------------------- */ /* Row_tuples: pointer to tuple list (alias with Numeric->Uip) Row_tlen: number of tuples (alias with Numeric->Uilen) Col_tuples: pointer to tuple list (alias with Numeric->Lip) Col_tlen: number of tuples (alias with Numeric->Lilen) Row_degree: degree of the row or column (alias Numeric->Rperm) Col_degree: degree of the row or column (alias Numeric->Cperm) The Row_degree and Col_degree are MATLAB-style colmmd approximations, are equal to the sum of the sizes of the elements (contribution blocks) in each row and column. They are maintained when elements are created and assembled. They are used only during the pivot row and column search. They are not needed to represent the pattern of the remaining matrix. */ /* ---------------------------------------------------------------------- */ /* information about each element */ /* ---------------------------------------------------------------------- */ Int *E ; /* E [0 .. Work->elen-1] element "pointers" */ /* (offsets in Numeric->Memory) */ /* ---------------------------------------------------------------------- */ /* generic workspace */ /* ---------------------------------------------------------------------- */ Entry *Wx, *Wy ; /* each of size maxnrows+1 */ Int /* Sizes: nn = MAX (n_row, n_col) */ *Wp, /* nn+1 */ *Wrp, /* n_col+1 */ *Wm, /* maxnrows+1 */ *Wio, /* maxncols+1 */ *Woi, /* maxncols+1 */ *Woo, /* MAX (maxnrows,maxncols)+1 */ *Wrow, /* pointer to Fcols, Wio, or Woi */ *NewRows, /* list of rows to scan */ *NewCols ; /* list of cols to scan */ /* ---------------------------------------------------------------------- */ Int *Lpattern, /* pattern of column of L, for one Lchain */ *Upattern, /* pattern of row of U, for one Uchain */ ulen, llen ; /* length of Upattern and Lpattern */ Int *Diagonal_map, /* used for symmetric pivoting, of size nn+1 */ *Diagonal_imap ;/* used for symmetric pivoting, of size nn+1 */ /* ---------------------------------------------------------------------- */ Int n_row, n_col, /* matrix is n_row-by-n_col */ nz, /* nonzeros in the elements for this matrix */ n1, /* number of row and col singletons */ elen, /* max possible number of elements */ npiv, /* number of pivot rows and columns so far */ ndiscard, /* number of discarded pivot columns */ Wrpflag, nel, /* elements in use are in the range 1..nel */ noff_diagonal, prior_element, rdeg0, cdeg0, rrdeg, ccdeg, Candidates [MAX_CANDIDATES], /* current candidate pivot columns */ nCandidates, /* number of candidates in Candidate set */ ksuper, firstsuper, jsuper, ncand, /* number of candidates (some not in Candidates[ ]) */ nextcand, /* next candidate to place in Candidate search set */ lo, hi, pivrow, /* current pivot row */ pivcol, /* current pivot column */ do_extend, /* true if the next pivot extends the current front */ do_update, /* true if update should be applied */ nforced, /* number of forced updates because of frontal growth */ any_skip, do_scan2row, do_scan2col, do_grow, pivot_case, frontid, /* id of current frontal matrix */ nfr ; /* number of frontal matrices */ /* ---------------------------------------------------------------------- */ /* For row-merge tree */ /* ---------------------------------------------------------------------- */ Int *Front_new1strow ; /* ---------------------------------------------------------------------- */ /* current frontal matrix, F */ /* ---------------------------------------------------------------------- */ Int Pivrow [MAXNB], Pivcol [MAXNB] ; Entry *Flublock, /* LU block, nb-by-nb */ *Flblock, /* L block, fnr_curr-by-nb */ *Fublock, /* U block, nb-by-fnc_curr, or U' fnc_curr-by-nb */ *Fcblock ; /* C block, fnr_curr-by-fnc_curr */ Int *Frows, /* Frows [0.. ]: row indices of F */ *Fcols, /* Fcols [0.. ]: column indices of F */ *Frpos, /* position of row indices in F, or -1 if not present */ /* if Frows[i] == row, then Frpos[row] == i */ *Fcpos, /* position of col indices in F, or -1 if not present */ /* if Fcols[j] == col, then */ /* Fcpos[col] == j*Work->fnr_curr */ fnrows, /* number of rows in contribution block in F */ fncols, /* number of columns in contribution block in F */ fnr_curr, /* maximum # of rows in F (leading dimension) */ fnc_curr, /* maximum # of columns in F */ fcurr_size, /* current size of F */ fnrows_max, /* max possible column-dimension (max # of rows) of F */ fncols_max, /* max possible row-dimension (max # of columns) of F */ nb, fnpiv, /* number of pivots in F */ fnzeros, /* number of explicit zero entries in LU block */ fscan_row, /* where to start scanning rows of F in UMF_assemble */ fscan_col, /* where to start scanning cols of F in UMF_assemble */ fnrows_new, /* number of new row indices in F after pivot added */ fncols_new, /* number of new col indices in F after pivot added */ pivrow_in_front, /* true if current pivot row in Frows */ pivcol_in_front ; /* true if current pivot column in Fcols */ /* ---------------------------------------------------------------------- * Current frontal matrix * ---------------------------------------------------------------------- * The current frontal matrix is held as a single block of memory allocated * from the "tail" end of Numeric->Memory. It is subdivided into four * parts: an LU block, an L block, a U block, and a C block. * * Let k = fnpiv, r = fnrows, and c = fncols for the following discussion. * Let dr = fnr_curr and dc = fnc_curr. Note that r <= dr and c <= dc. * * The LU block is of dimension nb-by-nb. The first k-by-k part holds the * "diagonal" part of the LU factors for these k pivot rows and columns. * The k pivot row and column indices in this part are Pivrow [0..k-1] and * Pivcol [0..k-1], respectively. * * The L block is of dimension dr-by-nb. It holds the k pivot columns, * except for the leading k-by-k part in the LU block. Only the leading * r-by-k part is in use. * * The U block is of dimension dc-by-nb. It holds the k pivot rows, * except for the leading k-by-k part in the LU block. It is stored in * row-oriented form. Only the leading c-by-k part is in use. * * The C block is of dimension dr-by-dc. It holds the current contribution * block. Only the leading r-by-c part is in use. The column indices in * the C block are Fcols [0..c-1], and the row indices are Frows [0..r-1]. * * dr is always odd, to avoid bad cache behavior. */ } WorkType ; /* -------------------------------------------------------------------------- */ /* Symbolic */ /* -------------------------------------------------------------------------- */ /* This is is constructed by UMFPACK_symbolic, and is needed by UMFPACK_numeric to factor the matrix. */ typedef struct /* SymbolicType */ { double num_mem_usage_est, /* estimated max Numeric->Memory size */ num_mem_size_est, /* estimated final Numeric->Memory size */ peak_sym_usage, /* peak Symbolic and SymbolicWork usage */ sym, /* symmetry of pattern */ dnum_mem_init_usage, /* min Numeric->Memory for UMF_kernel_init */ amd_lunz, /* nz in LU for AMD, with symmetric pivoting */ lunz_bound ; /* max nx in LU, for arbitrary row pivoting */ Int valid, /* set to SYMBOLIC_VALID, for validity check */ max_nchains, nchains, *Chain_start, *Chain_maxrows, *Chain_maxcols, maxnrows, /* largest number of rows in any front */ maxncols, /* largest number of columns in any front */ *Front_npivcol, /* Front_npivcol [j] = size of jth supercolumn*/ *Front_1strow, /* first row index in front j */ *Front_leftmostdesc, /* leftmost desc of front j */ *Front_parent, /* super-column elimination tree */ *Cperm_init, /* initial column ordering */ *Rperm_init, /* initial row ordering */ *Cdeg, *Rdeg, *Esize, dense_row_threshold, n1, /* number of singletons */ nempty, /* MIN (nempty_row, nempty_col) */ *Diagonal_map, /* initial "diagonal" (after 2by2) */ esize, /* size of Esize array */ nfr, n_row, n_col, /* matrix A is n_row-by-n_col */ nz, /* nz of original matrix */ nb, /* block size for BLAS 3 */ num_mem_init_usage, /* min Numeric->Memory for UMF_kernel_init */ nempty_row, nempty_col, strategy, ordering, fixQ, prefer_diagonal, nzaat, nzdiag, amd_dmax ; } SymbolicType ; /* -------------------------------------------------------------------------- */ /* for debugging only: */ /* -------------------------------------------------------------------------- */ #include "umf_dump.h" /* -------------------------------------------------------------------------- */ /* for statement coverage testing only: */ /* -------------------------------------------------------------------------- */ #ifdef TESTING /* for testing integer overflow: */ #ifdef TEST_FOR_INTEGER_OVERFLOW #undef MAX_MARK #define MAX_MARK(n) (3*(n)) #endif /* for testing out-of-memory conditions: */ #define UMF_TCOV_TEST #ifndef EXTERN #define EXTERN extern #endif GLOBAL EXTERN int umf_fail, umf_fail_lo, umf_fail_hi ; GLOBAL EXTERN int umf_realloc_fail, umf_realloc_lo, umf_realloc_hi ; /* for testing malloc count: */ #define UMF_MALLOC_COUNT #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_create_element.c0000644000175000017500000004151011674452555023642 0ustar sonnesonne/* ========================================================================== */ /* === UMF_create_element =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Factorization of a frontal matrix is complete. Create a new element for later assembly into a subsequent frontal matrix. Returns TRUE if successful, FALSE if out of memory. */ #include "umf_internal.h" #include "umf_create_element.h" #include "umf_mem_alloc_element.h" #include "umf_mem_alloc_tail_block.h" #include "umf_mem_free_tail_block.h" #include "umf_get_memory.h" /* ========================================================================== */ /* === copy_column ========================================================== */ /* ========================================================================== */ PRIVATE void copy_column (Int len, Entry *X, Entry *Y) { Int i ; #pragma ivdep for (i = 0 ; i < len ; i++) { Y [i] = X [i] ; } } /* ========================================================================== */ /* === UMF_create_element =================================================== */ /* ========================================================================== */ GLOBAL Int UMF_create_element ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int j, col, row, *Fcols, *Frows, fnrows, fncols, *Cols, len, needunits, t1, t2, size, e, i, *E, *Fcpos, *Frpos, *Rows, eloc, fnr_curr, f, got_memory, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, max_mark, *Col_degree, *Col_tlen, nn, n_row, n_col, r2, c2, do_Fcpos ; Entry *C, *Fcol ; Element *ep ; Unit *p, *Memory ; Tuple *tp, *tp1, *tp2, tuple, *tpend ; #ifndef NDEBUG DEBUG2 (("FRONTAL WRAPUP\n")) ; UMF_dump_current_front (Numeric, Work, TRUE) ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ ASSERT (Work->fnpiv == 0) ; ASSERT (Work->fnzeros == 0) ; Row_degree = Numeric->Rperm ; Row_tuples = Numeric->Uip ; Row_tlen = Numeric->Uilen ; Col_degree = Numeric->Cperm ; Col_tuples = Numeric->Lip ; Col_tlen = Numeric->Lilen ; n_row = Work->n_row ; n_col = Work->n_col ; nn = MAX (n_row, n_col) ; Fcols = Work->Fcols ; Frows = Work->Frows ; Fcpos = Work->Fcpos ; Frpos = Work->Frpos ; Memory = Numeric->Memory ; fncols = Work->fncols ; fnrows = Work->fnrows ; tp = (Tuple *) NULL ; tp1 = (Tuple *) NULL ; tp2 = (Tuple *) NULL ; /* ---------------------------------------------------------------------- */ /* add the current frontal matrix to the degrees of each column */ /* ---------------------------------------------------------------------- */ if (!Symbolic->fixQ) { /* but only if the column ordering is not fixed */ #pragma ivdep for (j = 0 ; j < fncols ; j++) { /* add the current frontal matrix to the degree */ ASSERT (Fcols [j] >= 0 && Fcols [j] < n_col) ; Col_degree [Fcols [j]] += fnrows ; } } /* ---------------------------------------------------------------------- */ /* add the current frontal matrix to the degrees of each row */ /* ---------------------------------------------------------------------- */ #pragma ivdep for (i = 0 ; i < fnrows ; i++) { /* add the current frontal matrix to the degree */ ASSERT (Frows [i] >= 0 && Frows [i] < n_row) ; Row_degree [Frows [i]] += fncols ; } /* ---------------------------------------------------------------------- */ /* Reset the external degree counters */ /* ---------------------------------------------------------------------- */ E = Work->E ; max_mark = MAX_MARK (nn) ; if (!Work->pivcol_in_front) { /* clear the external column degrees. no more Usons of current front */ Work->cdeg0 += (nn + 1) ; if (Work->cdeg0 >= max_mark) { /* guard against integer overflow. This is very rare */ DEBUG1 (("Integer overflow, cdeg\n")) ; Work->cdeg0 = 1 ; #pragma ivdep for (e = 1 ; e <= Work->nel ; e++) { if (E [e]) { ep = (Element *) (Memory + E [e]) ; ep->cdeg = 0 ; } } } } if (!Work->pivrow_in_front) { /* clear the external row degrees. no more Lsons of current front */ Work->rdeg0 += (nn + 1) ; if (Work->rdeg0 >= max_mark) { /* guard against integer overflow. This is very rare */ DEBUG1 (("Integer overflow, rdeg\n")) ; Work->rdeg0 = 1 ; #pragma ivdep for (e = 1 ; e <= Work->nel ; e++) { if (E [e]) { ep = (Element *) (Memory + E [e]) ; ep->rdeg = 0 ; } } } } /* ---------------------------------------------------------------------- */ /* clear row/col offsets */ /* ---------------------------------------------------------------------- */ if (!Work->pivrow_in_front) { #pragma ivdep for (j = 0 ; j < fncols ; j++) { Fcpos [Fcols [j]] = EMPTY ; } } if (!Work->pivcol_in_front) { #pragma ivdep for (i = 0 ; i < fnrows ; i++) { Frpos [Frows [i]] = EMPTY ; } } if (fncols <= 0 || fnrows <= 0) { /* no element to create */ DEBUG2 (("Element evaporation\n")) ; Work->prior_element = EMPTY ; return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* create element for later assembly */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG UMF_allocfail = FALSE ; if (UMF_gprob > 0) { double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; DEBUG4 (("Check random %e %e\n", rrr, UMF_gprob)) ; UMF_allocfail = rrr < UMF_gprob ; if (UMF_allocfail) DEBUGm2 (("Random garbage collection (create)\n")); } #endif needunits = 0 ; got_memory = FALSE ; eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C, &needunits, &ep) ; /* if UMF_get_memory needs to be called */ if (Work->do_grow) { /* full compaction of current frontal matrix, since UMF_grow_front will * be called next anyway. */ r2 = fnrows ; c2 = fncols ; do_Fcpos = FALSE ; } else { /* partial compaction. */ r2 = MAX (fnrows, Work->fnrows_new + 1) ; c2 = MAX (fncols, Work->fncols_new + 1) ; /* recompute Fcpos if pivot row is in the front */ do_Fcpos = Work->pivrow_in_front ; } if (!eloc) { /* Do garbage collection, realloc, and try again. */ /* Compact the current front if it needs to grow anyway. */ /* Note that there are no pivot rows or columns in the current front */ DEBUGm3 (("get_memory from umf_create_element, 1\n")) ; if (!UMF_get_memory (Numeric, Work, needunits, r2, c2, do_Fcpos)) { /* :: out of memory in umf_create_element (1) :: */ DEBUGm4 (("out of memory: create element (1)\n")) ; return (FALSE) ; /* out of memory */ } got_memory = TRUE ; Memory = Numeric->Memory ; eloc = UMF_mem_alloc_element (Numeric, fnrows, fncols, &Rows, &Cols, &C, &needunits, &ep) ; ASSERT (eloc >= 0) ; if (!eloc) { /* :: out of memory in umf_create_element (2) :: */ DEBUGm4 (("out of memory: create element (2)\n")) ; return (FALSE) ; /* out of memory */ } } e = ++(Work->nel) ; /* get the name of this new frontal matrix */ Work->prior_element = e ; DEBUG8 (("wrapup e "ID" nel "ID"\n", e, Work->nel)) ; ASSERT (e > 0 && e < Work->elen) ; ASSERT (E [e] == 0) ; E [e] = eloc ; if (Work->pivcol_in_front) { /* the new element is a Uson of the next frontal matrix */ ep->cdeg = Work->cdeg0 ; } if (Work->pivrow_in_front) { /* the new element is an Lson of the next frontal matrix */ ep->rdeg = Work->rdeg0 ; } /* ---------------------------------------------------------------------- */ /* copy frontal matrix into the new element */ /* ---------------------------------------------------------------------- */ #pragma ivdep for (i = 0 ; i < fnrows ; i++) { Rows [i] = Frows [i] ; } #pragma ivdep for (i = 0 ; i < fncols ; i++) { Cols [i] = Fcols [i] ; } Fcol = Work->Fcblock ; DEBUG0 (("copy front "ID" by "ID"\n", fnrows, fncols)) ; fnr_curr = Work->fnr_curr ; ASSERT (fnr_curr >= 0 && fnr_curr % 2 == 1) ; for (j = 0 ; j < fncols ; j++) { copy_column (fnrows, Fcol, C) ; Fcol += fnr_curr ; C += fnrows ; } DEBUG8 (("element copied\n")) ; /* ---------------------------------------------------------------------- */ /* add tuples for the new element */ /* ---------------------------------------------------------------------- */ tuple.e = e ; if (got_memory) { /* ------------------------------------------------------------------ */ /* UMF_get_memory ensures enough space exists for each new tuple */ /* ------------------------------------------------------------------ */ /* place (e,f) in the element list of each column */ for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++) { col = Fcols [tuple.f] ; ASSERT (col >= 0 && col < n_col) ; ASSERT (NON_PIVOTAL_COL (col)) ; ASSERT (Col_tuples [col]) ; tp = ((Tuple *) (Memory + Col_tuples [col])) + Col_tlen [col]++ ; *tp = tuple ; } /* ------------------------------------------------------------------ */ /* place (e,f) in the element list of each row */ for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++) { row = Frows [tuple.f] ; ASSERT (row >= 0 && row < n_row) ; ASSERT (NON_PIVOTAL_ROW (row)) ; ASSERT (Row_tuples [row]) ; tp = ((Tuple *) (Memory + Row_tuples [row])) + Row_tlen [row]++ ; *tp = tuple ; } } else { /* ------------------------------------------------------------------ */ /* place (e,f) in the element list of each column */ /* ------------------------------------------------------------------ */ /* might not have enough space for each tuple */ for (tuple.f = 0 ; tuple.f < fncols ; tuple.f++) { col = Fcols [tuple.f] ; ASSERT (col >= 0 && col < n_col) ; ASSERT (NON_PIVOTAL_COL (col)) ; t1 = Col_tuples [col] ; DEBUG1 (("Placing on col:"ID" , tuples at "ID"\n", col, Col_tuples [col])) ; size = 0 ; len = 0 ; if (t1) { p = Memory + t1 ; tp = (Tuple *) p ; size = GET_BLOCK_SIZE (p) ; len = Col_tlen [col] ; tp2 = tp + len ; } needunits = UNITS (Tuple, len + 1) ; DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n", len, size, needunits)); if (needunits > size && t1) { /* prune the tuples */ tp1 = tp ; tp2 = tp ; tpend = tp + len ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) continue ; /* element already deallocated */ f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; ; if (Cols [f] == EMPTY) continue ; /* already assembled */ ASSERT (col == Cols [f]) ; *tp2++ = *tp ; /* leave the tuple in the list */ } len = tp2 - tp1 ; Col_tlen [col] = len ; needunits = UNITS (Tuple, len + 1) ; } if (needunits > size) { /* no room exists - reallocate elsewhere */ DEBUG1 (("REALLOCATE Col: "ID", size "ID" to "ID"\n", col, size, 2*needunits)) ; #ifndef NDEBUG UMF_allocfail = FALSE ; if (UMF_gprob > 0) /* a double relop, but ignore NaN case */ { double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ; UMF_allocfail = rrr < UMF_gprob ; if (UMF_allocfail) DEBUGm2 (("Random gar. (col tuple)\n")) ; } #endif needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ; t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ; if (!t2) { /* :: get memory in umf_create_element (1) :: */ /* get memory, reconstruct all tuple lists, and return */ /* Compact the current front if it needs to grow anyway. */ /* Note: no pivot rows or columns in the current front */ DEBUGm4 (("get_memory from umf_create_element, 1\n")) ; return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos)); } Col_tuples [col] = t2 ; tp2 = (Tuple *) (Memory + t2) ; if (t1) { for (i = 0 ; i < len ; i++) { *tp2++ = *tp1++ ; } UMF_mem_free_tail_block (Numeric, t1) ; } } /* place the new (e,f) tuple in the element list of the column */ Col_tlen [col]++ ; *tp2 = tuple ; } /* ------------------------------------------------------------------ */ /* place (e,f) in the element list of each row */ /* ------------------------------------------------------------------ */ for (tuple.f = 0 ; tuple.f < fnrows ; tuple.f++) { row = Frows [tuple.f] ; ASSERT (row >= 0 && row < n_row) ; ASSERT (NON_PIVOTAL_ROW (row)) ; t1 = Row_tuples [row] ; DEBUG1 (("Placing on row:"ID" , tuples at "ID"\n", row, Row_tuples [row])) ; size = 0 ; len = 0 ; if (t1) { p = Memory + t1 ; tp = (Tuple *) p ; size = GET_BLOCK_SIZE (p) ; len = Row_tlen [row] ; tp2 = tp + len ; } needunits = UNITS (Tuple, len + 1) ; DEBUG1 (("len: "ID" size: "ID" needunits: "ID"\n", len, size, needunits)) ; if (needunits > size && t1) { /* prune the tuples */ tp1 = tp ; tp2 = tp ; tpend = tp + len ; for ( ; tp < tpend ; tp++) { e = tp->e ; ASSERT (e > 0 && e <= Work->nel) ; if (!E [e]) { continue ; /* element already deallocated */ } f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; Rows = Cols + (ep->ncols) ; if (Rows [f] == EMPTY) continue ; /* already assembled */ ASSERT (row == Rows [f]) ; *tp2++ = *tp ; /* leave the tuple in the list */ } len = tp2 - tp1 ; Row_tlen [row] = len ; needunits = UNITS (Tuple, len + 1) ; } if (needunits > size) { /* no room exists - reallocate elsewhere */ DEBUG1 (("REALLOCATE Row: "ID", size "ID" to "ID"\n", row, size, 2*needunits)) ; #ifndef NDEBUG UMF_allocfail = FALSE ; if (UMF_gprob > 0) /* a double relop, but ignore NaN case */ { double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ; UMF_allocfail = rrr < UMF_gprob ; if (UMF_allocfail) DEBUGm2 (("Random gar. (row tuple)\n")) ; } #endif needunits = MIN (2*needunits, (Int) UNITS (Tuple, nn)) ; t2 = UMF_mem_alloc_tail_block (Numeric, needunits) ; if (!t2) { /* :: get memory in umf_create_element (2) :: */ /* get memory, reconstruct all tuple lists, and return */ /* Compact the current front if it needs to grow anyway. */ /* Note: no pivot rows or columns in the current front */ DEBUGm4 (("get_memory from umf_create_element, 2\n")) ; return (UMF_get_memory (Numeric, Work, 0, r2, c2,do_Fcpos)); } Row_tuples [row] = t2 ; tp2 = (Tuple *) (Memory + t2) ; if (t1) { for (i = 0 ; i < len ; i++) { *tp2++ = *tp1++ ; } UMF_mem_free_tail_block (Numeric, t1) ; } } /* place the new (e,f) tuple in the element list of the row */ Row_tlen [row]++ ; *tp2 = tuple ; } } /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG1 (("Done extending\nFINAL: element row pattern: len="ID"\n", fncols)); for (j = 0 ; j < fncols ; j++) DEBUG1 ((""ID"\n", Fcols [j])) ; DEBUG1 (("FINAL: element col pattern: len="ID"\n", fnrows)) ; for (j = 0 ; j < fnrows ; j++) DEBUG1 ((""ID"\n", Frows [j])) ; for (j = 0 ; j < fncols ; j++) { col = Fcols [j] ; ASSERT (col >= 0 && col < n_col) ; UMF_dump_rowcol (1, Numeric, Work, col, !Symbolic->fixQ) ; } for (j = 0 ; j < fnrows ; j++) { row = Frows [j] ; ASSERT (row >= 0 && row < n_row) ; UMF_dump_rowcol (0, Numeric, Work, row, TRUE) ; } if (n_row < 1000 && n_col < 1000) { UMF_dump_memory (Numeric) ; } DEBUG1 (("New element, after filling with stuff: "ID"\n", e)) ; UMF_dump_element (Numeric, Work, e, TRUE) ; if (nn < 1000) { DEBUG4 (("Matrix dump, after New element: "ID"\n", e)) ; UMF_dump_matrix (Numeric, Work, TRUE) ; } DEBUG3 (("FRONTAL WRAPUP DONE\n")) ; #endif return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_qsymbolic.c0000644000175000017500000023452111674452555023535 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_qsymbolic ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Performs a symbolic factorization. See umfpack_qsymbolic.h and umfpack_symbolic.h for details. Dynamic memory usage: about (3.4nz + 8n + n) integers and n double's as workspace (via UMF_malloc, for a square matrix). All of it is free'd via UMF_free if an error occurs. If successful, the Symbolic object contains 12 to 14 objects allocated by UMF_malloc, with a total size of no more than about 13*n integers. */ #include "umf_internal.h" #include "umf_symbolic_usage.h" #include "umf_colamd.h" #include "umf_set_stats.h" #include "umf_analyze.h" #include "umf_transpose.h" #include "umf_is_permutation.h" #include "umf_malloc.h" #include "umf_free.h" #include "umf_2by2.h" #include "umf_singletons.h" typedef struct /* SWType */ { Int *Front_npivcol ; /* size n_col + 1 */ Int *Front_nrows ; /* size n_col */ Int *Front_ncols ; /* size n_col */ Int *Front_parent ; /* size n_col */ Int *Front_cols ; /* size n_col */ Int *InFront ; /* size n_row */ Int *Ci ; /* size Clen */ Int *Cperm1 ; /* size n_col */ Int *Rperm1 ; /* size n_row */ Int *InvRperm1 ; /* size n_row */ Int *Si ; /* size nz */ Int *Sp ; /* size n_col + 1 */ double *Rs ; /* size n_row */ Int *Rperm_2by2 ; /* size n_row */ } SWType ; PRIVATE void free_work ( SWType *SW ) ; PRIVATE void error ( SymbolicType **Symbolic, SWType *SW ) ; /* worst-case usage for SW object */ #define SYM_WORK_USAGE(n_col,n_row,Clen) \ (DUNITS (Int, Clen) + \ DUNITS (Int, nz) + \ 4 * DUNITS (Int, n_row) + \ 4 * DUNITS (Int, n_col) + \ 2 * DUNITS (Int, n_col + 1) + \ DUNITS (double, n_row)) /* required size of Ci for code that calls UMF_transpose and UMF_analyze below*/ #define UMF_ANALYZE_CLEN(nz,n_row,n_col,nn) \ ((n_col) + MAX ((nz),(n_col)) + 3*(nn)+1 + (n_col)) /* size of an element (in Units), including tuples */ #define ELEMENT_SIZE(r,c) \ (DGET_ELEMENT_SIZE (r, c) + 1 + (r + c) * UNITS (Tuple, 1)) #ifndef NDEBUG PRIVATE Int init_count ; #endif /* ========================================================================== */ /* === do_amd =============================================================== */ /* ========================================================================== */ PRIVATE void do_amd ( Int n, const Int Ap [ ], /* size n+1 */ const Int Ai [ ], /* size nz = Ap [n] */ Int Q [ ], /* output permutation, j = Q [k] */ Int Qinv [ ], /* output inverse permutation, Qinv [j] = k */ Int Sdeg [ ], /* degree of A+A', from AMD_aat */ Int Clen, /* size of Ci */ Int Ci [ ], /* size Ci workspace */ double amd_Control [ ], /* AMD control parameters */ double amd_Info [ ], /* AMD info */ SymbolicType *Symbolic, /* Symbolic object */ double Info [ ] /* UMFPACK info */ ) { if (n == 0) { Symbolic->amd_dmax = 0 ; Symbolic->amd_lunz = 0 ; Info [UMFPACK_SYMMETRIC_LUNZ] = 0 ; Info [UMFPACK_SYMMETRIC_FLOPS] = 0 ; Info [UMFPACK_SYMMETRIC_DMAX] = 0 ; Info [UMFPACK_SYMMETRIC_NDENSE] = 0 ; } else { AMD_1 (n, Ap, Ai, Q, Qinv, Sdeg, Clen, Ci, amd_Control, amd_Info) ; /* return estimates computed from AMD on PA+PA' */ Symbolic->amd_dmax = amd_Info [AMD_DMAX] ; Symbolic->amd_lunz = 2 * amd_Info [AMD_LNZ] + n ; Info [UMFPACK_SYMMETRIC_LUNZ] = Symbolic->amd_lunz ; Info [UMFPACK_SYMMETRIC_FLOPS] = DIV_FLOPS * amd_Info [AMD_NDIV] + MULTSUB_FLOPS * amd_Info [AMD_NMULTSUBS_LU] ; Info [UMFPACK_SYMMETRIC_DMAX] = Symbolic->amd_dmax ; Info [UMFPACK_SYMMETRIC_NDENSE] = amd_Info [AMD_NDENSE] ; Info [UMFPACK_SYMBOLIC_DEFRAG] += amd_Info [AMD_NCMPA] ; } } /* ========================================================================== */ /* === prune_singletons ===================================================== */ /* ========================================================================== */ /* Create the submatrix after removing the n1 singletons. The matrix has * row and column indices in the range 0 to n_row-n1 and 0 to n_col-n1, * respectively. */ PRIVATE Int prune_singletons ( Int n1, Int n_col, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif Int Cperm1 [ ], Int InvRperm1 [ ], Int Si [ ], Int Sp [ ] #ifndef NDEBUG , Int Rperm1 [ ] , Int n_row #endif ) { Int row, k, pp, p, oldcol, newcol, newrow, nzdiag, do_nzdiag ; #ifdef COMPLEX Int split = SPLIT (Az) ; #endif nzdiag = 0 ; do_nzdiag = (Ax != (double *) NULL) ; #ifndef NDEBUG DEBUGm4 (("Prune : S = A (Cperm1 (n1+1:end), Rperm1 (n1+1:end))\n")) ; for (k = 0 ; k < n_row ; k++) { ASSERT (Rperm1 [k] >= 0 && Rperm1 [k] < n_row) ; ASSERT (InvRperm1 [Rperm1 [k]] == k) ; } #endif /* create the submatrix after removing singletons */ pp = 0 ; for (k = n1 ; k < n_col ; k++) { oldcol = Cperm1 [k] ; newcol = k - n1 ; DEBUG5 (("Prune singletons k "ID" oldcol "ID" newcol "ID": "ID"\n", k, oldcol, newcol, pp)) ; Sp [newcol] = pp ; /* load column pointers */ for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++) { row = Ai [p] ; DEBUG5 ((" "ID": row "ID, pp, row)) ; ASSERT (row >= 0 && row < n_row) ; newrow = InvRperm1 [row] - n1 ; ASSERT (newrow < n_row - n1) ; if (newrow >= 0) { DEBUG5 ((" newrow "ID, newrow)) ; Si [pp++] = newrow ; if (do_nzdiag) { /* count the number of truly nonzero entries on the * diagonal of S, excluding entries that are present, * but numerically zero */ if (newrow == newcol) { /* this is the diagonal entry */ #ifdef COMPLEX if (split) { if (SCALAR_IS_NONZERO (Ax [p]) || SCALAR_IS_NONZERO (Az [p])) { nzdiag++ ; } } else { if (SCALAR_IS_NONZERO (Ax [2*p ]) || SCALAR_IS_NONZERO (Ax [2*p+1])) { nzdiag++ ; } } #else if (SCALAR_IS_NONZERO (Ax [p])) { nzdiag++ ; } #endif } } } DEBUG5 (("\n")) ; } } Sp [n_col - n1] = pp ; return (nzdiag) ; } /* ========================================================================== */ /* === combine_ordering ===================================================== */ /* ========================================================================== */ PRIVATE void combine_ordering ( Int n1, Int nempty_col, Int n_col, Int Cperm_init [ ], /* output permutation */ Int Cperm1 [ ], /* singleton and empty column ordering */ Int Qinv [ ] /* Qinv from AMD or COLAMD */ ) { Int k, oldcol, newcol, knew ; /* combine the singleton ordering with Qinv */ #ifndef NDEBUG for (k = 0 ; k < n_col ; k++) { Cperm_init [k] = EMPTY ; } #endif for (k = 0 ; k < n1 ; k++) { DEBUG1 ((ID" Initial singleton: "ID"\n", k, Cperm1 [k])) ; Cperm_init [k] = Cperm1 [k] ; } for (k = n1 ; k < n_col - nempty_col ; k++) { /* this is a non-singleton column */ oldcol = Cperm1 [k] ; /* user's name for this column */ newcol = k - n1 ; /* Qinv's name for this column */ knew = Qinv [newcol] ; /* Qinv's ordering for this column */ knew += n1 ; /* shift order, after singletons */ DEBUG1 ((" k "ID" oldcol "ID" newcol "ID" knew "ID"\n", k, oldcol, newcol, knew)) ; ASSERT (knew >= 0 && knew < n_col - nempty_col) ; ASSERT (Cperm_init [knew] == EMPTY) ; Cperm_init [knew] = oldcol ; } for (k = n_col - nempty_col ; k < n_col ; k++) { Cperm_init [k] = Cperm1 [k] ; } #ifndef NDEBUG { Int *W = (Int *) malloc ((n_col + 1) * sizeof (Int)) ; ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ; free (W) ; } #endif } /* ========================================================================== */ /* === UMFPACK_qsymbolic ==================================================== */ /* ========================================================================== */ GLOBAL Int UMFPACK_qsymbolic ( Int n_row, Int n_col, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif const Int Quser [ ], void **SymbolicHandle, const double Control [UMFPACK_CONTROL], double User_Info [UMFPACK_INFO] ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ double knobs [COLAMD_KNOBS], flops, f, r, c, force_fixQ, Info2 [UMFPACK_INFO], drow, dcol, dtail_usage, dlf, duf, dmax_usage, dhead_usage, dlnz, dunz, dmaxfrsize, dClen, dClen_analyze, sym, amd_Info [AMD_INFO], dClen_amd, dr, dc, cr, cc, cp, amd_Control [AMD_CONTROL], stats [2], tol ; double *Info ; Int i, nz, j, newj, status, f1, f2, maxnrows, maxncols, nfr, col, nchains, maxrows, maxcols, p, nb, nn, *Chain_start, *Chain_maxrows, *Chain_maxcols, *Front_npivcol, *Ci, Clen, colamd_stats [COLAMD_STATS], fpiv, n_inner, child, parent, *Link, row, *Front_parent, analyze_compactions, k, chain, is_sym, *Si, *Sp, n2, do_UMF_analyze, fpivcol, fallrows, fallcols, *InFront, *F1, snz, *Front_1strow, f1rows, kk, *Cperm_init, *Rperm_init, newrow, *InvRperm1, *Front_leftmostdesc, Clen_analyze, strategy, Clen_amd, fixQ, prefer_diagonal, nzdiag, nzaat, *Wq, *Sdeg, *Fr_npivcol, nempty, *Fr_nrows, *Fr_ncols, *Fr_parent, *Fr_cols, nempty_row, nempty_col, user_auto_strategy, fail, max_rdeg, head_usage, tail_usage, lnz, unz, esize, *Esize, rdeg, *Cdeg, *Rdeg, *Cperm1, *Rperm1, n1, oldcol, newcol, n1c, n1r, *Rperm_2by2, oldrow, dense_row_threshold, tlen, aggressive, scale, *Rp, *Ri ; SymbolicType *Symbolic ; SWType SWspace, *SW ; #ifndef NDEBUG UMF_dump_start ( ) ; init_count = UMF_malloc_count ; PRINTF (( "**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n" )) ; #endif /* ---------------------------------------------------------------------- */ /* get the amount of time used by the process so far */ /* ---------------------------------------------------------------------- */ umfpack_tic (stats) ; /* ---------------------------------------------------------------------- */ /* get control settings and check input parameters */ /* ---------------------------------------------------------------------- */ drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ; dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ; nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ; strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ; #if 0 tol = GET_CONTROL (UMFPACK_2BY2_TOLERANCE, UMFPACK_DEFAULT_2BY2_TOLERANCE) ; #endif scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ; force_fixQ = GET_CONTROL (UMFPACK_FIXQ, UMFPACK_DEFAULT_FIXQ) ; AMD_defaults (amd_Control) ; amd_Control [AMD_DENSE] = GET_CONTROL (UMFPACK_AMD_DENSE, UMFPACK_DEFAULT_AMD_DENSE) ; aggressive = (GET_CONTROL (UMFPACK_AGGRESSIVE, UMFPACK_DEFAULT_AGGRESSIVE) != 0) ; amd_Control [AMD_AGGRESSIVE] = aggressive ; nb = MAX (2, nb) ; nb = MIN (nb, MAXNB) ; ASSERT (nb >= 0) ; if (nb % 2 == 1) nb++ ; /* make sure nb is even */ DEBUG0 (("UMFPACK_qsymbolic: nb = "ID" aggressive = "ID"\n", nb, aggressive)) ; #if 0 tol = MAX (0.0, MIN (tol, 1.0)) ; #endif if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX) { scale = UMFPACK_DEFAULT_SCALE ; } if (User_Info != (double *) NULL) { /* return Info in user's array */ Info = User_Info ; } else { /* no Info array passed - use local one instead */ Info = Info2 ; } /* clear all of Info */ for (i = 0 ; i < UMFPACK_INFO ; i++) { Info [i] = EMPTY ; } nn = MAX (n_row, n_col) ; n_inner = MIN (n_row, n_col) ; Info [UMFPACK_STATUS] = UMFPACK_OK ; Info [UMFPACK_NROW] = n_row ; Info [UMFPACK_NCOL] = n_col ; Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ; Info [UMFPACK_SIZE_OF_INT] = (double) (sizeof (int)) ; Info [UMFPACK_SIZE_OF_LONG] = (double) (sizeof (UF_long)) ; Info [UMFPACK_SIZE_OF_POINTER] = (double) (sizeof (void *)) ; Info [UMFPACK_SIZE_OF_ENTRY] = (double) (sizeof (Entry)) ; Info [UMFPACK_SYMBOLIC_DEFRAG] = 0 ; if (!Ai || !Ap || !SymbolicHandle) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ; return (UMFPACK_ERROR_argument_missing) ; } *SymbolicHandle = (void *) NULL ; if (n_row <= 0 || n_col <= 0) /* n_row, n_col must be > 0 */ { Info [UMFPACK_STATUS] = UMFPACK_ERROR_n_nonpositive ; return (UMFPACK_ERROR_n_nonpositive) ; } nz = Ap [n_col] ; DEBUG0 (("n_row "ID" n_col "ID" nz "ID"\n", n_row, n_col, nz)) ; Info [UMFPACK_NZ] = nz ; if (nz < 0) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_matrix ; return (UMFPACK_ERROR_invalid_matrix) ; } /* ---------------------------------------------------------------------- */ /* get the requested strategy */ /* ---------------------------------------------------------------------- */ if (n_row != n_col) { /* if the matrix is rectangular, the only available strategy is * unsymmetric */ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; DEBUGm3 (("Rectangular: forcing unsymmetric strategy\n")) ; } if (strategy < UMFPACK_STRATEGY_AUTO || strategy > UMFPACK_STRATEGY_SYMMETRIC) { /* unrecognized strategy */ strategy = UMFPACK_STRATEGY_AUTO ; } if (Quser != (Int *) NULL) { /* when the user provides Q, only symmetric and unsymmetric strategies * are available */ if (strategy == UMFPACK_STRATEGY_2BY2) { strategy = UMFPACK_STRATEGY_SYMMETRIC ; } if (strategy != UMFPACK_STRATEGY_SYMMETRIC) { strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; } } user_auto_strategy = (strategy == UMFPACK_STRATEGY_AUTO) ; /* ---------------------------------------------------------------------- */ /* determine amount of memory required for UMFPACK_symbolic */ /* ---------------------------------------------------------------------- */ /* The size of Clen required for UMF_colamd is always larger than */ /* UMF_analyze, but the max is included here in case that changes in */ /* future versions. */ /* This is about 2.2*nz + 9*n_col + 6*n_row, or nz/5 + 13*n_col + 6*n_row, * whichever is bigger. For square matrices, it works out to * 2.2nz + 15n, or nz/5 + 19n, whichever is bigger (typically 2.2nz+15n). */ dClen = UMF_COLAMD_RECOMMENDED ((double) nz, (double) n_row, (double) n_col) ; /* This is defined above, as max (nz,n_col) + 3*nn+1 + 2*n_col, where * nn = max (n_row,n_col). It is always smaller than the space required * for colamd or amd. */ dClen_analyze = UMF_ANALYZE_CLEN ((double) nz, (double) n_row, (double) n_col, (double) nn) ; dClen = MAX (dClen, dClen_analyze) ; /* The space for AMD can be larger than what's required for colamd: */ dClen_amd = 2.4 * (double) nz + 8 * (double) n_inner ; /* additional space for the 2-by-2 strategy */ dClen_amd += (double) MAX (nn, nz) ; dClen = MAX (dClen, dClen_amd) ; /* worst case total memory usage for UMFPACK_symbolic (revised below) */ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] = SYM_WORK_USAGE (n_col, n_row, dClen) + UMF_symbolic_usage (n_row, n_col, n_col, n_col, n_col, TRUE) ; if (INT_OVERFLOW (dClen * sizeof (Int))) { /* :: int overflow, Clen too large :: */ /* Problem is too large for array indexing (Ci [i]) with an Int i. */ /* Cannot even analyze the problem to determine upper bounds on */ /* memory usage. Need to use the UF_long version, umfpack_*l_*. */ DEBUGm4 (("out of memory: symbolic int overflow\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; return (UMFPACK_ERROR_out_of_memory) ; } /* repeat the size calculations, in integers */ Clen = UMF_COLAMD_RECOMMENDED (nz, n_row, n_col) ; Clen_analyze = UMF_ANALYZE_CLEN (nz, n_row, n_col, nn) ; Clen = MAX (Clen, Clen_analyze) ; Clen_amd = 2.4 * nz + 8 * n_inner ; Clen_amd += MAX (nn, nz) ; /* for Ri, in UMF_2by2 */ Clen = MAX (Clen, Clen_amd) ; /* ---------------------------------------------------------------------- */ /* allocate the first part of the Symbolic object (header and Cperm_init) */ /* ---------------------------------------------------------------------- */ /* (1) Five calls to UMF_malloc are made, for a total space of * 2 * (n_row + n_col) + 4 integers + sizeof (SymbolicType). * sizeof (SymbolicType) is a small constant. This space is part of the * Symbolic object and is not freed unless an error occurs. If A is square * then this is about 4*n integers. */ Symbolic = (SymbolicType *) UMF_malloc (1, sizeof (SymbolicType)) ; if (!Symbolic) { /* If we fail here, Symbolic is NULL and thus it won't be */ /* dereferenced by UMFPACK_free_symbolic, as called by error ( ). */ DEBUGm4 (("out of memory: symbolic object\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Symbolic, (SWType *) NULL) ; return (UMFPACK_ERROR_out_of_memory) ; } /* We now know that Symbolic has been allocated */ Symbolic->valid = 0 ; Symbolic->Chain_start = (Int *) NULL ; Symbolic->Chain_maxrows = (Int *) NULL ; Symbolic->Chain_maxcols = (Int *) NULL ; Symbolic->Front_npivcol = (Int *) NULL ; Symbolic->Front_parent = (Int *) NULL ; Symbolic->Front_1strow = (Int *) NULL ; Symbolic->Front_leftmostdesc = (Int *) NULL ; Symbolic->Esize = (Int *) NULL ; Symbolic->esize = 0 ; Symbolic->Cperm_init = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ; Symbolic->Rperm_init = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ; Symbolic->Cdeg = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ; Symbolic->Rdeg = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ; Symbolic->Diagonal_map = (Int *) NULL ; Cperm_init = Symbolic->Cperm_init ; Rperm_init = Symbolic->Rperm_init ; Cdeg = Symbolic->Cdeg ; Rdeg = Symbolic->Rdeg ; if (!Cperm_init || !Rperm_init || !Cdeg || !Rdeg) { DEBUGm4 (("out of memory: symbolic perm\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Symbolic, (SWType *) NULL) ; return (UMFPACK_ERROR_out_of_memory) ; } Symbolic->n_row = n_row ; Symbolic->n_col = n_col ; Symbolic->nz = nz ; Symbolic->nb = nb ; /* ---------------------------------------------------------------------- */ /* check user's input permutation */ /* ---------------------------------------------------------------------- */ if (Quser != (Int *) NULL) { /* use Cperm_init as workspace to check input permutation */ if (!UMF_is_permutation (Quser, Cperm_init, n_col, n_col)) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_permutation ; error (&Symbolic, (SWType *) NULL) ; return (UMFPACK_ERROR_invalid_permutation) ; } } /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* (2) Eleven calls to UMF_malloc are made, for workspace of size * Clen + nz + 7*n_col + 2*n_row + 2 integers. Clen is the larger of * MAX (2*nz, 4*n_col) + 8*n_col + 6*n_row + n_col + nz/5 and * 2.4*nz + 8 * MIN (n_row, n_col) + MAX (n_row, n_col, nz) * If A is square and non-singular, then Clen is * MAX (MAX (2*nz, 4*n) + 7*n + nz/5, 3.4*nz) + 8*n * If A has at least 4*n nonzeros then Clen is * MAX (2.2*nz + 7*n, 3.4*nz) + 8*n * If A has at least (7/1.2)*n nonzeros, (about 5.8*n), then Clen is * 3.4*nz + 8*n * This space will be free'd when this routine finishes. * * Total space thus far is about 3.4nz + 12n integers. * For the double precision, 32-bit integer version, the user's matrix * requires an equivalent space of 3*nz + n integers. So this space is just * slightly larger than the user's input matrix (including the numerical * values themselves). */ SW = &SWspace ; /* used for UMFPACK_symbolic only */ /* Note that SW->Front_* does not include the dummy placeholder front. */ /* This space is accounted for by the SYM_WORK_USAGE macro. */ /* this is free'd early */ SW->Si = (Int *) UMF_malloc (nz, sizeof (Int)) ; SW->Sp = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ; SW->InvRperm1 = (Int *) UMF_malloc (n_row, sizeof (Int)) ; SW->Cperm1 = (Int *) UMF_malloc (n_col, sizeof (Int)) ; /* this is free'd late */ SW->Ci = (Int *) UMF_malloc (Clen, sizeof (Int)) ; SW->Front_npivcol = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ; SW->Front_nrows = (Int *) UMF_malloc (n_col, sizeof (Int)) ; SW->Front_ncols = (Int *) UMF_malloc (n_col, sizeof (Int)) ; SW->Front_parent = (Int *) UMF_malloc (n_col, sizeof (Int)) ; SW->Front_cols = (Int *) UMF_malloc (n_col, sizeof (Int)) ; SW->Rperm1 = (Int *) UMF_malloc (n_row, sizeof (Int)) ; SW->InFront = (Int *) UMF_malloc (n_row, sizeof (Int)) ; /* this is allocated later, and free'd after Cperm1 but before Ci */ SW->Rperm_2by2 = (Int *) NULL ; /* will be nn Int's */ /* this is allocated last, and free'd first */ SW->Rs = (double *) NULL ; /* will be n_row double's */ Ci = SW->Ci ; Fr_npivcol = SW->Front_npivcol ; Fr_nrows = SW->Front_nrows ; Fr_ncols = SW->Front_ncols ; Fr_parent = SW->Front_parent ; Fr_cols = SW->Front_cols ; Cperm1 = SW->Cperm1 ; Rperm1 = SW->Rperm1 ; Si = SW->Si ; Sp = SW->Sp ; InvRperm1 = SW->InvRperm1 ; Rperm_2by2 = (Int *) NULL ; InFront = SW->InFront ; if (!Ci || !Fr_npivcol || !Fr_nrows || !Fr_ncols || !Fr_parent || !Fr_cols || !Cperm1 || !Rperm1 || !Si || !Sp || !InvRperm1 || !InFront) { DEBUGm4 (("out of memory: symbolic work\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Symbolic, SW) ; return (UMFPACK_ERROR_out_of_memory) ; } DEBUG0 (("Symbolic UMF_malloc_count - init_count = "ID"\n", UMF_malloc_count - init_count)) ; ASSERT (UMF_malloc_count == init_count + 17) ; /* ---------------------------------------------------------------------- */ /* find the row and column singletons */ /* ---------------------------------------------------------------------- */ /* [ use first nz + n_row + MAX (n_row, n_col) entries in Ci as workspace, * and use Rperm_init as workspace */ ASSERT (Clen >= nz + n_row + MAX (n_row, n_col)) ; status = UMF_singletons (n_row, n_col, Ap, Ai, Quser, strategy, Cdeg, Cperm1, Rdeg, Rperm1, InvRperm1, &n1, &n1c, &n1r, &nempty_col, &nempty_row, &is_sym, &max_rdeg, /* workspace: */ Rperm_init, Ci, Ci + nz, Ci + nz + n_row) ; /* ] done using Rperm_init and Ci as workspace */ /* InvRperm1 is now the inverse of Rperm1 */ if (status != UMFPACK_OK) { DEBUGm4 (("matrix invalid: UMF_singletons\n")) ; Info [UMFPACK_STATUS] = status ; error (&Symbolic, SW) ; return (status) ; } Info [UMFPACK_NEMPTY_COL] = nempty_col ; Info [UMFPACK_NEMPTY_ROW] = nempty_row ; Info [UMFPACK_NDENSE_COL] = 0 ; /* # dense rows/cols recomputed below */ Info [UMFPACK_NDENSE_ROW] = 0 ; Info [UMFPACK_COL_SINGLETONS] = n1c ; Info [UMFPACK_ROW_SINGLETONS] = n1r ; Info [UMFPACK_S_SYMMETRIC] = is_sym ; nempty = MIN (nempty_col, nempty_row) ; Symbolic->nempty_row = nempty_row ; Symbolic->nempty_col = nempty_col ; /* UMF_singletons has verified that the user's input matrix is valid */ ASSERT (AMD_valid (n_row, n_col, Ap, Ai) == AMD_OK) ; Symbolic->n1 = n1 ; Symbolic->nempty = nempty ; ASSERT (n1 <= n_inner) ; n2 = nn - n1 - nempty ; dense_row_threshold = UMFPACK_DENSE_DEGREE_THRESHOLD (drow, n_col - n1 - nempty_col) ; Symbolic->dense_row_threshold = dense_row_threshold ; if (!is_sym) { /* either the pruned submatrix rectangular, or it is square and * Rperm [n1 .. n-nempty-1] is not the same as Cperm [n1 .. n-nempty-1]. * Switch to the unsymmetric strategy, ignoring user-requested * strategy. */ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; DEBUGm4 (("Strategy: Unsymmetric singletons\n")) ; } /* ---------------------------------------------------------------------- */ /* determine symmetry, nzdiag, and degrees of S+S' */ /* ---------------------------------------------------------------------- */ /* S is the matrix obtained after removing singletons * = A (Cperm1 [n1..n_col-nempty_col-1], Rperm1 [n1..n_row-nempty_row-1]) */ Wq = Rperm_init ; /* use Rperm_init as workspace for Wq [ */ Sdeg = Cperm_init ; /* use Cperm_init as workspace for Sdeg [ */ sym = EMPTY ; nzaat = EMPTY ; nzdiag = EMPTY ; for (i = 0 ; i < AMD_INFO ; i++) { amd_Info [i] = EMPTY ; } if (strategy != UMFPACK_STRATEGY_UNSYMMETRIC) { /* This also determines the degree of each node in S+S' (Sdeg), which * is needed by the 2-by-2 strategy, the symmetry of S, and the number * of nonzeros on the diagonal of S. */ ASSERT (n_row == n_col) ; ASSERT (nempty_row == nempty_col) ; /* get the count of nonzeros on the diagonal of S, excluding explicitly * zero entries. nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries * in S. */ nzdiag = prune_singletons (n1, nn, Ap, Ai, Ax, #ifdef COMPLEX Az, #endif Cperm1, InvRperm1, Si, Sp #ifndef NDEBUG , Rperm1, nn #endif ) ; /* use Ci as workspace to sort S into R, if needed [ */ if (Quser != (Int *) NULL) { /* need to sort the columns of S first */ Rp = Ci ; Ri = Ci + (n_row) + 1 ; (void) UMF_transpose (n2, n2, Sp, Si, (double *) NULL, (Int *) NULL, (Int *) NULL, 0, Rp, Ri, (double *) NULL, Wq, FALSE #ifdef COMPLEX , (double *) NULL, (double *) NULL, FALSE #endif ) ; } else { /* S already has sorted columns */ Rp = Sp ; Ri = Si ; } ASSERT (AMD_valid (n2, n2, Rp, Ri) == AMD_OK) ; nzaat = AMD_aat (n2, Rp, Ri, Sdeg, Wq, amd_Info) ; sym = amd_Info [AMD_SYMMETRY] ; Info [UMFPACK_N2] = n2 ; /* nzdiag = amd_Info [AMD_NZDIAG] counts the zero entries of S too */ /* done using Ci as workspace to sort S into R ] */ #ifndef NDEBUG for (k = 0 ; k < n2 ; k++) { ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ; } ASSERT (Sp [n2] - n2 <= nzaat && nzaat <= 2 * Sp [n2]) ; DEBUG0 (("Explicit zeros: "ID" %g\n", nzdiag, amd_Info [AMD_NZDIAG])) ; #endif } /* get statistics from amd_aat, if computed */ Symbolic->sym = sym ; Symbolic->nzaat = nzaat ; Symbolic->nzdiag = nzdiag ; Symbolic->amd_dmax = EMPTY ; Info [UMFPACK_PATTERN_SYMMETRY] = sym ; Info [UMFPACK_NZ_A_PLUS_AT] = nzaat ; Info [UMFPACK_NZDIAG] = nzdiag ; /* ---------------------------------------------------------------------- */ /* determine the initial strategy based on symmetry and nnz (diag (S)) */ /* ---------------------------------------------------------------------- */ #if 0 if (strategy == UMFPACK_STRATEGY_AUTO) { if (sym < 0.10) { /* highly unsymmetric: use the unsymmetric strategy */ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; DEBUGm4 (("Strategy: select unsymmetric\n")) ; } else if (sym >= 0.7 && nzdiag == n2) { /* mostly symmetric, zero-free diagonal: use symmetric strategy */ strategy = UMFPACK_STRATEGY_SYMMETRIC ; DEBUGm4 (("Strategy: select symmetric\n")) ; } else { /* Evaluate the symmetric 2-by-2 strategy, and select it, or * the unsymmetric strategy if the 2-by-2 strategy doesn't look * promising. */ strategy = UMFPACK_STRATEGY_2BY2 ; DEBUGm4 (("Strategy: try 2-by-2\n")) ; } } #endif /* The 2-by-2 strategy can cause an error UMFPACK_ERROR_different_pattern * (-11) when factorizing a structurally singular matrix. The problem * occurs very rarely. It's a conflict between the search of the row * merge tree and the 2-by-2 pre-permutation. Until this bug is fixed, * the 2-by-2 strategy is disabled. */ if (strategy == UMFPACK_STRATEGY_AUTO) { if (sym >= 0.7 && nzdiag >= 0.9 * n2) { /* pattern is mostly symmetric (70% or more) and the diagonal is * mostly zero-free (90% or more). Use symmetric strategy. */ strategy = UMFPACK_STRATEGY_SYMMETRIC ; DEBUG0 (("Strategy: select symmetric\n")) ; } else { /* otherwise use unsymmetric strategy */ strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; DEBUG0 (("Strategy: select unsymmetric\n")) ; } } if (strategy == UMFPACK_STRATEGY_2BY2) { /* If the user insists on the 2-by-2 strategy, use the symmetric * strategy instead. */ strategy = UMFPACK_STRATEGY_SYMMETRIC ; } #if 0 /* ---------------------------------------------------------------------- */ /* try the 2-by-2 strategy */ /* ---------------------------------------------------------------------- */ /* (3) If the 2-by-2 strategy is attempted, additional workspace of size * nn integers and nn double's is allocated, where nn = n_row = n_col. * The real workspace is immediately free'd. The integer workspace of * size nn remains until the end of umfpack_qsymbolic. */ /* If the resulting matrix S (Rperm_2by2, :) is too unsymmetric, then the * unsymmetric strategy will be used instead. */ if (strategy == UMFPACK_STRATEGY_2BY2) { double sym2 ; Int *Blen, *W, nz_papat, nzd2, nweak, unmatched, Clen3 ; /* ------------------------------------------------------------------ */ /* get workspace for UMF_2by2 */ /* ------------------------------------------------------------------ */ ASSERT (n_row == n_col && nn == n_row) ; #ifndef NDEBUG for (k = 0 ; k < n2 ; k++) { ASSERT (Sdeg [k] >= 0 && Sdeg [k] < n2) ; } #endif /* allocate Rperm_2by2 */ SW->Rperm_2by2 = (Int *) UMF_malloc (nn, sizeof (Int)) ; Rperm_2by2 = SW->Rperm_2by2 ; if (Rperm_2by2 == (Int *) NULL) { DEBUGm4 (("out of memory: Rperm_2by2\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Symbolic, SW) ; return (UMFPACK_ERROR_out_of_memory) ; } /* allocate Ri from the tail end of Ci [ */ Clen3 = Clen - (MAX (nn, nz) + 1) ; Ri = Ci + Clen3 ; ASSERT (Clen3 >= nz) ; /* space required for UMF_2by2 */ /* use Fr_* as workspace for Rp, Blen, and W [ */ Rp = Fr_npivcol ; Blen = Fr_ncols ; W = Fr_cols ; if (scale != UMFPACK_SCALE_NONE) { SW->Rs = (double *) UMF_malloc (nn, sizeof (double)) ; if (SW->Rs == (double *) NULL) { DEBUGm4 (("out of memory: scale factors for 2-by-2\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Symbolic, SW) ; return (UMFPACK_ERROR_out_of_memory) ; } } /* ------------------------------------------------------------------ */ /* find the 2-by-2 row permutation */ /* ------------------------------------------------------------------ */ /* find a row permutation Rperm_2by2 such that S (Rperm_2by2, :) * has a healthy diagonal */ UMF_2by2 (nn, Ap, Ai, Ax, #ifdef COMPLEX Az, #endif tol, scale, Cperm1, #ifndef NDEBUG Rperm1, #endif InvRperm1, n1, nempty, Sdeg, Rperm_2by2, &nweak, &unmatched, Ri, Rp, SW->Rs, Blen, W, Ci, Wq) ; DEBUGm3 (("2by2: nweak "ID" unmatched "ID"\n", nweak, unmatched)) ; Info [UMFPACK_2BY2_NWEAK] = nweak ; Info [UMFPACK_2BY2_UNMATCHED] = unmatched ; SW->Rs = (double *) UMF_free ((void *) SW->Rs) ; /* R = S (Rperm_2by2,:)' */ (void) UMF_transpose (n2, n2, Sp, Si, (double *) NULL, Rperm_2by2, (Int *) NULL, 0, Rp, Ri, (double *) NULL, W, FALSE #ifdef COMPLEX , (double *) NULL, (double *) NULL, FALSE #endif ) ; ASSERT (AMD_valid (n2, n2, Rp, Ri) == AMD_OK) ; /* contents of Si and Sp no longer needed, but the space is * still needed */ /* ------------------------------------------------------------------ */ /* find symmetry of S (Rperm_2by2, :)', and prepare to order with AMD */ /* ------------------------------------------------------------------ */ for (i = 0 ; i < AMD_INFO ; i++) { amd_Info [i] = EMPTY ; } nz_papat = AMD_aat (n2, Rp, Ri, Sdeg, Wq, amd_Info) ; sym2 = amd_Info [AMD_SYMMETRY] ; nzd2 = amd_Info [AMD_NZDIAG] ; Info [UMFPACK_2BY2_PATTERN_SYMMETRY] = sym2 ; Info [UMFPACK_2BY2_NZ_PA_PLUS_PAT] = nz_papat ; Info [UMFPACK_2BY2_NZDIAG] = nzd2 ; DEBUG0 (("2by2: sym2 %g nzd2 "ID" n2 "ID"\n", sym2, nzd2, n2)) ; /* ------------------------------------------------------------------ */ /* evaluate the 2-by-2 results */ /* ------------------------------------------------------------------ */ if (user_auto_strategy) { if ((sym2 > 1.1 * sym) && (nzd2 > 0.9 * n2)) { /* 2-by-2 made it much more symmetric */ DEBUGm4 (("eval Strategy 2by2: much more symmetric: 2by2\n")) ; strategy = UMFPACK_STRATEGY_2BY2 ; } else if (sym2 < 0.7 * sym) { /* 2-by-2 made it much more unsymmetric */ DEBUGm4 (("eval Strategy 2by2: much more UNsymmetric:unsym\n")); strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; } else if (sym2 < 0.25) { DEBUGm4 (("eval Strategy 2by2: is UNsymmetric: unsym\n")); strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; } else if (sym2 >= 0.51) { DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.51: 2by2\n")) ; strategy = UMFPACK_STRATEGY_2BY2 ; } else if (sym2 >= 0.999 * sym) { /* 2-by-2 improved symmetry, or made it only slightly worse */ DEBUGm4 (("eval Strategy 2by2: sym2 >= 0.999 sym: 2by2\n")) ; strategy = UMFPACK_STRATEGY_2BY2 ; } else { /* can't decide what to do, so pick the unsymmetric strategy */ DEBUGm4 (("eval Strategy 2by2: punt: unsym\n")); strategy = UMFPACK_STRATEGY_UNSYMMETRIC ; } } /* ------------------------------------------------------------------ */ /* if the 2-by-2 strategy is selected: */ /* ------------------------------------------------------------------ */ if (strategy == UMFPACK_STRATEGY_2BY2) { if (Quser == (Int *) NULL) { /* 2-by-2 strategy is successful */ /* compute amd (S) */ Int *Qinv = Fr_npivcol ; ASSERT (Clen3 >= (nz_papat + nz_papat/5 + nn) + 7*nn) ; do_amd (n2, Rp, Ri, Wq, Qinv, Sdeg, Clen3, Ci, amd_Control, amd_Info, Symbolic, Info) ; /* combine the singleton ordering and the AMD ordering */ combine_ordering (n1, nempty, nn, Cperm_init, Cperm1, Qinv) ; } /* fix Rperm_2by2 to reflect A, not S */ for (k = 0 ; k < n1 ; k++) { oldcol = Cperm1 [k] ; i = k ; oldrow = Rperm1 [k] ; W [oldcol] = oldrow ; } for (k = n1 ; k < nn - nempty ; k++) { oldcol = Cperm1 [k] ; i = Rperm_2by2 [k - n1] + n1 ; oldrow = Rperm1 [i] ; W [oldcol] = oldrow ; } for (k = nn - nempty ; k < nn ; k++) { oldcol = Cperm1 [k] ; i = k ; oldrow = Rperm1 [k] ; W [oldcol] = oldrow ; } for (k = 0 ; k < nn ; k++) { Rperm_2by2 [k] = W [k] ; } /* Now, the "diagonal" entry in oldcol (where oldcol is the user's * name for a column, is the entry in row oldrow (where oldrow is * the user's name for a row, and oldrow = Rperm_2by2 [oldcol] */ } /* Fr_* no longer needed for Rp, Blen, W ] */ } #endif /* ---------------------------------------------------------------------- */ /* finalize the strategy, including fixQ and prefer_diagonal */ /* ---------------------------------------------------------------------- */ if (strategy == UMFPACK_STRATEGY_SYMMETRIC) { /* use given Quser or AMD (A+A'), fix Q during factorization, * prefer diagonal */ DEBUG0 (("\nStrategy: symmetric\n")) ; ASSERT (n_row == n_col) ; Symbolic->ordering = UMFPACK_ORDERING_AMD ; fixQ = TRUE ; prefer_diagonal = TRUE ; } #if 0 else if (strategy == UMFPACK_STRATEGY_2BY2) { /* use Q = given Quser or Q = AMD (PA+PA'), fix Q during factorization, * prefer diagonal, and factorize PAQ, where P is found by UMF_2by2. */ DEBUG0 (("\nStrategy: symmetric 2-by-2\n")) ; ASSERT (n_row == n_col) ; Symbolic->ordering = UMFPACK_ORDERING_AMD ; fixQ = TRUE ; prefer_diagonal = TRUE ; } #endif else { /* use given Quser or COLAMD (A), refine Q during factorization, * no diagonal preference */ ASSERT (strategy == UMFPACK_STRATEGY_UNSYMMETRIC) ; DEBUG0 (("\nStrategy: unsymmetric\n")) ; Symbolic->ordering = UMFPACK_ORDERING_COLAMD ; fixQ = FALSE ; prefer_diagonal = FALSE ; } if (Quser != (Int *) NULL) { Symbolic->ordering = UMFPACK_ORDERING_GIVEN ; } if (force_fixQ > 0) { fixQ = TRUE ; DEBUG0 (("Force fixQ true\n")) ; } else if (force_fixQ < 0) { fixQ = FALSE ; DEBUG0 (("Force fixQ false\n")) ; } DEBUG0 (("Strategy: ordering: "ID"\n", Symbolic->ordering)) ; DEBUG0 (("Strategy: fixQ: "ID"\n", fixQ)) ; DEBUG0 (("Strategy: prefer diag "ID"\n", prefer_diagonal)) ; /* get statistics from amd_aat, if computed */ Symbolic->strategy = strategy ; Symbolic->fixQ = fixQ ; Symbolic->prefer_diagonal = prefer_diagonal ; Info [UMFPACK_STRATEGY_USED] = strategy ; Info [UMFPACK_ORDERING_USED] = Symbolic->ordering ; Info [UMFPACK_QFIXED] = fixQ ; Info [UMFPACK_DIAG_PREFERRED] = prefer_diagonal ; /* ---------------------------------------------------------------------- */ /* get the AMD ordering for the symmetric strategy */ /* ---------------------------------------------------------------------- */ if (strategy == UMFPACK_STRATEGY_SYMMETRIC && Quser == (Int *) NULL) { /* symmetric strategy for a matrix with mostly symmetric pattern */ Int *Qinv = Fr_npivcol ; ASSERT (n_row == n_col && nn == n_row) ; ASSERT (Clen >= (nzaat + nzaat/5 + nn) + 7*nn) ; do_amd (n2, Sp, Si, Wq, Qinv, Sdeg, Clen, Ci, amd_Control, amd_Info, Symbolic, Info) ; /* combine the singleton ordering and the AMD ordering */ combine_ordering (n1, nempty, nn, Cperm_init, Cperm1, Qinv) ; } /* Sdeg no longer needed ] */ /* done using Rperm_init as workspace for Wq ] */ /* Contents of Si and Sp no longer needed, but the space is still needed */ /* ---------------------------------------------------------------------- */ /* use the user's input column ordering (already in Cperm1) */ /* ---------------------------------------------------------------------- */ if (Quser != (Int *) NULL) { for (k = 0 ; k < n_col ; k++) { Cperm_init [k] = Cperm1 [k] ; } } /* ---------------------------------------------------------------------- */ /* use COLAMD to order the matrix */ /* ---------------------------------------------------------------------- */ if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC && Quser == (Int *) NULL) { /* ------------------------------------------------------------------ */ /* copy the matrix into colamd workspace (colamd destroys its input) */ /* ------------------------------------------------------------------ */ /* C = A (Cperm1 (n1+1:end), Rperm1 (n1+1:end)), where Ci is used as * the row indices and Cperm_init (on input) is used as the column * pointers. */ (void) prune_singletons (n1, n_col, Ap, Ai, (double *) NULL, #ifdef COMPLEX (double *) NULL, #endif Cperm1, InvRperm1, Ci, Cperm_init #ifndef NDEBUG , Rperm1, n_row #endif ) ; /* ------------------------------------------------------------------ */ /* set UMF_colamd defaults */ /* ------------------------------------------------------------------ */ UMF_colamd_set_defaults (knobs) ; knobs [COLAMD_DENSE_ROW] = drow ; knobs [COLAMD_DENSE_COL] = dcol ; knobs [COLAMD_AGGRESSIVE] = aggressive ; /* ------------------------------------------------------------------ */ /* check input matrix and find the initial column pre-ordering */ /* ------------------------------------------------------------------ */ /* NOTE: umf_colamd is not given any original empty rows or columns. * Those have already been removed via prune_singletons, above. The * umf_colamd routine has been modified to assume that all rows and * columns have at least one entry in them. It will break if it is * given empty rows or columns (an assertion is triggered when running * in debug mode. */ (void) UMF_colamd ( n_row - n1 - nempty_row, n_col - n1 - nempty_col, Clen, Ci, Cperm_init, knobs, colamd_stats, Fr_npivcol, Fr_nrows, Fr_ncols, Fr_parent, Fr_cols, &nfr, InFront) ; ASSERT (colamd_stats [COLAMD_EMPTY_ROW] == 0) ; ASSERT (colamd_stats [COLAMD_EMPTY_COL] == 0) ; /* # of dense rows will be recomputed below */ Info [UMFPACK_NDENSE_ROW] = colamd_stats [COLAMD_DENSE_ROW] ; Info [UMFPACK_NDENSE_COL] = colamd_stats [COLAMD_DENSE_COL] ; Info [UMFPACK_SYMBOLIC_DEFRAG] = colamd_stats [COLAMD_DEFRAG_COUNT] ; /* re-analyze if any "dense" rows or cols ignored by UMF_colamd */ do_UMF_analyze = colamd_stats [COLAMD_DENSE_ROW] > 0 || colamd_stats [COLAMD_DENSE_COL] > 0 ; /* Combine the singleton and colamd ordering into Cperm_init */ /* Note that colamd returns its inverse permutation in Ci */ combine_ordering (n1, nempty_col, n_col, Cperm_init, Cperm1, Ci) ; /* contents of Ci no longer needed */ #ifndef NDEBUG for (col = 0 ; col < n_col ; col++) { DEBUG1 (("Cperm_init ["ID"] = "ID"\n", col, Cperm_init[col])); } /* make sure colamd returned a valid permutation */ ASSERT (Cperm_init != (Int *) NULL) ; ASSERT (UMF_is_permutation (Cperm_init, Ci, n_col, n_col)) ; #endif } else { /* ------------------------------------------------------------------ */ /* do not call colamd - use input Quser or AMD instead */ /* ------------------------------------------------------------------ */ /* The ordering (Quser or Qamd) is already in Cperm_init */ do_UMF_analyze = TRUE ; } Cperm_init [n_col] = EMPTY ; /* unused in Cperm_init */ /* ---------------------------------------------------------------------- */ /* AMD ordering, if it exists, has been copied into Cperm_init */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG3 (("Cperm_init column permutation:\n")) ; ASSERT (UMF_is_permutation (Cperm_init, Ci, n_col, n_col)) ; for (k = 0 ; k < n_col ; k++) { DEBUG3 ((ID"\n", Cperm_init [k])) ; } /* ensure that empty columns have been placed last in A (:,Cperm_init) */ for (newj = 0 ; newj < n_col ; newj++) { /* empty columns will be last in A (:, Cperm_init (1:n_col)) */ j = Cperm_init [newj] ; ASSERT (IMPLIES (newj >= n_col-nempty_col, Cdeg [j] == 0)) ; ASSERT (IMPLIES (newj < n_col-nempty_col, Cdeg [j] > 0)) ; } #endif /* ---------------------------------------------------------------------- */ /* symbolic factorization (unless colamd has already done it) */ /* ---------------------------------------------------------------------- */ if (do_UMF_analyze) { Int *W, *Bp, *Bi, *Cperm2, ok, *P, Clen2, bsize, Clen0 ; /* ------------------------------------------------------------------ */ /* construct column pre-ordered, pruned submatrix */ /* ------------------------------------------------------------------ */ /* S = column form submatrix after removing singletons and applying * initial column ordering (includes singleton ordering) */ (void) prune_singletons (n1, n_col, Ap, Ai, (double *) NULL, #ifdef COMPLEX (double *) NULL, #endif Cperm_init, InvRperm1, Si, Sp #ifndef NDEBUG , Rperm1, n_row #endif ) ; /* ------------------------------------------------------------------ */ /* Ci [0 .. Clen-1] holds the following work arrays: first Clen0 entries empty space, where Clen0 = Clen - (nn+1 + 2*nn + n_col) and Clen0 >= nz + n_col next nn+1 entries Bp [0..nn] next nn entries Link [0..nn-1] next nn entries W [0..nn-1] last n_col entries Cperm2 [0..n_col-1] We have Clen >= n_col + MAX (nz,n_col) + 3*nn+1 + n_col, So Clen0 >= 2*n_col as required for AMD_postorder and Clen0 >= n_col + nz as required */ Clen0 = Clen - (nn+1 + 2*nn + n_col) ; Bp = Ci + Clen0 ; Link = Bp + (nn+1) ; W = Link + nn ; Cperm2 = W + nn ; ASSERT (Cperm2 + n_col == Ci + Clen) ; ASSERT (Clen0 >= nz + n_col) ; ASSERT (Clen0 >= 2*n_col) ; /* ------------------------------------------------------------------ */ /* P = order that rows will be used in UMF_analyze */ /* ------------------------------------------------------------------ */ /* use W to mark rows, and use Link for row permutation P [ [ */ for (row = 0 ; row < n_row - n1 ; row++) { W [row] = FALSE ; } P = Link ; k = 0 ; for (col = 0 ; col < n_col - n1 ; col++) { /* empty columns are last in S */ for (p = Sp [col] ; p < Sp [col+1] ; p++) { row = Si [p] ; if (!W [row]) { /* this row has just been seen for the first time */ W [row] = TRUE ; P [k++] = row ; } } } /* If the matrix has truly empty rows, then P will not be */ /* complete, and visa versa. The matrix is structurally singular. */ nempty_row = n_row - n1 - k ; if (k < n_row - n1) { /* complete P by putting empty rows last in their natural order, */ /* rather than declaring an error (the matrix is singular) */ for (row = 0 ; row < n_row - n1 ; row++) { if (!W [row]) { /* W [row] = TRUE ; (not required) */ P [k++] = row ; } } } /* contents of W no longer needed ] */ #ifndef NDEBUG DEBUG3 (("Induced row permutation:\n")) ; ASSERT (k == n_row - n1) ; ASSERT (UMF_is_permutation (P, W, n_row - n1, n_row - n1)) ; for (k = 0 ; k < n_row - n1 ; k++) { DEBUG3 ((ID"\n", P [k])) ; } #endif /* ------------------------------------------------------------------ */ /* B = row-form of the pattern of S (excluding empty columns) */ /* ------------------------------------------------------------------ */ /* Ci [0 .. Clen-1] holds the following work arrays: first Clen2 entries empty space, must be at least >= n_col next max (nz,1) Bi [0..max (nz,1)-1] next nn+1 entries Bp [0..nn] next nn entries Link [0..nn-1] next nn entries W [0..nn-1] last n_col entries Cperm2 [0..n_col-1] This memory usage is accounted for by the UMF_ANALYZE_CLEN macro. */ Clen2 = Clen0 ; snz = Sp [n_col - n1] ; bsize = MAX (snz, 1) ; Clen2 -= bsize ; Bi = Ci + Clen2 ; ASSERT (Clen2 >= n_col) ; (void) UMF_transpose (n_row - n1, n_col - n1 - nempty_col, Sp, Si, (double *) NULL, P, (Int *) NULL, 0, Bp, Bi, (double *) NULL, W, FALSE #ifdef COMPLEX , (double *) NULL, (double *) NULL, FALSE #endif ) ; /* contents of Si and Sp no longer needed */ /* contents of P (same as Link) and W not needed */ /* still need Link and W as work arrays, though ] */ ASSERT (Bp [0] == 0) ; ASSERT (Bp [n_row - n1] == snz) ; /* increment Bp to point into Ci, not Bi */ for (i = 0 ; i <= n_row - n1 ; i++) { Bp [i] += Clen2 ; } ASSERT (Bp [0] == Clen0 - bsize) ; ASSERT (Bp [n_row - n1] <= Clen0) ; /* Ci [0 .. Clen-1] holds the following work arrays: first Clen0 entries Ci [0 .. Clen0-1], where the col indices of B are at the tail end of this part, and Bp [0] = Clen2 >= n_col. Note that Clen0 = Clen2 + max (snz,1). next nn+1 entries Bp [0..nn] next nn entries Link [0..nn-1] next nn entries W [0..nn-1] last n_col entries Cperm2 [0..n_col-1] */ /* ------------------------------------------------------------------ */ /* analyze */ /* ------------------------------------------------------------------ */ /* only analyze the non-empty, non-singleton part of the matrix */ ok = UMF_analyze ( n_row - n1 - nempty_row, n_col - n1 - nempty_col, Ci, Bp, Cperm2, fixQ, W, Link, Fr_ncols, Fr_nrows, Fr_npivcol, Fr_parent, &nfr, &analyze_compactions) ; if (!ok) { /* :: internal error in umf_analyze :: */ Info [UMFPACK_STATUS] = UMFPACK_ERROR_internal_error ; error (&Symbolic, SW) ; return (UMFPACK_ERROR_internal_error) ; } Info [UMFPACK_SYMBOLIC_DEFRAG] += analyze_compactions ; /* ------------------------------------------------------------------ */ /* combine the input permutation and UMF_analyze's permutation */ /* ------------------------------------------------------------------ */ if (!fixQ) { /* Cperm2 is the column etree post-ordering */ ASSERT (UMF_is_permutation (Cperm2, W, n_col-n1-nempty_col, n_col-n1-nempty_col)) ; /* Note that the empty columns remain at the end of Cperm_init */ for (k = 0 ; k < n_col - n1 - nempty_col ; k++) { W [k] = Cperm_init [n1 + Cperm2 [k]] ; } for (k = 0 ; k < n_col - n1 - nempty_col ; k++) { Cperm_init [n1 + k] = W [k] ; } } ASSERT (UMF_is_permutation (Cperm_init, W, n_col, n_col)) ; } /* ---------------------------------------------------------------------- */ /* free some of the workspace */ /* ---------------------------------------------------------------------- */ /* (4) The real workspace, Rs, of size n_row doubles has already been * free'd. An additional workspace of size nz + n_col+1 + n_col integers * is now free'd as well. */ SW->Si = (Int *) UMF_free ((void *) SW->Si) ; SW->Sp = (Int *) UMF_free ((void *) SW->Sp) ; SW->Cperm1 = (Int *) UMF_free ((void *) SW->Cperm1) ; ASSERT (SW->Rs == (double *) NULL) ; /* ---------------------------------------------------------------------- */ /* determine the size of the Symbolic object */ /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /* determine the size of the Symbolic object */ /* ---------------------------------------------------------------------- */ nchains = 0 ; for (i = 0 ; i < nfr ; i++) { if (Fr_parent [i] != i+1) { nchains++ ; } } Symbolic->nchains = nchains ; Symbolic->nfr = nfr ; Symbolic->esize = (max_rdeg > dense_row_threshold) ? (n_col - n1 - nempty_col) : 0 ; /* true size of Symbolic object */ Info [UMFPACK_SYMBOLIC_SIZE] = UMF_symbolic_usage (n_row, n_col, nchains, nfr, Symbolic->esize, prefer_diagonal) ; /* actual peak memory usage for UMFPACK_symbolic (actual nfr, nchains) */ Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] = SYM_WORK_USAGE (n_col, n_row, Clen) + Info [UMFPACK_SYMBOLIC_SIZE] ; Symbolic->peak_sym_usage = Info [UMFPACK_SYMBOLIC_PEAK_MEMORY] ; DEBUG0 (("Number of fronts: "ID"\n", nfr)) ; /* ---------------------------------------------------------------------- */ /* allocate the second part of the Symbolic object (Front_*, Chain_*) */ /* ---------------------------------------------------------------------- */ /* (5) UMF_malloc is called 7 or 8 times, for a total space of * (4*(nfr+1) + 3*(nchains+1) + esize) integers, where nfr is the total * number of frontal matrices and nchains is the total number of frontal * matrix chains, and where nchains <= nfr <= n_col. esize is zero if there * are no dense rows, or n_col-n1-nempty_col otherwise (n1 is the number of * singletons and nempty_col is the number of empty columns). This space is * part of the Symbolic object and is not free'd unless an error occurs. * This is between 7 and about 8n integers when A is square. */ /* Note that Symbolic->Front_* does include the dummy placeholder front */ Symbolic->Front_npivcol = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ; Symbolic->Front_parent = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ; Symbolic->Front_1strow = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ; Symbolic->Front_leftmostdesc = (Int *) UMF_malloc (nfr+1, sizeof (Int)) ; Symbolic->Chain_start = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ; Symbolic->Chain_maxrows = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ; Symbolic->Chain_maxcols = (Int *) UMF_malloc (nchains+1, sizeof (Int)) ; fail = (!Symbolic->Front_npivcol || !Symbolic->Front_parent || !Symbolic->Front_1strow || !Symbolic->Front_leftmostdesc || !Symbolic->Chain_start || !Symbolic->Chain_maxrows || !Symbolic->Chain_maxcols) ; if (Symbolic->esize > 0) { Symbolic->Esize = (Int *) UMF_malloc (Symbolic->esize, sizeof (Int)) ; fail = fail || !Symbolic->Esize ; } if (fail) { DEBUGm4 (("out of memory: rest of symbolic object\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Symbolic, SW) ; return (UMFPACK_ERROR_out_of_memory) ; } DEBUG0 (("Symbolic UMF_malloc_count - init_count = "ID"\n", UMF_malloc_count - init_count)) ; ASSERT (UMF_malloc_count == init_count + 21 + (SW->Rperm_2by2 != (Int *) NULL) + (Symbolic->Esize != (Int *) NULL)) ; Front_npivcol = Symbolic->Front_npivcol ; Front_parent = Symbolic->Front_parent ; Front_1strow = Symbolic->Front_1strow ; Front_leftmostdesc = Symbolic->Front_leftmostdesc ; Chain_start = Symbolic->Chain_start ; Chain_maxrows = Symbolic->Chain_maxrows ; Chain_maxcols = Symbolic->Chain_maxcols ; Esize = Symbolic->Esize ; /* ---------------------------------------------------------------------- */ /* assign rows to fronts */ /* ---------------------------------------------------------------------- */ /* find InFront, unless colamd has already computed it */ if (do_UMF_analyze) { DEBUGm4 ((">>>>>>>>>Computing Front_1strow from scratch\n")) ; /* empty rows go to dummy front nfr */ for (row = 0 ; row < n_row ; row++) { InFront [row] = nfr ; } /* assign the singleton pivot rows to the "empty" front */ for (k = 0 ; k < n1 ; k++) { row = Rperm1 [k] ; InFront [row] = EMPTY ; } DEBUG1 (("Front (EMPTY), singleton nrows "ID" ncols "ID"\n", k, k)) ; newj = n1 ; for (i = 0 ; i < nfr ; i++) { fpivcol = Fr_npivcol [i] ; f1rows = 0 ; /* for all pivot columns in front i */ for (kk = 0 ; kk < fpivcol ; kk++, newj++) { j = Cperm_init [newj] ; ASSERT (IMPLIES (newj >= n_col-nempty_col, Ap [j+1] - Ap [j] == 0)); for (p = Ap [j] ; p < Ap [j+1] ; p++) { row = Ai [p] ; if (InFront [row] == nfr) { /* this row belongs to front i */ DEBUG1 ((" Row "ID" in Front "ID"\n", row, i)) ; InFront [row] = i ; f1rows++ ; } } } Front_1strow [i] = f1rows ; DEBUG1 ((" Front "ID" has 1strows: "ID" pivcols "ID"\n", i, f1rows, fpivcol)) ; } } else { /* COLAMD has already computed InFront, but it is not yet * InFront [row] = front i, where row is an original row. It is * InFront [k-n1] = i for k in the range n1 to n_row-nempty_row, * and where row = Rperm1 [k]. Need to permute InFront. Also compute * # of original rows assembled into each front. * [ use Ci as workspace */ DEBUGm4 ((">>>>>>>>>Computing Front_1strow from colamd's InFront\n")) ; for (i = 0 ; i <= nfr ; i++) { Front_1strow [i] = 0 ; } /* assign the singleton pivot rows to "empty" front */ for (k = 0 ; k < n1 ; k++) { row = Rperm1 [k] ; Ci [row] = EMPTY ; } /* assign the non-empty rows to the front that assembled them */ for ( ; k < n_row - nempty_row ; k++) { row = Rperm1 [k] ; i = InFront [k - n1] ; ASSERT (i >= EMPTY && i < nfr) ; if (i != EMPTY) { Front_1strow [i]++ ; } /* use Ci as permuted version of InFront */ Ci [row] = i ; } /* empty rows go to the "dummy" front */ for ( ; k < n_row ; k++) { row = Rperm1 [k] ; Ci [row] = nfr ; } /* permute InFront so that InFront [row] = i if the original row is * in front i */ for (row = 0 ; row < n_row ; row++) { InFront [row] = Ci [row] ; } /* ] no longer need Ci as workspace */ } #ifndef NDEBUG for (row = 0 ; row < n_row ; row++) { if (InFront [row] == nfr) { DEBUG1 ((" Row "ID" in Dummy Front "ID"\n", row, nfr)) ; } else if (InFront [row] == EMPTY) { DEBUG1 ((" singleton Row "ID"\n", row)) ; } else { DEBUG1 ((" Row "ID" in Front "ID"\n", row, nfr)) ; } } #endif /* ---------------------------------------------------------------------- */ /* copy front information into Symbolic object */ /* ---------------------------------------------------------------------- */ k = n1 ; for (i = 0 ; i < nfr ; i++) { fpivcol = Fr_npivcol [i] ; DEBUG1 (("Front "ID" k "ID" npivcol "ID" nrows "ID" ncols "ID"\n", i, k, fpivcol, Fr_nrows [i], Fr_ncols [i])) ; k += fpivcol ; /* copy Front info into Symbolic object from SW */ Front_npivcol [i] = fpivcol ; Front_parent [i] = Fr_parent [i] ; } /* assign empty columns to dummy placehold front nfr */ DEBUG1 (("Dummy Cols in Front "ID" : "ID"\n", nfr, n_col-k)) ; Front_npivcol [nfr] = n_col - k ; Front_parent [nfr] = EMPTY ; /* ---------------------------------------------------------------------- */ /* find initial row permutation */ /* ---------------------------------------------------------------------- */ /* order the singleton pivot rows */ for (k = 0 ; k < n1 ; k++) { Rperm_init [k] = Rperm1 [k] ; } /* determine the first row in each front (in the new row ordering) */ for (i = 0 ; i < nfr ; i++) { f1rows = Front_1strow [i] ; DEBUG1 (("Front "ID" : npivcol "ID" parent "ID, i, Front_npivcol [i], Front_parent [i])) ; DEBUG1 ((" 1st rows in Front "ID" : "ID"\n", i, f1rows)) ; Front_1strow [i] = k ; k += f1rows ; } /* assign empty rows to dummy placehold front nfr */ DEBUG1 (("Rows in Front "ID" (dummy): "ID"\n", nfr, n_row-k)) ; Front_1strow [nfr] = k ; DEBUG1 (("nfr "ID" 1strow[nfr] "ID" nrow "ID"\n", nfr, k, n_row)) ; /* Use Ci as temporary workspace for F1 */ F1 = Ci ; /* [ of size nfr+1 */ ASSERT (Clen >= 2*n_row + nfr+1) ; for (i = 0 ; i <= nfr ; i++) { F1 [i] = Front_1strow [i] ; } for (row = 0 ; row < n_row ; row++) { i = InFront [row] ; if (i != EMPTY) { newrow = F1 [i]++ ; ASSERT (newrow >= n1) ; Rperm_init [newrow] = row ; } } Rperm_init [n_row] = EMPTY ; /* unused */ #ifndef NDEBUG for (k = 0 ; k < n_row ; k++) { DEBUG2 (("Rperm_init ["ID"] = "ID"\n", k, Rperm_init [k])) ; } #endif /* ] done using F1 */ /* ---------------------------------------------------------------------- */ /* find the diagonal map */ /* ---------------------------------------------------------------------- */ /* Rperm_init [newrow] = row gives the row permutation that is implied * by the column permutation, where "row" is a row index of the original * matrix A. It is not dependent on the Rperm_2by2 permutation, which * only redefines the "diagonal". Both are used to construct the * Diagonal_map. */ if (prefer_diagonal) { Int *Diagonal_map ; ASSERT (n_row == n_col && nn == n_row) ; ASSERT (nempty_row == nempty_col && nempty == nempty_row) ; /* allocate the Diagonal_map */ Symbolic->Diagonal_map = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ; Diagonal_map = Symbolic->Diagonal_map ; if (Diagonal_map == (Int *) NULL) { /* :: out of memory (diagonal map) :: */ DEBUGm4 (("out of memory: Diagonal map\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Symbolic, SW) ; return (UMFPACK_ERROR_out_of_memory) ; } /* use Ci as workspace to compute the inverse of Rperm_init [ */ for (newrow = 0 ; newrow < nn ; newrow++) { oldrow = Rperm_init [newrow] ; ASSERT (oldrow >= 0 && oldrow < nn) ; Ci [oldrow] = newrow ; } #if 0 if (strategy == UMFPACK_STRATEGY_2BY2) { ASSERT (Rperm_2by2 != (Int *) NULL) ; for (newcol = 0 ; newcol < nn ; newcol++) { oldcol = Cperm_init [newcol] ; /* 2-by-2 pivoting done in S */ oldrow = Rperm_2by2 [oldcol] ; newrow = Ci [oldrow] ; ASSERT (newrow >= 0 && newrow < nn) ; Diagonal_map [newcol] = newrow ; } } else { #endif for (newcol = 0 ; newcol < nn ; newcol++) { oldcol = Cperm_init [newcol] ; /* no 2-by-2 pivoting in S */ oldrow = oldcol ; newrow = Ci [oldrow] ; ASSERT (newrow >= 0 && newrow < nn) ; Diagonal_map [newcol] = newrow ; } #if 0 } #endif #ifndef NDEBUG DEBUG1 (("\nDiagonal map:\n")) ; for (newcol = 0 ; newcol < nn ; newcol++) { oldcol = Cperm_init [newcol] ; DEBUG3 (("oldcol "ID" newcol "ID":\n", oldcol, newcol)) ; for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++) { Entry aij ; CLEAR (aij) ; oldrow = Ai [p] ; newrow = Ci [oldrow] ; if (Ax != (double *) NULL) { ASSIGN (aij, Ax, Az, p, SPLIT (Az)) ; } if (oldrow == oldcol) { DEBUG2 ((" old diagonal : oldcol "ID" oldrow "ID" ", oldcol, oldrow)) ; EDEBUG2 (aij) ; DEBUG2 (("\n")) ; } if (newrow == Diagonal_map [newcol]) { DEBUG2 ((" MAP diagonal : newcol "ID" MAProw "ID" ", newcol, Diagonal_map [newrow])) ; EDEBUG2 (aij) ; DEBUG2 (("\n")) ; } } } #endif /* done using Ci as workspace ] */ } /* ---------------------------------------------------------------------- */ /* find the leftmost descendant of each front */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i <= nfr ; i++) { Front_leftmostdesc [i] = EMPTY ; } for (i = 0 ; i < nfr ; i++) { /* start at i and walk up the tree */ DEBUG2 (("Walk up front tree from "ID"\n", i)) ; j = i ; while (j != EMPTY && Front_leftmostdesc [j] == EMPTY) { DEBUG3 ((" Leftmost desc of "ID" is "ID"\n", j, i)) ; Front_leftmostdesc [j] = i ; j = Front_parent [j] ; DEBUG3 ((" go to j = "ID"\n", j)) ; } } /* ---------------------------------------------------------------------- */ /* find the frontal matrix chains and max frontal matrix sizes */ /* ---------------------------------------------------------------------- */ maxnrows = 1 ; /* max # rows in any front */ maxncols = 1 ; /* max # cols in any front */ dmaxfrsize = 1 ; /* max frontal matrix size */ /* start the first chain */ nchains = 0 ; /* number of chains */ Chain_start [0] = 0 ; /* front 0 starts a new chain */ maxrows = 1 ; /* max # rows for any front in current chain */ maxcols = 1 ; /* max # cols for any front in current chain */ DEBUG1 (("Constructing chains:\n")) ; for (i = 0 ; i < nfr ; i++) { /* get frontal matrix info */ fpivcol = Front_npivcol [i] ; /* # candidate pivot columns */ fallrows = Fr_nrows [i] ; /* all rows (not just Schur comp) */ fallcols = Fr_ncols [i] ; /* all cols (not just Schur comp) */ parent = Front_parent [i] ; /* parent in column etree */ fpiv = MIN (fpivcol, fallrows) ; /* # pivot rows and cols */ maxrows = MAX (maxrows, fallrows) ; maxcols = MAX (maxcols, fallcols) ; DEBUG1 (("Front: "ID", pivcol "ID", "ID"-by-"ID" parent "ID ", npiv "ID" Chain: maxrows "ID" maxcols "ID"\n", i, fpivcol, fallrows, fallcols, parent, fpiv, maxrows, maxcols)) ; if (parent != i+1) { /* this is the end of a chain */ double s ; DEBUG1 (("\nEnd of chain "ID"\n", nchains)) ; /* make sure maxrows is an odd number */ ASSERT (maxrows >= 0) ; if (maxrows % 2 == 0) maxrows++ ; DEBUG1 (("Chain maxrows "ID" maxcols "ID"\n", maxrows, maxcols)) ; Chain_maxrows [nchains] = maxrows ; Chain_maxcols [nchains] = maxcols ; /* keep track of the maximum front size for all chains */ /* for Info only: */ s = (double) maxrows * (double) maxcols ; dmaxfrsize = MAX (dmaxfrsize, s) ; /* for the subsequent numerical factorization */ maxnrows = MAX (maxnrows, maxrows) ; maxncols = MAX (maxncols, maxcols) ; DEBUG1 (("Chain dmaxfrsize %g\n\n", dmaxfrsize)) ; /* start the next chain */ nchains++ ; Chain_start [nchains] = i+1 ; maxrows = 1 ; maxcols = 1 ; } } /* for Info only: */ dmaxfrsize = ceil (dmaxfrsize) ; DEBUGm1 (("dmaxfrsize %30.20g Int_MAX "ID"\n", dmaxfrsize, Int_MAX)) ; ASSERT (Symbolic->nchains == nchains) ; /* For allocating objects in umfpack_numeric (does not include all possible * pivots, particularly pivots from prior fronts in the chain. Need to add * nb to these to get the # of columns in the L block, for example. This * is the largest row dimension and largest column dimension of any frontal * matrix. maxnrows is always odd. */ Symbolic->maxnrows = maxnrows ; Symbolic->maxncols = maxncols ; DEBUGm3 (("maxnrows "ID" maxncols "ID"\n", maxnrows, maxncols)) ; /* ---------------------------------------------------------------------- */ /* find the initial element sizes */ /* ---------------------------------------------------------------------- */ if (max_rdeg > dense_row_threshold) { /* there are one or more dense rows in the input matrix */ /* count the number of dense rows in each column */ /* use Ci as workspace for inverse of Rperm_init [ */ ASSERT (Esize != (Int *) NULL) ; for (newrow = 0 ; newrow < n_row ; newrow++) { oldrow = Rperm_init [newrow] ; ASSERT (oldrow >= 0 && oldrow < nn) ; Ci [oldrow] = newrow ; } for (col = n1 ; col < n_col - nempty_col ; col++) { oldcol = Cperm_init [col] ; esize = Cdeg [oldcol] ; ASSERT (esize > 0) ; for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++) { oldrow = Ai [p] ; newrow = Ci [oldrow] ; if (newrow >= n1 && Rdeg [oldrow] > dense_row_threshold) { esize-- ; } } ASSERT (esize >= 0) ; Esize [col - n1] = esize ; } /* done using Ci as workspace ] */ } /* If there are no dense rows, then Esize [col-n1] is identical to * Cdeg [col], once Cdeg is permuted below */ /* ---------------------------------------------------------------------- */ /* permute Cdeg and Rdeg according to initial column and row permutation */ /* ---------------------------------------------------------------------- */ /* use Ci as workspace [ */ for (k = 0 ; k < n_col ; k++) { Ci [k] = Cdeg [Cperm_init [k]] ; } for (k = 0 ; k < n_col ; k++) { Cdeg [k] = Ci [k] ; } for (k = 0 ; k < n_row ; k++) { Ci [k] = Rdeg [Rperm_init [k]] ; } for (k = 0 ; k < n_row ; k++) { Rdeg [k] = Ci [k] ; } /* done using Ci as workspace ] */ /* ---------------------------------------------------------------------- */ /* simulate UMF_kernel_init */ /* ---------------------------------------------------------------------- */ /* count elements and tuples at tail, LU factors of singletons, and * head and tail markers */ dlnz = n_inner ; /* upper limit of nz in L (incl diag) */ dunz = dlnz ; /* upper limit of nz in U (incl diag) */ /* head marker */ head_usage = 1 ; dhead_usage = 1 ; /* tail markers: */ tail_usage = 2 ; dtail_usage = 2 ; /* allocate the Rpi and Rpx workspace for UMF_kernel_init (incl. headers) */ tail_usage += UNITS (Int *, n_row+1) + UNITS (Entry *, n_row+1) + 2 ; dtail_usage += DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) + 2 ; DEBUG1 (("Symbolic usage after Rpi/Rpx allocation: head "ID" tail "ID"\n", head_usage, tail_usage)) ; /* LU factors for singletons, at the head of memory */ for (k = 0 ; k < n1 ; k++) { lnz = Cdeg [k] - 1 ; unz = Rdeg [k] - 1 ; dlnz += lnz ; dunz += unz ; DEBUG1 (("singleton k "ID" pivrow "ID" pivcol "ID" lnz "ID" unz "ID"\n", k, Rperm_init [k], Cperm_init [k], lnz, unz)) ; head_usage += UNITS (Int, lnz) + UNITS (Entry, lnz) + UNITS (Int, unz) + UNITS (Entry, unz) ; dhead_usage += DUNITS (Int, lnz) + DUNITS (Entry, lnz) + DUNITS (Int, unz) + DUNITS (Entry, unz) ; } DEBUG1 (("Symbolic init head usage: "ID" for LU singletons\n",head_usage)) ; /* column elements: */ for (k = n1 ; k < n_col - nempty_col; k++) { esize = Esize ? Esize [k-n1] : Cdeg [k] ; DEBUG2 ((" esize: "ID"\n", esize)) ; ASSERT (esize >= 0) ; if (esize > 0) { tail_usage += GET_ELEMENT_SIZE (esize, 1) + 1 ; dtail_usage += DGET_ELEMENT_SIZE (esize, 1) + 1 ; } } /* dense row elements */ if (Esize) { Int nrow_elements = 0 ; for (k = n1 ; k < n_row - nempty_row ; k++) { rdeg = Rdeg [k] ; if (rdeg > dense_row_threshold) { tail_usage += GET_ELEMENT_SIZE (1, rdeg) + 1 ; dtail_usage += GET_ELEMENT_SIZE (1, rdeg) + 1 ; nrow_elements++ ; } } Info [UMFPACK_NDENSE_ROW] = nrow_elements ; } DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" after els\n", head_usage + tail_usage, head_usage, tail_usage)) ; /* compute the tuple lengths */ if (Esize) { /* row tuples */ for (row = n1 ; row < n_row ; row++) { rdeg = Rdeg [row] ; tlen = (rdeg > dense_row_threshold) ? 1 : rdeg ; tail_usage += 1 + UNITS (Tuple, TUPLES (tlen)) ; dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ; } /* column tuples */ for (col = n1 ; col < n_col - nempty_col ; col++) { /* tlen is 1 plus the number of dense rows in this column */ esize = Esize [col - n1] ; tlen = (esize > 0) + (Cdeg [col] - esize) ; tail_usage += 1 + UNITS (Tuple, TUPLES (tlen)) ; dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ; } for ( ; col < n_col ; col++) { tail_usage += 1 + UNITS (Tuple, TUPLES (0)) ; dtail_usage += 1 + DUNITS (Tuple, TUPLES (0)) ; } } else { /* row tuples */ for (row = n1 ; row < n_row ; row++) { tlen = Rdeg [row] ; tail_usage += 1 + UNITS (Tuple, TUPLES (tlen)) ; dtail_usage += 1 + DUNITS (Tuple, TUPLES (tlen)) ; } /* column tuples */ for (col = n1 ; col < n_col ; col++) { tail_usage += 1 + UNITS (Tuple, TUPLES (1)) ; dtail_usage += 1 + DUNITS (Tuple, TUPLES (1)) ; } } Symbolic->num_mem_init_usage = head_usage + tail_usage ; DEBUG1 (("Symbolic usage: "ID" = head "ID" + tail "ID" final\n", Symbolic->num_mem_init_usage, head_usage, tail_usage)) ; ASSERT (UMF_is_permutation (Rperm_init, Ci, n_row, n_row)) ; /* initial head and tail usage in Numeric->Memory */ dmax_usage = dhead_usage + dtail_usage ; dmax_usage = MAX (Symbolic->num_mem_init_usage, ceil (dmax_usage)) ; Info [UMFPACK_VARIABLE_INIT_ESTIMATE] = dmax_usage ; /* In case Symbolic->num_mem_init_usage overflows, keep as a double, too */ Symbolic->dnum_mem_init_usage = dmax_usage ; /* free the Rpi and Rpx workspace */ tail_usage -= UNITS (Int *, n_row+1) + UNITS (Entry *, n_row+1) ; dtail_usage -= DUNITS (Int *, n_row+1) + DUNITS (Entry *, n_row+1) ; /* ---------------------------------------------------------------------- */ /* simulate UMF_kernel, assuming unsymmetric pivoting */ /* ---------------------------------------------------------------------- */ /* Use Ci as temporary workspace for link lists [ */ Link = Ci ; for (i = 0 ; i < nfr ; i++) { Link [i] = EMPTY ; } flops = 0 ; /* flop count upper bound */ for (chain = 0 ; chain < nchains ; chain++) { double fsize ; f1 = Chain_start [chain] ; f2 = Chain_start [chain+1] - 1 ; /* allocate frontal matrix working array (C, L, and U) */ dr = Chain_maxrows [chain] ; dc = Chain_maxcols [chain] ; fsize = nb*nb /* LU is nb-by-nb */ + dr*nb /* L is dr-by-nb */ + nb*dc /* U is nb-by-dc, stored by rows */ + dr*dc ; /* C is dr by dc */ dtail_usage += DUNITS (Entry, fsize) ; dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ; for (i = f1 ; i <= f2 ; i++) { /* get frontal matrix info */ fpivcol = Front_npivcol [i] ; /* # candidate pivot columns */ fallrows = Fr_nrows [i] ; /* all rows (not just Schur comp*/ fallcols = Fr_ncols [i] ; /* all cols (not just Schur comp*/ parent = Front_parent [i] ; /* parent in column etree */ fpiv = MIN (fpivcol, fallrows) ; /* # pivot rows and cols */ f = (double) fpiv ; r = fallrows - fpiv ; /* # rows in Schur comp. */ c = fallcols - fpiv ; /* # cols in Schur comp. */ /* assemble all children of front i in column etree */ for (child = Link [i] ; child != EMPTY ; child = Link [child]) { ASSERT (child >= 0 && child < i) ; ASSERT (Front_parent [child] == i) ; /* free the child element and remove it from tuple lists */ cp = MIN (Front_npivcol [child], Fr_nrows [child]) ; cr = Fr_nrows [child] - cp ; cc = Fr_ncols [child] - cp ; ASSERT (cp >= 0 && cr >= 0 && cc >= 0) ; dtail_usage -= ELEMENT_SIZE (cr, cc) ; } /* The flop count computed here is "canonical". */ /* factorize the frontal matrix */ flops += DIV_FLOPS * (f*r + (f-1)*f/2) /* scale pivot columns */ /* f outer products: */ + MULTSUB_FLOPS * (f*r*c + (r+c)*(f-1)*f/2 + (f-1)*f*(2*f-1)/6); /* count nonzeros and memory usage in double precision */ dlf = (f*f-f)/2 + f*r ; /* nz in L below diagonal */ duf = (f*f-f)/2 + f*c ; /* nz in U above diagonal */ dlnz += dlf ; dunz += duf ; /* store f columns of L and f rows of U */ dhead_usage += DUNITS (Entry, dlf + duf) /* numerical values (excl diag) */ + DUNITS (Int, r + c + f) ; /* indices (compressed) */ if (parent != EMPTY) { /* create new element and place in tuple lists */ dtail_usage += ELEMENT_SIZE (r, c) ; /* place in link list of parent */ Link [i] = Link [parent] ; Link [parent] = i ; } /* keep track of peak Numeric->Memory usage */ dmax_usage = MAX (dmax_usage, dhead_usage + dtail_usage) ; } /* free the current frontal matrix */ dtail_usage -= DUNITS (Entry, fsize) ; } dhead_usage = ceil (dhead_usage) ; dmax_usage = ceil (dmax_usage) ; Symbolic->num_mem_size_est = dhead_usage ; Symbolic->num_mem_usage_est = dmax_usage ; Symbolic->lunz_bound = dlnz + dunz - n_inner ; /* ] done using Ci as workspace for Link array */ /* ---------------------------------------------------------------------- */ /* estimate total memory usage in UMFPACK_numeric */ /* ---------------------------------------------------------------------- */ UMF_set_stats ( Info, Symbolic, dmax_usage, /* estimated peak size of Numeric->Memory */ dhead_usage, /* estimated final size of Numeric->Memory */ flops, /* estimated "true flops" */ dlnz, /* estimated nz in L */ dunz, /* estimated nz in U */ dmaxfrsize, /* estimated largest front size */ (double) n_col, /* worst case Numeric->Upattern size */ (double) n_inner, /* max possible pivots to be found */ (double) maxnrows, /* estimated largest #rows in front */ (double) maxncols, /* estimated largest #cols in front */ TRUE, /* assume scaling is to be performed */ prefer_diagonal, ESTIMATE) ; /* ---------------------------------------------------------------------- */ #ifndef NDEBUG for (i = 0 ; i < nchains ; i++) { DEBUG2 (("Chain "ID" start "ID" end "ID" maxrows "ID" maxcols "ID"\n", i, Chain_start [i], Chain_start [i+1] - 1, Chain_maxrows [i], Chain_maxcols [i])) ; UMF_dump_chain (Chain_start [i], Fr_parent, Fr_npivcol, Fr_nrows, Fr_ncols, nfr) ; } fpivcol = 0 ; for (i = 0 ; i < nfr ; i++) { fpivcol = MAX (fpivcol, Front_npivcol [i]) ; } DEBUG0 (("Max pivot cols in any front: "ID"\n", fpivcol)) ; DEBUG1 (("Largest front: maxnrows "ID" maxncols "ID" dmaxfrsize %g\n", maxnrows, maxncols, dmaxfrsize)) ; #endif /* ---------------------------------------------------------------------- */ /* UMFPACK_symbolic was successful, return the object handle */ /* ---------------------------------------------------------------------- */ Symbolic->valid = SYMBOLIC_VALID ; *SymbolicHandle = (void *) Symbolic ; /* ---------------------------------------------------------------------- */ /* free workspace */ /* ---------------------------------------------------------------------- */ /* (6) The last of the workspace is free'd. The final Symbolic object * consists of 12 to 14 allocated objects. Its final total size is lies * roughly between 4*n and 13*n for a square matrix, which is all that is * left of the memory allocated by this routine. If an error occurs, the * entire Symbolic object is free'd when this routine returns (the error * return routine, below). */ free_work (SW) ; DEBUG0 (("(3)Symbolic UMF_malloc_count - init_count = "ID"\n", UMF_malloc_count - init_count)) ; ASSERT (UMF_malloc_count == init_count + 12 + (Symbolic->Esize != (Int *) NULL) + (Symbolic->Diagonal_map != (Int *) NULL)) ; /* ---------------------------------------------------------------------- */ /* get the time used by UMFPACK_*symbolic */ /* ---------------------------------------------------------------------- */ umfpack_toc (stats) ; Info [UMFPACK_SYMBOLIC_WALLTIME] = stats [0] ; Info [UMFPACK_SYMBOLIC_TIME] = stats [1] ; return (UMFPACK_OK) ; } /* ========================================================================== */ /* === free_work ============================================================ */ /* ========================================================================== */ PRIVATE void free_work ( SWType *SW ) { if (SW) { SW->Rperm_2by2 = (Int *) UMF_free ((void *) SW->Rperm_2by2) ; SW->InvRperm1 = (Int *) UMF_free ((void *) SW->InvRperm1) ; SW->Rs = (double *) UMF_free ((void *) SW->Rs) ; SW->Si = (Int *) UMF_free ((void *) SW->Si) ; SW->Sp = (Int *) UMF_free ((void *) SW->Sp) ; SW->Ci = (Int *) UMF_free ((void *) SW->Ci) ; SW->Front_npivcol = (Int *) UMF_free ((void *) SW->Front_npivcol); SW->Front_nrows = (Int *) UMF_free ((void *) SW->Front_nrows) ; SW->Front_ncols = (Int *) UMF_free ((void *) SW->Front_ncols) ; SW->Front_parent = (Int *) UMF_free ((void *) SW->Front_parent) ; SW->Front_cols = (Int *) UMF_free ((void *) SW->Front_cols) ; SW->Cperm1 = (Int *) UMF_free ((void *) SW->Cperm1) ; SW->Rperm1 = (Int *) UMF_free ((void *) SW->Rperm1) ; SW->InFront = (Int *) UMF_free ((void *) SW->InFront) ; } } /* ========================================================================== */ /* === error ================================================================ */ /* ========================================================================== */ /* Error return from UMFPACK_symbolic. Free all allocated memory. */ PRIVATE void error ( SymbolicType **Symbolic, SWType *SW ) { free_work (SW) ; UMFPACK_free_symbolic ((void **) Symbolic) ; ASSERT (UMF_malloc_count == init_count) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.h0000644000175000017500000000102011674452555023051 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_grow_front ( NumericType *Numeric, Int fnr2, Int fnc2, WorkType *Work, Int do_what ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.h0000644000175000017500000000100011674452555023217 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_report_perm ( Int n, const Int P [ ], Int W [ ], Int prl, Int user ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_numeric.c0000644000175000017500000000551011674452555024205 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_save_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Saves a Numeric object to a file. It can later be read back in via a call to umfpack_*_load_numeric. */ #include "umf_internal.h" #include "umf_valid_numeric.h" #define WRITE(object,type,n) \ { \ ASSERT (object != (type *) NULL) ; \ if (fwrite (object, sizeof (type), n, f) != (size_t) n) \ { \ fclose (f) ; \ return (UMFPACK_ERROR_file_IO) ; \ } \ } /* ========================================================================== */ /* === UMFPACK_save_numeric ================================================= */ /* ========================================================================== */ GLOBAL Int UMFPACK_save_numeric ( void *NumericHandle, char *user_filename ) { NumericType *Numeric ; char *filename ; FILE *f ; /* get the Numeric object */ Numeric = (NumericType *) NumericHandle ; /* make sure the Numeric object is valid */ if (!UMF_valid_numeric (Numeric)) { return (UMFPACK_ERROR_invalid_Numeric_object) ; } /* get the filename, or use the default name if filename is NULL */ if (user_filename == (char *) NULL) { filename = "numeric.umf" ; } else { filename = user_filename ; } f = fopen (filename, "wb") ; if (!f) { return (UMFPACK_ERROR_file_IO) ; } /* write the Numeric object to the file, in binary */ WRITE (Numeric, NumericType, 1) ; WRITE (Numeric->D, Entry, MIN (Numeric->n_row, Numeric->n_col)+1) ; WRITE (Numeric->Rperm, Int, Numeric->n_row+1) ; WRITE (Numeric->Cperm, Int, Numeric->n_col+1) ; WRITE (Numeric->Lpos, Int, Numeric->npiv+1) ; WRITE (Numeric->Lilen, Int, Numeric->npiv+1) ; WRITE (Numeric->Lip, Int, Numeric->npiv+1) ; WRITE (Numeric->Upos, Int, Numeric->npiv+1) ; WRITE (Numeric->Uilen, Int, Numeric->npiv+1) ; WRITE (Numeric->Uip, Int, Numeric->npiv+1) ; if (Numeric->scale != UMFPACK_SCALE_NONE) { WRITE (Numeric->Rs, double, Numeric->n_row) ; } if (Numeric->ulen > 0) { WRITE (Numeric->Upattern, Int, Numeric->ulen+1) ; } WRITE (Numeric->Memory, Unit, Numeric->size) ; /* close the file */ fclose (f) ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.h0000644000175000017500000002175711674452555022145 0ustar sonnesonne/* ========================================================================== */ /* === umf_colamd.h ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Authors: The authors of the COLAMD code itself are Stefan I. Larimore and Timothy A. Davis, University of Florida. The algorithm was developed in collaboration with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory. Date: UMFPACK Version: see above. COLAMD Version 2.0 was released on January 31, 2000. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974, DMS-9803599, and CCR-0203270. UMFPACK: Copyright (c) 2003 by Timothy A. Davis. All Rights Reserved. See the UMFPACK README file for the License for your use of this code. Availability: Both UMFPACK and the original unmodified colamd/symamd library are available at http://www.cise.ufl.edu/research/sparse. */ #ifndef COLAMD_H #define COLAMD_H /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ #include /* ========================================================================== */ /* === Knob and statistics definitions ====================================== */ /* ========================================================================== */ /* size of the knobs [ ] array. Only knobs [0..2] are currently used. */ #define COLAMD_KNOBS 20 /* number of output statistics. Only stats [0..8] are currently used. */ #define COLAMD_STATS 20 /* knobs [0] and stats [0]: dense row knob and output statistic. */ #define COLAMD_DENSE_ROW 0 /* knobs [1] and stats [1]: dense column knob and output statistic. */ #define COLAMD_DENSE_COL 1 /* knobs [2]: aggressive absorption option */ #define COLAMD_AGGRESSIVE 2 /* stats [2]: memory defragmentation count output statistic */ #define COLAMD_DEFRAG_COUNT 2 /* stats [3]: colamd status: zero OK, > 0 warning or notice, < 0 error */ #define COLAMD_STATUS 3 /* stats [4..6]: error info, or info on jumbled columns */ #define COLAMD_INFO1 4 #define COLAMD_INFO2 5 #define COLAMD_INFO3 6 /* ------------------ */ /* added for UMFPACK: */ /* stats [7]: number of originally empty rows */ #define COLAMD_EMPTY_ROW 7 /* stats [8]: number of originally empty cols */ #define COLAMD_EMPTY_COL 8 /* stats [9]: number of rows with entries only in dense cols */ #define COLAMD_NEWLY_EMPTY_ROW 9 /* stats [10]: number of cols with entries only in dense rows */ #define COLAMD_NEWLY_EMPTY_COL 10 /* ------------------ */ /* error codes returned in stats [3]: */ #define COLAMD_OK (0) #define COLAMD_ERROR_jumbled_matrix (-11) #define COLAMD_ERROR_A_not_present (-1) #define COLAMD_ERROR_p_not_present (-2) #define COLAMD_ERROR_nrow_negative (-3) #define COLAMD_ERROR_ncol_negative (-4) #define COLAMD_ERROR_nnz_negative (-5) #define COLAMD_ERROR_p0_nonzero (-6) #define COLAMD_ERROR_A_too_small (-7) #define COLAMD_ERROR_col_length_negative (-8) #define COLAMD_ERROR_row_index_out_of_bounds (-9) #define COLAMD_ERROR_out_of_memory (-10) #define COLAMD_ERROR_internal_error (-999) /* ========================================================================== */ /* === Row and Column structures ============================================ */ /* ========================================================================== */ /* User code that makes use of the colamd/symamd routines need not directly */ /* reference these structures. They are used only for the COLAMD_RECOMMENDED */ /* macro. */ typedef struct Colamd_Col_struct { Int start ; /* index for A of first row in this column, or DEAD */ /* if column is dead */ Int length ; /* number of rows in this column */ union { Int thickness ; /* number of original columns represented by this */ /* col, if the column is alive */ Int parent ; /* parent in parent tree super-column structure, if */ /* the column is dead */ } shared1 ; union { Int score ; /* the score used to maintain heap, if col is alive */ Int order ; /* pivot ordering of this column, if col is dead */ } shared2 ; union { Int headhash ; /* head of a hash bucket, if col is at the head of */ /* a degree list */ Int hash ; /* hash value, if col is not in a degree list */ Int prev ; /* previous column in degree list, if col is in a */ /* degree list (but not at the head of a degree list) */ } shared3 ; union { Int degree_next ; /* next column, if col is in a degree list */ Int hash_next ; /* next column, if col is in a hash list */ } shared4 ; /* ------------------ */ /* added for UMFPACK: */ Int nextcol ; /* next column in this supercolumn */ Int lastcol ; /* last column in this supercolumn */ /* ------------------ */ } Colamd_Col ; typedef struct Colamd_Row_struct { Int start ; /* index for A of first col in this row */ Int length ; /* number of principal columns in this row */ union { Int degree ; /* number of principal & non-principal columns in row */ Int p ; /* used as a row pointer in init_rows_cols () */ } shared1 ; union { Int mark ; /* for computing set differences and marking dead rows*/ Int first_column ;/* first column in row (used in garbage collection) */ } shared2 ; /* ------------------ */ /* added for UMFPACK: */ Int thickness ; /* number of original rows represented by this row */ /* that are not yet pivotal */ Int front ; /* -1 if an original row */ /* k if this row represents the kth frontal matrix */ /* where k goes from 0 to at most n_col-1 */ /* ------------------ */ } Colamd_Row ; /* ========================================================================== */ /* === Colamd recommended memory size ======================================= */ /* ========================================================================== */ /* The recommended length Alen of the array A passed to colamd is given by the COLAMD_RECOMMENDED (nnz, n_row, n_col) macro. It returns -1 if any argument is negative. 2*nnz space is required for the row and column indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is required for the Col and Row arrays, respectively, which are internal to colamd. An additional n_col space is the minimal amount of "elbow room", and nnz/5 more space is recommended for run time efficiency. This macro is not needed when using symamd. */ /* about 8*(n_col+1) integers: */ #define UMF_COLAMD_C(n_col) ((n_col + 1) * sizeof (Colamd_Col) / sizeof (Int)) /* about 6*(n_row+1) integers: */ #define UMF_COLAMD_R(n_row) ((n_row + 1) * sizeof (Colamd_Row) / sizeof (Int)) /* UMFPACK: make sure Alen is >= 5*n_col + size of Col and Row structures. * Alen is typically about 2.2*nz + 9*n_col + 6*n_row, or 2.2nz+15n for * square matrices. */ #define UMF_COLAMD_RECOMMENDED(nnz, n_row, n_col) \ ( \ ((nnz) < 0 || (n_row) < 0 || (n_col) < 0) \ ? \ (-1) \ : \ (MAX (2 * (nnz), 4 * (n_col)) + \ (Int) UMF_COLAMD_C (n_col) + \ (Int) UMF_COLAMD_R (n_row) + (n_col) + ((nnz) / 5)) \ ) /* ========================================================================== */ /* === Prototypes of user-callable routines ================================= */ /* ========================================================================== */ /* colamd_recommended removed for UMFPACK */ void UMF_colamd_set_defaults /* sets default parameters */ ( /* knobs argument is modified on output */ double knobs [COLAMD_KNOBS] /* parameter settings for colamd */ ) ; Int UMF_colamd /* returns (1) if successful, (0) otherwise*/ ( /* A and p arguments are modified on output */ Int n_row, /* number of rows in A */ Int n_col, /* number of columns in A */ Int Alen, /* size of the array A */ Int A [], /* row indices of A, of size Alen */ Int p [], /* column pointers of A, of size n_col+1 */ double knobs [COLAMD_KNOBS],/* parameter settings for colamd */ Int stats [COLAMD_STATS] /* colamd output statistics and error codes */ /* ------------------ */ /* added for UMFPACK: */ , Int Front_npivcol [ ] , Int Front_nrows [ ] , Int Front_ncols [ ] , Int Front_parent [ ] , Int Front_cols [ ] , Int *p_nfr , Int InFront [ ] /* ------------------ */ ) ; /* symamd deleted for UMFPACK */ /* colamd_report deleted for UMFPACK */ /* symamd_report deleted for UMFPACK */ #endif /* COLAMD_H */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_free.c0000644000175000017500000000265111674452555021612 0ustar sonnesonne/* ========================================================================== */ /* === UMF_free ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Free a block previously allocated by UMF_malloc and return NULL. Usage is p = UMF_free (p), to ensure that we don't free it twice. Also maintains the UMFPACK malloc count. */ #include "umf_internal.h" #include "umf_free.h" #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) #include "umf_malloc.h" #endif GLOBAL void *UMF_free ( void *p ) { DEBUG0 (("UMF_free: "ID"\n", (Int) p)) ; if (p) { /* see AMD/Source/amd_global.c for the memory allocator selection */ amd_free (p) ; #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) /* One more object has been free'd. Keep track of the count. */ /* (purely for sanity checks). */ UMF_malloc_count-- ; DEBUG0 ((" new malloc count: "ID"\n", UMF_malloc_count)) ; #endif } return ((void *) NULL) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.c0000644000175000017500000002003611674452555023041 0ustar sonnesonne/* ========================================================================== */ /* === UMF_init_front ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.h" #include "umf_init_front.h" #include "umf_grow_front.h" /* ========================================================================== */ /* === zero_init_front ====================================================== */ /* ========================================================================== */ /* Set the initial frontal matrix to zero. */ PRIVATE void zero_init_front (Int m, Int n, Entry *Fcblock, Int d) { Int i, j ; Entry *F, *Fj = Fcblock ; for (j = 0 ; j < m ; j++) { F = Fj ; Fj += d ; for (i = 0 ; i < n ; i++) { /* CLEAR (Fcblock [i + j*d]) ; */ CLEAR (*F) ; F++ ; } } } /* ========================================================================== */ /* === UMF_init_front ======================================================= */ /* ========================================================================== */ GLOBAL Int UMF_init_front ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int i, j, fnr_curr, row, col, *Frows, *Fcols, *Fcpos, *Frpos, fncols, fnrows, *Wrow, fnr2, fnc2, rrdeg, ccdeg, *Wm, fnrows_extended ; Entry *Fcblock, *Fl, *Wy, *Wx ; /* ---------------------------------------------------------------------- */ /* get current frontal matrix and check for frontal growth */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG0 (("INIT FRONT\n")) ; DEBUG1 (("CURR before init:\n")) ; UMF_dump_current_front (Numeric, Work, FALSE) ; #endif if (Work->do_grow) { fnr2 = UMF_FRONTAL_GROWTH * Work->fnrows_new + 2 ; fnc2 = UMF_FRONTAL_GROWTH * Work->fncols_new + 2 ; if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, Work->pivrow_in_front ? 2 : 0)) { /* :: out of memory in umf_init_front :: */ DEBUGm4 (("out of memory: init front\n")) ; return (FALSE) ; } } #ifndef NDEBUG DEBUG1 (("CURR after grow:\n")) ; UMF_dump_current_front (Numeric, Work, FALSE) ; DEBUG1 (("fnrows new "ID" fncols new "ID"\n", Work->fnrows_new, Work->fncols_new)) ; #endif ASSERT (Work->fnpiv == 0) ; fnr_curr = Work->fnr_curr ; ASSERT (Work->fnrows_new + 1 <= fnr_curr) ; ASSERT (Work->fncols_new + 1 <= Work->fnc_curr) ; ASSERT (fnr_curr >= 0) ; ASSERT (fnr_curr % 2 == 1) ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ /* current front is defined by pivot row and column */ Frows = Work->Frows ; Fcols = Work->Fcols ; Frpos = Work->Frpos ; Fcpos = Work->Fcpos ; Work->fnzeros = 0 ; ccdeg = Work->ccdeg ; rrdeg = Work->rrdeg ; fnrows = Work->fnrows ; fncols = Work->fncols ; /* if both pivrow and pivcol are in front, then we extend the old one */ /* in UMF_extend_front, rather than starting a new one here. */ ASSERT (! (Work->pivrow_in_front && Work->pivcol_in_front)) ; /* ---------------------------------------------------------------------- */ /* place pivot column pattern in frontal matrix */ /* ---------------------------------------------------------------------- */ Fl = Work->Flblock ; if (Work->pivcol_in_front) { /* Append the pivot column extension. * Note that all we need to do is increment the size, since the * candidate pivot column pattern is already in place in * Frows [0 ... fnrows-1] (the old pattern), and * Frows [fnrows ... fnrows + Work->ccdeg - 1] (the new * pattern). Frpos is also properly defined. */ /* make a list of the new rows to scan */ Work->fscan_row = fnrows ; /* only scan the new rows */ Work->NewRows = Work->Wrp ; Wy = Work->Wy ; for (i = 0 ; i < fnrows ; i++) { Fl [i] = Wy [i] ; } fnrows_extended = fnrows + ccdeg ; for (i = fnrows ; i < fnrows_extended ; i++) { Fl [i] = Wy [i] ; /* flip the row index, since Wrp must be < 0 */ row = Frows [i] ; Work->NewRows [i] = FLIP (row) ; } fnrows = fnrows_extended ; } else { /* this is a completely new column */ Work->fscan_row = 0 ; /* scan all the rows */ Work->NewRows = Frows ; Wm = Work->Wm ; Wx = Work->Wx ; for (i = 0 ; i < ccdeg ; i++) { Fl [i] = Wx [i] ; row = Wm [i] ; Frows [i] = row ; Frpos [row] = i ; } fnrows = ccdeg ; } Work->fnrows = fnrows ; #ifndef NDEBUG DEBUG3 (("New Pivot col "ID" now in front, length "ID"\n", Work->pivcol, fnrows)) ; for (i = 0 ; i < fnrows ; i++) { DEBUG4 ((" "ID": row "ID"\n", i, Frows [i])) ; ASSERT (Frpos [Frows [i]] == i) ; } #endif /* ---------------------------------------------------------------------- */ /* place pivot row pattern in frontal matrix */ /* ---------------------------------------------------------------------- */ Wrow = Work->Wrow ; if (Work->pivrow_in_front) { /* append the pivot row extension */ Work->fscan_col = fncols ; /* only scan the new columns */ Work->NewCols = Work->Wp ; #ifndef NDEBUG for (j = 0 ; j < fncols ; j++) { col = Fcols [j] ; ASSERT (col >= 0 && col < Work->n_col) ; ASSERT (Fcpos [col] == j * fnr_curr) ; } #endif /* Wrow == Fcol for the IN_IN case, and for the OUT_IN case when * the pivrow [IN][IN] happens to be the same as pivrow [OUT][IN]. * See UMF_local_search for more details. */ ASSERT (IMPLIES (Work->pivcol_in_front, Wrow == Fcols)) ; if (Wrow == Fcols) { for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; /* Fcols [j] = col ; not needed */ /* flip the col index, since Wp must be < 0 */ Work->NewCols [j] = FLIP (col) ; Fcpos [col] = j * fnr_curr ; } } else { for (j = fncols ; j < rrdeg ; j++) { col = Wrow [j] ; Fcols [j] = col ; /* flip the col index, since Wp must be < 0 */ Work->NewCols [j] = FLIP (col) ; Fcpos [col] = j * fnr_curr ; } } } else { /* this is a completely new row */ Work->fscan_col = 0 ; /* scan all the columns */ Work->NewCols = Fcols ; for (j = 0 ; j < rrdeg ; j++) { col = Wrow [j] ; Fcols [j] = col ; Fcpos [col] = j * fnr_curr ; } } DEBUGm1 (("rrdeg "ID" fncols "ID"\n", rrdeg, fncols)) ; fncols = rrdeg ; Work->fncols = fncols ; /* ---------------------------------------------------------------------- */ /* clear the frontal matrix */ /* ---------------------------------------------------------------------- */ ASSERT (fnrows == Work->fnrows_new + 1) ; ASSERT (fncols == Work->fncols_new + 1) ; Fcblock = Work->Fcblock ; ASSERT (Fcblock != (Entry *) NULL) ; zero_init_front (fncols, fnrows, Fcblock, fnr_curr) ; #ifndef NDEBUG DEBUG3 (("New Pivot row "ID" now in front, length "ID" fnr_curr "ID"\n", Work->pivrow, fncols, fnr_curr)) ; for (j = 0 ; j < fncols ; j++) { DEBUG4 (("col "ID" position "ID"\n", j, Fcols [j])) ; ASSERT (Fcpos [Fcols [j]] == j * fnr_curr) ; } #endif /* ---------------------------------------------------------------------- */ /* current workspace usage: */ /* ---------------------------------------------------------------------- */ /* Fcblock [0..fnr_curr-1, 0..fnc_curr-1]: space for the new frontal * matrix. Fcblock (i,j) is located at Fcblock [i+j*fnr_curr] */ return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/cholmod_blas.h0000644000175000017500000003223711674452555022460 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_blas.h =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_blas.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod_blas.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* This does not need to be included in the user's program. */ #ifndef CHOLMOD_BLAS_H #define CHOLMOD_BLAS_H /* ========================================================================== */ /* === Architecture ========================================================= */ /* ========================================================================== */ #if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2) #define CHOLMOD_SOL2 #define CHOLMOD_ARCHITECTURE "Sun Solaris" #elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI) #define CHOLMOD_SGI #define CHOLMOD_ARCHITECTURE "SGI Irix" #elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86) #define CHOLMOD_LINUX #define CHOLMOD_ARCHITECTURE "Linux" #elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS) #define CHOLMOD_AIX #define CHOLMOD_ARCHITECTURE "IBM AIX" #define BLAS_NO_UNDERSCORE #elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA) #define CHOLMOD_ALPHA #define CHOLMOD_ARCHITECTURE "Compaq Alpha" #elif defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64) #if defined (__MINGW32__) || defined (__MINGW32__) #define CHOLMOD_MINGW #elif defined (__CYGWIN32__) || defined (__CYGWIN32__) #define CHOLMOD_CYGWIN #else #define CHOLMOD_WINDOWS #define BLAS_NO_UNDERSCORE #endif #define CHOLMOD_ARCHITECTURE "Microsoft Windows" #elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX) #define CHOLMOD_HP #define CHOLMOD_ARCHITECTURE "HP Unix" #define BLAS_NO_UNDERSCORE #elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700) #define CHOLMOD_HP #define CHOLMOD_ARCHITECTURE "HP 700 Unix" #define BLAS_NO_UNDERSCORE #else /* If the architecture is unknown, and you call the BLAS, you may need to */ /* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */ #define CHOLMOD_ARCHITECTURE "unknown" #endif /* ========================================================================== */ /* === BLAS and LAPACK names ================================================ */ /* ========================================================================== */ /* Prototypes for the various versions of the BLAS. */ /* Determine if the 64-bit Sun Performance BLAS is to be used */ #if defined(CHOLMOD_SOL2) && !defined(NSUNPERF) && defined(LONG) && defined(LONGBLAS) #define SUN64 #endif #ifdef SUN64 #define BLAS_DTRSV dtrsv_64_ #define BLAS_DGEMV dgemv_64_ #define BLAS_DTRSM dtrsm_64_ #define BLAS_DGEMM dgemm_64_ #define BLAS_DSYRK dsyrk_64_ #define BLAS_DGER dger_64_ #define BLAS_DSCAL dscal_64_ #define LAPACK_DPOTRF dpotrf_64_ #define BLAS_ZTRSV ztrsv_64_ #define BLAS_ZGEMV zgemv_64_ #define BLAS_ZTRSM ztrsm_64_ #define BLAS_ZGEMM zgemm_64_ #define BLAS_ZHERK zherk_64_ #define BLAS_ZGER zgeru_64_ #define BLAS_ZSCAL zscal_64_ #define LAPACK_ZPOTRF zpotrf_64_ #elif defined (BLAS_NO_UNDERSCORE) #define BLAS_DTRSV dtrsv #define BLAS_DGEMV dgemv #define BLAS_DTRSM dtrsm #define BLAS_DGEMM dgemm #define BLAS_DSYRK dsyrk #define BLAS_DGER dger #define BLAS_DSCAL dscal #define LAPACK_DPOTRF dpotrf #define BLAS_ZTRSV ztrsv #define BLAS_ZGEMV zgemv #define BLAS_ZTRSM ztrsm #define BLAS_ZGEMM zgemm #define BLAS_ZHERK zherk #define BLAS_ZGER zgeru #define BLAS_ZSCAL zscal #define LAPACK_ZPOTRF zpotrf #else #define BLAS_DTRSV dtrsv_ #define BLAS_DGEMV dgemv_ #define BLAS_DTRSM dtrsm_ #define BLAS_DGEMM dgemm_ #define BLAS_DSYRK dsyrk_ #define BLAS_DGER dger_ #define BLAS_DSCAL dscal_ #define LAPACK_DPOTRF dpotrf_ #define BLAS_ZTRSV ztrsv_ #define BLAS_ZGEMV zgemv_ #define BLAS_ZTRSM ztrsm_ #define BLAS_ZGEMM zgemm_ #define BLAS_ZHERK zherk_ #define BLAS_ZGER zgeru_ #define BLAS_ZSCAL zscal_ #define LAPACK_ZPOTRF zpotrf_ #endif /* ========================================================================== */ /* === BLAS and LAPACK integer arguments ==================================== */ /* ========================================================================== */ /* CHOLMOD can be compiled with -D'LONGBLAS=long' for the Sun Performance * Library, or -D'LONGBLAS=long long' for SGI's SCSL BLAS. This defines the * integer used in the BLAS for the cholmod_l_* routines. * * The "int" version of CHOLMOD always uses the "int" version of the BLAS. */ #if defined (LONGBLAS) && defined (LONG) #define BLAS_INT LONGBLAS #else #define BLAS_INT int #endif /* If the BLAS integer is smaller than the basic CHOLMOD integer, then we need * to check for integer overflow when converting from one to the other. If * any integer overflows, the externally-defined blas_ok variable is set to * FALSE. blas_ok should be set to TRUE before calling any BLAS_* macro. */ #define CHECK_BLAS_INT (sizeof (BLAS_INT) < sizeof (Int)) #define EQ(K,k) (((BLAS_INT) K) == ((Int) k)) /* ========================================================================== */ /* === BLAS and LAPACK prototypes and macros ================================ */ /* ========================================================================== */ void BLAS_DGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta, double *Y, BLAS_INT *incy) ; #define BLAS_dgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \ && EQ (INCY,incy) ; \ } \ if (blas_ok) \ { \ BLAS_DGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \ } \ } void BLAS_ZGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta, double *Y, BLAS_INT *incy) ; #define BLAS_zgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \ && EQ (INCY,incy) ; \ } \ if (blas_ok) \ { \ BLAS_ZGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \ } \ } void BLAS_DTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx) ; #define BLAS_dtrsv(uplo,trans,diag,n,A,lda,X,incx) \ { \ BLAS_INT N = n, LDA = lda, INCX = incx ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) ; \ } \ if (blas_ok) \ { \ BLAS_DTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \ } \ } void BLAS_ZTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx) ; #define BLAS_ztrsv(uplo,trans,diag,n,A,lda,X,incx) \ { \ BLAS_INT N = n, LDA = lda, INCX = incx ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) ; \ } \ if (blas_ok) \ { \ BLAS_ZTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \ } \ } void BLAS_DTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb) ; #define BLAS_dtrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \ { \ BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (LDB,ldb) ; \ } \ if (blas_ok) \ { \ BLAS_DTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\ } \ } void BLAS_ZTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb) ; #define BLAS_ztrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \ { \ BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (LDB,ldb) ; \ } \ if (blas_ok) \ { \ BLAS_ZTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\ } \ } void BLAS_DGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_dgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \ { \ BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDA,lda) \ && EQ (LDB,ldb) && EQ (LDC,ldc) ; \ } \ if (blas_ok) \ { \ BLAS_DGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \ C, &LDC) ; \ } \ } void BLAS_ZGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \ { \ BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (K,k) && EQ (LDA,lda) \ && EQ (LDB,ldb) && EQ (LDC,ldc) ; \ } \ if (blas_ok) \ { \ BLAS_ZGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \ C, &LDC) ; \ } \ } void BLAS_DSYRK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \ { \ BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && EQ (LDC,ldc) ; \ } \ if (blas_ok) \ { \ BLAS_DSYRK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \ } \ } \ void BLAS_ZHERK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \ { \ BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && EQ (LDC,ldc) ; \ } \ if (blas_ok) \ { \ BLAS_ZHERK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \ } \ } \ void LAPACK_DPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda, BLAS_INT *info) ; #define LAPACK_dpotrf(uplo,n,A,lda,info) \ { \ BLAS_INT N = n, LDA = lda, INFO = 1 ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (LDA,lda) ; \ } \ if (blas_ok) \ { \ LAPACK_DPOTRF (uplo, &N, A, &LDA, &INFO) ; \ } \ info = INFO ; \ } void LAPACK_ZPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda, BLAS_INT *info) ; #define LAPACK_zpotrf(uplo,n,A,lda,info) \ { \ BLAS_INT N = n, LDA = lda, INFO = 1 ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (LDA,lda) ; \ } \ if (blas_ok) \ { \ LAPACK_ZPOTRF (uplo, &N, A, &LDA, &INFO) ; \ } \ info = INFO ; \ } /* ========================================================================== */ void BLAS_DSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ; #define BLAS_dscal(n,alpha,Y,incy) \ { \ BLAS_INT N = n, INCY = incy ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (INCY,incy) ; \ } \ if (blas_ok) \ { \ BLAS_DSCAL (&N, alpha, Y, &INCY) ; \ } \ } void BLAS_ZSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ; #define BLAS_zscal(n,alpha,Y,incy) \ { \ BLAS_INT N = n, INCY = incy ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (N,n) && EQ (INCY,incy) ; \ } \ if (blas_ok) \ { \ BLAS_ZSCAL (&N, alpha, Y, &INCY) ; \ } \ } void BLAS_DGER (BLAS_INT *m, BLAS_INT *n, double *alpha, double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy, double *A, BLAS_INT *lda) ; #define BLAS_dger(m,n,alpha,X,incx,Y,incy,A,lda) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \ && EQ (INCY,incy) ; \ } \ if (blas_ok) \ { \ BLAS_DGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \ } \ } void BLAS_ZGER (BLAS_INT *m, BLAS_INT *n, double *alpha, double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy, double *A, BLAS_INT *lda) ; #define BLAS_zgeru(m,n,alpha,X,incx,Y,incy,A,lda) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT) \ { \ blas_ok &= EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx) \ && EQ (INCY,incy) ; \ } \ if (blas_ok) \ { \ BLAS_ZGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \ } \ } #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.c0000644000175000017500000001251711674452555023366 0ustar sonnesonne/* ========================================================================== */ /* === UMF_build_tuples ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Construct the tuple lists from a set of packed elements (no holes in elements, no internal or external fragmentation, and a packed (0..Work->nel) element name space). Assume no tuple lists are currently allocated, but that the tuple lengths have been initialized by UMF_tuple_lengths. Returns TRUE if successful, FALSE if not enough memory. */ #include "umf_internal.h" #include "umf_build_tuples.h" #include "umf_mem_alloc_tail_block.h" GLOBAL Int UMF_build_tuples ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int e, nrows, ncols, nel, *Rows, *Cols, row, col, n_row, n_col, *E, *Row_tuples, *Row_degree, *Row_tlen, *Col_tuples, *Col_degree, *Col_tlen, n1 ; Element *ep ; Unit *p ; Tuple tuple, *tp ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ E = Work->E ; Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */ Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */ Row_tuples = Numeric->Uip ; Row_tlen = Numeric->Uilen ; Col_tuples = Numeric->Lip ; Col_tlen = Numeric->Lilen ; n_row = Work->n_row ; n_col = Work->n_col ; nel = Work->nel ; n1 = Work->n1 ; DEBUG3 (("BUILD_TUPLES: n_row "ID" n_col "ID" nel "ID"\n", n_row, n_col, nel)) ; /* ---------------------------------------------------------------------- */ /* allocate space for the tuple lists */ /* ---------------------------------------------------------------------- */ /* Garbage collection and memory reallocation have already attempted to */ /* ensure that there is enough memory for all the tuple lists. If */ /* memory allocation fails here, then there is nothing more to be done. */ for (row = n1 ; row < n_row ; row++) { if (NON_PIVOTAL_ROW (row)) { Row_tuples [row] = UMF_mem_alloc_tail_block (Numeric, UNITS (Tuple, TUPLES (Row_tlen [row]))) ; if (!Row_tuples [row]) { /* :: out of memory for row tuples :: */ DEBUGm4 (("out of memory: build row tuples\n")) ; return (FALSE) ; /* out of memory for row tuples */ } Row_tlen [row] = 0 ; } } /* push on stack in reverse order, so column tuples are in the order */ /* that they will be deleted. */ for (col = n_col-1 ; col >= n1 ; col--) { if (NON_PIVOTAL_COL (col)) { Col_tuples [col] = UMF_mem_alloc_tail_block (Numeric, UNITS (Tuple, TUPLES (Col_tlen [col]))) ; if (!Col_tuples [col]) { /* :: out of memory for col tuples :: */ DEBUGm4 (("out of memory: build col tuples\n")) ; return (FALSE) ; /* out of memory for col tuples */ } Col_tlen [col] = 0 ; } } #ifndef NDEBUG UMF_dump_memory (Numeric) ; #endif /* ---------------------------------------------------------------------- */ /* create the tuple lists (exclude element 0) */ /* ---------------------------------------------------------------------- */ /* for all elements, in order of creation */ for (e = 1 ; e <= nel ; e++) { DEBUG9 (("Adding tuples for element: "ID" at "ID"\n", e, E [e])) ; ASSERT (E [e]) ; /* no external fragmentation */ p = Numeric->Memory + E [e] ; GET_ELEMENT_PATTERN (ep, p, Cols, Rows, ncols) ; nrows = ep->nrows ; ASSERT (e != 0) ; ASSERT (e == 0 || nrows == ep->nrowsleft) ; ASSERT (e == 0 || ncols == ep->ncolsleft) ; tuple.e = e ; for (tuple.f = 0 ; tuple.f < ncols ; tuple.f++) { col = Cols [tuple.f] ; ASSERT (col >= n1 && col < n_col) ; ASSERT (NON_PIVOTAL_COL (col)) ; ASSERT (Col_tuples [col]) ; tp = ((Tuple *) (Numeric->Memory + Col_tuples [col])) + Col_tlen [col]++ ; *tp = tuple ; #ifndef NDEBUG UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; #endif } for (tuple.f = 0 ; tuple.f < nrows ; tuple.f++) { row = Rows [tuple.f] ; ASSERT (row >= n1 && row < n_row) ; ASSERT (NON_PIVOTAL_COL (col)) ; ASSERT (Row_tuples [row]) ; tp = ((Tuple *) (Numeric->Memory + Row_tuples [row])) + Row_tlen [row]++ ; *tp = tuple ; #ifndef NDEBUG UMF_dump_rowcol (0, Numeric, Work, row, FALSE) ; #endif } } /* ---------------------------------------------------------------------- */ /* the tuple lists are now valid, and can be scanned */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG UMF_dump_memory (Numeric) ; UMF_dump_matrix (Numeric, Work, FALSE) ; #endif DEBUG3 (("BUILD_TUPLES: done\n")) ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.c0000644000175000017500000007203011674452555023172 0ustar sonnesonne/* ========================================================================== */ /* === UMF_kernel_init ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Initialize the kernel: scale the matrix, load the initial elements, and build the tuple lists. Returns TRUE if successful, FALSE if out of memory or if the pattern has changed since UMFPACK_*symbolic. UMFPACK_numeric allocates at least enough space for UMF_kernel_init to succeed; otherwise it does not call UMF_kernel_init. So an out-of-memory condition means that the pattern must have gotten larger. */ #include "umf_internal.h" #include "umf_kernel_init.h" #include "umf_tuple_lengths.h" #include "umf_build_tuples.h" #include "umf_mem_init_memoryspace.h" #include "umf_mem_alloc_element.h" #include "umf_mem_alloc_head_block.h" #include "umf_mem_alloc_tail_block.h" #include "umf_mem_free_tail_block.h" #include "umf_scale.h" /* ========================================================================== */ /* === packsp =============================================================== */ /* ========================================================================== */ /* remove zero or small entries from a column of L or a row of U */ PRIVATE Int packsp /* returns new value of pnew */ ( Int pnew, /* index into Memory of next free space */ Int *p_p, /* ptr to index of old pattern in Memory on input, new pattern on output */ Int *p_len, /* ptr to length of old pattern on input, new pattern on output */ Int drop, /* TRUE if small nonzero entries are to be dropped */ double droptol, /* the drop tolerance */ Unit *Memory /* contains the sparse vector on input and output */ ) { Entry x ; double s ; Entry *Bx, *Bx2 ; Int p, i, len, len_new, *Bi, *Bi2 ; /* get the pointers to the sparse vector, and its length */ p = *p_p ; len = *p_len ; Bi = (Int *) (Memory + p) ; p += UNITS (Int, len) ; Bx = (Entry *) (Memory + p) ; p += UNITS (Entry, len) ; DEBUGm4 ((" p "ID" len "ID" pnew "ID"\n", p, len, pnew)) ; /* the vector resides in Bi [0..len-1] and Bx [0..len-1] */ /* first, compact the vector in place */ len_new = 0 ; for (p = 0 ; p < len ; p++) { i = Bi [p] ; x = Bx [p] ; DEBUGm4 ((" old vector: i "ID" value: ", i)) ; EDEBUGk (-4, x) ; DEBUGm4 (("\n")) ; ASSERT (i >= 0) ; /* skip if zero or below drop tolerance */ if (IS_ZERO (x)) continue ; if (drop) { APPROX_ABS (s, x) ; if (s <= droptol) continue ; } /* store the value back into the vector */ if (len_new != p) { Bi [len_new] = i ; Bx [len_new] = x ; } len_new++ ; } ASSERT (len_new <= len) ; /* the vector is now in Bi [0..len_new-1] and Bx [0..len_new-1] */ #ifndef NDEBUG for (p = 0 ; p < len_new ; p++) { DEBUGm4 ((" new vector: i "ID" value: ", Bi [p])) ; EDEBUGk (-4, Bx [p]) ; DEBUGm4 (("\n")) ; ASSERT (Bi [p] >= 0) ; } #endif /* allocate new space for the compacted vector */ *p_p = pnew ; *p_len = len_new ; Bi2 = (Int *) (Memory + pnew) ; pnew += UNITS (Int, len_new) ; Bx2 = (Entry *) (Memory + pnew) ; pnew += UNITS (Entry, len_new) ; DEBUGm4 ((" pnew "ID" len_new "ID"\n", pnew, len_new)) ; /* shift the vector upwards, into its new space */ for (p = 0 ; p < len_new ; p++) { Bi2 [p] = Bi [p] ; } for (p = 0 ; p < len_new ; p++) { Bx2 [p] = Bx [p] ; } #ifndef NDEBUG for (p = 0 ; p < len_new ; p++) { DEBUGm4 ((" packed vec: i "ID" value: ", Bi2 [p])) ; EDEBUGk (-4, Bx2 [p]) ; DEBUGm4 (("\n")) ; ASSERT (Bi2 [p] >= 0) ; } #endif /* return the pointer to the space just after the new vector */ return (pnew) ; } /* ========================================================================== */ /* === UMF_kernel_init ====================================================== */ /* ========================================================================== */ GLOBAL Int UMF_kernel_init ( const Int Ap [ ], /* user's input matrix (not modified) */ const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry x, pivot_value ; double unused = 0, rsmin, rsmax, rs, droptol ; Entry *D, *C, *Lval, **Rpx ; double *Rs ; Int row, k, oldcol, size, e, p1, p2, p, nz, *Rows, *Cols, *E, i, *Upos, *Lpos, n_row, n_col, *Wp, *Cperm_init, *Frpos, *Fcpos, *Row_degree, nn, *Row_tlen, *Col_degree, *Col_tlen, oldrow, newrow, ilast, *Wrp, *Rperm_init, col, n_inner, prefer_diagonal, *Diagonal_map, nempty, *Diagonal_imap, fixQ, rdeg, cdeg, nempty_col, *Esize, esize, pnew, *Lip, *Uip, *Lilen, *Uilen, llen, pa, *Cdeg, *Rdeg, n1, clen, do_scale, lnz, unz, lip, uip, k1, *Rperm, *Cperm, pivcol, *Li, lilen, drop, **Rpi, nempty_row, dense_row_threshold, empty_elements, rpi, rpx ; Element *ep ; Unit *Memory ; #ifdef COMPLEX Int split = SPLIT (Az) ; #endif #ifndef NRECIPROCAL Int do_recip = FALSE ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ DEBUG0 (("KERNEL INIT\n")) ; n_row = Symbolic->n_row ; n_col = Symbolic->n_col ; nn = MAX (n_row, n_col) ; n_inner = MIN (n_row, n_col) ; nempty_col = Symbolic->nempty_col ; nempty_row = Symbolic->nempty_row ; nempty = MIN (nempty_row, nempty_col) ; ASSERT (n_row > 0 && n_col > 0) ; Cperm_init = Symbolic->Cperm_init ; Rperm_init = Symbolic->Rperm_init ; Cdeg = Symbolic->Cdeg ; Rdeg = Symbolic->Rdeg ; n1 = Symbolic->n1 ; dense_row_threshold = Symbolic->dense_row_threshold ; DEBUG0 (("Singletons: "ID"\n", n1)) ; Work->nforced = 0 ; Work->ndiscard = 0 ; Work->noff_diagonal = 0 ; nz = Ap [n_col] ; if (nz < 0 || Ap [0] != 0 || nz != Symbolic->nz) { DEBUGm4 (("nz or Ap [0] bad\n")) ; return (FALSE) ; /* pattern changed */ } prefer_diagonal = Symbolic->prefer_diagonal ; Diagonal_map = Work->Diagonal_map ; Diagonal_imap = Work->Diagonal_imap ; /* ---------------------------------------------------------------------- */ /* initialize the Numeric->Memory space for LU, elements, and tuples */ /* ---------------------------------------------------------------------- */ UMF_mem_init_memoryspace (Numeric) ; DEBUG1 (("Kernel init head usage, before allocs: "ID"\n", Numeric->ihead)) ; /* ---------------------------------------------------------------------- */ /* initialize the Work and Numeric objects */ /* ---------------------------------------------------------------------- */ /* current front is empty */ Work->fnpiv = 0 ; Work->fncols = 0 ; Work->fnrows = 0 ; Work->fncols_max = 0 ; Work->fnrows_max = 0 ; Work->fnzeros = 0 ; Work->fcurr_size = 0 ; Work->fnr_curr = 0 ; Work->fnc_curr = 0 ; Work->nz = nz ; Work->prior_element = EMPTY ; Work->ulen = 0 ; Work->llen = 0 ; Work->npiv = n1 ; Work->frontid = 0 ; Work->nextcand = n1 ; Memory = Numeric->Memory ; Rperm = Numeric->Rperm ; Cperm = Numeric->Cperm ; Row_degree = Numeric->Rperm ; Col_degree = Numeric->Cperm ; /* Row_tuples = Numeric->Uip ; not needed */ Row_tlen = Numeric->Uilen ; /* Col_tuples = Numeric->Lip ; not needed */ Col_tlen = Numeric->Lilen ; Lip = Numeric->Lip ; Uip = Numeric->Uip ; Lilen = Numeric->Lilen ; Uilen = Numeric->Uilen ; Frpos = Work->Frpos ; Fcpos = Work->Fcpos ; Wp = Work->Wp ; Wrp = Work->Wrp ; D = Numeric->D ; Upos = Numeric->Upos ; Lpos = Numeric->Lpos ; for (k = 0 ; k < n_inner ; k++) { CLEAR (D [k]) ; } Rs = Numeric->Rs ; for (row = 0 ; row <= n_row ; row++) { Lpos [row] = EMPTY ; /* Row_tuples [row] = 0 ; set in UMF_build_tuples */ /* Row_degree [row] = 0 ; initialized below */ Row_tlen [row] = 0 ; /* Frpos [row] = EMPTY ; do this later */ } for (col = 0 ; col <= n_col ; col++) { Upos [col] = EMPTY ; /* Col_tuples [col] = 0 ; set in UMF_build_tuples */ /* Col_degree [col] = 0 ; initialized below */ Col_tlen [col] = 0 ; Fcpos [col] = EMPTY ; Wrp [col] = 0 ; } Work->Wrpflag = 1 ; /* When cleared, Wp [0..nn] is < 0 */ for (i = 0 ; i <= nn ; i++) { Wp [i] = EMPTY ; } /* In col search, Wp [row] is set to a position, which is >= 0. */ /* When cleared, Wrp [0..n_col] is < Wrpflag */ /* In row search, Wrp [col] is set to Wrpflag. */ /* no need to initialize Wm, Wio, Woi, and Woo */ /* clear the external degree counters */ Work->cdeg0 = 1 ; Work->rdeg0 = 1 ; fixQ = Symbolic->fixQ ; E = Work->E ; Numeric->n_row = n_row ; Numeric->n_col = n_col ; Numeric->npiv = 0 ; Numeric->nnzpiv = 0 ; Numeric->min_udiag = 0.0 ; Numeric->max_udiag = 0.0 ; Numeric->rcond = 0.0 ; Numeric->isize = 0 ; Numeric->nLentries = 0 ; Numeric->nUentries = 0 ; Numeric->lnz = 0 ; Numeric->unz = 0 ; Numeric->all_lnz = 0 ; Numeric->all_unz = 0 ; Numeric->maxfrsize = 0 ; Numeric->maxnrows = 0 ; Numeric->maxncols = 0 ; Numeric->flops = 0. ; Numeric->n1 = n1 ; droptol = Numeric->droptol ; drop = (droptol > 0) ; /* ---------------------------------------------------------------------- */ /* compute the scale factors, if requested, and check the input matrix */ /* ---------------------------------------------------------------------- */ /* UMFPACK_SCALE_SUM: Rs [i] = sum of the absolute values in row i. * UMFPACK_SCALE_MAX: Rs [i] = max of the absolute values in row i. * * If A is complex, an approximate abs is used (|xreal| + |ximag|). * * If min (Rs [0..n_row]) >= RECIPROCAL_TOLERANCE, then the scale * factors are inverted, and the rows of A are multiplied by the scale * factors. Otherwise, the rows are divided by the scale factors. If * NRECIPROCAL is defined, then the rows are always divided by the scale * factors. * * For MATLAB (either built-in routine or mexFunction), or for gcc, * the rows are always divided by the scale factors. */ do_scale = (Numeric->scale != UMFPACK_SCALE_NONE) ; if (do_scale) { int do_max = Numeric->scale == UMFPACK_SCALE_MAX ; for (row = 0 ; row < n_row ; row++) { Rs [row] = 0.0 ; } for (col = 0 ; col < n_col ; col++) { ilast = EMPTY ; p1 = Ap [col] ; p2 = Ap [col+1] ; if (p1 > p2) { /* invalid matrix */ DEBUGm4 (("invalid matrix (Ap)\n")) ; return (FALSE) ; } for (p = p1 ; p < p2 ; p++) { Entry aij ; double value ; row = Ai [p] ; if (row <= ilast || row >= n_row) { /* invalid matrix, columns must be sorted, no duplicates */ DEBUGm4 (("invalid matrix (Ai)\n")) ; return (FALSE) ; } ASSIGN (aij, Ax, Az, p, split) ; APPROX_ABS (value, aij) ; rs = Rs [row] ; if (!SCALAR_IS_NAN (rs)) { if (SCALAR_IS_NAN (value)) { /* if any entry in the row is NaN, then the scale factor * is NaN too (for now) and then set to 1.0 below */ Rs [row] = value ; } else if (do_max) { Rs [row] = MAX (rs, value) ; } else { Rs [row] += value ; } } DEBUG4 (("i "ID" j "ID" value %g, Rs[i]: %g\n", row, col, value, Rs[row])) ; ilast = row ; } } DEBUG2 (("Rs[0] = %30.20e\n", Rs [0])) ; for (row = 0 ; row < n_row ; row++) { rs = Rs [row] ; if (SCALAR_IS_ZERO (rs) || SCALAR_IS_NAN (rs)) { /* don't scale a completely zero row, or one with NaN's */ Rs [row] = 1.0 ; } } rsmin = Rs [0] ; rsmax = Rs [0] ; for (row = 0 ; row < n_row ; row++) { DEBUG2 (("sum %30.20e ", Rs [row])) ; rsmin = MIN (rsmin, Rs [row]) ; rsmax = MAX (rsmax, Rs [row]) ; DEBUG2 (("Rs["ID"] = %30.20e\n", row, Rs [row])) ; } #ifndef NRECIPROCAL /* multiply by the reciprocal if Rs is not too small */ do_recip = (rsmin >= RECIPROCAL_TOLERANCE) ; if (do_recip) { /* invert the scale factors */ for (row = 0 ; row < n_row ; row++) { Rs [row] = 1.0 / Rs [row] ; } } #endif } else { /* no scaling, rsmin and rsmax not computed */ rsmin = -1 ; rsmax = -1 ; #ifndef NRECIPROCAL do_recip = FALSE ; #endif /* check the input matrix */ if (AMD_valid (n_row, n_col, Ap, Ai) != AMD_OK) { /* matrix is invalid */ return (FALSE) ; } } Numeric->rsmin = rsmin ; Numeric->rsmax = rsmax ; #ifndef NRECIPROCAL Numeric->do_recip = do_recip ; #else Numeric->do_recip = FALSE ; #endif /* ---------------------------------------------------------------------- */ /* construct the inverse row Rperm_init permutation (use Frpos as temp) */ /* ---------------------------------------------------------------------- */ DEBUG3 (("\n\n===================LOAD_MATRIX:\n")) ; for (newrow = 0 ; newrow < n_row ; newrow++) { oldrow = Rperm_init [newrow] ; ASSERT (oldrow >= 0 && oldrow < n_row) ; Frpos [oldrow] = newrow ; } /* ---------------------------------------------------------------------- */ /* construct the diagonal imap if doing symmetric pivoting */ /* ---------------------------------------------------------------------- */ if (prefer_diagonal) { ASSERT (n_row == n_col) ; ASSERT (nempty_col == Symbolic->nempty_row) ; ASSERT (nempty_col == nempty) ; #ifndef NDEBUG for (i = 0 ; i < nn ; i++) { Diagonal_map [i] = EMPTY ; Diagonal_imap [i] = EMPTY ; } #endif for (k = 0 ; k < nn ; k++) { newrow = Symbolic->Diagonal_map [k] ; Diagonal_map [k] = newrow ; Diagonal_imap [newrow] = k ; } #ifndef NDEBUG for (i = 0 ; i < nn ; i++) { ASSERT (Diagonal_map [i] != EMPTY) ; ASSERT (Diagonal_imap [i] != EMPTY) ; } #endif } /* ---------------------------------------------------------------------- */ /* allocate O (n_row) workspace at the tail end of Memory */ /* ---------------------------------------------------------------------- */ rpi = UMF_mem_alloc_tail_block (Numeric, UNITS (Int *, n_row+1)) ; rpx = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry *, n_row+1)) ; if (!rpi || !rpx) { /* :: pattern change (out of memory for Rpx, Rpx) :: */ /* out of memory, which can only mean that the pattern has changed */ return (FALSE) ; /* pattern changed */ } Rpi = (Int **) (Memory + rpx) ; Rpx = (Entry **) (Memory + rpi) ; /* ---------------------------------------------------------------------- */ /* allocate the LU factors for the columns of the singletons */ /* ---------------------------------------------------------------------- */ DEBUG1 (("Allocating singletons:\n")) ; for (k = 0 ; k < n1 ; k++) { lnz = Cdeg [k] - 1 ; unz = Rdeg [k] - 1 ; DEBUG1 (("Singleton k "ID" pivrow "ID" pivcol "ID" cdeg "ID" rdeg " ID"\n", k, Rperm_init [k], Cperm_init [k], Cdeg [k], Rdeg [k])) ; ASSERT (unz >= 0 && lnz >= 0 && (lnz == 0 || unz == 0)) ; DEBUG1 ((" lnz "ID" unz "ID"\n", lnz, unz)) ; size = UNITS (Int, lnz) + UNITS (Entry, lnz) + UNITS (Int, unz) + UNITS (Entry, unz) ; p = UMF_mem_alloc_head_block (Numeric, size) ; DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ; if (!p) { /* :: pattern change (out of memory for singletons) :: */ DEBUG0 (("Pattern has gotten larger - kernel init failed\n")) ; return (FALSE) ; /* pattern changed */ } Numeric->all_lnz += lnz ; Numeric->all_unz += unz ; /* allocate the column of L */ lip = p ; p += UNITS (Int, lnz) ; p += UNITS (Entry, lnz) ; /* allocate the row of U */ uip = p ; Rpi [k] = (Int *) (Memory + p) ; p += UNITS (Int, unz) ; Rpx [k] = (Entry *) (Memory + p) ; /* p += UNITS (Entry, unz) ; (not needed) */ /* a single column of L (no Lchains) */ Lip [k] = lip ; Lilen [k] = lnz ; /* a single row of L (no Uchains) */ Uip [k] = uip ; Uilen [k] = unz ; Wp [k] = unz ; /* save row and column inverse permutation */ k1 = ONES_COMPLEMENT (k) ; Rperm [k] = k1 ; /* aliased with Row_degree */ Cperm [k] = k1 ; /* aliased with Col_degree */ } /* ---------------------------------------------------------------------- */ /* current frontal matrix is empty */ /* ---------------------------------------------------------------------- */ e = 0 ; E [e] = 0 ; Work->Flublock = (Entry *) NULL ; Work->Flblock = (Entry *) NULL ; Work->Fublock = (Entry *) NULL ; Work->Fcblock = (Entry *) NULL ; /* ---------------------------------------------------------------------- */ /* allocate the column elements */ /* ---------------------------------------------------------------------- */ Esize = Symbolic->Esize ; empty_elements = FALSE ; for (k = n1 ; k < n_col - nempty_col ; k++) { e = k - n1 + 1 ; ASSERT (e < Work->elen) ; esize = Esize ? Esize [k-n1] : Cdeg [k] ; if (esize > 0) { /* allocate an element for this column */ E [e] = UMF_mem_alloc_element (Numeric, esize, 1, &Rows, &Cols, &C, &size, &ep) ; if (E [e] <= 0) { /* :: pattern change (out of memory for column elements) :: */ return (FALSE) ; /* pattern has changed */ } Cols [0] = k ; DEBUG0 (("Got column element e "ID" esize "ID"\n", e, esize)) ; } else { /* all rows in this column are dense, or empty */ E [e] = 0 ; empty_elements = TRUE ; DEBUG0 (("column element e is empty "ID"\n", e)) ; } } DEBUG0 (("e "ID" n_col "ID" nempty_col "ID" n1 "ID"\n", e, n_col, nempty_col, n1)) ; ASSERT (e == n_col - nempty_col - n1) ; /* ---------------------------------------------------------------------- */ /* allocate the row elements for dense rows of A (if any) */ /* ---------------------------------------------------------------------- */ if (Esize) { for (k = n1 ; k < n_row - nempty_row ; k++) { rdeg = Rdeg [k] ; if (rdeg > dense_row_threshold) { /* allocate an element for this dense row */ e++ ; ASSERT (e < Work->elen) ; E [e] = UMF_mem_alloc_element (Numeric, 1, rdeg, &Rows, &Cols, &C, &size, &ep) ; if (E [e] <= 0) { /* :: pattern change (out of memory for row elements) :: */ return (FALSE) ; /* pattern has changed */ } Rows [0] = k ; Rpi [k] = Cols ; Rpx [k] = C ; Wp [k] = rdeg ; DEBUG0 (("Got row element e "ID" rdeg "ID"\n", e, rdeg)) ; } } } /* elements are currently in the range 0 to e */ Work->nel = e ; /* ---------------------------------------------------------------------- */ /* create the first n1 columns of L and U */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n1 ; k++) { pivcol = Cperm_init [k] ; p2 = Ap [pivcol+1] ; /* get the kth column of L */ p = Lip [k] ; Li = (Int *) (Memory + p) ; lilen = Lilen [k] ; p += UNITS (Int, lilen) ; Lval = (Entry *) (Memory + p) ; llen = 0 ; for (pa = Ap [pivcol] ; pa < p2 ; pa++) { oldrow = Ai [pa] ; newrow = Frpos [oldrow] ; ASSIGN (x, Ax, Az, pa, split) ; /* scale the value using the scale factors, Rs */ if (do_scale) { #ifndef NRECIPROCAL if (do_recip) { SCALE (x, Rs [oldrow]) ; } else #endif { SCALE_DIV (x, Rs [oldrow]) ; } } if (newrow == k) { /* this is the pivot entry itself */ ASSERT (oldrow == Rperm_init [k]) ; D [k] = x ; } else if (newrow < k) { /* this entry goes in a row of U */ DEBUG1 (("Singleton row of U: k "ID" newrow "ID"\n", k, newrow)) ; if (--(Wp [newrow]) < 0) { /* :: pattern change (singleton row too lengthy) :: */ DEBUGm4 (("bad U singleton row (too lengthy)\n")) ; return (FALSE) ; /* pattern changed */ } *(Rpi [newrow]++) = k ; *(Rpx [newrow]++) = x ; } else { /* this entry goes in a column of L */ DEBUG1 (("Singleton col of L: k "ID" newrow "ID"\n", k, newrow)) ; if (llen >= lilen) { DEBUGm4 (("bad L singleton col (too lengthy)\n")) ; return (FALSE) ; /* pattern changed */ } Li [llen] = newrow ; Lval [llen] = x ; llen++ ; } } if (llen != lilen) { /* :: pattern change (singleton column too lengthy) :: */ DEBUGm4 (("bad L singleton col (too short)\n")) ; return (FALSE) ; /* pattern changed */ } /* scale the column of L */ if (llen > 0) { pivot_value = D [k] ; UMF_scale (llen, pivot_value, Lval) ; } } /* ---------------------------------------------------------------------- */ /* allocate the elements and copy the columns of A */ /* ---------------------------------------------------------------------- */ /* also apply the row and column pre-ordering. */ for (k = n1 ; k < n_col ; k++) { /* The newcol is k, which is what the name of the column is in the * UMFPACK kernel. The user's name for the column is oldcol. */ oldcol = Cperm_init [k] ; ASSERT (oldcol >= 0 && oldcol < n_col) ; p2 = Ap [oldcol+1] ; cdeg = Cdeg [k] ; ASSERT (cdeg >= 0) ; ASSERT (IMPLIES ( (Symbolic->ordering != UMFPACK_ORDERING_GIVEN) && n1 > 0, cdeg > 1 || cdeg == 0)) ; /* if fixQ: set Col_degree to 0 for the NON_PIVOTAL_COL macro */ Col_degree [k] = fixQ ? 0 : cdeg ; /* get the element for this column (if any) */ e = k - n1 + 1 ; if (k < n_col - nempty_col) { esize = Esize ? Esize [k-n1] : cdeg ; if (E [e]) { Int ncols, nrows ; Unit *pp ; pp = Memory + E [e] ; GET_ELEMENT (ep, pp, Cols, Rows, ncols, nrows, C) ; ASSERT (ncols == 1) ; ASSERT (nrows == esize) ; ASSERT (Cols [0] == k) ; } } else { ASSERT (cdeg == 0) ; esize = 0 ; } clen = 0 ; for (pa = Ap [oldcol] ; pa < p2 ; pa++) { oldrow = Ai [pa] ; newrow = Frpos [oldrow] ; ASSIGN (x, Ax, Az, pa, split) ; /* scale the value using the scale factors, Rs */ if (do_scale) { #ifndef NRECIPROCAL if (do_recip) { /* multiply by the reciprocal */ SCALE (x, Rs [oldrow]) ; } else #endif { /* divide instead */ SCALE_DIV (x, Rs [oldrow]) ; } } rdeg = Rdeg [newrow] ; if (newrow < n1 || rdeg > dense_row_threshold) { /* this entry goes in a row of U or into a dense row */ DEBUG1 (("Singleton/dense row of U: k "ID" newrow "ID"\n", k, newrow)) ; if (--(Wp [newrow]) < 0) { DEBUGm4 (("bad row of U or A (too lengthy)\n")) ; return (FALSE) ; /* pattern changed */ } *(Rpi [newrow]++) = k ; *(Rpx [newrow]++) = x ; } else { /* this entry goes in an initial element */ DEBUG1 (("In element k "ID" e "ID" newrow "ID"\n", k, e, newrow)) ; if (clen >= esize) { DEBUGm4 (("bad A column (too lengthy)\n")) ; return (FALSE) ; /* pattern changed */ } ASSERT (E [e]) ; ASSERT (k < n_col - nempty_col) ; Rows [clen] = newrow ; C [clen] = x ; clen++ ; #ifndef NDEBUG if (Diagonal_map && (newrow == Diagonal_map [k])) { DEBUG0 (("Diagonal: old: row "ID" col "ID" : " "new: row "ID" col "ID" : ", oldrow, oldcol, newrow, k)) ; EDEBUGk (0, x) ; } #endif } } if (clen != esize) { /* :: pattern change (singleton column too short) :: */ DEBUGm4 (("bad A column (too short)\n")) ; return (FALSE) ; /* pattern changed */ } } /* ---------------------------------------------------------------------- */ /* free the Rpi and Rpx workspace at the tail end of memory */ /* ---------------------------------------------------------------------- */ UMF_mem_free_tail_block (Numeric, rpi) ; UMF_mem_free_tail_block (Numeric, rpx) ; /* ---------------------------------------------------------------------- */ /* prune zeros and small entries from the singleton rows and columns */ /* ---------------------------------------------------------------------- */ if (n1 > 0) { pnew = Lip [0] ; ASSERT (pnew == 1) ; for (k = 0 ; k < n1 ; k++) { DEBUGm4 (("\nPrune singleton L col "ID"\n", k)) ; pnew = packsp (pnew, &Lip [k], &Lilen [k], drop, droptol, Memory) ; Numeric->lnz += Lilen [k] ; DEBUGm4 (("\nPrune singleton U row "ID"\n", k)) ; pnew = packsp (pnew, &Uip [k], &Uilen [k], drop, droptol, Memory) ; Numeric->unz += Uilen [k] ; } /* free the unused space at the head of memory */ Numeric->ihead = pnew ; } /* ---------------------------------------------------------------------- */ /* initialize row degrees */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n1 ; k++) { if (Wp [k] != 0) { /* :: pattern change (singleton row too short) :: */ DEBUGm4 (("bad U singleton row (too short)\n")) ; return (FALSE) ; /* pattern changed */ } } for (k = n1 ; k < n_row ; k++) { DEBUG1 (("Initial row degree k "ID" oldrow "ID" Rdeg "ID"\n", k, Rperm_init [k], Rdeg [k])) ; rdeg = Rdeg [k] ; Row_degree [k] = rdeg ; if (rdeg > dense_row_threshold && Wp [k] != 0) { /* :: pattern change (dense row too short) :: */ DEBUGm4 (("bad dense row (too short)\n")) ; return (FALSE) ; /* pattern changed */ } } #ifndef NDEBUG if (prefer_diagonal) { Entry aij ; Int *InvCperm, newcol ; UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, nn) ; InvCperm = (Int *) malloc (n_col * sizeof (Int)) ; ASSERT (InvCperm != (Int *) NULL) ; for (newcol = 0 ; newcol < n_col ; newcol++) { oldcol = Cperm_init [newcol] ; InvCperm [oldcol] = newcol ; } DEBUGm3 (("Diagonal of P2*A:\n")) ; for (oldcol = 0 ; oldcol < n_col ; oldcol++) { newcol = InvCperm [oldcol] ; for (p = Ap [oldcol] ; p < Ap [oldcol+1] ; p++) { oldrow = Ai [p] ; newrow = Frpos [oldrow] ; ASSIGN (aij, Ax, Az, p, split) ; if (newrow == Diagonal_map [newcol]) { DEBUG0 (("old row "ID" col "ID" new row "ID" col "ID, oldrow, oldcol, newrow, newcol)) ; EDEBUGk (0, aij) ; DEBUG0 ((" scaled ")) ; if (do_scale) { #ifndef NRECIPROCAL if (do_recip) { SCALE (aij, Rs [oldrow]) ; } else #endif { SCALE_DIV (aij, Rs [oldrow]) ; } } EDEBUGk (0, aij) ; DEBUG0 (("\n")) ; } } } free (InvCperm) ; } #endif Col_degree [n_col] = 0 ; /* ---------------------------------------------------------------------- */ /* pack the element name space */ /* ---------------------------------------------------------------------- */ if (empty_elements) { Int e2 = 0 ; DEBUG0 (("\n\n============= Packing element space\n")) ; for (e = 1 ; e <= Work->nel ; e++) { if (E [e]) { e2++ ; E [e2] = E [e] ; } } Work->nel = e2 ; } #ifndef NDEBUG DEBUG0 (("Number of initial elements: "ID"\n", Work->nel)) ; for (e = 0 ; e <= Work->nel ; e++) UMF_dump_element (Numeric, Work,e,TRUE) ; #endif for (e = Work->nel + 1 ; e < Work->elen ; e++) { E [e] = 0 ; } /* Frpos no longer needed */ for (row = 0 ; row <= n_row ; row++) { Frpos [row] = EMPTY ; } /* clear Wp */ for (i = 0 ; i <= nn ; i++) { Wp [i] = EMPTY ; } DEBUG1 (("Kernel init head usage: "ID"\n", Numeric->ihead)) ; /* ---------------------------------------------------------------------- */ /* build the tuple lists */ /* ---------------------------------------------------------------------- */ /* if the memory usage changes, then the pattern has changed */ (void) UMF_tuple_lengths (Numeric, Work, &unused) ; if (!UMF_build_tuples (Numeric, Work)) { /* :: pattern change (out of memory in umf_build_tuples) :: */ /* We ran out of memory, which can only mean that */ /* the pattern (Ap and or Ai) has changed (gotten larger). */ DEBUG0 (("Pattern has gotten larger - build tuples failed\n")) ; return (FALSE) ; /* pattern changed */ } Numeric->init_usage = Numeric->max_usage ; /* ---------------------------------------------------------------------- */ /* construct the row merge sets */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i <= Symbolic->nfr ; i++) { Work->Front_new1strow [i] = Symbolic->Front_1strow [i] ; } #ifndef NDEBUG UMF_dump_rowmerge (Numeric, Symbolic, Work) ; DEBUG6 (("Column form of original matrix:\n")) ; UMF_dump_col_matrix (Ax, #ifdef COMPLEX Az, #endif Ai, Ap, n_row, n_col, nz) ; UMF_dump_memory (Numeric) ; UMF_dump_matrix (Numeric, Work, FALSE) ; DEBUG0 (("kernel init done...\n")) ; #endif return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_transpose.c0000644000175000017500000002145511674452555022712 0ustar sonnesonne/* ========================================================================== */ /* === UMF_transpose ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Not user-callable. Computes a permuted transpose, R = (A (P,Q(1:nq)))' in MATLAB notation, where R is in column-form. A is n_row-by-n_col, the row-form matrix R is n_row-by-nq, where nq <= n_col. A may be singular. The complex version can do transpose (') or array transpose (.'). Uses Gustavson's method (Two Fast Algorithms for Sparse Matrices: Multiplication and Permuted Transposition, ACM Trans. on Math. Softw., vol 4, no 3, pp. 250-269). */ #include "umf_internal.h" #include "umf_transpose.h" #include "umf_is_permutation.h" GLOBAL Int UMF_transpose ( Int n_row, /* A is n_row-by-n_col */ Int n_col, const Int Ap [ ], /* size n_col+1 */ const Int Ai [ ], /* size nz = Ap [n_col] */ const double Ax [ ], /* size nz if present */ const Int P [ ], /* P [k] = i means original row i is kth row in A(P,Q)*/ /* P is identity if not present */ /* size n_row, if present */ const Int Q [ ], /* Q [k] = j means original col j is kth col in A(P,Q)*/ /* Q is identity if not present */ /* size nq, if present */ Int nq, /* size of Q, ignored if Q is (Int *) NULL */ /* output matrix: Rp, Ri, Rx, and Rz: */ Int Rp [ ], /* size n_row+1 */ Int Ri [ ], /* size nz */ double Rx [ ], /* size nz, if present */ Int W [ ], /* size max (n_row,n_col) workspace */ Int check /* if true, then check inputs */ #ifdef COMPLEX , const double Az [ ] /* size nz */ , double Rz [ ] /* size nz */ , Int do_conjugate /* if true, then do conjugate transpose */ /* otherwise, do array transpose */ #endif ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int i, j, k, p, bp, newj, do_values ; #ifdef COMPLEX Int split ; #endif /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG Int nz ; ASSERT (n_col >= 0) ; nz = (Ap != (Int *) NULL) ? Ap [n_col] : 0 ; DEBUG2 (("UMF_transpose: "ID"-by-"ID" nz "ID"\n", n_row, n_col, nz)) ; #endif if (check) { /* UMFPACK_symbolic skips this check */ /* UMFPACK_transpose always does this check */ if (!Ai || !Ap || !Ri || !Rp || !W) { return (UMFPACK_ERROR_argument_missing) ; } if (n_row <= 0 || n_col <= 0) /* n_row,n_col must be > 0 */ { return (UMFPACK_ERROR_n_nonpositive) ; } if (!UMF_is_permutation (P, W, n_row, n_row) || !UMF_is_permutation (Q, W, nq, nq)) { return (UMFPACK_ERROR_invalid_permutation) ; } if (AMD_valid (n_row, n_col, Ap, Ai) != AMD_OK) { return (UMFPACK_ERROR_invalid_matrix) ; } } #ifndef NDEBUG DEBUG2 (("UMF_transpose, input matrix:\n")) ; UMF_dump_col_matrix (Ax, #ifdef COMPLEX Az, #endif Ai, Ap, n_row, n_col, nz) ; #endif /* ---------------------------------------------------------------------- */ /* count the entries in each row of A */ /* ---------------------------------------------------------------------- */ /* use W as workspace for RowCount */ for (i = 0 ; i < n_row ; i++) { W [i] = 0 ; Rp [i] = 0 ; } if (Q != (Int *) NULL) { for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; ASSERT (i >= 0 && i < n_row) ; W [i]++ ; } } } else { for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; ASSERT (i >= 0 && i < n_row) ; W [i]++ ; } } } /* ---------------------------------------------------------------------- */ /* compute the row pointers for R = A (P,Q) */ /* ---------------------------------------------------------------------- */ if (P != (Int *) NULL) { Rp [0] = 0 ; for (k = 0 ; k < n_row ; k++) { i = P [k] ; ASSERT (i >= 0 && i < n_row) ; Rp [k+1] = Rp [k] + W [i] ; } for (k = 0 ; k < n_row ; k++) { i = P [k] ; ASSERT (i >= 0 && i < n_row) ; W [i] = Rp [k] ; } } else { Rp [0] = 0 ; for (i = 0 ; i < n_row ; i++) { Rp [i+1] = Rp [i] + W [i] ; } for (i = 0 ; i < n_row ; i++) { W [i] = Rp [i] ; } } ASSERT (Rp [n_row] <= Ap [n_col]) ; /* at this point, W holds the permuted row pointers */ /* ---------------------------------------------------------------------- */ /* construct the row form of B */ /* ---------------------------------------------------------------------- */ do_values = Ax && Rx ; #ifdef COMPLEX split = SPLIT (Az) && SPLIT (Rz) ; if (do_conjugate && do_values) { if (Q != (Int *) NULL) { if (split) { /* R = A (P,Q)' */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [bp] = Ax [p] ; Rz [bp] = -Az [p] ; } } } else { /* R = A (P,Q)' (merged complex values) */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = -Ax [2*p+1] ; } } } } else { if (split) { /* R = A (P,:)' */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [bp] = Ax [p] ; Rz [bp] = -Az [p] ; } } } else { /* R = A (P,:)' (merged complex values) */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = -Ax [2*p+1] ; } } } } } else #endif { if (Q != (Int *) NULL) { if (do_values) { #ifdef COMPLEX if (split) #endif { /* R = A (P,Q).' */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [bp] = Ax [p] ; #ifdef COMPLEX Rz [bp] = Az [p] ; #endif } } } #ifdef COMPLEX else { /* R = A (P,Q).' (merged complex values) */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = newj ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = Ax [2*p+1] ; } } } #endif } else { /* R = pattern of A (P,Q).' */ for (newj = 0 ; newj < nq ; newj++) { j = Q [newj] ; ASSERT (j >= 0 && j < n_col) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { Ri [W [Ai [p]]++] = newj ; } } } } else { if (do_values) { #ifdef COMPLEX if (split) #endif { /* R = A (P,:).' */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [bp] = Ax [p] ; #ifdef COMPLEX Rz [bp] = Az [p] ; #endif } } } #ifdef COMPLEX else { /* R = A (P,:).' (merged complex values) */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { bp = W [Ai [p]]++ ; Ri [bp] = j ; Rx [2*bp] = Ax [2*p] ; Rx [2*bp+1] = Ax [2*p+1] ; } } } #endif } else { /* R = pattern of A (P,:).' */ for (j = 0 ; j < n_col ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { Ri [W [Ai [p]]++] = j ; } } } } } #ifndef NDEBUG for (k = 0 ; k < n_row ; k++) { if (P != (Int *) NULL) { i = P [k] ; } else { i = k ; } DEBUG3 ((ID": W[i] "ID" Rp[k+1] "ID"\n", i, W [i], Rp [k+1])) ; ASSERT (W [i] == Rp [k+1]) ; } DEBUG2 (("UMF_transpose, output matrix:\n")) ; UMF_dump_col_matrix (Rx, #ifdef COMPLEX Rz, #endif Ri, Rp, n_col, n_row, Rp [n_row]) ; ASSERT (AMD_valid (n_col, n_row, Rp, Ri) == AMD_OK) ; #endif return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_malloc.h0000644000175000017500000000124111674452555022137 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #ifndef _UMF_MALLOC #define _UMF_MALLOC #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) #ifndef EXTERN #define EXTERN extern #endif GLOBAL EXTERN Int UMF_malloc_count ; #endif GLOBAL void *UMF_malloc ( Int n_objects, size_t size_of_object ) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_valid_numeric.c0000644000175000017500000000313011674452555023503 0ustar sonnesonne/* ========================================================================== */ /* === UMF_valid_numeric ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Returns TRUE if the Numeric object is valid, FALSE otherwise. */ /* Does not check everything. UMFPACK_report_numeric checks more. */ #include "umf_internal.h" #include "umf_valid_numeric.h" GLOBAL Int UMF_valid_numeric ( NumericType *Numeric ) { /* This routine does not check the contents of the individual arrays, so */ /* it can miss some errors. All it checks for is the presence of the */ /* arrays, and the Numeric "valid" entry. */ if (!Numeric) { return (FALSE) ; } if (Numeric->valid != NUMERIC_VALID) { /* Numeric does not point to a NumericType object */ return (FALSE) ; } if (Numeric->n_row <= 0 || Numeric->n_col <= 0 || !Numeric->D || !Numeric->Rperm || !Numeric->Cperm || !Numeric->Lpos || !Numeric->Upos || !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip || !Numeric->Uip || !Numeric->Memory || (Numeric->ulen > 0 && !Numeric->Upattern)) { return (FALSE) ; } return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_usolve.c0000644000175000017500000001421411674452555022204 0ustar sonnesonne/* ========================================================================== */ /* === UMF_usolve =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* solves Ux = b, where U is the upper triangular factor of a matrix. */ /* B is overwritten with the solution X. */ /* Returns the floating point operation count */ #include "umf_internal.h" #include "umf_usolve.h" GLOBAL double UMF_usolve ( NumericType *Numeric, Entry X [ ], /* b on input, solution x on output */ Int Pattern [ ] /* a work array of size n */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry xk ; Entry *xp, *D, *Uval ; Int k, deg, j, *ip, col, *Upos, *Uilen, pos, *Uip, n, ulen, up, newUchain, npiv, n1, *Ui ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ if (Numeric->n_row != Numeric->n_col) return (0.) ; n = Numeric->n_row ; npiv = Numeric->npiv ; Upos = Numeric->Upos ; Uilen = Numeric->Uilen ; Uip = Numeric->Uip ; D = Numeric->D ; n1 = Numeric->n1 ; #ifndef NDEBUG DEBUG4 (("Usolve start: npiv = "ID" n = "ID"\n", npiv, n)) ; for (j = 0 ; j < n ; j++) { DEBUG4 (("Usolve start "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } #endif /* ---------------------------------------------------------------------- */ /* singular case */ /* ---------------------------------------------------------------------- */ #ifndef NO_DIVIDE_BY_ZERO /* handle the singular part of D, up to just before the last pivot */ for (k = n-1 ; k >= npiv ; k--) { /* This is an *** intentional *** divide-by-zero, to get Inf or Nan, * as appropriate. It is not a bug. */ ASSERT (IS_ZERO (D [k])) ; xk = X [k] ; /* X [k] = xk / D [k] ; */ DIV (X [k], xk, D [k]) ; } #else /* Do not divide by zero */ #endif deg = Numeric->ulen ; if (deg > 0) { /* :: make last pivot row of U (singular matrices only) :: */ for (j = 0 ; j < deg ; j++) { DEBUG1 (("Last row of U: j="ID"\n", j)) ; DEBUG1 (("Last row of U: Upattern[j]="ID"\n", Numeric->Upattern [j]) ); Pattern [j] = Numeric->Upattern [j] ; } } /* ---------------------------------------------------------------------- */ /* nonsingletons */ /* ---------------------------------------------------------------------- */ for (k = npiv-1 ; k >= n1 ; k--) { /* ------------------------------------------------------------------ */ /* use row k of U */ /* ------------------------------------------------------------------ */ up = Uip [k] ; ulen = Uilen [k] ; newUchain = (up < 0) ; if (newUchain) { up = -up ; xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ; } else { xp = (Entry *) (Numeric->Memory + up) ; } xk = X [k] ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" k "ID" col "ID" value", k, Pattern [j])) ; EDEBUG4 (*xp) ; DEBUG4 (("\n")) ; /* xk -= X [Pattern [j]] * (*xp) ; */ MULT_SUB (xk, X [Pattern [j]], *xp) ; xp++ ; } #ifndef NO_DIVIDE_BY_ZERO /* Go ahead and divide by zero if D [k] is zero */ /* X [k] = xk / D [k] ; */ DIV (X [k], xk, D [k]) ; #else /* Do not divide by zero */ if (IS_NONZERO (D [k])) { /* X [k] = xk / D [k] ; */ DIV (X [k], xk, D [k]) ; } #endif /* ------------------------------------------------------------------ */ /* make row k-1 of U in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ if (k == n1) break ; if (newUchain) { /* next row is a new Uchain */ deg = ulen ; ASSERT (IMPLIES (k == 0, deg == 0)) ; DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ; ip = (Int *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = *ip++ ; DEBUG4 ((" k "ID" col "ID"\n", k-1, col)) ; ASSERT (k <= col) ; Pattern [j] = col ; } } else { deg -= ulen ; DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k, deg)) ; ASSERT (deg >= 0) ; pos = Upos [k] ; if (pos != EMPTY) { /* add the pivot column */ DEBUG4 (("k "ID" add pivot entry at pos "ID"\n", k, pos)) ; ASSERT (pos >= 0 && pos <= deg) ; Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } } } /* ---------------------------------------------------------------------- */ /* singletons */ /* ---------------------------------------------------------------------- */ for (k = n1 - 1 ; k >= 0 ; k--) { deg = Uilen [k] ; xk = X [k] ; DEBUG4 (("Singleton k "ID"\n", k)) ; if (deg > 0) { up = Uip [k] ; Ui = (Int *) (Numeric->Memory + up) ; up += UNITS (Int, deg) ; Uval = (Entry *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" k "ID" col "ID" value", k, Ui [j])) ; EDEBUG4 (Uval [j]) ; DEBUG4 (("\n")) ; /* xk -= X [Ui [j]] * Uval [j] ; */ ASSERT (Ui [j] >= 0 && Ui [j] < n) ; MULT_SUB (xk, X [Ui [j]], Uval [j]) ; } } #ifndef NO_DIVIDE_BY_ZERO /* Go ahead and divide by zero if D [k] is zero */ /* X [k] = xk / D [k] ; */ DIV (X [k], xk, D [k]) ; #else /* Do not divide by zero */ if (IS_NONZERO (D [k])) { /* X [k] = xk / D [k] ; */ DIV (X [k], xk, D [k]) ; } #endif } #ifndef NDEBUG for (j = 0 ; j < n ; j++) { DEBUG4 (("Usolve done "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } DEBUG4 (("Usolve done.\n")) ; #endif return (DIV_FLOPS * ((double) n) + MULTSUB_FLOPS * ((double) Numeric->unz)); } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_grow_front.c0000644000175000017500000002363011674452555023057 0ustar sonnesonne/* ========================================================================== */ /* === UMF_grow_front ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Current frontal matrix is too small. Make it bigger. */ #include "umf_internal.h" #include "umf_grow_front.h" #include "umf_mem_free_tail_block.h" #include "umf_mem_alloc_tail_block.h" #include "umf_get_memory.h" GLOBAL Int UMF_grow_front ( NumericType *Numeric, Int fnr2, /* desired size is fnr2-by-fnc2 */ Int fnc2, WorkType *Work, Int do_what /* -1: UMF_start_front * 0: UMF_init_front, do not recompute Fcpos * 1: UMF_extend_front * 2: UMF_init_front, recompute Fcpos */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ double s ; Entry *Fcold, *Fcnew ; Int j, i, col, *Fcpos, *Fcols, fnrows_max, fncols_max, fnr_curr, nb, fnrows_new, fncols_new, fnr_min, fnc_min, minsize, newsize, fnrows, fncols, *E, eloc ; /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG if (do_what != -1) UMF_debug++ ; DEBUG0 (("\n\n====================GROW FRONT: do_what: "ID"\n", do_what)) ; if (do_what != -1) UMF_debug-- ; ASSERT (Work->do_grow) ; ASSERT (Work->fnpiv == 0) ; #endif Fcols = Work->Fcols ; Fcpos = Work->Fcpos ; E = Work->E ; /* ---------------------------------------------------------------------- */ /* The current front is too small, find the new size */ /* ---------------------------------------------------------------------- */ /* maximum size of frontal matrix for this chain */ nb = Work->nb ; fnrows_max = Work->fnrows_max + nb ; fncols_max = Work->fncols_max + nb ; ASSERT (fnrows_max >= 0 && (fnrows_max % 2) == 1) ; DEBUG0 (("Max size: "ID"-by-"ID" (incl. "ID" pivot block\n", fnrows_max, fncols_max, nb)) ; /* current dimensions of frontal matrix: fnr-by-fnc */ DEBUG0 (("Current : "ID"-by-"ID" (excl "ID" pivot blocks)\n", Work->fnr_curr, Work->fnc_curr, nb)) ; ASSERT (Work->fnr_curr >= 0) ; ASSERT ((Work->fnr_curr % 2 == 1) || Work->fnr_curr == 0) ; /* required dimensions of frontal matrix: fnr_min-by-fnc_min */ fnrows_new = Work->fnrows_new + 1 ; fncols_new = Work->fncols_new + 1 ; ASSERT (fnrows_new >= 0) ; if (fnrows_new % 2 == 0) fnrows_new++ ; fnrows_new += nb ; fncols_new += nb ; fnr_min = MIN (fnrows_new, fnrows_max) ; fnc_min = MIN (fncols_new, fncols_max) ; minsize = fnr_min * fnc_min ; if (INT_OVERFLOW ((double) fnr_min * (double) fnc_min * sizeof (Entry))) { /* :: the minimum front size is bigger than the integer maximum :: */ return (FALSE) ; } ASSERT (fnr_min >= 0) ; ASSERT (fnr_min % 2 == 1) ; DEBUG0 (("Min : "ID"-by-"ID"\n", fnr_min, fnc_min)) ; /* grow the front to fnr2-by-fnc2, but no bigger than the maximum, * and no smaller than the minumum. */ DEBUG0 (("Desired : ("ID"+"ID")-by-("ID"+"ID")\n", fnr2, nb, fnc2, nb)) ; fnr2 += nb ; fnc2 += nb ; ASSERT (fnr2 >= 0) ; if (fnr2 % 2 == 0) fnr2++ ; fnr2 = MAX (fnr2, fnr_min) ; fnc2 = MAX (fnc2, fnc_min) ; fnr2 = MIN (fnr2, fnrows_max) ; fnc2 = MIN (fnc2, fncols_max) ; DEBUG0 (("Try : "ID"-by-"ID"\n", fnr2, fnc2)) ; ASSERT (fnr2 >= 0) ; ASSERT (fnr2 % 2 == 1) ; s = ((double) fnr2) * ((double) fnc2) ; if (INT_OVERFLOW (s * sizeof (Entry))) { /* :: frontal matrix size int overflow :: */ /* the desired front size is bigger than the integer maximum */ /* compute a such that a*a*s < Int_MAX / sizeof (Entry) */ double a = 0.9 * sqrt ((Int_MAX / sizeof (Entry)) / s) ; fnr2 = MAX (fnr_min, a * fnr2) ; fnc2 = MAX (fnc_min, a * fnc2) ; /* the new frontal size is a*r*a*c = a*a*s */ newsize = fnr2 * fnc2 ; ASSERT (fnr2 >= 0) ; if (fnr2 % 2 == 0) fnr2++ ; fnc2 = newsize / fnr2 ; } fnr2 = MAX (fnr2, fnr_min) ; fnc2 = MAX (fnc2, fnc_min) ; newsize = fnr2 * fnc2 ; ASSERT (fnr2 >= 0) ; ASSERT (fnr2 % 2 == 1) ; ASSERT (fnr2 >= fnr_min) ; ASSERT (fnc2 >= fnc_min) ; ASSERT (newsize >= minsize) ; /* ---------------------------------------------------------------------- */ /* free the current front if it is empty of any numerical values */ /* ---------------------------------------------------------------------- */ if (E [0] && do_what != 1) { /* free the current front, if it exists and has nothing in it */ DEBUG0 (("Freeing empty front\n")) ; UMF_mem_free_tail_block (Numeric, E [0]) ; E [0] = 0 ; Work->Flublock = (Entry *) NULL ; Work->Flblock = (Entry *) NULL ; Work->Fublock = (Entry *) NULL ; Work->Fcblock = (Entry *) NULL ; } /* ---------------------------------------------------------------------- */ /* allocate the new front, doing garbage collection if necessary */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG UMF_allocfail = FALSE ; if (UMF_gprob > 0) /* a double relop, but ignore NaN case */ { double rrr = ((double) (rand ( ))) / (((double) RAND_MAX) + 1) ; DEBUG1 (("Check random %e %e\n", rrr, UMF_gprob)) ; UMF_allocfail = rrr < UMF_gprob ; if (UMF_allocfail) DEBUGm2 (("Random garbage collection (grow)\n")) ; } #endif DEBUG0 (("Attempt size: "ID"-by-"ID"\n", fnr2, fnc2)) ; eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; if (!eloc) { /* Do garbage collection, realloc, and try again. Compact the current * contribution block in the front to fnrows-by-fncols. Note that * there are no pivot rows/columns in current front. Do not recompute * Fcpos in UMF_garbage_collection. */ DEBUGm3 (("get_memory from umf_grow_front\n")) ; if (!UMF_get_memory (Numeric, Work, 1 + UNITS (Entry, newsize), Work->fnrows, Work->fncols, FALSE)) { /* :: out of memory in umf_grow_front :: */ return (FALSE) ; /* out of memory */ } DEBUG0 (("Attempt size: "ID"-by-"ID" again\n", fnr2, fnc2)) ; eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; } /* try again with something smaller */ while ((fnr2 != fnr_min || fnc2 != fnc_min) && !eloc) { fnr2 = MIN (fnr2 - 2, fnr2 * UMF_REALLOC_REDUCTION) ; fnc2 = MIN (fnc2 - 2, fnc2 * UMF_REALLOC_REDUCTION) ; ASSERT (fnr_min >= 0) ; ASSERT (fnr_min % 2 == 1) ; fnr2 = MAX (fnr_min, fnr2) ; fnc2 = MAX (fnc_min, fnc2) ; ASSERT (fnr2 >= 0) ; if (fnr2 % 2 == 0) fnr2++ ; newsize = fnr2 * fnc2 ; DEBUGm3 (("Attempt smaller size: "ID"-by-"ID" minsize "ID"-by-"ID"\n", fnr2, fnc2, fnr_min, fnc_min)) ; eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; } /* try again with the smallest possible size */ if (!eloc) { fnr2 = fnr_min ; fnc2 = fnc_min ; newsize = minsize ; DEBUG0 (("Attempt minsize: "ID"-by-"ID"\n", fnr2, fnc2)) ; eloc = UMF_mem_alloc_tail_block (Numeric, UNITS (Entry, newsize)) ; } if (!eloc) { /* out of memory */ return (FALSE) ; } ASSERT (fnr2 >= 0) ; ASSERT (fnr2 % 2 == 1) ; ASSERT (fnr2 >= fnr_min && fnc2 >= fnc_min) ; /* ---------------------------------------------------------------------- */ /* copy the old frontal matrix into the new one */ /* ---------------------------------------------------------------------- */ /* old contribution block (if any) */ fnr_curr = Work->fnr_curr ; /* garbage collection can change fn*_curr */ ASSERT (fnr_curr >= 0) ; ASSERT ((fnr_curr % 2 == 1) || fnr_curr == 0) ; fnrows = Work->fnrows ; fncols = Work->fncols ; Fcold = Work->Fcblock ; /* remove nb from the sizes */ fnr2 -= nb ; fnc2 -= nb ; /* new frontal matrix */ Work->Flublock = (Entry *) (Numeric->Memory + eloc) ; Work->Flblock = Work->Flublock + nb * nb ; Work->Fublock = Work->Flblock + nb * fnr2 ; Work->Fcblock = Work->Fublock + nb * fnc2 ; Fcnew = Work->Fcblock ; if (E [0]) { /* copy the old contribution block into the new one */ for (j = 0 ; j < fncols ; j++) { col = Fcols [j] ; DEBUG1 (("copy col "ID" \n",col)) ; ASSERT (col >= 0 && col < Work->n_col) ; for (i = 0 ; i < fnrows ; i++) { Fcnew [i] = Fcold [i] ; } Fcnew += fnr2 ; Fcold += fnr_curr ; DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ; Fcpos [col] = j * fnr2 ; } } else if (do_what == 2) { /* just find the new column offsets */ for (j = 0 ; j < fncols ; j++) { col = Fcols [j] ; DEBUG1 (("new offset col "ID" "ID"\n",col, j * fnr2)) ; Fcpos [col] = j * fnr2 ; } } /* free the old frontal matrix */ UMF_mem_free_tail_block (Numeric, E [0]) ; /* ---------------------------------------------------------------------- */ /* new frontal matrix size */ /* ---------------------------------------------------------------------- */ E [0] = eloc ; Work->fnr_curr = fnr2 ; /* C block is fnr2-by-fnc2 */ Work->fnc_curr = fnc2 ; Work->fcurr_size = newsize ; /* including LU, L, U, and C blocks */ Work->do_grow = FALSE ; /* the front has just been grown */ ASSERT (Work->fnr_curr >= 0) ; ASSERT (Work->fnr_curr % 2 == 1) ; DEBUG0 (("Newly grown front: "ID"+"ID" by "ID"+"ID"\n", Work->fnr_curr, nb, Work->fnc_curr, nb)) ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_timer.c0000644000175000017500000000615511674452555022653 0ustar sonnesonne/* ========================================================================== */ /* === umfpack_timer ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Returns the time in seconds used by the process. BE CAREFUL: if you compare the run time of UMFPACK with other sparse matrix packages, be sure to use the same timer. See umfpack_timer.h for details. See umfpack_tictoc.h, which is the timer used internally by UMFPACK. */ #include "umfpack_timer.h" #ifdef NO_TIMER /* -------------------------------------------------------------------------- */ /* no timer used if -DNO_TIMER is defined at compile time */ /* -------------------------------------------------------------------------- */ double umfpack_timer ( void ) { return (0) ; } #else #ifdef LIBRT #include double umfpack_timer ( void ) /* returns time in seconds */ { /* get the current real time and return as a double */ struct timespec now ; clock_gettime (CLOCK_REALTIME, &now) ; return ((double) (now.tv_sec ) + (double) (now.tv_nsec) * 1e-9) ; } #else #ifdef GETRUSAGE /* -------------------------------------------------------------------------- */ /* use getrusage for accurate process times (and no overflow) */ /* -------------------------------------------------------------------------- */ /* This works under Solaris, SGI Irix, Linux, IBM RS 6000 (AIX), and Compaq Alpha. It might work on other Unix systems, too. Includes both the "user time" and the "system time". The system time is the time spent by the operating system on behalf of the process, and thus should be charged to the process. */ #include #include double umfpack_timer ( void ) { struct rusage ru ; double user_time, sys_time ; (void) getrusage (RUSAGE_SELF, &ru) ; user_time = ru.ru_utime.tv_sec /* user time (seconds) */ + 1e-6 * ru.ru_utime.tv_usec ; /* user time (microseconds) */ sys_time = ru.ru_stime.tv_sec /* system time (seconds) */ + 1e-6 * ru.ru_stime.tv_usec ; /* system time (microseconds) */ return (user_time + sys_time) ; } #else /* -------------------------------------------------------------------------- */ /* Generic ANSI C: use the ANSI clock function */ /* -------------------------------------------------------------------------- */ /* This is portable, but may overflow. On Sun Solaris, when compiling in */ /* 32-bit mode, the overflow occurs in only 2147 seconds (about 36 minutes). */ #include double umfpack_timer ( void ) { return (((double) (clock ( ))) / ((double) (CLOCKS_PER_SEC))) ; } #endif #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_wrapup.c0000644000175000017500000003035211674452555023546 0ustar sonnesonne/* ========================================================================== */ /* === UMF_kernel_wrapup ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The matrix is factorized. Finish the LU data structure. */ #include "umf_internal.h" #include "umf_kernel_wrapup.h" GLOBAL void UMF_kernel_wrapup ( NumericType *Numeric, SymbolicType *Symbolic, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry pivot_value ; double d ; Entry *D ; Int i, k, col, row, llen, ulen, *ip, *Rperm, *Cperm, *Lilen, npiv, lp, *Uilen, *Lip, *Uip, *Cperm_init, up, pivrow, pivcol, *Lpos, *Upos, *Wr, *Wc, *Wp, *Frpos, *Fcpos, *Row_degree, *Col_degree, *Rperm_init, n_row, n_col, n_inner, zero_pivot, nan_pivot, n1 ; #ifndef NDEBUG UMF_dump_matrix (Numeric, Work, FALSE) ; #endif DEBUG0 (("Kernel complete, Starting Kernel wrapup\n")) ; n_row = Symbolic->n_row ; n_col = Symbolic->n_col ; n_inner = MIN (n_row, n_col) ; Rperm = Numeric->Rperm ; Cperm = Numeric->Cperm ; Lilen = Numeric->Lilen ; Uilen = Numeric->Uilen ; Upos = Numeric->Upos ; Lpos = Numeric->Lpos ; Lip = Numeric->Lip ; Uip = Numeric->Uip ; D = Numeric->D ; npiv = Work->npiv ; Numeric->npiv = npiv ; Numeric->ulen = Work->ulen ; ASSERT (n_row == Numeric->n_row) ; ASSERT (n_col == Symbolic->n_col) ; DEBUG0 (("Wrap-up: npiv "ID" ulen "ID"\n", npiv, Numeric->ulen)) ; ASSERT (npiv <= n_inner) ; /* this will be nonzero only if matrix is singular or rectangular */ ASSERT (IMPLIES (npiv == n_col, Work->ulen == 0)) ; /* ---------------------------------------------------------------------- */ /* find the smallest and largest entries in D */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < npiv ; k++) { pivot_value = D [k] ; ABS (d, pivot_value) ; zero_pivot = SCALAR_IS_ZERO (d) ; nan_pivot = SCALAR_IS_NAN (d) ; if (!zero_pivot) { /* the pivot is nonzero, but might be Inf or NaN */ Numeric->nnzpiv++ ; } if (k == 0) { Numeric->min_udiag = d ; Numeric->max_udiag = d ; } else { /* min (abs (diag (U))) behaves as follows: If any entry is zero, then the result is zero (regardless of the presence of NaN's). Otherwise, if any entry is NaN, then the result is NaN. Otherwise, the result is the smallest absolute value on the diagonal of U. */ if (SCALAR_IS_NONZERO (Numeric->min_udiag)) { if (zero_pivot || nan_pivot) { Numeric->min_udiag = d ; } else if (!SCALAR_IS_NAN (Numeric->min_udiag)) { /* d and min_udiag are both non-NaN */ Numeric->min_udiag = MIN (Numeric->min_udiag, d) ; } } /* max (abs (diag (U))) behaves as follows: If any entry is NaN then the result is NaN. Otherise, the result is the largest absolute value on the diagonal of U. */ if (nan_pivot) { Numeric->max_udiag = d ; } else if (!SCALAR_IS_NAN (Numeric->max_udiag)) { /* d and max_udiag are both non-NaN */ Numeric->max_udiag = MAX (Numeric->max_udiag, d) ; } } } /* ---------------------------------------------------------------------- */ /* check if matrix is singular or rectangular */ /* ---------------------------------------------------------------------- */ Col_degree = Cperm ; /* for NON_PIVOTAL_COL macro */ Row_degree = Rperm ; /* for NON_PIVOTAL_ROW macro */ if (npiv < n_row) { /* finalize the row permutation */ k = npiv ; DEBUGm3 (("Singular pivot rows "ID" to "ID"\n", k, n_row-1)) ; for (row = 0 ; row < n_row ; row++) { if (NON_PIVOTAL_ROW (row)) { Rperm [row] = ONES_COMPLEMENT (k) ; DEBUGm3 (("Singular row "ID" is k: "ID" pivot row\n", row, k)) ; ASSERT (!NON_PIVOTAL_ROW (row)) ; Lpos [row] = EMPTY ; Uip [row] = EMPTY ; Uilen [row] = 0 ; k++ ; } } ASSERT (k == n_row) ; } if (npiv < n_col) { /* finalize the col permutation */ k = npiv ; DEBUGm3 (("Singular pivot cols "ID" to "ID"\n", k, n_col-1)) ; for (col = 0 ; col < n_col ; col++) { if (NON_PIVOTAL_COL (col)) { Cperm [col] = ONES_COMPLEMENT (k) ; DEBUGm3 (("Singular col "ID" is k: "ID" pivot row\n", col, k)) ; ASSERT (!NON_PIVOTAL_COL (col)) ; Upos [col] = EMPTY ; Lip [col] = EMPTY ; Lilen [col] = 0 ; k++ ; } } ASSERT (k == n_col) ; } if (npiv < n_inner) { /* finalize the diagonal of U */ DEBUGm3 (("Diag of U is zero, "ID" to "ID"\n", npiv, n_inner-1)) ; for (k = npiv ; k < n_inner ; k++) { CLEAR (D [k]) ; } } /* save the pattern of the last row of U */ if (Numeric->ulen > 0) { DEBUGm3 (("Last row of U is not empty\n")) ; Numeric->Upattern = Work->Upattern ; Work->Upattern = (Int *) NULL ; } DEBUG2 (("Nnzpiv: "ID" npiv "ID"\n", Numeric->nnzpiv, npiv)) ; ASSERT (Numeric->nnzpiv <= npiv) ; if (Numeric->nnzpiv < n_inner && !SCALAR_IS_NAN (Numeric->min_udiag)) { /* the rest of the diagonal is zero, so min_udiag becomes 0, * unless it is already NaN. */ Numeric->min_udiag = 0.0 ; } /* ---------------------------------------------------------------------- */ /* size n_row, n_col workspaces that can be used here: */ /* ---------------------------------------------------------------------- */ Frpos = Work->Frpos ; /* of size n_row+1 */ Fcpos = Work->Fcpos ; /* of size n_col+1 */ Wp = Work->Wp ; /* of size MAX(n_row,n_col)+1 */ /* Work->Upattern ; cannot be used (in Numeric) */ Wr = Work->Lpattern ; /* of size n_row+1 */ Wc = Work->Wrp ; /* of size n_col+1 or bigger */ /* ---------------------------------------------------------------------- */ /* construct Rperm from inverse permutations */ /* ---------------------------------------------------------------------- */ /* use Frpos for temporary copy of inverse row permutation [ */ for (pivrow = 0 ; pivrow < n_row ; pivrow++) { k = Rperm [pivrow] ; ASSERT (k < 0) ; k = ONES_COMPLEMENT (k) ; ASSERT (k >= 0 && k < n_row) ; Wp [k] = pivrow ; Frpos [pivrow] = k ; } for (k = 0 ; k < n_row ; k++) { Rperm [k] = Wp [k] ; } /* ---------------------------------------------------------------------- */ /* construct Cperm from inverse permutation */ /* ---------------------------------------------------------------------- */ /* use Fcpos for temporary copy of inverse column permutation [ */ for (pivcol = 0 ; pivcol < n_col ; pivcol++) { k = Cperm [pivcol] ; ASSERT (k < 0) ; k = ONES_COMPLEMENT (k) ; ASSERT (k >= 0 && k < n_col) ; Wp [k] = pivcol ; /* save a copy of the inverse column permutation in Fcpos */ Fcpos [pivcol] = k ; } for (k = 0 ; k < n_col ; k++) { Cperm [k] = Wp [k] ; } #ifndef NDEBUG for (k = 0 ; k < n_col ; k++) { col = Cperm [k] ; ASSERT (col >= 0 && col < n_col) ; ASSERT (Fcpos [col] == k) ; /* col is the kth pivot */ } for (k = 0 ; k < n_row ; k++) { row = Rperm [k] ; ASSERT (row >= 0 && row < n_row) ; ASSERT (Frpos [row] == k) ; /* row is the kth pivot */ } #endif #ifndef NDEBUG UMF_dump_lu (Numeric) ; #endif /* ---------------------------------------------------------------------- */ /* permute Lpos, Upos, Lilen, Lip, Uilen, and Uip */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < npiv ; k++) { pivrow = Rperm [k] ; Wr [k] = Uilen [pivrow] ; Wp [k] = Uip [pivrow] ; } for (k = 0 ; k < npiv ; k++) { Uilen [k] = Wr [k] ; Uip [k] = Wp [k] ; } for (k = 0 ; k < npiv ; k++) { pivrow = Rperm [k] ; Wp [k] = Lpos [pivrow] ; } for (k = 0 ; k < npiv ; k++) { Lpos [k] = Wp [k] ; } for (k = 0 ; k < npiv ; k++) { pivcol = Cperm [k] ; Wc [k] = Lilen [pivcol] ; Wp [k] = Lip [pivcol] ; } for (k = 0 ; k < npiv ; k++) { Lilen [k] = Wc [k] ; Lip [k] = Wp [k] ; } for (k = 0 ; k < npiv ; k++) { pivcol = Cperm [k] ; Wp [k] = Upos [pivcol] ; } for (k = 0 ; k < npiv ; k++) { Upos [k] = Wp [k] ; } /* ---------------------------------------------------------------------- */ /* terminate the last Uchain and last Lchain */ /* ---------------------------------------------------------------------- */ Upos [npiv] = EMPTY ; Lpos [npiv] = EMPTY ; Uip [npiv] = EMPTY ; Lip [npiv] = EMPTY ; Uilen [npiv] = 0 ; Lilen [npiv] = 0 ; /* ---------------------------------------------------------------------- */ /* convert U to the new pivot order */ /* ---------------------------------------------------------------------- */ n1 = Symbolic->n1 ; for (k = 0 ; k < n1 ; k++) { /* this is a singleton row of U */ ulen = Uilen [k] ; DEBUG4 (("K "ID" New U. ulen "ID" Singleton 1\n", k, ulen)) ; if (ulen > 0) { up = Uip [k] ; ip = (Int *) (Numeric->Memory + up) ; for (i = 0 ; i < ulen ; i++) { col = *ip ; DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])); ASSERT (col >= 0 && col < n_col) ; *ip++ = Fcpos [col] ; } } } for (k = n1 ; k < npiv ; k++) { up = Uip [k] ; if (up < 0) { /* this is the start of a new Uchain (with a pattern) */ ulen = Uilen [k] ; DEBUG4 (("K "ID" New U. ulen "ID" End_Uchain 1\n", k, ulen)) ; if (ulen > 0) { up = -up ; ip = (Int *) (Numeric->Memory + up) ; for (i = 0 ; i < ulen ; i++) { col = *ip ; DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])); ASSERT (col >= 0 && col < n_col) ; *ip++ = Fcpos [col] ; } } } } ulen = Numeric->ulen ; if (ulen > 0) { /* convert last pivot row of U to the new pivot order */ DEBUG4 (("K "ID" (last)\n", k)) ; for (i = 0 ; i < ulen ; i++) { col = Numeric->Upattern [i] ; DEBUG4 ((" old col "ID" new col "ID"\n", col, Fcpos [col])) ; Numeric->Upattern [i] = Fcpos [col] ; } } /* Fcpos no longer needed ] */ /* ---------------------------------------------------------------------- */ /* convert L to the new pivot order */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n1 ; k++) { llen = Lilen [k] ; DEBUG4 (("K "ID" New L. llen "ID" Singleton col\n", k, llen)) ; if (llen > 0) { lp = Lip [k] ; ip = (Int *) (Numeric->Memory + lp) ; for (i = 0 ; i < llen ; i++) { row = *ip ; DEBUG4 ((" old row "ID" new row "ID"\n", row, Frpos [row])) ; ASSERT (row >= 0 && row < n_row) ; *ip++ = Frpos [row] ; } } } for (k = n1 ; k < npiv ; k++) { llen = Lilen [k] ; DEBUG4 (("K "ID" New L. llen "ID" \n", k, llen)) ; if (llen > 0) { lp = Lip [k] ; if (lp < 0) { /* this starts a new Lchain */ lp = -lp ; } ip = (Int *) (Numeric->Memory + lp) ; for (i = 0 ; i < llen ; i++) { row = *ip ; DEBUG4 ((" old row "ID" new row "ID"\n", row, Frpos [row])) ; ASSERT (row >= 0 && row < n_row) ; *ip++ = Frpos [row] ; } } } /* Frpos no longer needed ] */ /* ---------------------------------------------------------------------- */ /* combine symbolic and numeric permutations */ /* ---------------------------------------------------------------------- */ Cperm_init = Symbolic->Cperm_init ; Rperm_init = Symbolic->Rperm_init ; for (k = 0 ; k < n_row ; k++) { Rperm [k] = Rperm_init [Rperm [k]] ; } for (k = 0 ; k < n_col ; k++) { Cperm [k] = Cperm_init [Cperm [k]] ; } /* Work object will be freed immediately upon return (to UMF_kernel */ /* and then to UMFPACK_numeric). */ } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_status.c0000644000175000017500000000737311674452555024454 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_status ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints the return value from other UMFPACK_* routines. See umfpack_report_status.h for details. */ #include "umf_internal.h" GLOBAL void UMFPACK_report_status ( const double Control [UMFPACK_CONTROL], Int status ) { Int prl ; /* ---------------------------------------------------------------------- */ /* get control settings and status to determine what to print */ /* ---------------------------------------------------------------------- */ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl < 1) { /* no output generated if prl is less than 1 */ return ; } if (status == UMFPACK_OK && prl <= 1) { /* no output generated if prl is 1 or less and no error occurred. */ /* note that the default printing level is 1. */ return ; } /* ---------------------------------------------------------------------- */ /* print umfpack license, copyright, version, and status condition */ /* ---------------------------------------------------------------------- */ PRINTF (("\n")) ; PRINTF4 (("%s\n", UMFPACK_COPYRIGHT)) ; PRINTF6 (("%s", UMFPACK_LICENSE_PART1)) ; PRINTF6 (("%s", UMFPACK_LICENSE_PART2)) ; PRINTF6 (("%s", UMFPACK_LICENSE_PART3)) ; PRINTF (("UMFPACK V%d.%d.%d (%s): ", UMFPACK_MAIN_VERSION, UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE)) ; switch (status) { case UMFPACK_OK: PRINTF (("OK\n")) ; break ; case UMFPACK_WARNING_singular_matrix: PRINTF (("WARNING: matrix is singular\n")) ; break ; case UMFPACK_ERROR_out_of_memory: PRINTF (("ERROR: out of memory\n")) ; break ; case UMFPACK_ERROR_invalid_Numeric_object: PRINTF (("ERROR: Numeric object is invalid\n")) ; break ; case UMFPACK_ERROR_invalid_Symbolic_object: PRINTF (("ERROR: Symbolic object is invalid\n")) ; break ; case UMFPACK_ERROR_argument_missing: PRINTF (("ERROR: required argument(s) missing\n")) ; break ; case UMFPACK_ERROR_n_nonpositive: PRINTF (("ERROR: dimension (n_row or n_col) must be > 0\n")) ; break ; case UMFPACK_ERROR_invalid_matrix: PRINTF (("ERROR: input matrix is invalid\n")) ; break ; case UMFPACK_ERROR_invalid_system: PRINTF (("ERROR: system argument invalid\n")) ; break ; case UMFPACK_ERROR_invalid_permutation: PRINTF (("ERROR: invalid permutation\n")) ; break ; case UMFPACK_ERROR_different_pattern: PRINTF (("ERROR: pattern of matrix (Ap and/or Ai) has changed\n")) ; break ; case UMFPACK_ERROR_internal_error: PRINTF (("INTERNAL ERROR!\n" "Input arguments might be corrupted or aliased, or an internal\n" "error has occurred. Check your input arguments with the\n" "umfpack_*_report_* routines before calling the umfpack_*\n" "computational routines. Recompile UMFPACK with debugging\n" "enabled, and look for failed assertions. If all else fails\n" "please report this error to Tim Davis (davis@cise.ufl.edu).\n" )) ; break ; default: PRINTF (("ERROR: Unrecognized error code: "ID"\n", status)) ; } PRINTF (("\n")) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_save_symbolic.c0000644000175000017500000000616511674452555024373 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_save_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Saves a Symbolic object to a file. It can later be read back in via a call to umfpack_*_load_symbolic. */ #include "umf_internal.h" #include "umf_valid_symbolic.h" #define WRITE(object,type,n) \ { \ ASSERT (object != (type *) NULL) ; \ if (fwrite (object, sizeof (type), n, f) != (size_t) n) \ { \ fclose (f) ; \ return (UMFPACK_ERROR_file_IO) ; \ } \ } /* ========================================================================== */ /* === UMFPACK_save_symbolic ================================================ */ /* ========================================================================== */ GLOBAL Int UMFPACK_save_symbolic ( void *SymbolicHandle, char *user_filename ) { SymbolicType *Symbolic ; char *filename ; FILE *f ; /* get the Symbolic object */ Symbolic = (SymbolicType *) SymbolicHandle ; /* make sure the Symbolic object is valid */ if (!UMF_valid_symbolic (Symbolic)) { return (UMFPACK_ERROR_invalid_Symbolic_object) ; } /* get the filename, or use the default name if filename is NULL */ if (user_filename == (char *) NULL) { filename = "symbolic.umf" ; } else { filename = user_filename ; } f = fopen (filename, "wb") ; if (!f) { return (UMFPACK_ERROR_file_IO) ; } /* write the Symbolic object to the file, in binary */ WRITE (Symbolic, SymbolicType, 1) ; WRITE (Symbolic->Cperm_init, Int, Symbolic->n_col+1) ; WRITE (Symbolic->Rperm_init, Int, Symbolic->n_row+1) ; WRITE (Symbolic->Front_npivcol, Int, Symbolic->nfr+1) ; WRITE (Symbolic->Front_parent, Int, Symbolic->nfr+1) ; WRITE (Symbolic->Front_1strow, Int, Symbolic->nfr+1) ; WRITE (Symbolic->Front_leftmostdesc, Int, Symbolic->nfr+1) ; WRITE (Symbolic->Chain_start, Int, Symbolic->nchains+1) ; WRITE (Symbolic->Chain_maxrows, Int, Symbolic->nchains+1) ; WRITE (Symbolic->Chain_maxcols, Int, Symbolic->nchains+1) ; WRITE (Symbolic->Cdeg, Int, Symbolic->n_col+1) ; WRITE (Symbolic->Rdeg, Int, Symbolic->n_row+1) ; if (Symbolic->esize > 0) { /* only when dense rows are present */ WRITE (Symbolic->Esize, Int, Symbolic->esize) ; } if (Symbolic->prefer_diagonal) { /* only when diagonal pivoting is prefered */ WRITE (Symbolic->Diagonal_map, Int, Symbolic->n_col+1) ; } /* close the file */ fclose (f) ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_colamd.c0000644000175000017500000026715411674452555022143 0ustar sonnesonne/* ========================================================================== */ /* === UMF_colamd =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* UMF_colamd: an approximate minimum degree column ordering algorithm, used as a preordering for UMFPACK. NOTE: if this routine is used outside of UMFPACK, for a sparse Cholesky factorization of (AQ)'*(AQ) or a QR factorization of A, then one line should be removed (the "&& pivot_row_thickness > 0" expression). See the comment regarding the Cholesky factorization, below. Purpose: Colamd computes a permutation Q such that the Cholesky factorization of (AQ)'(AQ) has less fill-in and requires fewer floating point operations than A'A. This also provides a good ordering for sparse partial pivoting methods, P(AQ) = LU, where Q is computed prior to numerical factorization, and P is computed during numerical factorization via conventional partial pivoting with row interchanges. Colamd is the column ordering method used in SuperLU, part of the ScaLAPACK library. It is also available as built-in function in MATLAB Version 6, available from MathWorks, Inc. (http://www.mathworks.com). This routine can be used in place of colmmd in MATLAB. By default, the \ and / operators in MATLAB perform a column ordering (using colmmd or colamd) prior to LU factorization using sparse partial pivoting, in the built-in MATLAB lu(A) routine. This code is derived from Colamd Version 2.0. Authors: The authors of the COLAMD code itself are Stefan I. Larimore and Timothy A. Davis, University of Florida. The algorithm was developed in collaboration with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory. The AMD metric on which this is based is by Patrick Amestoy, T. Davis, and Iain Duff. Date: UMFPACK Version: see above. COLAMD Version 2.0 was released on January 31, 2000. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974, DMS-9803599, and CCR-0203270. UMFPACK: Copyright (c) 2003 by Timothy A. Davis. All Rights Reserved. See the UMFPACK README file for the License for your use of this code. Availability: Both UMFPACK and the original unmodified colamd/symamd library are available at http://www.cise.ufl.edu/research/sparse. Changes for inclusion in UMFPACK: * symamd, symamd_report, and colamd_report removed * additional terms added to RowInfo, ColInfo, and stats * Frontal matrix information computed for UMFPACK * routines renamed * column elimination tree post-ordering incorporated. In the original version 2.0, this was performed in colamd.m. For more information, see: Amestoy, P. R. and Davis, T. A. and Duff, I. S., An approximate minimum degree ordering algorithm, SIAM J. Matrix Analysis and Applic, vol 17, no 4., pp 886-905, 1996. Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G., A column approximate minimum degree ordering algorithm, Univ. of Florida, CISE Dept., TR-00-005, Gainesville, FL Oct. 2000. Submitted to ACM Trans. Math. Softw. */ /* ========================================================================== */ /* === Description of user-callable routines ================================ */ /* ========================================================================== */ /* ---------------------------------------------------------------------------- colamd_recommended: removed for UMFPACK ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- colamd_set_defaults: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" colamd_set_defaults (double knobs [COLAMD_KNOBS]) ; Purpose: Sets the default parameters. The use of this routine is optional. Arguments: double knobs [COLAMD_KNOBS] ; Output only. Let c = knobs [COLAMD_DENSE_COL], r = knobs [COLAMD_DENSE_ROW]. Colamd: rows with more than max (16, r*16*sqrt(n_col)) entries are removed prior to ordering. Columns with more than max (16, c*16*sqrt(n_row)) entries are removed prior to ordering, and placed last in the output column ordering. Symamd: removed for UMFPACK. COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1, respectively, in colamd.h. Default values of these two knobs are both 0.5. Currently, only knobs [0] and knobs [1] are used, but future versions may use more knobs. If so, they will be properly set to their defaults by the future version of colamd_set_defaults, so that the code that calls colamd will not need to change, assuming that you either use colamd_set_defaults, or pass a (double *) NULL pointer as the knobs array to colamd or symamd. knobs [COLAMD_AGGRESSIVE]: if nonzero, then perform aggressive absorption. Otherwise, do not. This version does aggressive absorption by default. COLAMD v2.1 (in MATLAB) always does aggressive absorption (it doesn't have an option to turn it off). ---------------------------------------------------------------------------- colamd: ---------------------------------------------------------------------------- C syntax: #include "colamd.h" Int UMF_colamd (Int n_row, Int n_col, Int Alen, Int *A, Int *p, double knobs [COLAMD_KNOBS], Int stats [COLAMD_STATS]) ; Purpose: Computes a column ordering (Q) of A such that P(AQ)=LU or (AQ)'AQ=LL' have less fill-in and require fewer floating point operations than factorizing the unpermuted matrix A or A'A, respectively. Returns: TRUE (1) if successful, FALSE (0) otherwise. Arguments: Int n_row ; Input argument. Number of rows in the matrix A. Restriction: n_row >= 0. Colamd returns FALSE if n_row is negative. Int n_col ; Input argument. Number of columns in the matrix A. Restriction: n_col >= 0. Colamd returns FALSE if n_col is negative. Int Alen ; Input argument. Restriction (see note): Alen >= 2*nnz + 8*(n_col+1) + 6*(n_row+1) + n_col Colamd returns FALSE if these conditions are not met. Note: this restriction makes an modest assumption regarding the size of the two typedef's structures in colamd.h. We do, however, guarantee that Alen >= UMF_COLAMD_RECOMMENDED (nnz, n_row, n_col) will be sufficient. Int A [Alen] ; Input and output argument. A is an integer array of size Alen. Alen must be at least as large as the bare minimum value given above, but this is very low, and can result in excessive run time. For best performance, we recommend that Alen be greater than or equal to UMF_COLAMD_RECOMMENDED (nnz, n_row, n_col), which adds nnz/5 to the bare minimum value given above. On input, the row indices of the entries in column c of the matrix are held in A [(p [c]) ... (p [c+1]-1)]. The row indices in a given column c need not be in ascending order, and duplicate row indices may be be present. However, colamd will work a little faster if both of these conditions are met (Colamd puts the matrix into this format, if it finds that the the conditions are not met). The matrix is 0-based. That is, rows are in the range 0 to n_row-1, and columns are in the range 0 to n_col-1. Colamd returns FALSE if any row index is out of range. A holds the inverse permutation on output. Int p [n_col+1] ; Both input and output argument. p is an integer array of size n_col+1. On input, it holds the "pointers" for the column form of the matrix A. Column c of the matrix A is held in A [(p [c]) ... (p [c+1]-1)]. The first entry, p [0], must be zero, and p [c] <= p [c+1] must hold for all c in the range 0 to n_col-1. The value p [n_col] is thus the total number of entries in the pattern of the matrix A. Colamd returns FALSE if these conditions are not met. On output, if colamd returns TRUE, the array p holds the column permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is the first column index in the new ordering, and p [n_col-1] is the last. That is, p [k] = j means that column j of A is the kth pivot column, in AQ, where k is in the range 0 to n_col-1 (p [0] = j means that column j of A is the first column in AQ). If colamd returns FALSE, then no permutation is returned, and p is undefined on output. double knobs [COLAMD_KNOBS] ; Input argument. See colamd_set_defaults for a description. The behavior is undefined if knobs contains NaN's. (UMFPACK does not call umf_colamd with NaN-valued knobs). Int stats [COLAMD_STATS] ; Output argument. Statistics on the ordering, and error status. See colamd.h for related definitions. Colamd returns FALSE if stats is not present. stats [0]: number of dense or empty rows ignored. stats [1]: number of dense or empty columns ignored (and ordered last in the output permutation p) Note that a row can become "empty" if it contains only "dense" and/or "empty" columns, and similarly a column can become "empty" if it only contains "dense" and/or "empty" rows. stats [2]: number of garbage collections performed. This can be excessively high if Alen is close to the minimum required value. stats [3]: status code. < 0 is an error code. > 1 is a warning or notice. 0 OK. Each column of the input matrix contained row indices in increasing order, with no duplicates. -11 Columns of input matrix jumbled (unsorted columns or duplicate entries). stats [4]: the bad column index stats [5]: the bad row index -1 A is a null pointer -2 p is a null pointer -3 n_row is negative stats [4]: n_row -4 n_col is negative stats [4]: n_col -5 number of nonzeros in matrix is negative stats [4]: number of nonzeros, p [n_col] -6 p [0] is nonzero stats [4]: p [0] -7 A is too small stats [4]: required size stats [5]: actual size (Alen) -8 a column has a zero or negative number of entries (changed for UMFPACK) stats [4]: column with <= 0 entries stats [5]: number of entries in col -9 a row index is out of bounds stats [4]: column with bad row index stats [5]: bad row index stats [6]: n_row, # of rows of matrx -10 unused -999 (unused; see symamd.c) Future versions may return more statistics in the stats array. Example: See http://www.cise.ufl.edu/~davis/colamd/example.c for a complete example. To order the columns of a 5-by-4 matrix with 11 nonzero entries in the following nonzero pattern x 0 x 0 x 0 x x 0 x x 0 0 0 x x x x 0 0 with default knobs and no output statistics, do the following: #include "colamd.h" #define ALEN UMF_COLAMD_RECOMMENDED (11, 5, 4) Int A [ALEN] = {1, 2, 5, 3, 5, 1, 2, 3, 4, 2, 4} ; Int p [ ] = {0, 3, 5, 9, 11} ; Int stats [COLAMD_STATS] ; UMF_colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ; The permutation is returned in the array p, and A is destroyed. ---------------------------------------------------------------------------- symamd: does not appear in this version for UMFPACK ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- colamd_report: does not appear in this version for UMFPACK ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- symamd_report: does not appear in this version for UMFPACK ---------------------------------------------------------------------------- */ /* ========================================================================== */ /* === Scaffolding code definitions ======================================== */ /* ========================================================================== */ /* UMFPACK debugging control moved to amd_internal.h */ /* Our "scaffolding code" philosophy: In our opinion, well-written library code should keep its "debugging" code, and just normally have it turned off by the compiler so as not to interfere with performance. This serves several purposes: (1) assertions act as comments to the reader, telling you what the code expects at that point. All assertions will always be true (unless there really is a bug, of course). (2) leaving in the scaffolding code assists anyone who would like to modify the code, or understand the algorithm (by reading the debugging output, one can get a glimpse into what the code is doing). (3) (gasp!) for actually finding bugs. This code has been heavily tested and "should" be fully functional and bug-free ... but you never know... To enable debugging, comment out the "#define NDEBUG" above. For a MATLAB mexFunction, you will also need to modify mexopts.sh to remove the -DNDEBUG definition. The code will become outrageously slow when debugging is enabled. To control the level of debugging output, set an environment variable D to 0 (little), 1 (some), 2, 3, or 4 (lots). When debugging, you should see the following message on the standard output: colamd: debug version, D = 1 (THIS WILL BE SLOW!) or a similar message for symamd. If you don't, then debugging has not been enabled. */ /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ /* ------------------ */ /* modified for UMFPACK: */ #include "umf_internal.h" #include "umf_colamd.h" #include "umf_apply_order.h" #include "umf_fsize.h" /* ------------------ */ /* ========================================================================== */ /* === Definitions ========================================================== */ /* ========================================================================== */ /* ------------------ */ /* UMFPACK: duplicate definitions moved to umf_internal.h */ /* ------------------ */ /* Row and column status */ #define ALIVE (0) #define DEAD (-1) /* Column status */ #define DEAD_PRINCIPAL (-1) #define DEAD_NON_PRINCIPAL (-2) /* Macros for row and column status update and checking. */ #define ROW_IS_DEAD(r) ROW_IS_MARKED_DEAD (Row[r].shared2.mark) #define ROW_IS_MARKED_DEAD(row_mark) (row_mark < ALIVE) #define ROW_IS_ALIVE(r) (Row [r].shared2.mark >= ALIVE) #define COL_IS_DEAD(c) (Col [c].start < ALIVE) #define COL_IS_ALIVE(c) (Col [c].start >= ALIVE) #define COL_IS_DEAD_PRINCIPAL(c) (Col [c].start == DEAD_PRINCIPAL) #define KILL_ROW(r) { Row [r].shared2.mark = DEAD ; } #define KILL_PRINCIPAL_COL(c) { Col [c].start = DEAD_PRINCIPAL ; } #define KILL_NON_PRINCIPAL_COL(c) { Col [c].start = DEAD_NON_PRINCIPAL ; } /* ------------------ */ /* UMFPACK: Colamd reporting mechanism moved to umf_internal.h */ /* ------------------ */ /* ========================================================================== */ /* === Prototypes of PRIVATE routines ======================================= */ /* ========================================================================== */ PRIVATE Int init_rows_cols ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int p [] /* Int stats [COLAMD_STATS] */ ) ; PRIVATE void init_scoring ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int head [], double knobs [COLAMD_KNOBS], Int *p_n_row2, Int *p_n_col2, Int *p_max_deg /* ------------------ */ /* added for UMFPACK */ , Int *p_ndense_row /* number of dense rows */ , Int *p_nempty_row /* number of original empty rows */ , Int *p_nnewlyempty_row /* number of newly empty rows */ , Int *p_ndense_col /* number of dense cols (excl "empty" cols) */ , Int *p_nempty_col /* number of original empty cols */ , Int *p_nnewlyempty_col /* number of newly empty cols */ ) ; PRIVATE Int find_ordering ( Int n_row, Int n_col, Int Alen, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int head [], Int n_col2, Int max_deg, Int pfree /* ------------------ */ /* added for UMFPACK: */ , Int Front_npivcol [ ] , Int Front_nrows [ ] , Int Front_ncols [ ] , Int Front_parent [ ] , Int Front_cols [ ] , Int *p_nfr , Int aggressive , Int InFront [ ] /* ------------------ */ ) ; /* ------------------ */ /* order_children deleted for UMFPACK: */ /* ------------------ */ PRIVATE void detect_super_cols ( #ifndef NDEBUG Int n_col, Colamd_Row Row [], #endif /* NDEBUG */ Colamd_Col Col [], Int A [], Int head [], Int row_start, Int row_length ) ; PRIVATE Int garbage_collection ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int *pfree ) ; PRIVATE Int clear_mark ( Int n_row, Colamd_Row Row [] ) ; /* ------------------ */ /* print_report deleted for UMFPACK */ /* ------------------ */ /* ========================================================================== */ /* === Debugging prototypes and definitions ================================= */ /* ========================================================================== */ #ifndef NDEBUG /* ------------------ */ /* debugging macros moved for UMFPACK */ /* ------------------ */ PRIVATE void debug_deg_lists ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int head [], Int min_score, Int should, Int max_deg ) ; PRIVATE void debug_mark ( Int n_row, Colamd_Row Row [], Int tag_mark, Int max_mark ) ; PRIVATE void debug_matrix ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [] ) ; PRIVATE void debug_structures ( Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int n_col2 ) ; /* ------------------ */ /* dump_super added for UMFPACK: */ PRIVATE void dump_super ( Int super_c, Colamd_Col Col [], Int n_col ) ; /* ------------------ */ #endif /* NDEBUG */ /* ========================================================================== */ /* ========================================================================== */ /* === USER-CALLABLE ROUTINES: ============================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === colamd_set_defaults ================================================== */ /* ========================================================================== */ /* The colamd_set_defaults routine sets the default values of the user- controllable parameters for colamd: knobs [0] rows with knobs[0]*n_col entries or more are removed prior to ordering in colamd. Rows and columns with knobs[0]*n_col entries or more are removed prior to ordering in symamd and placed last in the output ordering. knobs [1] columns with knobs[1]*n_row entries or more are removed prior to ordering in colamd, and placed last in the column permutation. Symamd ignores this knob. knobs [2] if nonzero, then perform aggressive absorption. knobs [3..19] unused, but future versions might use this */ GLOBAL void UMF_colamd_set_defaults ( /* === Parameters ======================================================= */ double knobs [COLAMD_KNOBS] /* knob array */ ) { /* === Local variables ================================================== */ Int i ; #if 0 if (!knobs) { return ; /* UMFPACK always passes knobs array */ } #endif for (i = 0 ; i < COLAMD_KNOBS ; i++) { knobs [i] = 0 ; } knobs [COLAMD_DENSE_ROW] = 0.2 ; /* default changed for UMFPACK */ knobs [COLAMD_DENSE_COL] = 0.2 ; /* default changed for UMFPACK */ knobs [COLAMD_AGGRESSIVE] = TRUE ; /* default is to do aggressive * absorption */ } /* ========================================================================== */ /* === symamd removed for UMFPACK =========================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === colamd =============================================================== */ /* ========================================================================== */ /* The colamd routine computes a column ordering Q of a sparse matrix A such that the LU factorization P(AQ) = LU remains sparse, where P is selected via partial pivoting. The routine can also be viewed as providing a permutation Q such that the Cholesky factorization (AQ)'(AQ) = LL' remains sparse. */ /* For UMFPACK: colamd always returns TRUE */ GLOBAL Int UMF_colamd /* returns TRUE if successful, FALSE otherwise*/ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows in A */ Int n_col, /* number of columns in A */ Int Alen, /* length of A */ Int A [], /* row indices of A */ Int p [], /* pointers to columns in A */ double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */ Int stats [COLAMD_STATS] /* output statistics and error codes */ /* ------------------ */ /* added for UMFPACK: each Front_ array is of size n_col+1 */ , Int Front_npivcol [ ] /* # pivot cols in each front */ , Int Front_nrows [ ] /* # of rows in each front (incl. pivot rows) */ , Int Front_ncols [ ] /* # of cols in each front (incl. pivot cols) */ , Int Front_parent [ ] /* parent of each front */ , Int Front_cols [ ] /* link list of pivot columns for each front */ , Int *p_nfr /* total number of frontal matrices */ , Int InFront [ ] /* InFront [row] = f if the original row was * absorbed into front f. EMPTY if the row was * empty, dense, or not absorbed. This array * has size n_row+1 */ /* ------------------ */ ) { /* === Local variables ================================================== */ Int row ; /* row index */ Int i ; /* loop index */ Int nnz ; /* nonzeros in A */ Int Row_size ; /* size of Row [], in integers */ Int Col_size ; /* size of Col [], in integers */ #if 0 Int need ; /* minimum required length of A */ #endif Colamd_Row *Row ; /* pointer into A of Row [0..n_row] array */ Colamd_Col *Col ; /* pointer into A of Col [0..n_col] array */ Int n_col2 ; /* number of non-dense, non-empty columns */ Int n_row2 ; /* number of non-dense, non-empty rows */ Int ngarbage ; /* number of garbage collections performed */ Int max_deg ; /* maximum row degree */ Int aggressive ; /* TRUE if doing aggressive absorption */ #if 0 double default_knobs [COLAMD_KNOBS] ; /* default knobs array */ #endif /* ------------------ */ /* debugging initializations moved for UMFPACK */ /* ------------------ */ /* ------------------ */ /* added for UMFPACK: */ Int ndense_row, nempty_row, parent, ndense_col, nempty_col, k, col, nfr, *Front_child, *Front_sibling, *Front_stack, *Front_order, *Front_size ; Int nnewlyempty_col, nnewlyempty_row ; /* ------------------ */ /* === Check the input arguments ======================================== */ #if 0 if (!stats) { DEBUG0 (("colamd: stats not present\n")) ; return (FALSE) ; /* UMFPACK: always passes stats [ ] */ } #endif ASSERT (stats != (Int *) NULL) ; for (i = 0 ; i < COLAMD_STATS ; i++) { stats [i] = 0 ; } stats [COLAMD_STATUS] = COLAMD_OK ; stats [COLAMD_INFO1] = -1 ; stats [COLAMD_INFO2] = -1 ; #if 0 if (!A) /* A is not present */ { /* UMFPACK: always passes A [ ] */ DEBUG0 (("colamd: A not present\n")) ; stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ; return (FALSE) ; } if (!p) /* p is not present */ { /* UMFPACK: always passes p [ ] */ DEBUG0 (("colamd: p not present\n")) ; stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ; return (FALSE) ; } if (n_row < 0) /* n_row must be >= 0 */ { /* UMFPACK: does not call UMF_colamd if n <= 0 */ DEBUG0 (("colamd: nrow negative "ID"\n", n_row)) ; stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ; stats [COLAMD_INFO1] = n_row ; return (FALSE) ; } if (n_col < 0) /* n_col must be >= 0 */ { /* UMFPACK: does not call UMF_colamd if n <= 0 */ DEBUG0 (("colamd: ncol negative "ID"\n", n_col)) ; stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ; stats [COLAMD_INFO1] = n_col ; return (FALSE) ; } #endif ASSERT (A != (Int *) NULL) ; ASSERT (p != (Int *) NULL) ; ASSERT (n_row >= 0) ; ASSERT (n_col >= 0) ; nnz = p [n_col] ; #if 0 if (nnz < 0) /* nnz must be >= 0 */ { /* UMFPACK: does not call UMF_colamd if nnz < 0 */ DEBUG0 (("colamd: number of entries negative "ID"\n", nnz)) ; stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ; stats [COLAMD_INFO1] = nnz ; return (FALSE) ; } if (p [0] != 0) /* p [0] must be exactly zero */ { DEBUG0 (("colamd: p[0] not zero "ID"\n", p [0])) ; stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ; stats [COLAMD_INFO1] = p [0] ; return (FALSE) ; } #endif ASSERT (nnz >= 0) ; ASSERT (p [0] == 0) ; /* === If no knobs, set default knobs =================================== */ #if 0 if (!knobs) { /* UMFPACK: always passes the knobs */ UMF_colamd_set_defaults (default_knobs) ; knobs = default_knobs ; } #endif ASSERT (knobs != (double *) NULL) ; /* --------------------- */ /* added for UMFPACK v4.1: */ aggressive = (knobs [COLAMD_AGGRESSIVE] != 0) ; /* --------------------- */ /* === Allocate the Row and Col arrays from array A ===================== */ Col_size = UMF_COLAMD_C (n_col) ; Row_size = UMF_COLAMD_R (n_row) ; #if 0 need = MAX (2*nnz, 4*n_col) + n_col + Col_size + Row_size ; if (need > Alen) { /* UMFPACK: always passes enough space */ /* not enough space in array A to perform the ordering */ DEBUG0 (("colamd: Need Alen >= "ID", given only Alen = "ID"\n", need, Alen)) ; stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ; stats [COLAMD_INFO1] = need ; stats [COLAMD_INFO2] = Alen ; return (FALSE) ; } #endif Alen -= Col_size + Row_size ; Col = (Colamd_Col *) &A [Alen] ; Row = (Colamd_Row *) &A [Alen + Col_size] ; /* Size of A is now Alen >= MAX (2*nnz, 4*n_col) + n_col. The ordering * requires Alen >= 2*nnz + n_col, and the postorder requires * Alen >= 5*n_col. */ /* === Construct the row and column data structures ===================== */ i = init_rows_cols (n_row, n_col, Row, Col, A, p) ; #if 0 if (!i) { /* input matrix is invalid */ DEBUG0 (("colamd: Matrix invalid\n")) ; return (FALSE) ; } #endif ASSERT (i) ; /* === UMFPACK: Initialize front info =================================== */ for (col = 0 ; col < n_col ; col++) { Front_npivcol [col] = 0 ; Front_nrows [col] = 0 ; Front_ncols [col] = 0 ; Front_parent [col] = EMPTY ; Front_cols [col] = EMPTY ; } /* === Initialize scores, kill dense rows/columns ======================= */ init_scoring (n_row, n_col, Row, Col, A, p, knobs, &n_row2, &n_col2, &max_deg /* ------------------ */ /* added for UMFPACK: */ , &ndense_row, &nempty_row, &nnewlyempty_row , &ndense_col, &nempty_col, &nnewlyempty_col /* ------------------ */ ) ; ASSERT (n_row2 == n_row - nempty_row - nnewlyempty_row - ndense_row) ; ASSERT (n_col2 == n_col - nempty_col - nnewlyempty_col - ndense_col) ; /* === Order the supercolumns =========================================== */ ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p, n_col2, max_deg, 2*nnz /* ------------------ */ /* added for UMFPACK: */ , Front_npivcol, Front_nrows, Front_ncols, Front_parent, Front_cols , &nfr, aggressive, InFront /* ------------------ */ ) ; /* ------------------ */ /* changed for UMFPACK: */ /* A is no longer needed, so use A [0..5*nfr-1] as workspace [ [ */ /* This step requires Alen >= 5*n_col */ Front_child = A ; Front_sibling = Front_child + nfr ; Front_stack = Front_sibling + nfr ; Front_order = Front_stack + nfr ; Front_size = Front_order + nfr ; UMF_fsize (nfr, Front_size, Front_nrows, Front_ncols, Front_parent, Front_npivcol) ; AMD_postorder (nfr, Front_parent, Front_npivcol, Front_size, Front_order, Front_child, Front_sibling, Front_stack) ; /* Front_size, Front_stack, Front_child, Front_sibling no longer needed ] */ /* use A [0..nfr-1] as workspace */ UMF_apply_order (Front_npivcol, Front_order, A, nfr, nfr) ; UMF_apply_order (Front_nrows, Front_order, A, nfr, nfr) ; UMF_apply_order (Front_ncols, Front_order, A, nfr, nfr) ; UMF_apply_order (Front_parent, Front_order, A, nfr, nfr) ; UMF_apply_order (Front_cols, Front_order, A, nfr, nfr) ; /* fix the parent to refer to the new numbering */ for (i = 0 ; i < nfr ; i++) { parent = Front_parent [i] ; if (parent != EMPTY) { Front_parent [i] = Front_order [parent] ; } } /* fix InFront to refer to the new numbering */ for (row = 0 ; row < n_row ; row++) { i = InFront [row] ; ASSERT (i >= EMPTY && i < nfr) ; if (i != EMPTY) { InFront [row] = Front_order [i] ; } } /* Front_order longer needed ] */ /* === Order the columns in the fronts ================================== */ /* use A [0..n_col-1] as inverse permutation */ for (i = 0 ; i < n_col ; i++) { A [i] = EMPTY ; } k = 0 ; for (i = 0 ; i < nfr ; i++) { ASSERT (Front_npivcol [i] > 0) ; for (col = Front_cols [i] ; col != EMPTY ; col = Col [col].nextcol) { ASSERT (col >= 0 && col < n_col) ; DEBUG1 (("Colamd output ordering: k "ID" col "ID"\n", k, col)) ; p [k] = col ; ASSERT (A [col] == EMPTY) ; A [col] = k ; k++ ; } } /* === Order the "dense" and null columns =============================== */ ASSERT (k == n_col2) ; if (n_col2 < n_col) { for (col = 0 ; col < n_col ; col++) { if (A [col] == EMPTY) { k = Col [col].shared2.order ; ASSERT (k >= n_col2 && k < n_col) ; DEBUG1 (("Colamd output ordering: k "ID" col "ID " (dense or null col)\n", k, col)) ; p [k] = col ; A [col] = k ; } } } /* ------------------ */ /* === Return statistics in stats ======================================= */ /* ------------------ */ /* modified for UMFPACK */ stats [COLAMD_DENSE_ROW] = ndense_row ; stats [COLAMD_EMPTY_ROW] = nempty_row ; stats [COLAMD_NEWLY_EMPTY_ROW] = nnewlyempty_row ; stats [COLAMD_DENSE_COL] = ndense_col ; stats [COLAMD_EMPTY_COL] = nempty_col ; stats [COLAMD_NEWLY_EMPTY_COL] = nnewlyempty_col ; ASSERT (ndense_col + nempty_col + nnewlyempty_col == n_col - n_col2) ; /* ------------------ */ stats [COLAMD_DEFRAG_COUNT] = ngarbage ; *p_nfr = nfr ; DEBUG1 (("colamd: done.\n")) ; return (TRUE) ; } /* ========================================================================== */ /* === colamd_report removed for UMFPACK ==================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === symamd_report removed for UMFPACK ==================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === NON-USER-CALLABLE ROUTINES: ========================================== */ /* ========================================================================== */ /* There are no user-callable routines beyond this point in the file */ /* ========================================================================== */ /* === init_rows_cols ======================================================= */ /* ========================================================================== */ /* Takes the column form of the matrix in A and creates the row form of the matrix. Also, row and column attributes are stored in the Col and Row structs. If the columns are un-sorted or contain duplicate row indices, this routine will also sort and remove duplicate row indices from the column form of the matrix. Returns FALSE if the matrix is invalid, TRUE otherwise. Not user-callable. */ /* For UMFPACK, this always returns TRUE */ PRIVATE Int init_rows_cols /* returns TRUE if OK, or FALSE otherwise */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* row indices of A, of size Alen */ Int p [] /* pointers to columns in A, of size n_col+1 */ /* Int stats [COLAMD_STATS] colamd statistics, removed for UMFPACK */ ) { /* === Local variables ================================================== */ Int col ; /* a column index */ Int row ; /* a row index */ Int *cp ; /* a column pointer */ Int *cp_end ; /* a pointer to the end of a column */ /* === Initialize columns, and check column pointers ==================== */ for (col = 0 ; col < n_col ; col++) { Col [col].start = p [col] ; Col [col].length = p [col+1] - p [col] ; #if 0 if (Col [col].length < 0) { /* column pointers must be non-decreasing */ stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = Col [col].length ; DEBUG0 (("colamd: col "ID" length "ID" <= 0\n", col, Col [col].length)); return (FALSE) ; } #endif ASSERT (Col [col].length >= 0) ; /* added for UMFPACK v4.1 */ ASSERT (Col [col].length > 0) ; Col [col].shared1.thickness = 1 ; Col [col].shared2.score = 0 ; Col [col].shared3.prev = EMPTY ; Col [col].shared4.degree_next = EMPTY ; /* ------------------ */ /* added for UMFPACK: */ Col [col].nextcol = EMPTY ; Col [col].lastcol = col ; /* ------------------ */ } /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ /* === Scan columns, compute row degrees, and check row indices ========= */ /* ------------------ */ /* stats [COLAMD_INFO3] = 0 ; */ /* number of duplicate or unsorted row indices - not computed in UMFPACK */ /* ------------------ */ for (row = 0 ; row < n_row ; row++) { Row [row].length = 0 ; /* ------------------ */ /* removed for UMFPACK */ /* Row [row].shared2.mark = -1 ; */ /* ------------------ */ /* ------------------ */ /* added for UMFPACK: */ Row [row].thickness = 1 ; Row [row].front = EMPTY ; /* ------------------ */ } for (col = 0 ; col < n_col ; col++) { #ifndef NDEBUG Int last_row = -1 ; #endif cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { row = *cp++ ; #if 0 /* make sure row indices within range */ if (row < 0 || row >= n_row) { stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = row ; /* ------------------ */ /* not needed in UMFPACK: */ /* stats [COLAMD_INFO3] = n_row ; */ /* ------------------ */ DEBUG0 (("colamd: row "ID" col "ID" out of bounds\n", row,col)); return (FALSE) ; } #endif ASSERT (row >= 0 && row < n_row) ; #if 0 /* ------------------ */ /* changed for UMFPACK */ if (row <= last_row) { /* row index are unsorted or repeated (or both), thus col */ /* is jumbled. This is an error condition for UMFPACK */ stats [COLAMD_STATUS] = COLAMD_ERROR_jumbled_matrix ; stats [COLAMD_INFO1] = col ; stats [COLAMD_INFO2] = row ; DEBUG1 (("colamd: row "ID" col "ID" unsorted/duplicate\n", row, col)) ; return (FALSE) ; } /* ------------------ */ #endif ASSERT (row > last_row) ; /* ------------------ */ /* changed for UMFPACK - jumbled columns not tolerated */ Row [row].length++ ; /* ------------------ */ #ifndef NDEBUG last_row = row ; #endif } } /* === Compute row pointers ============================================= */ /* row form of the matrix starts directly after the column */ /* form of matrix in A */ Row [0].start = p [n_col] ; Row [0].shared1.p = Row [0].start ; /* ------------------ */ /* removed for UMFPACK */ /* Row [0].shared2.mark = -1 ; */ /* ------------------ */ for (row = 1 ; row < n_row ; row++) { Row [row].start = Row [row-1].start + Row [row-1].length ; Row [row].shared1.p = Row [row].start ; /* ------------------ */ /* removed for UMFPACK */ /* Row [row].shared2.mark = -1 ; */ /* ------------------ */ } /* === Create row form ================================================== */ /* ------------------ */ /* jumbled matrix case removed for UMFPACK */ /* ------------------ */ for (col = 0 ; col < n_col ; col++) { cp = &A [p [col]] ; cp_end = &A [p [col+1]] ; while (cp < cp_end) { A [(Row [*cp++].shared1.p)++] = col ; } } /* === Clear the row marks and set row degrees ========================== */ for (row = 0 ; row < n_row ; row++) { Row [row].shared2.mark = 0 ; Row [row].shared1.degree = Row [row].length ; } /* ------------------ */ /* recreate columns for jumbled matrix case removed for UMFPACK */ /* ------------------ */ return (TRUE) ; } /* ========================================================================== */ /* === init_scoring ========================================================= */ /* ========================================================================== */ /* Kills dense or empty columns and rows, calculates an initial score for each column, and places all columns in the degree lists. Not user-callable. */ PRIVATE void init_scoring ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* column form and row form of A */ Int head [], /* of size n_col+1 */ double knobs [COLAMD_KNOBS],/* parameters */ Int *p_n_row2, /* number of non-dense, non-empty rows */ Int *p_n_col2, /* number of non-dense, non-empty columns */ Int *p_max_deg /* maximum row degree */ /* ------------------ */ /* added for UMFPACK */ , Int *p_ndense_row /* number of dense rows */ , Int *p_nempty_row /* number of original empty rows */ , Int *p_nnewlyempty_row /* number of newly empty rows */ , Int *p_ndense_col /* number of dense cols (excl "empty" cols) */ , Int *p_nempty_col /* number of original empty cols */ , Int *p_nnewlyempty_col /* number of newly empty cols */ /* ------------------ */ ) { /* === Local variables ================================================== */ Int c ; /* a column index */ Int r, row ; /* a row index */ Int *cp ; /* a column pointer */ Int deg ; /* degree of a row or column */ Int *cp_end ; /* a pointer to the end of a column */ Int *new_cp ; /* new column pointer */ Int col_length ; /* length of pruned column */ Int score ; /* current column score */ Int n_col2 ; /* number of non-dense, non-empty columns */ Int n_row2 ; /* number of non-dense, non-empty rows */ Int dense_row_count ; /* remove rows with more entries than this */ Int dense_col_count ; /* remove cols with more entries than this */ Int min_score ; /* smallest column score */ Int max_deg ; /* maximum row degree */ Int next_col ; /* Used to add to degree list.*/ /* ------------------ */ /* added for UMFPACK */ Int ndense_row ; /* number of dense rows */ Int nempty_row ; /* number of empty rows */ Int nnewlyempty_row ; /* number of newly empty rows */ Int ndense_col ; /* number of dense cols (excl "empty" cols) */ Int nempty_col ; /* number of original empty cols */ Int nnewlyempty_col ; /* number of newly empty cols */ Int ne ; /* ------------------ */ #ifndef NDEBUG Int debug_count ; /* debug only. */ #endif /* NDEBUG */ /* === Extract knobs ==================================================== */ /* --------------------- */ /* old dense row/column knobs: dense_row_count = MAX (0, MIN (knobs [COLAMD_DENSE_ROW] * n_col, n_col)) ; dense_col_count = MAX (0, MIN (knobs [COLAMD_DENSE_COL] * n_row, n_row)) ; */ /* new, for UMFPACK: */ /* Note: if knobs contains a NaN, this is undefined: */ dense_row_count = UMFPACK_DENSE_DEGREE_THRESHOLD (knobs [COLAMD_DENSE_ROW], n_col) ; dense_col_count = UMFPACK_DENSE_DEGREE_THRESHOLD (knobs [COLAMD_DENSE_COL], n_row) ; /* Make sure dense_*_count is between 0 and n: */ dense_row_count = MAX (0, MIN (dense_row_count, n_col)) ; dense_col_count = MAX (0, MIN (dense_col_count, n_row)) ; /* --------------------- */ DEBUG1 (("colamd: densecount: "ID" "ID"\n", dense_row_count, dense_col_count)) ; max_deg = 0 ; n_col2 = n_col ; n_row2 = n_row ; /* --------------------- */ /* added for UMFPACK */ ndense_col = 0 ; nempty_col = 0 ; nnewlyempty_col = 0 ; ndense_row = 0 ; nempty_row = 0 ; nnewlyempty_row = 0 ; /* --------------------- */ /* === Kill empty columns =============================================== */ /* removed for UMFPACK v4.1. prune_singletons has already removed empty * columns and empty rows */ #if 0 /* Put the empty columns at the end in their natural order, so that LU */ /* factorization can proceed as far as possible. */ for (c = n_col-1 ; c >= 0 ; c--) { deg = Col [c].length ; if (deg == 0) { /* this is a empty column, kill and order it last */ Col [c].shared2.order = --n_col2 ; KILL_PRINCIPAL_COL (c) ; /* --------------------- */ /* added for UMFPACK */ nempty_col++ ; /* --------------------- */ } } DEBUG1 (("colamd: null columns killed: "ID"\n", n_col - n_col2)) ; #endif #ifndef NDEBUG for (c = 0 ; c < n_col ; c++) { ASSERT (Col [c].length > 0) ; } #endif /* === Count null rows ================================================== */ #if 0 for (r = 0 ; r < n_row ; r++) { deg = Row [r].shared1.degree ; if (deg == 0) { /* this is an original empty row */ nempty_row++ ; } } #endif #ifndef NDEBUG for (r = 0 ; r < n_row ; r++) { ASSERT (Row [r].shared1.degree > 0) ; ASSERT (Row [r].length > 0) ; } #endif /* === Kill dense columns =============================================== */ /* Put the dense columns at the end, in their natural order */ for (c = n_col-1 ; c >= 0 ; c--) { /* ----------------------------------------------------------------- */ #if 0 /* removed for UMFPACK v4.1: no empty columns */ /* skip any dead columns */ if (COL_IS_DEAD (c)) { continue ; } #endif ASSERT (COL_IS_ALIVE (c)) ; ASSERT (Col [c].length > 0) ; /* ----------------------------------------------------------------- */ deg = Col [c].length ; if (deg > dense_col_count) { /* this is a dense column, kill and order it last */ Col [c].shared2.order = --n_col2 ; /* --------------------- */ /* added for UMFPACK */ ndense_col++ ; /* --------------------- */ /* decrement the row degrees */ cp = &A [Col [c].start] ; cp_end = cp + Col [c].length ; while (cp < cp_end) { Row [*cp++].shared1.degree-- ; } KILL_PRINCIPAL_COL (c) ; } } DEBUG1 (("colamd: Dense and null columns killed: "ID"\n", n_col - n_col2)) ; /* === Kill dense and empty rows ======================================== */ /* Note that there can now be empty rows, since dense columns have * been deleted. These are "newly" empty rows. */ ne = 0 ; for (r = 0 ; r < n_row ; r++) { deg = Row [r].shared1.degree ; ASSERT (deg >= 0 && deg <= n_col) ; /* --------------------- */ /* added for UMFPACK */ if (deg > dense_row_count) { /* There is at least one dense row. Continue ordering, but */ /* symbolic factorization will be redone after UMF_colamd is done.*/ ndense_row++ ; } if (deg == 0) { /* this is a newly empty row, or original empty row */ ne++ ; } /* --------------------- */ if (deg > dense_row_count || deg == 0) { /* kill a dense or empty row */ KILL_ROW (r) ; /* --------------------- */ /* added for UMFPACK */ Row [r].thickness = 0 ; /* --------------------- */ --n_row2 ; } else { /* keep track of max degree of remaining rows */ max_deg = MAX (max_deg, deg) ; } } nnewlyempty_row = ne - nempty_row ; DEBUG1 (("colamd: Dense rows killed: "ID"\n", ndense_row)) ; DEBUG1 (("colamd: Dense and null rows killed: "ID"\n", n_row - n_row2)) ; /* === Compute initial column scores ==================================== */ /* At this point the row degrees are accurate. They reflect the number */ /* of "live" (non-dense) columns in each row. No empty rows exist. */ /* Some "live" columns may contain only dead rows, however. These are */ /* pruned in the code below. */ /* now find the initial matlab score for each column */ for (c = n_col-1 ; c >= 0 ; c--) { /* skip dead column */ if (COL_IS_DEAD (c)) { continue ; } score = 0 ; cp = &A [Col [c].start] ; new_cp = cp ; cp_end = cp + Col [c].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; /* skip if dead */ if (ROW_IS_DEAD (row)) { continue ; } /* compact the column */ *new_cp++ = row ; /* add row's external degree */ score += Row [row].shared1.degree - 1 ; /* guard against integer overflow */ score = MIN (score, n_col) ; } /* determine pruned column length */ col_length = (Int) (new_cp - &A [Col [c].start]) ; if (col_length == 0) { /* a newly-made null column (all rows in this col are "dense" */ /* and have already been killed) */ DEBUG2 (("Newly null killed: "ID"\n", c)) ; Col [c].shared2.order = --n_col2 ; KILL_PRINCIPAL_COL (c) ; /* --------------------- */ /* added for UMFPACK */ nnewlyempty_col++ ; /* --------------------- */ } else { /* set column length and set score */ ASSERT (score >= 0) ; ASSERT (score <= n_col) ; Col [c].length = col_length ; Col [c].shared2.score = score ; } } DEBUG1 (("colamd: Dense, null, and newly-null columns killed: "ID"\n", n_col-n_col2)) ; /* At this point, all empty rows and columns are dead. All live columns */ /* are "clean" (containing no dead rows) and simplicial (no supercolumns */ /* yet). Rows may contain dead columns, but all live rows contain at */ /* least one live column. */ #ifndef NDEBUG debug_structures (n_row, n_col, Row, Col, A, n_col2) ; #endif /* NDEBUG */ /* === Initialize degree lists ========================================== */ #ifndef NDEBUG debug_count = 0 ; #endif /* NDEBUG */ /* clear the hash buckets */ for (c = 0 ; c <= n_col ; c++) { head [c] = EMPTY ; } min_score = n_col ; /* place in reverse order, so low column indices are at the front */ /* of the lists. This is to encourage natural tie-breaking */ for (c = n_col-1 ; c >= 0 ; c--) { /* only add principal columns to degree lists */ if (COL_IS_ALIVE (c)) { DEBUG4 (("place "ID" score "ID" minscore "ID" ncol "ID"\n", c, Col [c].shared2.score, min_score, n_col)) ; /* === Add columns score to DList =============================== */ score = Col [c].shared2.score ; ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (score >= 0) ; ASSERT (score <= n_col) ; ASSERT (head [score] >= EMPTY) ; /* now add this column to dList at proper score location */ next_col = head [score] ; Col [c].shared3.prev = EMPTY ; Col [c].shared4.degree_next = next_col ; /* if there already was a column with the same score, set its */ /* previous pointer to this new column */ if (next_col != EMPTY) { Col [next_col].shared3.prev = c ; } head [score] = c ; /* see if this score is less than current min */ min_score = MIN (min_score, score) ; #ifndef NDEBUG debug_count++ ; #endif /* NDEBUG */ } } #ifndef NDEBUG DEBUG1 (("colamd: Live cols "ID" out of "ID", non-princ: "ID"\n", debug_count, n_col, n_col-debug_count)) ; ASSERT (debug_count == n_col2) ; debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ; #endif /* NDEBUG */ /* === Return number of remaining columns, and max row degree =========== */ *p_n_col2 = n_col2 ; *p_n_row2 = n_row2 ; *p_max_deg = max_deg ; /* --------------------- */ /* added for UMFPACK */ *p_ndense_row = ndense_row ; *p_nempty_row = nempty_row ; /* original empty rows */ *p_nnewlyempty_row = nnewlyempty_row ; *p_ndense_col = ndense_col ; *p_nempty_col = nempty_col ; /* original empty cols */ *p_nnewlyempty_col = nnewlyempty_col ; /* --------------------- */ } /* ========================================================================== */ /* === find_ordering ======================================================== */ /* ========================================================================== */ /* Order the principal columns of the supercolumn form of the matrix (no supercolumns on input). Uses a minimum approximate column minimum degree ordering method. Not user-callable. */ PRIVATE Int find_ordering /* return the number of garbage collections */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows of A */ Int n_col, /* number of columns of A */ Int Alen, /* size of A, 2*nnz + n_col or larger */ Colamd_Row Row [], /* of size n_row+1 */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* column form and row form of A */ Int head [], /* of size n_col+1 */ Int n_col2, /* Remaining columns to order */ Int max_deg, /* Maximum row degree */ Int pfree /* index of first free slot (2*nnz on entry) */ /* ------------------ */ /* added for UMFPACK: */ , Int Front_npivcol [ ] , Int Front_nrows [ ] , Int Front_ncols [ ] , Int Front_parent [ ] , Int Front_cols [ ] , Int *p_nfr /* number of fronts */ , Int aggressive , Int InFront [ ] /* ------------------ */ ) { /* === Local variables ================================================== */ Int k ; /* current pivot ordering step */ Int pivot_col ; /* current pivot column */ Int *cp ; /* a column pointer */ Int *rp ; /* a row pointer */ Int pivot_row ; /* current pivot row */ Int *new_cp ; /* modified column pointer */ Int *new_rp ; /* modified row pointer */ Int pivot_row_start ; /* pointer to start of pivot row */ Int pivot_row_degree ; /* number of columns in pivot row */ Int pivot_row_length ; /* number of supercolumns in pivot row */ Int pivot_col_score ; /* score of pivot column */ Int needed_memory ; /* free space needed for pivot row */ Int *cp_end ; /* pointer to the end of a column */ Int *rp_end ; /* pointer to the end of a row */ Int row ; /* a row index */ Int col ; /* a column index */ Int max_score ; /* maximum possible score */ Int cur_score ; /* score of current column */ unsigned Int hash ; /* hash value for supernode detection */ Int head_column ; /* head of hash bucket */ Int first_col ; /* first column in hash bucket */ Int tag_mark ; /* marker value for mark array */ Int row_mark ; /* Row [row].shared2.mark */ Int set_difference ; /* set difference size of row with pivot row */ Int min_score ; /* smallest column score */ Int col_thickness ; /* "thickness" (no. of columns in a supercol) */ Int max_mark ; /* maximum value of tag_mark */ Int pivot_col_thickness ; /* number of columns represented by pivot col */ Int prev_col ; /* Used by Dlist operations. */ Int next_col ; /* Used by Dlist operations. */ Int ngarbage ; /* number of garbage collections performed */ #ifndef NDEBUG Int debug_d ; /* debug loop counter */ Int debug_step = 0 ; /* debug loop counter */ #endif /* NDEBUG */ /* ------------------ */ /* added for UMFPACK: */ Int pivot_row_thickness ; /* number of rows represented by pivot row */ Int nfr = 0 ; /* number of fronts */ Int child ; /* ------------------ */ /* === Initialization and clear mark ==================================== */ max_mark = MAX_MARK (n_col) ; /* defined in umfpack.h */ tag_mark = clear_mark (n_row, Row) ; min_score = 0 ; ngarbage = 0 ; DEBUG1 (("colamd: Ordering, n_col2="ID"\n", n_col2)) ; for (row = 0 ; row < n_row ; row++) { InFront [row] = EMPTY ; } /* === Order the columns ================================================ */ for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */) { #ifndef NDEBUG if (debug_step % 100 == 0) { DEBUG2 (("\n... Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ; } else { DEBUG3 (("\n-----Step k: "ID" out of n_col2: "ID"\n", k, n_col2)) ; } debug_step++ ; debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k, max_deg) ; debug_matrix (n_row, n_col, Row, Col, A) ; #endif /* NDEBUG */ /* === Select pivot column, and order it ============================ */ /* make sure degree list isn't empty */ ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (head [min_score] >= EMPTY) ; #ifndef NDEBUG for (debug_d = 0 ; debug_d < min_score ; debug_d++) { ASSERT (head [debug_d] == EMPTY) ; } #endif /* NDEBUG */ /* get pivot column from head of minimum degree list */ while (head [min_score] == EMPTY && min_score < n_col) { min_score++ ; } pivot_col = head [min_score] ; ASSERT (pivot_col >= 0 && pivot_col <= n_col) ; next_col = Col [pivot_col].shared4.degree_next ; head [min_score] = next_col ; if (next_col != EMPTY) { Col [next_col].shared3.prev = EMPTY ; } ASSERT (COL_IS_ALIVE (pivot_col)) ; DEBUG3 (("Pivot col: "ID"\n", pivot_col)) ; /* remember score for defrag check */ pivot_col_score = Col [pivot_col].shared2.score ; /* the pivot column is the kth column in the pivot order */ Col [pivot_col].shared2.order = k ; /* increment order count by column thickness */ pivot_col_thickness = Col [pivot_col].shared1.thickness ; /* ------------------ */ /* changed for UMFPACK: */ k += pivot_col_thickness ; /* ------------------ */ ASSERT (pivot_col_thickness > 0) ; /* === Garbage_collection, if necessary ============================= */ needed_memory = MIN (pivot_col_score, n_col - k) ; if (pfree + needed_memory >= Alen) { pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ; ngarbage++ ; /* after garbage collection we will have enough */ ASSERT (pfree + needed_memory < Alen) ; /* garbage collection has wiped out the Row[].shared2.mark array */ tag_mark = clear_mark (n_row, Row) ; #ifndef NDEBUG debug_matrix (n_row, n_col, Row, Col, A) ; #endif /* NDEBUG */ } /* === Compute pivot row pattern ==================================== */ /* get starting location for this new merged row */ pivot_row_start = pfree ; /* initialize new row counts to zero */ pivot_row_degree = 0 ; /* ------------------ */ /* added for UMFPACK: */ pivot_row_thickness = 0 ; /* ------------------ */ /* [ tag pivot column as having been visited so it isn't included */ /* in merged pivot row */ Col [pivot_col].shared1.thickness = -pivot_col_thickness ; /* pivot row is the union of all rows in the pivot column pattern */ cp = &A [Col [pivot_col].start] ; cp_end = cp + Col [pivot_col].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; DEBUG4 (("Pivot col pattern %d "ID"\n", ROW_IS_ALIVE(row), row)) ; /* skip if row is dead */ if (ROW_IS_DEAD (row)) { continue ; } /* ------------------ */ /* added for UMFPACK: */ /* sum the thicknesses of all the rows */ /* ASSERT (Row [row].thickness > 0) ; */ pivot_row_thickness += Row [row].thickness ; /* ------------------ */ rp = &A [Row [row].start] ; rp_end = rp + Row [row].length ; while (rp < rp_end) { /* get a column */ col = *rp++ ; /* add the column, if alive and untagged */ col_thickness = Col [col].shared1.thickness ; if (col_thickness > 0 && COL_IS_ALIVE (col)) { /* tag column in pivot row */ Col [col].shared1.thickness = -col_thickness ; ASSERT (pfree < Alen) ; /* place column in pivot row */ A [pfree++] = col ; pivot_row_degree += col_thickness ; /* ------------------ */ /* added for UMFPACK: */ DEBUG4 (("\t\t\tNew live column in pivot row: "ID"\n",col)); /* ------------------ */ } /* ------------------ */ /* added for UMFPACK */ #ifndef NDEBUG if (col_thickness < 0 && COL_IS_ALIVE (col)) { DEBUG4 (("\t\t\tOld live column in pivot row: "ID"\n",col)); } #endif /* ------------------ */ } } /* ------------------ */ /* added for UMFPACK: */ /* pivot_row_thickness is the number of rows in frontal matrix */ /* both pivotal rows and nonpivotal rows */ /* ------------------ */ /* clear tag on pivot column */ Col [pivot_col].shared1.thickness = pivot_col_thickness ; /* ] */ max_deg = MAX (max_deg, pivot_row_degree) ; #ifndef NDEBUG DEBUG3 (("check2\n")) ; debug_mark (n_row, Row, tag_mark, max_mark) ; #endif /* NDEBUG */ /* === Kill all rows used to construct pivot row ==================== */ /* also kill pivot row, temporarily */ cp = &A [Col [pivot_col].start] ; cp_end = cp + Col [pivot_col].length ; while (cp < cp_end) { /* may be killing an already dead row */ row = *cp++ ; DEBUG2 (("Kill row in pivot col: "ID" alive? %d, front "ID"\n", row, ROW_IS_ALIVE (row), Row [row].front)) ; /* added for UMFPACK: */ if (ROW_IS_ALIVE (row)) { if (Row [row].front != EMPTY) { /* This row represents a frontal matrix. */ /* Row [row].front is a child of current front */ child = Row [row].front ; Front_parent [child] = nfr ; DEBUG1 (("Front "ID" => front "ID", normal\n", child, nfr)); } else { /* This is an original row. Keep track of which front * is its parent in the row-merge tree. */ InFront [row] = nfr ; DEBUG1 (("Row "ID" => front "ID", normal\n", row, nfr)) ; } } KILL_ROW (row) ; /* ------------------ */ /* added for UMFPACK: */ Row [row].thickness = 0 ; /* ------------------ */ } /* === Select a row index to use as the new pivot row =============== */ pivot_row_length = pfree - pivot_row_start ; if (pivot_row_length > 0) { /* pick the "pivot" row arbitrarily (first row in col) */ pivot_row = A [Col [pivot_col].start] ; DEBUG3 (("Pivotal row is "ID"\n", pivot_row)) ; } else { /* there is no pivot row, since it is of zero length */ pivot_row = EMPTY ; ASSERT (pivot_row_length == 0) ; } ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ; /* === Approximate degree computation =============================== */ /* Here begins the computation of the approximate degree. The column */ /* score is the sum of the pivot row "length", plus the size of the */ /* set differences of each row in the column minus the pattern of the */ /* pivot row itself. The column ("thickness") itself is also */ /* excluded from the column score (we thus use an approximate */ /* external degree). */ /* The time taken by the following code (compute set differences, and */ /* add them up) is proportional to the size of the data structure */ /* being scanned - that is, the sum of the sizes of each column in */ /* the pivot row. Thus, the amortized time to compute a column score */ /* is proportional to the size of that column (where size, in this */ /* context, is the column "length", or the number of row indices */ /* in that column). The number of row indices in a column is */ /* monotonically non-decreasing, from the length of the original */ /* column on input to colamd. */ /* === Compute set differences ====================================== */ DEBUG3 (("** Computing set differences phase. **\n")) ; /* pivot row is currently dead - it will be revived later. */ DEBUG3 (("Pivot row: \n")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { col = *rp++ ; ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; DEBUG3 ((" Col: "ID"\n", col)) ; /* clear tags used to construct pivot row pattern */ col_thickness = -Col [col].shared1.thickness ; ASSERT (col_thickness > 0) ; Col [col].shared1.thickness = col_thickness ; /* === Remove column from degree list =========================== */ cur_score = Col [col].shared2.score ; prev_col = Col [col].shared3.prev ; next_col = Col [col].shared4.degree_next ; ASSERT (cur_score >= 0) ; ASSERT (cur_score <= n_col) ; ASSERT (cur_score >= EMPTY) ; if (prev_col == EMPTY) { head [cur_score] = next_col ; } else { Col [prev_col].shared4.degree_next = next_col ; } if (next_col != EMPTY) { Col [next_col].shared3.prev = prev_col ; } /* === Scan the column ========================================== */ cp = &A [Col [col].start] ; cp_end = cp + Col [col].length ; while (cp < cp_end) { /* get a row */ row = *cp++ ; row_mark = Row [row].shared2.mark ; /* skip if dead */ if (ROW_IS_MARKED_DEAD (row_mark)) { continue ; } ASSERT (row != pivot_row) ; set_difference = row_mark - tag_mark ; /* check if the row has been seen yet */ if (set_difference < 0) { ASSERT (Row [row].shared1.degree <= max_deg) ; set_difference = Row [row].shared1.degree ; } /* subtract column thickness from this row's set difference */ set_difference -= col_thickness ; ASSERT (set_difference >= 0) ; ASSERT (ROW_IS_ALIVE (row)) ; /* absorb this row if the set difference becomes zero */ if (set_difference == 0 && aggressive) { /* v4.1: do aggressive absorption */ DEBUG3 (("aggressive absorption. Row: "ID"\n", row)) ; if (Row [row].front != EMPTY) { /* Row [row].front is a child of current front. */ child = Row [row].front ; Front_parent [child] = nfr ; DEBUG1 (("Front "ID" => front "ID", aggressive\n", child, nfr)) ; } else { /* this is an original row. Keep track of which front * assembles it, for the row-merge tree */ InFront [row] = nfr ; DEBUG1 (("Row "ID" => front "ID", aggressive\n", row, nfr)) ; } KILL_ROW (row) ; /* sum the thicknesses of all the rows */ /* ASSERT (Row [row].thickness > 0) ; */ pivot_row_thickness += Row [row].thickness ; Row [row].thickness = 0 ; } else { /* save the new mark */ Row [row].shared2.mark = set_difference + tag_mark ; } } } #ifndef NDEBUG debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k-pivot_row_degree, max_deg) ; #endif /* NDEBUG */ /* === Add up set differences for each column ======================= */ DEBUG3 (("** Adding set differences phase. **\n")) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { /* get a column */ col = *rp++ ; ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ; hash = 0 ; cur_score = 0 ; cp = &A [Col [col].start] ; /* compact the column */ new_cp = cp ; cp_end = cp + Col [col].length ; DEBUG4 (("Adding set diffs for Col: "ID".\n", col)) ; while (cp < cp_end) { /* get a row */ row = *cp++ ; ASSERT(row >= 0 && row < n_row) ; row_mark = Row [row].shared2.mark ; /* skip if dead */ if (ROW_IS_MARKED_DEAD (row_mark)) { /* ------------------ */ /* changed for UMFPACK: */ DEBUG4 ((" Row "ID", dead\n", row)) ; /* ------------------ */ continue ; } /* ------------------ */ /* changed for UMFPACK: */ /* ASSERT (row_mark > tag_mark) ; */ DEBUG4 ((" Row "ID", set diff "ID"\n", row, row_mark-tag_mark)); ASSERT (row_mark >= tag_mark) ; /* ------------------ */ /* compact the column */ *new_cp++ = row ; /* compute hash function */ hash += row ; /* add set difference */ cur_score += row_mark - tag_mark ; /* integer overflow... */ cur_score = MIN (cur_score, n_col) ; } /* recompute the column's length */ Col [col].length = (Int) (new_cp - &A [Col [col].start]) ; /* === Further mass elimination ================================= */ if (Col [col].length == 0) { DEBUG4 (("further mass elimination. Col: "ID"\n", col)) ; /* nothing left but the pivot row in this column */ KILL_PRINCIPAL_COL (col) ; pivot_row_degree -= Col [col].shared1.thickness ; ASSERT (pivot_row_degree >= 0) ; /* order it */ Col [col].shared2.order = k ; /* increment order count by column thickness */ k += Col [col].shared1.thickness ; /* ------------------ */ /* added for UMFPACK: */ pivot_col_thickness += Col [col].shared1.thickness ; /* add to column list of front ... */ #ifndef NDEBUG DEBUG1 (("Mass")) ; dump_super (col, Col, n_col) ; #endif Col [Col [col].lastcol].nextcol = Front_cols [nfr] ; Front_cols [nfr] = col ; /* ------------------ */ } else { /* === Prepare for supercolumn detection ==================== */ DEBUG4 (("Preparing supercol detection for Col: "ID".\n", col)); /* save score so far */ Col [col].shared2.score = cur_score ; /* add column to hash table, for supercolumn detection */ /* NOTE: hash is an unsigned Int to avoid a problem in ANSI C. * The sign of the expression a % b is not defined when a and/or * b are negative. Since hash is unsigned and n_col >= 0, * this problem is avoided. */ hash %= n_col + 1 ; DEBUG4 ((" Hash = "ID", n_col = "ID".\n", (Int) hash, n_col)) ; ASSERT (((Int) hash) <= n_col) ; head_column = head [hash] ; if (head_column > EMPTY) { /* degree list "hash" is non-empty, use prev (shared3) of */ /* first column in degree list as head of hash bucket */ first_col = Col [head_column].shared3.headhash ; Col [head_column].shared3.headhash = col ; } else { /* degree list "hash" is empty, use head as hash bucket */ first_col = - (head_column + 2) ; head [hash] = - (col + 2) ; } Col [col].shared4.hash_next = first_col ; /* save hash function in Col [col].shared3.hash */ Col [col].shared3.hash = (Int) hash ; ASSERT (COL_IS_ALIVE (col)) ; } } /* The approximate external column degree is now computed. */ /* === Supercolumn detection ======================================== */ DEBUG3 (("** Supercolumn detection phase. **\n")) ; detect_super_cols ( #ifndef NDEBUG n_col, Row, #endif /* NDEBUG */ Col, A, head, pivot_row_start, pivot_row_length) ; /* === Kill the pivotal column ====================================== */ KILL_PRINCIPAL_COL (pivot_col) ; /* ------------------ */ /* added for UMFPACK: */ /* add columns to column list of front */ #ifndef NDEBUG DEBUG1 (("Pivot")) ; dump_super (pivot_col, Col, n_col) ; #endif Col [Col [pivot_col].lastcol].nextcol = Front_cols [nfr] ; Front_cols [nfr] = pivot_col ; /* ------------------ */ /* === Clear mark =================================================== */ tag_mark += (max_deg + 1) ; if (tag_mark >= max_mark) { DEBUG2 (("clearing tag_mark\n")) ; tag_mark = clear_mark (n_row, Row) ; } #ifndef NDEBUG DEBUG3 (("check3\n")) ; debug_mark (n_row, Row, tag_mark, max_mark) ; #endif /* NDEBUG */ /* === Finalize the new pivot row, and column scores ================ */ DEBUG3 (("** Finalize scores phase. **\n")) ; DEBUG3 (("pivot_row_degree "ID"\n", pivot_row_degree)) ; /* for each column in pivot row */ rp = &A [pivot_row_start] ; /* compact the pivot row */ new_rp = rp ; rp_end = rp + pivot_row_length ; while (rp < rp_end) { col = *rp++ ; DEBUG3 (("Col "ID" \n", col)) ; /* skip dead columns */ if (COL_IS_DEAD (col)) { DEBUG3 (("dead\n")) ; continue ; } *new_rp++ = col ; /* add new pivot row to column */ A [Col [col].start + (Col [col].length++)] = pivot_row ; /* retrieve score so far and add on pivot row's degree. */ /* (we wait until here for this in case the pivot */ /* row's degree was reduced due to mass elimination). */ cur_score = Col [col].shared2.score + pivot_row_degree ; DEBUG3 ((" cur_score "ID" ", cur_score)) ; /* calculate the max possible score as the number of */ /* external columns minus the 'k' value minus the */ /* columns thickness */ max_score = n_col - k - Col [col].shared1.thickness ; DEBUG3 ((" max_score "ID" ", max_score)) ; /* make the score the external degree of the union-of-rows */ cur_score -= Col [col].shared1.thickness ; DEBUG3 ((" cur_score "ID" ", cur_score)) ; /* make sure score is less or equal than the max score */ cur_score = MIN (cur_score, max_score) ; ASSERT (cur_score >= 0) ; /* store updated score */ Col [col].shared2.score = cur_score ; DEBUG3 ((" "ID"\n", cur_score)) ; /* === Place column back in degree list ========================= */ ASSERT (min_score >= 0) ; ASSERT (min_score <= n_col) ; ASSERT (cur_score >= 0) ; ASSERT (cur_score <= n_col) ; ASSERT (head [cur_score] >= EMPTY) ; next_col = head [cur_score] ; Col [col].shared4.degree_next = next_col ; Col [col].shared3.prev = EMPTY ; if (next_col != EMPTY) { Col [next_col].shared3.prev = col ; } head [cur_score] = col ; /* see if this score is less than current min */ min_score = MIN (min_score, cur_score) ; } #ifndef NDEBUG debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2-k, max_deg) ; #endif /* NDEBUG */ /* ------------------ */ /* added for UMFPACK: */ /* frontal matrix can have more pivot cols than pivot rows for */ /* singular matrices. */ /* number of candidate pivot columns */ Front_npivcol [nfr] = pivot_col_thickness ; /* all rows (not just size of contrib. block) */ Front_nrows [nfr] = pivot_row_thickness ; /* all cols */ Front_ncols [nfr] = pivot_col_thickness + pivot_row_degree ; Front_parent [nfr] = EMPTY ; pivot_row_thickness -= pivot_col_thickness ; DEBUG1 (("Front "ID" Pivot_row_thickness after pivot cols elim: "ID"\n", nfr, pivot_row_thickness)) ; pivot_row_thickness = MAX (0, pivot_row_thickness) ; /* ------------------ */ /* === Resurrect the new pivot row ================================== */ if (pivot_row_degree > 0 /* ------------------ */ /* added for UMFPACK. Note that this part of the expression should be * removed if this routine is used outside of UMFPACK, for a Cholesky * factorization of (AQ)'(AQ) */ && pivot_row_thickness > 0 /* ------------------ */ ) { /* update pivot row length to reflect any cols that were killed */ /* during super-col detection and mass elimination */ Row [pivot_row].start = pivot_row_start ; Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ; ASSERT (Row [pivot_row].length > 0) ; Row [pivot_row].shared1.degree = pivot_row_degree ; Row [pivot_row].shared2.mark = 0 ; /* ------------------ */ /* added for UMFPACK: */ Row [pivot_row].thickness = pivot_row_thickness ; Row [pivot_row].front = nfr ; /* ------------------ */ /* pivot row is no longer dead */ } /* ------------------ */ /* added for UMFPACK: */ #ifndef NDEBUG DEBUG1 (("Front "ID" : "ID" "ID" "ID" ", nfr, Front_npivcol [nfr], Front_nrows [nfr], Front_ncols [nfr])) ; DEBUG1 ((" cols:[ ")) ; debug_d = 0 ; for (col = Front_cols [nfr] ; col != EMPTY ; col = Col [col].nextcol) { DEBUG1 ((" "ID, col)) ; ASSERT (col >= 0 && col < n_col) ; ASSERT (COL_IS_DEAD (col)) ; debug_d++ ; ASSERT (debug_d <= pivot_col_thickness) ; } ASSERT (debug_d == pivot_col_thickness) ; DEBUG1 ((" ]\n ")) ; #endif nfr++ ; /* one more front */ /* ------------------ */ } /* === All principal columns have now been ordered ====================== */ /* ------------------ */ /* added for UMFPACK: */ *p_nfr = nfr ; /* ------------------ */ return (ngarbage) ; } /* ========================================================================== */ /* === order_children deleted for UMFPACK =================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === detect_super_cols ==================================================== */ /* ========================================================================== */ /* Detects supercolumns by finding matches between columns in the hash buckets. Check amongst columns in the set A [row_start ... row_start + row_length-1]. The columns under consideration are currently *not* in the degree lists, and have already been placed in the hash buckets. The hash bucket for columns whose hash function is equal to h is stored as follows: if head [h] is >= 0, then head [h] contains a degree list, so: head [h] is the first column in degree bucket h. Col [head [h]].headhash gives the first column in hash bucket h. otherwise, the degree list is empty, and: -(head [h] + 2) is the first column in hash bucket h. For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous column" pointer. Col [c].shared3.hash is used instead as the hash number for that column. The value of Col [c].shared4.hash_next is the next column in the same hash bucket. Assuming no, or "few" hash collisions, the time taken by this routine is linear in the sum of the sizes (lengths) of each column whose score has just been computed in the approximate degree computation. Not user-callable. */ PRIVATE void detect_super_cols ( /* === Parameters ======================================================= */ #ifndef NDEBUG /* these two parameters are only needed when debugging is enabled: */ Int n_col, /* number of columns of A */ Colamd_Row Row [], /* of size n_row+1 */ #endif /* NDEBUG */ Colamd_Col Col [], /* of size n_col+1 */ Int A [], /* row indices of A */ Int head [], /* head of degree lists and hash buckets */ Int row_start, /* pointer to set of columns to check */ Int row_length /* number of columns to check */ ) { /* === Local variables ================================================== */ Int hash ; /* hash value for a column */ Int *rp ; /* pointer to a row */ Int c ; /* a column index */ Int super_c ; /* column index of the column to absorb into */ Int *cp1 ; /* column pointer for column super_c */ Int *cp2 ; /* column pointer for column c */ Int length ; /* length of column super_c */ Int prev_c ; /* column preceding c in hash bucket */ Int i ; /* loop counter */ Int *rp_end ; /* pointer to the end of the row */ Int col ; /* a column index in the row to check */ Int head_column ; /* first column in hash bucket or degree list */ Int first_col ; /* first column in hash bucket */ /* === Consider each column in the row ================================== */ rp = &A [row_start] ; rp_end = rp + row_length ; while (rp < rp_end) { col = *rp++ ; if (COL_IS_DEAD (col)) { continue ; } /* get hash number for this column */ hash = Col [col].shared3.hash ; ASSERT (hash <= n_col) ; /* === Get the first column in this hash bucket ===================== */ head_column = head [hash] ; if (head_column > EMPTY) { first_col = Col [head_column].shared3.headhash ; } else { first_col = - (head_column + 2) ; } /* === Consider each column in the hash bucket ====================== */ for (super_c = first_col ; super_c != EMPTY ; super_c = Col [super_c].shared4.hash_next) { ASSERT (COL_IS_ALIVE (super_c)) ; ASSERT (Col [super_c].shared3.hash == hash) ; length = Col [super_c].length ; /* prev_c is the column preceding column c in the hash bucket */ prev_c = super_c ; /* === Compare super_c with all columns after it ================ */ for (c = Col [super_c].shared4.hash_next ; c != EMPTY ; c = Col [c].shared4.hash_next) { ASSERT (c != super_c) ; ASSERT (COL_IS_ALIVE (c)) ; ASSERT (Col [c].shared3.hash == hash) ; /* not identical if lengths or scores are different */ if (Col [c].length != length || Col [c].shared2.score != Col [super_c].shared2.score) { prev_c = c ; continue ; } /* compare the two columns */ cp1 = &A [Col [super_c].start] ; cp2 = &A [Col [c].start] ; for (i = 0 ; i < length ; i++) { /* the columns are "clean" (no dead rows) */ ASSERT (ROW_IS_ALIVE (*cp1)) ; ASSERT (ROW_IS_ALIVE (*cp2)) ; /* row indices will same order for both supercols, */ /* no gather scatter nessasary */ if (*cp1++ != *cp2++) { break ; } } /* the two columns are different if the for-loop "broke" */ if (i != length) { prev_c = c ; continue ; } /* === Got it! two columns are identical =================== */ ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ; Col [super_c].shared1.thickness += Col [c].shared1.thickness ; Col [c].shared1.parent = super_c ; KILL_NON_PRINCIPAL_COL (c) ; Col [c].shared2.order = EMPTY ; /* remove c from hash bucket */ Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ; /* ------------------ */ /* added for UMFPACK: */ /* add c to end of list of super_c */ ASSERT (Col [super_c].lastcol >= 0) ; ASSERT (Col [super_c].lastcol < n_col) ; Col [Col [super_c].lastcol].nextcol = c ; Col [super_c].lastcol = Col [c].lastcol ; #ifndef NDEBUG /* dump the supercolumn */ DEBUG1 (("Super")) ; dump_super (super_c, Col, n_col) ; #endif /* ------------------ */ } } /* === Empty this hash bucket ======================================= */ if (head_column > EMPTY) { /* corresponding degree list "hash" is not empty */ Col [head_column].shared3.headhash = EMPTY ; } else { /* corresponding degree list "hash" is empty */ head [hash] = EMPTY ; } } } /* ========================================================================== */ /* === garbage_collection =================================================== */ /* ========================================================================== */ /* Defragments and compacts columns and rows in the workspace A. Used when all avaliable memory has been used while performing row merging. Returns the index of the first free position in A, after garbage collection. The time taken by this routine is linear is the size of the array A, which is itself linear in the number of nonzeros in the input matrix. Not user-callable. */ PRIVATE Int garbage_collection /* returns the new value of pfree */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows */ Int n_col, /* number of columns */ Colamd_Row Row [], /* row info */ Colamd_Col Col [], /* column info */ Int A [], /* A [0 ... Alen-1] holds the matrix */ Int *pfree /* &A [0] ... pfree is in use */ ) { /* === Local variables ================================================== */ Int *psrc ; /* source pointer */ Int *pdest ; /* destination pointer */ Int j ; /* counter */ Int r ; /* a row index */ Int c ; /* a column index */ Int length ; /* length of a row or column */ #ifndef NDEBUG Int debug_rows ; DEBUG2 (("Defrag..\n")) ; for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ; debug_rows = 0 ; #endif /* NDEBUG */ /* === Defragment the columns =========================================== */ pdest = &A[0] ; for (c = 0 ; c < n_col ; c++) { if (COL_IS_ALIVE (c)) { psrc = &A [Col [c].start] ; /* move and compact the column */ ASSERT (pdest <= psrc) ; Col [c].start = (Int) (pdest - &A [0]) ; length = Col [c].length ; for (j = 0 ; j < length ; j++) { r = *psrc++ ; if (ROW_IS_ALIVE (r)) { *pdest++ = r ; } } Col [c].length = (Int) (pdest - &A [Col [c].start]) ; } } /* === Prepare to defragment the rows =================================== */ for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { if (Row [r].length == 0) { /* :: defrag row kill :: */ /* This row is of zero length. cannot compact it, so kill it. * NOTE: in the current version, there are no zero-length live * rows when garbage_collection is called. So this code will * never trigger. However, if the code is modified, or if * garbage_collection is called at a different place, then rows * can be of zero length. So this test is kept, just in case. */ DEBUGm4 (("Defrag row kill\n")) ; KILL_ROW (r) ; } else { /* save first column index in Row [r].shared2.first_column */ psrc = &A [Row [r].start] ; Row [r].shared2.first_column = *psrc ; ASSERT (ROW_IS_ALIVE (r)) ; /* flag the start of the row with the one's complement of row */ *psrc = ONES_COMPLEMENT (r) ; #ifndef NDEBUG debug_rows++ ; #endif /* NDEBUG */ } } } /* === Defragment the rows ============================================== */ psrc = pdest ; while (psrc < pfree) { /* find a negative number ... the start of a row */ if (*psrc++ < 0) { psrc-- ; /* get the row index */ r = ONES_COMPLEMENT (*psrc) ; ASSERT (r >= 0 && r < n_row) ; /* restore first column index */ *psrc = Row [r].shared2.first_column ; ASSERT (ROW_IS_ALIVE (r)) ; /* move and compact the row */ ASSERT (pdest <= psrc) ; Row [r].start = (Int) (pdest - &A [0]) ; length = Row [r].length ; for (j = 0 ; j < length ; j++) { c = *psrc++ ; if (COL_IS_ALIVE (c)) { *pdest++ = c ; } } Row [r].length = (Int) (pdest - &A [Row [r].start]) ; #ifndef NDEBUG debug_rows-- ; #endif /* NDEBUG */ } } /* ensure we found all the rows */ ASSERT (debug_rows == 0) ; /* === Return the new value of pfree ==================================== */ return ((Int) (pdest - &A [0])) ; } /* ========================================================================== */ /* === clear_mark =========================================================== */ /* ========================================================================== */ /* Clears the Row [].shared2.mark array, and returns the new tag_mark. Return value is the new tag_mark. Not user-callable. */ PRIVATE Int clear_mark /* return the new value for tag_mark */ ( /* === Parameters ======================================================= */ Int n_row, /* number of rows in A */ Colamd_Row Row [] /* Row [0 ... n-1].shared2.mark is set to zero */ ) { /* === Local variables ================================================== */ Int r ; for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { Row [r].shared2.mark = 0 ; } } /* ------------------ */ return (1) ; /* ------------------ */ } /* ========================================================================== */ /* === print_report removed for UMFPACK ===================================== */ /* ========================================================================== */ /* ========================================================================== */ /* === colamd debugging routines ============================================ */ /* ========================================================================== */ /* When debugging is disabled, the remainder of this file is ignored. */ #ifndef NDEBUG /* ========================================================================== */ /* === debug_structures ===================================================== */ /* ========================================================================== */ /* At this point, all empty rows and columns are dead. All live columns are "clean" (containing no dead rows) and simplicial (no supercolumns yet). Rows may contain dead columns, but all live rows contain at least one live column. */ PRIVATE void debug_structures ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [], Int n_col2 ) { /* === Local variables ================================================== */ Int i ; Int c ; Int *cp ; Int *cp_end ; Int len ; Int score ; Int r ; Int *rp ; Int *rp_end ; Int deg ; /* === Check A, Row, and Col ============================================ */ for (c = 0 ; c < n_col ; c++) { if (COL_IS_ALIVE (c)) { len = Col [c].length ; score = Col [c].shared2.score ; DEBUG4 (("initial live col "ID" "ID" "ID"\n", c, len, score)) ; ASSERT (len > 0) ; ASSERT (score >= 0) ; ASSERT (Col [c].shared1.thickness == 1) ; cp = &A [Col [c].start] ; cp_end = cp + len ; while (cp < cp_end) { r = *cp++ ; ASSERT (ROW_IS_ALIVE (r)) ; } } else { i = Col [c].shared2.order ; ASSERT (i >= n_col2 && i < n_col) ; } } for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { i = 0 ; len = Row [r].length ; deg = Row [r].shared1.degree ; ASSERT (len > 0) ; ASSERT (deg > 0) ; rp = &A [Row [r].start] ; rp_end = rp + len ; while (rp < rp_end) { c = *rp++ ; if (COL_IS_ALIVE (c)) { i++ ; } } ASSERT (i > 0) ; } } } /* ========================================================================== */ /* === debug_deg_lists ====================================================== */ /* ========================================================================== */ /* Prints the contents of the degree lists. Counts the number of columns in the degree list and compares it to the total it should have. Also checks the row degrees. */ PRIVATE void debug_deg_lists ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int head [], Int min_score, Int should, Int max_deg ) { /* === Local variables ================================================== */ Int deg ; Int col ; Int have ; Int row ; /* === Check the degree lists =========================================== */ if (n_col > 10000 && UMF_debug <= 0) { return ; } have = 0 ; DEBUG4 (("Degree lists: "ID"\n", min_score)) ; for (deg = 0 ; deg <= n_col ; deg++) { col = head [deg] ; if (col == EMPTY) { continue ; } DEBUG4 ((ID":", deg)) ; while (col != EMPTY) { DEBUG4 ((" "ID, col)) ; have += Col [col].shared1.thickness ; ASSERT (COL_IS_ALIVE (col)) ; col = Col [col].shared4.degree_next ; } DEBUG4 (("\n")) ; } DEBUG4 (("should "ID" have "ID"\n", should, have)) ; ASSERT (should == have) ; /* === Check the row degrees ============================================ */ if (n_row > 10000 && UMF_debug <= 0) { return ; } for (row = 0 ; row < n_row ; row++) { if (ROW_IS_ALIVE (row)) { ASSERT (Row [row].shared1.degree <= max_deg) ; } } } /* ========================================================================== */ /* === debug_mark =========================================================== */ /* ========================================================================== */ /* Ensures that the tag_mark is less that the maximum and also ensures that each entry in the mark array is less than the tag mark. */ PRIVATE void debug_mark ( /* === Parameters ======================================================= */ Int n_row, Colamd_Row Row [], Int tag_mark, Int max_mark ) { /* === Local variables ================================================== */ Int r ; /* === Check the Row marks ============================================== */ ASSERT (tag_mark > 0 && tag_mark <= max_mark) ; if (n_row > 10000 && UMF_debug <= 0) { return ; } for (r = 0 ; r < n_row ; r++) { ASSERT (Row [r].shared2.mark < tag_mark) ; } } /* ========================================================================== */ /* === debug_matrix ========================================================= */ /* ========================================================================== */ /* Prints out the contents of the columns and the rows. */ PRIVATE void debug_matrix ( /* === Parameters ======================================================= */ Int n_row, Int n_col, Colamd_Row Row [], Colamd_Col Col [], Int A [] ) { /* === Local variables ================================================== */ Int r ; Int c ; Int *rp ; Int *rp_end ; Int *cp ; Int *cp_end ; /* === Dump the rows and columns of the matrix ========================== */ if (UMF_debug < 3) { return ; } DEBUG3 (("DUMP MATRIX:\n")) ; for (r = 0 ; r < n_row ; r++) { DEBUG3 (("Row "ID" alive? %d\n", r, ROW_IS_ALIVE (r))) ; if (ROW_IS_DEAD (r)) { continue ; } /* ------------------ */ /* changed for UMFPACK: */ DEBUG3 (("start "ID" length "ID" degree "ID" thickness "ID"\n", Row [r].start, Row [r].length, Row [r].shared1.degree, Row [r].thickness)) ; /* ------------------ */ rp = &A [Row [r].start] ; rp_end = rp + Row [r].length ; while (rp < rp_end) { c = *rp++ ; DEBUG4 ((" %d col "ID"\n", COL_IS_ALIVE (c), c)) ; } } for (c = 0 ; c < n_col ; c++) { DEBUG3 (("Col "ID" alive? %d\n", c, COL_IS_ALIVE (c))) ; if (COL_IS_DEAD (c)) { continue ; } /* ------------------ */ /* changed for UMFPACK: */ DEBUG3 (("start "ID" length "ID" shared1[thickness,parent] "ID " shared2 [order,score] "ID"\n", Col [c].start, Col [c].length, Col [c].shared1.thickness, Col [c].shared2.score)); /* ------------------ */ cp = &A [Col [c].start] ; cp_end = cp + Col [c].length ; while (cp < cp_end) { r = *cp++ ; DEBUG4 ((" %d row "ID"\n", ROW_IS_ALIVE (r), r)) ; } /* ------------------ */ /* added for UMFPACK: */ DEBUG1 (("Col")) ; dump_super (c, Col, n_col) ; /* ------------------ */ } } /* ------------------ */ /* dump_super added for UMFPACK: */ PRIVATE void dump_super ( Int super_c, Colamd_Col Col [], Int n_col ) { Int col, ncols ; DEBUG1 ((" =[ ")) ; ncols = 0 ; for (col = super_c ; col != EMPTY ; col = Col [col].nextcol) { DEBUG1 ((" "ID, col)) ; ASSERT (col >= 0 && col < n_col) ; if (col != super_c) { ASSERT (COL_IS_DEAD (col)) ; } if (Col [col].nextcol == EMPTY) { ASSERT (col == Col [super_c].lastcol) ; } ncols++ ; ASSERT (ncols <= Col [super_c].shared1.thickness) ; } ASSERT (ncols == Col [super_c].shared1.thickness) ; DEBUG1 (("]\n")) ; } /* ------------------ */ #endif /* NDEBUG */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_numeric.c0000644000175000017500000006751611674452555023205 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_numeric ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Factorizes A into its LU factors, given a symbolic pre-analysis computed by UMFPACK_symbolic. See umfpack_numeric.h for a description. Dynamic memory allocation: substantial. See comments (1) through (7), below. If an error occurs, all allocated space is free'd by UMF_free. If successful, the Numeric object contains 11 to 13 objects allocated by UMF_malloc that hold the LU factors of the input matrix. */ #include "umf_internal.h" #include "umf_valid_symbolic.h" #include "umf_set_stats.h" #include "umf_kernel.h" #include "umf_malloc.h" #include "umf_free.h" #include "umf_realloc.h" #ifndef NDEBUG PRIVATE Int init_count ; #endif PRIVATE Int work_alloc ( WorkType *Work, SymbolicType *Symbolic ) ; PRIVATE void free_work ( WorkType *Work ) ; PRIVATE Int numeric_alloc ( NumericType **NumericHandle, SymbolicType *Symbolic, double alloc_init, Int scale ) ; PRIVATE void error ( NumericType **Numeric, WorkType *Work ) ; /* ========================================================================== */ /* === UMFPACK_numeric ====================================================== */ /* ========================================================================== */ GLOBAL Int UMFPACK_numeric ( const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif void *SymbolicHandle, void **NumericHandle, const double Control [UMFPACK_CONTROL], double User_Info [UMFPACK_INFO] ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ double Info2 [UMFPACK_INFO], alloc_init, relpt, relpt2, droptol, front_alloc_init, stats [2] ; double *Info ; WorkType WorkSpace, *Work ; NumericType *Numeric ; SymbolicType *Symbolic ; Int n_row, n_col, n_inner, newsize, i, status, *inew, npiv, ulen, scale ; Unit *mnew ; /* ---------------------------------------------------------------------- */ /* get the amount of time used by the process so far */ /* ---------------------------------------------------------------------- */ umfpack_tic (stats) ; /* ---------------------------------------------------------------------- */ /* initialize and check inputs */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG UMF_dump_start ( ) ; init_count = UMF_malloc_count ; DEBUGm4 (("\nUMFPACK numeric: U transpose version\n")) ; #endif /* If front_alloc_init negative then allocate that size of front in * UMF_start_front. If alloc_init negative, then allocate that initial * size of Numeric->Memory. */ relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE, UMFPACK_DEFAULT_PIVOT_TOLERANCE) ; relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE, UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ; alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ; front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT, UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ; scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ; droptol = GET_CONTROL (UMFPACK_DROPTOL, UMFPACK_DEFAULT_DROPTOL) ; relpt = MAX (0.0, MIN (relpt, 1.0)) ; relpt2 = MAX (0.0, MIN (relpt2, 1.0)) ; droptol = MAX (0.0, droptol) ; front_alloc_init = MIN (1.0, front_alloc_init) ; if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX) { scale = UMFPACK_DEFAULT_SCALE ; } if (User_Info != (double *) NULL) { /* return Info in user's array */ Info = User_Info ; /* clear the parts of Info that are set by UMFPACK_numeric */ for (i = UMFPACK_NUMERIC_SIZE ; i <= UMFPACK_MAX_FRONT_NCOLS ; i++) { Info [i] = EMPTY ; } for (i = UMFPACK_NUMERIC_DEFRAG ; i < UMFPACK_IR_TAKEN ; i++) { Info [i] = EMPTY ; } } else { /* no Info array passed - use local one instead */ Info = Info2 ; for (i = 0 ; i < UMFPACK_INFO ; i++) { Info [i] = EMPTY ; } } Symbolic = (SymbolicType *) SymbolicHandle ; Numeric = (NumericType *) NULL ; if (!UMF_valid_symbolic (Symbolic)) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_invalid_Symbolic_object ; return (UMFPACK_ERROR_invalid_Symbolic_object) ; } /* compute alloc_init automatically for AMD ordering */ if (Symbolic->ordering == UMFPACK_ORDERING_AMD && alloc_init >= 0) { alloc_init = (Symbolic->nz + Symbolic->amd_lunz) / Symbolic->lunz_bound; alloc_init = MIN (1.0, alloc_init) ; alloc_init *= UMF_REALLOC_INCREASE ; } n_row = Symbolic->n_row ; n_col = Symbolic->n_col ; n_inner = MIN (n_row, n_col) ; /* check for integer overflow in Numeric->Memory minimum size */ if (INT_OVERFLOW (Symbolic->dnum_mem_init_usage * sizeof (Unit))) { /* :: int overflow, initial Numeric->Memory size :: */ /* There's no hope to allocate a Numeric object big enough simply to * hold the initial matrix, so return an out-of-memory condition */ DEBUGm4 (("out of memory: numeric int overflow\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; return (UMFPACK_ERROR_out_of_memory) ; } Info [UMFPACK_STATUS] = UMFPACK_OK ; Info [UMFPACK_NROW] = n_row ; Info [UMFPACK_NCOL] = n_col ; Info [UMFPACK_SIZE_OF_UNIT] = (double) (sizeof (Unit)) ; if (!Ap || !Ai || !Ax || !NumericHandle) { Info [UMFPACK_STATUS] = UMFPACK_ERROR_argument_missing ; return (UMFPACK_ERROR_argument_missing) ; } Info [UMFPACK_NZ] = Ap [n_col] ; *NumericHandle = (void *) NULL ; /* ---------------------------------------------------------------------- */ /* allocate the Work object */ /* ---------------------------------------------------------------------- */ /* (1) calls UMF_malloc 15 or 17 times, to obtain temporary workspace of * size c+1 Entry's and 2*(n_row+1) + 3*(n_col+1) + (n_col+n_inner+1) + * (nn+1) + * 3*(c+1) + 2*(r+1) + max(r,c) + (nfr+1) integers plus 2*nn * more integers if diagonal pivoting is to be done. r is the maximum * number of rows in any frontal matrix, c is the maximum number of columns * in any frontal matrix, n_inner is min (n_row,n_col), nn is * max (n_row,n_col), and nfr is the number of frontal matrices. For a * square matrix, this is c+1 Entry's and about 8n + 3c + 2r + max(r,c) + * nfr integers, plus 2n more for diagonal pivoting. */ Work = &WorkSpace ; Work->n_row = n_row ; Work->n_col = n_col ; Work->nfr = Symbolic->nfr ; Work->nb = Symbolic->nb ; Work->n1 = Symbolic->n1 ; if (!work_alloc (Work, Symbolic)) { DEBUGm4 (("out of memory: numeric work\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Numeric, Work) ; return (UMFPACK_ERROR_out_of_memory) ; } ASSERT (UMF_malloc_count == init_count + 16 + 2*Symbolic->prefer_diagonal) ; /* ---------------------------------------------------------------------- */ /* allocate Numeric object */ /* ---------------------------------------------------------------------- */ /* (2) calls UMF_malloc 10 or 11 times, for a total space of * sizeof (NumericType) bytes, 4*(n_row+1) + 4*(n_row+1) integers, and * (n_inner+1) Entry's, plus n_row Entry's if row scaling is to be done. * sizeof (NumericType) is a small constant. Next, it calls UMF_malloc * once, for the variable-sized part of the Numeric object * (Numeric->Memory). The size of this object is the larger of * (Control [UMFPACK_ALLOC_INIT]) * (the approximate upper bound computed * by UMFPACK_symbolic), and the minimum required to start the numerical * factorization. * This request is reduced if it fails. */ if (!numeric_alloc (&Numeric, Symbolic, alloc_init, scale)) { DEBUGm4 (("out of memory: initial numeric\n")) ; Info [UMFPACK_STATUS] = UMFPACK_ERROR_out_of_memory ; error (&Numeric, Work) ; return (UMFPACK_ERROR_out_of_memory) ; } DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n", init_count, UMF_malloc_count)) ; ASSERT (UMF_malloc_count == init_count + (16 + 2*Symbolic->prefer_diagonal) + (11 + (scale != UMFPACK_SCALE_NONE))) ; /* set control parameters */ Numeric->relpt = relpt ; Numeric->relpt2 = relpt2 ; Numeric->droptol = droptol ; Numeric->alloc_init = alloc_init ; Numeric->front_alloc_init = front_alloc_init ; Numeric->scale = scale ; DEBUG0 (("umf relpt %g %g init %g %g inc %g red %g\n", relpt, relpt2, alloc_init, front_alloc_init, UMF_REALLOC_INCREASE, UMF_REALLOC_REDUCTION)) ; /* ---------------------------------------------------------------------- */ /* scale and factorize */ /* ---------------------------------------------------------------------- */ /* (3) During numerical factorization (inside UMF_kernel), the variable-size * block of memory is increased in size via a call to UMF_realloc if it is * found to be too small. During factorization, this block holds the * pattern and values of L and U at the top end, and the elements * (contibution blocks) and the current frontal matrix (Work->F*) at the * bottom end. The peak size of the variable-sized object is estimated in * UMFPACK_*symbolic (Info [UMFPACK_VARIABLE_PEAK_ESTIMATE]), although this * upper bound can be very loose. The size of the Symbolic object * (which is currently allocated) is in Info [UMFPACK_SYMBOLIC_SIZE], and * is between 2*n and 13*n integers. */ DEBUG0 (("Calling umf_kernel\n")) ; status = UMF_kernel (Ap, Ai, Ax, #ifdef COMPLEX Az, #endif Numeric, Work, Symbolic) ; Info [UMFPACK_STATUS] = status ; if (status < UMFPACK_OK) { /* out of memory, or pattern has changed */ error (&Numeric, Work) ; return (status) ; } Info [UMFPACK_FORCED_UPDATES] = Work->nforced ; Info [UMFPACK_VARIABLE_INIT] = Numeric->init_usage ; if (Symbolic->prefer_diagonal) { Info [UMFPACK_NOFF_DIAG] = Work->noff_diagonal ; } DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n", init_count, UMF_malloc_count)) ; npiv = Numeric->npiv ; /* = n_inner for nonsingular matrices */ ulen = Numeric->ulen ; /* = 0 for square nonsingular matrices */ /* ---------------------------------------------------------------------- */ /* free Work object */ /* ---------------------------------------------------------------------- */ /* (4) After numerical factorization all of the objects allocated in step * (1) are freed via UMF_free, except that one object of size n_col+1 is * kept if there are off-diagonal nonzeros in the last pivot row (can only * occur for singular or rectangular matrices). This is Work->Upattern, * which is transfered to Numeric->Upattern if ulen > 0. */ DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n", init_count, UMF_malloc_count)) ; free_work (Work) ; DEBUG0 (("malloc: init_count "ID" UMF_malloc_count "ID"\n", init_count, UMF_malloc_count)) ; DEBUG0 (("Numeric->ulen: "ID" scale: "ID"\n", ulen, scale)) ; ASSERT (UMF_malloc_count == init_count + (ulen > 0) + (11 + (scale != UMFPACK_SCALE_NONE))) ; /* ---------------------------------------------------------------------- */ /* reduce Lpos, Lilen, Lip, Upos, Uilen and Uip to size npiv+1 */ /* ---------------------------------------------------------------------- */ /* (5) Six components of the Numeric object are reduced in size if the * matrix is singular or rectangular. The original size is 3*(n_row+1) + * 3*(n_col+1) integers. The new size is 6*(npiv+1) integers. For * square non-singular matrices, these two sizes are the same. */ if (npiv < n_row) { /* reduce Lpos, Uilen, and Uip from size n_row+1 to size npiv */ inew = (Int *) UMF_realloc (Numeric->Lpos, npiv+1, sizeof (Int)) ; if (inew) { Numeric->Lpos = inew ; } inew = (Int *) UMF_realloc (Numeric->Uilen, npiv+1, sizeof (Int)) ; if (inew) { Numeric->Uilen = inew ; } inew = (Int *) UMF_realloc (Numeric->Uip, npiv+1, sizeof (Int)) ; if (inew) { Numeric->Uip = inew ; } } if (npiv < n_col) { /* reduce Upos, Lilen, and Lip from size n_col+1 to size npiv */ inew = (Int *) UMF_realloc (Numeric->Upos, npiv+1, sizeof (Int)) ; if (inew) { Numeric->Upos = inew ; } inew = (Int *) UMF_realloc (Numeric->Lilen, npiv+1, sizeof (Int)) ; if (inew) { Numeric->Lilen = inew ; } inew = (Int *) UMF_realloc (Numeric->Lip, npiv+1, sizeof (Int)) ; if (inew) { Numeric->Lip = inew ; } } /* ---------------------------------------------------------------------- */ /* reduce Numeric->Upattern from size n_col+1 to size ulen+1 */ /* ---------------------------------------------------------------------- */ /* (6) The size of Numeric->Upattern (formerly Work->Upattern) is reduced * from size n_col+1 to size ulen + 1. If ulen is zero, the object does * not exist. */ DEBUG4 (("ulen: "ID" Upattern "ID"\n", ulen, (Int) Numeric->Upattern)) ; ASSERT (IMPLIES (ulen == 0, Numeric->Upattern == (Int *) NULL)) ; if (ulen > 0 && ulen < n_col) { inew = (Int *) UMF_realloc (Numeric->Upattern, ulen+1, sizeof (Int)) ; if (inew) { Numeric->Upattern = inew ; } } /* ---------------------------------------------------------------------- */ /* reduce Numeric->Memory to hold just the LU factors at the head */ /* ---------------------------------------------------------------------- */ /* (7) The variable-sized block (Numeric->Memory) is reduced to hold just L * and U, via a call to UMF_realloc, since the frontal matrices are no * longer needed. */ newsize = Numeric->ihead ; if (newsize < Numeric->size) { mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ; if (mnew) { /* realloc succeeded (how can it fail since the size is reduced?) */ Numeric->Memory = mnew ; Numeric->size = newsize ; } } Numeric->ihead = Numeric->size ; Numeric->itail = Numeric->ihead ; Numeric->tail_usage = 0 ; Numeric->ibig = EMPTY ; /* UMF_mem_alloc_tail_block can no longer be called (no tail marker) */ /* ---------------------------------------------------------------------- */ /* report the results and return the Numeric object */ /* ---------------------------------------------------------------------- */ UMF_set_stats ( Info, Symbolic, (double) Numeric->max_usage, /* actual peak Numeric->Memory */ (double) Numeric->size, /* actual final Numeric->Memory */ Numeric->flops, /* actual "true flops" */ (double) Numeric->lnz + n_inner, /* actual nz in L */ (double) Numeric->unz + Numeric->nnzpiv, /* actual nz in U */ (double) Numeric->maxfrsize, /* actual largest front size */ (double) ulen, /* actual Numeric->Upattern size */ (double) npiv, /* actual # pivots found */ (double) Numeric->maxnrows, /* actual largest #rows in front */ (double) Numeric->maxncols, /* actual largest #cols in front */ scale != UMFPACK_SCALE_NONE, Symbolic->prefer_diagonal, ACTUAL) ; Info [UMFPACK_ALLOC_INIT_USED] = Numeric->alloc_init ; Info [UMFPACK_NUMERIC_DEFRAG] = Numeric->ngarbage ; Info [UMFPACK_NUMERIC_REALLOC] = Numeric->nrealloc ; Info [UMFPACK_NUMERIC_COSTLY_REALLOC] = Numeric->ncostly ; Info [UMFPACK_COMPRESSED_PATTERN] = Numeric->isize ; Info [UMFPACK_LU_ENTRIES] = Numeric->nLentries + Numeric->nUentries + Numeric->npiv ; Info [UMFPACK_UDIAG_NZ] = Numeric->nnzpiv ; Info [UMFPACK_RSMIN] = Numeric->rsmin ; Info [UMFPACK_RSMAX] = Numeric->rsmax ; Info [UMFPACK_WAS_SCALED] = Numeric->scale ; /* nz in L and U with no dropping of small entries */ Info [UMFPACK_ALL_LNZ] = Numeric->all_lnz + n_inner ; Info [UMFPACK_ALL_UNZ] = Numeric->all_unz + Numeric->nnzpiv ; Info [UMFPACK_NZDROPPED] = (Numeric->all_lnz - Numeric->lnz) + (Numeric->all_unz - Numeric->unz) ; /* estimate of the reciprocal of the condition number. */ if (SCALAR_IS_ZERO (Numeric->min_udiag) || SCALAR_IS_ZERO (Numeric->max_udiag) || SCALAR_IS_NAN (Numeric->min_udiag) || SCALAR_IS_NAN (Numeric->max_udiag)) { /* rcond is zero if there is any zero or NaN on the diagonal */ Numeric->rcond = 0.0 ; } else { /* estimate of the recipricol of the condition number. */ /* This is NaN if diagonal is zero-free, but has one or more NaN's. */ Numeric->rcond = Numeric->min_udiag / Numeric->max_udiag ; } Info [UMFPACK_UMIN] = Numeric->min_udiag ; Info [UMFPACK_UMAX] = Numeric->max_udiag ; Info [UMFPACK_RCOND] = Numeric->rcond ; if (Numeric->nnzpiv < n_inner || SCALAR_IS_ZERO (Numeric->rcond) || SCALAR_IS_NAN (Numeric->rcond)) { /* there are zeros and/or NaN's on the diagonal of U */ DEBUG0 (("Warning, matrix is singular in umfpack_numeric\n")) ; DEBUG0 (("nnzpiv "ID" n_inner "ID" rcond %g\n", Numeric->nnzpiv, n_inner, Numeric->rcond)) ; status = UMFPACK_WARNING_singular_matrix ; Info [UMFPACK_STATUS] = status ; } Numeric->valid = NUMERIC_VALID ; *NumericHandle = (void *) Numeric ; /* Numeric has 11 to 13 objects */ ASSERT (UMF_malloc_count == init_count + 11 + + (ulen > 0) /* Numeric->Upattern */ + (scale != UMFPACK_SCALE_NONE)) ; /* Numeric->Rs */ /* ---------------------------------------------------------------------- */ /* get the time used by UMFPACK_numeric */ /* ---------------------------------------------------------------------- */ umfpack_toc (stats) ; Info [UMFPACK_NUMERIC_WALLTIME] = stats [0] ; Info [UMFPACK_NUMERIC_TIME] = stats [1] ; /* return UMFPACK_OK or UMFPACK_WARNING_singular_matrix */ return (status) ; } /* ========================================================================== */ /* === numeric_alloc ======================================================== */ /* ========================================================================== */ /* Allocate the Numeric object */ PRIVATE Int numeric_alloc ( NumericType **NumericHandle, SymbolicType *Symbolic, double alloc_init, Int scale ) { double nsize, bsize ; Int n_row, n_col, n_inner, min_usage, trying ; NumericType *Numeric ; DEBUG0 (("numeric alloc:\n")) ; n_row = Symbolic->n_row ; n_col = Symbolic->n_col ; n_inner = MIN (n_row, n_col) ; *NumericHandle = (NumericType *) NULL ; /* 1 allocation: accounted for in UMF_set_stats (num_On_size1), * free'd in umfpack_free_numeric */ Numeric = (NumericType *) UMF_malloc (1, sizeof (NumericType)) ; if (!Numeric) { return (FALSE) ; /* out of memory */ } Numeric->valid = 0 ; *NumericHandle = Numeric ; /* 9 allocations: accounted for in UMF_set_stats (num_On_size1), * free'd in umfpack_free_numeric */ Numeric->D = (Entry *) UMF_malloc (n_inner+1, sizeof (Entry)) ; Numeric->Rperm = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ; Numeric->Cperm = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ; Numeric->Lpos = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ; Numeric->Lilen = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ; Numeric->Lip = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ; Numeric->Upos = (Int *) UMF_malloc (n_col+1, sizeof (Int)) ; Numeric->Uilen = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ; Numeric->Uip = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ; /* 1 allocation if scaling: in UMF_set_stats (num_On_size1), * free'd in umfpack_free_numeric */ if (scale != UMFPACK_SCALE_NONE) { DEBUG0 (("Allocating scale factors\n")) ; Numeric->Rs = (double *) UMF_malloc (n_row, sizeof (double)) ; } else { DEBUG0 (("No scale factors allocated (R = I)\n")) ; Numeric->Rs = (double *) NULL ; } Numeric->Memory = (Unit *) NULL ; /* Upattern has already been allocated as part of the Work object. If * the matrix is singular or rectangular, and there are off-diagonal * nonzeros in the last pivot row, then Work->Upattern is not free'd. * Instead it is transfered to Numeric->Upattern. If it exists, * Numeric->Upattern is free'd in umfpack_free_numeric. */ Numeric->Upattern = (Int *) NULL ; /* used for singular matrices only */ if (!Numeric->D || !Numeric->Rperm || !Numeric->Cperm || !Numeric->Upos || !Numeric->Lpos || !Numeric->Lilen || !Numeric->Uilen || !Numeric->Lip || !Numeric->Uip || (scale != UMFPACK_SCALE_NONE && !Numeric->Rs)) { return (FALSE) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* allocate initial Numeric->Memory for LU factors and elements */ /* ---------------------------------------------------------------------- */ if (alloc_init < 0) { /* -alloc_init is the exact size to initially allocate */ nsize = -alloc_init ; } else { /* alloc_init is a ratio of the upper bound memory usage */ nsize = (alloc_init * Symbolic->num_mem_usage_est) + 1 ; } min_usage = Symbolic->num_mem_init_usage ; /* Numeric->Memory must be large enough for UMF_kernel_init */ nsize = MAX (min_usage, nsize) ; /* Numeric->Memory cannot be larger in size than Int_MAX / sizeof(Unit) */ /* For ILP32 mode: 2GB (nsize cannot be bigger than 256 Mwords) */ bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ; DEBUG0 (("bsize %g\n", bsize)) ; nsize = MIN (nsize, bsize) ; Numeric->size = (Int) nsize ; DEBUG0 (("Num init %g usage_est %g numsize "ID" minusage "ID"\n", alloc_init, Symbolic->num_mem_usage_est, Numeric->size, min_usage)) ; /* allocates 1 object: */ /* keep trying until successful, or memory request is too small */ trying = TRUE ; while (trying) { Numeric->Memory = (Unit *) UMF_malloc (Numeric->size, sizeof (Unit)) ; if (Numeric->Memory) { DEBUG0 (("Successful Numeric->size: "ID"\n", Numeric->size)) ; return (TRUE) ; } /* too much, reduce the request (but not below the minimum) */ /* and try again */ trying = Numeric->size > min_usage ; Numeric->size = (Int) (UMF_REALLOC_REDUCTION * ((double) Numeric->size)) ; Numeric->size = MAX (min_usage, Numeric->size) ; } return (FALSE) ; /* we failed to allocate Numeric->Memory */ } /* ========================================================================== */ /* === work_alloc =========================================================== */ /* ========================================================================== */ /* Allocate the Work object. Return TRUE if successful. */ PRIVATE Int work_alloc ( WorkType *Work, SymbolicType *Symbolic ) { Int n_row, n_col, nn, maxnrows, maxncols, nfr, ok, maxnrc, n1 ; n_row = Work->n_row ; n_col = Work->n_col ; nn = MAX (n_row, n_col) ; nfr = Work->nfr ; n1 = Symbolic->n1 ; ASSERT (n1 <= n_row && n1 <= n_col) ; maxnrows = Symbolic->maxnrows + Symbolic->nb ; maxnrows = MIN (n_row, maxnrows) ; maxncols = Symbolic->maxncols + Symbolic->nb ; maxncols = MIN (n_col, maxncols) ; maxnrc = MAX (maxnrows, maxncols) ; DEBUG0 (("work alloc: maxnrows+nb "ID" maxncols+nb "ID"\n", maxnrows, maxncols)) ; /* 15 allocations, freed in free_work: */ /* accounted for in UMF_set_stats (work_usage) */ Work->Wx = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ; Work->Wy = (Entry *) UMF_malloc (maxnrows + 1, sizeof (Entry)) ; Work->Frpos = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ; Work->Lpattern = (Int *) UMF_malloc (n_row + 1, sizeof (Int)) ; Work->Fcpos = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ; Work->Wp = (Int *) UMF_malloc (nn + 1, sizeof (Int)) ; Work->Wrp = (Int *) UMF_malloc (MAX (n_col,maxnrows) + 1, sizeof (Int)) ; Work->Frows = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ; Work->Wm = (Int *) UMF_malloc (maxnrows + 1, sizeof (Int)) ; Work->Fcols = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ; Work->Wio = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ; Work->Woi = (Int *) UMF_malloc (maxncols + 1, sizeof (Int)) ; Work->Woo = (Int *) UMF_malloc (maxnrc + 1, sizeof (Int)); Work->elen = (n_col - n1) + (n_row - n1) + MIN (n_col-n1, n_row-n1) + 1 ; Work->E = (Int *) UMF_malloc (Work->elen, sizeof (Int)) ; Work->Front_new1strow = (Int *) UMF_malloc (nfr + 1, sizeof (Int)) ; ok = (Work->Frpos && Work->Fcpos && Work->Lpattern && Work->Wp && Work->Wrp && Work->Frows && Work->Fcols && Work->Wio && Work->Woi && Work->Woo && Work->Wm && Work->E && Work->Front_new1strow && Work->Wx && Work->Wy) ; /* 2 allocations: accounted for in UMF_set_stats (work_usage) */ if (Symbolic->prefer_diagonal) { Work->Diagonal_map = (Int *) UMF_malloc (nn, sizeof (Int)) ; Work->Diagonal_imap = (Int *) UMF_malloc (nn, sizeof (Int)) ; ok = ok && Work->Diagonal_map && Work->Diagonal_imap ; } else { /* no diagonal map needed for rectangular matrices */ Work->Diagonal_map = (Int *) NULL ; Work->Diagonal_imap = (Int *) NULL ; } /* 1 allocation, may become part of Numeric (if singular or rectangular): */ Work->Upattern = (Int *) UMF_malloc (n_col + 1, sizeof (Int)) ; ok = ok && Work->Upattern ; /* current frontal matrix does not yet exist */ Work->Flublock = (Entry *) NULL ; Work->Flblock = (Entry *) NULL ; Work->Fublock = (Entry *) NULL ; Work->Fcblock = (Entry *) NULL ; DEBUG0 (("work alloc done.\n")) ; return (ok) ; } /* ========================================================================== */ /* === free_work ============================================================ */ /* ========================================================================== */ PRIVATE void free_work ( WorkType *Work ) { DEBUG0 (("work free:\n")) ; if (Work) { /* these 16 objects do exist */ Work->Wx = (Entry *) UMF_free ((void *) Work->Wx) ; Work->Wy = (Entry *) UMF_free ((void *) Work->Wy) ; Work->Frpos = (Int *) UMF_free ((void *) Work->Frpos) ; Work->Fcpos = (Int *) UMF_free ((void *) Work->Fcpos) ; Work->Lpattern = (Int *) UMF_free ((void *) Work->Lpattern) ; Work->Upattern = (Int *) UMF_free ((void *) Work->Upattern) ; Work->Wp = (Int *) UMF_free ((void *) Work->Wp) ; Work->Wrp = (Int *) UMF_free ((void *) Work->Wrp) ; Work->Frows = (Int *) UMF_free ((void *) Work->Frows) ; Work->Fcols = (Int *) UMF_free ((void *) Work->Fcols) ; Work->Wio = (Int *) UMF_free ((void *) Work->Wio) ; Work->Woi = (Int *) UMF_free ((void *) Work->Woi) ; Work->Woo = (Int *) UMF_free ((void *) Work->Woo) ; Work->Wm = (Int *) UMF_free ((void *) Work->Wm) ; Work->E = (Int *) UMF_free ((void *) Work->E) ; Work->Front_new1strow = (Int *) UMF_free ((void *) Work->Front_new1strow) ; /* these objects might not exist */ Work->Diagonal_map = (Int *) UMF_free ((void *) Work->Diagonal_map) ; Work->Diagonal_imap = (Int *) UMF_free ((void *) Work->Diagonal_imap) ; } DEBUG0 (("work free done.\n")) ; } /* ========================================================================== */ /* === error ================================================================ */ /* ========================================================================== */ /* Error return from UMFPACK_numeric. Free all allocated memory. */ PRIVATE void error ( NumericType **Numeric, WorkType *Work ) { free_work (Work) ; UMFPACK_free_numeric ((void **) Numeric) ; ASSERT (UMF_malloc_count == init_count) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_build_tuples.h0000644000175000017500000000074511674452555023373 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_build_tuples ( NumericType *Numeric, WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_lunz.c0000644000175000017500000000317011674452555023354 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_get_lunz ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Determines the number of nonzeros in L and U, and the size of L and U. */ #include "umf_internal.h" #include "umf_valid_numeric.h" GLOBAL Int UMFPACK_get_lunz ( Int *lnz, Int *unz, Int *n_row, Int *n_col, Int *nz_udiag, void *NumericHandle ) { NumericType *Numeric ; Numeric = (NumericType *) NumericHandle ; if (!UMF_valid_numeric (Numeric)) { return (UMFPACK_ERROR_invalid_Numeric_object) ; } if (!lnz || !unz || !n_row || !n_col || !nz_udiag) { return (UMFPACK_ERROR_argument_missing) ; } *n_row = Numeric->n_row ; *n_col = Numeric->n_col ; /* number of nz's in L below diagonal, plus the unit diagonal of L */ *lnz = Numeric->lnz + MIN (Numeric->n_row, Numeric->n_col) ; /* number of nz's in U above diagonal, plus nz's on diagaonal of U */ *unz = Numeric->unz + Numeric->nnzpiv ; /* number of nz's on the diagonal */ *nz_udiag = Numeric->nnzpiv ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_vector.c0000644000175000017500000000231711674452555024424 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_vector ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints a real or complex vector. See umfpack_report_vector.h for details. */ #include "umf_internal.h" #include "umf_report_vector.h" GLOBAL Int UMFPACK_report_vector ( Int n, const double Xx [ ], #ifdef COMPLEX const double Xz [ ], #endif const double Control [UMFPACK_CONTROL] ) { Int prl ; #ifndef COMPLEX double *Xz = (double *) NULL ; #endif prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl <= 2) { return (UMFPACK_OK) ; } return (UMF_report_vector (n, Xx, Xz, prl, TRUE, FALSE)) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.h0000644000175000017500000000075111674452555024760 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_mem_alloc_head_block ( NumericType *Numeric, Int nunits ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_get_memory.c0000644000175000017500000001615211674452555023041 0ustar sonnesonne/* ========================================================================== */ /* === UMF_get_memory ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Reallocate the workspace (Numeric->Memory) and shift elements downwards. needunits: increase in size so that the free space is at least this many Units (to which the tuple lengths is added). Return TRUE if successful, FALSE if out of memory. */ #include "umf_internal.h" #include "umf_get_memory.h" #include "umf_garbage_collection.h" #include "umf_tuple_lengths.h" #include "umf_build_tuples.h" #include "umf_mem_free_tail_block.h" #include "umf_realloc.h" GLOBAL Int UMF_get_memory ( NumericType *Numeric, WorkType *Work, Int needunits, Int r2, /* compact current front to r2-by-c2 */ Int c2, Int do_Fcpos ) { double nsize, bsize, tsize ; Int i, minsize, newsize, newmem, costly, row, col, *Row_tlen, *Col_tlen, n_row, n_col, *Row_degree, *Col_degree ; Unit *mnew, *p ; /* ---------------------------------------------------------------------- */ /* get and check parameters */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG DEBUG1 (("::::GET MEMORY::::\n")) ; UMF_dump_memory (Numeric) ; #endif n_row = Work->n_row ; n_col = Work->n_col ; Row_degree = Numeric->Rperm ; /* for NON_PIVOTAL_ROW macro */ Col_degree = Numeric->Cperm ; /* for NON_PIVOTAL_COL macro */ Row_tlen = Numeric->Uilen ; Col_tlen = Numeric->Lilen ; /* ---------------------------------------------------------------------- */ /* initialize the tuple list lengths */ /* ---------------------------------------------------------------------- */ for (row = 0 ; row < n_row ; row++) { if (NON_PIVOTAL_ROW (row)) { Row_tlen [row] = 0 ; } } for (col = 0 ; col < n_col ; col++) { if (NON_PIVOTAL_COL (col)) { Col_tlen [col] = 0 ; } } /* ---------------------------------------------------------------------- */ /* determine how much memory is needed for the tuples */ /* ---------------------------------------------------------------------- */ nsize = (double) needunits + 2 ; needunits += UMF_tuple_lengths (Numeric, Work, &tsize) ; nsize += tsize ; needunits += 2 ; /* add 2, so that newmem >= 2 is true if realloc'd */ /* note: Col_tlen and Row_tlen are updated, but the tuple lists */ /* themselves are not. Do not attempt to scan the tuple lists. */ /* They are now stale, and are about to be destroyed and recreated. */ /* ---------------------------------------------------------------------- */ /* determine the desired new size of memory */ /* ---------------------------------------------------------------------- */ DEBUG0 (("UMF_get_memory: needunits: "ID"\n", needunits)) ; minsize = Numeric->size + needunits ; nsize += (double) Numeric->size ; bsize = ((double) Int_MAX) / sizeof (Unit) - 1 ; newsize = (Int) (UMF_REALLOC_INCREASE * ((double) minsize)) ; nsize *= UMF_REALLOC_INCREASE ; nsize += 1 ; if (newsize < 0 || nsize > bsize) { /* :: realloc Numeric->Memory int overflow :: */ DEBUGm3 (("Realloc hit integer limit\n")) ; newsize = (Int) bsize ; /* we cannot increase the size beyond bsize */ } else { ASSERT (newsize <= nsize) ; newsize = MAX (newsize, minsize) ; } newsize = MAX (newsize, Numeric->size) ; DEBUG0 (( "REALLOC MEMORY: needunits "ID" old size: "ID" new size: "ID" Units \n", needunits, Numeric->size, newsize)) ; /* Forget where the biggest free block is (we no longer need it) */ /* since garbage collection will occur shortly. */ Numeric->ibig = EMPTY ; DEBUG0 (("Before realloc E [0] "ID"\n", Work->E [0])) ; /* ---------------------------------------------------------------------- */ /* reallocate the memory, if possible, and make it bigger */ /* ---------------------------------------------------------------------- */ mnew = (Unit *) NULL ; while (!mnew) { mnew = (Unit *) UMF_realloc (Numeric->Memory, newsize, sizeof (Unit)) ; if (!mnew) { if (newsize == minsize) /* last realloc attempt failed */ { /* We failed to get the minimum. Just stick with the */ /* current allocation and hope that garbage collection */ /* can recover enough space. */ mnew = Numeric->Memory ; /* no new memory available */ newsize = Numeric->size ; } else { /* otherwise, reduce the request and keep trying */ newsize = (Int) (UMF_REALLOC_REDUCTION * ((double) newsize)) ; newsize = MAX (minsize, newsize) ; } } } ASSERT (mnew != (Unit *) NULL) ; /* see if realloc had to copy, rather than just extend memory */ costly = (mnew != Numeric->Memory) ; /* ---------------------------------------------------------------------- */ /* extend the tail portion of memory downwards */ /* ---------------------------------------------------------------------- */ Numeric->Memory = mnew ; if (Work->E [0]) { Int nb, dr, dc ; nb = Work->nb ; dr = Work->fnr_curr ; dc = Work->fnc_curr ; Work->Flublock = (Entry *) (Numeric->Memory + Work->E [0]) ; Work->Flblock = Work->Flublock + nb * nb ; Work->Fublock = Work->Flblock + dr * nb ; Work->Fcblock = Work->Fublock + nb * dc ; DEBUG0 (("after realloc E [0] "ID"\n", Work->E [0])) ; } ASSERT (IMPLIES (!(Work->E [0]), Work->Flublock == (Entry *) NULL)) ; newmem = newsize - Numeric->size ; ASSERT (newmem == 0 || newmem >= 2) ; if (newmem >= 2) { /* reallocation succeeded */ /* point to the old tail marker block of size 1 + header */ p = Numeric->Memory + Numeric->size - 2 ; /* create a new block out of the newly extended memory */ p->header.size = newmem - 1 ; i = Numeric->size - 1 ; p += newmem ; /* create a new tail marker block */ p->header.prevsize = newmem - 1 ; p->header.size = 1 ; Numeric->size = newsize ; /* free the new block */ UMF_mem_free_tail_block (Numeric, i) ; Numeric->nrealloc++ ; if (costly) { Numeric->ncostly++ ; } } DEBUG1 (("Done with realloc memory\n")) ; /* ---------------------------------------------------------------------- */ /* garbage collection on the tail of Numeric->memory (destroys tuples) */ /* ---------------------------------------------------------------------- */ UMF_garbage_collection (Numeric, Work, r2, c2, do_Fcpos) ; /* ---------------------------------------------------------------------- */ /* rebuild the tuples */ /* ---------------------------------------------------------------------- */ return (UMF_build_tuples (Numeric, Work)) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_triplet_to_col.c0000644000175000017500000001465011674452555024554 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_triplet_to_col =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User callable. Converts triplet input to column-oriented form. Duplicate entries may exist (they are summed in the output). The columns of the column-oriented form are in sorted order. The input is not modified. Returns 1 if OK, 0 if an error occurred. See umfpack_triplet_to_col.h for details. If Map is present (a non-NULL pointer to an Int array of size nz), then on output it holds the position of the triplets in the column-form matrix. That is, suppose p = Map [k], and the k-th triplet is i=Ti[k], j=Tj[k], and aij=Tx[k]. Then i=Ai[p], and aij will have been summed into Ax[p]. Also, Ap[j] <= p < Ap[j+1]. The Map array is not computed if it is (Int *) NULL. Dynamic memory usage: If numerical values are present, then one (two for complex version) workspace of size (nz+1)*sizeof(double) is allocated via UMF_malloc. Next, 4 calls to UMF_malloc are made to obtain workspace of size ((nz+1) + (n_row+1) + n_row + MAX (n_row,n_col)) * sizeof(Int). All of this workspace (4 to 6 objects) are free'd via UMF_free on return. For the complex version, additional space is allocated. An extra array of size nz*sizeof(Int) is allocated if Map is present. */ #include "umf_internal.h" #include "umf_malloc.h" #include "umf_free.h" #include "umf_triplet.h" #ifndef NDEBUG PRIVATE Int init_count ; #endif /* ========================================================================== */ GLOBAL Int UMFPACK_triplet_to_col ( Int n_row, Int n_col, Int nz, const Int Ti [ ], /* size nz */ const Int Tj [ ], /* size nz */ const double Tx [ ], /* size nz */ #ifdef COMPLEX const double Tz [ ], /* size nz */ #endif Int Ap [ ], /* size n_col + 1 */ Int Ai [ ], /* size nz */ double Ax [ ] /* size nz */ #ifdef COMPLEX , double Az [ ] /* size nz */ #endif , Int Map [ ] /* size nz */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int *RowCount, *Rp, *Rj, *W, nn, do_values, do_map, *Map2, status ; double *Rx ; #ifdef COMPLEX double *Rz ; Int split ; #endif #ifndef NDEBUG UMF_dump_start ( ) ; init_count = UMF_malloc_count ; #endif /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ if (!Ai || !Ap || !Ti || !Tj) { return (UMFPACK_ERROR_argument_missing) ; } if (n_row <= 0 || n_col <= 0) /* must be > 0 */ { return (UMFPACK_ERROR_n_nonpositive) ; } if (nz < 0) /* nz must be >= 0 (singular matrices are OK) */ { return (UMFPACK_ERROR_invalid_matrix) ; } nn = MAX (n_row, n_col) ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ Rx = (double *) NULL ; do_values = Ax && Tx ; if (do_values) { #ifdef COMPLEX Rx = (double *) UMF_malloc (2*nz+2, sizeof (double)) ; split = SPLIT (Tz) && SPLIT (Az) ; if (split) { Rz = Rx + nz ; } else { Rz = (double *) NULL ; } #else Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ; #endif if (!Rx) { DEBUGm4 (("out of memory: triplet work \n")) ; ASSERT (UMF_malloc_count == init_count) ; return (UMFPACK_ERROR_out_of_memory) ; } } do_map = (Map != (Int *) NULL) ; Map2 = (Int *) NULL ; if (do_map) { DEBUG0 (("Do map:\n")) ; Map2 = (Int *) UMF_malloc (nz+1, sizeof (Int)) ; if (!Map2) { DEBUGm4 (("out of memory: triplet map\n")) ; (void) UMF_free ((void *) Rx) ; ASSERT (UMF_malloc_count == init_count) ; return (UMFPACK_ERROR_out_of_memory) ; } } Rj = (Int *) UMF_malloc (nz+1, sizeof (Int)) ; Rp = (Int *) UMF_malloc (n_row+1, sizeof (Int)) ; RowCount = (Int *) UMF_malloc (n_row, sizeof (Int)) ; W = (Int *) UMF_malloc (nn, sizeof (Int)) ; if (!Rj || !Rp || !RowCount || !W) { DEBUGm4 (("out of memory: triplet work (int)\n")) ; (void) UMF_free ((void *) Rx) ; (void) UMF_free ((void *) Map2) ; (void) UMF_free ((void *) Rp) ; (void) UMF_free ((void *) Rj) ; (void) UMF_free ((void *) RowCount) ; (void) UMF_free ((void *) W) ; ASSERT (UMF_malloc_count == init_count) ; return (UMFPACK_ERROR_out_of_memory) ; } ASSERT (UMF_malloc_count == init_count + 4 + (Rx != (double *) NULL) + do_map) ; /* ---------------------------------------------------------------------- */ /* convert from triplet to column form */ /* ---------------------------------------------------------------------- */ if (do_map) { if (do_values) { status = UMF_triplet_map_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp, Rj, W, RowCount, Tx, Ax, Rx #ifdef COMPLEX , Tz, Az, Rz #endif , Map, Map2) ; } else { status = UMF_triplet_map_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp, Rj, W, RowCount, Map, Map2) ; } } else { if (do_values) { status = UMF_triplet_nomap_x (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp, Rj, W, RowCount , Tx, Ax, Rx #ifdef COMPLEX , Tz, Az, Rz #endif ) ; } else { status = UMF_triplet_nomap_nox (n_row, n_col, nz, Ti, Tj, Ap, Ai, Rp, Rj, W, RowCount) ; } } /* ---------------------------------------------------------------------- */ /* free the workspace */ /* ---------------------------------------------------------------------- */ (void) UMF_free ((void *) Rx) ; (void) UMF_free ((void *) Map2) ; (void) UMF_free ((void *) Rp) ; (void) UMF_free ((void *) Rj) ; (void) UMF_free ((void *) RowCount) ; (void) UMF_free ((void *) W) ; ASSERT (UMF_malloc_count == init_count) ; return (status) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_singletons.h0000644000175000017500000000150211674452555023055 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_singletons ( Int n_row, Int n_col, const Int Ap [ ], const Int Ai [ ], const Int Quser [ ], Int strategy, Int Cdeg [ ], Int Cperm [ ], Int Rdeg [ ], Int Rperm [ ], Int InvRperm [ ], Int *n1, Int *n1c, Int *n1r, Int *nempty_col, Int *nempty_row, Int *is_sym, Int *max_rdeg, Int Rp [ ], Int Ri [ ], Int W [ ], Int Next [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_control.c0000644000175000017500000003126711674452555024610 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_control =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints the control settings. See umfpack_report_control.h for details. */ #include "umf_internal.h" GLOBAL void UMFPACK_report_control ( const double Control [UMFPACK_CONTROL] ) { double drow, dcol, relpt, relpt2, alloc_init, front_alloc_init, amd_alpha, tol, force_fixQ, droptol, aggr ; Int prl, nb, irstep, strategy, scale, s ; prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl < 2) { /* default is to print nothing */ return ; } PRINTF (("UMFPACK V%d.%d.%d (%s), Control:\n", UMFPACK_MAIN_VERSION, UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE)) ; /* ---------------------------------------------------------------------- */ /* run-time options */ /* ---------------------------------------------------------------------- */ /* This is a "run-time" option because all four umfpack_* versions */ /* compiled into the UMFPACK library. */ #ifdef DINT PRINTF ((" Matrix entry defined as: double\n")) ; PRINTF ((" Int (generic integer) defined as: int\n")) ; #endif #ifdef DLONG PRINTF ((" Matrix entry defined as: double\n")) ; PRINTF ((" Int (generic integer) defined as: UF_long\n")) ; #endif #ifdef ZINT PRINTF ((" Matrix entry defined as: double complex\n")) ; PRINTF ((" Int (generic integer) defined as: int\n")) ; #endif #ifdef ZLONG PRINTF ((" Matrix entry defined as: double complex\n")) ; PRINTF ((" Int (generic integer) defined as: UF_long\n")) ; #endif /* ---------------------------------------------------------------------- */ /* printing level */ /* ---------------------------------------------------------------------- */ PRINTF (("\n "ID": print level: "ID"\n", (Int) INDEX (UMFPACK_PRL), prl)) ; /* ---------------------------------------------------------------------- */ /* dense row/col parameters */ /* ---------------------------------------------------------------------- */ drow = GET_CONTROL (UMFPACK_DENSE_ROW, UMFPACK_DEFAULT_DENSE_ROW) ; dcol = GET_CONTROL (UMFPACK_DENSE_COL, UMFPACK_DEFAULT_DENSE_COL) ; PRINTF ((" "ID": dense row parameter: %g\n", (Int) INDEX (UMFPACK_DENSE_ROW), drow)) ; PRINTF ((" \"dense\" rows have > max (16, (%g)*16*sqrt(n_col)" " entries)\n", drow)) ; PRINTF ((" "ID": dense column parameter: %g\n", (Int) INDEX (UMFPACK_DENSE_COL), dcol)) ; PRINTF ((" \"dense\" columns have > max (16, (%g)*16*sqrt(n_row)" " entries)\n", dcol)) ; /* ---------------------------------------------------------------------- */ /* pivot tolerance */ /* ---------------------------------------------------------------------- */ relpt = GET_CONTROL (UMFPACK_PIVOT_TOLERANCE, UMFPACK_DEFAULT_PIVOT_TOLERANCE) ; relpt = MAX (0.0, MIN (relpt, 1.0)) ; PRINTF ((" "ID": pivot tolerance: %g\n", (Int) INDEX (UMFPACK_PIVOT_TOLERANCE), relpt)) ; /* ---------------------------------------------------------------------- */ /* block size */ /* ---------------------------------------------------------------------- */ nb = GET_CONTROL (UMFPACK_BLOCK_SIZE, UMFPACK_DEFAULT_BLOCK_SIZE) ; nb = MAX (1, nb) ; PRINTF ((" "ID": block size for dense matrix kernels: "ID"\n", (Int) INDEX (UMFPACK_BLOCK_SIZE), nb)) ; /* ---------------------------------------------------------------------- */ /* strategy */ /* ---------------------------------------------------------------------- */ strategy = GET_CONTROL (UMFPACK_STRATEGY, UMFPACK_DEFAULT_STRATEGY) ; if (strategy < UMFPACK_STRATEGY_AUTO || strategy > UMFPACK_STRATEGY_SYMMETRIC) { strategy = UMFPACK_STRATEGY_AUTO ; } PRINTF ((" "ID": strategy: "ID, (Int) INDEX (UMFPACK_STRATEGY), strategy)) ; if (strategy == UMFPACK_STRATEGY_SYMMETRIC) { PRINTF ((" (symmetric)\n" " Q = AMD (A+A'), Q not refined during numerical\n" " factorization, and diagonal pivoting (P=Q') attempted.\n")) ; } else if (strategy == UMFPACK_STRATEGY_UNSYMMETRIC) { PRINTF ((" (unsymmetric)\n" " Q = COLAMD (A), Q refined during numerical\n" " factorization, and no attempt at diagonal pivoting.\n")) ; } #if 0 else if (strategy == UMFPACK_STRATEGY_2BY2) { PRINTF ((" (symmetric, with 2-by-2 block pivoting)\n" " P2 = row permutation that tries to place large entries on\n" " the diagonal. Q = AMD (P2*A+(P2*A)'), Q not refined during\n" " numerical factorization, attempt to select pivots from the\n" " diagonal of P2*A.\n")) ; } #endif else /* auto strategy */ { strategy = UMFPACK_STRATEGY_AUTO ; PRINTF ((" (auto)\n")) ; } /* ---------------------------------------------------------------------- */ /* initial allocation parameter */ /* ---------------------------------------------------------------------- */ alloc_init = GET_CONTROL (UMFPACK_ALLOC_INIT, UMFPACK_DEFAULT_ALLOC_INIT) ; if (alloc_init >= 0) { PRINTF ((" "ID": initial allocation ratio: %g\n", (Int) INDEX (UMFPACK_ALLOC_INIT), alloc_init)) ; } else { s = -alloc_init ; s = MAX (1, s) ; PRINTF ((" "ID": initial allocation (in Units): "ID"\n", (Int) INDEX (UMFPACK_ALLOC_INIT), s)) ; } /* ---------------------------------------------------------------------- */ /* maximum iterative refinement steps */ /* ---------------------------------------------------------------------- */ irstep = GET_CONTROL (UMFPACK_IRSTEP, UMFPACK_DEFAULT_IRSTEP) ; irstep = MAX (0, irstep) ; PRINTF ((" "ID": max iterative refinement steps: "ID"\n", (Int) INDEX (UMFPACK_IRSTEP), irstep)) ; /* ---------------------------------------------------------------------- */ /* 2-by-2 pivot tolerance */ /* ---------------------------------------------------------------------- */ tol = GET_CONTROL (UMFPACK_2BY2_TOLERANCE, UMFPACK_DEFAULT_2BY2_TOLERANCE) ; tol = MAX (0.0, MIN (tol, 1.0)) ; PRINTF ((" "ID": 2-by-2 pivot tolerance: %g\n", (Int) INDEX (UMFPACK_2BY2_TOLERANCE), tol)) ; /* ---------------------------------------------------------------------- */ /* force fixQ */ /* ---------------------------------------------------------------------- */ force_fixQ = GET_CONTROL (UMFPACK_FIXQ, UMFPACK_DEFAULT_FIXQ) ; PRINTF ((" "ID": Q fixed during numerical factorization: %g ", (Int) INDEX (UMFPACK_FIXQ), force_fixQ)) ; if (force_fixQ > 0) { PRINTF (("(yes)\n")) ; } else if (force_fixQ < 0) { PRINTF (("(no)\n")) ; } else { PRINTF (("(auto)\n")) ; } /* ---------------------------------------------------------------------- */ /* AMD parameters */ /* ---------------------------------------------------------------------- */ amd_alpha = GET_CONTROL (UMFPACK_AMD_DENSE, UMFPACK_DEFAULT_AMD_DENSE) ; PRINTF ((" "ID": AMD dense row/col parameter: %g\n", (Int) INDEX (UMFPACK_AMD_DENSE), amd_alpha)) ; if (amd_alpha < 0) { PRINTF ((" no \"dense\" rows/columns\n")) ; } else { PRINTF ((" \"dense\" rows/columns have > max (16, (%g)*sqrt(n))" " entries\n", amd_alpha)) ; } PRINTF ((" Only used if the AMD ordering is used.\n")) ; /* ---------------------------------------------------------------------- */ /* pivot tolerance for symmetric pivoting */ /* ---------------------------------------------------------------------- */ relpt2 = GET_CONTROL (UMFPACK_SYM_PIVOT_TOLERANCE, UMFPACK_DEFAULT_SYM_PIVOT_TOLERANCE) ; relpt2 = MAX (0.0, MIN (relpt2, 1.0)) ; PRINTF ((" "ID": diagonal pivot tolerance: %g\n" " Only used if diagonal pivoting is attempted.\n", (Int) INDEX (UMFPACK_SYM_PIVOT_TOLERANCE), relpt2)) ; /* ---------------------------------------------------------------------- */ /* scaling */ /* ---------------------------------------------------------------------- */ scale = GET_CONTROL (UMFPACK_SCALE, UMFPACK_DEFAULT_SCALE) ; if (scale != UMFPACK_SCALE_NONE && scale != UMFPACK_SCALE_MAX) { scale = UMFPACK_DEFAULT_SCALE ; } PRINTF ((" "ID": scaling: "ID, (Int) INDEX (UMFPACK_SCALE), scale)) ; if (scale == UMFPACK_SCALE_NONE) { PRINTF ((" (no)")) ; } else if (scale == UMFPACK_SCALE_SUM) { PRINTF ((" (divide each row by sum of abs. values in each row)")) ; } else if (scale == UMFPACK_SCALE_MAX) { PRINTF ((" (divide each row by max. abs. value in each row)")) ; } PRINTF (("\n")) ; /* ---------------------------------------------------------------------- */ /* frontal matrix allocation parameter */ /* ---------------------------------------------------------------------- */ front_alloc_init = GET_CONTROL (UMFPACK_FRONT_ALLOC_INIT, UMFPACK_DEFAULT_FRONT_ALLOC_INIT) ; front_alloc_init = MIN (1.0, front_alloc_init) ; if (front_alloc_init >= 0) { PRINTF ((" "ID": frontal matrix allocation ratio: %g\n", (Int) INDEX (UMFPACK_FRONT_ALLOC_INIT), front_alloc_init)) ; } else { s = -front_alloc_init ; s = MAX (1, s) ; PRINTF ((" "ID": initial frontal matrix size (# of Entry's): "ID"\n", (Int) INDEX (UMFPACK_FRONT_ALLOC_INIT), s)) ; } /* ---------------------------------------------------------------------- */ /* drop tolerance */ /* ---------------------------------------------------------------------- */ droptol = GET_CONTROL (UMFPACK_DROPTOL, UMFPACK_DEFAULT_DROPTOL) ; PRINTF ((" "ID": drop tolerance: %g\n", (Int) INDEX (UMFPACK_DROPTOL), droptol)) ; /* ---------------------------------------------------------------------- */ /* aggressive absorption */ /* ---------------------------------------------------------------------- */ aggr = GET_CONTROL (UMFPACK_AGGRESSIVE, UMFPACK_DEFAULT_AGGRESSIVE) ; PRINTF ((" "ID": AMD and COLAMD aggressive absorption: %g", (Int) INDEX (UMFPACK_AGGRESSIVE), aggr)) ; if (aggr != 0.0) { PRINTF ((" (yes)\n")) ; } else { PRINTF ((" (no)\n")) ; } /* ---------------------------------------------------------------------- */ /* compile-time options */ /* ---------------------------------------------------------------------- */ PRINTF (( "\n The following options can only be changed at compile-time:\n")) ; PRINTF ((" "ID": BLAS library used: ", (Int) INDEX (UMFPACK_COMPILED_WITH_BLAS))) ; #ifdef NBLAS PRINTF (("none. UMFPACK will be slow.\n")) ; #else PRINTF (("Fortran BLAS. size of BLAS integer: "ID"\n", (Int) (sizeof (BLAS_INT)))) ; #endif #ifdef MATLAB_MEX_FILE PRINTF ((" "ID": compiled for MATLAB\n", (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ; #else #ifdef MATHWORKS PRINTF ((" "ID": compiled for MATLAB\n", (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ; #else PRINTF ((" "ID": compiled for ANSI C\n", (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ; #endif #endif #ifdef NO_TIMER PRINTF ((" "ID": no CPU timer \n", (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ; #else #ifndef NPOSIX PRINTF ((" "ID": CPU timer is POSIX times ( ) routine.\n", (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ; #else #ifdef GETRUSAGE PRINTF ((" "ID": CPU timer is getrusage.\n", (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ; #else PRINTF ((" "ID": CPU timer is ANSI C clock (may wrap around).\n", (Int) INDEX (UMFPACK_COMPILED_WITH_GETRUSAGE))) ; #endif #endif #endif #ifndef NDEBUG PRINTF (( "**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n" " "ID": compiled with debugging enabled. ", (Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ; #else PRINTF ((" "ID": compiled for normal operation (debugging disabled)\n", (Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ; #endif PRINTF ((" computer/operating system: %s\n", UMFPACK_ARCHITECTURE)) ; PRINTF ((" size of int: %g UF_long: %g Int: %g pointer: %g" " double: %g Entry: %g (in bytes)\n\n", (double) sizeof (int), (double) sizeof (UF_long), (double) sizeof (Int), (double) sizeof (void *), (double) sizeof (double), (double) sizeof (Entry))) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_scale.c0000644000175000017500000000451211674452555021756 0ustar sonnesonne/* ========================================================================== */ /* === UMF_scale ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Divide a vector of stride 1 by the pivot value. */ #include "umf_internal.h" #include "umf_scale.h" GLOBAL void UMF_scale ( Int n, Entry pivot, Entry X [ ] ) { Entry x ; double s ; Int i ; /* ---------------------------------------------------------------------- */ /* compute the approximate absolute value of the pivot, and select method */ /* ---------------------------------------------------------------------- */ APPROX_ABS (s, pivot) ; if (s < RECIPROCAL_TOLERANCE || IS_NAN (pivot)) { /* ------------------------------------------------------------------ */ /* tiny, or zero, pivot case */ /* ------------------------------------------------------------------ */ /* The pivot is tiny, or NaN. Do not divide zero by the pivot value, * and do not multiply by 1/pivot, either. */ for (i = 0 ; i < n ; i++) { /* X [i] /= pivot ; */ x = X [i] ; #ifndef NO_DIVIDE_BY_ZERO if (IS_NONZERO (x)) { DIV (X [i], x, pivot) ; } #else /* Do not divide by zero */ if (IS_NONZERO (x) && IS_NONZERO (pivot)) { DIV (X [i], x, pivot) ; } #endif } } else { /* ------------------------------------------------------------------ */ /* normal case */ /* ------------------------------------------------------------------ */ /* The pivot is not tiny, and is not NaN. Don't bother to check for * zeros in the pivot column, X. This is slightly more accurate than * multiplying by 1/pivot (but slightly slower), particularly if the * pivot column consists of only IEEE subnormals. */ for (i = 0 ; i < n ; i++) { /* X [i] /= pivot ; */ x = X [i] ; DIV (X [i], x, pivot) ; } } } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_analyze.c0000644000175000017500000005056311674452555022341 0ustar sonnesonne/* ========================================================================== */ /* === UMF_analyze ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Symbolic LL' factorization of A'*A, to get upper bounds on the size of L and U for LU = PAQ, and to determine the frontal matrices and (supernodal) column elimination tree. No fill-reducing column pre-ordering is used. Returns TRUE if successful, FALSE if out of memory. UMF_analyze can only run out of memory if anzmax (which is Ap [n_row]) is too small. Uses workspace of size O(nonzeros in A). On input, the matrix A is stored in row-form at the tail end of Ai. It is destroyed on output. The rows of A must be sorted by increasing first column index. The matrix is assumed to be valid. Empty rows and columns have already been removed. */ #include "umf_internal.h" #include "umf_analyze.h" #include "umf_apply_order.h" #include "umf_fsize.h" /* ========================================================================== */ GLOBAL Int UMF_analyze ( Int n_row, /* A is n_row-by-n_col */ Int n_col, Int Ai [ ], /* Ai [Ap [0]..Ap[n_row]-1]: column indices */ /* destroyed on output. Note that this is NOT the */ /* user's Ai that was passed to UMFPACK_*symbolic */ /* size of Ai, Ap [n_row] = anzmax >= anz + n_col */ /* Ap [0] must be => n_col. The space to the */ /* front of Ai is used as workspace. */ Int Ap [ ], /* of size MAX (n_row, n_col) + 1 */ /* Ap [0..n_row]: row pointers */ /* Row i is in Ai [Ap [i] ... Ap [i+1]-1] */ /* rows must have smallest col index first, or be */ /* in sorted form. Used as workspace of size n_col */ /* and destroyed. */ /* Note that this is NOT the */ /* user's Ap that was passed to UMFPACK_*symbolic */ Int Up [ ], /* workspace of size n_col, and output column perm. * for column etree postorder. */ Int fixQ, /* temporary workspaces: */ Int W [ ], /* W [0..n_col-1] */ Int Link [ ], /* Link [0..n_col-1] */ /* output: information about each frontal matrix: */ Int Front_ncols [ ], /* size n_col */ Int Front_nrows [ ], /* of size n_col */ Int Front_npivcol [ ], /* of size n_col */ Int Front_parent [ ], /* of size n_col */ Int *nfr_out, Int *p_ncompactions /* number of compactions in UMF_analyze */ ) { /* ====================================================================== */ /* ==== local variables ================================================= */ /* ====================================================================== */ Int j, j3, col, k, row, parent, j2, pdest, p, p2, thickness, npivots, nfr, i, *Winv, kk, npiv, jnext, krow, knext, pfirst, jlast, ncompactions, *Front_stack, *Front_order, *Front_child, *Front_sibling, Wflag, npivcol, fallrows, fallcols, fpiv, frows, fcols, *Front_size ; nfr = 0 ; DEBUG0 (("UMF_analyze: anzmax "ID" anrow "ID" ancol "ID"\n", Ap [n_row], n_row, n_col)) ; /* ====================================================================== */ /* ==== initializations ================================================= */ /* ====================================================================== */ #pragma ivdep for (j = 0 ; j < n_col ; j++) { Link [j] = EMPTY ; W [j] = EMPTY ; Up [j] = EMPTY ; /* Frontal matrix data structure: */ Front_npivcol [j] = 0 ; /* number of pivot columns */ Front_nrows [j] = 0 ; /* number of rows, incl. pivot rows */ Front_ncols [j] = 0 ; /* number of cols, incl. pivot cols */ Front_parent [j] = EMPTY ; /* parent front */ /* Note that only non-pivotal columns are stored in a front (a "row" */ /* of U) during elimination. */ } /* the rows must be sorted by increasing min col */ krow = 0 ; pfirst = Ap [0] ; jlast = EMPTY ; jnext = EMPTY ; Wflag = 0 ; /* this test requires the size of Ai to be >= n_col + nz */ ASSERT (pfirst >= n_col) ; /* Ai must be large enough */ /* pdest points to the first free space in Ai */ pdest = 0 ; ncompactions = 0 ; /* ====================================================================== */ /* === compute symbolic LL' factorization (unsorted) ==================== */ /* ====================================================================== */ for (j = 0 ; j < n_col ; j = jnext) { DEBUG1 (("\n\n============Front "ID" starting. nfr = "ID"\n", j, nfr)) ; /* ================================================================== */ /* === garbage collection =========================================== */ /* ================================================================== */ if (pdest + (n_col-j) > pfirst) { /* we might run out ... compact the rows of U */ #ifndef NDEBUG DEBUG0 (("UMF_analyze COMPACTION, j="ID" pfirst="ID"\n", j, pfirst)) ; for (row = 0 ; row < j ; row++) { if (Up [row] != EMPTY) { /* this is a live row of U */ DEBUG1 (("Live row: "ID" cols: ", row)) ; p = Up [row] ; ASSERT (Front_ncols [row] > Front_npivcol [row]) ; p2 = p + (Front_ncols [row] - Front_npivcol [row]) ; for ( ; p < p2 ; p++) { DEBUG1 ((ID, Ai [p])) ; ASSERT (p < pfirst) ; ASSERT (Ai [p] > row && Ai [p] < n_col) ; } DEBUG1 (("\n")) ; } } DEBUG1 (("\nStarting to compact:\n")) ; #endif pdest = 0 ; ncompactions++ ; for (row = 0 ; row < j ; row++) { if (Up [row] != EMPTY) { /* this is a live row of U */ DEBUG1 (("Live row: "ID" cols: ", row)) ; ASSERT (row < n_col) ; p = Up [row] ; ASSERT (Front_ncols [row] > Front_npivcol [row]) ; p2 = p + (Front_ncols [row] - Front_npivcol [row]) ; Up [row] = pdest ; for ( ; p < p2 ; p++) { DEBUG1 ((ID, Ai [p])) ; ASSERT (p < pfirst) ; ASSERT (Ai [p] > row && Ai [p] < n_col) ; Ai [pdest++] = Ai [p] ; ASSERT (pdest <= pfirst) ; } DEBUG1 (("\n")) ; } } #ifndef NDEBUG DEBUG1 (("\nAFTER COMPACTION, j="ID" pfirst="ID"\n", j, pfirst)) ; for (row = 0 ; row < j ; row++) { if (Up [row] != EMPTY) { /* this is a live row of U */ DEBUG1 (("Live row: "ID" cols: ", row)) ; p = Up [row] ; ASSERT (Front_ncols [row] > Front_npivcol [row]) ; p2 = p + (Front_ncols [row] - Front_npivcol [row]) ; for ( ; p < p2 ; p++) { DEBUG1 ((ID, Ai [p])) ; ASSERT (p < pfirst) ; ASSERT (Ai [p] > row && Ai [p] < n_col) ; } DEBUG1 (("\n")) ; } } #endif } if (pdest + (n_col-j) > pfirst) { /* :: out of memory in umf_analyze :: */ /* it can't happen, if pfirst >= n_col */ return (FALSE) ; /* internal error! */ } /* ------------------------------------------------------------------ */ /* is the last front a child of this one? */ /* ------------------------------------------------------------------ */ if (jlast != EMPTY && Link [j] == jlast) { /* yes - create row j by appending to jlast */ DEBUG1 (("GOT:last front is child of this one: j "ID" jlast "ID"\n", j, jlast)) ; ASSERT (jlast >= 0 && jlast < j) ; Up [j] = Up [jlast] ; Up [jlast] = EMPTY ; /* find the parent, delete column j, and update W */ parent = n_col ; for (p = Up [j] ; p < pdest ; ) { j3 = Ai [p] ; DEBUG1 (("Initial row of U: col "ID" ", j3)) ; ASSERT (j3 >= 0 && j3 < n_col) ; DEBUG1 (("W: "ID" \n", W [j3])) ; ASSERT (W [j3] == Wflag) ; if (j == j3) { DEBUG1 (("Found column j at p = "ID"\n", p)) ; Ai [p] = Ai [--pdest] ; } else { if (j3 < parent) { parent = j3 ; } p++ ; } } /* delete jlast from the link list of j */ Link [j] = Link [jlast] ; ASSERT (Front_nrows [jlast] > Front_npivcol [jlast]) ; thickness = (Front_nrows [jlast] - Front_npivcol [jlast]) ; DEBUG1 (("initial thickness: "ID"\n", thickness)) ; } else { Up [j] = pdest ; parent = n_col ; /* thickness: number of (nonpivotal) rows in frontal matrix j */ thickness = 0 ; Wflag = j ; } /* ================================================================== */ /* === compute row j of A*A' ======================================== */ /* ================================================================== */ /* ------------------------------------------------------------------ */ /* flag the diagonal entry in row U, but do not add to pattern */ /* ------------------------------------------------------------------ */ ASSERT (pdest <= pfirst) ; W [j] = Wflag ; DEBUG1 (("\nComputing row "ID" of A'*A\n", j)) ; DEBUG2 ((" col: "ID" (diagonal)\n", j)) ; /* ------------------------------------------------------------------ */ /* find the rows the contribute to this column j */ /* ------------------------------------------------------------------ */ jnext = n_col ; for (knext = krow ; knext < n_row ; knext++) { ASSERT (Ap [knext] < Ap [knext+1]) ; ASSERT (Ap [knext] >= pfirst && Ap [knext] <= Ap [n_row]) ; jnext = Ai [Ap [knext]] ; ASSERT (jnext >= j) ; if (jnext != j) { break ; } } /* rows krow ... knext-1 all have first column index of j */ /* (or are empty) */ /* row knext has first column index of jnext */ /* if knext = n_row, then jnext is n_col */ if (knext == n_row) { jnext = n_col ; } ASSERT (jnext > j) ; ASSERT (jnext <= n_col) ; /* ------------------------------------------------------------------ */ /* for each nonzero A (k,j) in column j of A do: */ /* ------------------------------------------------------------------ */ for (k = krow ; k < knext ; k++) { p = Ap [k] ; p2 = Ap [k+1] ; ASSERT (p < p2) ; /* merge row k of A into W */ DEBUG2 ((" ---- A row "ID" ", k)) ; ASSERT (k >= 0 && k < n_row) ; ASSERT (Ai [p] == j) ; DEBUG2 ((" p "ID" p2 "ID"\n cols:", p, p2)) ; ASSERT (p >= pfirst && p < Ap [n_row]) ; ASSERT (p2 > pfirst && p2 <= Ap [n_row]) ; for ( ; p < p2 ; p++) { /* add to pattern if seen for the first time */ col = Ai [p] ; ASSERT (col >= j && col < n_col) ; DEBUG3 ((" "ID, col)) ; if (W [col] != Wflag) { Ai [pdest++] = col ; ASSERT (pdest <= pfirst) ; /* flag this column has having been seen for row j */ W [col] = Wflag ; if (col < parent) { parent = col ; } } } DEBUG2 (("\n")) ; thickness++ ; } #ifndef NDEBUG DEBUG3 (("\nRow "ID" of A'A:\n", j)) ; for (p = Up [j] ; p < pdest ; p++) { DEBUG3 ((" "ID, Ai [p])) ; } DEBUG3 (("\n")) ; #endif /* ------------------------------------------------------------------ */ /* delete rows up to but not including knext */ /* ------------------------------------------------------------------ */ krow = knext ; pfirst = Ap [knext] ; /* we can now use Ai [0..pfirst-1] as workspace for rows of U */ /* ================================================================== */ /* === compute jth row of U ========================================= */ /* ================================================================== */ /* for each nonzero U (k,j) in column j of U (1:j-1,:) do */ for (k = Link [j] ; k != EMPTY ; k = Link [k]) { /* merge row k of U into W */ DEBUG2 ((" ---- U row "ID, k)) ; ASSERT (k >= 0 && k < n_col) ; ASSERT (Up [k] != EMPTY) ; p = Up [k] ; ASSERT (Front_ncols [k] > Front_npivcol [k]) ; p2 = p + (Front_ncols [k] - Front_npivcol [k]) ; DEBUG2 ((" p "ID" p2 "ID"\n cols:", p, p2)) ; ASSERT (p <= pfirst) ; ASSERT (p2 <= pfirst) ; for ( ; p < p2 ; p++) { /* add to pattern if seen for the first time */ col = Ai [p] ; ASSERT (col >= j && col < n_col) ; DEBUG3 ((" "ID, col)) ; if (W [col] != Wflag) { Ai [pdest++] = col ; ASSERT (pdest <= pfirst) ; /* flag this col has having been seen for row j */ W [col] = Wflag ; if (col < parent) { parent = col ; } } } DEBUG2 (("\n")) ; /* mark the row k as deleted */ Up [k] = EMPTY ; ASSERT (Front_nrows [k] > Front_npivcol [k]) ; thickness += (Front_nrows [k] - Front_npivcol [k]) ; ASSERT (Front_parent [k] == j) ; } #ifndef NDEBUG DEBUG3 (("\nRow "ID" of U prior to supercolumn detection:\n", j)); for (p = Up [j] ; p < pdest ; p++) { DEBUG3 ((" "ID, Ai [p])) ; } DEBUG3 (("\n")) ; DEBUG1 (("thickness, prior to supercol detect: "ID"\n", thickness)) ; #endif /* ================================================================== */ /* === quicky mass elimination ====================================== */ /* ================================================================== */ /* this code detects some supernodes, but it might miss */ /* some because the elimination tree (created on the fly) */ /* is not yet post-ordered, and because the pattern of A'*A */ /* is also computed on the fly. */ /* j2 is incremented because the pivot columns are not stored */ for (j2 = j+1 ; j2 < jnext ; j2++) { ASSERT (j2 >= 0 && j2 < n_col) ; if (W [j2] != Wflag || Link [j2] != EMPTY) { break ; } } /* the loop above terminated with j2 at the first non-supernode */ DEBUG1 (("jnext = "ID"\n", jnext)) ; ASSERT (j2 <= jnext) ; jnext = j2 ; j2-- ; DEBUG1 (("j2 = "ID"\n", j2)) ; ASSERT (j2 < n_col) ; npivots = j2-j+1 ; DEBUG1 (("Number of pivot columns: "ID"\n", npivots)) ; /* rows j:j2 have the same nonzero pattern, except for columns j:j2-1 */ if (j2 > j) { /* supernode detected, prune the pattern of new row j */ ASSERT (parent == j+1) ; ASSERT (j2 < n_col) ; DEBUG1 (("Supernode detected, j "ID" to j2 "ID"\n", j, j2)) ; parent = n_col ; p2 = pdest ; pdest = Up [j] ; for (p = Up [j] ; p < p2 ; p++) { col = Ai [p] ; ASSERT (col >= 0 && col < n_col) ; ASSERT (W [col] == Wflag) ; if (col > j2) { /* keep this col in the pattern of the new row j */ Ai [pdest++] = col ; if (col < parent) { parent = col ; } } } } DEBUG1 (("Parent ["ID"] = "ID"\n", j, parent)) ; ASSERT (parent > j2) ; if (parent == n_col) { /* this front has no parent - it is the root of a subtree */ parent = EMPTY ; } #ifndef NDEBUG DEBUG3 (("\nFinal row "ID" of U after supercolumn detection:\n", j)) ; for (p = Up [j] ; p < pdest ; p++) { ASSERT (Ai [p] >= 0 && Ai [p] < n_col) ; DEBUG3 ((" "ID" ("ID")", Ai [p], W [Ai [p]])) ; ASSERT (W [Ai [p]] == Wflag) ; } DEBUG3 (("\n")) ; #endif /* ================================================================== */ /* === frontal matrix =============================================== */ /* ================================================================== */ /* front has Front_npivcol [j] pivot columns */ /* entire front is Front_nrows [j] -by- Front_ncols [j] */ /* j is first column in the front */ npivcol = npivots ; fallrows = thickness ; fallcols = npivots + pdest - Up [j] ; /* number of pivots in the front (rows and columns) */ fpiv = MIN (npivcol, fallrows) ; /* size of contribution block */ frows = fallrows - fpiv ; fcols = fallcols - fpiv ; if (frows == 0 || fcols == 0) { /* front has no contribution block and thus needs no parent */ DEBUG1 (("Frontal matrix evaporation\n")) ; Up [j] = EMPTY ; parent = EMPTY ; } Front_npivcol [j] = npivots ; Front_nrows [j] = fallrows ; Front_ncols [j] = fallcols ; Front_parent [j] = parent ; ASSERT (npivots > 0) ; /* Front_parent [j] is the first column of the parent frontal matrix */ DEBUG1 (("\n\n==== Front "ID", nfr "ID" pivot columns "ID":"ID " all front: "ID"-by-"ID" Parent: "ID"\n", j, nfr, j,j+npivots-1, Front_nrows [j], Front_ncols [j], Front_parent [j])) ; nfr++ ; /* ================================================================== */ /* === prepare this row for its parent ============================== */ /* ================================================================== */ if (parent != EMPTY) { Link [j] = Link [parent] ; Link [parent] = j ; } ASSERT (jnext > j) ; jlast = j ; } /* ====================================================================== */ /* === postorder the fronts ============================================= */ /* ====================================================================== */ *nfr_out = nfr ; Front_order = W ; /* use W for Front_order [ */ if (fixQ) { /* do not postorder the fronts if Q is fixed */ DEBUG1 (("\nNo postorder (Q is fixed)\n")) ; k = 0 ; /* Pragma added May 14, 2003. The Intel compiler icl 6.0 (an old * version) incorrectly vectorizes this loop. */ #pragma novector for (j = 0 ; j < n_col ; j++) { if (Front_npivcol [j] > 0) { Front_order [j] = k++ ; DEBUG1 (("Front order of j: "ID" is:"ID"\n", j, Front_order [j])) ; } else { Front_order [j] = EMPTY ; } } } else { /* use Ap for Front_child and use Link for Front_sibling [ */ Front_child = Ap ; Front_sibling = Link ; /* use Ai for Front_stack, size of Ai is >= 2*n_col */ Front_stack = Ai ; Front_size = Front_stack + n_col ; UMF_fsize (n_col, Front_size, Front_nrows, Front_ncols, Front_parent, Front_npivcol) ; AMD_postorder (n_col, Front_parent, Front_npivcol, Front_size, Front_order, Front_child, Front_sibling, Front_stack) ; /* done with Front_child, Front_sibling, Front_size, and Front_stack ]*/ /* ------------------------------------------------------------------ */ /* construct the column permutation (return in Up) */ /* ------------------------------------------------------------------ */ /* Front_order [i] = k means that front i is kth front in the new order. * i is in the range 0 to n_col-1, and k is in the range 0 to nfr-1 */ /* Use Ai as workspace for Winv [ */ Winv = Ai ; for (k = 0 ; k < nfr ; k++) { Winv [k] = EMPTY ; } /* compute the inverse of Front_order, so that Winv [k] = i */ /* if Front_order [i] = k */ DEBUG1 (("\n\nComputing output column permutation:\n")) ; for (i = 0 ; i < n_col ; i++) { k = Front_order [i] ; if (k != EMPTY) { DEBUG1 (("Front "ID" new order: "ID"\n", i, k)) ; ASSERT (k >= 0 && k < nfr) ; ASSERT (Winv [k] == EMPTY) ; Winv [k] = i ; } } /* Use Up as output permutation */ kk = 0 ; for (k = 0 ; k < nfr ; k++) { i = Winv [k] ; DEBUG1 (("Old Front "ID" New Front "ID" npivots "ID" nrows "ID " ncols "ID"\n", i, k, Front_npivcol [i], Front_nrows [i], Front_ncols [i])) ; ASSERT (i >= 0 && i < n_col) ; ASSERT (Front_npivcol [i] > 0) ; for (npiv = 0 ; npiv < Front_npivcol [i] ; npiv++) { Up [kk] = i + npiv ; DEBUG1 ((" Cperm ["ID"] = "ID"\n", kk, Up [kk])) ; kk++ ; } } ASSERT (kk == n_col) ; /* Winv no longer needed ] */ } /* ---------------------------------------------------------------------- */ /* apply the postorder traversal to renumber the frontal matrices */ /* (or pack them in same order, if fixQ) */ /* ---------------------------------------------------------------------- */ /* use Ai as workspace */ UMF_apply_order (Front_npivcol, Front_order, Ai, n_col, nfr) ; UMF_apply_order (Front_nrows, Front_order, Ai, n_col, nfr) ; UMF_apply_order (Front_ncols, Front_order, Ai, n_col, nfr) ; UMF_apply_order (Front_parent, Front_order, Ai, n_col, nfr) ; /* fix the parent to refer to the new numbering */ for (i = 0 ; i < nfr ; i++) { parent = Front_parent [i] ; if (parent != EMPTY) { ASSERT (parent >= 0 && parent < n_col) ; ASSERT (Front_order [parent] >= 0 && Front_order [parent] < nfr) ; Front_parent [i] = Front_order [parent] ; } } /* Front_order longer needed ] */ #ifndef NDEBUG DEBUG1 (("\nFinal frontal matrices:\n")) ; for (i = 0 ; i < nfr ; i++) { DEBUG1 (("Final front "ID": npiv "ID" nrows "ID" ncols "ID" parent " ID"\n", i, Front_npivcol [i], Front_nrows [i], Front_ncols [i], Front_parent [i])) ; } #endif *p_ncompactions = ncompactions ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.h0000644000175000017500000000072511674452555023676 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_valid_symbolic ( SymbolicType *Symbolic ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_kernel.c0000644000175000017500000002275211674452555022155 0ustar sonnesonne/* ========================================================================== */ /* === UMF_kernel =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Primary factorization routine. Called by UMFPACK_numeric. Returns: UMFPACK_OK if successful, UMFPACK_ERROR_out_of_memory if out of memory, or UMFPACK_ERROR_different_pattern if pattern of matrix (Ap and/or Ai) has changed since the call to UMFPACK_*symbolic. */ #include "umf_internal.h" #include "umf_kernel.h" #include "umf_kernel_init.h" #include "umf_init_front.h" #include "umf_start_front.h" #include "umf_assemble.h" #include "umf_scale_column.h" #include "umf_local_search.h" #include "umf_create_element.h" #include "umf_extend_front.h" #include "umf_blas3_update.h" #include "umf_store_lu.h" #include "umf_kernel_wrapup.h" /* perform an action, and return if out of memory */ #define DO(action) { if (! (action)) { return (UMFPACK_ERROR_out_of_memory) ; }} GLOBAL Int UMF_kernel ( const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Int j, f1, f2, chain, nchains, *Chain_start, status, fixQ, evaporate, *Front_npivcol, jmax, nb, drop ; /* ---------------------------------------------------------------------- */ /* initialize memory space and load the matrix. Optionally scale. */ /* ---------------------------------------------------------------------- */ if (!UMF_kernel_init (Ap, Ai, Ax, #ifdef COMPLEX Az, #endif Numeric, Work, Symbolic)) { /* UMF_kernel_init is guaranteed to succeed, since UMFPACK_numeric */ /* either allocates enough space or if not, UMF_kernel does not get */ /* called. So running out of memory here is a fatal error, and means */ /* that the user changed Ap and/or Ai since the call to */ /* UMFPACK_*symbolic. */ DEBUGm4 (("kernel init failed\n")) ; return (UMFPACK_ERROR_different_pattern) ; } /* ---------------------------------------------------------------------- */ /* get the symbolic factorization */ /* ---------------------------------------------------------------------- */ nchains = Symbolic->nchains ; Chain_start = Symbolic->Chain_start ; Front_npivcol = Symbolic->Front_npivcol ; nb = Symbolic->nb ; fixQ = Symbolic->fixQ ; drop = Numeric->droptol > 0.0 ; #ifndef NDEBUG for (chain = 0 ; chain < nchains ; chain++) { Int i ; f1 = Chain_start [chain] ; f2 = Chain_start [chain+1] - 1 ; DEBUG1 (("\nCHain: "ID" start "ID" end "ID"\n", chain, f1, f2)) ; for (i = f1 ; i <= f2 ; i++) { DEBUG1 (("Front "ID", npivcol "ID"\n", i, Front_npivcol [i])) ; } } #endif /* ---------------------------------------------------------------------- */ /* factorize each chain of frontal matrices */ /* ---------------------------------------------------------------------- */ for (chain = 0 ; chain < nchains ; chain++) { f1 = Chain_start [chain] ; f2 = Chain_start [chain+1] - 1 ; /* ------------------------------------------------------------------ */ /* get the initial frontal matrix size for this chain */ /* ------------------------------------------------------------------ */ DO (UMF_start_front (chain, Numeric, Work, Symbolic)) ; /* ------------------------------------------------------------------ */ /* factorize each front in the chain */ /* ------------------------------------------------------------------ */ for (Work->frontid = f1 ; Work->frontid <= f2 ; Work->frontid++) { /* -------------------------------------------------------------- */ /* Initialize the pivot column candidate set */ /* -------------------------------------------------------------- */ Work->ncand = Front_npivcol [Work->frontid] ; Work->lo = Work->nextcand ; Work->hi = Work->nextcand + Work->ncand - 1 ; jmax = MIN (MAX_CANDIDATES, Work->ncand) ; DEBUGm1 ((">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Starting front " ID", npivcol: "ID"\n", Work->frontid, Work->ncand)) ; if (fixQ) { /* do not modify the column order */ jmax = 1 ; } DEBUGm1 (("Initial candidates: ")) ; for (j = 0 ; j < jmax ; j++) { DEBUGm1 ((" "ID, Work->nextcand)) ; ASSERT (Work->nextcand <= Work->hi) ; Work->Candidates [j] = Work->nextcand++ ; } Work->nCandidates = jmax ; DEBUGm1 (("\n")) ; /* -------------------------------------------------------------- */ /* Assemble and factorize the current frontal matrix */ /* -------------------------------------------------------------- */ while (Work->ncand > 0) { /* ---------------------------------------------------------- */ /* get the pivot row and column */ /* ---------------------------------------------------------- */ status = UMF_local_search (Numeric, Work, Symbolic) ; if (status == UMFPACK_ERROR_different_pattern) { /* :: pattern change detected in umf_local_search :: */ /* input matrix has changed since umfpack_*symbolic */ DEBUGm4 (("local search failed\n")) ; return (UMFPACK_ERROR_different_pattern) ; } if (status == UMFPACK_WARNING_singular_matrix) { /* no pivot found, discard and try again */ continue ; } /* ---------------------------------------------------------- */ /* update if front not extended or too many zeros in L,U */ /* ---------------------------------------------------------- */ if (Work->do_update) { UMF_blas3_update (Work) ; if (drop) { DO (UMF_store_lu_drop (Numeric, Work)) ; } else { DO (UMF_store_lu (Numeric, Work)) ; } } /* ---------------------------------------------------------- */ /* extend the frontal matrix, or start a new one */ /* ---------------------------------------------------------- */ if (Work->do_extend) { /* extend the current front */ DO (UMF_extend_front (Numeric, Work)) ; } else { /* finish the current front (if any) and start a new one */ DO (UMF_create_element (Numeric, Work, Symbolic)) ; DO (UMF_init_front (Numeric, Work)) ; } /* ---------------------------------------------------------- */ /* Numerical & symbolic assembly into current frontal matrix */ /* ---------------------------------------------------------- */ if (fixQ) { UMF_assemble_fixq (Numeric, Work) ; } else { UMF_assemble (Numeric, Work) ; } /* ---------------------------------------------------------- */ /* scale the pivot column */ /* ---------------------------------------------------------- */ UMF_scale_column (Numeric, Work) ; /* ---------------------------------------------------------- */ /* Numerical update if enough pivots accumulated */ /* ---------------------------------------------------------- */ evaporate = Work->fnrows == 0 || Work->fncols == 0 ; if (Work->fnpiv >= nb || evaporate) { UMF_blas3_update (Work) ; if (drop) { DO (UMF_store_lu_drop (Numeric, Work)) ; } else { DO (UMF_store_lu (Numeric, Work)) ; } } Work->pivrow_in_front = FALSE ; Work->pivcol_in_front = FALSE ; /* ---------------------------------------------------------- */ /* If front is empty, evaporate it */ /* ---------------------------------------------------------- */ if (evaporate) { /* This does not create an element, just evaporates it. * It ensures that a front is not 0-by-c or r-by-0. No * memory is allocated, so it is guaranteed to succeed. */ (void) UMF_create_element (Numeric, Work, Symbolic) ; Work->fnrows = 0 ; Work->fncols = 0 ; } } } /* ------------------------------------------------------------------ * Wrapup the current frontal matrix. This is the last in a chain * in the column elimination tree. The next frontal matrix * cannot overlap with the current one, which will be its sibling * in the column etree. * ------------------------------------------------------------------ */ UMF_blas3_update (Work) ; if (drop) { DO (UMF_store_lu_drop (Numeric, Work)) ; } else { DO (UMF_store_lu (Numeric, Work)) ; } Work->fnrows_new = Work->fnrows ; Work->fncols_new = Work->fncols ; DO (UMF_create_element (Numeric, Work, Symbolic)) ; /* ------------------------------------------------------------------ */ /* current front is now empty */ /* ------------------------------------------------------------------ */ Work->fnrows = 0 ; Work->fncols = 0 ; } /* ---------------------------------------------------------------------- */ /* end the last Lchain and Uchain and finalize the LU factors */ /* ---------------------------------------------------------------------- */ UMF_kernel_wrapup (Numeric, Symbolic, Work) ; /* note that the matrix may be singular (this is OK) */ return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_numeric.c0000644000175000017500000006532011674452555024033 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_get_numeric ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Gets the LU factors and the permutation vectors held in the Numeric object. L is returned in sparse row form with sorted rows, U is returned in sparse column form with sorted columns, and P and Q are returned as permutation vectors. See umfpack_get_numeric.h for a more detailed description. Returns TRUE if successful, FALSE if the Numeric object is invalid or if out of memory. Dynamic memory usage: calls UMF_malloc twice, for a total space of 2*n integers, and then frees all of it via UMF_free when done. */ #include "umf_internal.h" #include "umf_valid_numeric.h" #include "umf_malloc.h" #include "umf_free.h" #ifndef NDEBUG PRIVATE Int init_count ; #endif PRIVATE void get_L ( Int Lp [ ], Int Lj [ ], double Lx [ ], #ifdef COMPLEX double Lz [ ], #endif NumericType *Numeric, Int Pattern [ ], Int Wi [ ] ) ; PRIVATE void get_U ( Int Up [ ], Int Ui [ ], double Ux [ ], #ifdef COMPLEX double Uz [ ], #endif NumericType *Numeric, Int Pattern [ ], Int Wi [ ] ) ; /* ========================================================================== */ /* === UMFPACK_get_numeric ================================================== */ /* ========================================================================== */ GLOBAL Int UMFPACK_get_numeric ( Int Lp [ ], Int Lj [ ], double Lx [ ], #ifdef COMPLEX double Lz [ ], #endif Int Up [ ], Int Ui [ ], double Ux [ ], #ifdef COMPLEX double Uz [ ], #endif Int P [ ], Int Q [ ], double Dx [ ], #ifdef COMPLEX double Dz [ ], #endif Int *p_do_recip, double Rs [ ], void *NumericHandle ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ NumericType *Numeric ; Int getL, getU, *Rperm, *Cperm, k, nn, n_row, n_col, *Wi, *Pattern, n_inner ; double *Rs1 ; Entry *D ; #ifndef NDEBUG init_count = UMF_malloc_count ; #endif Wi = (Int *) NULL ; Pattern = (Int *) NULL ; /* ---------------------------------------------------------------------- */ /* check input parameters */ /* ---------------------------------------------------------------------- */ Numeric = (NumericType *) NumericHandle ; if (!UMF_valid_numeric (Numeric)) { return (UMFPACK_ERROR_invalid_Numeric_object) ; } n_row = Numeric->n_row ; n_col = Numeric->n_col ; nn = MAX (n_row, n_col) ; n_inner = MIN (n_row, n_col) ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ getL = Lp && Lj && Lx ; getU = Up && Ui && Ux ; if (getL || getU) { Wi = (Int *) UMF_malloc (nn, sizeof (Int)) ; Pattern = (Int *) UMF_malloc (nn, sizeof (Int)) ; if (!Wi || !Pattern) { (void) UMF_free ((void *) Wi) ; (void) UMF_free ((void *) Pattern) ; ASSERT (UMF_malloc_count == init_count) ; DEBUGm4 (("out of memory: get numeric\n")) ; return (UMFPACK_ERROR_out_of_memory) ; } ASSERT (UMF_malloc_count == init_count + 2) ; } /* ---------------------------------------------------------------------- */ /* get contents of Numeric */ /* ---------------------------------------------------------------------- */ if (P != (Int *) NULL) { Rperm = Numeric->Rperm ; for (k = 0 ; k < n_row ; k++) { P [k] = Rperm [k] ; } } if (Q != (Int *) NULL) { Cperm = Numeric->Cperm ; for (k = 0 ; k < n_col ; k++) { Q [k] = Cperm [k] ; } } if (getL) { get_L (Lp, Lj, Lx, #ifdef COMPLEX Lz, #endif Numeric, Pattern, Wi) ; } if (getU) { get_U (Up, Ui, Ux, #ifdef COMPLEX Uz, #endif Numeric, Pattern, Wi) ; } if (Dx != (double *) NULL) { D = Numeric->D ; #ifdef COMPLEX if (SPLIT (Dz)) { for (k = 0 ; k < n_inner ; k++) { Dx [k] = REAL_COMPONENT (D [k]) ; Dz [k] = IMAG_COMPONENT (D [k]) ; } } else { for (k = 0 ; k < n_inner ; k++) { Dx [2*k ] = REAL_COMPONENT (D [k]) ; Dx [2*k+1] = IMAG_COMPONENT (D [k]) ; } } #else { D = Numeric->D ; for (k = 0 ; k < n_inner ; k++) { Dx [k] = D [k] ; } } #endif } /* return the flag stating whether the scale factors are to be multiplied, * or divided. If do_recip is TRUE, multiply. Otherwise, divided. * If NRECIPROCAL is defined at compile time, the scale factors are always * to be used by dividing. */ if (p_do_recip != (Int *) NULL) { #ifndef NRECIPROCAL *p_do_recip = Numeric->do_recip ; #else *p_do_recip = FALSE ; #endif } if (Rs != (double *) NULL) { Rs1 = Numeric->Rs ; if (Rs1 == (double *) NULL) { /* R is the identity matrix. */ for (k = 0 ; k < n_row ; k++) { Rs [k] = 1.0 ; } } else { for (k = 0 ; k < n_row ; k++) { Rs [k] = Rs1 [k] ; } } } /* ---------------------------------------------------------------------- */ /* free the workspace */ /* ---------------------------------------------------------------------- */ (void) UMF_free ((void *) Wi) ; (void) UMF_free ((void *) Pattern) ; ASSERT (UMF_malloc_count == init_count) ; return (UMFPACK_OK) ; } /* ========================================================================== */ /* === get_L ================================================================ */ /* ========================================================================== */ /* The matrix L is stored in the following arrays in the Numeric object: Int Lpos [0..npiv] Int Lip [0..npiv], index into Numeric->Memory Int Lilen [0..npiv] Unit *(Numeric->Memory), pointer to memory space holding row indices and numerical values where npiv is the number of pivot entries found. If A is n_row-by-n_col, then npiv <= MIN (n_row,n_col). Let L_k denote the pattern of entries in column k of L (excluding the diagonal). An Lchain is a sequence of columns of L whose nonzero patterns are related. The start of an Lchain is denoted by a negative value of Lip [k]. To obtain L_k: (1) If column k starts an Lchain, then L_k is stored in its entirety. |Lip [k]| is an index into Numeric->Memory for the integer row indices in L_k. The number of entries in the column is |L_k| = Lilen [k]. This defines the pattern of the "leading" column of this chain. Lpos [k] is not used for the first column in the chain. Column zero is always a leading column. (2) If column k does not start an Lchain, then L_k is represented as a superset of L_k-1. Define Lnew_k such that (L_k-1 - {k} union Lnew_k) = L_k, where Lnew_k and (L_k-1)-{k} are disjoint. Lnew_k are the entries in L_k that are not in L_k-1. Lpos [k] holds the position of pivot row index k in the prior pattern L_k-1 (if it is present), so that the set subtraction (L_k-1)-{k} can be computed quickly, when computing the pattern of L_k from L_k-1. The number of new entries in L_k is stored in Lilen [k] = |Lnew_k|. Note that this means we must have the pattern L_k-1 to compute L_k. In both cases (1) and (2), we obtain the pattern L_k. The numerical values are stored in Numeric->Memory, starting at the index |Lip [k]| + Lilen [k]. It is stored in the same order as the entries in L_k, after L_k is obtained from cases (1) or (2), above. The advantage of using this "packed" data structure is that it can dramatically reduce the amount of storage needed for the pattern of L. The disadvantage is that it can be difficult for the user to access, and it does not match the sparse matrix data structure used in MATLAB. Thus, this routine is provided to create a conventional sparse matrix data structure for L, in sparse-row form. A row-form of L appears to MATLAB to be a column-oriented from of the transpose of L. If you would like a column-form of L, then use UMFPACK_transpose (an example of this is in umfpackmex.c). */ /* ========================================================================== */ PRIVATE void get_L ( Int Lp [ ], /* of size n_row+1 */ Int Lj [ ], /* of size lnz, where lnz = Lp [n_row] */ double Lx [ ], /* of size lnz */ #ifdef COMPLEX double Lz [ ], /* of size lnz */ #endif NumericType *Numeric, Int Pattern [ ], /* workspace of size n_row */ Int Wi [ ] /* workspace of size n_row */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry value ; Entry *xp, *Lval ; Int deg, *ip, j, row, n_row, n_col, n_inner, *Lpos, *Lilen, *Lip, p, llen, lnz2, lp, newLchain, k, pos, npiv, *Li, n1 ; #ifdef COMPLEX Int split = SPLIT (Lz) ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ DEBUG4 (("get_L start:\n")) ; n_row = Numeric->n_row ; n_col = Numeric->n_col ; n_inner = MIN (n_row, n_col) ; npiv = Numeric->npiv ; n1 = Numeric->n1 ; Lpos = Numeric->Lpos ; Lilen = Numeric->Lilen ; Lip = Numeric->Lip ; deg = 0 ; /* ---------------------------------------------------------------------- */ /* count the nonzeros in each row of L */ /* ---------------------------------------------------------------------- */ #pragma ivdep for (row = 0 ; row < n_inner ; row++) { /* include the diagonal entry in the row counts */ Wi [row] = 1 ; } #pragma ivdep for (row = n_inner ; row < n_row ; row++) { Wi [row] = 0 ; } /* singletons */ for (k = 0 ; k < n1 ; k++) { DEBUG4 (("Singleton k "ID"\n", k)) ; deg = Lilen [k] ; if (deg > 0) { lp = Lip [k] ; Li = (Int *) (Numeric->Memory + lp) ; lp += UNITS (Int, deg) ; Lval = (Entry *) (Numeric->Memory + lp) ; for (j = 0 ; j < deg ; j++) { row = Li [j] ; value = Lval [j] ; DEBUG4 ((" row "ID" k "ID" value", row, k)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [row]++ ; } } } } /* non-singletons */ for (k = n1 ; k < npiv ; k++) { /* ------------------------------------------------------------------ */ /* make column of L in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ lp = Lip [k] ; newLchain = (lp < 0) ; if (newLchain) { lp = -lp ; deg = 0 ; DEBUG4 (("start of chain for column of L\n")) ; } /* remove pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n", k, Pattern [pos], pos)) ; ASSERT (!newLchain) ; ASSERT (deg > 0) ; ASSERT (pos >= 0 && pos < deg) ; ASSERT (Pattern [pos] == k) ; Pattern [pos] = Pattern [--deg] ; } /* concatenate the pattern */ ip = (Int *) (Numeric->Memory + lp) ; llen = Lilen [k] ; for (j = 0 ; j < llen ; j++) { row = *ip++ ; DEBUG4 ((" row "ID" k "ID"\n", row, k)) ; ASSERT (row > k && row < n_row) ; Pattern [deg++] = row ; } xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ; row = Pattern [j] ; value = *xp++ ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [row]++ ; } } } /* ---------------------------------------------------------------------- */ /* construct the final row form of L */ /* ---------------------------------------------------------------------- */ /* create the row pointers */ lnz2 = 0 ; for (row = 0 ; row < n_row ; row++) { Lp [row] = lnz2 ; lnz2 += Wi [row] ; Wi [row] = Lp [row] ; } Lp [n_row] = lnz2 ; ASSERT (Numeric->lnz + n_inner == lnz2) ; /* add entries from the rows of L (singletons) */ for (k = 0 ; k < n1 ; k++) { DEBUG4 (("Singleton k "ID"\n", k)) ; deg = Lilen [k] ; if (deg > 0) { lp = Lip [k] ; Li = (Int *) (Numeric->Memory + lp) ; lp += UNITS (Int, deg) ; Lval = (Entry *) (Numeric->Memory + lp) ; for (j = 0 ; j < deg ; j++) { row = Li [j] ; value = Lval [j] ; DEBUG4 ((" row "ID" k "ID" value", row, k)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = Wi [row]++ ; Lj [p] = k ; #ifdef COMPLEX if (split) { Lx [p] = REAL_COMPONENT (value) ; Lz [p] = IMAG_COMPONENT (value) ; } else { Lx [2*p ] = REAL_COMPONENT (value) ; Lx [2*p+1] = IMAG_COMPONENT (value) ; } #else Lx [p] = value ; #endif } } } } /* add entries from the rows of L (non-singletons) */ for (k = n1 ; k < npiv ; k++) { /* ------------------------------------------------------------------ */ /* make column of L in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ lp = Lip [k] ; newLchain = (lp < 0) ; if (newLchain) { lp = -lp ; deg = 0 ; DEBUG4 (("start of chain for column of L\n")) ; } /* remove pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n", k, Pattern [pos], pos)) ; ASSERT (!newLchain) ; ASSERT (deg > 0) ; ASSERT (pos >= 0 && pos < deg) ; ASSERT (Pattern [pos] == k) ; Pattern [pos] = Pattern [--deg] ; } /* concatenate the pattern */ ip = (Int *) (Numeric->Memory + lp) ; llen = Lilen [k] ; for (j = 0 ; j < llen ; j++) { row = *ip++ ; DEBUG4 ((" row "ID" k "ID"\n", row, k)) ; ASSERT (row > k) ; Pattern [deg++] = row ; } xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ; row = Pattern [j] ; value = *xp++ ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = Wi [row]++ ; Lj [p] = k ; #ifdef COMPLEX if (split) { Lx [p] = REAL_COMPONENT (value) ; Lz [p] = IMAG_COMPONENT (value) ; } else { Lx [2*p ] = REAL_COMPONENT (value) ; Lx [2*p+1] = IMAG_COMPONENT (value) ; } #else Lx [p] = value ; #endif } } } /* add all of the diagonal entries (L is unit diagonal) */ for (row = 0 ; row < n_inner ; row++) { p = Wi [row]++ ; Lj [p] = row ; #ifdef COMPLEX if (split) { Lx [p] = 1. ; Lz [p] = 0. ; } else { Lx [2*p ] = 1. ; Lx [2*p+1] = 0. ; } #else Lx [p] = 1. ; #endif ASSERT (Wi [row] == Lp [row+1]) ; } #ifndef NDEBUG DEBUG6 (("L matrix (stored by rows):")) ; UMF_dump_col_matrix (Lx, #ifdef COMPLEX Lz, #endif Lj, Lp, n_inner, n_row, Numeric->lnz+n_inner) ; #endif DEBUG4 (("get_L done:\n")) ; } /* ========================================================================== */ /* === get_U ================================================================ */ /* ========================================================================== */ /* The matrix U is stored in the following arrays in the Numeric object: Int Upos [0..npiv] Int Uip [0..npiv], index into Numeric->Memory Int Uilen [0..npiv] Unit *(Numeric->Memory), pointer to memory space holding column indices and numerical values where npiv is the number of pivot entries found. If A is n_row-by-n_col, then npiv <= MIN (n_row,n_col). Let U_k denote the pattern of entries in row k of U (excluding the diagonal). A Uchain is a sequence of columns of U whose nonzero patterns are related. The start of a Uchain is denoted by a negative value of Uip [k]. To obtain U_k-1: (1) If row k is the start of a Uchain then Uip [k] is negative and |Uip [k]| is an index into Numeric->Memory for the integer column indices in U_k-1. The number of entries in the row is |U_k-1| = Uilen [k]. This defines the pattern of the "trailing" row of this chain that ends at row k-1. (2) If row k is not the start of a Uchain, then U_k-1 is a subset of U_k. The indices in U_k are arranged so that last Uilen [k] entries of U_k are those indices not in U_k-1. Next, the pivot column index k is added if it appears in row U_k-1 (it never appears in U_k). Upos [k] holds the position of pivot column index k in the pattern U_k-1 (if it is present), so that the set union (U_k-1)+{k} can be computed quickly, when computing the pattern of U_k-1 from U_k. Note that this means we must have the pattern U_k to compute L_k-1. In both cases (1) and (2), we obtain the pattern U_k. The numerical values are stored in Numeric->Memory. If k is the start of a Uchain, then the offset is |Uip [k]| plus the size of the space needed to store the pattern U_k-1. Otherwise, Uip [k] is the offset itself of the numerical values, since in this case no pattern is stored. The numerical values are stored in the same order as the entries in U_k, after U_k is obtained from cases (1) or (2), above. The advantage of using this "packed" data structure is that it can dramatically reduce the amount of storage needed for the pattern of U. The disadvantage is that it can be difficult for the user to access, and it does not match the sparse matrix data structure used in MATLAB. Thus, this routine is provided to create a conventional sparse matrix data structure for U, in sparse-column form. */ /* ========================================================================== */ PRIVATE void get_U ( Int Up [ ], /* of size n_col+1 */ Int Ui [ ], /* of size unz, where unz = Up [n_col] */ double Ux [ ], /* of size unz */ #ifdef COMPLEX double Uz [ ], /* of size unz */ #endif NumericType *Numeric, Int Pattern [ ], /* workspace of size n_col */ Int Wi [ ] /* workspace of size n_col */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry value ; Entry *xp, *D, *Uval ; Int deg, j, *ip, col, *Upos, *Uilen, *Uip, n_col, ulen, *Usi, unz2, p, k, up, newUchain, pos, npiv, n1 ; #ifdef COMPLEX Int split = SPLIT (Uz) ; #endif #ifndef NDEBUG Int nnzpiv = 0 ; #endif /* ---------------------------------------------------------------------- */ /* get parameters */ /* ---------------------------------------------------------------------- */ DEBUG4 (("get_U start:\n")) ; n_col = Numeric->n_col ; n1 = Numeric->n1 ; npiv = Numeric->npiv ; Upos = Numeric->Upos ; Uilen = Numeric->Uilen ; Uip = Numeric->Uip ; D = Numeric->D ; /* ---------------------------------------------------------------------- */ /* count the nonzeros in each column of U */ /* ---------------------------------------------------------------------- */ for (col = 0 ; col < npiv ; col++) { /* include the diagonal entry in the column counts */ DEBUG4 (("D ["ID"] = ", col)) ; EDEBUG4 (D [col]) ; Wi [col] = IS_NONZERO (D [col]) ; DEBUG4 ((" is nonzero: "ID"\n", Wi [col])) ; #ifndef NDEBUG nnzpiv += IS_NONZERO (D [col]) ; #endif } DEBUG4 (("nnzpiv "ID" "ID"\n", nnzpiv, Numeric->nnzpiv)) ; ASSERT (nnzpiv == Numeric->nnzpiv) ; for (col = npiv ; col < n_col ; col++) { /* diagonal entries are zero for structurally singular part */ Wi [col] = 0 ; } deg = Numeric->ulen ; if (deg > 0) { /* make last pivot row of U (singular matrices only) */ DEBUG0 (("Last pivot row of U: ulen "ID"\n", deg)) ; for (j = 0 ; j < deg ; j++) { Pattern [j] = Numeric->Upattern [j] ; DEBUG0 ((" column "ID"\n", Pattern [j])) ; } } /* non-singletons */ for (k = npiv-1 ; k >= n1 ; k--) { /* ------------------------------------------------------------------ */ /* use row k of U */ /* ------------------------------------------------------------------ */ up = Uip [k] ; ulen = Uilen [k] ; newUchain = (up < 0) ; if (newUchain) { up = -up ; xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ; } else { xp = (Entry *) (Numeric->Memory + up) ; } for (j = 0 ; j < deg ; j++) { DEBUG4 ((" k "ID" col "ID" value\n", k, Pattern [j])) ; col = Pattern [j] ; ASSERT (col >= 0 && col < n_col) ; value = *xp++ ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [col]++ ; } } /* ------------------------------------------------------------------ */ /* make row k-1 of U in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ if (k == n1) break ; if (newUchain) { /* next row is a new Uchain */ deg = ulen ; DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ; ip = (Int *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = *ip++ ; DEBUG4 ((" k "ID" col "ID"\n", k-1, col)) ; ASSERT (k <= col) ; Pattern [j] = col ; } } else { deg -= ulen ; DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg)); ASSERT (deg >= 0) ; pos = Upos [k] ; if (pos != EMPTY) { /* add the pivot column */ DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ; ASSERT (pos >= 0 && pos <= deg) ; Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } } } /* singletons */ for (k = n1 - 1 ; k >= 0 ; k--) { deg = Uilen [k] ; DEBUG4 (("Singleton k "ID"\n", k)) ; if (deg > 0) { up = Uip [k] ; Usi = (Int *) (Numeric->Memory + up) ; up += UNITS (Int, deg) ; Uval = (Entry *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = Usi [j] ; value = Uval [j] ; DEBUG4 ((" k "ID" col "ID" value", k, col)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { Wi [col]++ ; } } } } /* ---------------------------------------------------------------------- */ /* construct the final column form of U */ /* ---------------------------------------------------------------------- */ /* create the column pointers */ unz2 = 0 ; for (col = 0 ; col < n_col ; col++) { Up [col] = unz2 ; unz2 += Wi [col] ; } Up [n_col] = unz2 ; DEBUG1 (("Numeric->unz "ID" npiv "ID" nnzpiv "ID" unz2 "ID"\n", Numeric->unz, npiv, Numeric->nnzpiv, unz2)) ; ASSERT (Numeric->unz + Numeric->nnzpiv == unz2) ; for (col = 0 ; col < n_col ; col++) { Wi [col] = Up [col+1] ; } /* add all of the diagonal entries */ for (col = 0 ; col < npiv ; col++) { if (IS_NONZERO (D [col])) { p = --(Wi [col]) ; Ui [p] = col ; #ifdef COMPLEX if (split) { Ux [p] = REAL_COMPONENT (D [col]) ; Uz [p] = IMAG_COMPONENT (D [col]) ; } else { Ux [2*p ] = REAL_COMPONENT (D [col]) ; Ux [2*p+1] = IMAG_COMPONENT (D [col]) ; } #else Ux [p] = D [col] ; #endif } } /* add all the entries from the rows of U */ deg = Numeric->ulen ; if (deg > 0) { /* make last pivot row of U (singular matrices only) */ for (j = 0 ; j < deg ; j++) { Pattern [j] = Numeric->Upattern [j] ; } } /* non-singletons */ for (k = npiv-1 ; k >= n1 ; k--) { /* ------------------------------------------------------------------ */ /* use row k of U */ /* ------------------------------------------------------------------ */ up = Uip [k] ; ulen = Uilen [k] ; newUchain = (up < 0) ; if (newUchain) { up = -up ; xp = (Entry *) (Numeric->Memory + up + UNITS (Int, ulen)) ; } else { xp = (Entry *) (Numeric->Memory + up) ; } xp += deg ; for (j = deg-1 ; j >= 0 ; j--) { DEBUG4 ((" k "ID" col "ID" value", k, Pattern [j])) ; col = Pattern [j] ; ASSERT (col >= 0 && col < n_col) ; value = *(--xp) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = --(Wi [col]) ; Ui [p] = k ; #ifdef COMPLEX if (split) { Ux [p] = REAL_COMPONENT (value) ; Uz [p] = IMAG_COMPONENT (value) ; } else { Ux [2*p ] = REAL_COMPONENT (value) ; Ux [2*p+1] = IMAG_COMPONENT (value) ; } #else Ux [p] = value ; #endif } } /* ------------------------------------------------------------------ */ /* make row k-1 of U in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ if (newUchain) { /* next row is a new Uchain */ deg = ulen ; DEBUG4 (("end of chain for row of U "ID" deg "ID"\n", k-1, deg)) ; ip = (Int *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = *ip++ ; DEBUG4 ((" k "ID" col "ID"\n", k-1, col)) ; ASSERT (k <= col) ; Pattern [j] = col ; } } else { deg -= ulen ; DEBUG4 (("middle of chain for row of U "ID" deg "ID"\n", k-1, deg)); ASSERT (deg >= 0) ; pos = Upos [k] ; if (pos != EMPTY) { /* add the pivot column */ DEBUG4 (("k "ID" add pivot entry at position "ID"\n", k, pos)) ; ASSERT (pos >= 0 && pos <= deg) ; Pattern [deg++] = Pattern [pos] ; Pattern [pos] = k ; } } } /* singletons */ for (k = n1 - 1 ; k >= 0 ; k--) { deg = Uilen [k] ; DEBUG4 (("Singleton k "ID"\n", k)) ; if (deg > 0) { up = Uip [k] ; Usi = (Int *) (Numeric->Memory + up) ; up += UNITS (Int, deg) ; Uval = (Entry *) (Numeric->Memory + up) ; for (j = 0 ; j < deg ; j++) { col = Usi [j] ; value = Uval [j] ; DEBUG4 ((" k "ID" col "ID" value", k, col)) ; EDEBUG4 (value) ; DEBUG4 (("\n")) ; if (IS_NONZERO (value)) { p = --(Wi [col]) ; Ui [p] = k ; #ifdef COMPLEX if (split) { Ux [p] = REAL_COMPONENT (value) ; Uz [p] = IMAG_COMPONENT (value) ; } else { Ux [2*p ] = REAL_COMPONENT (value) ; Ux [2*p+1] = IMAG_COMPONENT (value) ; } #else Ux [p] = value ; #endif } } } } #ifndef NDEBUG DEBUG6 (("U matrix:")) ; UMF_dump_col_matrix (Ux, #ifdef COMPLEX Uz, #endif Ui, Up, Numeric->n_row, n_col, Numeric->unz + Numeric->nnzpiv) ; #endif } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_lsolve.c0000644000175000017500000001022411674452555022170 0ustar sonnesonne/* ========================================================================== */ /* === UMF_lsolve =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* solves Lx = b, where L is the lower triangular factor of a matrix */ /* B is overwritten with the solution X. */ /* Returns the floating point operation count */ #include "umf_internal.h" #include "umf_lsolve.h" GLOBAL double UMF_lsolve ( NumericType *Numeric, Entry X [ ], /* b on input, solution x on output */ Int Pattern [ ] /* a work array of size n */ ) { Entry xk ; Entry *xp, *Lval ; Int k, deg, *ip, j, row, *Lpos, *Lilen, *Lip, llen, lp, newLchain, pos, npiv, n1, *Li ; /* ---------------------------------------------------------------------- */ if (Numeric->n_row != Numeric->n_col) return (0.) ; npiv = Numeric->npiv ; Lpos = Numeric->Lpos ; Lilen = Numeric->Lilen ; Lip = Numeric->Lip ; n1 = Numeric->n1 ; #ifndef NDEBUG DEBUG4 (("Lsolve start:\n")) ; for (j = 0 ; j < Numeric->n_row ; j++) { DEBUG4 (("Lsolve start "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } #endif /* ---------------------------------------------------------------------- */ /* singletons */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n1 ; k++) { DEBUG4 (("Singleton k "ID"\n", k)) ; xk = X [k] ; deg = Lilen [k] ; if (deg > 0 && IS_NONZERO (xk)) { lp = Lip [k] ; Li = (Int *) (Numeric->Memory + lp) ; lp += UNITS (Int, deg) ; Lval = (Entry *) (Numeric->Memory + lp) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Li [j], k)) ; EDEBUG4 (Lval [j]) ; DEBUG4 (("\n")) ; /* X [Li [j]] -= xk * Lval [j] ; */ MULT_SUB (X [Li [j]], xk, Lval [j]) ; } } } /* ---------------------------------------------------------------------- */ /* rest of L */ /* ---------------------------------------------------------------------- */ deg = 0 ; for (k = n1 ; k < npiv ; k++) { /* ------------------------------------------------------------------ */ /* make column of L in Pattern [0..deg-1] */ /* ------------------------------------------------------------------ */ lp = Lip [k] ; newLchain = (lp < 0) ; if (newLchain) { lp = -lp ; deg = 0 ; DEBUG4 (("start of chain for column of L\n")) ; } /* remove pivot row */ pos = Lpos [k] ; if (pos != EMPTY) { DEBUG4 ((" k "ID" removing row "ID" at position "ID"\n", k, Pattern [pos], pos)) ; ASSERT (!newLchain) ; ASSERT (deg > 0) ; ASSERT (pos >= 0 && pos < deg) ; ASSERT (Pattern [pos] == k) ; Pattern [pos] = Pattern [--deg] ; } /* concatenate the pattern */ ip = (Int *) (Numeric->Memory + lp) ; llen = Lilen [k] ; for (j = 0 ; j < llen ; j++) { row = *ip++ ; DEBUG4 ((" row "ID" k "ID"\n", row, k)) ; ASSERT (row > k) ; Pattern [deg++] = row ; } /* ------------------------------------------------------------------ */ /* use column k of L */ /* ------------------------------------------------------------------ */ xk = X [k] ; if (IS_NONZERO (xk)) { xp = (Entry *) (Numeric->Memory + lp + UNITS (Int, llen)) ; for (j = 0 ; j < deg ; j++) { DEBUG4 ((" row "ID" k "ID" value", Pattern [j], k)) ; EDEBUG4 (*xp) ; DEBUG4 (("\n")) ; /* X [Pattern [j]] -= xk * (*xp) ; */ MULT_SUB (X [Pattern [j]], xk, *xp) ; xp++ ; } } } #ifndef NDEBUG for (j = 0 ; j < Numeric->n_row ; j++) { DEBUG4 (("Lsolve done "ID": ", j)) ; EDEBUG4 (X [j]) ; DEBUG4 (("\n")) ; } DEBUG4 (("Lsolve done.\n")) ; #endif return (MULTSUB_FLOPS * ((double) Numeric->lnz)) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_alloc_head_block.c0000644000175000017500000000342611674452555024755 0ustar sonnesonne/* ========================================================================== */ /* === UMF_mem_alloc_head_block ============================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ /* allocate nunits from head of Numeric->Memory. No header allocated. */ /* Returns the index into Numeric->Memory if successful, or 0 on failure. */ #include "umf_internal.h" #include "umf_mem_alloc_head_block.h" GLOBAL Int UMF_mem_alloc_head_block ( NumericType *Numeric, Int nunits ) { Int p, usage ; DEBUG2 (("GET BLOCK: from head, size "ID" ", nunits)) ; ASSERT (Numeric != (NumericType *) NULL) ; ASSERT (Numeric->Memory != (Unit *) NULL) ; #ifndef NDEBUG if (UMF_allocfail) { /* pretend to fail, to test garbage_collection */ DEBUGm2 (("UMF_mem_alloc_head_block: pretend to fail\n")) ; UMF_allocfail = FALSE ; /* don't fail the next time */ return (0) ; } #endif if (nunits > (Numeric->itail - Numeric->ihead)) { DEBUG2 ((" failed\n")) ; return (0) ; } /* return p as an offset from Numeric->Memory */ p = Numeric->ihead ; Numeric->ihead += nunits ; DEBUG2 (("p: "ID"\n", p)) ; usage = Numeric->ihead + Numeric->tail_usage ; Numeric->max_usage = MAX (Numeric->max_usage, usage) ; return (p) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_report_perm.c0000644000175000017500000000402411674452555023223 0ustar sonnesonne/* ========================================================================== */ /* === UMF_report_perm ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.h" #include "umf_report_perm.h" #define PRINTF4U(params) { if (user || prl >= 4) PRINTF (params) ; } GLOBAL Int UMF_report_perm ( Int n, const Int P [ ], Int W [ ], /* workspace of size n */ Int prl, Int user ) { Int i, k, valid, prl1 ; ASSERT (prl >= 3) ; PRINTF4U (("permutation vector, n = "ID". ", n)) ; if (n <= 0) { PRINTF (("ERROR: length of permutation is <= 0\n\n")) ; return (UMFPACK_ERROR_n_nonpositive) ; } if (!P) { /* if P is (Int *) NULL, this is the identity permutation */ PRINTF (("(not present)\n\n")) ; return (UMFPACK_OK) ; } if (!W) { PRINTF (("ERROR: out of memory\n\n")) ; return (UMFPACK_ERROR_out_of_memory) ; } PRINTF4 (("\n")) ; for (i = 0 ; i < n ; i++) { W [i] = TRUE ; } prl1 = prl ; for (k = 0 ; k < n ; k++) { i = P [k] ; PRINTF4 ((" "ID" : "ID" ", INDEX (k), INDEX (i))) ; valid = (i >= 0 && i < n) ; if (valid) { valid = W [i] ; W [i] = FALSE ; } if (!valid) { /* out of range or duplicate entry */ PRINTF (("ERROR: invalid\n\n")) ; return (UMFPACK_ERROR_invalid_permutation) ; } PRINTF4 (("\n")) ; if (prl == 4 && k == 9 && n > 10) { PRINTF ((" ...\n")) ; prl-- ; } } prl = prl1 ; PRINTF4 ((" permutation vector ")) ; PRINTF4U (("OK\n\n")) ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_valid_symbolic.c0000644000175000017500000000317311674452555023671 0ustar sonnesonne/* ========================================================================== */ /* === UMF_valid_symbolic =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.h" #include "umf_valid_symbolic.h" /* Returns TRUE if the Symbolic object is valid, FALSE otherwise. */ /* The UMFPACK_report_symbolic routine does a more thorough check. */ GLOBAL Int UMF_valid_symbolic ( SymbolicType *Symbolic ) { /* This routine does not check the contents of the individual arrays, so */ /* it can miss some errors. All it checks for is the presence of the */ /* arrays, and the Symbolic "valid" entry. */ if (!Symbolic) { return (FALSE) ; } if (Symbolic->valid != SYMBOLIC_VALID) { /* Symbolic does not point to a SymbolicType object */ return (FALSE) ; } if (!Symbolic->Cperm_init || !Symbolic->Rperm_init || !Symbolic->Front_npivcol || !Symbolic->Front_1strow || !Symbolic->Front_leftmostdesc || !Symbolic->Front_parent || !Symbolic->Chain_start || !Symbolic->Chain_maxrows || !Symbolic->Chain_maxcols || Symbolic->n_row <= 0 || Symbolic->n_col <= 0) { return (FALSE) ; } return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_triplet.h0000644000175000017500000000322311674452555022355 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_triplet_map_x ( Int n_row, Int n_col, Int nz, const Int Ti [ ], const Int Tj [ ], Int Ap [ ], Int Ai [ ], Int Rp [ ], Int Rj [ ], Int W [ ], Int RowCount [ ] , const double Tx [ ] , double Ax [ ] , double Rx [ ] #ifdef COMPLEX , const double Tz [ ] , double Az [ ] , double Rz [ ] #endif , Int Map [ ] , Int Map2 [ ] ) ; GLOBAL Int UMF_triplet_map_nox ( Int n_row, Int n_col, Int nz, const Int Ti [ ], const Int Tj [ ], Int Ap [ ], Int Ai [ ], Int Rp [ ], Int Rj [ ], Int W [ ], Int RowCount [ ] , Int Map [ ] , Int Map2 [ ] ) ; GLOBAL Int UMF_triplet_nomap_x ( Int n_row, Int n_col, Int nz, const Int Ti [ ], const Int Tj [ ], Int Ap [ ], Int Ai [ ], Int Rp [ ], Int Rj [ ], Int W [ ], Int RowCount [ ] , const double Tx [ ] , double Ax [ ] , double Rx [ ] #ifdef COMPLEX , const double Tz [ ] , double Az [ ] , double Rz [ ] #endif ) ; GLOBAL Int UMF_triplet_nomap_nox ( Int n_row, Int n_col, Int nz, const Int Ti [ ], const Int Tj [ ], Int Ap [ ], Int Ai [ ], Int Rp [ ], Int Rj [ ], Int W [ ], Int RowCount [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_apply_order.h0000644000175000017500000000102111674452555023204 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_apply_order ( Int Front [ ], const Int Order [ ], Int Temp [ ], Int n_col, Int nfr ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_free_numeric.c0000644000175000017500000000360611674452555024174 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_free_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Free the entire Numeric object (consists of 11 to 13 * malloc'd objects. See UMFPACK_free_numeric.h for details. */ #include "umf_internal.h" #include "umf_free.h" GLOBAL void UMFPACK_free_numeric ( void **NumericHandle ) { NumericType *Numeric ; if (!NumericHandle) { return ; } Numeric = *((NumericType **) NumericHandle) ; if (!Numeric) { return ; } /* these 9 objects always exist */ (void) UMF_free ((void *) Numeric->D) ; (void) UMF_free ((void *) Numeric->Rperm) ; (void) UMF_free ((void *) Numeric->Cperm) ; (void) UMF_free ((void *) Numeric->Lpos) ; (void) UMF_free ((void *) Numeric->Lilen) ; (void) UMF_free ((void *) Numeric->Lip) ; (void) UMF_free ((void *) Numeric->Upos) ; (void) UMF_free ((void *) Numeric->Uilen) ; (void) UMF_free ((void *) Numeric->Uip) ; /* Rs does not exist if scaling was not performed */ (void) UMF_free ((void *) Numeric->Rs) ; /* Upattern can only exist for singular or rectangular matrices */ (void) UMF_free ((void *) Numeric->Upattern) ; /* these 2 objects always exist */ (void) UMF_free ((void *) Numeric->Memory) ; (void) UMF_free ((void *) Numeric) ; *NumericHandle = (void *) NULL ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_2by2.h0000644000175000017500000000157711674452555021462 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_2by2 ( Int n, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif double tol, Int scale, Int Cperm1 [ ], #ifndef NDEBUG Int Rperm1 [ ], #endif Int InvRperm [ ], Int n1, Int nempty, Int Degree [ ], Int P [ ], Int *p_nweak, Int *p_nmatched, Int Ri [ ], Int Rp [ ], double Rs [ ], Int Head [ ], Int Next [ ], Int Si [ ], Int Sp [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_init_front.h0000644000175000017500000000074311674452555023051 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_init_front ( NumericType *Numeric, WorkType *Work ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_set_stats.h0000644000175000017500000000133711674452555022707 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_set_stats ( double Info [ ], SymbolicType *Symbolic, double max_usage, double num_mem_size, double flops, double lnz, double unz, double maxfrsize, double ulen, double npiv, double maxnrows, double maxncols, Int scale, Int prefer_diagonal, Int what ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_free.h0000644000175000017500000000067611674452555021624 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void *UMF_free ( void *p ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_global.c0000644000175000017500000000742511674452555022774 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_global ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Global variables. UMFPACK uses these function pointers for several user-redefinable functions. The amd_* functions are defined in AMD/Source/amd_global.c. Function pointer default for mexFunction (see MATLAB/umfpackmex.c) ---------------- ------- --------------- amd_malloc malloc mxMalloc amd_free free mxFree amd_realloc realloc mxRealloc amd_calloc calloc mxCalloc amd_printf printf mexPrintf umfpack_hypot umf_hypot umf_hypot umfpack_divcomplex umf_divcomplex umf_divcomplex This routine is compiled just once for all four versions of UMFPACK (int/UF_long, double/complex). */ #include "umf_internal.h" double (*umfpack_hypot) (double, double) = umf_hypot ; int (*umfpack_divcomplex) (double, double, double, double, double *, double *) = umf_divcomplex ; /* ========================================================================== */ /* === umf_hypot ============================================================ */ /* ========================================================================== */ /* There is an equivalent routine called hypot in , which conforms * to ANSI C99. However, UMFPACK does not assume that ANSI C99 is available. * You can use the ANSI C99 hypot routine with: * * #include * umfpack_hypot = hypot ; * * prior to calling any UMFPACK routine. * * s = hypot (x,y) computes s = sqrt (x*x + y*y) but does so more accurately. * * The NaN case for the double relops x >= y and x+y == x is safely ignored. */ double umf_hypot (double x, double y) { double s, r ; x = SCALAR_ABS (x) ; y = SCALAR_ABS (y) ; if (x >= y) { if (x + y == x) { s = x ; } else { r = y / x ; s = x * sqrt (1.0 + r*r) ; } } else { if (y + x == y) { s = y ; } else { r = x / y ; s = y * sqrt (1.0 + r*r) ; } } return (s) ; } /* ========================================================================== */ /* === umf_divcomplex ======================================================= */ /* ========================================================================== */ /* c = a/b where c, a, and b are complex. The real and imaginary parts are * passed as separate arguments to this routine. The NaN case is ignored * for the double relop br >= bi. Returns TRUE (1) if the denominator is * zero, FALSE (0) otherwise. * * This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid * underflow and overflow. * * c can be the same variable as a or b. */ int umf_divcomplex ( double ar, double ai, /* real and imaginary parts of a */ double br, double bi, /* real and imaginary parts of b */ double *cr, double *ci /* real and imaginary parts of c */ ) { double tr, ti, r, den ; if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) { r = bi / br ; den = br + r * bi ; tr = (ar + ai * r) / den ; ti = (ai - ar * r) / den ; } else { r = br / bi ; den = r * br + bi ; tr = (ar * r + ai) / den ; ti = (ai * r - ar) / den ; } *cr = tr ; *ci = ti ; return (SCALAR_IS_ZERO (den)) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_init_memoryspace.h0000644000175000017500000000073211674452555025101 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_mem_init_memoryspace ( NumericType *Numeric ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_row_search.h0000644000175000017500000000152011674452555023024 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_row_search ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic, Int cdeg0, Int cdeg1, const Int Pattern [ ], const Int Pos [ ], Int pivrow [2], Int rdeg [2], Int W_i [ ], Int W_o [ ], Int prior_pivrow [2], const Entry Wxy [ ], Int pivcol, Int freebie [2] ) ; #define IN 0 #define OUT 1 #define IN_IN 0 #define IN_OUT 1 #define OUT_IN 2 #define OUT_OUT 3 cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_get_symbolic.c0000644000175000017500000001002311674452555024200 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_get_symbolic ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Gets the symbolic information held in the Symbolic object. See umfpack_get_symbolic.h for a more detailed description. */ #include "umf_internal.h" #include "umf_valid_symbolic.h" GLOBAL Int UMFPACK_get_symbolic ( Int *p_n_row, Int *p_n_col, Int *p_n1, /* number of singletons */ Int *p_nz, Int *p_nfr, Int *p_nchains, Int P [ ], Int Q [ ], Int Front_npivcol [ ], Int Front_parent [ ], Int Front_1strow [ ], Int Front_leftmostdesc [ ], Int Chain_start [ ], Int Chain_maxrows [ ], Int Chain_maxcols [ ], void *SymbolicHandle ) { SymbolicType *Symbolic ; Int k, n_row, n_col, n1, nfr, nchains, *p ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ Symbolic = (SymbolicType *) SymbolicHandle ; if (!UMF_valid_symbolic (Symbolic)) { return (UMFPACK_ERROR_invalid_Symbolic_object) ; } /* ---------------------------------------------------------------------- */ /* get contents of Symbolic */ /* ---------------------------------------------------------------------- */ n_row = Symbolic->n_row ; n_col = Symbolic->n_col ; n1 = Symbolic->n1 ; nfr = Symbolic->nfr ; nchains = Symbolic->nchains ; if (p_n_row) { *p_n_row = n_row ; } if (p_n_col) { *p_n_col = n_col ; } if (p_n1) { *p_n1 = n1 ; } if (p_nz) { *p_nz = Symbolic->nz ; } if (p_nfr) { *p_nfr = nfr ; } if (p_nchains) { *p_nchains = nchains ; } if (P != (Int *) NULL) { Int *Rperm_init, *Diagonal_map ; Rperm_init = Symbolic->Rperm_init ; Diagonal_map = Symbolic->Diagonal_map ; if (Diagonal_map != (Int *) NULL) { ASSERT (n_row == n_col) ; /* next pivot rows are found in the diagonal map */ for (k = 0 ; k < n_row ; k++) { P [k] = Rperm_init [Diagonal_map [k]] ; } } else { /* there is no diagonal map. */ for (k = 0 ; k < n_row ; k++) { P [k] = Rperm_init [k] ; } } } if (Q != (Int *) NULL) { p = Symbolic->Cperm_init ; for (k = 0 ; k < n_col ; k++) { Q [k] = p [k] ; } } if (Front_npivcol != (Int *) NULL) { p = Symbolic->Front_npivcol ; for (k = 0 ; k <= nfr ; k++) { Front_npivcol [k] = p [k] ; } } if (Front_parent != (Int *) NULL) { p = Symbolic->Front_parent ; for (k = 0 ; k <= nfr ; k++) { Front_parent [k] = p [k] ; } } if (Front_1strow != (Int *) NULL) { p = Symbolic->Front_1strow ; for (k = 0 ; k <= nfr ; k++) { Front_1strow [k] = p [k] ; } } if (Front_leftmostdesc != (Int *) NULL) { p = Symbolic->Front_leftmostdesc ; for (k = 0 ; k <= nfr ; k++) { Front_leftmostdesc [k] = p [k] ; } } if (Chain_start != (Int *) NULL) { p = Symbolic->Chain_start ; for (k = 0 ; k <= nchains ; k++) { Chain_start [k] = p [k] ; } } if (Chain_maxrows != (Int *) NULL) { p = Symbolic->Chain_maxrows ; for (k = 0 ; k < nchains ; k++) { Chain_maxrows [k] = p [k] ; } Chain_maxrows [nchains] = 0 ; } if (Chain_maxcols != (Int *) NULL) { p = Symbolic->Chain_maxcols ; for (k = 0 ; k < nchains ; k++) { Chain_maxcols [k] = p [k] ; } Chain_maxcols [nchains] = 0 ; } return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_info.c0000644000175000017500000005262511674452555024064 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_info ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints the Info array. See umfpack_report_info.h for details. */ #include "umf_internal.h" #define PRINT_INFO(format,x) \ { \ if (SCALAR_IS_NAN (x) || (!SCALAR_IS_LTZERO (x))) \ { \ PRINTF ((format, x)) ; \ } \ } /* RATIO macro uses a double relop, but ignore NaN case: */ #define RATIO(a,b,c) (((b) == 0) ? (c) : (((double) a)/((double) b))) /* ========================================================================== */ /* === print_ratio ========================================================== */ /* ========================================================================== */ PRIVATE void print_ratio ( char *what, char *format, double estimate, double actual ) { if (estimate < 0 && actual < 0) /* double relop, but ignore Nan case */ { return ; } PRINTF ((" %-27s", what)) ; if (estimate >= 0) /* double relop, but ignore Nan case */ { PRINTF ((format, estimate)) ; } else { PRINTF ((" -")) ; } if (actual >= 0) /* double relop, but ignore Nan case */ { PRINTF ((format, actual)) ; } else { PRINTF ((" -")) ; } if (estimate >= 0 && actual >= 0) /* double relop, but ignore Nan case */ { PRINTF ((" %5.0f%%\n", 100 * RATIO (actual, estimate, 1))) ; } else { PRINTF ((" -\n")) ; } } /* ========================================================================== */ /* === UMFPACK_report_info ================================================== */ /* ========================================================================== */ GLOBAL void UMFPACK_report_info ( const double Control [UMFPACK_CONTROL], const double Info [UMFPACK_INFO] ) { double lnz_est, unz_est, lunz_est, lnz, unz, lunz, tsym, tnum, fnum, tsolve, fsolve, ttot, ftot, twsym, twnum, twsolve, twtot, n2 ; Int n_row, n_col, n_inner, prl, is_sym ; /* ---------------------------------------------------------------------- */ /* get control settings and status to determine what to print */ /* ---------------------------------------------------------------------- */ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (!Info || prl < 2) { /* no output generated if Info is (double *) NULL */ /* or if prl is less than 2 */ return ; } /* ---------------------------------------------------------------------- */ /* print umfpack version */ /* ---------------------------------------------------------------------- */ PRINTF (("UMFPACK V%d.%d.%d (%s), Info:\n", UMFPACK_MAIN_VERSION, UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION, UMFPACK_DATE)) ; #ifndef NDEBUG PRINTF (( "**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n" )) ; #endif /* ---------------------------------------------------------------------- */ /* print run-time options */ /* ---------------------------------------------------------------------- */ #ifdef DINT PRINTF ((" matrix entry defined as: double\n")) ; PRINTF ((" Int (generic integer) defined as: int\n")) ; #endif #ifdef DLONG PRINTF ((" matrix entry defined as: double\n")) ; PRINTF ((" Int (generic integer) defined as: UF_long\n")) ; #endif #ifdef ZINT PRINTF ((" matrix entry defined as: double complex\n")) ; PRINTF ((" Int (generic integer) defined as: int\n")) ; #endif #ifdef ZLONG PRINTF ((" matrix entry defined as: double complex\n")) ; PRINTF ((" Int (generic integer) defined as: UF_long\n")) ; #endif /* ---------------------------------------------------------------------- */ /* print compile-time options */ /* ---------------------------------------------------------------------- */ PRINTF ((" BLAS library used: ")) ; #ifdef NBLAS PRINTF (("none. UMFPACK will be slow.\n")) ; #else PRINTF (("Fortran BLAS. size of BLAS integer: "ID"\n", (Int) (sizeof (BLAS_INT)))) ; #endif PRINTF ((" MATLAB: ")) ; #ifdef MATLAB_MEX_FILE PRINTF (("yes.\n")) ; #else #ifdef MATHWORKS PRINTF (("yes.\n")) ; #else PRINTF (("no.\n")) ; #endif #endif PRINTF ((" CPU timer: ")) ; #ifdef NO_TIMER PRINTF (("none.\n")) ; #else #ifndef NPOSIX PRINTF (("POSIX times ( ) routine.\n")) ; #else #ifdef GETRUSAGE PRINTF (("getrusage ( ) routine.\n")) ; #else PRINTF (("ANSI clock ( ) routine.\n")) ; #endif #endif #endif /* ---------------------------------------------------------------------- */ /* print n and nz */ /* ---------------------------------------------------------------------- */ n_row = (Int) Info [UMFPACK_NROW] ; n_col = (Int) Info [UMFPACK_NCOL] ; n_inner = MIN (n_row, n_col) ; PRINT_INFO (" number of rows in matrix A: "ID"\n", n_row) ; PRINT_INFO (" number of columns in matrix A: "ID"\n", n_col) ; PRINT_INFO (" entries in matrix A: "ID"\n", (Int) Info [UMFPACK_NZ]) ; PRINT_INFO (" memory usage reported in: "ID"-byte Units\n", (Int) Info [UMFPACK_SIZE_OF_UNIT]) ; PRINT_INFO (" size of int: "ID" bytes\n", (Int) Info [UMFPACK_SIZE_OF_INT]) ; PRINT_INFO (" size of UF_long: "ID" bytes\n", (Int) Info [UMFPACK_SIZE_OF_LONG]) ; PRINT_INFO (" size of pointer: "ID" bytes\n", (Int) Info [UMFPACK_SIZE_OF_POINTER]) ; PRINT_INFO (" size of numerical entry: "ID" bytes\n", (Int) Info [UMFPACK_SIZE_OF_ENTRY]) ; /* ---------------------------------------------------------------------- */ /* symbolic parameters */ /* ---------------------------------------------------------------------- */ if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_SYMMETRIC) { PRINTF (("\n strategy used: symmetric\n")) ; } else /* if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_UNSYMMETRIC)*/ { PRINTF (("\n strategy used: unsymmetric\n")) ; } #if 0 else if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_2BY2) { PRINTF (("\n strategy used: symmetric 2-by-2\n")); } #endif if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_AMD) { PRINTF ((" ordering used: amd on A+A'\n")) ; } else if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_COLAMD) { PRINTF ((" ordering used: colamd on A\n")) ; } else if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_GIVEN) { PRINTF ((" ordering used: provided by user\n")) ; } if (Info [UMFPACK_QFIXED] == 1) { PRINTF ((" modify Q during factorization: no\n")) ; } else if (Info [UMFPACK_QFIXED] == 0) { PRINTF ((" modify Q during factorization: yes\n")) ; } if (Info [UMFPACK_DIAG_PREFERRED] == 0) { PRINTF ((" prefer diagonal pivoting: no\n")) ; } else if (Info [UMFPACK_DIAG_PREFERRED] == 1) { PRINTF ((" prefer diagonal pivoting: yes\n")) ; } /* ---------------------------------------------------------------------- */ /* singleton statistics */ /* ---------------------------------------------------------------------- */ PRINT_INFO (" pivots with zero Markowitz cost: %0.f\n", Info [UMFPACK_COL_SINGLETONS] + Info [UMFPACK_ROW_SINGLETONS]) ; PRINT_INFO (" submatrix S after removing zero-cost pivots:\n" " number of \"dense\" rows: %.0f\n", Info [UMFPACK_NDENSE_ROW]) ; PRINT_INFO (" number of \"dense\" columns: %.0f\n", Info [UMFPACK_NDENSE_COL]) ; PRINT_INFO (" number of empty rows: %.0f\n", Info [UMFPACK_NEMPTY_ROW]) ; PRINT_INFO (" number of empty columns %.0f\n", Info [UMFPACK_NEMPTY_COL]) ; is_sym = Info [UMFPACK_S_SYMMETRIC] ; if (is_sym > 0) { PRINTF ((" submatrix S square and diagonal preserved\n")) ; } else if (is_sym == 0) { PRINTF ((" submatrix S not square or diagonal not preserved\n")); } /* ---------------------------------------------------------------------- */ /* statistics from amd_aat */ /* ---------------------------------------------------------------------- */ n2 = Info [UMFPACK_N2] ; if (n2 >= 0) { PRINTF ((" pattern of square submatrix S:\n")) ; } PRINT_INFO (" number rows and columns %.0f\n", n2) ; PRINT_INFO (" symmetry of nonzero pattern: %.6f\n", Info [UMFPACK_PATTERN_SYMMETRY]) ; PRINT_INFO (" nz in S+S' (excl. diagonal): %.0f\n", Info [UMFPACK_NZ_A_PLUS_AT]) ; PRINT_INFO (" nz on diagonal of matrix S: %.0f\n", Info [UMFPACK_NZDIAG]) ; if (Info [UMFPACK_NZDIAG] >= 0 && n2 > 0) { PRINTF ((" fraction of nz on diagonal: %.6f\n", Info [UMFPACK_NZDIAG] / n2)) ; } /* ---------------------------------------------------------------------- */ /* statistics from 2-by-2 permutation */ /* ---------------------------------------------------------------------- */ #if 0 PRINT_INFO (" 2-by-2 pivoting to place large entries on diagonal:\n" " # of small diagonal entries of S: %.0f\n", Info [UMFPACK_2BY2_NWEAK]) ; PRINT_INFO (" # unmatched: %.0f\n", Info [UMFPACK_2BY2_UNMATCHED]) ; PRINT_INFO (" symmetry of P2*S: %.6f\n", Info [UMFPACK_2BY2_PATTERN_SYMMETRY]) ; PRINT_INFO (" nz in P2*S+(P2*S)' (excl. diag.): %.0f\n", Info [UMFPACK_2BY2_NZ_PA_PLUS_PAT]) ; PRINT_INFO (" nz on diagonal of P2*S: %.0f\n", Info [UMFPACK_2BY2_NZDIAG]) ; if (Info [UMFPACK_2BY2_NZDIAG] >= 0 && n2 > 0) { PRINTF ((" fraction of nz on diag of P2*S: %.6f\n", Info [UMFPACK_2BY2_NZDIAG] / n2)) ; } #endif /* ---------------------------------------------------------------------- */ /* statistics from AMD */ /* ---------------------------------------------------------------------- */ if (Info [UMFPACK_ORDERING_USED] == UMFPACK_ORDERING_AMD) { double dmax = Info [UMFPACK_SYMMETRIC_DMAX] ; PRINTF ((" AMD statistics, for strict diagonal pivoting:\n")) ; PRINT_INFO (" est. flops for LU factorization: %.5e\n", Info [UMFPACK_SYMMETRIC_FLOPS]) ; PRINT_INFO (" est. nz in L+U (incl. diagonal): %.0f\n", Info [UMFPACK_SYMMETRIC_LUNZ]) ; PRINT_INFO (" est. largest front (# entries): %.0f\n", dmax*dmax) ; PRINT_INFO (" est. max nz in any column of L: %.0f\n", dmax) ; PRINT_INFO ( " number of \"dense\" rows/columns in S+S': %.0f\n", Info [UMFPACK_SYMMETRIC_NDENSE]) ; } /* ---------------------------------------------------------------------- */ /* symbolic factorization */ /* ---------------------------------------------------------------------- */ tsym = Info [UMFPACK_SYMBOLIC_TIME] ; twsym = Info [UMFPACK_SYMBOLIC_WALLTIME] ; PRINT_INFO (" symbolic factorization defragmentations: %.0f\n", Info [UMFPACK_SYMBOLIC_DEFRAG]) ; PRINT_INFO (" symbolic memory usage (Units): %.0f\n", Info [UMFPACK_SYMBOLIC_PEAK_MEMORY]) ; PRINT_INFO (" symbolic memory usage (MBytes): %.1f\n", MBYTES (Info [UMFPACK_SYMBOLIC_PEAK_MEMORY])) ; PRINT_INFO (" Symbolic size (Units): %.0f\n", Info [UMFPACK_SYMBOLIC_SIZE]) ; PRINT_INFO (" Symbolic size (MBytes): %.0f\n", MBYTES (Info [UMFPACK_SYMBOLIC_SIZE])) ; PRINT_INFO (" symbolic factorization CPU time (sec): %.2f\n", tsym) ; PRINT_INFO (" symbolic factorization wallclock time(sec): %.2f\n", twsym) ; /* ---------------------------------------------------------------------- */ /* scaling, from numerical factorization */ /* ---------------------------------------------------------------------- */ if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_NONE) { PRINTF (("\n matrix scaled: no\n")) ; } else if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_SUM) { PRINTF (("\n matrix scaled: yes ")) ; PRINTF (("(divided each row by sum of abs values in each row)\n")) ; PRINTF ((" minimum sum (abs (rows of A)): %.5e\n", Info [UMFPACK_RSMIN])) ; PRINTF ((" maximum sum (abs (rows of A)): %.5e\n", Info [UMFPACK_RSMAX])) ; } else if (Info [UMFPACK_WAS_SCALED] == UMFPACK_SCALE_MAX) { PRINTF (("\n matrix scaled: yes ")) ; PRINTF (("(divided each row by max abs value in each row)\n")) ; PRINTF ((" minimum max (abs (rows of A)): %.5e\n", Info [UMFPACK_RSMIN])) ; PRINTF ((" maximum max (abs (rows of A)): %.5e\n", Info [UMFPACK_RSMAX])) ; } /* ---------------------------------------------------------------------- */ /* estimate/actual in symbolic/numeric factorization */ /* ---------------------------------------------------------------------- */ /* double relop, but ignore NaN case: */ if (Info [UMFPACK_SYMBOLIC_DEFRAG] >= 0 /* UMFPACK_*symbolic called */ || Info [UMFPACK_NUMERIC_DEFRAG] >= 0) /* UMFPACK_numeric called */ { PRINTF (("\n symbolic/numeric factorization: upper bound")) ; PRINTF ((" actual %%\n")) ; PRINTF ((" variable-sized part of Numeric object:\n")) ; } print_ratio (" initial size (Units)", " %20.0f", Info [UMFPACK_VARIABLE_INIT_ESTIMATE], Info [UMFPACK_VARIABLE_INIT]) ; print_ratio (" peak size (Units)", " %20.0f", Info [UMFPACK_VARIABLE_PEAK_ESTIMATE], Info [UMFPACK_VARIABLE_PEAK]) ; print_ratio (" final size (Units)", " %20.0f", Info [UMFPACK_VARIABLE_FINAL_ESTIMATE], Info [UMFPACK_VARIABLE_FINAL]) ; print_ratio ("Numeric final size (Units)", " %20.0f", Info [UMFPACK_NUMERIC_SIZE_ESTIMATE], Info [UMFPACK_NUMERIC_SIZE]) ; print_ratio ("Numeric final size (MBytes)", " %20.1f", MBYTES (Info [UMFPACK_NUMERIC_SIZE_ESTIMATE]), MBYTES (Info [UMFPACK_NUMERIC_SIZE])) ; print_ratio ("peak memory usage (Units)", " %20.0f", Info [UMFPACK_PEAK_MEMORY_ESTIMATE], Info [UMFPACK_PEAK_MEMORY]) ; print_ratio ("peak memory usage (MBytes)", " %20.1f", MBYTES (Info [UMFPACK_PEAK_MEMORY_ESTIMATE]), MBYTES (Info [UMFPACK_PEAK_MEMORY])) ; print_ratio ("numeric factorization flops", " %20.5e", Info [UMFPACK_FLOPS_ESTIMATE], Info [UMFPACK_FLOPS]) ; lnz_est = Info [UMFPACK_LNZ_ESTIMATE] ; unz_est = Info [UMFPACK_UNZ_ESTIMATE] ; if (lnz_est >= 0 && unz_est >= 0) /* double relop, but ignore NaN case */ { lunz_est = lnz_est + unz_est - n_inner ; } else { lunz_est = EMPTY ; } lnz = Info [UMFPACK_LNZ] ; unz = Info [UMFPACK_UNZ] ; if (lnz >= 0 && unz >= 0) /* double relop, but ignore NaN case */ { lunz = lnz + unz - n_inner ; } else { lunz = EMPTY ; } print_ratio ("nz in L (incl diagonal)", " %20.0f", lnz_est, lnz) ; print_ratio ("nz in U (incl diagonal)", " %20.0f", unz_est, unz) ; print_ratio ("nz in L+U (incl diagonal)", " %20.0f", lunz_est, lunz) ; print_ratio ("largest front (# entries)", " %20.0f", Info [UMFPACK_MAX_FRONT_SIZE_ESTIMATE], Info [UMFPACK_MAX_FRONT_SIZE]) ; print_ratio ("largest # rows in front", " %20.0f", Info [UMFPACK_MAX_FRONT_NROWS_ESTIMATE], Info [UMFPACK_MAX_FRONT_NROWS]) ; print_ratio ("largest # columns in front", " %20.0f", Info [UMFPACK_MAX_FRONT_NCOLS_ESTIMATE], Info [UMFPACK_MAX_FRONT_NCOLS]) ; /* ---------------------------------------------------------------------- */ /* numeric factorization */ /* ---------------------------------------------------------------------- */ tnum = Info [UMFPACK_NUMERIC_TIME] ; twnum = Info [UMFPACK_NUMERIC_WALLTIME] ; fnum = Info [UMFPACK_FLOPS] ; PRINT_INFO ("\n initial allocation ratio used: %0.3g\n", Info [UMFPACK_ALLOC_INIT_USED]) ; PRINT_INFO (" # of forced updates due to frontal growth: %.0f\n", Info [UMFPACK_FORCED_UPDATES]) ; PRINT_INFO (" number of off-diagonal pivots: %.0f\n", Info [UMFPACK_NOFF_DIAG]) ; PRINT_INFO (" nz in L (incl diagonal), if none dropped %.0f\n", Info [UMFPACK_ALL_LNZ]) ; PRINT_INFO (" nz in U (incl diagonal), if none dropped %.0f\n", Info [UMFPACK_ALL_UNZ]) ; PRINT_INFO (" number of small entries dropped %.0f\n", Info [UMFPACK_NZDROPPED]) ; PRINT_INFO (" nonzeros on diagonal of U: %.0f\n", Info [UMFPACK_UDIAG_NZ]) ; PRINT_INFO (" min abs. value on diagonal of U: %.2e\n", Info [UMFPACK_UMIN]) ; PRINT_INFO (" max abs. value on diagonal of U: %.2e\n", Info [UMFPACK_UMAX]) ; PRINT_INFO (" estimate of reciprocal of condition number: %.2e\n", Info [UMFPACK_RCOND]) ; PRINT_INFO (" indices in compressed pattern: %.0f\n", Info [UMFPACK_COMPRESSED_PATTERN]) ; PRINT_INFO (" numerical values stored in Numeric object: %.0f\n", Info [UMFPACK_LU_ENTRIES]) ; PRINT_INFO (" numeric factorization defragmentations: %.0f\n", Info [UMFPACK_NUMERIC_DEFRAG]) ; PRINT_INFO (" numeric factorization reallocations: %.0f\n", Info [UMFPACK_NUMERIC_REALLOC]) ; PRINT_INFO (" costly numeric factorization reallocations: %.0f\n", Info [UMFPACK_NUMERIC_COSTLY_REALLOC]) ; PRINT_INFO (" numeric factorization CPU time (sec): %.2f\n", tnum) ; PRINT_INFO (" numeric factorization wallclock time (sec): %.2f\n", twnum) ; #define TMIN 0.001 if (tnum > TMIN && fnum > 0) { PRINT_INFO ( " numeric factorization mflops (CPU time): %.2f\n", 1e-6 * fnum / tnum) ; } if (twnum > TMIN && fnum > 0) { PRINT_INFO ( " numeric factorization mflops (wallclock): %.2f\n", 1e-6 * fnum / twnum) ; } ttot = EMPTY ; ftot = fnum ; if (tsym >= TMIN && tnum >= 0) { ttot = tsym + tnum ; PRINT_INFO (" symbolic + numeric CPU time (sec): %.2f\n", ttot) ; if (ftot > 0 && ttot > TMIN) { PRINT_INFO ( " symbolic + numeric mflops (CPU time): %.2f\n", 1e-6 * ftot / ttot) ; } } twtot = EMPTY ; if (twsym >= TMIN && twnum >= TMIN) { twtot = twsym + twnum ; PRINT_INFO (" symbolic + numeric wall clock time (sec): %.2f\n", twtot) ; if (ftot > 0 && twtot > TMIN) { PRINT_INFO ( " symbolic + numeric mflops (wall clock): %.2f\n", 1e-6 * ftot / twtot) ; } } /* ---------------------------------------------------------------------- */ /* solve */ /* ---------------------------------------------------------------------- */ tsolve = Info [UMFPACK_SOLVE_TIME] ; twsolve = Info [UMFPACK_SOLVE_WALLTIME] ; fsolve = Info [UMFPACK_SOLVE_FLOPS] ; PRINT_INFO ("\n solve flops: %.5e\n", fsolve) ; PRINT_INFO (" iterative refinement steps taken: %.0f\n", Info [UMFPACK_IR_TAKEN]) ; PRINT_INFO (" iterative refinement steps attempted: %.0f\n", Info [UMFPACK_IR_ATTEMPTED]) ; PRINT_INFO (" sparse backward error omega1: %.2e\n", Info [UMFPACK_OMEGA1]) ; PRINT_INFO (" sparse backward error omega2: %.2e\n", Info [UMFPACK_OMEGA2]) ; PRINT_INFO (" solve CPU time (sec): %.2f\n", tsolve) ; PRINT_INFO (" solve wall clock time (sec): %.2f\n", twsolve) ; if (fsolve > 0 && tsolve > TMIN) { PRINT_INFO ( " solve mflops (CPU time): %.2f\n", 1e-6 * fsolve / tsolve) ; } if (fsolve > 0 && twsolve > TMIN) { PRINT_INFO ( " solve mflops (wall clock time): %.2f\n", 1e-6 * fsolve / twsolve) ; } if (ftot >= 0 && fsolve >= 0) { ftot += fsolve ; PRINT_INFO ( "\n total symbolic + numeric + solve flops: %.5e\n", ftot) ; } if (tsolve >= TMIN) { if (ttot >= TMIN && ftot >= 0) { ttot += tsolve ; PRINT_INFO ( " total symbolic + numeric + solve CPU time: %.2f\n", ttot) ; if (ftot > 0 && ttot > TMIN) { PRINT_INFO ( " total symbolic + numeric + solve mflops (CPU): %.2f\n", 1e-6 * ftot / ttot) ; } } } if (twsolve >= TMIN) { if (twtot >= TMIN && ftot >= 0) { twtot += tsolve ; PRINT_INFO ( " total symbolic+numeric+solve wall clock time: %.2f\n", twtot) ; if (ftot > 0 && twtot > TMIN) { PRINT_INFO ( " total symbolic+numeric+solve mflops(wallclock) %.2f\n", 1e-6 * ftot / twtot) ; } } } PRINTF (("\n")) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_solve.h0000644000175000017500000000140211674452555022017 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_solve ( Int sys, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], double Xx [ ], const double Bx [ ], #ifdef COMPLEX const double Az [ ], double Xz [ ], const double Bz [ ], #endif NumericType *Numeric, Int irstep, double Info [UMFPACK_INFO], Int Pattern [ ], double SolveWork [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_mem_free_tail_block.h0000644000175000017500000000074411674452555024641 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_mem_free_tail_block ( NumericType *Numeric, Int i ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_fsize.h0000644000175000017500000000104111674452555022006 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_fsize ( Int nn, Int MaxFsize [ ], Int Fnrows [ ], Int Fncols [ ], Int Parent [ ], Int Npiv [ ] ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.c0000644000175000017500000002113311674452555023232 0ustar sonnesonne/* ========================================================================== */ /* === UMF_start_front ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Allocate the initial frontal matrix working array for a single chain. The * front does not have to be big enough, since if it's too small it will get * reallocated. The size computed here is just an estimate. */ #include "umf_internal.h" #include "umf_start_front.h" #include "umf_grow_front.h" GLOBAL Int UMF_start_front /* returns TRUE if successful, FALSE otherwise */ ( Int chain, NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) { double maxbytes ; Int fnrows_max, fncols_max, fnr2, fnc2, fsize, fcurr_size, maxfrsize, overflow, nb, f, cdeg ; nb = Symbolic->nb ; fnrows_max = Symbolic->Chain_maxrows [chain] ; fncols_max = Symbolic->Chain_maxcols [chain] ; DEBUGm2 (("Start Front for chain "ID". fnrows_max "ID" fncols_max "ID"\n", chain, fnrows_max, fncols_max)) ; Work->fnrows_max = fnrows_max ; Work->fncols_max = fncols_max ; Work->any_skip = FALSE ; maxbytes = sizeof (Entry) * (double) (fnrows_max + nb) * (double) (fncols_max + nb) ; fcurr_size = Work->fcurr_size ; if (Symbolic->prefer_diagonal) { /* Get a rough upper bound on the degree of the first pivot column in * this front. Note that Col_degree is not maintained if diagonal * pivoting is preferred. For most matrices, the first pivot column * of the first frontal matrix of a new chain has only one tuple in * it anyway, so this bound is exact in that case. */ Int col, tpi, e, *E, *Col_tuples, *Col_tlen, *Cols ; Tuple *tp, *tpend ; Unit *Memory, *p ; Element *ep ; E = Work->E ; Memory = Numeric->Memory ; Col_tuples = Numeric->Lip ; Col_tlen = Numeric->Lilen ; col = Work->nextcand ; tpi = Col_tuples [col] ; tp = (Tuple *) Memory + tpi ; tpend = tp + Col_tlen [col] ; cdeg = 0 ; DEBUGm3 (("\n=============== start front: col "ID" tlen "ID"\n", col, Col_tlen [col])) ; for ( ; tp < tpend ; tp++) { DEBUG1 (("Tuple ("ID","ID")\n", tp->e, tp->f)) ; e = tp->e ; if (!E [e]) continue ; f = tp->f ; p = Memory + E [e] ; ep = (Element *) p ; p += UNITS (Element, 1) ; Cols = (Int *) p ; if (Cols [f] == EMPTY) continue ; DEBUG1 ((" nrowsleft "ID"\n", ep->nrowsleft)) ; cdeg += ep->nrowsleft ; } #ifndef NDEBUG DEBUGm3 (("start front cdeg: "ID" col "ID"\n", cdeg, col)) ; UMF_dump_rowcol (1, Numeric, Work, col, FALSE) ; #endif /* cdeg is now the rough upper bound on the degree of the next pivot * column. */ /* If AMD was called, we know the maximum number of nonzeros in any * column of L. Use this as an upper bound for cdeg, but add 2 to * account for a small amount of off-diagonal pivoting. */ if (Symbolic->amd_dmax > 0) { cdeg = MIN (cdeg, Symbolic->amd_dmax) ; } /* Increase it to account for larger columns later on. * Also ensure that it's larger than zero. */ cdeg += 2 ; /* cdeg cannot be larger than fnrows_max */ cdeg = MIN (cdeg, fnrows_max) ; } else { /* don't do the above cdeg computation */ cdeg = 0 ; } DEBUGm2 (("fnrows max "ID" fncols_max "ID"\n", fnrows_max, fncols_max)) ; /* the current frontal matrix is empty */ ASSERT (Work->fnrows == 0 && Work->fncols == 0 && Work->fnpiv == 0) ; /* maximum row dimension is always odd, to avoid bad cache effects */ ASSERT (fnrows_max >= 0) ; ASSERT (fnrows_max % 2 == 1) ; /* ---------------------------------------------------------------------- * allocate working array for current frontal matrix: * minimum size: 1-by-1 * maximum size: fnrows_max-by-fncols_max * desired size: * * if Numeric->front_alloc_init >= 0: * * for unsymmetric matrices: * Numeric->front_alloc_init * (fnrows_max-by-fncols_max) * * for symmetric matrices (diagonal pivoting preference, actually): * Numeric->front_alloc_init * (fnrows_max-by-fncols_max), or * cdeg*cdeg, whichever is smaller. * * if Numeric->front_alloc_init < 0: * allocate a front of size -Numeric->front_alloc_init. * * Allocate the whole thing if it's small (less than 2*nb^2). Make sure the * leading dimension of the frontal matrix is odd. * * Also allocate the nb-by-nb LU block, the dr-by-nb L block, and the * nb-by-dc U block. * ---------------------------------------------------------------------- */ /* get the maximum front size, avoiding integer overflow */ overflow = INT_OVERFLOW (maxbytes) ; if (overflow) { /* :: int overflow, max front size :: */ maxfrsize = Int_MAX / sizeof (Entry) ; } else { maxfrsize = (fnrows_max + nb) * (fncols_max + nb) ; } ASSERT (!INT_OVERFLOW ((double) maxfrsize * sizeof (Entry))) ; if (Numeric->front_alloc_init < 0) { /* allocate a front of -Numeric->front_alloc_init entries */ fsize = -Numeric->front_alloc_init ; fsize = MAX (1, fsize) ; } else { if (INT_OVERFLOW (Numeric->front_alloc_init * maxbytes)) { /* :: int overflow, requested front size :: */ fsize = Int_MAX / sizeof (Entry) ; } else { fsize = Numeric->front_alloc_init * maxfrsize ; } if (cdeg > 0) { /* diagonal pivoting is in use. cdeg was computed above */ Int fsize2 ; /* add the L and U blocks */ cdeg += nb ; if (INT_OVERFLOW (((double) cdeg * (double) cdeg) * sizeof (Entry))) { /* :: int overflow, symmetric front size :: */ fsize2 = Int_MAX / sizeof (Entry) ; } else { fsize2 = MAX (cdeg * cdeg, fcurr_size) ; } fsize = MIN (fsize, fsize2) ; } } fsize = MAX (fsize, 2*nb*nb) ; /* fsize and maxfrsize are now safe from integer overflow. They both * include the size of the pivot blocks. */ ASSERT (!INT_OVERFLOW ((double) fsize * sizeof (Entry))) ; Work->fnrows_new = 0 ; Work->fncols_new = 0 ; /* desired size is fnr2-by-fnc2 (includes L and U blocks): */ DEBUGm2 ((" fsize "ID" fcurr_size "ID"\n", fsize, fcurr_size)) ; DEBUGm2 ((" maxfrsize "ID" fnr_curr "ID" fnc_curr "ID"\n", maxfrsize, Work->fnr_curr, Work->fnc_curr)) ; if (fsize >= maxfrsize && !overflow) { /* max working array is small, allocate all of it */ fnr2 = fnrows_max + nb ; fnc2 = fncols_max + nb ; fsize = maxfrsize ; DEBUGm1 ((" sufficient for ("ID"+"ID")-by-("ID"+"ID")\n", fnrows_max, nb, fncols_max, nb)) ; } else { /* allocate a smaller working array */ if (fnrows_max <= fncols_max) { fnr2 = (Int) sqrt ((double) fsize) ; /* make sure fnr2 is odd */ fnr2 = MAX (fnr2, 1) ; if (fnr2 % 2 == 0) fnr2++ ; fnr2 = MIN (fnr2, fnrows_max + nb) ; fnc2 = fsize / fnr2 ; } else { fnc2 = (Int) sqrt ((double) fsize) ; fnc2 = MIN (fnc2, fncols_max + nb) ; fnr2 = fsize / fnc2 ; /* make sure fnr2 is odd */ fnr2 = MAX (fnr2, 1) ; if (fnr2 % 2 == 0) { fnr2++ ; fnc2 = fsize / fnr2 ; } } DEBUGm1 ((" smaller "ID"-by-"ID"\n", fnr2, fnc2)) ; } fnr2 = MIN (fnr2, fnrows_max + nb) ; fnc2 = MIN (fnc2, fncols_max + nb) ; ASSERT (fnr2 % 2 == 1) ; ASSERT (fnr2 * fnc2 <= fsize) ; fnr2 -= nb ; fnc2 -= nb ; ASSERT (fnr2 >= 0) ; ASSERT (fnc2 >= 0) ; if (fsize > fcurr_size) { DEBUGm1 ((" Grow front \n")) ; Work->do_grow = TRUE ; if (!UMF_grow_front (Numeric, fnr2, fnc2, Work, -1)) { /* since the minimum front size is 1-by-1, it would be nearly * impossible to run out of memory here. */ DEBUGm4 (("out of memory: start front\n")) ; return (FALSE) ; } } else { /* use the existing front */ DEBUGm1 ((" existing front ok\n")) ; Work->fnr_curr = fnr2 ; Work->fnc_curr = fnc2 ; Work->Flblock = Work->Flublock + nb * nb ; Work->Fublock = Work->Flblock + nb * fnr2 ; Work->Fcblock = Work->Fublock + nb * fnc2 ; } ASSERT (Work->Flblock == Work->Flublock + Work->nb*Work->nb) ; ASSERT (Work->Fublock == Work->Flblock + Work->fnr_curr*Work->nb) ; ASSERT (Work->Fcblock == Work->Fublock + Work->nb*Work->fnc_curr) ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umfpack_report_matrix.c0000644000175000017500000001225511674452555024430 0ustar sonnesonne/* ========================================================================== */ /* === UMFPACK_report_matrix ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints a column or row-oriented matrix. See umfpack_report_matrix.h for details. */ #include "umf_internal.h" GLOBAL Int UMFPACK_report_matrix ( Int n_row, Int n_col, const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif Int col_form, /* 1: column form, 0: row form */ const double Control [UMFPACK_CONTROL] ) { Entry a ; Int prl, i, k, length, ilast, p, nz, prl1, p1, p2, n, n_i, do_values ; char *vector, *index ; #ifdef COMPLEX Int split = SPLIT (Az) ; #endif /* ---------------------------------------------------------------------- */ /* determine the form, and check if inputs exist */ /* ---------------------------------------------------------------------- */ prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl <= 2) { return (UMFPACK_OK) ; } if (col_form) { vector = "column" ; /* column vectors */ index = "row" ; /* with row indices */ n = n_col ; n_i = n_row ; } else { vector = "row" ; /* row vectors */ index = "column" ; /* with column indices */ n = n_row ; n_i = n_col ; } PRINTF (("%s-form matrix, n_row "ID" n_col "ID", ", vector, n_row, n_col)) ; if (n_row <= 0 || n_col <= 0) { PRINTF (("ERROR: n_row <= 0 or n_col <= 0\n\n")) ; return (UMFPACK_ERROR_n_nonpositive) ; } if (!Ap) { PRINTF (("ERROR: Ap missing\n\n")) ; return (UMFPACK_ERROR_argument_missing) ; } nz = Ap [n] ; PRINTF (("nz = "ID". ", nz)) ; if (nz < 0) { PRINTF (("ERROR: number of entries < 0\n\n")) ; return (UMFPACK_ERROR_invalid_matrix) ; } if (Ap [0] != 0) { PRINTF (("ERROR: Ap ["ID"] = "ID" must be "ID"\n\n", (Int) INDEX (0), INDEX (Ap [0]), (Int) INDEX (0))) ; return (UMFPACK_ERROR_invalid_matrix) ; } if (!Ai) { PRINTF (("ERROR: Ai missing\n\n")) ; return (UMFPACK_ERROR_argument_missing) ; } do_values = Ax != (double *) NULL ; PRINTF4 (("\n")) ; /* ---------------------------------------------------------------------- */ /* check the row/column pointers, Ap */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < n ; k++) { if (Ap [k] < 0) { PRINTF (("ERROR: Ap ["ID"] < 0\n\n", INDEX (k))) ; return (UMFPACK_ERROR_invalid_matrix) ; } if (Ap [k] > nz) { PRINTF (("ERROR: Ap ["ID"] > size of Ai\n\n", INDEX (k))) ; return (UMFPACK_ERROR_invalid_matrix) ; } } for (k = 0 ; k < n ; k++) { length = Ap [k+1] - Ap [k] ; if (length < 0) { PRINTF (("ERROR: # entries in %s "ID" is < 0\n\n", vector, INDEX (k))) ; return (UMFPACK_ERROR_invalid_matrix) ; } } /* ---------------------------------------------------------------------- */ /* print each vector */ /* ---------------------------------------------------------------------- */ prl1 = prl ; for (k = 0 ; k < n ; k++) { /* if prl is 4, print the first 10 entries of the first 10 vectors */ if (k < 10) { prl = prl1 ; } /* get the vector pointers */ p1 = Ap [k] ; p2 = Ap [k+1] ; length = p2 - p1 ; PRINTF4 (("\n %s "ID": start: "ID" end: "ID" entries: "ID"\n", vector, INDEX (k), p1, p2-1, length)) ; ilast = EMPTY ; for (p = p1 ; p < p2 ; p++) { i = Ai [p] ; PRINTF4 (("\t%s "ID" ", index, INDEX (i))) ; if (do_values && prl >= 4) { PRINTF ((":")) ; ASSIGN (a, Ax, Az, p, split) ; PRINT_ENTRY (a) ; } if (i < 0 || i >= n_i) { PRINTF ((" ERROR: %s index "ID" out of range in %s "ID"\n\n", index, INDEX (i), vector, INDEX (k))) ; return (UMFPACK_ERROR_invalid_matrix) ; } if (i <= ilast) { PRINTF ((" ERROR: %s index "ID" out of order (or duplicate) in " "%s "ID"\n\n", index, INDEX (i), vector, INDEX (k))) ; return (UMFPACK_ERROR_invalid_matrix) ; } PRINTF4 (("\n")) ; /* truncate printout, but continue to check matrix */ if (prl == 4 && (p - p1) == 9 && length > 10) { PRINTF4 (("\t...\n")) ; prl-- ; } ilast = i ; } /* truncate printout, but continue to check matrix */ if (prl == 4 && k == 9 && n > 10) { PRINTF4 (("\n ...\n")) ; prl-- ; } } prl = prl1 ; /* ---------------------------------------------------------------------- */ /* return the status of the matrix */ /* ---------------------------------------------------------------------- */ PRINTF4 ((" %s-form matrix ", vector)) ; PRINTF (("OK\n\n")) ; return (UMFPACK_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_report_vector.h0000644000175000017500000000104011674452555023562 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_report_vector ( Int n, const double Xx [ ], const double Xz [ ], Int prl, Int user, Int scalar ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_dump.h0000644000175000017500000000761711674452555021652 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* umf_dump.h: debugging definitions. */ #ifndef NDEBUG GLOBAL void UMF_dump_dense ( Entry *C, Int dim, Int m, Int n ) ; GLOBAL void UMF_dump_element ( NumericType *Numeric, WorkType *Work, Int e, Int clean ) ; GLOBAL void UMF_dump_rowcol ( Int dump_which, NumericType *Numeric, WorkType *Work, Int dump_index, Int check_degree ) ; GLOBAL void UMF_dump_matrix ( NumericType *Numeric, WorkType *Work, Int check_degree ) ; GLOBAL void UMF_dump_current_front ( NumericType *Numeric, WorkType *Work, Int check ) ; GLOBAL void UMF_dump_lu ( NumericType *Numeric ) ; GLOBAL void UMF_dump_memory ( NumericType *Numeric ) ; GLOBAL void UMF_dump_packed_memory ( NumericType *Numeric, WorkType *Work ) ; GLOBAL void UMF_dump_col_matrix ( const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif const Int Ai [ ], const Int Ap [ ], Int n_row, Int n_col, Int nz ) ; GLOBAL void UMF_dump_chain ( Int frontid, Int Front_parent [ ], Int Front_npivcol [ ], Int Front_nrows [ ], Int Front_ncols [ ], Int nfr ) ; GLOBAL void UMF_dump_rowmerge ( NumericType *Numeric, SymbolicType *Symbolic, WorkType *Work ) ; GLOBAL void UMF_dump_start ( void ) ; GLOBAL void UMF_dump_diagonal_map ( Int Diagonal_map [ ], Int Diagonal_imap [ ], Int nn ) ; #define UMF_DBMAX 50000 #ifndef EXTERN #define EXTERN extern #endif GLOBAL EXTERN Int UMF_debug ; GLOBAL EXTERN Int UMF_allocfail ; GLOBAL EXTERN double UMF_gprob ; #define DEBUGk(k,params) { if (UMF_debug >= (k)) { PRINTF (params) ; } } #define DEBUGm4(params) DEBUGk (-4, params) #define DEBUGm3(params) DEBUGk (-3, params) #define DEBUGm2(params) DEBUGk (-2, params) #define DEBUGm1(params) DEBUGk (-1, params) #define DEBUG0(params) DEBUGk (0, params) #define DEBUG1(params) DEBUGk (1, params) #define DEBUG2(params) DEBUGk (2, params) #define DEBUG3(params) DEBUGk (3, params) #define DEBUG4(params) DEBUGk (4, params) #define DEBUG5(params) DEBUGk (5, params) #define DEBUG6(params) DEBUGk (6, params) #define DEBUG7(params) DEBUGk (7, params) #define DEBUG8(params) DEBUGk (8, params) #define DEBUG9(params) DEBUGk (9, params) #define EDEBUGk(k,a) { if (UMF_debug >= (k)) { PRINT_ENTRY (a) ; } } #define EDEBUG0(a) EDEBUGk (0, a) #define EDEBUG1(a) EDEBUGk (1, a) #define EDEBUG2(a) EDEBUGk (2, a) #define EDEBUG3(a) EDEBUGk (3, a) #define EDEBUG4(a) EDEBUGk (4, a) #define EDEBUG5(a) EDEBUGk (5, a) #define EDEBUG6(a) EDEBUGk (6, a) #define EDEBUG7(a) EDEBUGk (7, a) #define EDEBUG8(a) EDEBUGk (8, a) #define EDEBUG9(a) EDEBUGk (9, a) /* ASSERT defined in amd_dump.h */ #else /* ========================================================================== */ /* === No debugging ========================================================= */ /* ========================================================================== */ /* turn off all debugging macros */ #define DEBUGk(k,params) #define DEBUGm4(params) #define DEBUGm3(params) #define DEBUGm2(params) #define DEBUGm1(params) #define DEBUG0(params) #define DEBUG1(params) #define DEBUG2(params) #define DEBUG3(params) #define DEBUG4(params) #define DEBUG5(params) #define DEBUG6(params) #define DEBUG7(params) #define DEBUG8(params) #define DEBUG9(params) #define EDEBUGk(k,a) #define EDEBUG0(a) #define EDEBUG1(a) #define EDEBUG2(a) #define EDEBUG3(a) #define EDEBUG4(a) #define EDEBUG5(a) #define EDEBUG6(a) #define EDEBUG7(a) #define EDEBUG8(a) #define EDEBUG9(a) #endif /* NDEBUG */ cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_start_front.h0000644000175000017500000000101711674452555023236 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_start_front ( Int chain, NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Source/umf_kernel_init.h0000644000175000017500000000116411674452555023177 0ustar sonnesonne/* -------------------------------------------------------------------------- */ /* UMFPACK Copyright (c) Timothy A. Davis, CISE, */ /* Univ. of Florida. All Rights Reserved. See ../Doc/License for License. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_kernel_init ( const Int Ap [ ], const Int Ai [ ], const double Ax [ ], #ifdef COMPLEX const double Az [ ], #endif NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Lib/0000755000175000017500000000000011674452555017120 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Lib/libumfpack.def0000644000175000017500000000447511674452555021727 0ustar sonnesonneLIBRARY libumfpack.dll EXPORTS umfpack_di_col_to_triplet umfpack_di_defaults umfpack_di_free_numeric umfpack_di_free_symbolic umfpack_di_get_numeric umfpack_di_get_lunz umfpack_di_get_symbolic umfpack_di_get_determinant umfpack_di_numeric umfpack_di_qsymbolic umfpack_di_report_control umfpack_di_report_info umfpack_di_report_matrix umfpack_di_report_numeric umfpack_di_report_perm umfpack_di_report_status umfpack_di_report_symbolic umfpack_di_report_triplet umfpack_di_report_vector umfpack_di_solve umfpack_di_wsolve umfpack_di_symbolic umfpack_di_transpose umfpack_di_triplet_to_col umfpack_di_scale umfpack_dl_col_to_triplet umfpack_dl_defaults umfpack_dl_free_numeric umfpack_dl_free_symbolic umfpack_dl_get_numeric umfpack_dl_get_lunz umfpack_dl_get_symbolic umfpack_dl_get_determinant umfpack_dl_numeric umfpack_dl_qsymbolic umfpack_dl_report_control umfpack_dl_report_info umfpack_dl_report_matrix umfpack_dl_report_numeric umfpack_dl_report_perm umfpack_dl_report_status umfpack_dl_report_symbolic umfpack_dl_report_triplet umfpack_dl_report_vector umfpack_dl_solve umfpack_dl_wsolve umfpack_dl_symbolic umfpack_dl_transpose umfpack_dl_triplet_to_col umfpack_dl_scale umfpack_zi_col_to_triplet umfpack_zi_defaults umfpack_zi_free_numeric umfpack_zi_free_symbolic umfpack_zi_get_numeric umfpack_zi_get_lunz umfpack_zi_get_symbolic umfpack_zi_get_determinant umfpack_zi_numeric umfpack_zi_qsymbolic umfpack_zi_report_control umfpack_zi_report_info umfpack_zi_report_matrix umfpack_zi_report_numeric umfpack_zi_report_perm umfpack_zi_report_status umfpack_zi_report_symbolic umfpack_zi_report_triplet umfpack_zi_report_vector umfpack_zi_solve umfpack_zi_wsolve umfpack_zi_symbolic umfpack_zi_transpose umfpack_zi_triplet_to_col umfpack_zi_scale umfpack_zl_col_to_triplet umfpack_zl_defaults umfpack_zl_free_numeric umfpack_zl_free_symbolic umfpack_zl_get_numeric umfpack_zl_get_lunz umfpack_zl_get_symbolic umfpack_zl_get_determinant umfpack_zl_numeric umfpack_zl_qsymbolic umfpack_zl_report_control umfpack_zl_report_info umfpack_zl_report_matrix umfpack_zl_report_numeric umfpack_zl_report_perm umfpack_zl_report_status umfpack_zl_report_symbolic umfpack_zl_report_triplet umfpack_zl_report_vector umfpack_zl_solve umfpack_zl_wsolve umfpack_zl_symbolic umfpack_zl_transpose umfpack_zl_triplet_to_col umfpack_zl_scale umfpack_timer umfpack_tic umfpack_toc cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Lib/Makefile0000644000175000017500000007656211674452555020600 0ustar sonnesonne#------------------------------------------------------------------------------- # UMFPACK Makefile for compiling on Unix systems (for original make only) #------------------------------------------------------------------------------- # This is a very ugly Makefile, and is only provided for those who do not # have GNU make. Note that it is not used if you have GNU make. It ignores # dependency checking and just compiles everything. default: everything include ../../UFconfig/UFconfig.mk C = $(CC) $(CFLAGS) $(UMFPACK_CONFIG) -I../Include -I../../AMD/Include \ -I../Source everything: $(C) -c ../Source/umfpack_global.c -o umfpack_gn_global.o $(C) -DDINT -c ../Source/umf_analyze.c -o umf_i_analyze.o $(C) -DDINT -c ../Source/umf_apply_order.c -o umf_i_apply_order.o $(C) -DDINT -c ../Source/umf_colamd.c -o umf_i_colamd.o $(C) -DDINT -c ../Source/umf_free.c -o umf_i_free.o $(C) -DDINT -c ../Source/umf_fsize.c -o umf_i_fsize.o $(C) -DDINT -c ../Source/umf_is_permutation.c -o umf_i_is_permutation.o $(C) -DDINT -c ../Source/umf_malloc.c -o umf_i_malloc.o $(C) -DDINT -c ../Source/umf_realloc.c -o umf_i_realloc.o $(C) -DDINT -c ../Source/umf_report_perm.c -o umf_i_report_perm.o $(C) -DDINT -c ../Source/umf_singletons.c -o umf_i_singletons.o $(C) -DDLONG -c ../Source/umf_analyze.c -o umf_l_analyze.o $(C) -DDLONG -c ../Source/umf_apply_order.c -o umf_l_apply_order.o $(C) -DDLONG -c ../Source/umf_colamd.c -o umf_l_colamd.o $(C) -DDLONG -c ../Source/umf_free.c -o umf_l_free.o $(C) -DDLONG -c ../Source/umf_fsize.c -o umf_l_fsize.o $(C) -DDLONG -c ../Source/umf_is_permutation.c -o umf_l_is_permutation.o $(C) -DDLONG -c ../Source/umf_malloc.c -o umf_l_malloc.o $(C) -DDLONG -c ../Source/umf_realloc.c -o umf_l_realloc.o $(C) -DDLONG -c ../Source/umf_report_perm.c -o umf_l_report_perm.o $(C) -DDLONG -c ../Source/umf_singletons.c -o umf_l_singletons.o $(C) -c ../Source/umfpack_timer.c -o umfpack_gn_timer.o $(C) -c ../Source/umfpack_tictoc.c -o umfpack_gn_tictoc.o $(C) -DDINT -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c -o umf_di_lhsolve.o $(C) -DDINT -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c -o umf_di_uhsolve.o $(C) -DDINT -DDO_MAP -c ../Source/umf_triplet.c -o umf_di_triplet_map_nox.o $(C) -DDINT -DDO_VALUES -c ../Source/umf_triplet.c -o umf_di_triplet_nomap_x.o $(C) -DDINT -c ../Source/umf_triplet.c -o umf_di_triplet_nomap_nox.o $(C) -DDINT -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c -o umf_di_triplet_map_x.o $(C) -DDINT -DFIXQ -c ../Source/umf_assemble.c -o umf_di_assemble_fixq.o $(C) -DDINT -DDROP -c ../Source/umf_store_lu.c -o umf_di_store_lu_drop.o $(C) -DDINT -c ../Source/umf_assemble.c -o umf_di_assemble.o $(C) -DDINT -c ../Source/umf_blas3_update.c -o umf_di_blas3_update.o $(C) -DDINT -c ../Source/umf_build_tuples.c -o umf_di_build_tuples.o $(C) -DDINT -c ../Source/umf_create_element.c -o umf_di_create_element.o $(C) -DDINT -c ../Source/umf_dump.c -o umf_di_dump.o $(C) -DDINT -c ../Source/umf_extend_front.c -o umf_di_extend_front.o $(C) -DDINT -c ../Source/umf_garbage_collection.c -o umf_di_garbage_collection.o $(C) -DDINT -c ../Source/umf_get_memory.c -o umf_di_get_memory.o $(C) -DDINT -c ../Source/umf_init_front.c -o umf_di_init_front.o $(C) -DDINT -c ../Source/umf_kernel.c -o umf_di_kernel.o $(C) -DDINT -c ../Source/umf_kernel_init.c -o umf_di_kernel_init.o $(C) -DDINT -c ../Source/umf_kernel_wrapup.c -o umf_di_kernel_wrapup.o $(C) -DDINT -c ../Source/umf_local_search.c -o umf_di_local_search.o $(C) -DDINT -c ../Source/umf_lsolve.c -o umf_di_lsolve.o $(C) -DDINT -c ../Source/umf_ltsolve.c -o umf_di_ltsolve.o $(C) -DDINT -c ../Source/umf_mem_alloc_element.c -o umf_di_mem_alloc_element.o $(C) -DDINT -c ../Source/umf_mem_alloc_head_block.c -o umf_di_mem_alloc_head_block.o $(C) -DDINT -c ../Source/umf_mem_alloc_tail_block.c -o umf_di_mem_alloc_tail_block.o $(C) -DDINT -c ../Source/umf_mem_free_tail_block.c -o umf_di_mem_free_tail_block.o $(C) -DDINT -c ../Source/umf_mem_init_memoryspace.c -o umf_di_mem_init_memoryspace.o $(C) -DDINT -c ../Source/umf_report_vector.c -o umf_di_report_vector.o $(C) -DDINT -c ../Source/umf_row_search.c -o umf_di_row_search.o $(C) -DDINT -c ../Source/umf_scale_column.c -o umf_di_scale_column.o $(C) -DDINT -c ../Source/umf_set_stats.c -o umf_di_set_stats.o $(C) -DDINT -c ../Source/umf_solve.c -o umf_di_solve.o $(C) -DDINT -c ../Source/umf_symbolic_usage.c -o umf_di_symbolic_usage.o $(C) -DDINT -c ../Source/umf_transpose.c -o umf_di_transpose.o $(C) -DDINT -c ../Source/umf_tuple_lengths.c -o umf_di_tuple_lengths.o $(C) -DDINT -c ../Source/umf_usolve.c -o umf_di_usolve.o $(C) -DDINT -c ../Source/umf_utsolve.c -o umf_di_utsolve.o $(C) -DDINT -c ../Source/umf_valid_numeric.c -o umf_di_valid_numeric.o $(C) -DDINT -c ../Source/umf_valid_symbolic.c -o umf_di_valid_symbolic.o $(C) -DDINT -c ../Source/umf_grow_front.c -o umf_di_grow_front.o $(C) -DDINT -c ../Source/umf_start_front.c -o umf_di_start_front.o $(C) -DDINT -c ../Source/umf_2by2.c -o umf_di_2by2.o $(C) -DDINT -c ../Source/umf_store_lu.c -o umf_di_store_lu.o $(C) -DDINT -c ../Source/umf_scale.c -o umf_di_scale.o $(C) -DDINT -DWSOLVE -c ../Source/umfpack_solve.c -o umfpack_di_wsolve.o $(C) -DDINT -c ../Source/umfpack_col_to_triplet.c -o umfpack_di_col_to_triplet.o $(C) -DDINT -c ../Source/umfpack_defaults.c -o umfpack_di_defaults.o $(C) -DDINT -c ../Source/umfpack_free_numeric.c -o umfpack_di_free_numeric.o $(C) -DDINT -c ../Source/umfpack_free_symbolic.c -o umfpack_di_free_symbolic.o $(C) -DDINT -c ../Source/umfpack_get_numeric.c -o umfpack_di_get_numeric.o $(C) -DDINT -c ../Source/umfpack_get_lunz.c -o umfpack_di_get_lunz.o $(C) -DDINT -c ../Source/umfpack_get_symbolic.c -o umfpack_di_get_symbolic.o $(C) -DDINT -c ../Source/umfpack_get_determinant.c -o umfpack_di_get_determinant.o $(C) -DDINT -c ../Source/umfpack_numeric.c -o umfpack_di_numeric.o $(C) -DDINT -c ../Source/umfpack_qsymbolic.c -o umfpack_di_qsymbolic.o $(C) -DDINT -c ../Source/umfpack_report_control.c -o umfpack_di_report_control.o $(C) -DDINT -c ../Source/umfpack_report_info.c -o umfpack_di_report_info.o $(C) -DDINT -c ../Source/umfpack_report_matrix.c -o umfpack_di_report_matrix.o $(C) -DDINT -c ../Source/umfpack_report_numeric.c -o umfpack_di_report_numeric.o $(C) -DDINT -c ../Source/umfpack_report_perm.c -o umfpack_di_report_perm.o $(C) -DDINT -c ../Source/umfpack_report_status.c -o umfpack_di_report_status.o $(C) -DDINT -c ../Source/umfpack_report_symbolic.c -o umfpack_di_report_symbolic.o $(C) -DDINT -c ../Source/umfpack_report_triplet.c -o umfpack_di_report_triplet.o $(C) -DDINT -c ../Source/umfpack_report_vector.c -o umfpack_di_report_vector.o $(C) -DDINT -c ../Source/umfpack_solve.c -o umfpack_di_solve.o $(C) -DDINT -c ../Source/umfpack_symbolic.c -o umfpack_di_symbolic.o $(C) -DDINT -c ../Source/umfpack_transpose.c -o umfpack_di_transpose.o $(C) -DDINT -c ../Source/umfpack_triplet_to_col.c -o umfpack_di_triplet_to_col.o $(C) -DDINT -c ../Source/umfpack_scale.c -o umfpack_di_scale.o $(C) -DDINT -c ../Source/umfpack_load_numeric.c -o umfpack_di_load_numeric.o $(C) -DDINT -c ../Source/umfpack_save_numeric.c -o umfpack_di_save_numeric.o $(C) -DDINT -c ../Source/umfpack_load_symbolic.c -o umfpack_di_load_symbolic.o $(C) -DDINT -c ../Source/umfpack_save_symbolic.c -o umfpack_di_save_symbolic.o $(C) -DDLONG -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c -o umf_dl_lhsolve.o $(C) -DDLONG -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c -o umf_dl_uhsolve.o $(C) -DDLONG -DDO_MAP -c ../Source/umf_triplet.c -o umf_dl_triplet_map_nox.o $(C) -DDLONG -DDO_VALUES -c ../Source/umf_triplet.c -o umf_dl_triplet_nomap_x.o $(C) -DDLONG -c ../Source/umf_triplet.c -o umf_dl_triplet_nomap_nox.o $(C) -DDLONG -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c -o umf_dl_triplet_map_x.o $(C) -DDLONG -DFIXQ -c ../Source/umf_assemble.c -o umf_dl_assemble_fixq.o $(C) -DDLONG -DDROP -c ../Source/umf_store_lu.c -o umf_dl_store_lu_drop.o $(C) -DDLONG -c ../Source/umf_assemble.c -o umf_dl_assemble.o $(C) -DDLONG -c ../Source/umf_blas3_update.c -o umf_dl_blas3_update.o $(C) -DDLONG -c ../Source/umf_build_tuples.c -o umf_dl_build_tuples.o $(C) -DDLONG -c ../Source/umf_create_element.c -o umf_dl_create_element.o $(C) -DDLONG -c ../Source/umf_dump.c -o umf_dl_dump.o $(C) -DDLONG -c ../Source/umf_extend_front.c -o umf_dl_extend_front.o $(C) -DDLONG -c ../Source/umf_garbage_collection.c -o umf_dl_garbage_collection.o $(C) -DDLONG -c ../Source/umf_get_memory.c -o umf_dl_get_memory.o $(C) -DDLONG -c ../Source/umf_init_front.c -o umf_dl_init_front.o $(C) -DDLONG -c ../Source/umf_kernel.c -o umf_dl_kernel.o $(C) -DDLONG -c ../Source/umf_kernel_init.c -o umf_dl_kernel_init.o $(C) -DDLONG -c ../Source/umf_kernel_wrapup.c -o umf_dl_kernel_wrapup.o $(C) -DDLONG -c ../Source/umf_local_search.c -o umf_dl_local_search.o $(C) -DDLONG -c ../Source/umf_lsolve.c -o umf_dl_lsolve.o $(C) -DDLONG -c ../Source/umf_ltsolve.c -o umf_dl_ltsolve.o $(C) -DDLONG -c ../Source/umf_mem_alloc_element.c -o umf_dl_mem_alloc_element.o $(C) -DDLONG -c ../Source/umf_mem_alloc_head_block.c -o umf_dl_mem_alloc_head_block.o $(C) -DDLONG -c ../Source/umf_mem_alloc_tail_block.c -o umf_dl_mem_alloc_tail_block.o $(C) -DDLONG -c ../Source/umf_mem_free_tail_block.c -o umf_dl_mem_free_tail_block.o $(C) -DDLONG -c ../Source/umf_mem_init_memoryspace.c -o umf_dl_mem_init_memoryspace.o $(C) -DDLONG -c ../Source/umf_report_vector.c -o umf_dl_report_vector.o $(C) -DDLONG -c ../Source/umf_row_search.c -o umf_dl_row_search.o $(C) -DDLONG -c ../Source/umf_scale_column.c -o umf_dl_scale_column.o $(C) -DDLONG -c ../Source/umf_set_stats.c -o umf_dl_set_stats.o $(C) -DDLONG -c ../Source/umf_solve.c -o umf_dl_solve.o $(C) -DDLONG -c ../Source/umf_symbolic_usage.c -o umf_dl_symbolic_usage.o $(C) -DDLONG -c ../Source/umf_transpose.c -o umf_dl_transpose.o $(C) -DDLONG -c ../Source/umf_tuple_lengths.c -o umf_dl_tuple_lengths.o $(C) -DDLONG -c ../Source/umf_usolve.c -o umf_dl_usolve.o $(C) -DDLONG -c ../Source/umf_utsolve.c -o umf_dl_utsolve.o $(C) -DDLONG -c ../Source/umf_valid_numeric.c -o umf_dl_valid_numeric.o $(C) -DDLONG -c ../Source/umf_valid_symbolic.c -o umf_dl_valid_symbolic.o $(C) -DDLONG -c ../Source/umf_grow_front.c -o umf_dl_grow_front.o $(C) -DDLONG -c ../Source/umf_start_front.c -o umf_dl_start_front.o $(C) -DDLONG -c ../Source/umf_2by2.c -o umf_dl_2by2.o $(C) -DDLONG -c ../Source/umf_store_lu.c -o umf_dl_store_lu.o $(C) -DDLONG -c ../Source/umf_scale.c -o umf_dl_scale.o $(C) -DDLONG -DWSOLVE -c ../Source/umfpack_solve.c -o umfpack_dl_wsolve.o $(C) -DDLONG -c ../Source/umfpack_col_to_triplet.c -o umfpack_dl_col_to_triplet.o $(C) -DDLONG -c ../Source/umfpack_defaults.c -o umfpack_dl_defaults.o $(C) -DDLONG -c ../Source/umfpack_free_numeric.c -o umfpack_dl_free_numeric.o $(C) -DDLONG -c ../Source/umfpack_free_symbolic.c -o umfpack_dl_free_symbolic.o $(C) -DDLONG -c ../Source/umfpack_get_numeric.c -o umfpack_dl_get_numeric.o $(C) -DDLONG -c ../Source/umfpack_get_lunz.c -o umfpack_dl_get_lunz.o $(C) -DDLONG -c ../Source/umfpack_get_symbolic.c -o umfpack_dl_get_symbolic.o $(C) -DDLONG -c ../Source/umfpack_get_determinant.c -o umfpack_dl_get_determinant.o $(C) -DDLONG -c ../Source/umfpack_numeric.c -o umfpack_dl_numeric.o $(C) -DDLONG -c ../Source/umfpack_qsymbolic.c -o umfpack_dl_qsymbolic.o $(C) -DDLONG -c ../Source/umfpack_report_control.c -o umfpack_dl_report_control.o $(C) -DDLONG -c ../Source/umfpack_report_info.c -o umfpack_dl_report_info.o $(C) -DDLONG -c ../Source/umfpack_report_matrix.c -o umfpack_dl_report_matrix.o $(C) -DDLONG -c ../Source/umfpack_report_numeric.c -o umfpack_dl_report_numeric.o $(C) -DDLONG -c ../Source/umfpack_report_perm.c -o umfpack_dl_report_perm.o $(C) -DDLONG -c ../Source/umfpack_report_status.c -o umfpack_dl_report_status.o $(C) -DDLONG -c ../Source/umfpack_report_symbolic.c -o umfpack_dl_report_symbolic.o $(C) -DDLONG -c ../Source/umfpack_report_triplet.c -o umfpack_dl_report_triplet.o $(C) -DDLONG -c ../Source/umfpack_report_vector.c -o umfpack_dl_report_vector.o $(C) -DDLONG -c ../Source/umfpack_solve.c -o umfpack_dl_solve.o $(C) -DDLONG -c ../Source/umfpack_symbolic.c -o umfpack_dl_symbolic.o $(C) -DDLONG -c ../Source/umfpack_transpose.c -o umfpack_dl_transpose.o $(C) -DDLONG -c ../Source/umfpack_triplet_to_col.c -o umfpack_dl_triplet_to_col.o $(C) -DDLONG -c ../Source/umfpack_scale.c -o umfpack_dl_scale.o $(C) -DDLONG -c ../Source/umfpack_load_numeric.c -o umfpack_dl_load_numeric.o $(C) -DDLONG -c ../Source/umfpack_save_numeric.c -o umfpack_dl_save_numeric.o $(C) -DDLONG -c ../Source/umfpack_load_symbolic.c -o umfpack_dl_load_symbolic.o $(C) -DDLONG -c ../Source/umfpack_save_symbolic.c -o umfpack_dl_save_symbolic.o $(C) -DZINT -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c -o umf_zi_lhsolve.o $(C) -DZINT -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c -o umf_zi_uhsolve.o $(C) -DZINT -DDO_MAP -c ../Source/umf_triplet.c -o umf_zi_triplet_map_nox.o $(C) -DZINT -DDO_VALUES -c ../Source/umf_triplet.c -o umf_zi_triplet_nomap_x.o $(C) -DZINT -c ../Source/umf_triplet.c -o umf_zi_triplet_nomap_nox.o $(C) -DZINT -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c -o umf_zi_triplet_map_x.o $(C) -DZINT -DFIXQ -c ../Source/umf_assemble.c -o umf_zi_assemble_fixq.o $(C) -DZINT -DDROP -c ../Source/umf_store_lu.c -o umf_zi_store_lu_drop.o $(C) -DZINT -c ../Source/umf_assemble.c -o umf_zi_assemble.o $(C) -DZINT -c ../Source/umf_blas3_update.c -o umf_zi_blas3_update.o $(C) -DZINT -c ../Source/umf_build_tuples.c -o umf_zi_build_tuples.o $(C) -DZINT -c ../Source/umf_create_element.c -o umf_zi_create_element.o $(C) -DZINT -c ../Source/umf_dump.c -o umf_zi_dump.o $(C) -DZINT -c ../Source/umf_extend_front.c -o umf_zi_extend_front.o $(C) -DZINT -c ../Source/umf_garbage_collection.c -o umf_zi_garbage_collection.o $(C) -DZINT -c ../Source/umf_get_memory.c -o umf_zi_get_memory.o $(C) -DZINT -c ../Source/umf_init_front.c -o umf_zi_init_front.o $(C) -DZINT -c ../Source/umf_kernel.c -o umf_zi_kernel.o $(C) -DZINT -c ../Source/umf_kernel_init.c -o umf_zi_kernel_init.o $(C) -DZINT -c ../Source/umf_kernel_wrapup.c -o umf_zi_kernel_wrapup.o $(C) -DZINT -c ../Source/umf_local_search.c -o umf_zi_local_search.o $(C) -DZINT -c ../Source/umf_lsolve.c -o umf_zi_lsolve.o $(C) -DZINT -c ../Source/umf_ltsolve.c -o umf_zi_ltsolve.o $(C) -DZINT -c ../Source/umf_mem_alloc_element.c -o umf_zi_mem_alloc_element.o $(C) -DZINT -c ../Source/umf_mem_alloc_head_block.c -o umf_zi_mem_alloc_head_block.o $(C) -DZINT -c ../Source/umf_mem_alloc_tail_block.c -o umf_zi_mem_alloc_tail_block.o $(C) -DZINT -c ../Source/umf_mem_free_tail_block.c -o umf_zi_mem_free_tail_block.o $(C) -DZINT -c ../Source/umf_mem_init_memoryspace.c -o umf_zi_mem_init_memoryspace.o $(C) -DZINT -c ../Source/umf_report_vector.c -o umf_zi_report_vector.o $(C) -DZINT -c ../Source/umf_row_search.c -o umf_zi_row_search.o $(C) -DZINT -c ../Source/umf_scale_column.c -o umf_zi_scale_column.o $(C) -DZINT -c ../Source/umf_set_stats.c -o umf_zi_set_stats.o $(C) -DZINT -c ../Source/umf_solve.c -o umf_zi_solve.o $(C) -DZINT -c ../Source/umf_symbolic_usage.c -o umf_zi_symbolic_usage.o $(C) -DZINT -c ../Source/umf_transpose.c -o umf_zi_transpose.o $(C) -DZINT -c ../Source/umf_tuple_lengths.c -o umf_zi_tuple_lengths.o $(C) -DZINT -c ../Source/umf_usolve.c -o umf_zi_usolve.o $(C) -DZINT -c ../Source/umf_utsolve.c -o umf_zi_utsolve.o $(C) -DZINT -c ../Source/umf_valid_numeric.c -o umf_zi_valid_numeric.o $(C) -DZINT -c ../Source/umf_valid_symbolic.c -o umf_zi_valid_symbolic.o $(C) -DZINT -c ../Source/umf_grow_front.c -o umf_zi_grow_front.o $(C) -DZINT -c ../Source/umf_start_front.c -o umf_zi_start_front.o $(C) -DZINT -c ../Source/umf_2by2.c -o umf_zi_2by2.o $(C) -DZINT -c ../Source/umf_store_lu.c -o umf_zi_store_lu.o $(C) -DZINT -c ../Source/umf_scale.c -o umf_zi_scale.o $(C) -DZINT -DWSOLVE -c ../Source/umfpack_solve.c -o umfpack_zi_wsolve.o $(C) -DZINT -c ../Source/umfpack_col_to_triplet.c -o umfpack_zi_col_to_triplet.o $(C) -DZINT -c ../Source/umfpack_defaults.c -o umfpack_zi_defaults.o $(C) -DZINT -c ../Source/umfpack_free_numeric.c -o umfpack_zi_free_numeric.o $(C) -DZINT -c ../Source/umfpack_free_symbolic.c -o umfpack_zi_free_symbolic.o $(C) -DZINT -c ../Source/umfpack_get_numeric.c -o umfpack_zi_get_numeric.o $(C) -DZINT -c ../Source/umfpack_get_lunz.c -o umfpack_zi_get_lunz.o $(C) -DZINT -c ../Source/umfpack_get_symbolic.c -o umfpack_zi_get_symbolic.o $(C) -DZINT -c ../Source/umfpack_get_determinant.c -o umfpack_zi_get_determinant.o $(C) -DZINT -c ../Source/umfpack_numeric.c -o umfpack_zi_numeric.o $(C) -DZINT -c ../Source/umfpack_qsymbolic.c -o umfpack_zi_qsymbolic.o $(C) -DZINT -c ../Source/umfpack_report_control.c -o umfpack_zi_report_control.o $(C) -DZINT -c ../Source/umfpack_report_info.c -o umfpack_zi_report_info.o $(C) -DZINT -c ../Source/umfpack_report_matrix.c -o umfpack_zi_report_matrix.o $(C) -DZINT -c ../Source/umfpack_report_numeric.c -o umfpack_zi_report_numeric.o $(C) -DZINT -c ../Source/umfpack_report_perm.c -o umfpack_zi_report_perm.o $(C) -DZINT -c ../Source/umfpack_report_status.c -o umfpack_zi_report_status.o $(C) -DZINT -c ../Source/umfpack_report_symbolic.c -o umfpack_zi_report_symbolic.o $(C) -DZINT -c ../Source/umfpack_report_triplet.c -o umfpack_zi_report_triplet.o $(C) -DZINT -c ../Source/umfpack_report_vector.c -o umfpack_zi_report_vector.o $(C) -DZINT -c ../Source/umfpack_solve.c -o umfpack_zi_solve.o $(C) -DZINT -c ../Source/umfpack_symbolic.c -o umfpack_zi_symbolic.o $(C) -DZINT -c ../Source/umfpack_transpose.c -o umfpack_zi_transpose.o $(C) -DZINT -c ../Source/umfpack_triplet_to_col.c -o umfpack_zi_triplet_to_col.o $(C) -DZINT -c ../Source/umfpack_scale.c -o umfpack_zi_scale.o $(C) -DZINT -c ../Source/umfpack_load_numeric.c -o umfpack_zi_load_numeric.o $(C) -DZINT -c ../Source/umfpack_save_numeric.c -o umfpack_zi_save_numeric.o $(C) -DZINT -c ../Source/umfpack_load_symbolic.c -o umfpack_zi_load_symbolic.o $(C) -DZINT -c ../Source/umfpack_save_symbolic.c -o umfpack_zi_save_symbolic.o $(C) -DZLONG -DCONJUGATE_SOLVE -c ../Source/umf_ltsolve.c -o umf_zl_lhsolve.o $(C) -DZLONG -DCONJUGATE_SOLVE -c ../Source/umf_utsolve.c -o umf_zl_uhsolve.o $(C) -DZLONG -DDO_MAP -c ../Source/umf_triplet.c -o umf_zl_triplet_map_nox.o $(C) -DZLONG -DDO_VALUES -c ../Source/umf_triplet.c -o umf_zl_triplet_nomap_x.o $(C) -DZLONG -c ../Source/umf_triplet.c -o umf_zl_triplet_nomap_nox.o $(C) -DZLONG -DDO_MAP -DDO_VALUES -c ../Source/umf_triplet.c -o umf_zl_triplet_map_x.o $(C) -DZLONG -DFIXQ -c ../Source/umf_assemble.c -o umf_zl_assemble_fixq.o $(C) -DZLONG -DDROP -c ../Source/umf_store_lu.c -o umf_zl_store_lu_drop.o $(C) -DZLONG -c ../Source/umf_assemble.c -o umf_zl_assemble.o $(C) -DZLONG -c ../Source/umf_blas3_update.c -o umf_zl_blas3_update.o $(C) -DZLONG -c ../Source/umf_build_tuples.c -o umf_zl_build_tuples.o $(C) -DZLONG -c ../Source/umf_create_element.c -o umf_zl_create_element.o $(C) -DZLONG -c ../Source/umf_dump.c -o umf_zl_dump.o $(C) -DZLONG -c ../Source/umf_extend_front.c -o umf_zl_extend_front.o $(C) -DZLONG -c ../Source/umf_garbage_collection.c -o umf_zl_garbage_collection.o $(C) -DZLONG -c ../Source/umf_get_memory.c -o umf_zl_get_memory.o $(C) -DZLONG -c ../Source/umf_init_front.c -o umf_zl_init_front.o $(C) -DZLONG -c ../Source/umf_kernel.c -o umf_zl_kernel.o $(C) -DZLONG -c ../Source/umf_kernel_init.c -o umf_zl_kernel_init.o $(C) -DZLONG -c ../Source/umf_kernel_wrapup.c -o umf_zl_kernel_wrapup.o $(C) -DZLONG -c ../Source/umf_local_search.c -o umf_zl_local_search.o $(C) -DZLONG -c ../Source/umf_lsolve.c -o umf_zl_lsolve.o $(C) -DZLONG -c ../Source/umf_ltsolve.c -o umf_zl_ltsolve.o $(C) -DZLONG -c ../Source/umf_mem_alloc_element.c -o umf_zl_mem_alloc_element.o $(C) -DZLONG -c ../Source/umf_mem_alloc_head_block.c -o umf_zl_mem_alloc_head_block.o $(C) -DZLONG -c ../Source/umf_mem_alloc_tail_block.c -o umf_zl_mem_alloc_tail_block.o $(C) -DZLONG -c ../Source/umf_mem_free_tail_block.c -o umf_zl_mem_free_tail_block.o $(C) -DZLONG -c ../Source/umf_mem_init_memoryspace.c -o umf_zl_mem_init_memoryspace.o $(C) -DZLONG -c ../Source/umf_report_vector.c -o umf_zl_report_vector.o $(C) -DZLONG -c ../Source/umf_row_search.c -o umf_zl_row_search.o $(C) -DZLONG -c ../Source/umf_scale_column.c -o umf_zl_scale_column.o $(C) -DZLONG -c ../Source/umf_set_stats.c -o umf_zl_set_stats.o $(C) -DZLONG -c ../Source/umf_solve.c -o umf_zl_solve.o $(C) -DZLONG -c ../Source/umf_symbolic_usage.c -o umf_zl_symbolic_usage.o $(C) -DZLONG -c ../Source/umf_transpose.c -o umf_zl_transpose.o $(C) -DZLONG -c ../Source/umf_tuple_lengths.c -o umf_zl_tuple_lengths.o $(C) -DZLONG -c ../Source/umf_usolve.c -o umf_zl_usolve.o $(C) -DZLONG -c ../Source/umf_utsolve.c -o umf_zl_utsolve.o $(C) -DZLONG -c ../Source/umf_valid_numeric.c -o umf_zl_valid_numeric.o $(C) -DZLONG -c ../Source/umf_valid_symbolic.c -o umf_zl_valid_symbolic.o $(C) -DZLONG -c ../Source/umf_grow_front.c -o umf_zl_grow_front.o $(C) -DZLONG -c ../Source/umf_start_front.c -o umf_zl_start_front.o $(C) -DZLONG -c ../Source/umf_2by2.c -o umf_zl_2by2.o $(C) -DZLONG -c ../Source/umf_store_lu.c -o umf_zl_store_lu.o $(C) -DZLONG -c ../Source/umf_scale.c -o umf_zl_scale.o $(C) -DZLONG -DWSOLVE -c ../Source/umfpack_solve.c -o umfpack_zl_wsolve.o $(C) -DZLONG -c ../Source/umfpack_col_to_triplet.c -o umfpack_zl_col_to_triplet.o $(C) -DZLONG -c ../Source/umfpack_defaults.c -o umfpack_zl_defaults.o $(C) -DZLONG -c ../Source/umfpack_free_numeric.c -o umfpack_zl_free_numeric.o $(C) -DZLONG -c ../Source/umfpack_free_symbolic.c -o umfpack_zl_free_symbolic.o $(C) -DZLONG -c ../Source/umfpack_get_numeric.c -o umfpack_zl_get_numeric.o $(C) -DZLONG -c ../Source/umfpack_get_lunz.c -o umfpack_zl_get_lunz.o $(C) -DZLONG -c ../Source/umfpack_get_symbolic.c -o umfpack_zl_get_symbolic.o $(C) -DZLONG -c ../Source/umfpack_get_determinant.c -o umfpack_zl_get_determinant.o $(C) -DZLONG -c ../Source/umfpack_numeric.c -o umfpack_zl_numeric.o $(C) -DZLONG -c ../Source/umfpack_qsymbolic.c -o umfpack_zl_qsymbolic.o $(C) -DZLONG -c ../Source/umfpack_report_control.c -o umfpack_zl_report_control.o $(C) -DZLONG -c ../Source/umfpack_report_info.c -o umfpack_zl_report_info.o $(C) -DZLONG -c ../Source/umfpack_report_matrix.c -o umfpack_zl_report_matrix.o $(C) -DZLONG -c ../Source/umfpack_report_numeric.c -o umfpack_zl_report_numeric.o $(C) -DZLONG -c ../Source/umfpack_report_perm.c -o umfpack_zl_report_perm.o $(C) -DZLONG -c ../Source/umfpack_report_status.c -o umfpack_zl_report_status.o $(C) -DZLONG -c ../Source/umfpack_report_symbolic.c -o umfpack_zl_report_symbolic.o $(C) -DZLONG -c ../Source/umfpack_report_triplet.c -o umfpack_zl_report_triplet.o $(C) -DZLONG -c ../Source/umfpack_report_vector.c -o umfpack_zl_report_vector.o $(C) -DZLONG -c ../Source/umfpack_solve.c -o umfpack_zl_solve.o $(C) -DZLONG -c ../Source/umfpack_symbolic.c -o umfpack_zl_symbolic.o $(C) -DZLONG -c ../Source/umfpack_transpose.c -o umfpack_zl_transpose.o $(C) -DZLONG -c ../Source/umfpack_triplet_to_col.c -o umfpack_zl_triplet_to_col.o $(C) -DZLONG -c ../Source/umfpack_scale.c -o umfpack_zl_scale.o $(C) -DZLONG -c ../Source/umfpack_load_numeric.c -o umfpack_zl_load_numeric.o $(C) -DZLONG -c ../Source/umfpack_save_numeric.c -o umfpack_zl_save_numeric.o $(C) -DZLONG -c ../Source/umfpack_load_symbolic.c -o umfpack_zl_load_symbolic.o $(C) -DZLONG -c ../Source/umfpack_save_symbolic.c -o umfpack_zl_save_symbolic.o $(AR) ../Lib/libumfpack.a \ umfpack_gn_global.o \ umf_i_analyze.o umf_i_apply_order.o umf_i_colamd.o umf_i_free.o \ umf_i_fsize.o umf_i_is_permutation.o umf_i_malloc.o umf_i_realloc.o \ umf_i_report_perm.o umf_i_singletons.o \ umf_l_analyze.o umf_l_apply_order.o umf_l_colamd.o umf_l_free.o \ umf_l_fsize.o umf_l_is_permutation.o umf_l_malloc.o umf_l_realloc.o \ umf_l_report_perm.o umf_l_singletons.o \ umfpack_gn_timer.o umfpack_gn_tictoc.o \ umf_di_lhsolve.o \ umf_di_uhsolve.o umf_di_triplet_map_nox.o umf_di_triplet_nomap_x.o \ umf_di_triplet_nomap_nox.o umf_di_triplet_map_x.o \ umf_di_assemble_fixq.o umf_di_store_lu_drop.o umf_di_assemble.o \ umf_di_blas3_update.o umf_di_build_tuples.o \ umf_di_create_element.o umf_di_dump.o umf_di_extend_front.o \ umf_di_garbage_collection.o umf_di_get_memory.o \ umf_di_init_front.o umf_di_kernel.o umf_di_kernel_init.o \ umf_di_kernel_wrapup.o umf_di_local_search.o umf_di_lsolve.o \ umf_di_ltsolve.o umf_di_mem_alloc_element.o \ umf_di_mem_alloc_head_block.o umf_di_mem_alloc_tail_block.o \ umf_di_mem_free_tail_block.o umf_di_mem_init_memoryspace.o \ umf_di_report_vector.o umf_di_row_search.o umf_di_scale_column.o \ umf_di_set_stats.o umf_di_solve.o umf_di_symbolic_usage.o \ umf_di_transpose.o umf_di_tuple_lengths.o umf_di_usolve.o \ umf_di_utsolve.o umf_di_valid_numeric.o umf_di_valid_symbolic.o \ umf_di_grow_front.o umf_di_start_front.o umf_di_2by2.o \ umf_di_store_lu.o umf_di_scale.o umfpack_di_wsolve.o \ umfpack_di_col_to_triplet.o umfpack_di_defaults.o \ umfpack_di_free_numeric.o umfpack_di_free_symbolic.o \ umfpack_di_get_numeric.o umfpack_di_get_lunz.o \ umfpack_di_get_symbolic.o umfpack_di_get_determinant.o \ umfpack_di_numeric.o \ umfpack_di_qsymbolic.o umfpack_di_report_control.o \ umfpack_di_report_info.o umfpack_di_report_matrix.o \ umfpack_di_report_numeric.o umfpack_di_report_perm.o \ umfpack_di_report_status.o umfpack_di_report_symbolic.o \ umfpack_di_report_triplet.o umfpack_di_report_vector.o \ umfpack_di_solve.o umfpack_di_symbolic.o umfpack_di_transpose.o \ umfpack_di_triplet_to_col.o umfpack_di_scale.o \ umfpack_di_load_numeric.o umfpack_di_save_numeric.o \ umfpack_di_load_symbolic.o umfpack_di_save_symbolic.o \ umf_dl_lhsolve.o \ umf_dl_uhsolve.o umf_dl_triplet_map_nox.o umf_dl_triplet_nomap_x.o \ umf_dl_triplet_nomap_nox.o umf_dl_triplet_map_x.o \ umf_dl_assemble_fixq.o umf_dl_store_lu_drop.o umf_dl_assemble.o \ umf_dl_blas3_update.o umf_dl_build_tuples.o \ umf_dl_create_element.o umf_dl_dump.o umf_dl_extend_front.o \ umf_dl_garbage_collection.o umf_dl_get_memory.o \ umf_dl_init_front.o umf_dl_kernel.o umf_dl_kernel_init.o \ umf_dl_kernel_wrapup.o umf_dl_local_search.o umf_dl_lsolve.o \ umf_dl_ltsolve.o umf_dl_mem_alloc_element.o \ umf_dl_mem_alloc_head_block.o umf_dl_mem_alloc_tail_block.o \ umf_dl_mem_free_tail_block.o umf_dl_mem_init_memoryspace.o \ umf_dl_report_vector.o umf_dl_row_search.o umf_dl_scale_column.o \ umf_dl_set_stats.o umf_dl_solve.o umf_dl_symbolic_usage.o \ umf_dl_transpose.o umf_dl_tuple_lengths.o umf_dl_usolve.o \ umf_dl_utsolve.o umf_dl_valid_numeric.o umf_dl_valid_symbolic.o \ umf_dl_grow_front.o umf_dl_start_front.o umf_dl_2by2.o \ umf_dl_store_lu.o umf_dl_scale.o umfpack_dl_wsolve.o \ umfpack_dl_col_to_triplet.o umfpack_dl_defaults.o \ umfpack_dl_free_numeric.o umfpack_dl_free_symbolic.o \ umfpack_dl_get_numeric.o umfpack_dl_get_lunz.o \ umfpack_dl_get_symbolic.o umfpack_dl_get_determinant.o \ umfpack_dl_numeric.o \ umfpack_dl_qsymbolic.o umfpack_dl_report_control.o \ umfpack_dl_report_info.o umfpack_dl_report_matrix.o \ umfpack_dl_report_numeric.o umfpack_dl_report_perm.o \ umfpack_dl_report_status.o umfpack_dl_report_symbolic.o \ umfpack_dl_report_triplet.o umfpack_dl_report_vector.o \ umfpack_dl_solve.o umfpack_dl_symbolic.o umfpack_dl_transpose.o \ umfpack_dl_triplet_to_col.o umfpack_dl_scale.o \ umfpack_dl_load_numeric.o umfpack_dl_save_numeric.o \ umfpack_dl_load_symbolic.o umfpack_dl_save_symbolic.o \ umf_zi_lhsolve.o \ umf_zi_uhsolve.o umf_zi_triplet_map_nox.o umf_zi_triplet_nomap_x.o \ umf_zi_triplet_nomap_nox.o umf_zi_triplet_map_x.o \ umf_zi_assemble_fixq.o umf_zi_store_lu_drop.o umf_zi_assemble.o \ umf_zi_blas3_update.o umf_zi_build_tuples.o \ umf_zi_create_element.o umf_zi_dump.o umf_zi_extend_front.o \ umf_zi_garbage_collection.o umf_zi_get_memory.o \ umf_zi_init_front.o umf_zi_kernel.o umf_zi_kernel_init.o \ umf_zi_kernel_wrapup.o umf_zi_local_search.o umf_zi_lsolve.o \ umf_zi_ltsolve.o umf_zi_mem_alloc_element.o \ umf_zi_mem_alloc_head_block.o umf_zi_mem_alloc_tail_block.o \ umf_zi_mem_free_tail_block.o umf_zi_mem_init_memoryspace.o \ umf_zi_report_vector.o umf_zi_row_search.o umf_zi_scale_column.o \ umf_zi_set_stats.o umf_zi_solve.o umf_zi_symbolic_usage.o \ umf_zi_transpose.o umf_zi_tuple_lengths.o umf_zi_usolve.o \ umf_zi_utsolve.o umf_zi_valid_numeric.o umf_zi_valid_symbolic.o \ umf_zi_grow_front.o umf_zi_start_front.o umf_zi_2by2.o \ umf_zi_store_lu.o umf_zi_scale.o umfpack_zi_wsolve.o \ umfpack_zi_col_to_triplet.o umfpack_zi_defaults.o \ umfpack_zi_free_numeric.o umfpack_zi_free_symbolic.o \ umfpack_zi_get_numeric.o umfpack_zi_get_lunz.o \ umfpack_zi_get_symbolic.o umfpack_zi_get_determinant.o \ umfpack_zi_numeric.o \ umfpack_zi_qsymbolic.o umfpack_zi_report_control.o \ umfpack_zi_report_info.o umfpack_zi_report_matrix.o \ umfpack_zi_report_numeric.o umfpack_zi_report_perm.o \ umfpack_zi_report_status.o umfpack_zi_report_symbolic.o \ umfpack_zi_report_triplet.o umfpack_zi_report_vector.o \ umfpack_zi_solve.o umfpack_zi_symbolic.o umfpack_zi_transpose.o \ umfpack_zi_triplet_to_col.o umfpack_zi_scale.o \ umfpack_zi_load_numeric.o umfpack_zi_save_numeric.o \ umfpack_zi_load_symbolic.o umfpack_zi_save_symbolic.o \ umf_zl_lhsolve.o \ umf_zl_uhsolve.o umf_zl_triplet_map_nox.o umf_zl_triplet_nomap_x.o \ umf_zl_triplet_nomap_nox.o umf_zl_triplet_map_x.o \ umf_zl_assemble_fixq.o umf_zl_store_lu_drop.o umf_zl_assemble.o \ umf_zl_blas3_update.o umf_zl_build_tuples.o \ umf_zl_create_element.o umf_zl_dump.o umf_zl_extend_front.o \ umf_zl_garbage_collection.o umf_zl_get_memory.o \ umf_zl_init_front.o umf_zl_kernel.o umf_zl_kernel_init.o \ umf_zl_kernel_wrapup.o umf_zl_local_search.o umf_zl_lsolve.o \ umf_zl_ltsolve.o umf_zl_mem_alloc_element.o \ umf_zl_mem_alloc_head_block.o umf_zl_mem_alloc_tail_block.o \ umf_zl_mem_free_tail_block.o umf_zl_mem_init_memoryspace.o \ umf_zl_report_vector.o umf_zl_row_search.o umf_zl_scale_column.o \ umf_zl_set_stats.o umf_zl_solve.o umf_zl_symbolic_usage.o \ umf_zl_transpose.o umf_zl_tuple_lengths.o umf_zl_usolve.o \ umf_zl_utsolve.o umf_zl_valid_numeric.o umf_zl_valid_symbolic.o \ umf_zl_grow_front.o umf_zl_start_front.o umf_zl_2by2.o \ umf_zl_store_lu.o umf_zl_scale.o umfpack_zl_wsolve.o \ umfpack_zl_col_to_triplet.o umfpack_zl_defaults.o \ umfpack_zl_free_numeric.o umfpack_zl_free_symbolic.o \ umfpack_zl_get_numeric.o umfpack_zl_get_lunz.o \ umfpack_zl_get_symbolic.o umfpack_zl_get_determinant.o \ umfpack_zl_numeric.o \ umfpack_zl_qsymbolic.o umfpack_zl_report_control.o \ umfpack_zl_report_info.o umfpack_zl_report_matrix.o \ umfpack_zl_report_numeric.o umfpack_zl_report_perm.o \ umfpack_zl_report_status.o umfpack_zl_report_symbolic.o \ umfpack_zl_report_triplet.o umfpack_zl_report_vector.o \ umfpack_zl_solve.o umfpack_zl_symbolic.o umfpack_zl_transpose.o \ umfpack_zl_triplet_to_col.o umfpack_zl_scale.o \ umfpack_zl_load_numeric.o umfpack_zl_save_numeric.o \ umfpack_zl_load_symbolic.o umfpack_zl_save_symbolic.o - $(RANLIB) ../Lib/libumfpack.a #------------------------------------------------------------------------------- # Remove all but the files in the original distribution #------------------------------------------------------------------------------- purge: clean - $(RM) ../Lib/libumfpack.a clean: - $(RM) $(CLEAN) cvxopt-1.1.4/src/C/SuiteSparse/UMFPACK/Lib/GNUmakefile0000644000175000017500000002323611674452555021200 0ustar sonnesonne#------------------------------------------------------------------------------- # UMFPACK Makefile for compiling on Unix systems (for GNU Make) #------------------------------------------------------------------------------- default: ../Lib/libumfpack.a include ../../UFconfig/UFconfig.mk C = $(CC) $(CFLAGS) $(UMFPACK_CONFIG) \ -I../Include -I../Source -I../../AMD/Include -I../../UFconfig #------------------------------------------------------------------------------- # source files #------------------------------------------------------------------------------- # non-user-callable umf_*.[ch] files: UMFCH = umf_assemble umf_blas3_update umf_build_tuples umf_create_element \ umf_dump umf_extend_front umf_garbage_collection umf_get_memory \ umf_init_front umf_kernel umf_kernel_init umf_kernel_wrapup \ umf_local_search umf_lsolve umf_ltsolve umf_mem_alloc_element \ umf_mem_alloc_head_block umf_mem_alloc_tail_block \ umf_mem_free_tail_block umf_mem_init_memoryspace \ umf_report_vector umf_row_search umf_scale_column \ umf_set_stats umf_solve umf_symbolic_usage umf_transpose \ umf_tuple_lengths umf_usolve umf_utsolve umf_valid_numeric \ umf_valid_symbolic umf_grow_front umf_start_front umf_2by2 \ umf_store_lu umf_scale # non-user-callable umf_*.[ch] files, int/UF_long versions only (no real/complex): UMFINT = umf_analyze umf_apply_order umf_colamd umf_free umf_fsize \ umf_is_permutation umf_malloc umf_realloc umf_report_perm \ umf_singletons # non-user-callable, created from umf_ltsolve.c, umf_utsolve.c, # umf_triplet.c, and umf_assemble.c , with int/UF_long and real/complex versions: UMF_CREATED = umf_lhsolve umf_uhsolve umf_triplet_map_nox \ umf_triplet_nomap_x umf_triplet_nomap_nox umf_triplet_map_x \ umf_assemble_fixq umf_store_lu_drop # non-user-callable, int/UF_long and real/complex versions: UMF = $(UMF_CREATED) $(UMFCH) # user-callable umfpack_*.[ch] files (int/UF_long and real/complex): UMFPACK = umfpack_col_to_triplet umfpack_defaults umfpack_free_numeric \ umfpack_free_symbolic umfpack_get_numeric umfpack_get_lunz \ umfpack_get_symbolic umfpack_get_determinant umfpack_numeric \ umfpack_qsymbolic umfpack_report_control umfpack_report_info \ umfpack_report_matrix umfpack_report_numeric umfpack_report_perm \ umfpack_report_status umfpack_report_symbolic umfpack_report_triplet \ umfpack_report_vector umfpack_solve umfpack_symbolic \ umfpack_transpose umfpack_triplet_to_col umfpack_scale \ umfpack_load_numeric umfpack_save_numeric \ umfpack_load_symbolic umfpack_save_symbolic # user-callable, created from umfpack_solve.c (umfpack_wsolve.h exists, though): # with int/UF_long and real/complex versions: UMFPACKW = umfpack_wsolve USER = $(UMFPACKW) $(UMFPACK) # user-callable, only one version for int/UF_long, real/complex, *.[ch] files: GENERIC = umfpack_timer umfpack_tictoc umfpack_global #------------------------------------------------------------------------------- # include files: #------------------------------------------------------------------------------- INC = ../Include/umfpack.h ../../UFconfig/UFconfig.h \ ../Source/umf_config.h ../Source/umf_version.h \ ../Source/umf_internal.h ../Source/umf_triplet.h \ $(addprefix ../Source/, $(addsuffix .h,$(UMFCH))) \ $(addprefix ../Source/, $(addsuffix .h,$(UMFINT))) \ $(addprefix ../Include/, $(addsuffix .h,$(USER))) \ $(addprefix ../Include/, $(addsuffix .h,$(GENERIC))) \ ../../AMD/Include/amd_internal.h ../../AMD/Include/amd.h #------------------------------------------------------------------------------- # object files for each version #------------------------------------------------------------------------------- DI = $(addsuffix .o, $(subst umf_,umf_di_,$(UMF)) $(subst umfpack_,umfpack_di_,$(USER))) DL = $(addsuffix .o, $(subst umf_,umf_dl_,$(UMF)) $(subst umfpack_,umfpack_dl_,$(USER))) ZI = $(addsuffix .o, $(subst umf_,umf_zi_,$(UMF)) $(subst umfpack_,umfpack_zi_,$(USER))) ZL = $(addsuffix .o, $(subst umf_,umf_zl_,$(UMF)) $(subst umfpack_,umfpack_zl_,$(USER))) II = $(addsuffix .o, $(subst umf_,umf_i_,$(UMFINT))) LL = $(addsuffix .o, $(subst umf_,umf_l_,$(UMFINT))) GN = $(addsuffix .o, $(subst umfpack_,umfpack_gn_,$(GENERIC))) #------------------------------------------------------------------------------- # compile each int and UF_long routine (with no real/complex version) #------------------------------------------------------------------------------- umf_i_%.o: ../Source/umf_%.c $(INC) $(C) -DDINT -c $< -o $@ umf_l_%.o: ../Source/umf_%.c $(INC) $(C) -DDLONG -c $< -o $@ #------------------------------------------------------------------------------- # compile each routine in the DI version #------------------------------------------------------------------------------- umf_di_%.o: ../Source/umf_%.c $(INC) $(C) -DDINT -c $< -o $@ umf_di_%hsolve.o: ../Source/umf_%tsolve.c $(INC) $(C) -DDINT -DCONJUGATE_SOLVE -c $< -o $@ umf_di_triplet_map_x.o: ../Source/umf_triplet.c $(INC) $(C) -DDINT -DDO_MAP -DDO_VALUES -c $< -o $@ umf_di_triplet_map_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DDINT -DDO_MAP -c $< -o $@ umf_di_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC) $(C) -DDINT -DDO_VALUES -c $< -o $@ umf_di_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DDINT -c $< -o $@ umf_di_assemble_fixq.o: ../Source/umf_assemble.c $(INC) $(C) -DDINT -DFIXQ -c $< -o $@ umf_di_store_lu_drop.o: ../Source/umf_store_lu.c $(INC) $(C) -DDINT -DDROP -c $< -o $@ umfpack_di_wsolve.o: ../Source/umfpack_solve.c $(INC) $(C) -DDINT -DWSOLVE -c $< -o $@ umfpack_di_%.o: ../Source/umfpack_%.c $(INC) $(C) -DDINT -c $< -o $@ #------------------------------------------------------------------------------- # compile each routine in the DL version #------------------------------------------------------------------------------- umf_dl_%.o: ../Source/umf_%.c $(INC) $(C) -DDLONG -c $< -o $@ umf_dl_%hsolve.o: ../Source/umf_%tsolve.c $(INC) $(C) -DDLONG -DCONJUGATE_SOLVE -c $< -o $@ umf_dl_triplet_map_x.o: ../Source/umf_triplet.c $(INC) $(C) -DDLONG -DDO_MAP -DDO_VALUES -c $< -o $@ umf_dl_triplet_map_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DDLONG -DDO_MAP -c $< -o $@ umf_dl_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC) $(C) -DDLONG -DDO_VALUES -c $< -o $@ umf_dl_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DDLONG -c $< -o $@ umf_dl_assemble_fixq.o: ../Source/umf_assemble.c $(INC) $(C) -DDLONG -DFIXQ -c $< -o $@ umf_dl_store_lu_drop.o: ../Source/umf_store_lu.c $(INC) $(C) -DDLONG -DDROP -c $< -o $@ umfpack_dl_wsolve.o: ../Source/umfpack_solve.c $(INC) $(C) -DDLONG -DWSOLVE -c $< -o $@ umfpack_dl_%.o: ../Source/umfpack_%.c $(INC) $(C) -DDLONG -c $< -o $@ #------------------------------------------------------------------------------- # compile each routine in the ZI version #------------------------------------------------------------------------------- umf_zi_%.o: ../Source/umf_%.c $(INC) $(C) -DZINT -c $< -o $@ umf_zi_%hsolve.o: ../Source/umf_%tsolve.c $(INC) $(C) -DZINT -DCONJUGATE_SOLVE -c $< -o $@ umf_zi_triplet_map_x.o: ../Source/umf_triplet.c $(INC) $(C) -DZINT -DDO_MAP -DDO_VALUES -c $< -o $@ umf_zi_triplet_map_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DZINT -DDO_MAP -c $< -o $@ umf_zi_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC) $(C) -DZINT -DDO_VALUES -c $< -o $@ umf_zi_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DZINT -c $< -o $@ umf_zi_assemble_fixq.o: ../Source/umf_assemble.c $(INC) $(C) -DZINT -DFIXQ -c $< -o $@ umf_zi_store_lu_drop.o: ../Source/umf_store_lu.c $(INC) $(C) -DZINT -DDROP -c $< -o $@ umfpack_zi_wsolve.o: ../Source/umfpack_solve.c $(INC) $(C) -DZINT -DWSOLVE -c $< -o $@ umfpack_zi_%.o: ../Source/umfpack_%.c $(INC) $(C) -DZINT -c $< -o $@ #------------------------------------------------------------------------------- # compile each routine in the ZL version #------------------------------------------------------------------------------- umf_zl_%.o: ../Source/umf_%.c $(INC) $(C) -DZLONG -c $< -o $@ umf_zl_%hsolve.o: ../Source/umf_%tsolve.c $(INC) $(C) -DZLONG -DCONJUGATE_SOLVE -c $< -o $@ umf_zl_triplet_map_x.o: ../Source/umf_triplet.c $(INC) $(C) -DZLONG -DDO_MAP -DDO_VALUES -c $< -o $@ umf_zl_triplet_map_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DZLONG -DDO_MAP -c $< -o $@ umf_zl_triplet_nomap_x.o: ../Source/umf_triplet.c $(INC) $(C) -DZLONG -DDO_VALUES -c $< -o $@ umf_zl_triplet_nomap_nox.o: ../Source/umf_triplet.c $(INC) $(C) -DZLONG -c $< -o $@ umf_zl_assemble_fixq.o: ../Source/umf_assemble.c $(INC) $(C) -DZLONG -DFIXQ -c $< -o $@ umf_zl_store_lu_drop.o: ../Source/umf_store_lu.c $(INC) $(C) -DZLONG -DDROP -c $< -o $@ umfpack_zl_wsolve.o: ../Source/umfpack_solve.c $(INC) $(C) -DZLONG -DWSOLVE -c $< -o $@ umfpack_zl_%.o: ../Source/umfpack_%.c $(INC) $(C) -DZLONG -c $< -o $@ #------------------------------------------------------------------------------- # Create the generic routines (GN) using a generic rule #------------------------------------------------------------------------------- umfpack_gn_%.o: ../Source/umfpack_%.c $(INC) $(C) -c $< -o $@ #------------------------------------------------------------------------------- # Create the ../Lib/libumfpack.a library #------------------------------------------------------------------------------- ../Lib/libumfpack.a: $(II) $(LL) $(GN) $(DI) $(DL) $(ZI) $(ZL) $(AR) ../Lib/libumfpack.a $^ - $(RANLIB) ../Lib/libumfpack.a so: $(II) $(LL) $(GN) $(DI) $(DL) $(ZI) $(ZL) gcc -shared -Wl,-soname,libumfpack.so -o libumfpack.so $^ #------------------------------------------------------------------------------- # Remove all but the files in the original distribution #------------------------------------------------------------------------------- purge: clean - $(RM) ../Lib/libumfpack.a clean: - $(RM) $(CLEAN) cvxopt-1.1.4/src/C/SuiteSparse/README.txt0000644000175000017500000001406411674452555017027 0ustar sonnesonneSuiteSparse: A Suite of Sparse matrix packages ------------------ SuiteSparse/README ------------------ ================================================================================ QUICK START FOR MATLAB USERS: uncompress the SuiteSparse.zip or SuiteSparse.tar.gz archive file (they contain the same thing), then in the MATLAB Command Window, cd to the SuiteSparse directory and type SuiteSparse_install. All packages will be compiled, and several demos will be run. ================================================================================ May 20, 2009. SuiteSparse version 3.4.0 AMD approximate minimum degree ordering CAMD constrained approximate minimum degree ordering COLAMD column approximate minimum degree ordering CCOLAMD constrained column approximate minimum degree ordering BTF permutation to block triangular form KLU sparse LU factorization, primarily for circuit simulation. Requires AMD, COLAMD, and BTF. Optionally uses CHOLMOD, CAMD, CCOLAMD, and METIS. UMFPACK sparse LU factorization. Requires AMD and the BLAS. CHOLMOD sparse Cholesky factorization. Requires AMD, COLAMD, CCOLAMD, the BLAS, and LAPACK. Optionally uses METIS. UFconfig configuration file for all the above packages. The UFconfig/UFconfig.mk is included in the Makefile's of all packages. CSparse and RBio do not use UFconfig. CSparse a concise sparse matrix package, developed for my upcoming book, "Direct Methods for Sparse Linear Systems", to be published by SIAM. CXSparse CSparse Extended. Includes support for complex matrices and both int or long integers. RBio read/write sparse matrices in Rutherford/Boeing format UFcollection toolbox for managing the UF Sparse Matrix Collection LPDASA LP dual active set algorithm (to appear) MESHND 2D and 3D mesh generation and nested dissection ordering SSMULT sparse matrix multiply for MATLAB LINFACTOR simple m-file demonstrating how to use LU and CHOL in MATLAB to solve Ax=b MATLAB_Tools various simple m-files for use in MATLAB SuiteSparseQR sparse QR factorization CHOLMOD optionally uses METIS 4.0.1 (http://www-users.cs.umn.edu/~karypis/metis). To use METIS, place a copy of the metis-4.0 directory in the same directory containing this README file. Be sure that you do not have a nested metis-4.0/metis-4.0 directory; SuiteSparse won't find METIS if you do this, which can happen with a zip file of metis-4.0 on Windows. The use of METIS will improve the ordering quality in CHOLMOD. Refer to each package for license, copyright, and author information. All codes are authored or co-authored by Timothy A. Davis, CISE Dept., Univ. of Florida. email: my last name @ cise dot ufl dot edu. ================================================================================ If you use SuiteSparse_install in MATLAB, stop reading here. ================================================================================ ---------------------------- To use "make" in Unix/Linux: ---------------------------- (1) Use the right BLAS and LAPACK libraries See http://www.netlib.org/blas for the Fortran reference BLAS (slow, but they work). See http://www.tacc.utexas.edu/~kgoto/ or http://www.cs.utexas.edu/users/flame/goto/ for an optimized BLAS. See http://www.netlib.org/lapack for LAPACK. The UFconfig/UFconfig.mk file assumes the vanilla BLAS (-lblas). You should use an optimized BLAS; otherwise UMFPACK and CHOLMOD will be slow. Change -lblas to -l(your BLAS library here) in the UFconfig/UFconfig.mk file. (2) Install Intel's Threading Building Blocks (TBB) This is optionally used by SuiteSparseQR. Refer to the User Guide in SuiteSparse/SPQR/Doc/spqr_user_guide.pdf for details. (3) Configure METIS (or don't use METIS) cd to metis-4.0 and edit the Makefile.in file. I recommend making these changes to metis-4.0/Makefile.in: CC = gcc OPTFLAGS = -O3 And, if you want to use METIS in MATLAB and compile with "make" instead of using SuiteSparse_install.m: COPTIONS = -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE Next, cd to metis-4.0 and type "make". If you do not wish to use METIS, then edit the UFconfig/UFconfig.mk file, and change the lines CHOLMOD_CONFIG = SPQR_CONFIG = to CHOLMOD_CONFIG = -DNPARTITION SPQR_CONFIG = -DNPARTITION Also change the line METIS = ../../metis-4.0/libmetis.a to METIS = (4) Make other changes to UFconfig/UFconfig.mk as needed Edit the UFconfig/UFconfig.mk file as needed. Directions are in that file. If you have compiled SuiteSparse already (partially or completely), then whenever you edit the UFconfig/UFconfig.mk file, you should then type "make purge" (or "make realclean") in this directory. If you want to use "make" to compile mexFunctions, I recommend adding these options to the CFLAGS = line: -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE (5) Type "make" in this directory. All packages will be be compiled. METIS will be compiled if you have it. Several demos will be run. The libraries will appear in */Lib/*.a. Include files, as needed by user programs that use CHOLMOD, AMD, CAMD, COLAMD, CCOLAMD, BTF, KLU, UMFPACK, LDL, etc. are in */Include/*.h. The METIS library is in metis-4.0/libmetis.a. METIS Include files (not needed by the end user of SuiteSparse) are in located in metis-4.0/Lib/*.h. In a future version, I will include a "make install" that will create *.so libraries and place them in /usr/lib. The libraries should be called libPACKAGE.so.VERSION.SUBVERSION.SUBSUBVERSION. For example, libcolamd.so.2.7.1 should be the library name for COLAMD version 2.7.1. The version numbers are located in UFconfig.h (in comments) and in each package (as a #define). cvxopt-1.1.4/src/C/SuiteSparse/README_cvxopt0000644000175000017500000000106511674452555017611 0ustar sonnesonneThis is version 3.5.0 of the SuiteSparse package from www.cise.ufl.edu/research/sparse/SuiteSparse/, with the following files and directories removed. AMD/Demo AMD/MATLAB BTF CAMD CCOLAMD CHOLMOD/Demo CHOLMOD/MATLAB CHOLMOD/MatrixOps CHOLMOD/Modify CHOLMOD/Partition CHOLMOD/Tcov CHOLMOD/Valgrind COLAMD/MATLAB CSparse Csparse_to_CXsparse CXSparse CXSparse_newfiles CXSparse_newfiles.tar.gz KLU LDL LINFACTOR MATLAB_Tools MESHND RBio SPQR SSMULT SuiteSparse_demo.m SuiteSparse_install.m SuiteSparse_test.m UFcollection UMFPACK/Demo UMFPACK/MATLAB UMFPACK/Tcov cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/0000755000175000017500000000000011674452555016411 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/0000755000175000017500000000000011674452555020172 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/License.txt0000644000175000017500000000206411674452555022317 0ustar sonnesonneCHOLMOD/Cholesky module, Copyright (C) 2005-2006, Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://www.cise.ufl.edu/research/sparse Note that this license is for the CHOLMOD/Cholesky module only. All CHOLMOD modules are licensed separately. -------------------------------------------------------------------------------- This Module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This Module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_amd.c0000644000175000017500000001613511674452555022612 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_amd ================================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD interface to the AMD ordering routine. Orders A if the matrix is * symmetric. On output, Perm [k] = i if row/column i of A is the kth * row/column of P*A*P'. This corresponds to A(p,p) in MATLAB notation. * * If A is unsymmetric, cholmod_amd orders A*A'. On output, Perm [k] = i if * row/column i of A*A' is the kth row/column of P*A*A'*P'. This corresponds to * A(p,:)*A(p,:)' in MATLAB notation. If f is present, A(p,f)*A(p,f)' is * ordered. * * Computes the flop count for a subsequent LL' factorization, the number * of nonzeros in L, and the number of nonzeros in the matrix ordered (A, * A*A' or A(:,f)*A(:,f)'). * * workspace: Iwork (6*nrow). Head (nrow). * * Allocates a temporary copy of A+A' or A*A' (with * both upper and lower triangular parts) as input to AMD. * * Supports any xtype (pattern, real, complex, or zomplex) */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "amd.h" #include "cholmod_cholesky.h" #if (!defined (AMD_VERSION) || (AMD_VERSION < AMD_VERSION_CODE (2,0))) #error "AMD v2.0 or later is required" #endif /* ========================================================================== */ /* === cholmod_amd ========================================================== */ /* ========================================================================== */ int CHOLMOD(amd) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ Int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) { double Info [AMD_INFO], Control2 [AMD_CONTROL], *Control ; Int *Cp, *Len, *Nv, *Head, *Elen, *Degree, *Wi, *Iwork, *Next ; cholmod_sparse *C ; Int j, n, cnz ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; n = A->nrow ; RETURN_IF_NULL (Perm, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; if (n == 0) { /* nothing to do */ Common->fl = 0 ; Common->lnz = 0 ; Common->anz = 0 ; return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ /* Note: this is less than the space used in cholmod_analyze, so if * cholmod_amd is being called by that routine, no space will be * allocated. */ /* s = MAX (6*n, A->ncol) */ s = CHOLMOD(mult_size_t) (n, 6, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } s = MAX (s, A->ncol) ; CHOLMOD(allocate_work) (n, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } Iwork = Common->Iwork ; Degree = Iwork ; /* size n */ Wi = Iwork + n ; /* size n */ Len = Iwork + 2*((size_t) n) ; /* size n */ Nv = Iwork + 3*((size_t) n) ; /* size n */ Next = Iwork + 4*((size_t) n) ; /* size n */ Elen = Iwork + 5*((size_t) n) ; /* size n */ Head = Common->Head ; /* size n+1, but only n is used */ /* ---------------------------------------------------------------------- */ /* construct the input matrix for AMD */ /* ---------------------------------------------------------------------- */ if (A->stype == 0) { /* C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C */ C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ; } else { /* C = A+A', but use only the upper triangular part of A if A->stype = 1 * and only the lower part of A if A->stype = -1. Add extra space of * nnz(C)/2+n to C. */ C = CHOLMOD(copy) (A, 0, -2, Common) ; } if (Common->status < CHOLMOD_OK) { /* out of memory, fset invalid, or other error */ return (FALSE) ; } Cp = C->p ; for (j = 0 ; j < n ; j++) { Len [j] = Cp [j+1] - Cp [j] ; } /* C does not include the diagonal, and both upper and lower parts. * Common->anz includes the diagonal, and just the lower part of C */ cnz = Cp [n] ; Common->anz = cnz / 2 + n ; /* ---------------------------------------------------------------------- */ /* order C using AMD */ /* ---------------------------------------------------------------------- */ /* get parameters */ if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS) { /* use AMD defaults */ Control = NULL ; } else { Control = Control2 ; Control [AMD_DENSE] = Common->method [Common->current].prune_dense ; Control [AMD_AGGRESSIVE] = Common->method [Common->current].aggressive ; } /* AMD_2 does not use amd_malloc and amd_free, but set these pointers just * be safe. */ amd_malloc = Common->malloc_memory ; amd_free = Common->free_memory ; amd_calloc = Common->calloc_memory ; amd_realloc = Common->realloc_memory ; /* AMD_2 doesn't print anything either, but future versions might, * so set the amd_printf pointer too. */ amd_printf = Common->print_function ; #ifdef LONG amd_l2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen, Degree, Wi, Control, Info) ; #else amd_2 (n, C->p, C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen, Degree, Wi, Control, Info) ; #endif /* LL' flop count. Need to subtract n for LL' flop count. Note that this * is a slight upper bound which is often exact (see AMD/Source/amd_2.c for * details). cholmod_analyze computes an exact flop count and fill-in. */ Common->fl = Info [AMD_NDIV] + 2 * Info [AMD_NMULTSUBS_LDL] + n ; /* Info [AMD_LNZ] excludes the diagonal */ Common->lnz = n + Info [AMD_LNZ] ; /* ---------------------------------------------------------------------- */ /* free the AMD workspace and clear the persistent workspace in Common */ /* ---------------------------------------------------------------------- */ ASSERT (IMPLIES (Common->status == CHOLMOD_OK, CHOLMOD(dump_perm) (Perm, n, n, "AMD2 perm", Common))) ; CHOLMOD(free_sparse) (&C, Common) ; for (j = 0 ; j <= n ; j++) { Head [j] = EMPTY ; } return (TRUE) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_colamd.c0000644000175000017500000001566211674452555023314 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_colamd ============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD interface to the COLAMD ordering routine (version 2.4 or later). * Finds a permutation p such that the Cholesky factorization of PAA'P' is * sparser than AA' using colamd. If the postorder input parameter is TRUE, * the column etree is found and postordered, and the colamd ordering is then * combined with its postordering. A must be unsymmetric. * * There can be no duplicate entries in f. * f can be length 0 to n if A is m-by-n. * * workspace: Iwork (4*nrow+ncol), Head (nrow+1), Flag (nrow) * Allocates a copy of its input matrix, which * is then used as CCOLAMD's workspace. * * Supports any xtype (pattern, real, complex, or zomplex) */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "colamd.h" #include "cholmod_cholesky.h" #if (!defined (COLAMD_VERSION) || (COLAMD_VERSION < COLAMD_VERSION_CODE (2,5))) #error "COLAMD v2.5 or later is required" #endif /* ========================================================================== */ /* === cholmod_colamd ======================================================= */ /* ========================================================================== */ int CHOLMOD(colamd) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int postorder, /* if TRUE, follow with a coletree postorder */ /* ---- output --- */ Int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) { double knobs [COLAMD_KNOBS] ; cholmod_sparse *C ; Int *NewPerm, *Parent, *Post, *Work2n ; Int k, nrow, ncol ; size_t s, alen ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (Perm, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (A->stype != 0) { ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* Note: this is less than the space used in cholmod_analyze, so if * cholmod_colamd is being called by that routine, no space will be * allocated. */ /* s = 4*nrow + ncol */ s = CHOLMOD(mult_size_t) (nrow, 4, &ok) ; s = CHOLMOD(add_size_t) (s, ncol, &ok) ; #ifdef LONG alen = colamd_l_recommended (A->nzmax, ncol, nrow) ; colamd_l_set_defaults (knobs) ; #else alen = colamd_recommended (A->nzmax, ncol, nrow) ; colamd_set_defaults (knobs) ; #endif if (!ok || alen == 0) { ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* allocate COLAMD workspace */ /* ---------------------------------------------------------------------- */ /* colamd_printf is only available in colamd v2.4 or later */ colamd_printf = Common->print_function ; C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0, CHOLMOD_PATTERN, Common) ; /* ---------------------------------------------------------------------- */ /* copy (and transpose) the input matrix A into the colamd workspace */ /* ---------------------------------------------------------------------- */ /* C = A (:,f)', which also packs A if needed. */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) */ ok = CHOLMOD(transpose_unsym) (A, 0, NULL, fset, fsize, C, Common) ; /* ---------------------------------------------------------------------- */ /* order the matrix (destroys the contents of C->i and C->p) */ /* ---------------------------------------------------------------------- */ /* get parameters */ if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS) { /* this is the CHOLMOD default, not the COLAMD default */ knobs [COLAMD_DENSE_ROW] = -1 ; } else { /* get the knobs from the Common parameters */ knobs [COLAMD_DENSE_COL] = Common->method[Common->current].prune_dense ; knobs [COLAMD_DENSE_ROW] = Common->method[Common->current].prune_dense2; knobs [COLAMD_AGGRESSIVE] = Common->method[Common->current].aggressive ; } if (ok) { Int *Cp ; Int stats [COLAMD_STATS] ; Cp = C->p ; #ifdef LONG colamd_l (ncol, nrow, alen, C->i, Cp, knobs, stats) ; #else colamd (ncol, nrow, alen, C->i, Cp, knobs, stats) ; #endif ok = stats [COLAMD_STATUS] ; ok = (ok == COLAMD_OK || ok == COLAMD_OK_BUT_JUMBLED) ; /* permutation returned in C->p, if the ordering succeeded */ for (k = 0 ; k < nrow ; k++) { Perm [k] = Cp [k] ; } } CHOLMOD(free_sparse) (&C, Common) ; /* ---------------------------------------------------------------------- */ /* column etree postordering */ /* ---------------------------------------------------------------------- */ if (postorder) { /* use the last 2*n space in Iwork for Parent and Post */ Work2n = Common->Iwork ; Work2n += 2*((size_t) nrow) + ncol ; Parent = Work2n ; /* size nrow (i/i/l) */ Post = Work2n + nrow ; /* size nrow (i/i/l) */ /* workspace: Iwork (2*nrow+ncol), Flag (nrow), Head (nrow+1) */ ok = ok && CHOLMOD(analyze_ordering) (A, CHOLMOD_COLAMD, Perm, fset, fsize, Parent, Post, NULL, NULL, NULL, Common) ; /* combine the colamd permutation with its postordering */ if (ok) { NewPerm = Common->Iwork ; /* size nrow (i/i/l) */ for (k = 0 ; k < nrow ; k++) { NewPerm [k] = Perm [Post [k]] ; } for (k = 0 ; k < nrow ; k++) { Perm [k] = NewPerm [k] ; } } } return (ok) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_solve.c0000644000175000017500000001120211674452555023512 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/t_cholmod_solve ============================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_solve. Supports any numeric xtype (real, * complex, or zomplex). The xtypes of all matrices (L and Y) must match. */ #include "cholmod_template.h" /* ========================================================================== */ /* === simplicial template solvers ========================================== */ /* ========================================================================== */ /* LL': solve Lx=b with non-unit diagonal */ #define LL #include "t_cholmod_lsolve.c" /* LDL': solve LDx=b */ #define LD #include "t_cholmod_lsolve.c" /* LDL': solve Lx=b with unit diagonal */ #include "t_cholmod_lsolve.c" /* LL': solve L'x=b with non-unit diagonal */ #define LL #include "t_cholmod_ltsolve.c" /* LDL': solve DL'x=b */ #define LD #include "t_cholmod_ltsolve.c" /* LDL': solve L'x=b with unit diagonal */ #include "t_cholmod_ltsolve.c" /* ========================================================================== */ /* === t_ldl_dsolve ========================================================= */ /* ========================================================================== */ /* Solve Dx=b for an LDL' factorization, where Y holds b' on input and x' on * output. */ static void TEMPLATE (ldl_dsolve) ( cholmod_factor *L, cholmod_dense *Y /* nr-by-n with leading dimension nr */ ) { double d [1] ; double *Lx, *Yx, *Yz ; Int *Lp ; Int n, nrhs, k, p, k1, k2 ; ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */ ASSERT (L->n == Y->ncol) ; /* dimensions must match */ ASSERT (Y->nrow == Y->d) ; /* leading dimension of Y = # rows of Y */ ASSERT (L->xtype != CHOLMOD_PATTERN) ; /* L is not symbolic */ ASSERT (!(L->is_super) && !(L->is_ll)) ; /* L is simplicial LDL' */ nrhs = Y->nrow ; n = L->n ; Lp = L->p ; Lx = L->x ; Yx = Y->x ; Yz = Y->z ; for (k = 0 ; k < n ; k++) { k1 = k*nrhs ; k2 = (k+1)*nrhs ; ASSIGN_REAL (d,0, Lx,Lp[k]) ; for (p = k1 ; p < k2 ; p++) { DIV_REAL (Yx,Yz,p, Yx,Yz,p, d,0) ; } } } /* ========================================================================== */ /* === t_simplicial_solver ================================================== */ /* ========================================================================== */ /* Solve a linear system, where Y' contains the (array-transposed) right-hand * side on input, and the solution on output. No permutations are applied; * these must have already been applied to Y on input. */ static void TEMPLATE (simplicial_solver) ( int sys, /* system to solve */ cholmod_factor *L, /* factor to use, a simplicial LL' or LDL' */ cholmod_dense *Y /* right-hand-side on input, solution on output */ ) { if (L->is_ll) { /* The factorization is LL' */ if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) { /* Solve Ax=b or LL'x=b */ TEMPLATE (ll_lsolve_k) (L, Y) ; TEMPLATE (ll_ltsolve_k) (L, Y) ; } else if (sys == CHOLMOD_L || sys == CHOLMOD_LD) { /* Solve Lx=b */ TEMPLATE (ll_lsolve_k) (L, Y) ; } else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt) { /* Solve L'x=b */ TEMPLATE (ll_ltsolve_k) (L, Y) ; } } else { /* The factorization is LDL' */ if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) { /* Solve Ax=b or LDL'x=b */ TEMPLATE (ldl_lsolve_k) (L, Y) ; TEMPLATE (ldl_dltsolve_k) (L, Y) ; } else if (sys == CHOLMOD_LD) { /* Solve LDx=b */ TEMPLATE (ldl_ldsolve_k) (L, Y) ; } else if (sys == CHOLMOD_L) { /* Solve Lx=b */ TEMPLATE (ldl_lsolve_k) (L, Y) ; } else if (sys == CHOLMOD_Lt) { /* Solve L'x=b */ TEMPLATE (ldl_ltsolve_k) (L, Y) ; } else if (sys == CHOLMOD_DLt) { /* Solve DL'x=b */ TEMPLATE (ldl_dltsolve_k) (L, Y) ; } else if (sys == CHOLMOD_D) { /* Solve Dx=b */ TEMPLATE (ldl_dsolve) (L, Y) ; } } } #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rcond.c0000644000175000017500000001151511674452555023153 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_rcond =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Return a rough estimate of the reciprocal of the condition number: * the minimum entry on the diagonal of L (or absolute entry of D for an LDL' * factorization) divided by the maximum entry (squared for LL'). L can be * real, complex, or zomplex. Returns -1 on error, 0 if the matrix is singular * or has a zero entry on the diagonal of L, 1 if the matrix is 0-by-0, or * min(diag(L))/max(diag(L)) otherwise. Never returns NaN; if L has a NaN on * the diagonal it returns zero instead. * * For an LL' factorization, (min(diag(L))/max(diag(L)))^2 is returned. * For an LDL' factorization, (min(diag(D))/max(diag(D))) is returned. */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" /* ========================================================================== */ /* === LMINMAX ============================================================== */ /* ========================================================================== */ /* Update lmin and lmax for one entry L(j,j) */ #define FIRST_LMINMAX(Ljj,lmin,lmax) \ { \ double ljj = Ljj ; \ if (IS_NAN (ljj)) \ { \ return (0) ; \ } \ lmin = ljj ; \ lmax = ljj ; \ } #define LMINMAX(Ljj,lmin,lmax) \ { \ double ljj = Ljj ; \ if (IS_NAN (ljj)) \ { \ return (0) ; \ } \ if (ljj < lmin) \ { \ lmin = ljj ; \ } \ else if (ljj > lmax) \ { \ lmax = ljj ; \ } \ } /* ========================================================================== */ /* === cholmod_rcond ======================================================== */ /* ========================================================================== */ double CHOLMOD(rcond) /* return min(diag(L)) / max(diag(L)) */ ( /* ---- input ---- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) { double lmin, lmax, rcond ; double *Lx ; Int *Lpi, *Lpx, *Super, *Lp ; Int n, e, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol, jj, j ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (L, EMPTY) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ n = L->n ; if (n == 0) { return (1) ; } if (L->minor < L->n) { return (0) ; } e = (L->xtype == CHOLMOD_COMPLEX) ? 2 : 1 ; if (L->is_super) { /* L is supernodal */ nsuper = L->nsuper ; /* number of supernodes in L */ Lpi = L->pi ; /* column pointers for integer pattern */ Lpx = L->px ; /* column pointers for numeric values */ Super = L->super ; /* supernode sizes */ Lx = L->x ; /* numeric values */ FIRST_LMINMAX (Lx [0], lmin, lmax) ; /* first diagonal entry of L */ for (s = 0 ; s < nsuper ; s++) { k1 = Super [s] ; /* first column in supernode s */ k2 = Super [s+1] ; /* last column in supernode is k2-1 */ psi = Lpi [s] ; /* first row index is L->s [psi] */ psend = Lpi [s+1] ; /* last row index is L->s [psend-1] */ psx = Lpx [s] ; /* first numeric entry is Lx [psx] */ nsrow = psend - psi ; /* supernode is nsrow-by-nscol */ nscol = k2 - k1 ; for (jj = 0 ; jj < nscol ; jj++) { LMINMAX (Lx [e * (psx + jj + jj*nsrow)], lmin, lmax) ; } } } else { /* L is simplicial */ Lp = L->p ; Lx = L->x ; if (L->is_ll) { /* LL' factorization */ FIRST_LMINMAX (Lx [Lp [0]], lmin, lmax) ; for (j = 1 ; j < n ; j++) { LMINMAX (Lx [e * Lp [j]], lmin, lmax) ; } } else { /* LDL' factorization, the diagonal might be negative */ FIRST_LMINMAX (fabs (Lx [Lp [0]]), lmin, lmax) ; for (j = 1 ; j < n ; j++) { LMINMAX (fabs (Lx [e * Lp [j]]), lmin, lmax) ; } } } rcond = lmin / lmax ; if (L->is_ll) { rcond = rcond*rcond ; } return (rcond) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_resymbol.c0000644000175000017500000004446711674452555023716 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_resymbol ============================================ */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Recompute the symbolic pattern of L. Entries not in the symbolic pattern * are dropped. L->Perm can be used (or not) to permute the input matrix A. * * These routines are used after a supernodal factorization is converted into * a simplicial one, to remove zero entries that were added due to relaxed * supernode amalgamation. They can also be used after a series of downdates * to remove entries that would no longer be present if the matrix were * factorized from scratch. A downdate (cholmod_updown) does not remove any * entries from L. * * workspace: Flag (nrow), Head (nrow+1), * if symmetric: Iwork (2*nrow) * if unsymmetric: Iwork (2*nrow+ncol). * Allocates up to 2 copies of its input matrix A (pattern only). */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" /* ========================================================================== */ /* === cholmod_resymbol ===================================================== */ /* ========================================================================== */ /* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). * * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it * first permutes A according to L->Perm. A can be upper/lower/unsymmetric, * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */ int CHOLMOD(resymbol) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int pack, /* if TRUE, pack the columns of L */ /* ---- in/out --- */ cholmod_factor *L, /* factorization, entries pruned on output */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *H, *F, *G ; Int stype, nrow, ncol ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; if (L->is_super) { /* cannot operate on a supernodal factorization */ ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ; return (FALSE) ; } if (L->n != A->nrow) { /* dimensions must agree */ ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ stype = A->stype ; nrow = A->nrow ; ncol = A->ncol ; /* s = 2*nrow + (stype ? 0 : ncol) */ s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; s = CHOLMOD(add_size_t) (s, (stype ? 0 : ncol), &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* permute the input matrix if necessary */ /* ---------------------------------------------------------------------- */ H = NULL ; G = NULL ; if (stype > 0) { if (L->ordering == CHOLMOD_NATURAL) { /* F = triu(A)' */ /* workspace: Iwork (nrow) */ G = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ; } else { /* F = triu(A(p,p))' */ /* workspace: Iwork (2*nrow) */ G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ; } F = G ; } else if (stype < 0) { if (L->ordering == CHOLMOD_NATURAL) { F = A ; } else { /* G = triu(A(p,p))' */ /* workspace: Iwork (2*nrow) */ G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ; /* H = G' */ /* workspace: Iwork (nrow) */ H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ; F = H ; } } else { if (L->ordering == CHOLMOD_NATURAL) { F = A ; } else { /* G = A(p,f)' */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ G = CHOLMOD(ptranspose) (A, 0, L->Perm, fset, fsize, Common) ; /* H = G' */ /* workspace: Iwork (ncol) */ H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ; F = H ; } } /* No need to check for failure here. cholmod_resymbol_noperm will return * FALSE if F is NULL. */ /* ---------------------------------------------------------------------- */ /* resymbol */ /* ---------------------------------------------------------------------- */ ok = CHOLMOD(resymbol_noperm) (F, fset, fsize, pack, L, Common) ; /* ---------------------------------------------------------------------- */ /* free the temporary matrices, if they exist */ /* ---------------------------------------------------------------------- */ CHOLMOD(free_sparse) (&H, Common) ; CHOLMOD(free_sparse) (&G, Common) ; return (ok) ; } /* ========================================================================== */ /* === cholmod_resymbol_noperm ============================================== */ /* ========================================================================== */ /* Redo symbolic LDL' or LL' factorization of I + F*F' or I+A, where F=A(:,f). * * L already exists, but is a superset of the true dynamic pattern (simple * column downdates and row deletions haven't pruned anything). Just redo the * symbolic factorization and drop entries that are no longer there. The * diagonal is not modified. The number of nonzeros in column j of L * (L->nz[j]) can decrease. The column pointers (L->p[j]) remain unchanged if * pack is FALSE or if L is not monotonic. Otherwise, the columns of L are * packed in place. * * For the symmetric case, the columns of the lower triangular part of A * are accessed by column. NOTE that this the transpose of the general case. * * For the unsymmetric case, F=A(:,f) is accessed by column. * * A need not be sorted, and can be packed or unpacked. If L->Perm is not * identity, then A must already be permuted according to the permutation used * to factorize L. The advantage of using this routine is that it does not * need to create permuted copies of A first. * * This routine can be called if L is only partially factored via cholmod_rowfac * since all it does is prune. If an entry is in F*F' or A, but not in L, it * isn't added to L. * * L must be simplicial LDL' or LL'; it cannot be supernodal or symbolic. * * The set f is held in fset and fsize. * fset = NULL means ":" in MATLAB. fset is ignored. * fset != NULL means f = fset [0..fset-1]. * fset != NULL and fsize = 0 means f is the empty set. * There can be no duplicates in fset. * Common->status is set to CHOLMOD_INVALID if fset is invalid. * * workspace: Flag (nrow), Head (nrow+1), * if symmetric: Iwork (2*nrow) * if unsymmetric: Iwork (2*nrow+ncol). * Unlike cholmod_resymbol, this routine does not allocate any temporary * copies of its input matrix. */ int CHOLMOD(resymbol_noperm) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int pack, /* if TRUE, pack the columns of L */ /* ---- in/out --- */ cholmod_factor *L, /* factorization, entries pruned on output */ /* --------------- */ cholmod_common *Common ) { double *Lx, *Lz ; Int i, j, k, row, parent, p, pend, pdest, ncol, apacked, sorted, nrow, nf, use_fset, mark, jj, stype, xtype ; Int *Ap, *Ai, *Anz, *Li, *Lp, *Lnz, *Flag, *Head, *Link, *Anext, *Iwork ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; ncol = A->ncol ; nrow = A->nrow ; stype = A->stype ; ASSERT (IMPLIES (stype != 0, nrow == ncol)) ; if (stype > 0) { /* symmetric, with upper triangular part, not supported */ ERROR (CHOLMOD_INVALID, "symmetric upper not supported ") ; return (FALSE) ; } if (L->is_super) { /* cannot operate on a supernodal or symbolic factorization */ ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ; return (FALSE) ; } if (L->n != A->nrow) { /* dimensions must agree */ ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* s = 2*nrow + (stype ? 0 : ncol) */ s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; if (stype != 0) { s = CHOLMOD(add_size_t) (s, ncol, &ok) ; } if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ Ai = A->i ; Ap = A->p ; Anz = A->nz ; apacked = A->packed ; sorted = A->sorted ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lp = L->p ; Lnz = L->nz ; xtype = L->xtype ; /* If L is monotonic on input, then it can be packed or * unpacked on output, depending on the pack input parameter. */ /* cannot pack a non-monotonic matrix */ if (!(L->is_monotonic)) { pack = FALSE ; } ASSERT (L->nzmax >= (size_t) (Lp [L->n])) ; pdest = 0 ; PRINT1 (("\n\n===================== Resymbol pack %d Apacked %d\n", pack, A->packed)) ; ASSERT (CHOLMOD(dump_sparse) (A, "ReSymbol A:", Common) >= 0) ; DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol initial L (i, x):", Common)) ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Flag = Common->Flag ; /* size nrow */ Head = Common->Head ; /* size nrow+1 */ Iwork = Common->Iwork ; Link = Iwork ; /* size nrow (i/i/l) [ */ Lnz = Iwork + nrow ; /* size nrow (i/i/l), if L not packed */ Anext = Iwork + 2*((size_t) nrow) ; /* size ncol (i/i/l), unsym. only */ for (j = 0 ; j < nrow ; j++) { Link [j] = EMPTY ; } /* use Lnz in L itself */ Lnz = L->nz ; ASSERT (Lnz != NULL) ; /* ---------------------------------------------------------------------- */ /* for the unsymmetric case, queue each column of A (:,f) */ /* ---------------------------------------------------------------------- */ /* place each column of the basis set on the link list corresponding to */ /* the smallest row index in that column */ if (stype == 0) { use_fset = (fset != NULL) ; if (use_fset) { nf = fsize ; /* This is the only O(ncol) loop in cholmod_resymbol. * It is required only to check the fset. */ for (j = 0 ; j < ncol ; j++) { Anext [j] = -2 ; } for (jj = 0 ; jj < nf ; jj++) { j = fset [jj] ; if (j < 0 || j > ncol || Anext [j] != -2) { /* out-of-range or duplicate entry in fset */ ERROR (CHOLMOD_INVALID, "fset invalid") ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; return (FALSE) ; } /* flag column j as having been seen */ Anext [j] = EMPTY ; } /* the fset is now valid */ ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ; } else { nf = ncol ; } for (jj = 0 ; jj < nf ; jj++) { j = (use_fset) ? (fset [jj]) : jj ; /* column j is the fset; find the smallest row (if any) */ p = Ap [j] ; pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; if (pend > p) { k = Ai [p] ; if (!sorted) { for ( ; p < pend ; p++) { k = MIN (k, Ai [p]) ; } } /* place column j on link list k */ ASSERT (k >= 0 && k < nrow) ; Anext [j] = Head [k] ; Head [k] = j ; } } } /* ---------------------------------------------------------------------- */ /* recompute symbolic LDL' factorization */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < nrow ; k++) { #ifndef NDEBUG PRINT1 (("\n\n================== Initial column k = "ID"\n", k)) ; for (p = Lp [k] ; p < Lp [k] + Lnz [k] ; p++) { PRINT1 ((" row: "ID" value: ", Li [p])) ; PRINT1 (("\n")) ; } PRINT1 (("Recomputing LDL, column k = "ID"\n", k)) ; #endif /* ------------------------------------------------------------------ */ /* compute column k of I+F*F' or I+A */ /* ------------------------------------------------------------------ */ /* flag the diagonal entry */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; Flag [k] = mark ; PRINT1 ((" row: "ID" (diagonal)\n", k)) ; if (stype != 0) { /* merge column k of A into Flag (lower triangular part only) */ p = Ap [k] ; pend = (apacked) ? (Ap [k+1]) : (p + Anz [k]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i > k) { Flag [i] = mark ; } } } else { /* for each column j whos first row index is in row k */ for (j = Head [k] ; j != EMPTY ; j = Anext [j]) { /* merge column j of A into Flag */ PRINT1 ((" ---- A column "ID"\n", j)) ; p = Ap [j] ; pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ; PRINT1 ((" length "ID" adding\n", pend-p)) ; for ( ; p < pend ; p++) { #ifndef NDEBUG ASSERT (Ai [p] >= k && Ai [p] < nrow) ; if (Flag [Ai [p]] < mark) PRINT1 ((" row "ID"\n", Ai [p])) ; #endif Flag [Ai [p]] = mark ; } } /* clear the kth link list */ Head [k] = EMPTY ; } /* ------------------------------------------------------------------ */ /* compute pruned pattern of kth column of L = union of children */ /* ------------------------------------------------------------------ */ /* for each column j of L whose parent is k */ for (j = Link [k] ; j != EMPTY ; j = Link [j]) { /* merge column j of L into Flag */ PRINT1 ((" ---- L column "ID"\n", k)) ; ASSERT (j < k) ; ASSERT (Lnz [j] > 0) ; p = Lp [j] ; pend = p + Lnz [j] ; ASSERT (Li [p] == j && Li [p+1] == k) ; p++ ; /* skip past the diagonal entry */ for ( ; p < pend ; p++) { /* add to pattern */ ASSERT (Li [p] >= k && Li [p] < nrow) ; Flag [Li [p]] = mark ; } } /* ------------------------------------------------------------------ */ /* prune the kth column of L */ /* ------------------------------------------------------------------ */ PRINT1 (("Final column of L:\n")) ; p = Lp [k] ; pend = p + Lnz [k] ; if (pack) { /* shift column k upwards */ Lp [k] = pdest ; } else { /* leave column k in place, just reduce Lnz [k] */ pdest = p ; } for ( ; p < pend ; p++) { ASSERT (pdest < pend) ; ASSERT (pdest <= p) ; row = Li [p] ; ASSERT (row >= k && row < nrow) ; if (Flag [row] == mark) { /* keep this entry */ Li [pdest] = row ; if (xtype == CHOLMOD_REAL) { Lx [pdest] = Lx [p] ; } else if (xtype == CHOLMOD_COMPLEX) { Lx [2*pdest ] = Lx [2*p ] ; Lx [2*pdest+1] = Lx [2*p+1] ; } else if (xtype == CHOLMOD_ZOMPLEX) { Lx [pdest] = Lx [p] ; Lz [pdest] = Lz [p] ; } pdest++ ; } } /* ------------------------------------------------------------------ */ /* prepare this column for its parent */ /* ------------------------------------------------------------------ */ Lnz [k] = pdest - Lp [k] ; PRINT1 ((" L("ID") length "ID"\n", k, Lnz [k])) ; ASSERT (Lnz [k] > 0) ; /* parent is the first entry in the column after the diagonal */ parent = (Lnz [k] > 1) ? (Li [Lp [k] + 1]) : EMPTY ; PRINT1 (("parent ("ID") = "ID"\n", k, parent)) ; ASSERT ((parent > k && parent < nrow) || (parent == EMPTY)) ; if (parent != EMPTY) { Link [k] = Link [parent] ; Link [parent] = k ; } } /* done using Iwork for Link, Lnz (if needed), and Anext ] */ /* ---------------------------------------------------------------------- */ /* convert L to packed, if requested */ /* ---------------------------------------------------------------------- */ if (pack) { /* finalize Lp */ Lp [nrow] = pdest ; /* Shrink L to be just large enough. It cannot fail. */ /* workspace: none */ ASSERT ((size_t) (Lp [nrow]) <= L->nzmax) ; CHOLMOD(reallocate_factor) (Lp [nrow], L, Common) ; ASSERT (Common->status >= CHOLMOD_OK) ; } /* ---------------------------------------------------------------------- */ /* clear workspace */ /* ---------------------------------------------------------------------- */ /* CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol final L (i, x):", Common)) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; return (TRUE) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_lsolve.c0000644000175000017500000006306111674452555023700 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/t_cholmod_lsolve ============================================ */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine to solve Lx=b with unit or non-unit diagonal, or * solve LDx=b. * * The numeric xtype of L and Y must match. Y contains b on input and x on * output, stored in row-form. Y is nrow-by-n, where nrow must equal 1 for the * complex or zomplex cases, and nrow <= 4 for the real case. * * This file is not compiled separately. It is included in t_cholmod_solve.c * instead. It contains no user-callable routines. * * workspace: none * * Supports real, complex, and zomplex factors. */ /* undefine all prior definitions */ #undef FORM_NAME #undef LSOLVE /* -------------------------------------------------------------------------- */ /* define the method */ /* -------------------------------------------------------------------------- */ #ifdef LL /* LL': solve Lx=b with non-unit diagonal */ #define FORM_NAME(prefix,rank) prefix ## ll_lsolve_ ## rank #elif defined (LD) /* LDL': solve LDx=b */ #define FORM_NAME(prefix,rank) prefix ## ldl_ldsolve_ ## rank #else /* LDL': solve Lx=b with unit diagonal */ #define FORM_NAME(prefix,rank) prefix ## ldl_lsolve_ ## rank #endif /* LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. */ #define LSOLVE(prefix,rank) FORM_NAME(prefix,rank) #ifdef REAL /* ========================================================================== */ /* === LSOLVE (1) =========================================================== */ /* ========================================================================== */ /* Solve Lx=b, where b has 1 column */ static void LSOLVE (PREFIX,1) ( cholmod_factor *L, double X [ ] /* n-by-1 in row form */ ) { double *Lx = L->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = 0 ; j < n ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j+1, and j+2) */ if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y = X [j] ; #ifdef LL y /= Lx [p] ; X [j] = y ; #elif defined (LD) X [j] = y / Lx [p] ; #endif for (p++ ; p < pend ; p++) { X [Li [p]] -= Lx [p] * y ; } j++ ; /* advance to next column of L */ } else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2] ; Int q = Lp [j+1] ; #ifdef LL y [0] = X [j] / Lx [p] ; y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ; X [j ] = y [0] ; X [j+1] = y [1] ; #elif defined (LD) y [0] = X [j] ; y [1] = X [j+1] - Lx [p+1] * y [0] ; X [j ] = y [0] / Lx [p] ; X [j+1] = y [1] / Lx [q] ; #else y [0] = X [j] ; y [1] = X [j+1] - Lx [p+1] * y [0] ; X [j+1] = y [1] ; #endif for (p += 2, q++ ; p < pend ; p++, q++) { X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] ; } j += 2 ; /* advance to next column of L */ } else { /* -------------------------------------------------------------- */ /* solve with a supernode of three columns of L */ /* -------------------------------------------------------------- */ double y [3] ; Int q = Lp [j+1] ; Int r = Lp [j+2] ; #ifdef LL y [0] = X [j] / Lx [p] ; y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ; y [2] = (X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1]) / Lx [r] ; X [j ] = y [0] ; X [j+1] = y [1] ; X [j+2] = y [2] ; #elif defined (LD) y [0] = X [j] ; y [1] = X [j+1] - Lx [p+1] * y [0] ; y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ; X [j ] = y [0] / Lx [p] ; X [j+1] = y [1] / Lx [q] ; X [j+2] = y [2] / Lx [r] ; #else y [0] = X [j] ; y [1] = X [j+1] - Lx [p+1] * y [0] ; y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ; X [j+1] = y [1] ; X [j+2] = y [2] ; #endif for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) { X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] + Lx [r] * y [2] ; } j += 3 ; /* advance to next column of L */ } } } /* ========================================================================== */ /* === LSOLVE (2) =========================================================== */ /* ========================================================================== */ /* Solve Lx=b, where b has 2 columns */ static void LSOLVE (PREFIX,2) ( cholmod_factor *L, double X [ ][2] /* n-by-2 in row form */ ) { double *Lx = L->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = 0 ; j < n ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j+1, and j+2) */ if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y [2] ; y [0] = X [j][0] ; y [1] = X [j][1] ; #ifdef LL y [0] /= Lx [p] ; y [1] /= Lx [p] ; X [j][0] = y [0] ; X [j][1] = y [1] ; #elif defined (LD) X [j][0] = y [0] / Lx [p] ; X [j][1] = y [1] / Lx [p] ; #endif for (p++ ; p < pend ; p++) { Int i = Li [p] ; X [i][0] -= Lx [p] * y [0] ; X [i][1] -= Lx [p] * y [1] ; } j++ ; /* advance to next column of L */ } else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2][2] ; Int q = Lp [j+1] ; y [0][0] = X [j][0] ; y [0][1] = X [j][1] ; #ifdef LL y [0][0] /= Lx [p] ; y [0][1] /= Lx [p] ; y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; #elif defined (LD) y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; X [j ][0] = y [0][0] / Lx [p] ; X [j ][1] = y [0][1] / Lx [p] ; X [j+1][0] = y [1][0] / Lx [q] ; X [j+1][1] = y [1][1] / Lx [q] ; #else y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; #endif for (p += 2, q++ ; p < pend ; p++, q++) { Int i = Li [p] ; X [i][0] -= Lx [p] * y [0][0] + Lx [q] * y [1][0] ; X [i][1] -= Lx [p] * y [0][1] + Lx [q] * y [1][1] ; } j += 2 ; /* advance to next column of L */ } else { /* -------------------------------------------------------------- */ /* solve with a supernode of three columns of L */ /* -------------------------------------------------------------- */ double y [3][2] ; Int q = Lp [j+1] ; Int r = Lp [j+2] ; y [0][0] = X [j][0] ; y [0][1] = X [j][1] ; #ifdef LL y [0][0] /= Lx [p] ; y [0][1] /= Lx [p] ; y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+2][0] = y [2][0] ; X [j+2][1] = y [2][1] ; #elif defined (LD) y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; X [j ][0] = y [0][0] / Lx [p] ; X [j ][1] = y [0][1] / Lx [p] ; X [j+1][0] = y [1][0] / Lx [q] ; X [j+1][1] = y [1][1] / Lx [q] ; X [j+2][0] = y [2][0] / Lx [r] ; X [j+2][1] = y [2][1] / Lx [r] ; #else y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+2][0] = y [2][0] ; X [j+2][1] = y [2][1] ; #endif for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) { Int i = Li [p] ; X[i][0] -= Lx[p] * y[0][0] + Lx[q] * y[1][0] + Lx[r] * y[2][0] ; X[i][1] -= Lx[p] * y[0][1] + Lx[q] * y[1][1] + Lx[r] * y[2][1] ; } j += 3 ; /* advance to next column of L */ } } } /* ========================================================================== */ /* === LSOLVE (3) =========================================================== */ /* ========================================================================== */ /* Solve Lx=b, where b has 3 columns */ static void LSOLVE (PREFIX,3) ( cholmod_factor *L, double X [ ][3] /* n-by-3 in row form */ ) { double *Lx = L->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = 0 ; j < n ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j+1, and j+2) */ if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y [3] ; y [0] = X [j][0] ; y [1] = X [j][1] ; y [2] = X [j][2] ; #ifdef LL y [0] /= Lx [p] ; y [1] /= Lx [p] ; y [2] /= Lx [p] ; X [j][0] = y [0] ; X [j][1] = y [1] ; X [j][2] = y [2] ; #elif defined (LD) X [j][0] = y [0] / Lx [p] ; X [j][1] = y [1] / Lx [p] ; X [j][2] = y [2] / Lx [p] ; #endif for (p++ ; p < pend ; p++) { Int i = Li [p] ; double lx = Lx [p] ; X [i][0] -= lx * y [0] ; X [i][1] -= lx * y [1] ; X [i][2] -= lx * y [2] ; } j++ ; /* advance to next column of L */ } else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2][3] ; Int q = Lp [j+1] ; y [0][0] = X [j][0] ; y [0][1] = X [j][1] ; y [0][2] = X [j][2] ; #ifdef LL y [0][0] /= Lx [p] ; y [0][1] /= Lx [p] ; y [0][2] /= Lx [p] ; y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ; X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j ][2] = y [0][2] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; #elif defined (LD) y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; X [j ][0] = y [0][0] / Lx [p] ; X [j ][1] = y [0][1] / Lx [p] ; X [j ][2] = y [0][2] / Lx [p] ; X [j+1][0] = y [1][0] / Lx [q] ; X [j+1][1] = y [1][1] / Lx [q] ; X [j+1][2] = y [1][2] / Lx [q] ; #else y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; #endif for (p += 2, q++ ; p < pend ; p++, q++) { Int i = Li [p] ; double lx [2] ; lx [0] = Lx [p] ; lx [1] = Lx [q] ; X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ; X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ; X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ; } j += 2 ; /* advance to next column of L */ } else { /* -------------------------------------------------------------- */ /* solve with a supernode of three columns of L */ /* -------------------------------------------------------------- */ double y [3][3] ; Int q = Lp [j+1] ; Int r = Lp [j+2] ; y [0][0] = X [j][0] ; y [0][1] = X [j][1] ; y [0][2] = X [j][2] ; #ifdef LL y [0][0] /= Lx [p] ; y [0][1] /= Lx [p] ; y [0][2] /= Lx [p] ; y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ; y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r]; X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j ][2] = y [0][2] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; X [j+2][0] = y [2][0] ; X [j+2][1] = y [2][1] ; X [j+2][2] = y [2][2] ; #elif defined (LD) y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; X [j ][0] = y [0][0] / Lx [p] ; X [j ][1] = y [0][1] / Lx [p] ; X [j ][2] = y [0][2] / Lx [p] ; X [j+1][0] = y [1][0] / Lx [q] ; X [j+1][1] = y [1][1] / Lx [q] ; X [j+1][2] = y [1][2] / Lx [q] ; X [j+2][0] = y [2][0] / Lx [r] ; X [j+2][1] = y [2][1] / Lx [r] ; X [j+2][2] = y [2][2] / Lx [r] ; #else y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; X [j+2][0] = y [2][0] ; X [j+2][1] = y [2][1] ; X [j+2][2] = y [2][2] ; #endif for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) { Int i = Li [p] ; double lx [3] ; lx [0] = Lx [p] ; lx [1] = Lx [q] ; lx [2] = Lx [r] ; X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0]; X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1]; X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2]; } j += 3 ; /* advance to next column of L */ } } } /* ========================================================================== */ /* === LSOLVE (4) =========================================================== */ /* ========================================================================== */ /* Solve Lx=b, where b has 4 columns */ static void LSOLVE (PREFIX,4) ( cholmod_factor *L, double X [ ][4] /* n-by-4 in row form */ ) { double *Lx = L->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = 0 ; j < n ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j+1, and j+2) */ if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y [4] ; y [0] = X [j][0] ; y [1] = X [j][1] ; y [2] = X [j][2] ; y [3] = X [j][3] ; #ifdef LL y [0] /= Lx [p] ; y [1] /= Lx [p] ; y [2] /= Lx [p] ; y [3] /= Lx [p] ; X [j][0] = y [0] ; X [j][1] = y [1] ; X [j][2] = y [2] ; X [j][3] = y [3] ; #elif defined (LD) X [j][0] = y [0] / Lx [p] ; X [j][1] = y [1] / Lx [p] ; X [j][2] = y [2] / Lx [p] ; X [j][3] = y [3] / Lx [p] ; #endif for (p++ ; p < pend ; p++) { Int i = Li [p] ; double lx = Lx [p] ; X [i][0] -= lx * y [0] ; X [i][1] -= lx * y [1] ; X [i][2] -= lx * y [2] ; X [i][3] -= lx * y [3] ; } j++ ; /* advance to next column of L */ } else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2) { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2][4] ; Int q = Lp [j+1] ; y [0][0] = X [j][0] ; y [0][1] = X [j][1] ; y [0][2] = X [j][2] ; y [0][3] = X [j][3] ; #ifdef LL y [0][0] /= Lx [p] ; y [0][1] /= Lx [p] ; y [0][2] /= Lx [p] ; y [0][3] /= Lx [p] ; y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ; y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ; y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ; y [1][3] = (X [j+1][3] - Lx [p+1] * y [0][3]) / Lx [q] ; X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j ][2] = y [0][2] ; X [j ][3] = y [0][3] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; X [j+1][3] = y [1][3] ; #elif defined (LD) y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; X [j ][0] = y [0][0] / Lx [p] ; X [j ][1] = y [0][1] / Lx [p] ; X [j ][2] = y [0][2] / Lx [p] ; X [j ][3] = y [0][3] / Lx [p] ; X [j+1][0] = y [1][0] / Lx [q] ; X [j+1][1] = y [1][1] / Lx [q] ; X [j+1][2] = y [1][2] / Lx [q] ; X [j+1][3] = y [1][3] / Lx [q] ; #else y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; X [j+1][3] = y [1][3] ; #endif for (p += 2, q++ ; p < pend ; p++, q++) { Int i = Li [p] ; double lx [2] ; lx [0] = Lx [p] ; lx [1] = Lx [q] ; X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ; X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ; X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ; X [i][3] -= lx [0] * y [0][3] + lx [1] * y [1][3] ; } j += 2 ; /* advance to next column of L */ } else { /* -------------------------------------------------------------- */ /* solve with a supernode of three columns of L */ /* -------------------------------------------------------------- */ double y [3][4] ; Int q = Lp [j+1] ; Int r = Lp [j+2] ; y [0][0] = X [j][0] ; y [0][1] = X [j][1] ; y [0][2] = X [j][2] ; y [0][3] = X [j][3] ; #ifdef LL y [0][0] /= Lx [p] ; y [0][1] /= Lx [p] ; y [0][2] /= Lx [p] ; y [0][3] /= Lx [p] ; y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ; y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ; y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ; y [1][3] = (X [j+1][3] - Lx[p+1] * y[0][3]) / Lx [q] ; y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r]; y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r]; y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r]; y [2][3] = (X [j+2][3] - Lx[p+2] * y[0][3] - Lx[q+1]*y[1][3])/Lx[r]; X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j ][2] = y [0][2] ; X [j ][3] = y [0][3] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; X [j+1][3] = y [1][3] ; X [j+2][0] = y [2][0] ; X [j+2][1] = y [2][1] ; X [j+2][2] = y [2][2] ; X [j+2][3] = y [2][3] ; #elif defined (LD) y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ; X [j ][0] = y [0][0] / Lx [p] ; X [j ][1] = y [0][1] / Lx [p] ; X [j ][2] = y [0][2] / Lx [p] ; X [j ][3] = y [0][3] / Lx [p] ; X [j+1][0] = y [1][0] / Lx [q] ; X [j+1][1] = y [1][1] / Lx [q] ; X [j+1][2] = y [1][2] / Lx [q] ; X [j+1][3] = y [1][3] / Lx [q] ; X [j+2][0] = y [2][0] / Lx [r] ; X [j+2][1] = y [2][1] / Lx [r] ; X [j+2][2] = y [2][2] / Lx [r] ; X [j+2][3] = y [2][3] / Lx [r] ; #else y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ; y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ; y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ; y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ; y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ; y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ; y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ; y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ; X [j+1][0] = y [1][0] ; X [j+1][1] = y [1][1] ; X [j+1][2] = y [1][2] ; X [j+1][3] = y [1][3] ; X [j+2][0] = y [2][0] ; X [j+2][1] = y [2][1] ; X [j+2][2] = y [2][2] ; X [j+2][3] = y [2][3] ; #endif for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++) { Int i = Li [p] ; double lx [3] ; lx [0] = Lx [p] ; lx [1] = Lx [q] ; lx [2] = Lx [r] ; X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0]; X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1]; X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2]; X [i][3] -= lx[0] * y[0][3] + lx[1] * y[1][3] + lx[2] * y[2][3]; } j += 3 ; /* advance to next column of L */ } } } #endif /* ========================================================================== */ /* === LSOLVE (k) =========================================================== */ /* ========================================================================== */ static void LSOLVE (PREFIX,k) ( cholmod_factor *L, cholmod_dense *Y /* nr-by-n where nr is 1 to 4 */ ) { #ifndef REAL double yx [2] ; #ifdef ZOMPLEX double yz [1] ; double *Lz = L->z ; double *Xz = Y->z ; #endif double *Lx = L->x ; double *Xx = Y->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int i, j, n = L->n ; #endif ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */ ASSERT (L->n == Y->ncol) ; /* dimensions must match */ ASSERT (Y->nrow == Y->d) ; /* leading dimension of Y = # rows of Y */ ASSERT (L->xtype != CHOLMOD_PATTERN) ; /* L is not symbolic */ ASSERT (!(L->is_super)) ; /* L is simplicial LL' or LDL' */ #ifdef REAL /* ---------------------------------------------------------------------- */ /* solve a real linear system, with 1 to 4 RHS's and dynamic supernodes */ /* ---------------------------------------------------------------------- */ ASSERT (Y->nrow <= 4) ; switch (Y->nrow) { case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ; case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ; case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ; case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ; } #else /* ---------------------------------------------------------------------- */ /* solve a complex linear system, with just one right-hand-side */ /* ---------------------------------------------------------------------- */ ASSERT (Y->nrow == 1) ; for (j = 0 ; j < n ; j++) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* y = X [j] ; */ ASSIGN (yx,yz,0, Xx,Xz,j) ; #ifdef LL /* y /= Lx [p] ; */ /* X [j] = y ; */ DIV_REAL (yx,yz,0, yx,yz,0, Lx,p) ; ASSIGN (Xx,Xz,j, yx,yz,0) ; #elif defined (LD) /* X [j] = y / Lx [p] ; */ DIV_REAL (Xx,Xz,j, yx,yz,0, Lx,p) ; #endif for (p++ ; p < pend ; p++) { /* X [Li [p]] -= Lx [p] * y ; */ i = Li [p] ; MULTSUB (Xx,Xz,i, Lx,Lz,p, yx,yz,0) ; } } #endif } /* prepare for the next inclusion of this file in cholmod_solve.c */ #undef LL #undef LD cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_analyze.c0000644000175000017500000007747711674452555023534 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_analyze ============================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Order and analyze a matrix (either simplicial or supernodal), in prepartion * for numerical factorization via cholmod_factorize or via the "expert" * routines cholmod_rowfac and cholmod_super_numeric. * * symmetric case: A or A(p,p) * unsymmetric case: AA', A(p,:)*A(p,:)', A(:,f)*A(:,f)', or A(p,f)*A(p,f)' * * For the symmetric case, only the upper or lower triangular part of A is * accessed (depending on the type of A). LL'=A (or permuted A) is analzed. * For the unsymmetric case (LL'=AA' or permuted A). * * There can be no duplicate entries in p or f. p is of length m if A is * m-by-n. f can be length 0 to n. * * In both cases, the columns of A need not be sorted. A can be in packed * or unpacked form. * * Ordering options include: * * natural: A is not permuted to reduce fill-in * given: a permutation can be provided to this routine (UserPerm) * AMD: approximate minumum degree (AMD for the symmetric case, * COLAMD for the AA' case). * METIS: nested dissection with METIS_NodeND * NESDIS: nested dissection using METIS_NodeComputeSeparator, * typically followed by a constrained minimum degree * (CAMD for the symmetric case, CCOLAMD for the AA' case). * * Multiple ordering options can be tried (up to 9 of them), and the best one * is selected (the one that gives the smallest number of nonzeros in the * simplicial factor L). If one method fails, cholmod_analyze keeps going, and * picks the best among the methods that succeeded. This routine fails (and * returns NULL) if either initial memory allocation fails, all ordering methods * fail, or the supernodal analysis (if requested) fails. By default, the 9 * methods available are: * * 1) given permutation (skipped if UserPerm is NULL) * 2) AMD (symmetric case) or COLAMD (unsymmetric case) * 3) METIS with default parameters * 4) NESDIS with default parameters (stopping the partitioning when * the graph is of size nd_small = 200 or less, remove nodes with * more than max (16, prune_dense * sqrt (n)) nodes where * prune_dense = 10, and follow partitioning with CCOLAMD, a * constrained minimum degree ordering). * 5) natural * 6) NESDIS, nd_small = 20000, prune_dense = 10 * 7) NESDIS, nd_small = 4, prune_dense = 10, no min degree * 8) NESDIS, nd_small = 200, prune_dense = 0 * 9) COLAMD for A*A' or AMD for A * * By default, the first two are tried, and METIS is tried if AMD reports a high * flop count and fill-in. Let fl denote the flop count for the AMD, ordering, * nnz(L) the # of nonzeros in L, and nnz(tril(A)) (or A*A'). If * fl/nnz(L) >= 500 and nnz(L)/nnz(tril(A)) >= 5, then METIS is attempted. The * best ordering is used (UserPerm if given, AMD, and METIS if attempted). If * you do not have METIS, only the first two will be tried (user permutation, * if provided, and AMD/COLAMD). This default behavior is obtained when * Common->nmethods is zero. In this case, methods 0, 1, and 2 in * Common->method [..] are reset to User-provided, AMD, and METIS (or NESDIS * if Common->default_nesdis is set to the non-default value of TRUE), * respectively. * * You can modify these 9 methods and the number of methods tried by changing * parameters in the Common argument. If you know the best ordering for your * matrix, set Common->nmethods to 1 and set Common->method[0].ordering to the * requested ordering method. Parameters for each method can also be modified * (refer to cholmod.h for details). * * Note that it is possible for METIS to terminate your program if it runs out * of memory. This is not the case for any CHOLMOD or minimum degree ordering * routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD). Since NESDIS relies on * METIS, it too can terminate your program. * * The factor L is returned as simplicial symbolic (L->is_super FALSE) if * Common->supernodal <= CHOLMOD_SIMPLICIAL (0) or as supernodal symbolic if * Common->supernodal >= CHOLMOD_SUPERNODAL (2). If Common->supernodal is * equal to CHOLMOD_AUTO (1), then L is simplicial if the flop count per * nonzero in L is less than Common->supernodal_switch (default: 40), and * is returned as a supernodal factor otherwise. * * In both cases, L->xtype is CHOLMOD_PATTERN. * A subsequent call to cholmod_factorize will perform a * simplicial or supernodal factorization, depending on the type of L. * * For the simplicial case, L contains the fill-reducing permutation (L->Perm) * and the counts of nonzeros in each column of L (L->ColCount). For the * supernodal case, L also contains the nonzero pattern of each supernode. * * workspace: Flag (nrow), Head (nrow+1) * if symmetric: Iwork (6*nrow) * if unsymmetric: Iwork (6*nrow+ncol). * calls various ordering routines, which typically allocate O(nnz(A)) * temporary workspace ((2 to 3)*nnz(A) * sizeof (Int) is typical, but it * can be much higher if A*A' must be explicitly formed for METIS). Also * allocates up to 2 temporary (permuted/transpose) copies of the nonzero * pattern of A, and up to 3*n*sizeof(Int) additional workspace. * * Supports any xtype (pattern, real, complex, or zomplex) */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" #ifndef NSUPERNODAL #include "cholmod_supernodal.h" #endif #ifndef NPARTITION #include "cholmod_partition.h" #endif /* ========================================================================== */ /* === cholmod_analyze ====================================================== */ /* ========================================================================== */ /* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor * that can later be passed to cholmod_factorize. */ cholmod_factor *CHOLMOD(analyze) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order and analyze */ /* --------------- */ cholmod_common *Common ) { return (CHOLMOD(analyze_p2) (TRUE, A, NULL, NULL, 0, Common)) ; } /* ========================================================================== */ /* === cholmod_analyze_p ==================================================== */ /* ========================================================================== */ /* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a * symbolic factor that can later be passed to cholmod_factorize, where * F = A(:,fset) if fset is not NULL and A->stype is zero. * UserPerm is tried if non-NULL. */ cholmod_factor *CHOLMOD(analyze_p) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order and analyze */ Int *UserPerm, /* user-provided permutation, size A->nrow */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* --------------- */ cholmod_common *Common ) { return (CHOLMOD(analyze_p2) (TRUE, A, UserPerm, fset, fsize, Common)) ; } /* ========================================================================== */ /* === permute_matrices ===================================================== */ /* ========================================================================== */ /* Permute and transpose a matrix. Allocates the A1 and A2 matrices, if needed, * or returns them as NULL if not needed. */ static int permute_matrices ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to permute */ Int ordering, /* ordering method used */ Int *Perm, /* fill-reducing permutation */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ Int do_rowcolcounts,/* if TRUE, compute both S and F. If FALSE, only * S is needed for the symmetric case, and only F for * the unsymmetric case */ /* ---- output --- */ cholmod_sparse **A1_handle, /* see comments below for A1, A2, S, F */ cholmod_sparse **A2_handle, cholmod_sparse **S_handle, cholmod_sparse **F_handle, /* --------------- */ cholmod_common *Common ) { cholmod_sparse *A1, *A2, *S, *F ; *A1_handle = NULL ; *A2_handle = NULL ; *S_handle = NULL ; *F_handle = NULL ; A1 = NULL ; A2 = NULL ; if (ordering == CHOLMOD_NATURAL) { /* ------------------------------------------------------------------ */ /* natural ordering of A */ /* ------------------------------------------------------------------ */ if (A->stype < 0) { /* symmetric lower case: A already in lower form, so S=A' */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ; F = A ; S = A2 ; } else if (A->stype > 0) { /* symmetric upper case: F = pattern of triu (A)', S = A */ /* workspace: Iwork (nrow) */ if (do_rowcolcounts) { /* F not needed for symmetric case if do_rowcolcounts FALSE */ A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; } F = A1 ; S = A ; } else { /* unsymmetric case: F = pattern of A (:,f)', S = A */ /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */ A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ; F = A1 ; S = A ; } } else { /* ------------------------------------------------------------------ */ /* A is permuted */ /* ------------------------------------------------------------------ */ if (A->stype < 0) { /* symmetric lower case: S = tril (A (p,p))' and F = S' */ /* workspace: Iwork (2*nrow) */ A2 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; S = A2 ; /* workspace: Iwork (nrow) */ if (do_rowcolcounts) { /* F not needed for symmetric case if do_rowcolcounts FALSE */ A1 = CHOLMOD(ptranspose) (A2, 0, NULL, NULL, 0, Common) ; } F = A1 ; } else if (A->stype > 0) { /* symmetric upper case: F = triu (A (p,p))' and S = F' */ /* workspace: Iwork (2*nrow) */ A1 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ; F = A1 ; /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; S = A2 ; } else { /* unsymmetric case: F = A (p,f)' and S = F' */ /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */ A1 = CHOLMOD(ptranspose) (A, 0, Perm, fset, fsize, Common) ; F = A1 ; if (do_rowcolcounts) { /* S not needed for unsymmetric case if do_rowcolcounts FALSE */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ; } S = A2 ; } } /* If any cholmod_*transpose fails, one or more matrices will be NULL */ *A1_handle = A1 ; *A2_handle = A2 ; *S_handle = S ; *F_handle = F ; return (Common->status == CHOLMOD_OK) ; } /* ========================================================================== */ /* === cholmod_analyze_ordering ============================================= */ /* ========================================================================== */ /* Given a matrix A and its fill-reducing permutation, compute the elimination * tree, its (non-weighted) postordering, and the number of nonzeros in each * column of L. Also computes the flop count, the total nonzeros in L, and * the nonzeros in A (Common->fl, Common->lnz, and Common->anz). * * The column counts of L, flop count, and other statistics from * cholmod_rowcolcounts are not computed if ColCount is NULL. * * workspace: Iwork (2*nrow if symmetric, 2*nrow+ncol if unsymmetric), * Flag (nrow), Head (nrow+1) */ int CHOLMOD(analyze_ordering) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ int ordering, /* ordering method used */ Int *Perm, /* size n, fill-reducing permutation to analyze */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ Int *Parent, /* size n, elimination tree */ Int *Post, /* size n, postordering of elimination tree */ Int *ColCount, /* size n, nnz in each column of L */ /* ---- workspace */ Int *First, /* size n workspace for cholmod_postorder */ Int *Level, /* size n workspace for cholmod_postorder */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *A1, *A2, *S, *F ; Int n, ok, do_rowcolcounts ; /* check inputs */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; n = A->nrow ; do_rowcolcounts = (ColCount != NULL) ; /* permute A according to Perm and fset */ ok = permute_matrices (A, ordering, Perm, fset, fsize, do_rowcolcounts, &A1, &A2, &S, &F, Common) ; /* find etree of S (symmetric upper/lower case) or F (unsym case) */ /* workspace: symmmetric: Iwork (nrow), unsym: Iwork (nrow+ncol) */ ok = ok && CHOLMOD(etree) (A->stype ? S:F, Parent, Common) ; /* postorder the etree (required by cholmod_rowcolcounts) */ /* workspace: Iwork (2*nrow) */ ok = ok && (CHOLMOD(postorder) (Parent, n, NULL, Post, Common) == n) ; /* cholmod_postorder doesn't set Common->status if it returns < n */ Common->status = (!ok && Common->status == CHOLMOD_OK) ? CHOLMOD_INVALID : Common->status ; /* analyze LL'=S or SS' or S(:,f)*S(:,f)' */ /* workspace: * if symmetric: Flag (nrow), Iwork (2*nrow) * if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1) */ if (do_rowcolcounts) { ok = ok && CHOLMOD(rowcolcounts) (A->stype ? F:S, fset, fsize, Parent, Post, NULL, ColCount, First, Level, Common) ; } /* free temporary matrices and return result */ CHOLMOD(free_sparse) (&A1, Common) ; CHOLMOD(free_sparse) (&A2, Common) ; return (ok) ; } /* ========================================================================== */ /* === Free workspace and return L ========================================== */ /* ========================================================================== */ #define FREE_WORKSPACE_AND_RETURN \ { \ Common->no_workspace_reallocate = FALSE ; \ CHOLMOD(free) (n, sizeof (Int), Lparent, Common) ; \ CHOLMOD(free) (n, sizeof (Int), Perm, Common) ; \ CHOLMOD(free) (n, sizeof (Int), ColCount, Common) ; \ if (Common->status < CHOLMOD_OK) \ { \ CHOLMOD(free_factor) (&L, Common) ; \ } \ ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \ return (L) ; \ } /* ========================================================================== */ /* === cholmod_analyze_p2 =================================================== */ /* ========================================================================== */ /* Ordering and analysis for sparse Cholesky or sparse QR. CHOLMOD itself * always uses for_cholesky = TRUE. The for_cholesky = FALSE option is * for SuiteSparseQR only. */ cholmod_factor *CHOLMOD(analyze_p2) ( /* ---- input ---- */ int for_cholesky, /* if TRUE, then analyze for Cholesky; else for QR */ cholmod_sparse *A, /* matrix to order and analyze */ Int *UserPerm, /* user-provided permutation, size A->nrow */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* --------------- */ cholmod_common *Common ) { double lnz_best ; Int *First, *Level, *Work4n, *Cmember, *CParent, *ColCount, *Lperm, *Parent, *Post, *Perm, *Lparent, *Lcolcount ; cholmod_factor *L ; Int k, n, ordering, method, nmethods, status, default_strategy, ncol, uncol, skip_analysis, skip_best ; Int amd_backup ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; Common->status = CHOLMOD_OK ; status = CHOLMOD_OK ; Common->selected = EMPTY ; Common->called_nd = FALSE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ n = A->nrow ; ncol = A->ncol ; uncol = (A->stype == 0) ? (A->ncol) : 0 ; /* ---------------------------------------------------------------------- */ /* set the default strategy */ /* ---------------------------------------------------------------------- */ lnz_best = (double) EMPTY ; skip_best = FALSE ; nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ; nmethods = MAX (0, nmethods) ; PRINT1 (("nmethods "ID"\n", nmethods)) ; default_strategy = (nmethods == 0) ; if (default_strategy) { /* default strategy: try UserPerm, if given. Try AMD for A, or AMD * to order A*A'. Try METIS for the symmetric case only if AMD reports * a high degree of fill-in and flop count. METIS is not tried if the * Partition Module isn't installed. If Common->default_nesdis is * TRUE, then NESDIS is used as the 3rd ordering instead. */ Common->method [0].ordering = CHOLMOD_GIVEN ;/* skip if UserPerm NULL */ Common->method [1].ordering = CHOLMOD_AMD ; Common->method [2].ordering = (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ; amd_backup = FALSE ; #ifndef NPARTITION nmethods = 3 ; #else nmethods = 2 ; #endif } else { /* If only METIS and NESDIS are selected, or if 2 or more methods are * being tried, then enable AMD backup */ amd_backup = (nmethods > 1) || (nmethods == 1 && (Common->method [0].ordering == CHOLMOD_METIS || Common->method [0].ordering == CHOLMOD_NESDIS)) ; } #ifdef NSUPERNODAL /* CHOLMOD Supernodal module not installed, just do simplicial analysis */ Common->supernodal = CHOLMOD_SIMPLICIAL ; #endif /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* Note: enough space needs to be allocated here so that routines called by * cholmod_analyze do not reallocate the space. */ /* s = 6*n + uncol */ s = CHOLMOD(mult_size_t) (n, 6, &ok) ; s = CHOLMOD(add_size_t) (s, uncol, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } CHOLMOD(allocate_work) (n, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ensure that subsequent routines, called by cholmod_analyze, do not * reallocate any workspace. This is set back to FALSE in the * FREE_WORKSPACE_AND_RETURN macro, which is the only way this function * returns to its caller. */ Common->no_workspace_reallocate = TRUE ; /* Use the last 4*n Int's in Iwork for Parent, First, Level, and Post, since * other CHOLMOD routines will use the first 2n+uncol space. The ordering * routines (cholmod_amd, cholmod_colamd, cholmod_ccolamd, cholmod_metis) * are an exception. They can use all 6n + ncol space, since the contents * of Parent, First, Level, and Post are not needed across calls to those * routines. */ Work4n = Common->Iwork ; Work4n += 2*((size_t) n) + uncol ; Parent = Work4n ; First = Work4n + n ; Level = Work4n + 2*((size_t) n) ; Post = Work4n + 3*((size_t) n) ; /* note that this assignment means that cholmod_nested_dissection, * cholmod_ccolamd, and cholmod_camd can use only the first 4n+uncol * space in Common->Iwork */ Cmember = Post ; CParent = Level ; /* ---------------------------------------------------------------------- */ /* allocate more workspace, and an empty simplicial symbolic factor */ /* ---------------------------------------------------------------------- */ L = CHOLMOD(allocate_factor) (n, Common) ; Lparent = CHOLMOD(malloc) (n, sizeof (Int), Common) ; Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ; ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ FREE_WORKSPACE_AND_RETURN ; } Lperm = L->Perm ; Lcolcount = L->ColCount ; Common->anz = EMPTY ; /* ---------------------------------------------------------------------- */ /* try all the requested ordering options and backup to AMD if needed */ /* ---------------------------------------------------------------------- */ /* turn off error handling [ */ Common->try_catch = TRUE ; for (method = 0 ; method <= nmethods ; method++) { /* ------------------------------------------------------------------ */ /* determine the method to try */ /* ------------------------------------------------------------------ */ Common->fl = EMPTY ; Common->lnz = EMPTY ; skip_analysis = FALSE ; if (method == nmethods) { /* All methods failed: backup to AMD */ if (Common->selected == EMPTY && amd_backup) { PRINT1 (("All methods requested failed: backup to AMD\n")) ; ordering = CHOLMOD_AMD ; } else { break ; } } else { ordering = Common->method [method].ordering ; } Common->current = method ; PRINT1 (("method "ID": Try method: "ID"\n", method, ordering)) ; /* ------------------------------------------------------------------ */ /* find the fill-reducing permutation */ /* ------------------------------------------------------------------ */ if (ordering == CHOLMOD_NATURAL) { /* -------------------------------------------------------------- */ /* natural ordering */ /* -------------------------------------------------------------- */ for (k = 0 ; k < n ; k++) { Perm [k] = k ; } } else if (ordering == CHOLMOD_GIVEN) { /* -------------------------------------------------------------- */ /* use given ordering of A, if provided */ /* -------------------------------------------------------------- */ if (UserPerm == NULL) { /* this is not an error condition */ PRINT1 (("skip, no user perm given\n")) ; continue ; } for (k = 0 ; k < n ; k++) { /* UserPerm is checked in cholmod_ptranspose */ Perm [k] = UserPerm [k] ; } } else if (ordering == CHOLMOD_AMD) { /* -------------------------------------------------------------- */ /* AMD ordering of A, A*A', or A(:,f)*A(:,f)' */ /* -------------------------------------------------------------- */ amd_backup = FALSE ; /* no need to try AMD twice ... */ CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; skip_analysis = TRUE ; } else if (ordering == CHOLMOD_COLAMD) { /* -------------------------------------------------------------- */ /* AMD for symmetric case, COLAMD for A*A' or A(:,f)*A(:,f)' */ /* -------------------------------------------------------------- */ if (A->stype) { CHOLMOD(amd) (A, fset, fsize, Perm, Common) ; skip_analysis = TRUE ; } else { /* Alternative: CHOLMOD(ccolamd) (A, fset, fsize, NULL, Perm, Common) ; */ /* do not postorder, it is done later, below */ /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1)*/ CHOLMOD(colamd) (A, fset, fsize, FALSE, Perm, Common) ; } } else if (ordering == CHOLMOD_METIS) { /* -------------------------------------------------------------- */ /* use METIS_NodeND directly (via a CHOLMOD wrapper) */ /* -------------------------------------------------------------- */ #ifndef NPARTITION /* postorder parameter is false, because it will be later, below */ /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) */ Common->called_nd = TRUE ; CHOLMOD(metis) (A, fset, fsize, FALSE, Perm, Common) ; #else Common->status = CHOLMOD_NOT_INSTALLED ; #endif } else if (ordering == CHOLMOD_NESDIS) { /* -------------------------------------------------------------- */ /* use CHOLMOD's nested dissection */ /* -------------------------------------------------------------- */ /* this method is based on METIS' node bissection routine * (METIS_NodeComputeSeparator). In contrast to METIS_NodeND, * it calls CAMD or CCOLAMD on the whole graph, instead of MMD * on just the leaves. */ #ifndef NPARTITION /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow) */ Common->called_nd = TRUE ; CHOLMOD(nested_dissection) (A, fset, fsize, Perm, CParent, Cmember, Common) ; #else Common->status = CHOLMOD_NOT_INSTALLED ; #endif } else { /* -------------------------------------------------------------- */ /* invalid ordering method */ /* -------------------------------------------------------------- */ Common->status = CHOLMOD_INVALID ; PRINT1 (("No such ordering: "ID"\n", ordering)) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; if (Common->status < CHOLMOD_OK) { /* out of memory, or method failed */ status = MIN (status, Common->status) ; Common->status = CHOLMOD_OK ; continue ; } /* ------------------------------------------------------------------ */ /* analyze the ordering */ /* ------------------------------------------------------------------ */ if (!skip_analysis) { if (!CHOLMOD(analyze_ordering) (A, ordering, Perm, fset, fsize, Parent, Post, ColCount, First, Level, Common)) { /* ordering method failed; clear status and try next method */ status = MIN (status, Common->status) ; Common->status = CHOLMOD_OK ; continue ; } } ASSERT (Common->fl >= 0 && Common->lnz >= 0) ; Common->method [method].fl = Common->fl ; Common->method [method].lnz = Common->lnz ; PRINT1 (("lnz %g fl %g\n", Common->lnz, Common->fl)) ; /* ------------------------------------------------------------------ */ /* pick the best method */ /* ------------------------------------------------------------------ */ /* fl.pt. compare, but lnz can never be NaN */ if (Common->selected == EMPTY || Common->lnz < lnz_best) { Common->selected = method ; PRINT1 (("this is best so far, method "ID"\n", method)) ; L->ordering = ordering ; lnz_best = Common->lnz ; for (k = 0 ; k < n ; k++) { Lperm [k] = Perm [k] ; } /* save the results of cholmod_analyze_ordering, if it was called */ skip_best = skip_analysis ; if (!skip_analysis) { /* save the column count; becomes permanent part of L */ for (k = 0 ; k < n ; k++) { Lcolcount [k] = ColCount [k] ; } /* Parent is needed for weighted postordering and for supernodal * analysis. Does not become a permanent part of L */ for (k = 0 ; k < n ; k++) { Lparent [k] = Parent [k] ; } } } /* ------------------------------------------------------------------ */ /* determine if METIS is to be skipped */ /* ------------------------------------------------------------------ */ if (default_strategy && ordering == CHOLMOD_AMD) { if ((Common->fl < 500 * Common->lnz) || (Common->lnz < 5 * Common->anz)) { /* AMD found an ordering with less than 500 flops per nonzero in * L, or one with a fill-in ratio (nnz(L)/nnz(A)) of less than * 5. This is pretty good, and it's unlikely that METIS will do * better (this heuristic is based on tests on all symmetric * positive definite matrices in the UF sparse matrix * collection, and it works well across a wide range of * problems). METIS can take much more time than AMD. */ break ; } } } /* turn error printing back on ] */ Common->try_catch = FALSE ; /* ---------------------------------------------------------------------- */ /* return if no ordering method succeeded */ /* ---------------------------------------------------------------------- */ if (Common->selected == EMPTY) { /* All methods failed. * If two or more methods failed, they may have failed for different * reasons. Both would clear Common->status and skip to the next * method. Common->status needs to be restored here to the worst error * obtained in any of the methods. CHOLMOD_INVALID is worse * than CHOLMOD_OUT_OF_MEMORY, since the former implies something may * be wrong with the user's input. CHOLMOD_OUT_OF_MEMORY is simply an * indication of lack of resources. */ ASSERT (status < CHOLMOD_OK) ; ERROR (status, "all methods failed") ; FREE_WORKSPACE_AND_RETURN ; } /* ---------------------------------------------------------------------- */ /* do the analysis for AMD, if skipped */ /* ---------------------------------------------------------------------- */ Common->fl = Common->method [Common->selected].fl ; Common->lnz = Common->method [Common->selected].lnz ; ASSERT (Common->lnz >= 0) ; if (skip_best) { if (!CHOLMOD(analyze_ordering) (A, L->ordering, Lperm, fset, fsize, Lparent, Post, Lcolcount, First, Level, Common)) { /* out of memory, or method failed */ FREE_WORKSPACE_AND_RETURN ; } } /* ---------------------------------------------------------------------- */ /* postorder the etree, weighted by the column counts */ /* ---------------------------------------------------------------------- */ if (Common->postorder) { /* combine the fill-reducing ordering with the weighted postorder */ /* workspace: Iwork (2*nrow) */ if (CHOLMOD(postorder) (Lparent, n, Lcolcount, Post, Common) == n) { /* use First and Level as workspace [ */ Int *Wi = First, *InvPost = Level ; Int newchild, oldchild, newparent, oldparent ; for (k = 0 ; k < n ; k++) { Wi [k] = Lperm [Post [k]] ; } for (k = 0 ; k < n ; k++) { Lperm [k] = Wi [k] ; } for (k = 0 ; k < n ; k++) { Wi [k] = Lcolcount [Post [k]] ; } for (k = 0 ; k < n ; k++) { Lcolcount [k] = Wi [k] ; } for (k = 0 ; k < n ; k++) { InvPost [Post [k]] = k ; } /* updated Lparent needed only for supernodal case */ for (newchild = 0 ; newchild < n ; newchild++) { oldchild = Post [newchild] ; oldparent = Lparent [oldchild] ; newparent = (oldparent == EMPTY) ? EMPTY : InvPost [oldparent] ; Wi [newchild] = newparent ; } for (k = 0 ; k < n ; k++) { Lparent [k] = Wi [k] ; } /* done using Iwork as workspace ] */ /* L is now postordered, no longer in natural ordering */ if (L->ordering == CHOLMOD_NATURAL) { L->ordering = CHOLMOD_POSTORDERED ; } } } /* ---------------------------------------------------------------------- */ /* supernodal analysis, if requested or if selected automatically */ /* ---------------------------------------------------------------------- */ #ifndef NSUPERNODAL if (Common->supernodal > CHOLMOD_AUTO || (Common->supernodal == CHOLMOD_AUTO && Common->lnz > 0 && (Common->fl / Common->lnz) >= Common->supernodal_switch)) { cholmod_sparse *S, *F, *A2, *A1 ; permute_matrices (A, L->ordering, Lperm, fset, fsize, TRUE, &A1, &A2, &S, &F, Common) ; /* workspace: Flag (nrow), Head (nrow), Iwork (5*nrow) */ CHOLMOD(super_symbolic2) (for_cholesky, S, F, Lparent, L, Common) ; PRINT1 (("status %d\n", Common->status)) ; CHOLMOD(free_sparse) (&A1, Common) ; CHOLMOD(free_sparse) (&A2, Common) ; } #endif /* ---------------------------------------------------------------------- */ /* free temporary matrices and workspace, and return result L */ /* ---------------------------------------------------------------------- */ FREE_WORKSPACE_AND_RETURN ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_etree.c0000644000175000017500000001604311674452555023153 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_etree =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Compute the elimination tree of A or A'*A * * In the symmetric case, the upper triangular part of A is used. Entries not * in this part of the matrix are ignored. Computing the etree of a symmetric * matrix from just its lower triangular entries is not supported. * * In the unsymmetric case, all of A is used, and the etree of A'*A is computed. * * References: * * J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans. * Math. Software, vol 12, 1986, pp. 127-148. * * J. Liu, "The role of elimination trees in sparse factorization", SIAM J. * Matrix Analysis & Applic., vol 11, 1990, pp. 134-172. * * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. * * workspace: symmetric: Iwork (nrow), unsymmetric: Iwork (nrow+ncol) * * Supports any xtype (pattern, real, complex, or zomplex) */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" /* ========================================================================== */ /* === update_etree ========================================================= */ /* ========================================================================== */ static void update_etree ( /* inputs, not modified */ Int k, /* process the edge (k,i) in the input graph */ Int i, /* inputs, modified on output */ Int Parent [ ], /* Parent [t] = p if p is the parent of t */ Int Ancestor [ ] /* Ancestor [t] is the ancestor of node t in the partially-constructed etree */ ) { Int a ; for ( ; ; ) /* traverse the path from k to the root of the tree */ { a = Ancestor [k] ; if (a == i) { /* final ancestor reached; no change to tree */ return ; } /* perform path compression */ Ancestor [k] = i ; if (a == EMPTY) { /* final ancestor undefined; this is a new edge in the tree */ Parent [k] = i ; return ; } /* traverse up to the ancestor of k */ k = a ; } } /* ========================================================================== */ /* === cholmod_etree ======================================================== */ /* ========================================================================== */ /* Find the elimination tree of A or A'*A */ int CHOLMOD(etree) ( /* ---- input ---- */ cholmod_sparse *A, /* ---- output --- */ Int *Parent, /* size ncol. Parent [j] = p if p is the parent of j */ /* --------------- */ cholmod_common *Common ) { Int *Ap, *Ai, *Anz, *Ancestor, *Prev, *Iwork ; Int i, j, jprev, p, pend, nrow, ncol, packed, stype ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (Parent, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ stype = A->stype ; /* s = A->nrow + (stype ? 0 : A->ncol) */ s = CHOLMOD(add_size_t) (A->nrow, (stype ? 0 : A->ncol), &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } ASSERT (CHOLMOD(dump_sparse) (A, "etree", Common) >= 0) ; Iwork = Common->Iwork ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ncol = A->ncol ; /* the number of columns of A */ nrow = A->nrow ; /* the number of rows of A */ Ap = A->p ; /* size ncol+1, column pointers for A */ Ai = A->i ; /* the row indices of A */ Anz = A->nz ; /* number of nonzeros in each column of A */ packed = A->packed ; Ancestor = Iwork ; /* size ncol (i/i/l) */ for (j = 0 ; j < ncol ; j++) { Parent [j] = EMPTY ; Ancestor [j] = EMPTY ; } /* ---------------------------------------------------------------------- */ /* compute the etree */ /* ---------------------------------------------------------------------- */ if (stype > 0) { /* ------------------------------------------------------------------ */ /* symmetric (upper) case: compute etree (A) */ /* ------------------------------------------------------------------ */ for (j = 0 ; j < ncol ; j++) { /* for each row i in column j of triu(A), excluding the diagonal */ p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i < j) { update_etree (i, j, Parent, Ancestor) ; } } } } else if (stype == 0) { /* ------------------------------------------------------------------ */ /* unsymmetric case: compute etree (A'*A) */ /* ------------------------------------------------------------------ */ Prev = Iwork + ncol ; /* size nrow (i/i/l) */ for (i = 0 ; i < nrow ; i++) { Prev [i] = EMPTY ; } for (j = 0 ; j < ncol ; j++) { /* for each row i in column j of A */ p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { /* a graph is constructed dynamically with one path per row * of A. If the ith row of A contains column indices * (j1,j2,j3,j4) then the new graph has edges (j1,j2), (j2,j3), * and (j3,j4). When at node i of this path-graph, all edges * (jprev,j) are considered, where jprevx ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = n-1 ; j >= 0 ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j-1, and j-2) */ if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y = X [j] ; #ifdef DIAG double d = Lx [p] ; #endif #ifdef LD y /= d ; #endif for (p++ ; p < pend ; p++) { y -= Lx [p] * X [Li [p]] ; } #ifdef LL X [j] = y / d ; #else X [j] = y ; #endif j-- ; /* advance to the next column of L */ } else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2], t ; Int q = Lp [j-1] ; #ifdef DIAG double d [2] ; d [0] = Lx [p] ; d [1] = Lx [q] ; #endif t = Lx [q+1] ; #ifdef LD y [0] = X [j ] / d [0] ; y [1] = X [j-1] / d [1] ; #else y [0] = X [j ] ; y [1] = X [j-1] ; #endif for (p++, q += 2 ; p < pend ; p++, q++) { Int i = Li [p] ; y [0] -= Lx [p] * X [i] ; y [1] -= Lx [q] * X [i] ; } #ifdef LL y [0] /= d [0] ; y [1] = (y [1] - t * y [0]) / d [1] ; #else y [1] -= t * y [0] ; #endif X [j ] = y [0] ; X [j-1] = y [1] ; j -= 2 ; /* advance to the next column of L */ } else { /* -------------------------------------------------------------- */ /* solve with a supernode of three columns of L */ /* -------------------------------------------------------------- */ double y [3], t [3] ; Int q = Lp [j-1] ; Int r = Lp [j-2] ; #ifdef DIAG double d [3] ; d [0] = Lx [p] ; d [1] = Lx [q] ; d [2] = Lx [r] ; #endif t [0] = Lx [q+1] ; t [1] = Lx [r+1] ; t [2] = Lx [r+2] ; #ifdef LD y [0] = X [j] / d [0] ; y [1] = X [j-1] / d [1] ; y [2] = X [j-2] / d [2] ; #else y [0] = X [j] ; y [1] = X [j-1] ; y [2] = X [j-2] ; #endif for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) { Int i = Li [p] ; y [0] -= Lx [p] * X [i] ; y [1] -= Lx [q] * X [i] ; y [2] -= Lx [r] * X [i] ; } #ifdef LL y [0] /= d [0] ; y [1] = (y [1] - t [0] * y [0]) / d [1] ; y [2] = (y [2] - t [2] * y [0] - t [1] * y [1]) / d [2] ; #else y [1] -= t [0] * y [0] ; y [2] -= t [2] * y [0] + t [1] * y [1] ; #endif X [j-2] = y [2] ; X [j-1] = y [1] ; X [j ] = y [0] ; j -= 3 ; /* advance to the next column of L */ } } } /* ========================================================================== */ /* === LSOLVE (2) =========================================================== */ /* ========================================================================== */ /* Solve L'x=b, where b has 2 columns */ static void LSOLVE (PREFIX,2) ( cholmod_factor *L, double X [ ][2] /* n-by-2 in row form */ ) { double *Lx = L->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = n-1 ; j >= 0 ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j-1, and j-2) */ if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y [2] ; #ifdef DIAG double d = Lx [p] ; #endif #ifdef LD y [0] = X [j][0] / d ; y [1] = X [j][1] / d ; #else y [0] = X [j][0] ; y [1] = X [j][1] ; #endif for (p++ ; p < pend ; p++) { Int i = Li [p] ; y [0] -= Lx [p] * X [i][0] ; y [1] -= Lx [p] * X [i][1] ; } #ifdef LL X [j][0] = y [0] / d ; X [j][1] = y [1] / d ; #else X [j][0] = y [0] ; X [j][1] = y [1] ; #endif j-- ; /* advance to the next column of L */ } else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2][2], t ; Int q = Lp [j-1] ; #ifdef DIAG double d [2] ; d [0] = Lx [p] ; d [1] = Lx [q] ; #endif t = Lx [q+1] ; #ifdef LD y [0][0] = X [j ][0] / d [0] ; y [0][1] = X [j ][1] / d [0] ; y [1][0] = X [j-1][0] / d [1] ; y [1][1] = X [j-1][1] / d [1] ; #else y [0][0] = X [j ][0] ; y [0][1] = X [j ][1] ; y [1][0] = X [j-1][0] ; y [1][1] = X [j-1][1] ; #endif for (p++, q += 2 ; p < pend ; p++, q++) { Int i = Li [p] ; y [0][0] -= Lx [p] * X [i][0] ; y [0][1] -= Lx [p] * X [i][1] ; y [1][0] -= Lx [q] * X [i][0] ; y [1][1] -= Lx [q] * X [i][1] ; } #ifdef LL y [0][0] /= d [0] ; y [0][1] /= d [0] ; y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; #else y [1][0] -= t * y [0][0] ; y [1][1] -= t * y [0][1] ; #endif X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j-1][0] = y [1][0] ; X [j-1][1] = y [1][1] ; j -= 2 ; /* advance to the next column of L */ } else { /* -------------------------------------------------------------- */ /* solve with a supernode of three columns of L */ /* -------------------------------------------------------------- */ double y [3][2], t [3] ; Int q = Lp [j-1] ; Int r = Lp [j-2] ; #ifdef DIAG double d [3] ; d [0] = Lx [p] ; d [1] = Lx [q] ; d [2] = Lx [r] ; #endif t [0] = Lx [q+1] ; t [1] = Lx [r+1] ; t [2] = Lx [r+2] ; #ifdef LD y [0][0] = X [j ][0] / d [0] ; y [0][1] = X [j ][1] / d [0] ; y [1][0] = X [j-1][0] / d [1] ; y [1][1] = X [j-1][1] / d [1] ; y [2][0] = X [j-2][0] / d [2] ; y [2][1] = X [j-2][1] / d [2] ; #else y [0][0] = X [j ][0] ; y [0][1] = X [j ][1] ; y [1][0] = X [j-1][0] ; y [1][1] = X [j-1][1] ; y [2][0] = X [j-2][0] ; y [2][1] = X [j-2][1] ; #endif for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) { Int i = Li [p] ; y [0][0] -= Lx [p] * X [i][0] ; y [0][1] -= Lx [p] * X [i][1] ; y [1][0] -= Lx [q] * X [i][0] ; y [1][1] -= Lx [q] * X [i][1] ; y [2][0] -= Lx [r] * X [i][0] ; y [2][1] -= Lx [r] * X [i][1] ; } #ifdef LL y [0][0] /= d [0] ; y [0][1] /= d [0] ; y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ; y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ; y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2]; y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2]; #else y [1][0] -= t [0] * y [0][0] ; y [1][1] -= t [0] * y [0][1] ; y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ; y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ; #endif X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j-1][0] = y [1][0] ; X [j-1][1] = y [1][1] ; X [j-2][0] = y [2][0] ; X [j-2][1] = y [2][1] ; j -= 3 ; /* advance to the next column of L */ } } } /* ========================================================================== */ /* === LSOLVE (3) =========================================================== */ /* ========================================================================== */ /* Solve L'x=b, where b has 3 columns */ static void LSOLVE (PREFIX,3) ( cholmod_factor *L, double X [ ][3] /* n-by-3 in row form */ ) { double *Lx = L->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = n-1 ; j >= 0 ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j-1, and j-2) */ if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y [3] ; #ifdef DIAG double d = Lx [p] ; #endif #ifdef LD y [0] = X [j][0] / d ; y [1] = X [j][1] / d ; y [2] = X [j][2] / d ; #else y [0] = X [j][0] ; y [1] = X [j][1] ; y [2] = X [j][2] ; #endif for (p++ ; p < pend ; p++) { Int i = Li [p] ; y [0] -= Lx [p] * X [i][0] ; y [1] -= Lx [p] * X [i][1] ; y [2] -= Lx [p] * X [i][2] ; } #ifdef LL X [j][0] = y [0] / d ; X [j][1] = y [1] / d ; X [j][2] = y [2] / d ; #else X [j][0] = y [0] ; X [j][1] = y [1] ; X [j][2] = y [2] ; #endif j-- ; /* advance to the next column of L */ } else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2][3], t ; Int q = Lp [j-1] ; #ifdef DIAG double d [2] ; d [0] = Lx [p] ; d [1] = Lx [q] ; #endif t = Lx [q+1] ; #ifdef LD y [0][0] = X [j ][0] / d [0] ; y [0][1] = X [j ][1] / d [0] ; y [0][2] = X [j ][2] / d [0] ; y [1][0] = X [j-1][0] / d [1] ; y [1][1] = X [j-1][1] / d [1] ; y [1][2] = X [j-1][2] / d [1] ; #else y [0][0] = X [j ][0] ; y [0][1] = X [j ][1] ; y [0][2] = X [j ][2] ; y [1][0] = X [j-1][0] ; y [1][1] = X [j-1][1] ; y [1][2] = X [j-1][2] ; #endif for (p++, q += 2 ; p < pend ; p++, q++) { Int i = Li [p] ; y [0][0] -= Lx [p] * X [i][0] ; y [0][1] -= Lx [p] * X [i][1] ; y [0][2] -= Lx [p] * X [i][2] ; y [1][0] -= Lx [q] * X [i][0] ; y [1][1] -= Lx [q] * X [i][1] ; y [1][2] -= Lx [q] * X [i][2] ; } #ifdef LL y [0][0] /= d [0] ; y [0][1] /= d [0] ; y [0][2] /= d [0] ; y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ; #else y [1][0] -= t * y [0][0] ; y [1][1] -= t * y [0][1] ; y [1][2] -= t * y [0][2] ; #endif X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j ][2] = y [0][2] ; X [j-1][0] = y [1][0] ; X [j-1][1] = y [1][1] ; X [j-1][2] = y [1][2] ; j -= 2 ; /* advance to the next column of L */ } else { /* -------------------------------------------------------------- */ /* solve with a supernode of three columns of L */ /* -------------------------------------------------------------- */ double y [3][3], t [3] ; Int q = Lp [j-1] ; Int r = Lp [j-2] ; #ifdef DIAG double d [3] ; d [0] = Lx [p] ; d [1] = Lx [q] ; d [2] = Lx [r] ; #endif t [0] = Lx [q+1] ; t [1] = Lx [r+1] ; t [2] = Lx [r+2] ; #ifdef LD y [0][0] = X [j ][0] / d [0] ; y [0][1] = X [j ][1] / d [0] ; y [0][2] = X [j ][2] / d [0] ; y [1][0] = X [j-1][0] / d [1] ; y [1][1] = X [j-1][1] / d [1] ; y [1][2] = X [j-1][2] / d [1] ; y [2][0] = X [j-2][0] / d [2] ; y [2][1] = X [j-2][1] / d [2] ; y [2][2] = X [j-2][2] / d [2] ; #else y [0][0] = X [j ][0] ; y [0][1] = X [j ][1] ; y [0][2] = X [j ][2] ; y [1][0] = X [j-1][0] ; y [1][1] = X [j-1][1] ; y [1][2] = X [j-1][2] ; y [2][0] = X [j-2][0] ; y [2][1] = X [j-2][1] ; y [2][2] = X [j-2][2] ; #endif for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++) { Int i = Li [p] ; y [0][0] -= Lx [p] * X [i][0] ; y [0][1] -= Lx [p] * X [i][1] ; y [0][2] -= Lx [p] * X [i][2] ; y [1][0] -= Lx [q] * X [i][0] ; y [1][1] -= Lx [q] * X [i][1] ; y [1][2] -= Lx [q] * X [i][2] ; y [2][0] -= Lx [r] * X [i][0] ; y [2][1] -= Lx [r] * X [i][1] ; y [2][2] -= Lx [r] * X [i][2] ; } #ifdef LL y [0][0] /= d [0] ; y [0][1] /= d [0] ; y [0][2] /= d [0] ; y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ; y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ; y [1][2] = (y [1][2] - t [0] * y [0][2]) / d [1] ; y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2]; y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2]; y [2][2] = (y [2][2] - t [2] * y [0][2] - t [1] * y [1][2]) / d [2]; #else y [1][0] -= t [0] * y [0][0] ; y [1][1] -= t [0] * y [0][1] ; y [1][2] -= t [0] * y [0][2] ; y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ; y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ; y [2][2] -= t [2] * y [0][2] + t [1] * y [1][2] ; #endif X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j ][2] = y [0][2] ; X [j-1][0] = y [1][0] ; X [j-1][1] = y [1][1] ; X [j-1][2] = y [1][2] ; X [j-2][0] = y [2][0] ; X [j-2][1] = y [2][1] ; X [j-2][2] = y [2][2] ; j -= 3 ; /* advance to the next column of L */ } } } /* ========================================================================== */ /* === LSOLVE (4) =========================================================== */ /* ========================================================================== */ /* Solve L'x=b, where b has 4 columns */ static void LSOLVE (PREFIX,4) ( cholmod_factor *L, double X [ ][4] /* n-by-4 in row form */ ) { double *Lx = L->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int j, n = L->n ; for (j = n-1 ; j >= 0 ; ) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* find a chain of supernodes (up to j, j-1, and j-2) */ if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j) { /* -------------------------------------------------------------- */ /* solve with a single column of L */ /* -------------------------------------------------------------- */ double y [4] ; #ifdef DIAG double d = Lx [p] ; #endif #ifdef LD y [0] = X [j][0] / d ; y [1] = X [j][1] / d ; y [2] = X [j][2] / d ; y [3] = X [j][3] / d ; #else y [0] = X [j][0] ; y [1] = X [j][1] ; y [2] = X [j][2] ; y [3] = X [j][3] ; #endif for (p++ ; p < pend ; p++) { Int i = Li [p] ; y [0] -= Lx [p] * X [i][0] ; y [1] -= Lx [p] * X [i][1] ; y [2] -= Lx [p] * X [i][2] ; y [3] -= Lx [p] * X [i][3] ; } #ifdef LL X [j][0] = y [0] / d ; X [j][1] = y [1] / d ; X [j][2] = y [2] / d ; X [j][3] = y [3] / d ; #else X [j][0] = y [0] ; X [j][1] = y [1] ; X [j][2] = y [2] ; X [j][3] = y [3] ; #endif j-- ; /* advance to the next column of L */ } else /* if (j == 1 || lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) */ { /* -------------------------------------------------------------- */ /* solve with a supernode of two columns of L */ /* -------------------------------------------------------------- */ double y [2][4], t ; Int q = Lp [j-1] ; #ifdef DIAG double d [2] ; d [0] = Lx [p] ; d [1] = Lx [q] ; #endif t = Lx [q+1] ; #ifdef LD y [0][0] = X [j ][0] / d [0] ; y [0][1] = X [j ][1] / d [0] ; y [0][2] = X [j ][2] / d [0] ; y [0][3] = X [j ][3] / d [0] ; y [1][0] = X [j-1][0] / d [1] ; y [1][1] = X [j-1][1] / d [1] ; y [1][2] = X [j-1][2] / d [1] ; y [1][3] = X [j-1][3] / d [1] ; #else y [0][0] = X [j ][0] ; y [0][1] = X [j ][1] ; y [0][2] = X [j ][2] ; y [0][3] = X [j ][3] ; y [1][0] = X [j-1][0] ; y [1][1] = X [j-1][1] ; y [1][2] = X [j-1][2] ; y [1][3] = X [j-1][3] ; #endif for (p++, q += 2 ; p < pend ; p++, q++) { Int i = Li [p] ; y [0][0] -= Lx [p] * X [i][0] ; y [0][1] -= Lx [p] * X [i][1] ; y [0][2] -= Lx [p] * X [i][2] ; y [0][3] -= Lx [p] * X [i][3] ; y [1][0] -= Lx [q] * X [i][0] ; y [1][1] -= Lx [q] * X [i][1] ; y [1][2] -= Lx [q] * X [i][2] ; y [1][3] -= Lx [q] * X [i][3] ; } #ifdef LL y [0][0] /= d [0] ; y [0][1] /= d [0] ; y [0][2] /= d [0] ; y [0][3] /= d [0] ; y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ; y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ; y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ; y [1][3] = (y [1][3] - t * y [0][3]) / d [1] ; #else y [1][0] -= t * y [0][0] ; y [1][1] -= t * y [0][1] ; y [1][2] -= t * y [0][2] ; y [1][3] -= t * y [0][3] ; #endif X [j ][0] = y [0][0] ; X [j ][1] = y [0][1] ; X [j ][2] = y [0][2] ; X [j ][3] = y [0][3] ; X [j-1][0] = y [1][0] ; X [j-1][1] = y [1][1] ; X [j-1][2] = y [1][2] ; X [j-1][3] = y [1][3] ; j -= 2 ; /* advance to the next column of L */ } /* NOTE: with 4 right-hand-sides, it suffices to exploit dynamic * supernodes of just size 1 and 2. 3-column supernodes are not * needed. */ } } #endif /* ========================================================================== */ /* === LSOLVE (k) =========================================================== */ /* ========================================================================== */ static void LSOLVE (PREFIX,k) ( cholmod_factor *L, cholmod_dense *Y /* nr-by-n where nr is 1 to 4 */ ) { #ifndef REAL #ifdef DIAG double d [1] ; #endif double yx [2] ; #ifdef ZOMPLEX double yz [1] ; double *Lz = L->z ; double *Xz = Y->z ; #endif double *Lx = L->x ; double *Xx = Y->x ; Int *Li = L->i ; Int *Lp = L->p ; Int *Lnz = L->nz ; Int i, j, n = L->n ; #endif ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */ ASSERT (L->n == Y->ncol) ; /* dimensions must match */ ASSERT (Y->nrow == Y->d) ; /* leading dimension of Y = # rows of Y */ ASSERT (L->xtype != CHOLMOD_PATTERN) ; /* L is not symbolic */ ASSERT (!(L->is_super)) ; /* L is simplicial LL' or LDL' */ #ifdef REAL /* ---------------------------------------------------------------------- */ /* solve a real linear system, with 1 to 4 RHS's and dynamic supernodes */ /* ---------------------------------------------------------------------- */ ASSERT (Y->nrow <= 4) ; switch (Y->nrow) { case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ; case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ; case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ; case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ; } #else /* ---------------------------------------------------------------------- */ /* solve a complex linear system, with just one right-hand-side */ /* ---------------------------------------------------------------------- */ ASSERT (Y->nrow == 1) ; for (j = n-1 ; j >= 0 ; j--) { /* get the start, end, and length of column j */ Int p = Lp [j] ; Int lnz = Lnz [j] ; Int pend = p + lnz ; /* y = X [j] ; */ ASSIGN (yx,yz,0, Xx,Xz,j) ; #ifdef DIAG /* d = Lx [p] ; */ ASSIGN_REAL (d,0, Lx,p) ; #endif #ifdef LD /* y /= d ; */ DIV_REAL (yx,yz,0, yx,yz,0, d,0) ; #endif for (p++ ; p < pend ; p++) { /* y -= conj (Lx [p]) * X [Li [p]] ; */ i = Li [p] ; MULTSUBCONJ (yx,yz,0, Lx,Lz,p, Xx,Xz,i) ; } #ifdef LL /* X [j] = y / d ; */ DIV_REAL (Xx,Xz,j, yx,yz,0, d,0) ; #else /* X [j] = y ; */ ASSIGN (Xx,Xz,j, yx,yz,0) ; #endif } #endif } /* prepare for the next inclusion of this file in cholmod_solve.c */ #undef LL #undef LD cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_solve.c0000644000175000017500000007606011674452555023204 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_solve =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Solve one of the following systems: * * Ax=b 0: CHOLMOD_A also applies the permutation L->Perm * LDL'x=b 1: CHOLMOD_LDLt does not apply L->Perm * LDx=b 2: CHOLMOD_LD * DL'x=b 3: CHOLMOD_DLt * Lx=b 4: CHOLMOD_L * L'x=b 5: CHOLMOD_Lt * Dx=b 6: CHOLMOD_D * x=Pb 7: CHOLMOD_P apply a permutation (P is L->Perm) * x=P'b 8: CHOLMOD_Pt apply an inverse permutation * * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'. * For an LL' factorization, D is the identity matrix. Thus CHOLMOD_LD and * CHOLMOD_L solve the same system if an LL' factorization was performed, * for example. * * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm, * or their complex counterparts ztrsv, zgemv, ztrsm, and zgemm. * * If both L and B are real, then X is returned real. If either is complex * or zomplex, X is returned as either complex or zomplex, depending on the * Common->prefer_zomplex parameter. * * Supports any numeric xtype (pattern-only matrices not supported). * * This routine does not check to see if the diagonal of L or D is zero, * because sometimes a partial solve can be done with indefinite or singular * matrix. If you wish to check in your own code, test L->minor. If * L->minor == L->n, then the matrix has no zero diagonal entries. * If k = L->minor < L->n, then L(k,k) is zero for an LL' factorization, or * D(k,k) is zero for an LDL' factorization. * * This routine returns X as NULL only if it runs out of memory. If L is * indefinite or singular, then X may contain Inf's or NaN's, but it will * exist on output. */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" #ifndef NSUPERNODAL #include "cholmod_supernodal.h" #endif /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define REAL #include "t_cholmod_solve.c" #define COMPLEX #include "t_cholmod_solve.c" #define ZOMPLEX #include "t_cholmod_solve.c" /* ========================================================================== */ /* === Permutation macro ==================================================== */ /* ========================================================================== */ /* If Perm is NULL, it is interpretted as the identity permutation */ #define P(k) ((Perm == NULL) ? (k) : Perm [k]) /* ========================================================================== */ /* === perm ================================================================= */ /* ========================================================================== */ /* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1) where B is nrow-by-ncol. * * Creates a permuted copy of a contiguous set of columns of B. * Y is already allocated on input. Y must be of sufficient size. Let nk be * the number of columns accessed in B. Y->xtype determines the complexity of * the result. * * If B is real and Y is complex (or zomplex), only the real part of B is * copied into Y. The imaginary part of Y is set to zero. * * If B is complex (or zomplex) and Y is real, both the real and imaginary and * parts of B are returned in Y. Y is returned as nrow-by-2*nk. The even * columns of Y contain the real part of B and the odd columns contain the * imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is * returned as nrow-by-nk with leading dimension nrow. Y->nzmax must be >= * nrow*nk. * * The case where the input (B) is real and the output (Y) is zomplex is * not used. */ static void perm ( /* ---- input ---- */ cholmod_dense *B, /* input matrix B */ Int *Perm, /* optional input permutation (can be NULL) */ Int k1, /* first column of B to copy */ Int ncols, /* last column to copy is min(k1+ncols,B->ncol)-1 */ /* ---- in/out --- */ cholmod_dense *Y /* output matrix Y, already allocated */ ) { double *Yx, *Yz, *Bx, *Bz ; Int k2, nk, p, k, j, nrow, ncol, d, dual, dj, j2 ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ncol = B->ncol ; nrow = B->nrow ; k2 = MIN (k1+ncols, ncol) ; nk = MAX (k2 - k1, 0) ; dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; d = B->d ; Bx = B->x ; Bz = B->z ; Yx = Y->x ; Yz = Y->z ; Y->nrow = nrow ; Y->ncol = dual*nk ; Y->d = nrow ; ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ; /* ---------------------------------------------------------------------- */ /* Y = B (P (1:nrow), k1:k2-1) */ /* ---------------------------------------------------------------------- */ switch (Y->xtype) { case CHOLMOD_REAL: switch (B->xtype) { case CHOLMOD_REAL: /* Y real, B real */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [k + j2] = Bx [p] ; /* real */ } } break ; case CHOLMOD_COMPLEX: /* Y real, B complex. Y is nrow-by-2*nk */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [k + j2 ] = Bx [2*p ] ; /* real */ Yx [k + j2 + nrow] = Bx [2*p+1] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y real, B zomplex. Y is nrow-by-2*nk */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [k + j2 ] = Bx [p] ; /* real */ Yx [k + j2 + nrow] = Bz [p] ; /* imag */ } } break ; } break ; case CHOLMOD_COMPLEX: switch (B->xtype) { case CHOLMOD_REAL: /* Y complex, B real */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [2*k + j2] = Bx [p] ; /* real */ Yx [2*k+1 + j2] = 0 ; /* imag */ } } break ; case CHOLMOD_COMPLEX: /* Y complex, B complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [2*k + j2] = Bx [2*p ] ; /* real */ Yx [2*k+1 + j2] = Bx [2*p+1] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y complex, B zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [2*k + j2] = Bx [p] ; /* real */ Yx [2*k+1 + j2] = Bz [p] ; /* imag */ } } break ; } break ; case CHOLMOD_ZOMPLEX: switch (B->xtype) { #if 0 case CHOLMOD_REAL: /* this case is not used */ break ; #endif case CHOLMOD_COMPLEX: /* Y zomplex, B complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [k + j2] = Bx [2*p ] ; /* real */ Yz [k + j2] = Bx [2*p+1] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y zomplex, B zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [k + j2] = Bx [p] ; /* real */ Yz [k + j2] = Bz [p] ; /* imag */ } } break ; } break ; } } /* ========================================================================== */ /* === iperm ================================================================ */ /* ========================================================================== */ /* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y where X is nrow-by-ncol. * * Copies and permutes Y into a contiguous set of columns of X. X is already * allocated on input. Y must be of sufficient size. Let nk be the number * of columns accessed in X. X->xtype determines the complexity of the result. * * If X is real and Y is complex (or zomplex), only the real part of B is * copied into X. The imaginary part of Y is ignored. * * If X is complex (or zomplex) and Y is real, both the real and imaginary and * parts of Y are returned in X. Y is nrow-by-2*nk. The even * columns of Y contain the real part of B and the odd columns contain the * imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is * nrow-by-nk with leading dimension nrow. Y->nzmax must be >= nrow*nk. * * The case where the input (Y) is complex and the output (X) is real, * and the case where the input (Y) is zomplex and the output (X) is real, * are not used. */ static void iperm ( /* ---- input ---- */ cholmod_dense *Y, /* input matrix Y */ Int *Perm, /* optional input permutation (can be NULL) */ Int k1, /* first column of B to copy */ Int ncols, /* last column to copy is min(k1+ncols,B->ncol)-1 */ /* ---- in/out --- */ cholmod_dense *X /* output matrix X, already allocated */ ) { double *Yx, *Yz, *Xx, *Xz ; Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ncol = X->ncol ; nrow = X->nrow ; k2 = MIN (k1+ncols, ncol) ; nk = MAX (k2 - k1, 0) ; d = X->d ; Xx = X->x ; Xz = X->z ; Yx = Y->x ; Yz = Y->z ; ASSERT (((Int) Y->nzmax) >= nrow*nk* ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ; /* ---------------------------------------------------------------------- */ /* X (P (1:nrow), k1:k2-1) = Y */ /* ---------------------------------------------------------------------- */ switch (Y->xtype) { case CHOLMOD_REAL: switch (X->xtype) { case CHOLMOD_REAL: /* Y real, X real */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [k + j2] ; /* real */ } } break ; case CHOLMOD_COMPLEX: /* Y real, X complex. Y is nrow-by-2*nk */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [2*p ] = Yx [k + j2 ] ; /* real */ Xx [2*p+1] = Yx [k + j2 + nrow] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y real, X zomplex. Y is nrow-by-2*nk */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [k + j2 ] ; /* real */ Xz [p] = Yx [k + j2 + nrow] ; /* imag */ } } break ; } break ; case CHOLMOD_COMPLEX: switch (X->xtype) { #if 0 case CHOLMOD_REAL: /* this case is not used */ break ; #endif case CHOLMOD_COMPLEX: /* Y complex, X complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [2*p ] = Yx [2*k + j2] ; /* real */ Xx [2*p+1] = Yx [2*k+1 + j2] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y complex, X zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * 2 * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [2*k + j2] ; /* real */ Xz [p] = Yx [2*k+1 + j2] ; /* imag */ } } break ; } break ; case CHOLMOD_ZOMPLEX: switch (X->xtype) { #if 0 case CHOLMOD_REAL: /* this case is not used */ break ; #endif case CHOLMOD_COMPLEX: /* Y zomplex, X complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [2*p ] = Yx [k + j2] ; /* real */ Xx [2*p+1] = Yz [k + j2] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y zomplex, X zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = nrow * (j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [k + j2] ; /* real */ Xz [p] = Yz [k + j2] ; /* imag */ } } break ; } break ; } } /* ========================================================================== */ /* === ptrans =============================================================== */ /* ========================================================================== */ /* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1)' where B is nrow-by-ncol. * * Creates a permuted and transposed copy of a contiguous set of columns of B. * Y is already allocated on input. Y must be of sufficient size. Let nk be * the number of columns accessed in B. Y->xtype determines the complexity of * the result. * * If B is real and Y is complex (or zomplex), only the real part of B is * copied into Y. The imaginary part of Y is set to zero. * * If B is complex (or zomplex) and Y is real, both the real and imaginary and * parts of B are returned in Y. Y is returned as 2*nk-by-nrow. The even * rows of Y contain the real part of B and the odd rows contain the * imaginary part of B. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is * returned as nk-by-nrow with leading dimension nk. Y->nzmax must be >= * nrow*nk. * * The array transpose is performed, not the complex conjugate transpose. */ static void ptrans ( /* ---- input ---- */ cholmod_dense *B, /* input matrix B */ Int *Perm, /* optional input permutation (can be NULL) */ Int k1, /* first column of B to copy */ Int ncols, /* last column to copy is min(k1+ncols,B->ncol)-1 */ /* ---- in/out --- */ cholmod_dense *Y /* output matrix Y, already allocated */ ) { double *Yx, *Yz, *Bx, *Bz ; Int k2, nk, p, k, j, nrow, ncol, d, dual, dj, j2 ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ncol = B->ncol ; nrow = B->nrow ; k2 = MIN (k1+ncols, ncol) ; nk = MAX (k2 - k1, 0) ; dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; d = B->d ; Bx = B->x ; Bz = B->z ; Yx = Y->x ; Yz = Y->z ; Y->nrow = dual*nk ; Y->ncol = nrow ; Y->d = dual*nk ; ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ; /* ---------------------------------------------------------------------- */ /* Y = B (P (1:nrow), k1:k2-1)' */ /* ---------------------------------------------------------------------- */ switch (Y->xtype) { case CHOLMOD_REAL: switch (B->xtype) { case CHOLMOD_REAL: /* Y real, B real */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = j-k1 ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*nk] = Bx [p] ; /* real */ } } break ; case CHOLMOD_COMPLEX: /* Y real, B complex. Y is 2*nk-by-nrow */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*2*nk] = Bx [2*p ] ; /* real */ Yx [j2+1 + k*2*nk] = Bx [2*p+1] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y real, B zomplex. Y is 2*nk-by-nrow */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*2*nk] = Bx [p] ; /* real */ Yx [j2+1 + k*2*nk] = Bz [p] ; /* imag */ } } break ; } break ; case CHOLMOD_COMPLEX: switch (B->xtype) { case CHOLMOD_REAL: /* Y complex, B real */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*2*nk] = Bx [p] ; /* real */ Yx [j2+1 + k*2*nk] = 0 ; /* imag */ } } break ; case CHOLMOD_COMPLEX: /* Y complex, B complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*2*nk] = Bx [2*p ] ; /* real */ Yx [j2+1 + k*2*nk] = Bx [2*p+1] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y complex, B zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*2*nk] = Bx [p] ; /* real */ Yx [j2+1 + k*2*nk] = Bz [p] ; /* imag */ } } break ; } break ; case CHOLMOD_ZOMPLEX: switch (B->xtype) { case CHOLMOD_REAL: /* Y zomplex, B real */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = j-k1 ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*nk] = Bx [p] ; /* real */ Yz [j2 + k*nk] = 0 ; /* imag */ } } break ; case CHOLMOD_COMPLEX: /* Y zomplex, B complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = j-k1 ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*nk] = Bx [2*p ] ; /* real */ Yz [j2 + k*nk] = Bx [2*p+1] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y zomplex, B zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = j-k1 ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Yx [j2 + k*nk] = Bx [p] ; /* real */ Yz [j2 + k*nk] = Bz [p] ; /* imag */ } } break ; } break ; } } /* ========================================================================== */ /* === iptrans ============================================================== */ /* ========================================================================== */ /* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y' where X is nrow-by-ncol. * * Copies into a permuted and transposed contiguous set of columns of X. * X is already allocated on input. Y must be of sufficient size. Let nk be * the number of columns accessed in X. X->xtype determines the complexity of * the result. * * If X is real and Y is complex (or zomplex), only the real part of Y is * copied into X. The imaginary part of Y is ignored. * * If X is complex (or zomplex) and Y is real, both the real and imaginary and * parts of X are returned in Y. Y is 2*nk-by-nrow. The even * rows of Y contain the real part of X and the odd rows contain the * imaginary part of X. Y->nzmax must be >= 2*nrow*nk. Otherise, Y is * nk-by-nrow with leading dimension nk. Y->nzmax must be >= nrow*nk. * * The case where Y is complex or zomplex, and X is real, is not used. * * The array transpose is performed, not the complex conjugate transpose. */ static void iptrans ( /* ---- input ---- */ cholmod_dense *Y, /* input matrix Y */ Int *Perm, /* optional input permutation (can be NULL) */ Int k1, /* first column of X to copy into */ Int ncols, /* last column to copy is min(k1+ncols,X->ncol)-1 */ /* ---- in/out --- */ cholmod_dense *X /* output matrix X, already allocated */ ) { double *Yx, *Yz, *Xx, *Xz ; Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ncol = X->ncol ; nrow = X->nrow ; k2 = MIN (k1+ncols, ncol) ; nk = MAX (k2 - k1, 0) ; d = X->d ; Xx = X->x ; Xz = X->z ; Yx = Y->x ; Yz = Y->z ; ASSERT (((Int) Y->nzmax) >= nrow*nk* ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ; /* ---------------------------------------------------------------------- */ /* X (P (1:nrow), k1:k2-1) = Y' */ /* ---------------------------------------------------------------------- */ switch (Y->xtype) { case CHOLMOD_REAL: switch (X->xtype) { case CHOLMOD_REAL: /* Y real, X real */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = j-k1 ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [j2 + k*nk] ; /* real */ } } break ; case CHOLMOD_COMPLEX: /* Y real, X complex. Y is 2*nk-by-nrow */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [2*p ] = Yx [j2 + k*2*nk] ; /* real */ Xx [2*p+1] = Yx [j2+1 + k*2*nk] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y real, X zomplex. Y is 2*nk-by-nrow */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [j2 + k*2*nk] ; /* real */ Xz [p] = Yx [j2+1 + k*2*nk] ; /* imag */ } } break ; } break ; case CHOLMOD_COMPLEX: switch (X->xtype) { #if 0 case CHOLMOD_REAL: /* this case is not used */ break ; #endif case CHOLMOD_COMPLEX: /* Y complex, X complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [2*p ] = Yx [j2 + k*2*nk] ; /* real */ Xx [2*p+1] = Yx [j2+1 + k*2*nk] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y complex, X zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = 2*(j-k1) ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [j2 + k*2*nk] ; /* real */ Xz [p] = Yx [j2+1 + k*2*nk] ; /* imag */ } } break ; } break ; case CHOLMOD_ZOMPLEX: switch (X->xtype) { #if 0 case CHOLMOD_REAL: /* this case is not used */ break ; #endif case CHOLMOD_COMPLEX: /* Y zomplex, X complex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = j-k1 ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [2*p ] = Yx [j2 + k*nk] ; /* real */ Xx [2*p+1] = Yz [j2 + k*nk] ; /* imag */ } } break ; case CHOLMOD_ZOMPLEX: /* Y zomplex, X zomplex */ for (j = k1 ; j < k2 ; j++) { dj = d*j ; j2 = j-k1 ; for (k = 0 ; k < nrow ; k++) { p = P(k) + dj ; Xx [p] = Yx [j2 + k*nk] ; /* real */ Xz [p] = Yz [j2 + k*nk] ; /* imag */ } } break ; } break ; } } /* ========================================================================== */ /* === cholmod_solve ======================================================== */ /* ========================================================================== */ /* Solve a linear system. * * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'. * The Dx=b solve returns silently for the LL' factorizations (it is implicitly * identity). */ cholmod_dense *CHOLMOD(solve) ( /* ---- input ---- */ int sys, /* system to solve */ cholmod_factor *L, /* factorization to use */ cholmod_dense *B, /* right-hand-side */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *Y = NULL, *X = NULL ; Int *Perm ; Int n, nrhs, ncols, ctype, xtype, k1, nr, ytype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (L, NULL) ; RETURN_IF_NULL (B, NULL) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; if (sys < CHOLMOD_A || sys > CHOLMOD_Pt) { ERROR (CHOLMOD_INVALID, "invalid system") ; return (NULL) ; } if (B->d < L->n || B->nrow != L->n) { ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ; return (NULL) ; } DEBUG (CHOLMOD(dump_factor) (L, "L", Common)) ; DEBUG (CHOLMOD(dump_dense) (B, "B", Common)) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if ((sys == CHOLMOD_P || sys == CHOLMOD_Pt || sys == CHOLMOD_A) && L->ordering != CHOLMOD_NATURAL) { Perm = L->Perm ; } else { /* do not use L->Perm; use the identity permutation instead */ Perm = NULL ; } nrhs = B->ncol ; n = L->n ; /* ---------------------------------------------------------------------- */ /* allocate the result X */ /* ---------------------------------------------------------------------- */ ctype = (Common->prefer_zomplex) ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX ; if (sys == CHOLMOD_P || sys == CHOLMOD_Pt) { /* x=Pb and x=P'b return X real if B is real; X is the preferred * complex/zcomplex type if B is complex or zomplex */ xtype = (B->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : ctype ; } else if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) { /* X is real if both L and B are real */ xtype = CHOLMOD_REAL ; } else { /* X is complex, use the preferred complex/zomplex type */ xtype = ctype ; } X = CHOLMOD(allocate_dense) (n, nrhs, n, xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; } /* ---------------------------------------------------------------------- */ /* solve using L, D, L', P, or some combination */ /* ---------------------------------------------------------------------- */ if (sys == CHOLMOD_P) { /* ------------------------------------------------------------------ */ /* x = P*b */ /* ------------------------------------------------------------------ */ perm (B, Perm, 0, nrhs, X) ; } else if (sys == CHOLMOD_Pt) { /* ------------------------------------------------------------------ */ /* x = P'*b */ /* ------------------------------------------------------------------ */ iperm (B, Perm, 0, nrhs, X) ; } else if (L->is_super) { /* ------------------------------------------------------------------ */ /* solve using a supernodal LL' factorization */ /* ------------------------------------------------------------------ */ #ifndef NSUPERNODAL /* allocate workspace */ cholmod_dense *E ; Int dual ; Common->blas_ok = TRUE ; dual = (L->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ; Y = CHOLMOD(allocate_dense) (n, dual*nrhs, n, L->xtype, Common) ; E = CHOLMOD(allocate_dense) (dual*nrhs, L->maxesize, dual*nrhs, L->xtype, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ CHOLMOD(free_dense) (&X, Common) ; CHOLMOD(free_dense) (&Y, Common) ; CHOLMOD(free_dense) (&E, Common) ; return (NULL) ; } perm (B, Perm, 0, nrhs, Y) ; /* Y = P*B */ if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt) { CHOLMOD(super_lsolve) (L, Y, E, Common) ; /* Y = L\Y */ CHOLMOD(super_ltsolve) (L, Y, E, Common) ; /* Y = L'\Y*/ } else if (sys == CHOLMOD_L || sys == CHOLMOD_LD) { CHOLMOD(super_lsolve) (L, Y, E, Common) ; /* Y = L\Y */ } else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt) { CHOLMOD(super_ltsolve) (L, Y, E, Common) ; /* Y = L'\Y*/ } CHOLMOD(free_dense) (&E, Common) ; iperm (Y, Perm, 0, nrhs, X) ; /* X = P'*Y */ if (CHECK_BLAS_INT && !Common->blas_ok) { /* Integer overflow in the BLAS. This is probably impossible, * since the BLAS were used to create the supernodal factorization. * It might be possible for the calls to the BLAS to differ between * factorization and forward/backsolves, however. This statement * is untested; it does not appear in the compiled code if * CHECK_BLAS_INT is true (when the same integer is used in CHOLMOD * and the BLAS. */ CHOLMOD(free_dense) (&X, Common) ; } #else /* CHOLMOD Supernodal module not installed */ ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ; #endif } else { /* ------------------------------------------------------------------ */ /* solve using a simplicial LL' or LDL' factorization */ /* ------------------------------------------------------------------ */ if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) { /* L, B, and Y are all real */ /* solve with up to 4 columns of B at a time */ ncols = 4 ; nr = MAX (4, nrhs) ; ytype = CHOLMOD_REAL ; } else if (L->xtype == CHOLMOD_REAL) { /* solve with one column of B (real/imag), at a time */ ncols = 1 ; nr = 2 ; ytype = CHOLMOD_REAL ; } else { /* L is complex or zomplex, B is real/complex/zomplex, Y has the * same complexity as L. Solve with one column of B at a time. */ ncols = 1 ; nr = 1 ; ytype = L->xtype ; } Y = CHOLMOD(allocate_dense) (nr, n, nr, ytype, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ CHOLMOD(free_dense) (&X, Common) ; CHOLMOD(free_dense) (&Y, Common) ; return (NULL) ; } for (k1 = 0 ; k1 < nrhs ; k1 += ncols) { /* -------------------------------------------------------------- */ /* Y = B (P, k1:k1+ncols-1)' = (P * B (:,...))' */ /* -------------------------------------------------------------- */ ptrans (B, Perm, k1, ncols, Y) ; /* -------------------------------------------------------------- */ /* solve Y = (L' \ (L \ Y'))', or other system, with template */ /* -------------------------------------------------------------- */ switch (L->xtype) { case CHOLMOD_REAL: r_simplicial_solver (sys, L, Y) ; break ; case CHOLMOD_COMPLEX: c_simplicial_solver (sys, L, Y) ; break ; case CHOLMOD_ZOMPLEX: z_simplicial_solver (sys, L, Y) ; break ; } /* -------------------------------------------------------------- */ /* X (P, k1:k2+ncols-1) = Y' */ /* -------------------------------------------------------------- */ iptrans (Y, Perm, k1, ncols, X) ; } } CHOLMOD(free_dense) (&Y, Common) ; DEBUG (CHOLMOD(dump_dense) (X, "X result", Common)) ; return (X) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_postorder.c0000644000175000017500000002301211674452555024062 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_postorder =========================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Compute the postorder of a tree. */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" /* ========================================================================== */ /* === dfs ================================================================== */ /* ========================================================================== */ /* The code below includes both a recursive and non-recursive depth-first-search * of a tree. The recursive code is simpler, but can lead to stack overflow. * It is left here for reference, to understand what the non-recursive code * is computing. To try the recursive version, uncomment the following * #define, or compile the code with -DRECURSIVE. Be aware that stack * overflow may occur. #define RECURSIVE */ #ifdef RECURSIVE /* recursive version: a working code for reference only, not actual use */ static Int dfs /* return the new value of k */ ( Int p, /* start a DFS at node p */ Int k, /* start the node numbering at k */ Int Post [ ], /* Post ordering, modified on output */ Int Head [ ], /* Head [p] = youngest child of p; EMPTY on output */ Int Next [ ], /* Next [j] = sibling of j; unmodified */ Int Pstack [ ] /* unused */ ) { Int j ; /* start a DFS at each child of node p */ for (j = Head [p] ; j != EMPTY ; j = Next [j]) { /* start a DFS at child node j */ k = dfs (j, k, Post, Head, Next, Pstack) ; } Post [k++] = p ; /* order node p as the kth node */ Head [p] = EMPTY ; /* link list p no longer needed */ return (k) ; /* the next node will be numbered k */ } #else /* non-recursive version for actual use */ static Int dfs /* return the new value of k */ ( Int p, /* start the DFS at a root node p */ Int k, /* start the node numbering at k */ Int Post [ ], /* Post ordering, modified on output */ Int Head [ ], /* Head [p] = youngest child of p; EMPTY on output */ Int Next [ ], /* Next [j] = sibling of j; unmodified */ Int Pstack [ ] /* workspace of size n, undefined on input or output */ ) { Int j, phead ; /* put the root node on the stack */ Pstack [0] = p ; phead = 0 ; /* while the stack is not empty, do: */ while (phead >= 0) { /* grab the node p from top of the stack and get its youngest child j */ p = Pstack [phead] ; j = Head [p] ; if (j == EMPTY) { /* all children of p ordered. remove p from stack and order it */ phead-- ; Post [k++] = p ; /* order node p as the kth node */ } else { /* leave p on the stack. Start a DFS at child node j by putting * j on the stack and removing j from the list of children of p. */ Head [p] = Next [j] ; Pstack [++phead] = j ; } } return (k) ; /* the next node will be numbered k */ } #endif /* ========================================================================== */ /* === cholmod_postorder ==================================================== */ /* ========================================================================== */ /* Postorder a tree. The tree is either an elimination tree (the output from * from cholmod_etree) or a component tree (from cholmod_nested_dissection). * * An elimination tree is a complete tree of n nodes with Parent [j] > j or * Parent [j] = EMPTY if j is a root. On output Post [0..n-1] is a complete * permutation vector. * * A component tree is a subset of 0..n-1. Parent [j] = -2 if node j is not * in the component tree. Parent [j] = EMPTY if j is a root of the component * tree, and Parent [j] is in the range 0 to n-1 if j is in the component * tree but not a root. On output, Post [k] is defined only for nodes in * the component tree. Post [k] = j if node j is the kth node in the * postordered component tree, where k is in the range 0 to the number of * components minus 1. * * Node j is ignored and not included in the postorder if Parent [j] < EMPTY. * * As a result, check_parent (Parent, n,...) may fail on input, since * cholmod_check_parent assumes Parent is an elimination tree. Similarly, * cholmod_check_perm (Post, ...) may fail on output, since Post is a partial * permutation if Parent is a component tree. * * An optional node weight can be given. When starting a postorder at node j, * the children of j are ordered in increasing order of their weight. * If no weights are given (Weight is NULL) then children are ordered in * increasing order of their node number. The weight of a node must be in the * range 0 to n-1. Weights outside that range are silently converted to that * range (weights < 0 are treated as zero, and weights >= n are treated as n-1). * * * workspace: Head (n), Iwork (2*n) */ UF_long CHOLMOD(postorder) /* return # of nodes postordered */ ( /* ---- input ---- */ Int *Parent, /* size n. Parent [j] = p if p is the parent of j */ size_t n, Int *Weight, /* size n, optional. Weight [j] is weight of node j */ /* ---- output --- */ Int *Post, /* size n. Post [k] = j is kth in postordered tree */ /* --------------- */ cholmod_common *Common ) { Int *Head, *Next, *Pstack, *Iwork ; Int j, p, k, w, nextj ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (Parent, EMPTY) ; RETURN_IF_NULL (Post, EMPTY) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* s = 2*n */ s = CHOLMOD(mult_size_t) (n, 2, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (EMPTY) ; } CHOLMOD(allocate_work) (n, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (EMPTY) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ Head = Common->Head ; /* size n+1, initially all EMPTY */ Iwork = Common->Iwork ; Next = Iwork ; /* size n (i/i/l) */ Pstack = Iwork + n ; /* size n (i/i/l) */ /* ---------------------------------------------------------------------- */ /* construct a link list of children for each node */ /* ---------------------------------------------------------------------- */ if (Weight == NULL) { /* in reverse order so children are in ascending order in each list */ for (j = n-1 ; j >= 0 ; j--) { p = Parent [j] ; if (p >= 0 && p < ((Int) n)) { /* add j to the list of children for node p */ Next [j] = Head [p] ; Head [p] = j ; } } /* Head [p] = j if j is the youngest (least-numbered) child of p */ /* Next [j1] = j2 if j2 is the next-oldest sibling of j1 */ } else { /* First, construct a set of link lists according to Weight. * * Whead [w] = j if node j is the first node in bucket w. * Next [j1] = j2 if node j2 follows j1 in a link list. */ Int *Whead = Pstack ; /* use Pstack as workspace for Whead [ */ for (w = 0 ; w < ((Int) n) ; w++) { Whead [w] = EMPTY ; } /* do in forward order, so nodes that ties are ordered by node index */ for (j = 0 ; j < ((Int) n) ; j++) { p = Parent [j] ; if (p >= 0 && p < ((Int) n)) { w = Weight [j] ; w = MAX (0, w) ; w = MIN (w, ((Int) n) - 1) ; /* place node j at the head of link list for weight w */ Next [j] = Whead [w] ; Whead [w] = j ; } } /* traverse weight buckets, placing each node in its parent's list */ for (w = n-1 ; w >= 0 ; w--) { for (j = Whead [w] ; j != EMPTY ; j = nextj) { nextj = Next [j] ; /* put node j in the link list of its parent */ p = Parent [j] ; ASSERT (p >= 0 && p < ((Int) n)) ; Next [j] = Head [p] ; Head [p] = j ; } } /* Whead no longer needed ] */ /* Head [p] = j if j is the lightest child of p */ /* Next [j1] = j2 if j2 is the next-heaviest sibling of j1 */ } /* ---------------------------------------------------------------------- */ /* start a DFS at each root node of the etree */ /* ---------------------------------------------------------------------- */ k = 0 ; for (j = 0 ; j < ((Int) n) ; j++) { if (Parent [j] == EMPTY) { /* j is the root of a tree; start a DFS here */ k = dfs (j, k, Post, Head, Next, Pstack) ; } } /* this would normally be EMPTY already, unless Parent is invalid */ for (j = 0 ; j < ((Int) n) ; j++) { Head [j] = EMPTY ; } PRINT1 (("postordered "ID" nodes\n", k)) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; return (k) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/t_cholmod_rowfac.c0000644000175000017500000003234311674452555023654 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/t_cholmod_rowfac ============================================ */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_rowfac. Supports any numeric xtype * (real, complex, or zomplex). * * workspace: Iwork (n), Flag (n), Xwork (n if real, 2*n if complex) */ #include "cholmod_template.h" #ifdef MASK static int TEMPLATE (cholmod_rowfac_mask) #else static int TEMPLATE (cholmod_rowfac) #endif ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ double beta [2], /* factorize beta*I+A or beta*I+AA' (beta [0] only) */ size_t kstart, /* first row to factorize */ size_t kend, /* last row to factorize is kend-1 */ #ifdef MASK /* These inputs are used for cholmod_rowfac_mask only */ Int *mask, /* size A->nrow. if mask[i] then W(i) is set to zero */ Int *RLinkUp, /* size A->nrow. link list of rows to compute */ #endif /* ---- in/out --- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) { double yx [2], lx [2], fx [2], dk [1], di [1], fl = 0 ; #ifdef ZOMPLEX double yz [1], lz [1], fz [1] ; #endif double *Ax, *Az, *Lx, *Lz, *Wx, *Wz, *Fx, *Fz ; Int *Ap, *Anz, *Ai, *Lp, *Lnz, *Li, *Lnext, *Flag, *Stack, *Fp, *Fi, *Fnz, *Iwork ; Int i, p, k, t, pf, pfend, top, s, mark, pend, n, lnz, is_ll, multadds, use_dbound, packed, stype, Fpacked, sorted, nzmax, len, parent ; #ifndef REAL Int dk_imaginary ; #endif /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ PRINT1 (("\nin cholmod_rowfac, kstart %d kend %d stype %d\n", kstart, kend, A->stype)) ; DEBUG (CHOLMOD(dump_factor) (L, "Initial L", Common)) ; n = A->nrow ; stype = A->stype ; if (stype > 0) { /* symmetric upper case: F is not needed. It may be NULL */ Fp = NULL ; Fi = NULL ; Fx = NULL ; Fz = NULL ; Fnz = NULL ; Fpacked = TRUE ; } else { /* unsymmetric case: F is required. */ Fp = F->p ; Fi = F->i ; Fx = F->x ; Fz = F->z ; Fnz = F->nz ; Fpacked = F->packed ; } Ap = A->p ; /* size A->ncol+1, column pointers of A */ Ai = A->i ; /* size nz = Ap [A->ncol], row indices of A */ Ax = A->x ; /* size nz, numeric values of A */ Az = A->z ; Anz = A->nz ; packed = A->packed ; sorted = A->sorted ; use_dbound = IS_GT_ZERO (Common->dbound) ; /* get the current factors L (and D for LDL'); allocate space if needed */ is_ll = L->is_ll ; if (L->xtype == CHOLMOD_PATTERN) { /* ------------------------------------------------------------------ */ /* L is symbolic only; allocate and initialize L (and D for LDL') */ /* ------------------------------------------------------------------ */ /* workspace: none */ CHOLMOD(change_factor) (A->xtype, is_ll, FALSE, FALSE, TRUE, L, Common); if (Common->status < CHOLMOD_OK) { /* out of memory */ return (FALSE) ; } ASSERT (L->minor == (size_t) n) ; } else if (kstart == 0 && kend == (size_t) n) { /* ------------------------------------------------------------------ */ /* refactorization; reset L->nz and L->minor to restart factorization */ /* ------------------------------------------------------------------ */ L->minor = n ; Lnz = L->nz ; for (k = 0 ; k < n ; k++) { Lnz [k] = 1 ; } } ASSERT (is_ll == L->is_ll) ; ASSERT (L->xtype != CHOLMOD_PATTERN) ; DEBUG (CHOLMOD(dump_factor) (L, "L ready", Common)) ; DEBUG (CHOLMOD(dump_sparse) (A, "A ready", Common)) ; DEBUG (if (stype == 0) CHOLMOD(dump_sparse) (F, "F ready", Common)) ; /* inputs, can be modified on output: */ Lp = L->p ; /* size n+1 */ ASSERT (Lp != NULL) ; /* outputs, contents defined on input for incremental case only: */ Lnz = L->nz ; /* size n */ Lnext = L->next ; /* size n+2 */ Li = L->i ; /* size L->nzmax, can change in size */ Lx = L->x ; /* size L->nzmax or 2*L->nzmax, can change in size */ Lz = L->z ; /* size L->nzmax for zomplex case, can change in size */ nzmax = L->nzmax ; ASSERT (Lnz != NULL && Li != NULL && Lx != NULL) ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Iwork = Common->Iwork ; Stack = Iwork ; /* size n (i/i/l) */ Flag = Common->Flag ; /* size n, Flag [i] < mark must hold */ Wx = Common->Xwork ; /* size n if real, 2*n if complex or * zomplex. Xwork [i] == 0 must hold. */ Wz = Wx + n ; /* size n for zomplex case only */ mark = Common->mark ; ASSERT ((Int) Common->xworksize >= (L->xtype == CHOLMOD_REAL ? 1:2)*n) ; /* ---------------------------------------------------------------------- */ /* compute LDL' or LL' factorization by rows */ /* ---------------------------------------------------------------------- */ #ifdef MASK #define NEXT(k) k = RLinkUp [k] #else #define NEXT(k) k++ #endif for (k = kstart ; k < ((Int) kend) ; NEXT(k)) { PRINT1 (("\n===============K "ID" Lnz [k] "ID"\n", k, Lnz [k])) ; /* ------------------------------------------------------------------ */ /* compute pattern of kth row of L and scatter kth input column */ /* ------------------------------------------------------------------ */ /* column k of L is currently empty */ ASSERT (Lnz [k] == 1) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ; top = n ; /* Stack is empty */ Flag [k] = mark ; /* do not include diagonal entry in Stack */ /* use Li [Lp [i]+1] for etree */ #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY if (stype > 0) { /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ p = Ap [k] ; pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; /* W [i] = Ax [i] ; scatter column of A */ #define SCATTER ASSIGN(Wx,Wz,i, Ax,Az,p) SUBTREE ; #undef SCATTER } else { /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ pf = Fp [k] ; pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; for ( ; pf < pfend ; pf++) { /* get nonzero entry F (t,k) */ t = Fi [pf] ; /* fk = Fx [pf] */ ASSIGN (fx, fz, 0, Fx, Fz, pf) ; p = Ap [t] ; pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; multadds = 0 ; /* W [i] += Ax [p] * fx ; scatter column of A*A' */ #define SCATTER MULTADD (Wx,Wz,i, Ax,Az,p, fx,fz,0) ; multadds++ ; SUBTREE ; #undef SCATTER #ifdef REAL fl += 2 * ((double) multadds) ; #else fl += 8 * ((double) multadds) ; #endif } } #undef PARENT /* ------------------------------------------------------------------ */ /* if mask is present, set the corresponding entries in W to zero */ /* ------------------------------------------------------------------ */ #ifdef MASK /* remove the dead element of Wx */ if (mask != NULL) { #if 0 /* older version */ for (p = n; p > top;) { i = Stack [--p] ; if ( mask [i] >= 0 ) { CLEAR (Wx,Wz,i) ; /* set W(i) to zero */ } } #endif for (s = top ; s < n ; s++) { i = Stack [s] ; if (mask [i] >= 0) { CLEAR (Wx,Wz,i) ; /* set W(i) to zero */ } } } #endif /* nonzero pattern of kth row of L is now in Stack [top..n-1]. * Flag [Stack [top..n-1]] is equal to mark, but no longer needed */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; /* ------------------------------------------------------------------ */ /* compute kth row of L and store in column form */ /* ------------------------------------------------------------------ */ /* Solve L (0:k-1, 0:k-1) * y (0:k-1) = b (0:k-1) where * b (0:k) = A (0:k,k) or A(0:k,:) * F(:,k) is in W and Stack. * * For LDL' factorization: * L (k, 0:k-1) = y (0:k-1) ./ D (0:k-1) * D (k) = b (k) - L (k, 0:k-1) * y (0:k-1) * * For LL' factorization: * L (k, 0:k-1) = y (0:k-1) * L (k,k) = sqrt (b (k) - L (k, 0:k-1) * L (0:k-1, k)) */ /* dk = W [k] + beta */ ADD_REAL (dk,0, Wx,k, beta,0) ; #ifndef REAL /* In the unsymmetric case, the imaginary part of W[k] must be real, * since F is assumed to be the complex conjugate transpose of A. In * the symmetric case, W[k] is the diagonal of A. If the imaginary part * of W[k] is nonzero, then the Cholesky factorization cannot be * computed; A is not positive definite */ dk_imaginary = (stype > 0) ? (IMAG_IS_NONZERO (Wx,Wz,k)) : FALSE ; #endif /* W [k] = 0.0 ; */ CLEAR (Wx,Wz,k) ; for (s = top ; s < n ; s++) { /* get i for each nonzero entry L(k,i) */ i = Stack [s] ; /* y = W [i] ; */ ASSIGN (yx,yz,0, Wx,Wz,i) ; /* W [i] = 0.0 ; */ CLEAR (Wx,Wz,i) ; lnz = Lnz [i] ; p = Lp [i] ; ASSERT (lnz > 0 && Li [p] == i) ; pend = p + lnz ; /* di = Lx [p] ; the diagonal entry L or D(i,i), which is real */ ASSIGN_REAL (di,0, Lx,p) ; if (i >= (Int) L->minor || IS_ZERO (di [0])) { /* For the LL' factorization, L(i,i) is zero. For the LDL', * D(i,i) is zero. Skip column i of L, and set L(k,i) = 0. */ CLEAR (lx,lz,0) ; p = pend ; } else if (is_ll) { #ifdef REAL fl += 2 * ((double) (pend - p - 1)) + 3 ; #else fl += 8 * ((double) (pend - p - 1)) + 6 ; #endif /* forward solve using L (i:(k-1),i) */ /* divide by L(i,i), which must be real and nonzero */ /* y /= di [0] */ DIV_REAL (yx,yz,0, yx,yz,0, di,0) ; for (p++ ; p < pend ; p++) { /* W [Li [p]] -= Lx [p] * y ; */ MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ; } /* do not scale L; compute dot product for L(k,k) */ /* L(k,i) = conj(y) ; */ ASSIGN_CONJ (lx,lz,0, yx,yz,0) ; /* d -= conj(y) * y ; */ LLDOT (dk,0, yx,yz,0) ; } else { #ifdef REAL fl += 2 * ((double) (pend - p - 1)) + 3 ; #else fl += 8 * ((double) (pend - p - 1)) + 6 ; #endif /* forward solve using D (i,i) and L ((i+1):(k-1),i) */ for (p++ ; p < pend ; p++) { /* W [Li [p]] -= Lx [p] * y ; */ MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ; } /* Scale L (k,0:k-1) for LDL' factorization, compute D (k,k)*/ #ifdef REAL /* L(k,i) = y/d */ lx [0] = yx [0] / di [0] ; /* d -= L(k,i) * y */ dk [0] -= lx [0] * yx [0] ; #else /* L(k,i) = conj(y) ; */ ASSIGN_CONJ (lx,lz,0, yx,yz,0) ; /* L(k,i) /= di ; */ DIV_REAL (lx,lz,0, lx,lz,0, di,0) ; /* d -= conj(y) * y / di */ LDLDOT (dk,0, yx,yz,0, di,0) ; #endif } /* determine if column i of L can hold the new L(k,i) entry */ if (p >= Lp [Lnext [i]]) { /* column i needs to grow */ PRINT1 (("Factor Colrealloc "ID", old Lnz "ID"\n", i, Lnz [i])); if (!CHOLMOD(reallocate_column) (i, lnz + 1, L, Common)) { /* out of memory, L is now simplicial symbolic */ for (i = 0 ; i < n ; i++) { /* W [i] = 0 ; */ CLEAR (Wx,Wz,i) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ; return (FALSE) ; } Li = L->i ; /* L->i, L->x, L->z may have moved */ Lx = L->x ; Lz = L->z ; p = Lp [i] + lnz ; /* contents of L->p changed */ ASSERT (p < Lp [Lnext [i]]) ; } /* store L (k,i) in the column form matrix of L */ Li [p] = k ; /* Lx [p] = L(k,i) ; */ ASSIGN (Lx,Lz,p, lx,lz,0) ; Lnz [i]++ ; } /* ------------------------------------------------------------------ */ /* ensure abs (d) >= dbound if dbound is given, and store it in L */ /* ------------------------------------------------------------------ */ p = Lp [k] ; Li [p] = k ; if (k >= (Int) L->minor) { /* the matrix is already not positive definite */ dk [0] = 0 ; } else if (use_dbound) { /* modify the diagonal to force LL' or LDL' to exist */ dk [0] = CHOLMOD(dbound) (is_ll ? fabs (dk [0]) : dk [0], Common) ; } else if ((is_ll ? (IS_LE_ZERO (dk [0])) : (IS_ZERO (dk [0]))) #ifndef REAL || dk_imaginary #endif ) { /* the matrix has just been found to be not positive definite */ dk [0] = 0 ; L->minor = k ; ERROR (CHOLMOD_NOT_POSDEF, "not positive definite") ; } if (is_ll) { /* this is counted as one flop, below */ dk [0] = sqrt (dk [0]) ; } /* Lx [p] = D(k,k) = d ; real part only */ ASSIGN_REAL (Lx,p, dk,0) ; CLEAR_IMAG (Lx,Lz,p) ; } #undef NEXT if (is_ll) fl += MAX ((Int) kend - (Int) kstart, 0) ; /* count sqrt's */ Common->rowfacfl = fl ; DEBUG (CHOLMOD(dump_factor) (L, "final cholmod_rowfac", Common)) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ; return (TRUE) ; } #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_factorize.c0000644000175000017500000003435411674452555024042 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_factorize =========================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Computes the numerical factorization of a symmetric matrix. The primary * inputs to this routine are a sparse matrix A and the symbolic factor L from * cholmod_analyze or a prior numerical factor L. If A is symmetric, this * routine factorizes A(p,p)+beta*I (beta can be zero), where p is the * fill-reducing permutation (L->Perm). If A is unsymmetric, either * A(p,:)*A(p,:)'+beta*I or A(p,f)*A(p,f)'+beta*I is factorized. The set f and * the nonzero pattern of the matrix A must be the same as the matrix passed to * cholmod_analyze for the supernodal case. For the simplicial case, it can * be different, but it should be the same for best performance. beta is real. * * A simplicial factorization or supernodal factorization is chosen, based on * the type of the factor L. If L->is_super is TRUE, a supernodal LL' * factorization is computed. Otherwise, a simplicial numeric factorization * is computed, either LL' or LDL', depending on Common->final_ll. * * Once the factorization is complete, it can be left as is or optionally * converted into any simplicial numeric type, depending on the * Common->final_* parameters. If converted from a supernodal to simplicial * type, and the Common->final_resymbol parameter is true, then numerically * zero entries in L due to relaxed supernodal amalgamation are removed from * the simplicial factor (they are always left in the supernodal form of L). * Entries that are numerically zero but present in the simplicial symbolic * pattern of L are left in place (that is, the graph of L remains chordal). * This is required for the update/downdate/rowadd/rowdel routines to work * properly. * * workspace: Flag (nrow), Head (nrow+1), * if symmetric: Iwork (2*nrow+2*nsuper) * if unsymmetric: Iwork (2*nrow+MAX(2*nsuper,ncol)) * where nsuper is 0 if simplicial, or the # of relaxed supernodes in * L otherwise (nsuper <= nrow). * if simplicial: W (nrow). * Allocates up to two temporary copies of its input matrix (including * both pattern and numerical values). * * If the matrix is not positive definite the routine returns TRUE, but * sets Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the * column at which the failure occurred. Columns L->minor to L->n-1 are * set to zero. * * Supports any xtype (pattern, real, complex, or zomplex), except that the * input matrix A cannot be pattern-only. If L is simplicial, its numeric * xtype matches A on output. If L is supernodal, its xtype is real if A is * real, or complex if A is complex or zomplex. */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" #ifndef NSUPERNODAL #include "cholmod_supernodal.h" #endif /* ========================================================================== */ /* === cholmod_factorize ==================================================== */ /* ========================================================================== */ /* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained * from cholmod_analyze. The analysis can be re-used simply by calling this * routine a second time with another matrix. A must have the same nonzero * pattern as that passed to cholmod_analyze. */ int CHOLMOD(factorize) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ /* ---- in/out --- */ cholmod_factor *L, /* resulting factorization */ /* --------------- */ cholmod_common *Common ) { double zero [2] ; zero [0] = 0 ; zero [1] = 0 ; return (CHOLMOD(factorize_p) (A, zero, NULL, 0, L, Common)) ; } /* ========================================================================== */ /* === cholmod_factorize_p ================================================== */ /* ========================================================================== */ /* Same as cholmod_factorize, but with more options. */ int CHOLMOD(factorize_p) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ double beta [2], /* factorize beta*I+A or beta*I+A'*A */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- in/out --- */ cholmod_factor *L, /* resulting factorization */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *S, *F, *A1, *A2 ; Int nrow, ncol, stype, convert, n, nsuper, grow2, status ; size_t s, t, uncol ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; nrow = A->nrow ; ncol = A->ncol ; n = L->n ; stype = A->stype ; if (L->n != A->nrow) { ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ; return (FALSE) ; } if (stype != 0 && nrow != ncol) { ERROR (CHOLMOD_INVALID, "matrix invalid") ; return (FALSE) ; } DEBUG (CHOLMOD(dump_sparse) (A, "A for cholmod_factorize", Common)) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nsuper = (L->is_super ? L->nsuper : 0) ; uncol = ((stype != 0) ? 0 : ncol) ; /* s = 2*nrow + MAX (uncol, 2*nsuper) */ s = CHOLMOD(mult_size_t) (nsuper, 2, &ok) ; s = MAX (uncol, s) ; t = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; s = CHOLMOD(add_size_t) (s, t, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (nrow, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } S = NULL ; F = NULL ; A1 = NULL ; A2 = NULL ; /* convert to another form when done, if requested */ convert = !(Common->final_asis) ; /* ---------------------------------------------------------------------- */ /* perform supernodal LL' or simplicial LDL' factorization */ /* ---------------------------------------------------------------------- */ if (L->is_super) { #ifndef NSUPERNODAL /* ------------------------------------------------------------------ */ /* supernodal factorization */ /* ------------------------------------------------------------------ */ if (L->ordering == CHOLMOD_NATURAL) { /* -------------------------------------------------------------- */ /* natural ordering */ /* -------------------------------------------------------------- */ if (stype > 0) { /* S = tril (A'), F not needed */ /* workspace: Iwork (nrow) */ A1 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ; S = A1 ; } else if (stype < 0) { /* This is the fastest option for the natural ordering */ /* S = A; F not needed */ S = A ; } else { /* F = A(:,f)' */ /* workspace: Iwork (nrow) */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ; F = A1 ; /* S = A */ S = A ; } } else { /* -------------------------------------------------------------- */ /* permute the input matrix before factorization */ /* -------------------------------------------------------------- */ if (stype > 0) { /* This is the fastest option for factoring a permuted matrix */ /* S = tril (PAP'); F not needed */ /* workspace: Iwork (2*nrow) */ A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; S = A1 ; } else if (stype < 0) { /* A2 = triu (PAP') */ /* workspace: Iwork (2*nrow) */ A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; /* S = tril (A2'); F not needed */ /* workspace: Iwork (nrow) */ A1 = CHOLMOD(ptranspose) (A2, 2, NULL, NULL, 0, Common) ; S = A1 ; CHOLMOD(free_sparse) (&A2, Common) ; ASSERT (A2 == NULL) ; } else { /* F = A(p,f)' */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ; F = A1 ; /* S = F' */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ; S = A2 ; } } /* ------------------------------------------------------------------ */ /* supernodal factorization */ /* ------------------------------------------------------------------ */ /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow+2*nsuper) */ if (Common->status == CHOLMOD_OK) { CHOLMOD(super_numeric) (S, F, beta, L, Common) ; } status = Common->status ; ASSERT (IMPLIES (status >= CHOLMOD_OK, L->xtype != CHOLMOD_PATTERN)) ; /* ------------------------------------------------------------------ */ /* convert to final form, if requested */ /* ------------------------------------------------------------------ */ if (Common->status >= CHOLMOD_OK && convert) { /* workspace: none */ ok = CHOLMOD(change_factor) (L->xtype, Common->final_ll, Common->final_super, Common->final_pack, Common->final_monotonic, L, Common) ; if (ok && Common->final_resymbol && !(L->is_super)) { /* workspace: Flag (nrow), Head (nrow+1), * if symmetric: Iwork (2*nrow) * if unsymmetric: Iwork (2*nrow+ncol) */ CHOLMOD(resymbol_noperm) (S, fset, fsize, Common->final_pack, L, Common) ; } } #else /* ------------------------------------------------------------------ */ /* CHOLMOD Supernodal module not installed */ /* ------------------------------------------------------------------ */ status = CHOLMOD_NOT_INSTALLED ; ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ; #endif } else { /* ------------------------------------------------------------------ */ /* simplicial LDL' factorization */ /* ------------------------------------------------------------------ */ /* Permute the input matrix A if necessary. cholmod_rowfac requires * triu(A) in column form for the symmetric case, and A in column form * for the unsymmetric case (the matrix S). The unsymmetric case * requires A in row form, or equivalently A' in column form (the * matrix F). */ if (L->ordering == CHOLMOD_NATURAL) { /* -------------------------------------------------------------- */ /* natural ordering */ /* -------------------------------------------------------------- */ if (stype > 0) { /* F is not needed, S = A */ S = A ; } else if (stype < 0) { /* F is not needed, S = A' */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ; S = A2 ; } else { /* F = A (:,f)' */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ; F = A1 ; S = A ; } } else { /* -------------------------------------------------------------- */ /* permute the input matrix before factorization */ /* -------------------------------------------------------------- */ if (stype > 0) { /* F = tril (A (p,p)') */ /* workspace: Iwork (2*nrow) */ A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; /* A2 = triu (F') */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (A1, 2, NULL, NULL, 0, Common) ; /* the symmetric case does not need F, free it and set to NULL*/ CHOLMOD(free_sparse) (&A1, Common) ; } else if (stype < 0) { /* A2 = triu (A (p,p)'), F not needed. This is the fastest * way to factorize a matrix using the simplicial routine * (cholmod_rowfac). */ /* workspace: Iwork (2*nrow) */ A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ; } else { /* F = A (p,f)' */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ; F = A1 ; /* A2 = F' */ /* workspace: Iwork (nrow) */ A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ; } S = A2 ; } /* ------------------------------------------------------------------ */ /* simplicial LDL' or LL' factorization */ /* ------------------------------------------------------------------ */ /* factorize beta*I+S (symmetric) or beta*I+F*F' (unsymmetric) */ /* workspace: Flag (nrow), W (nrow), Iwork (2*nrow) */ if (Common->status == CHOLMOD_OK) { grow2 = Common->grow2 ; L->is_ll = BOOLEAN (Common->final_ll) ; if (L->xtype == CHOLMOD_PATTERN && Common->final_pack) { /* allocate a factor with exactly the space required */ Common->grow2 = 0 ; } CHOLMOD(rowfac) (S, F, beta, 0, nrow, L, Common) ; Common->grow2 = grow2 ; } status = Common->status ; /* ------------------------------------------------------------------ */ /* convert to final form, if requested */ /* ------------------------------------------------------------------ */ if (Common->status >= CHOLMOD_OK && convert) { /* workspace: none */ CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, Common->final_pack, Common->final_monotonic, L, Common) ; } } /* ---------------------------------------------------------------------- */ /* free A1 and A2 if they exist */ /* ---------------------------------------------------------------------- */ CHOLMOD(free_sparse) (&A1, Common) ; CHOLMOD(free_sparse) (&A2, Common) ; Common->status = MAX (Common->status, status) ; return (Common->status >= CHOLMOD_OK) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_spsolve.c0000644000175000017500000002371611674452555023547 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_spsolve ============================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Given an LL' or LDL' factorization of A, solve one of the following systems: * * Ax=b 0: CHOLMOD_A also applies the permutation L->Perm * LDL'x=b 1: CHOLMOD_LDLt does not apply L->Perm * LDx=b 2: CHOLMOD_LD * DL'x=b 3: CHOLMOD_DLt * Lx=b 4: CHOLMOD_L * L'x=b 5: CHOLMOD_Lt * Dx=b 6: CHOLMOD_D * x=Pb 7: CHOLMOD_P apply a permutation (P is L->Perm) * x=P'b 8: CHOLMOD_Pt apply an inverse permutation * * where b and x are sparse. If L and b are real, then x is real. Otherwise, * x is complex or zomplex, depending on the Common->prefer_zomplex parameter. * All xtypes of x and b are supported (real, complex, and zomplex). */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" /* ========================================================================== */ /* === EXPAND_AS_NEEDED ===================================================== */ /* ========================================================================== */ /* Double the size of the sparse matrix X, if we have run out of space. */ #define EXPAND_AS_NEEDED \ if (xnz >= nzmax) \ { \ nzmax *= 2 ; \ CHOLMOD(reallocate_sparse) (nzmax, X, Common) ; \ if (Common->status < CHOLMOD_OK) \ { \ CHOLMOD(free_sparse) (&X, Common) ; \ CHOLMOD(free_dense) (&X4, Common) ; \ CHOLMOD(free_dense) (&B4, Common) ; \ return (NULL) ; \ } \ Xi = X->i ; \ Xx = X->x ; \ Xz = X->z ; \ } /* ========================================================================== */ /* === cholmod_spolve ======================================================= */ /* ========================================================================== */ cholmod_sparse *CHOLMOD(spsolve) /* returns the sparse solution X */ ( /* ---- input ---- */ int sys, /* system to solve */ cholmod_factor *L, /* factorization to use */ cholmod_sparse *B, /* right-hand-side */ /* --------------- */ cholmod_common *Common ) { double x, z ; cholmod_dense *X4, *B4 ; cholmod_sparse *X ; double *Bx, *Bz, *Xx, *Xz, *B4x, *B4z, *X4x, *X4z ; Int *Bi, *Bp, *Xp, *Xi, *Bnz ; Int n, nrhs, q, p, i, j, jfirst, jlast, packed, block, pend, j_n, xtype ; size_t xnz, nzmax ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (L, NULL) ; RETURN_IF_NULL (B, NULL) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; if (L->n != B->nrow) { ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ; return (NULL) ; } if (B->stype) { ERROR (CHOLMOD_INVALID, "B cannot be stored in symmetric mode") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace B4 and initial result X */ /* ---------------------------------------------------------------------- */ n = L->n ; nrhs = B->ncol ; /* X is real if both L and B are real, complex/zomplex otherwise */ xtype = (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : (Common->prefer_zomplex ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX) ; /* solve up to 4 columns at a time */ block = MIN (nrhs, 4) ; /* initial size of X is at most 4*n */ nzmax = n*block ; X = CHOLMOD(spzeros) (n, nrhs, nzmax, xtype, Common) ; B4 = CHOLMOD(zeros) (n, block, B->xtype, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&X, Common) ; CHOLMOD(free_dense) (&B4, Common) ; return (NULL) ; } Bp = B->p ; Bi = B->i ; Bx = B->x ; Bz = B->z ; Bnz = B->nz ; packed = B->packed ; Xp = X->p ; Xi = X->i ; Xx = X->x ; Xz = X->z ; xnz = 0 ; B4x = B4->x ; B4z = B4->z ; /* ---------------------------------------------------------------------- */ /* solve in chunks of 4 columns at a time */ /* ---------------------------------------------------------------------- */ for (jfirst = 0 ; jfirst < nrhs ; jfirst += block) { /* ------------------------------------------------------------------ */ /* adjust the number of columns of B4 */ /* ------------------------------------------------------------------ */ jlast = MIN (nrhs, jfirst + block) ; B4->ncol = jlast - jfirst ; /* ------------------------------------------------------------------ */ /* scatter B(jfirst:jlast-1) into B4 */ /* ------------------------------------------------------------------ */ for (j = jfirst ; j < jlast ; j++) { p = Bp [j] ; pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ; j_n = (j-jfirst)*n ; switch (B->xtype) { case CHOLMOD_REAL: for ( ; p < pend ; p++) { B4x [Bi [p] + j_n] = Bx [p] ; } break ; case CHOLMOD_COMPLEX: for ( ; p < pend ; p++) { q = Bi [p] + j_n ; B4x [2*q ] = Bx [2*p ] ; B4x [2*q+1] = Bx [2*p+1] ; } break ; case CHOLMOD_ZOMPLEX: for ( ; p < pend ; p++) { q = Bi [p] + j_n ; B4x [q] = Bx [p] ; B4z [q] = Bz [p] ; } break ; } } /* ------------------------------------------------------------------ */ /* solve the system (X4 = A\B4 or other system) */ /* ------------------------------------------------------------------ */ X4 = CHOLMOD(solve) (sys, L, B4, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&X, Common) ; CHOLMOD(free_dense) (&B4, Common) ; CHOLMOD(free_dense) (&X4, Common) ; return (NULL) ; } ASSERT (X4->xtype == xtype) ; X4x = X4->x ; X4z = X4->z ; /* ------------------------------------------------------------------ */ /* append the solution onto X */ /* ------------------------------------------------------------------ */ for (j = jfirst ; j < jlast ; j++) { Xp [j] = xnz ; j_n = (j-jfirst)*n ; if ( xnz + n <= nzmax) { /* ---------------------------------------------------------- */ /* X is guaranteed to be large enough */ /* ---------------------------------------------------------- */ switch (xtype) { case CHOLMOD_REAL: for (i = 0 ; i < n ; i++) { x = X4x [i + j_n] ; if (IS_NONZERO (x)) { Xi [xnz] = i ; Xx [xnz] = x ; xnz++ ; } } break ; case CHOLMOD_COMPLEX: for (i = 0 ; i < n ; i++) { x = X4x [2*(i + j_n) ] ; z = X4x [2*(i + j_n)+1] ; if (IS_NONZERO (x) || IS_NONZERO (z)) { Xi [xnz] = i ; Xx [2*xnz ] = x ; Xx [2*xnz+1] = z ; xnz++ ; } } break ; case CHOLMOD_ZOMPLEX: for (i = 0 ; i < n ; i++) { x = X4x [i + j_n] ; z = X4z [i + j_n] ; if (IS_NONZERO (x) || IS_NONZERO (z)) { Xi [xnz] = i ; Xx [xnz] = x ; Xz [xnz] = z ; xnz++ ; } } break ; } } else { /* ---------------------------------------------------------- */ /* X may need to increase in size */ /* ---------------------------------------------------------- */ switch (xtype) { case CHOLMOD_REAL: for (i = 0 ; i < n ; i++) { x = X4x [i + j_n] ; if (IS_NONZERO (x)) { EXPAND_AS_NEEDED ; Xi [xnz] = i ; Xx [xnz] = x ; xnz++ ; } } break ; case CHOLMOD_COMPLEX: for (i = 0 ; i < n ; i++) { x = X4x [2*(i + j_n) ] ; z = X4x [2*(i + j_n)+1] ; if (IS_NONZERO (x) || IS_NONZERO (z)) { EXPAND_AS_NEEDED ; Xi [xnz] = i ; Xx [2*xnz ] = x ; Xx [2*xnz+1] = z ; xnz++ ; } } break ; case CHOLMOD_ZOMPLEX: for (i = 0 ; i < n ; i++) { x = X4x [i + j_n] ; z = X4z [i + j_n] ; if (IS_NONZERO (x) || IS_NONZERO (z)) { EXPAND_AS_NEEDED ; Xi [xnz] = i ; Xx [xnz] = x ; Xz [xnz] = z ; xnz++ ; } } break ; } } } CHOLMOD(free_dense) (&X4, Common) ; /* ------------------------------------------------------------------ */ /* clear B4 for next iteration */ /* ------------------------------------------------------------------ */ if (jlast < nrhs) { for (j = jfirst ; j < jlast ; j++) { p = Bp [j] ; pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ; j_n = (j-jfirst)*n ; switch (B->xtype) { case CHOLMOD_REAL: for ( ; p < pend ; p++) { B4x [Bi [p] + j_n] = 0 ; } break ; case CHOLMOD_COMPLEX: for ( ; p < pend ; p++) { q = Bi [p] + j_n ; B4x [2*q ] = 0 ; B4x [2*q+1] = 0 ; } break ; case CHOLMOD_ZOMPLEX: for ( ; p < pend ; p++) { q = Bi [p] + j_n ; B4x [q] = 0 ; B4z [q] = 0 ; } break ; } } } } Xp [nrhs] = xnz ; /* ---------------------------------------------------------------------- */ /* reduce X in size, free workspace, and return result */ /* ---------------------------------------------------------------------- */ ASSERT (xnz <= X->nzmax) ; CHOLMOD(reallocate_sparse) (xnz, X, Common) ; ASSERT (Common->status == CHOLMOD_OK) ; CHOLMOD(free_dense) (&B4, Common) ; return (X) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/lesser.txt0000644000175000017500000006350011674452555022234 0ustar sonnesonne GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowcolcounts.c0000644000175000017500000004373111674452555024614 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_rowcolcounts ======================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Compute the row and column counts of the Cholesky factor L of the matrix * A or A*A'. The etree and its postordering must already be computed (see * cholmod_etree and cholmod_postorder) and given as inputs to this routine. * * For the symmetric case (LL'=A), A is accessed by column. Only the lower * triangular part of A is used. Entries not in this part of the matrix are * ignored. This is the same as storing the upper triangular part of A by * rows, with entries in the lower triangular part being ignored. NOTE: this * representation is the TRANSPOSE of the input to cholmod_etree. * * For the unsymmetric case (LL'=AA'), A is accessed by column. Equivalently, * if A is viewed as a matrix in compressed-row form, this routine computes * the row and column counts for L where LL'=A'A. If the input vector f is * present, then F*F' is analyzed instead, where F = A(:,f). * * The set f is held in fset and fsize. * fset = NULL means ":" in MATLAB. fset is ignored. * fset != NULL means f = fset [0..fset-1]. * fset != NULL and fsize = 0 means f is the empty set. * Common->status is set to CHOLMOD_INVALID if fset is invalid. * * In both cases, the columns of A need not be sorted. * A can be packed or unpacked. * * References: * J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and * column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis & * Applic., vol 15, 1994, pp. 1075-1091. * * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. * * workspace: * if symmetric: Flag (nrow), Iwork (2*nrow) * if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1) * * Supports any xtype (pattern, real, complex, or zomplex). */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" /* ========================================================================== */ /* === initialize_node ====================================================== */ /* ========================================================================== */ static int initialize_node /* initial work for kth node in postordered etree */ ( Int k, /* at the kth step of the algorithm (and kth node) */ Int Post [ ], /* Post [k] = i, the kth node in postordered etree */ Int Parent [ ], /* Parent [i] is the parent of i in the etree */ Int ColCount [ ], /* ColCount [c] is the current weight of node c */ Int PrevNbr [ ] /* PrevNbr [u] = k if u was last considered at step k */ ) { Int p, parent ; /* determine p, the kth node in the postordered etree */ p = Post [k] ; /* adjust the weight if p is not a root of the etree */ parent = Parent [p] ; if (parent != EMPTY) { ColCount [parent]-- ; } /* flag node p to exclude self edges (p,p) */ PrevNbr [p] = k ; return (p) ; } /* ========================================================================== */ /* === process_edge ========================================================= */ /* ========================================================================== */ /* edge (p,u) is being processed. p < u is a descendant of its ancestor u in * the etree. node p is the kth node in the postordered etree. */ static void process_edge ( Int p, /* process edge (p,u) of the matrix */ Int u, Int k, /* we are at the kth node in the postordered etree */ Int First [ ], /* First [i] = k if the postordering of first * descendent of node i is k */ Int PrevNbr [ ], /* u was last considered at step k = PrevNbr [u] */ Int ColCount [ ], /* ColCount [c] is the current weight of node c */ Int PrevLeaf [ ], /* s = PrevLeaf [u] means that s was the last leaf * seen in the subtree rooted at u. */ Int RowCount [ ], /* RowCount [i] is # of nonzeros in row i of L, * including the diagonal. Not computed if NULL. */ Int SetParent [ ], /* the FIND/UNION data structure, which forms a set * of trees. A root i has i = SetParent [i]. Following * a path from i to the root q of the subtree containing * i means that q is the SetParent representative of i. * All nodes in the tree could have their SetParent * equal to the root q; the tree representation is used * to save time. When a path is traced from i to its * root q, the path is re-traversed to set the SetParent * of the whole path to be the root q. */ Int Level [ ] /* Level [i] = length of path from node i to root */ ) { Int prevleaf, q, s, sparent ; if (First [p] > PrevNbr [u]) { /* p is a leaf of the subtree of u */ ColCount [p]++ ; prevleaf = PrevLeaf [u] ; if (prevleaf == EMPTY) { /* p is the first leaf of subtree of u; RowCount will be incremented * by the length of the path in the etree from p up to u. */ q = u ; } else { /* q = FIND (prevleaf): find the root q of the * SetParent tree containing prevleaf */ for (q = prevleaf ; q != SetParent [q] ; q = SetParent [q]) { ; } /* the root q has been found; re-traverse the path and * perform path compression */ s = prevleaf ; for (s = prevleaf ; s != q ; s = sparent) { sparent = SetParent [s] ; SetParent [s] = q ; } /* adjust the RowCount and ColCount; RowCount will be incremented by * the length of the path from p to the SetParent root q, and * decrement the ColCount of q by one. */ ColCount [q]-- ; } if (RowCount != NULL) { /* if RowCount is being computed, increment it by the length of * the path from p to q */ RowCount [u] += (Level [p] - Level [q]) ; } /* p is a leaf of the subtree of u, so mark PrevLeaf [u] to be p */ PrevLeaf [u] = p ; } /* flag u has having been processed at step k */ PrevNbr [u] = k ; } /* ========================================================================== */ /* === finalize_node ======================================================== */ /* ========================================================================== */ static void finalize_node /* compute UNION (p, Parent [p]) */ ( Int p, Int Parent [ ], /* Parent [p] is the parent of p in the etree */ Int SetParent [ ] /* see process_edge, above */ ) { /* all nodes in the SetParent tree rooted at p now have as their final * root the node Parent [p]. This computes UNION (p, Parent [p]) */ if (Parent [p] != EMPTY) { SetParent [p] = Parent [p] ; } } /* ========================================================================== */ /* === cholmod_rowcolcounts ================================================= */ /* ========================================================================== */ int CHOLMOD(rowcolcounts) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ Int *Parent, /* size nrow. Parent [i] = p if p is the parent of i */ Int *Post, /* size nrow. Post [k] = i if i is the kth node in * the postordered etree. */ /* ---- output --- */ Int *RowCount, /* size nrow. RowCount [i] = # entries in the ith row of * L, including the diagonal. */ Int *ColCount, /* size nrow. ColCount [i] = # entries in the ith * column of L, including the diagonal. */ Int *First, /* size nrow. First [i] = k is the least postordering * of any descendant of i. */ Int *Level, /* size nrow. Level [i] is the length of the path from * i to the root, with Level [root] = 0. */ /* --------------- */ cholmod_common *Common ) { double fl, ff ; Int *Ap, *Ai, *Anz, *PrevNbr, *SetParent, *Head, *PrevLeaf, *Anext, *Ipost, *Iwork ; Int i, j, r, k, len, s, p, pend, inew, stype, nf, anz, inode, parent, nrow, ncol, packed, use_fset, jj ; size_t w ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (Parent, FALSE) ; RETURN_IF_NULL (Post, FALSE) ; RETURN_IF_NULL (ColCount, FALSE) ; RETURN_IF_NULL (First, FALSE) ; RETURN_IF_NULL (Level, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; stype = A->stype ; if (stype > 0) { /* symmetric with upper triangular part not supported */ ERROR (CHOLMOD_INVALID, "symmetric upper not supported") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; /* the number of rows of A */ ncol = A->ncol ; /* the number of columns of A */ /* w = 2*nrow + (stype ? 0 : ncol) */ w = CHOLMOD(mult_size_t) (nrow, 2, &ok) ; w = CHOLMOD(add_size_t) (w, (stype ? 0 : ncol), &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (nrow, w, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_perm) (Post, nrow, nrow, "Post", Common)) ; ASSERT (CHOLMOD(dump_parent) (Parent, nrow, "Parent", Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ Ap = A->p ; /* size ncol+1, column pointers for A */ Ai = A->i ; /* the row indices of A, of size nz=Ap[ncol+1] */ Anz = A->nz ; packed = A->packed ; ASSERT (IMPLIES (!packed, Anz != NULL)) ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Iwork = Common->Iwork ; SetParent = Iwork ; /* size nrow (i/i/l) */ PrevNbr = Iwork + nrow ; /* size nrow (i/i/l) */ Anext = Iwork + 2*((size_t) nrow) ; /* size ncol (i/i/l) (unsym only) */ PrevLeaf = Common->Flag ; /* size nrow */ Head = Common->Head ; /* size nrow+1 (unsym only)*/ /* ---------------------------------------------------------------------- */ /* find the first descendant and level of each node in the tree */ /* ---------------------------------------------------------------------- */ /* First [i] = k if the postordering of first descendent of node i is k */ /* Level [i] = length of path from node i to the root (Level [root] = 0) */ for (i = 0 ; i < nrow ; i++) { First [i] = EMPTY ; } /* postorder traversal of the etree */ for (k = 0 ; k < nrow ; k++) { /* node i of the etree is the kth node in the postordered etree */ i = Post [k] ; /* i is a leaf if First [i] is still EMPTY */ /* ColCount [i] starts at 1 if i is a leaf, zero otherwise */ ColCount [i] = (First [i] == EMPTY) ? 1 : 0 ; /* traverse the path from node i to the root, stopping if we find a * node r whose First [r] is already defined. */ len = 0 ; for (r = i ; (r != EMPTY) && (First [r] == EMPTY) ; r = Parent [r]) { First [r] = k ; len++ ; } if (r == EMPTY) { /* we hit a root node, the level of which is zero */ len-- ; } else { /* we stopped at node r, where Level [r] is already defined */ len += Level [r] ; } /* re-traverse the path from node i to r; set the level of each node */ for (s = i ; s != r ; s = Parent [s]) { Level [s] = len-- ; } } /* ---------------------------------------------------------------------- */ /* AA' case: sort columns of A according to first postordered row index */ /* ---------------------------------------------------------------------- */ fl = 0.0 ; if (stype == 0) { /* [ use PrevNbr [0..nrow-1] as workspace for Ipost */ Ipost = PrevNbr ; /* Ipost [i] = k if i is the kth node in the postordered etree. */ for (k = 0 ; k < nrow ; k++) { Ipost [Post [k]] = k ; } use_fset = (fset != NULL) ; if (use_fset) { nf = fsize ; /* clear Anext to check fset */ for (j = 0 ; j < ncol ; j++) { Anext [j] = -2 ; } /* find the first postordered row in each column of A (post,f) * and place the column in the corresponding link list */ for (jj = 0 ; jj < nf ; jj++) { j = fset [jj] ; if (j < 0 || j > ncol || Anext [j] != -2) { /* out-of-range or duplicate entry in fset */ ERROR (CHOLMOD_INVALID, "fset invalid") ; return (FALSE) ; } /* flag column j as having been seen */ Anext [j] = EMPTY ; } /* fset is now valid */ ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ; } else { nf = ncol ; } for (jj = 0 ; jj < nf ; jj++) { j = (use_fset) ? (fset [jj]) : jj ; /* column j is in the fset; find the smallest row (if any) */ p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; ff = (double) MAX (0, pend - p) ; fl += ff*ff + ff ; if (pend > p) { k = Ipost [Ai [p]] ; for ( ; p < pend ; p++) { inew = Ipost [Ai [p]] ; k = MIN (k, inew) ; } /* place column j in link list k */ ASSERT (k >= 0 && k < nrow) ; Anext [j] = Head [k] ; Head [k] = j ; } } /* Ipost no longer needed for inverse postordering ] * Head [k] contains a link list of all columns whose first * postordered row index is equal to k, for k = 0 to nrow-1. */ } /* ---------------------------------------------------------------------- */ /* compute the row counts and node weights */ /* ---------------------------------------------------------------------- */ if (RowCount != NULL) { for (i = 0 ; i < nrow ; i++) { RowCount [i] = 1 ; } } for (i = 0 ; i < nrow ; i++) { PrevLeaf [i] = EMPTY ; PrevNbr [i] = EMPTY ; SetParent [i] = i ; /* every node is in its own set, by itself */ } if (stype != 0) { /* ------------------------------------------------------------------ */ /* symmetric case: LL' = A */ /* ------------------------------------------------------------------ */ /* also determine the number of entries in triu(A) */ anz = nrow ; for (k = 0 ; k < nrow ; k++) { /* j is the kth node in the postordered etree */ j = initialize_node (k, Post, Parent, ColCount, PrevNbr) ; /* for all nonzeros A(i,j) below the diagonal, in column j of A */ p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i > j) { /* j is a descendant of i in etree(A) */ anz++ ; process_edge (j, i, k, First, PrevNbr, ColCount, PrevLeaf, RowCount, SetParent, Level) ; } } /* update SetParent: UNION (j, Parent [j]) */ finalize_node (j, Parent, SetParent) ; } Common->anz = anz ; } else { /* ------------------------------------------------------------------ */ /* unsymmetric case: LL' = AA' */ /* ------------------------------------------------------------------ */ for (k = 0 ; k < nrow ; k++) { /* inode is the kth node in the postordered etree */ inode = initialize_node (k, Post, Parent, ColCount, PrevNbr) ; /* for all cols j whose first postordered row is k: */ for (j = Head [k] ; j != EMPTY ; j = Anext [j]) { /* k is the first postordered row in column j of A */ /* for all rows i in column j: */ p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; /* has i already been considered at this step k */ if (PrevNbr [i] < k) { /* inode is a descendant of i in etree(AA') */ /* process edge (inode,i) and set PrevNbr[i] to k */ process_edge (inode, i, k, First, PrevNbr, ColCount, PrevLeaf, RowCount, SetParent, Level) ; } } } /* clear link list k */ Head [k] = EMPTY ; /* update SetParent: UNION (inode, Parent [inode]) */ finalize_node (inode, Parent, SetParent) ; } } /* ---------------------------------------------------------------------- */ /* finish computing the column counts */ /* ---------------------------------------------------------------------- */ for (j = 0 ; j < nrow ; j++) { parent = Parent [j] ; if (parent != EMPTY) { /* add the ColCount of j to its parent */ ColCount [parent] += ColCount [j] ; } } /* ---------------------------------------------------------------------- */ /* clear workspace */ /* ---------------------------------------------------------------------- */ Common->mark = EMPTY ; /* CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* flop count and nnz(L) for subsequent LL' numerical factorization */ /* ---------------------------------------------------------------------- */ /* use double to avoid integer overflow. lnz cannot be NaN. */ Common->aatfl = fl ; Common->lnz = 0. ; fl = 0 ; for (j = 0 ; j < nrow ; j++) { ff = (double) (ColCount [j]) ; Common->lnz += ff ; fl += ff*ff ; } Common->fl = fl ; PRINT1 (("rowcol fl %g lnz %g\n", Common->fl, Common->lnz)) ; return (TRUE) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Cholesky/cholmod_rowfac.c0000644000175000017500000005243711674452555023337 0ustar sonnesonne/* ========================================================================== */ /* === Cholesky/cholmod_rowfac ============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Cholesky Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Full or incremental numerical LDL' or LL' factorization (simplicial, not * supernodal) cholmod_factorize is the "easy" wrapper for this code, but it * does not provide access to incremental factorization. * * cholmod_rowfac computes the full or incremental LDL' or LL' factorization of * A+beta*I (where A is symmetric) or A*F+beta*I (where A and F are unsymmetric * and only the upper triangular part of A*F+beta*I is used). It computes * L (and D, for LDL') one row at a time. beta is real. * * A is nrow-by-ncol or nrow-by-nrow. In "packed" form it is a conventional * column-oriented sparse matrix. Row indices of column j are in * Ai [Ap [j] ... Ap [j+1]-1] and values in the same locations of Ax. * will be faster if A has sorted columns. In "unpacked" form the column * of A ends at Ap [j] + Anz [j] - 1 instead of Ap [j+1] - 1. * * Row indices in each column of A can be sorted or unsorted, but the routine * routine works fastest if A is sorted, or if only triu(A) is provided * for the symmetric case. * * The unit-diagonal nrow-by-nrow output matrix L is returned in "unpacked" * column form, with row indices of column j in Li [Lp [j] ... * Lp [j] + Lnz [j] - 1] and values in the same location in Lx. The row * indices in each column of L are in sorted order. The unit diagonal of L * is not stored. * * L can be a simplicial symbolic or numeric (L->is_super must be FALSE). * A symbolic factor is converted immediately into a numeric factor containing * the identity matrix. * * For a full factorization, kstart = 0 and kend = nrow. The existing nonzero * entries (numerical values in L->x and L->z for the zomplex case, and indices * in L->i), if any, are overwritten. * * To compute an incremental factorization, select kstart and kend as the range * of rows of L you wish to compute. A correct factorization will be computed * only if all descendants of all nodes k = kstart to kend-1 in the etree have * been factorized by a prior call to this routine, and if rows kstart to kend-1 * have not been factorized. This condition is NOT checked on input. * * --------------- * Symmetric case: * --------------- * * The factorization (in MATLAB notation) is: * * S = beta*I + A * S = triu (S) + triu (S,1)' * L*D*L' = S, or L*L' = S * * A is a conventional sparse matrix in compressed column form. Only the * diagonal and upper triangular part of A is accessed; the lower * triangular part is ignored and assumed to be equal to the upper * triangular part. For an incremental factorization, only columns kstart * to kend-1 of A are accessed. F is not used. * * --------------- * Unsymmetric case: * --------------- * * The factorization (in MATLAB notation) is: * * S = beta*I + A*F * S = triu (S) + triu (S,1)' * L*D*L' = S, or L*L' = S * * The typical case is F=A'. Alternatively, if F=A(:,f)', then this * routine factorizes S = beta*I + A(:,f)*A(:,f)'. * * All of A and F are accessed, but only the upper triangular part of A*F * is used. F must be of size A->ncol by A->nrow. F is used for the * unsymmetric case only. F can be packed or unpacked and it need not be * sorted. * * For a complete factorization of beta*I + A*A', * this routine performs a number of flops exactly equal to: * * sum (for each column j of A) of (Anz (j)^2 + Anz (j)), to form S * + * sum (for each column j of L) of (Lnz (j)^2 + 3*Lnz (j)), to factorize S * * where Anz (j) is the number of nonzeros in column j of A, and Lnz (j) * is the number of nonzero in column j of L below the diagonal. * * * workspace: Flag (nrow), W (nrow if real, 2*nrow if complex/zomplex), * Iwork (nrow) * * Supports any xtype, except a pattern-only input matrix A cannot be * factorized. */ #ifndef NCHOLESKY #include "cholmod_internal.h" #include "cholmod_cholesky.h" /* ========================================================================== */ /* === subtree ============================================================== */ /* ========================================================================== */ /* Compute the nonzero pattern of the sparse triangular solve Lx=b, where L in * this case is L(0:k-1,0:k-1), and b is a column of A. This is done by * traversing the kth row-subtree of the elimination tree of L, starting from * each nonzero entry in b. The pattern is returned postordered, and is valid * for a subsequent numerical triangular solve of Lx=b. The elimination tree * can be provided in a Parent array, or extracted from the pattern of L itself. * * The pattern of x = inv(L)*b is returned in Stack [top...]. * Also scatters b, or a multiple of b, into the work vector W. * * The SCATTER macro is defines how the numerical values of A or A*A' are to be * scattered. * * PARENT(i) is a macro the defines how the etree is accessed. It is either: * #define PARENT(i) Parent [i] * #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY */ #define SUBTREE \ for ( ; p < pend ; p++) \ { \ i = Ai [p] ; \ if (i <= k) \ { \ /* scatter the column of A, or A*A' into Wx and Wz */ \ SCATTER ; \ /* start at node i and traverse up the subtree, stop at node k */ \ for (len = 0 ; i < k && i != EMPTY && Flag [i] < mark ; i = parent) \ { \ /* L(k,i) is nonzero, and seen for the first time */ \ Stack [len++] = i ; /* place i on the stack */ \ Flag [i] = mark ; /* mark i as visited */ \ parent = PARENT (i) ; /* traverse up the etree to the parent */ \ } \ /* move the path down to the bottom of the stack */ \ while (len > 0) \ { \ Stack [--top] = Stack [--len] ; \ } \ } \ else if (sorted) \ { \ break ; \ } \ } /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define REAL #include "t_cholmod_rowfac.c" #define COMPLEX #include "t_cholmod_rowfac.c" #define ZOMPLEX #include "t_cholmod_rowfac.c" #define MASK #define REAL #include "t_cholmod_rowfac.c" #define COMPLEX #include "t_cholmod_rowfac.c" #define ZOMPLEX #include "t_cholmod_rowfac.c" #undef MASK /* ========================================================================== */ /* === cholmod_row_subtree ================================================== */ /* ========================================================================== */ /* Compute the nonzero pattern of the solution to the lower triangular system * L(0:k-1,0:k-1) * x = A (0:k-1,k) if A is symmetric, or * L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)' if A is unsymmetric. * This gives the nonzero pattern of row k of L (excluding the diagonal). * The pattern is returned postordered. * * The symmetric case requires A to be in symmetric-upper form. * * The result is returned in R, a pre-allocated sparse matrix of size nrow-by-1, * with R->nzmax >= nrow. R is assumed to be packed (Rnz [0] is not updated); * the number of entries in R is given by Rp [0]. * * FUTURE WORK: a very minor change to this routine could allow it to compute * the nonzero pattern of x for any system Lx=b. The SUBTREE macro would need * to change, to eliminate its dependence on k. * * workspace: Flag (nrow) */ int CHOLMOD(row_subtree) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ size_t krow, /* row k of L */ Int *Parent, /* elimination tree */ /* ---- output --- */ cholmod_sparse *R, /* pattern of L(k,:), 1-by-n with R->nzmax >= n */ /* --------------- */ cholmod_common *Common ) { Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Fp, *Fi, *Fnz ; Int p, pend, parent, t, stype, nrow, k, pf, pfend, Fpacked, packed, sorted, top, len, i, mark ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (R, FALSE) ; RETURN_IF_NULL (Parent, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; stype = A->stype ; if (stype == 0) { RETURN_IF_NULL (F, FALSE) ; RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; } if (krow >= A->nrow) { ERROR (CHOLMOD_INVALID, "subtree: k invalid") ; return (FALSE) ; } if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax) { ERROR (CHOLMOD_INVALID, "subtree: R invalid") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if (stype > 0) { /* symmetric upper case: F is not needed. It may be NULL */ Fp = NULL ; Fi = NULL ; Fnz = NULL ; Fpacked = TRUE ; } else if (stype == 0) { /* unsymmetric case: F is required. */ Fp = F->p ; Fi = F->i ; Fnz = F->nz ; Fpacked = F->packed ; } else { /* symmetric lower triangular form not supported */ ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; return (FALSE) ; } Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; sorted = A->sorted ; k = krow ; Stack = R->i ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Flag = Common->Flag ; /* size nrow, Flag [i] < mark must hold */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; /* ---------------------------------------------------------------------- */ /* compute the pattern of L(k,:) */ /* ---------------------------------------------------------------------- */ top = nrow ; /* Stack is empty */ Flag [k] = mark ; /* do not include diagonal entry in Stack */ #define SCATTER /* do not scatter numerical values */ #define PARENT(i) Parent [i] /* use Parent for etree */ if (stype != 0) { /* scatter kth col of triu (A), get pattern L(k,:) */ p = Ap [k] ; pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; SUBTREE ; } else { /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ pf = Fp [k] ; pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ; for ( ; pf < pfend ; pf++) { /* get nonzero entry F (t,k) */ t = Fi [pf] ; p = Ap [t] ; pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; SUBTREE ; } } #undef SCATTER #undef PARENT /* shift the stack upwards, to the first part of R */ len = nrow - top ; for (i = 0 ; i < len ; i++) { Stack [i] = Stack [top + i] ; } Rp = R->p ; Rp [0] = 0 ; Rp [1] = len ; R->sorted = FALSE ; CHOLMOD(clear_flag) (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_row_lsubtree ================================================= */ /* ========================================================================== */ /* Identical to cholmod_row_subtree, except that the elimination tree is * obtained from L itself, as the first off-diagonal entry in each column. * L must be simplicial, not supernodal */ int CHOLMOD(row_lsubtree) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ Int *Fi, size_t fnz, /* nonzero pattern of kth row of A', not required * for the symmetric case. Need not be sorted. */ size_t krow, /* row k of L */ cholmod_factor *L, /* the factor L from which parent(i) is derived */ /* ---- output --- */ cholmod_sparse *R, /* pattern of L(k,:), 1-by-n with R->nzmax >= n */ /* --------------- */ cholmod_common *Common ) { Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Lp, *Li, *Lnz ; Int p, pend, parent, t, stype, nrow, k, pf, packed, sorted, top, len, i, mark ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (R, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; stype = A->stype ; if (stype == 0) { RETURN_IF_NULL (Fi, FALSE) ; } if (krow >= A->nrow) { ERROR (CHOLMOD_INVALID, "lsubtree: k invalid") ; return (FALSE) ; } if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax) { ERROR (CHOLMOD_INVALID, "lsubtree: R invalid") ; return (FALSE) ; } if (L->is_super) { ERROR (CHOLMOD_INVALID, "lsubtree: L invalid (cannot be supernodal)") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; CHOLMOD(allocate_work) (nrow, 0, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if (stype < 0) { /* symmetric lower triangular form not supported */ ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; return (FALSE) ; } Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; sorted = A->sorted ; k = krow ; Stack = R->i ; Lp = L->p ; Li = L->i ; Lnz = L->nz ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Flag = Common->Flag ; /* size nrow, Flag [i] < mark must hold */ mark = CHOLMOD(clear_flag) (Common) ; /* ---------------------------------------------------------------------- */ /* compute the pattern of L(k,:) */ /* ---------------------------------------------------------------------- */ top = nrow ; /* Stack is empty */ Flag [k] = mark ; /* do not include diagonal entry in Stack */ #define SCATTER /* do not scatter numerical values */ #define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY if (stype != 0) { /* scatter kth col of triu (A), get pattern L(k,:) */ p = Ap [k] ; pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ; SUBTREE ; } else { /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */ for (pf = 0 ; pf < (Int) fnz ; pf++) { /* get nonzero entry F (t,k) */ t = Fi [pf] ; p = Ap [t] ; pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ; SUBTREE ; } } #undef SCATTER #undef PARENT /* shift the stack upwards, to the first part of R */ len = nrow - top ; for (i = 0 ; i < len ; i++) { Stack [i] = Stack [top + i] ; } Rp = R->p ; Rp [0] = 0 ; Rp [1] = len ; R->sorted = FALSE ; CHOLMOD(clear_flag) (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_rowfac ======================================================= */ /* ========================================================================== */ /* This is the incremental factorization for general purpose usage. */ int CHOLMOD(rowfac) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ double beta [2], /* factorize beta*I+A or beta*I+AA' */ size_t kstart, /* first row to factorize */ size_t kend, /* last row to factorize is kend-1 */ /* ---- in/out --- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) { return (CHOLMOD(rowfac_mask) (A, F, beta, kstart, kend, NULL, NULL, L, Common)) ; } /* ========================================================================== */ /* === cholmod_rowfac_mask ================================================== */ /* ========================================================================== */ /* This is meant for use in LPDASA only. */ int CHOLMOD(rowfac_mask) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,f)' */ double beta [2], /* factorize beta*I+A or beta*I+AA' */ size_t kstart, /* first row to factorize */ size_t kend, /* last row to factorize is kend-1 */ Int *mask, /* size A->nrow. if mask[i] >= 0 row i is set to zero */ Int *RLinkUp, /* size A->nrow. link list of rows to compute */ /* ---- in/out --- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) { Int n ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (L->xtype != CHOLMOD_PATTERN && A->xtype != L->xtype) { ERROR (CHOLMOD_INVALID, "xtype of A and L do not match") ; return (FALSE) ; } if (L->is_super) { ERROR (CHOLMOD_INVALID, "can only do simplicial factorization"); return (FALSE) ; } if (A->stype == 0) { RETURN_IF_NULL (F, FALSE) ; if (A->xtype != F->xtype) { ERROR (CHOLMOD_INVALID, "xtype of A and F do not match") ; return (FALSE) ; } } if (A->stype < 0) { /* symmetric lower triangular form not supported */ ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; return (FALSE) ; } if (kend > L->n) { ERROR (CHOLMOD_INVALID, "kend invalid") ; return (FALSE) ; } if (A->nrow != L->n) { ERROR (CHOLMOD_INVALID, "dimensions of A and L do not match") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; Common->rowfacfl = 0 ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* Xwork is of size n for the real case, 2*n for complex/zomplex */ n = L->n ; /* s = ((A->xtype != CHOLMOD_REAL) ? 2:1)*n */ s = CHOLMOD(mult_size_t) (n, ((A->xtype != CHOLMOD_REAL) ? 2:1), &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (n, n, s, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, A->nrow, Common)) ; /* ---------------------------------------------------------------------- */ /* factorize the matrix, using template routine */ /* ---------------------------------------------------------------------- */ if (RLinkUp == NULL) { switch (A->xtype) { case CHOLMOD_REAL: ok = r_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; break ; case CHOLMOD_COMPLEX: ok = c_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; break ; case CHOLMOD_ZOMPLEX: ok = z_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ; break ; } } else { switch (A->xtype) { case CHOLMOD_REAL: ok = r_cholmod_rowfac_mask (A, F, beta, kstart, kend, mask, RLinkUp, L, Common) ; break ; case CHOLMOD_COMPLEX: ok = c_cholmod_rowfac_mask (A, F, beta, kstart, kend, mask, RLinkUp, L, Common) ; break ; case CHOLMOD_ZOMPLEX: ok = z_cholmod_rowfac_mask (A, F, beta, kstart, kend, mask, RLinkUp, L, Common) ; break ; } } return (ok) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Makefile0000644000175000017500000000300411674452555020046 0ustar sonnesonne#------------------------------------------------------------------------------- # CHOLMOD Makefile #------------------------------------------------------------------------------- # Note: If you do not have METIS, or do not wish to use it in CHOLMOD, you must # compile CHOLMOD with the -DNPARTITION flag. See ../UFconfig/UFconfig.mk. default: all include ../UFconfig/UFconfig.mk # Compile the C-callable libraries and the Demo programs. all: ( cd Lib ; $(MAKE) ) ( cd Demo ; $(MAKE) ) # Compile the C-callable libraries only. library: ( cd Lib ; $(MAKE) ) # Remove all files not in the original distribution purge: ( cd MATLAB ; $(MAKE) purge ) ( cd Tcov ; $(MAKE) purge ) ( cd Lib ; $(MAKE) purge ) ( cd Valgrind ; $(MAKE) dopurge ) ( cd Demo ; $(MAKE) purge ) ( cd Doc ; $(MAKE) purge ) # Remove all files not in the original distribution, except keep the # compiled libraries. clean: ( cd MATLAB ; $(MAKE) clean ) ( cd Tcov ; $(MAKE) clean ) ( cd Lib ; $(MAKE) clean ) ( cd Valgrind ; $(MAKE) clean ) ( cd Demo ; $(MAKE) clean ) distclean: purge ccode: all # Compile the MATLAB mexFunctions (you can also use cholmod_make.m in MATLAB) mex: ( cd MATLAB ; $(MAKE) ) # Run the test coverage suite. Takes about 40 minutes on a 3.2GHz Pentium. # Requires Linux (gcc, gcov). cov: ( cd Tcov ; $(MAKE) go ) # Run the test coverage suite using Valgrind. This takes a *** long *** time. valgrind: ( cd Valgrind ; $(MAKE) ) # Compile the C-callable libraries and the Demo programs. demo: ( cd Demo ; $(MAKE) ) cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/README.txt0000644000175000017500000001025311674452555020110 0ustar sonnesonneCHOLMOD: a sparse CHOLesky MODification package Version 1.7.1, March 24, 2009. Copyright (c) 2005-2009. ----------------------------------------------- CHOLMOD is a set of routines for factorizing sparse symmetric positive definite matrices of the form A or AA', updating/downdating a sparse Cholesky factorization, solving linear systems, updating/downdating the solution to the triangular system Lx=b, and many other sparse matrix functions for both symmetric and unsymmetric matrices. Its supernodal Cholesky factorization relies on LAPACK and the Level-3 BLAS, and obtains a substantial fraction of the peak performance of the BLAS. Both real and complex matrices are supported. CHOLMOD is written in ANSI/ISO C, with both C and MATLAB interfaces. This code works on Microsoft Windows and many versions of Unix and Linux. Some Modules of CHOLMOD are copyrighted by the University of Florida (the Core and Partition Modules). The rest are copyrighted by the authors: Timothy A. Davis (all of them), and William W. Hager (the Modify Module). CHOLMOD relies on several other packages: AMD, CAMD, COLAMD, CCOLAMD, UFconfig, METIS, the BLAS, and LAPACK. All but METIS, the BLAS, and LAPACK are part of SuiteSparse. AMD is authored by T. Davis, Iain Duff, and Patrick Amestoy. COLAMD is authored by T. Davis and Stefan Larimore, with algorithmic design in collaboration with John Gilbert and Esmond Ng. CCOLAMD is authored by T. Davis and Siva Rajamanickam. CAMD is authored by T. Davis and Y. Chen. LAPACK and the BLAS are authored by Jack Dongarra and many others. LAPACK is available at http://www.netlib.org/lapack METIS is authored by George Karypis, Univ. of Minnesota. Its use in CHOLMOD is optional. See http://www-users.cs.umn.edu/~karypis/metis. Place a copy of the metis-4.0 directory in the same directory that contains the CHOLMOD, AMD, COLAMD, and CCOLAMD directories prior to compiling with "make". If you do not wish to use METIS, you must edit UFconfig and change the line: CHOLMOD_CONFIG = to CHOLMOD_CONFIG = -DNPARTITION The CHOLMOD, AMD, COLAMD, CCOLAMD, and UFconfig directories must all reside in a common parent directory. To compile all these libraries, edit UFconfig/UFconfig.mk to reflect your environment (C compiler, location of the BLAS, and so on) and then type "make" in either the CHOLMOD directory or in the parent directory of CHOLMOD. See each package for more details on how to compile them. For use in MATLAB (on any system, including Windows): start MATLAB, cd to the CHOLMOD/MATLAB directory, and type cholmod_make in the MATLAB Command Window. This is the best way to compile CHOLMOD for MATLAB; it provides a workaround for a METIS design feature, in which METIS terminates your program (and thus MATLAB) if it runs out of memory. Using cholmod_make also ensures your mexFunctions are compiled with -fexceptions, so that exceptions are handled properly (when hitting control-C in the MATLAB command window, for example). If you have MATLAB 7.2 or earlier and use "make mex", you must first edit UFconfig/UFconfig.h to remove the "-largeArrayDims" option from the MEX command (or just use cholmod_make.m inside MATLAB). On the Pentium, do NOT use the Intel MKL BLAS prior to MKL Version 8.0 with CHOLMOD. Older versions (prior to 8.0) have a bug in dgemm when computing A*B'. The bug generates a NaN result, when the inputs are well-defined. Use the Goto BLAS or the MKL v8.0 BLAS instead. The Goto BLAS is faster and more reliable. See http://www.tacc.utexas.edu/~kgoto/ or http://www.cs.utexas.edu/users/flame/goto/. Sadly, the Intel MKL BLAS 7.x is the default for MATLAB 7.0.4. See http://www.mathworks.com/support/bugreports/details.html?rp=252103 for more details. To workaround this problem on Linux, set environment variable BLAS_VERSION to libmkl_p3.so:libguide.so. On Windows, set environment variable BLAS_VERSION to mkl_p3.dll. Better yet, get MATLAB 7sp3 (MATLAB 7.1) or later. Acknowledgements: this work was supported in part by the National Science Foundation (NFS CCR-0203270 and DMS-9803599), and a grant from Sandia National Laboratories (Dept. of Energy) which supported the development of CHOLMOD's Partition Module. cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Check/0000755000175000017500000000000011674452555017426 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Check/License.txt0000644000175000017500000000205711674452555021555 0ustar sonnesonneCHOLMOD/Check Module. Copyright (C) 2005-2006, Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://www.cise.ufl.edu/research/sparse Note that this license is for the CHOLMOD/Check module only. All CHOLMOD modules are licensed separately. -------------------------------------------------------------------------------- This Module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This Module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Check/cholmod_read.c0000644000175000017500000011745411674452555022226 0ustar sonnesonne/* ========================================================================== */ /* === Check/cholmod_read =================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Check Module. Copyright (C) 2005-2006, Timothy A. Davis. * The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Read a sparse matrix in triplet or dense form. A triplet matrix can be * returned as compressed-column sparse matrix. The file format is compatible * with all variations of the Matrix Market "coordinate" and "array" format * (http://www.nist.gov/MatrixMarket). The format supported by these routines * also allow other formats, where the Matrix Market header is optional. * * Although the Matrix Market header is optional, I recommend that users stick * with the strict Matrix Market format. The optional format appears here to * support the reading of symmetric matrices stored with just their upper * triangular parts present, for testing and development of the A->stype > 0 * format in CHOLMOD. That format is not included in the Matrix Market format. * * If the first line of the file starts with %%MatrixMarket, then it is * interpretted as a file in Matrix Market format. This line must have * the following format: * * %%MatrixMarket matrix * * is one of: coordinate or array. The former is a sparse matrix in * triplet form. The latter is a dense matrix in column-major form. * * is one of: real, complex, pattern, or integer. * The functions here convert the "integer" and "pattern" types to real. * * is one of: general, hermitian, symmetric, or skew-symmetric * * The strings are case-insensitive. Only the first character is * significant (or the first two for skew-symmetric). * * is ignored for all matrices; the actual type (real, complex, * or pattern) is inferred from the number of tokens in each line of the * file. For a "coordinate" matrix: 2: pattern, 3: real, 4: complex; for * a dense "array" matrix: 1: real, 2: complex. This is compatible with * the Matrix Market format, since pattern matrices must have two tokens * per line, real matrices must have 3, and complex matrices must have 4. * A storage of "general" implies an stype of zero (see below). * "symmetric" and "hermitian" imply an stype of -1. Skew-symmetric and * complex symmetric matrices are always returned with both upper and lower * triangular parts present, with an stype of zero, since CHOLMOD does not * have a method for representing skew-symmetric and complex symmetric * matrices. Real symmetric and complex Hermitian matrices may optionally * be returned with both parts present. * * Any other lines starting with "%" are treated as comments, and are ignored. * Blank lines are ignored. The Matrix Market header is optional in this * routine (it is not optional in the Matrix Market format). * * Note that complex matrices are always returned in CHOLMOD_COMPLEX format, * not CHOLMOD_ZOMPLEX. * * ----------------------------------------------------------------------------- * Triplet matrices: * ----------------------------------------------------------------------------- * * The first data line of a triplet matrix contains 3 or 4 integers: * * nrow ncol nnz stype * * where stype is optional (stype does not appear in the Matrix Market format). * The matrix is nrow-by-ncol. The following nnz lines (excluding comments * and blank lines) each contain a single entry. Duplicates are permitted, * and are summed in the output matrix. * * The stype is first derived from the Matrix Market header. If the stype * appears as the fourth integer in the first data line, it is determined from * that line. * * If stype is present, it denotes the storage format for the matrix. * stype = 0 denotes an unsymmetric matrix (same as Matrix Market "general"). * stype = -1 denotes a real symmetric or complex Hermitian matrix whose lower * triangular entries are stored. Entries may be present in the upper * triangular part, but these are ignored (same as Matrix Market * "real symmetric" and "complex Hermitian"). * stype = 1 denotes a real symmetric or complex Hermitian matrix whose upper * triangular entries are stored. Entries may be present in the lower * triangular part, but these are ignored. This option is not present * in the Matrix Market format. * * If stype is not present (no Matrix Market header and not in the first data * line) it is inferred from the rest of the data. If the matrix is * rectangular, or has entries in both the upper and lower triangular parts, * then it is assumed to be unsymmetric (stype=0). If only entries in the * lower triangular part are present, the matrix is assumed to have stype = -1. * If only entries in the upper triangular part are present, the matrix is * assumed to have stype = 1. * * After the first data line (with nrow, ncol, nnz, and optionally stype), * each nonzero consists of one line with 2, 3, or 4 entries. All lines must * have the same number of entries. The first two entries are the row and * column indices of the nonzero. If 3 entries are present, the 3rd entry is * the numerical value, and the matrix is real. If 4 entries are present, * the 3rd and 4th entries in the line are the real and imaginary parts of * a complex value. * * The matrix can be either 0-based or 1-based. It is first assumed to be * one-based (all matrices in the Matrix Market are one-based), with row indices * in the range 1 to ncol and column indices in the range 1 to nrow. If a row * or column index of zero is found, the matrix is assumed to be zero-based * (with row indices in the range 0 to ncol-1 and column indices in the range 0 * to nrow-1). * * If Common->prefer_binary is set to its default value of FALSE, then * for symmetric pattern-only matrices, the kth diagonal (if present) is set to * one plus the degree of the row/column k, and the off-diagonal entries are set * to -1. A symmetric pattern-only matrix with a zero-free diagonal is thus * converted into a symmetric positive definite matrix. All entries are set to * one for an unsymmetric pattern-only matrix. This differs from the * Matrix Market format (A = mmread ('file') returns a binary pattern for A for * symmetric pattern-only matrices). If Common->prefer_binary is TRUE, then * this function returns a binary matrix (just like mmread('file')). * * ----------------------------------------------------------------------------- * Dense matrices: * ----------------------------------------------------------------------------- * * A dense matrix is specified by the Matrix Market "array" format. The * Matrix Market header is optional; if not present, the matrix is assumed to * be in the Matrix Market "general" format. The first data line contains just * two integers: * * nrow ncol * * The can be real, integer, or complex (not pattern). These functions * convert an integer type to real. The entries in the matrix are stored in * column-major format, with one line per entry. Two entries are present in * each line for complex matrices, one for real and integer matrices. In * rectangular and unsymmetric matrices, all entries are present. For real * symmetric or complex Hermitian matrices, only entries in the lower triangular * part appear. For skew-symmetric matrices, only entries in the strictly * lower triangular part appear. * * Since CHOLMOD does not have a data structure for presenting dense symmetric/ * Hermitian matrices, these functions always return a dense matrix in its * general form, with both upper and lower parts present. */ #ifndef NCHECK #include "cholmod_internal.h" #include "cholmod_check.h" #include #include /* The MatrixMarket format specificies a maximum line length of 1024 */ #define MAXLINE 1030 /* ========================================================================== */ /* === get_line ============================================================= */ /* ========================================================================== */ /* Read one line of the file, return TRUE if successful, FALSE if EOF. */ static int get_line (FILE *f, char *buf) { buf [0] = '\0' ; buf [1] = '\0' ; buf [MAXLINE] = '\0' ; return (fgets (buf, MAXLINE, f) != NULL) ; } /* ========================================================================== */ /* === fix_inf ============================================================== */ /* ========================================================================== */ /* Replace huge values with +/- Inf's, since scanf and printf don't deal * with Inf's properly. */ static double fix_inf (double x) { if ((x >= HUGE_DOUBLE) || (x <= -HUGE_DOUBLE)) { /* treat this as +/- Inf (assume 2*x leads to overflow) */ x = 2*x ; } return (x) ; } /* ========================================================================== */ /* === is_blank_line ======================================================== */ /* ========================================================================== */ /* TRUE if s is a blank line or comment, FALSE otherwise */ static int is_blank_line ( char *s ) { int c, k ; if (s [0] == '%') { /* a comment line */ return (TRUE) ; } for (k = 0 ; k <= MAXLINE ; k++) { c = s [k] ; if (c == '\0') { /* end of line */ break ; } if (!isspace (c)) { /* non-space character */ return (FALSE) ; } } return (TRUE) ; } /* ========================================================================== */ /* === read_header ========================================================== */ /* ========================================================================== */ /* Read the header. This consists of zero or more comment lines (blank, or * starting with a "%" in the first column), followed by a single data line * containing up to four numerical values. * * The first line may optionally be a Matrix Market header line, of the form * * %%MatrixMarket matrix * * The first data line of a sparse matrix in triplet form consists of 3 or 4 * numerical values: * * nrow ncol nnz stype * * where stype is optional (it does not appear in the Matrix Market file * format). The first line of a dense matrix in column-major form consists of * two numerical values: * * nrow ncol * * The stype of the matrix is determine either from the Matrix Market header, * or (optionally) from the first data line. stypes of 0 to -3 directly * correlate with the Matrix Market format; stype = 1 is an extension to that * format. * * 999: unknown (will be inferred from the data) * 1: real symmetric or complex Hermitian with upper part stored * (not in the Matrix Market format) * 0: unsymmetric (same as Matrix Market "general") * -1: real symmetric or complex Hermitian, with lower part stored * (Matrix Market "real symmetric" or "complex hermitian") * -2: real or complex skew symmetric (lower part stored, can only be * specified by Matrix Market header) * -3: complex symmetric (lower part stored) * specified by Matrix Market header) * * The Matrix Market header is optional. If stype appears in the first data * line, it is determine by that data line. Otherwise, if the Matrix Market * header appears, stype is determined from that header. If stype does not * appear, it is set to "unknown" (999). */ #define STYPE_UNKNOWN 999 #define STYPE_SYMMETRIC_UPPER 1 #define STYPE_UNSYMMETRIC 0 #define STYPE_SYMMETRIC_LOWER -1 #define STYPE_SKEW_SYMMETRIC -2 #define STYPE_COMPLEX_SYMMETRIC_LOWER -3 static int read_header /* returns TRUE if successful, FALSE on error */ ( /* ---- input ---- */ FILE *f, /* file to read from */ /* ---- output --- */ char *buf, /* a character array of size MAXLINE+1 */ int *mtype, /* CHOLMOD_TRIPLET or CHOLMOD_DENSE */ size_t *nrow, /* number of rows in the matrix */ size_t *ncol, /* number of columns in the matrix */ size_t *nnz, /* number of entries in a triplet matrix (0 for dense)*/ int *stype /* stype (see above) */ ) { char *p ; int first = TRUE, got_mm_header = FALSE, c, c2, is_complex, nitems ; double l1, l2, l3, l4 ; *mtype = CHOLMOD_TRIPLET ; *nrow = 0 ; *ncol = 0 ; *nnz = 0 ; *stype = STYPE_UNKNOWN ; for ( ; ; ) { /* ------------------------------------------------------------------ */ /* get the next line */ /* ------------------------------------------------------------------ */ if (!get_line (f, buf)) { /* premature end of file */ return (FALSE) ; } if (first && (strncmp (buf, "%%MatrixMarket", 14) == 0)) { /* -------------------------------------------------------------- */ /* read a Matrix Market header */ /* -------------------------------------------------------------- */ got_mm_header = TRUE ; p = buf ; /* -------------------------------------------------------------- */ /* get "matrix" token */ /* -------------------------------------------------------------- */ while (*p && !isspace (*p)) p++ ; while (*p && isspace (*p)) p++ ; c = tolower (*p) ; if (c != 'm') { /* bad format */ return (FALSE) ; } /* -------------------------------------------------------------- */ /* get the fmt token ("coord" or "array") */ /* -------------------------------------------------------------- */ while (*p && !isspace (*p)) p++ ; while (*p && isspace (*p)) p++ ; c = tolower (*p) ; if (c == 'c') { *mtype = CHOLMOD_TRIPLET ; } else if (c == 'a') { *mtype = CHOLMOD_DENSE ; } else { /* bad format, neither "coordinate" nor "array" */ return (FALSE) ; } /* -------------------------------------------------------------- */ /* get type token (real, pattern, complex, integer) */ /* -------------------------------------------------------------- */ while (*p && !isspace (*p)) p++ ; while (*p && isspace (*p)) p++ ; c = tolower (*p) ; if (!(c == 'r' || c == 'p' || c == 'c' || c == 'i')) { /* bad format */ return (FALSE) ; } is_complex = (c == 'c') ; /* -------------------------------------------------------------- */ /* get storage token (general, hermitian, symmetric, skew) */ /* -------------------------------------------------------------- */ while (*p && !isspace (*p)) p++ ; while (*p && isspace (*p)) p++ ; c = tolower (*p) ; c2 = tolower (*(p+1)) ; if (c == 'g') { /* "general" storage (unsymmetric matrix), both parts present */ *stype = STYPE_UNSYMMETRIC ; } else if (c == 's' && c2 == 'y') { /* "symmetric" */ if (is_complex) { /* complex symmetric, lower triangular part present */ *stype = STYPE_COMPLEX_SYMMETRIC_LOWER ; } else { /* real symmetric, lower triangular part present */ *stype = STYPE_SYMMETRIC_LOWER ; } } else if (c == 'h') { /* "hermitian" matrix, lower triangular part present */ *stype = STYPE_SYMMETRIC_LOWER ; } else if (c == 's' && c2 == 'k') { /* "skew-symmetric" (real or complex), lower part present */ *stype = STYPE_SKEW_SYMMETRIC ; } else { /* bad format */ return (FALSE) ; } } else if (is_blank_line (buf)) { /* -------------------------------------------------------------- */ /* blank line or comment line */ /* -------------------------------------------------------------- */ continue ; } else { /* -------------------------------------------------------------- */ /* read the first data line and return */ /* -------------------------------------------------------------- */ /* format: nrow ncol nnz stype */ l1 = EMPTY ; l2 = EMPTY ; l3 = 0 ; l4 = 0 ; nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &l3, &l4) ; if (nitems < 2 || nitems > 4 || l1 > Int_max || l2 > Int_max) { /* invalid matrix */ return (FALSE) ; } *nrow = l1 ; *ncol = l2 ; if (nitems == 2) { /* a dense matrix */ if (!got_mm_header) { *mtype = CHOLMOD_DENSE ; *stype = STYPE_UNSYMMETRIC ; } } if (nitems == 3 || nitems == 4) { /* a sparse triplet matrix */ *nnz = l3 ; if (!got_mm_header) { *mtype = CHOLMOD_TRIPLET ; } } if (nitems == 4) { /* an stype specified here can only be 1, 0, or -1 */ if (l4 < 0) { *stype = STYPE_SYMMETRIC_LOWER ; } else if (l4 > 0) { *stype = STYPE_SYMMETRIC_UPPER ; } else { *stype = STYPE_UNSYMMETRIC ; } } if (*nrow != *ncol) { /* a rectangular matrix must be unsymmetric */ *stype = STYPE_UNSYMMETRIC ; } return (TRUE) ; } first = FALSE ; } } /* ========================================================================== */ /* === read_triplet ========================================================= */ /* ========================================================================== */ /* Header has already been read in, including first line (nrow ncol nnz stype). * Read the triplets. */ static cholmod_triplet *read_triplet ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ size_t nrow, /* number of rows */ size_t ncol, /* number of columns */ size_t nnz, /* number of triplets in file to read */ int stype, /* stype from header, or "unknown" */ int prefer_unsym, /* if TRUE, always return T->stype of zero */ /* ---- workspace */ char *buf, /* of size MAXLINE+1 */ /* --------------- */ cholmod_common *Common ) { double x, z ; double *Tx ; Int *Ti, *Tj, *Rdeg, *Cdeg ; cholmod_triplet *T ; double l1, l2 ; Int nitems, xtype, unknown, k, nshould, is_lower, is_upper, one_based, i, j, imax, jmax, skew_symmetric, p, complex_symmetric ; size_t s, nnz2, extra ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* quick return for empty matrix */ /* ---------------------------------------------------------------------- */ if (nrow == 0 || ncol == 0 || nnz == 0) { /* return an empty matrix */ return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, CHOLMOD_REAL, Common)) ; } /* ---------------------------------------------------------------------- */ /* special stype cases: unknown, skew symmetric, and complex symmetric */ /* ---------------------------------------------------------------------- */ unknown = (stype == STYPE_UNKNOWN) ; skew_symmetric = (stype == STYPE_SKEW_SYMMETRIC) ; complex_symmetric = (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) ; extra = 0 ; if (stype < STYPE_SYMMETRIC_LOWER || (prefer_unsym && stype != STYPE_UNSYMMETRIC)) { /* 999: unknown might be converted to unsymmetric */ /* 1: symmetric upper converted to unsym. if prefer_unsym is TRUE */ /* -1: symmetric lower converted to unsym. if prefer_unsym is TRUE */ /* -2: real or complex skew symmetric converted to unsymmetric */ /* -3: complex symmetric converted to unsymmetric */ stype = STYPE_UNSYMMETRIC ; extra = nnz ; } nnz2 = CHOLMOD(add_size_t) (nnz, extra, &ok) ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* s = nrow + ncol */ s = CHOLMOD(add_size_t) (nrow, ncol, &ok) ; if (!ok || nrow > Int_max || ncol > Int_max || nnz > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; Rdeg = Common->Iwork ; /* size nrow */ Cdeg = Rdeg + nrow ; /* size ncol */ /* ---------------------------------------------------------------------- */ /* read the triplets */ /* ---------------------------------------------------------------------- */ is_lower = TRUE ; is_upper = TRUE ; one_based = TRUE ; imax = 0 ; jmax = 0 ; Tx = NULL ; Ti = NULL ; Tj = NULL ; xtype = 999 ; nshould = 0 ; for (k = 0 ; k < (Int) nnz ; k++) { /* ------------------------------------------------------------------ */ /* get the next triplet, skipping blank lines and comment lines */ /* ------------------------------------------------------------------ */ l1 = EMPTY ; l2 = EMPTY ; x = 0 ; z = 0 ; for ( ; ; ) { if (!get_line (f, buf)) { /* premature end of file - not enough triplets read in */ ERROR (CHOLMOD_INVALID, "premature EOF") ; return (NULL) ; } if (is_blank_line (buf)) { /* blank line or comment */ continue ; } nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &x, &z) ; x = fix_inf (x) ; z = fix_inf (z) ; break ; } nitems = (nitems == EOF) ? 0 : nitems ; i = l1 ; j = l2 ; /* ------------------------------------------------------------------ */ /* for first triplet: determine type and allocate triplet matrix */ /* ------------------------------------------------------------------ */ if (k == 0) { if (nitems < 2 || nitems > 4) { /* invalid matrix */ ERROR (CHOLMOD_INVALID, "invalid format") ; return (NULL) ; } else if (nitems == 2) { /* this will be converted into a real matrix later */ xtype = CHOLMOD_PATTERN ; } else if (nitems == 3) { xtype = CHOLMOD_REAL ; } else if (nitems == 4) { xtype = CHOLMOD_COMPLEX ; } /* the rest of the lines should have the same number of entries */ nshould = nitems ; /* allocate triplet matrix */ T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz2, stype, (xtype == CHOLMOD_PATTERN ? CHOLMOD_REAL : xtype), Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } Ti = T->i ; Tj = T->j ; Tx = T->x ; T->nnz = nnz ; } /* ------------------------------------------------------------------ */ /* save the entry in the triplet matrix */ /* ------------------------------------------------------------------ */ if (nitems != nshould || i < 0 || j < 0) { /* wrong format, premature end-of-file, or negative indices */ CHOLMOD(free_triplet) (&T, Common) ; ERROR (CHOLMOD_INVALID, "invalid matrix file") ; return (NULL) ; } Ti [k] = i ; Tj [k] = j ; if (i < j) { /* this entry is in the upper triangular part */ is_lower = FALSE ; } if (i > j) { /* this entry is in the lower triangular part */ is_upper = FALSE ; } if (xtype == CHOLMOD_REAL) { Tx [k] = x ; } else if (xtype == CHOLMOD_COMPLEX) { Tx [2*k ] = x ; /* real part */ Tx [2*k+1] = z ; /* imaginary part */ } if (i == 0 || j == 0) { one_based = FALSE ; } imax = MAX (i, imax) ; jmax = MAX (j, jmax) ; } /* ---------------------------------------------------------------------- */ /* convert to zero-based */ /* ---------------------------------------------------------------------- */ if (one_based) { /* input matrix is one-based; convert matrix to zero-based */ for (k = 0 ; k < (Int) nnz ; k++) { Ti [k]-- ; Tj [k]-- ; } } if (one_based ? (imax > (Int) nrow || jmax > (Int) ncol) : (imax >= (Int) nrow || jmax >= (Int) ncol)) { /* indices out of range */ CHOLMOD(free_triplet) (&T, Common) ; ERROR (CHOLMOD_INVALID, "indices out of range") ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* determine the stype, if not yet known */ /* ---------------------------------------------------------------------- */ if (unknown) { if (is_lower && is_upper) { /* diagonal matrix, symmetric with upper part present */ stype = STYPE_SYMMETRIC_UPPER ; } else if (is_lower && !is_upper) { /* symmetric, lower triangular part present */ stype = STYPE_SYMMETRIC_LOWER ; } else if (!is_lower && is_upper) { /* symmetric, upper triangular part present */ stype = STYPE_SYMMETRIC_UPPER ; } else { /* unsymmetric */ stype = STYPE_UNSYMMETRIC ; extra = 0 ; } } /* ---------------------------------------------------------------------- */ /* add the remainder of symmetric, skew-symmetric or Hermitian matrices */ /* ---------------------------------------------------------------------- */ /* note that this step is not done for real symmetric or complex Hermitian * matrices, unless prefer_unsym is TRUE */ if (extra > 0) { p = nnz ; for (k = 0 ; k < (Int) nnz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i != j) { Ti [p] = j ; Tj [p] = i ; if (xtype == CHOLMOD_REAL) { if (skew_symmetric) { Tx [p] = -Tx [k] ; } else { Tx [p] = Tx [k] ; } } else if (xtype == CHOLMOD_COMPLEX) { if (skew_symmetric) { Tx [2*p ] = -Tx [2*k ] ; Tx [2*p+1] = -Tx [2*k+1] ; } else if (complex_symmetric) { Tx [2*p ] = Tx [2*k ] ; Tx [2*p+1] = Tx [2*k+1] ; } else /* Hermitian */ { Tx [2*p ] = Tx [2*k ] ; Tx [2*p+1] = -Tx [2*k+1] ; } } p++ ; } } T->nnz = p ; nnz = p ; } T->stype = stype ; /* ---------------------------------------------------------------------- */ /* create values for a pattern-only matrix */ /* ---------------------------------------------------------------------- */ if (xtype == CHOLMOD_PATTERN) { if (stype == STYPE_UNSYMMETRIC || Common->prefer_binary) { /* unsymmetric case, or binary case */ for (k = 0 ; k < (Int) nnz ; k++) { Tx [k] = 1 ; } } else { /* compute the row and columm degrees (excluding the diagonal) */ for (i = 0 ; i < (Int) nrow ; i++) { Rdeg [i] = 0 ; } for (j = 0 ; j < (Int) ncol ; j++) { Cdeg [j] = 0 ; } for (k = 0 ; k < (Int) nnz ; k++) { i = Ti [k] ; j = Tj [k] ; if ((stype < 0 && i > j) || (stype > 0 && i < j)) { /* both a(i,j) and a(j,i) appear in the matrix */ Rdeg [i]++ ; Cdeg [j]++ ; Rdeg [j]++ ; Cdeg [i]++ ; } } /* assign the numerical values */ for (k = 0 ; k < (Int) nnz ; k++) { i = Ti [k] ; j = Tj [k] ; Tx [k] = (i == j) ? (1 + MAX (Rdeg [i], Cdeg [j])) : (-1) ; } } } /* ---------------------------------------------------------------------- */ /* return the new triplet matrix */ /* ---------------------------------------------------------------------- */ return (T) ; } /* ========================================================================== */ /* === read_dense =========================================================== */ /* ========================================================================== */ /* Header has already been read in, including first line (nrow ncol). * Read a dense matrix. */ static cholmod_dense *read_dense ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ size_t nrow, /* number of rows */ size_t ncol, /* number of columns */ int stype, /* stype from header */ /* ---- workspace */ char *buf, /* of size MAXLINE+1 */ /* --------------- */ cholmod_common *Common ) { double x, z ; double *Xx = NULL ; cholmod_dense *X ; Int nitems, xtype = -1, nshould = 0, i, j, k, kup, first ; /* ---------------------------------------------------------------------- */ /* quick return for empty matrix */ /* ---------------------------------------------------------------------- */ if (nrow == 0 || ncol == 0) { /* return an empty dense matrix */ return (CHOLMOD(zeros) (nrow, ncol, CHOLMOD_REAL, Common)) ; } /* ---------------------------------------------------------------------- */ /* read the entries */ /* ---------------------------------------------------------------------- */ first = TRUE ; for (j = 0 ; j < (Int) ncol ; j++) { /* ------------------------------------------------------------------ */ /* get the row index of the first entry in the file for column j */ /* ------------------------------------------------------------------ */ if (stype == STYPE_UNSYMMETRIC) { i = 0 ; } else if (stype == STYPE_SKEW_SYMMETRIC) { i = j+1 ; } else /* real symmetric or complex Hermitian lower */ { i = j ; } /* ------------------------------------------------------------------ */ /* get column j */ /* ------------------------------------------------------------------ */ for ( ; i < (Int) nrow ; i++) { /* -------------------------------------------------------------- */ /* get the next entry, skipping blank lines and comment lines */ /* -------------------------------------------------------------- */ x = 0 ; z = 0 ; for ( ; ; ) { if (!get_line (f, buf)) { /* premature end of file - not enough entries read in */ ERROR (CHOLMOD_INVALID, "premature EOF") ; return (NULL) ; } if (is_blank_line (buf)) { /* blank line or comment */ continue ; } nitems = sscanf (buf, "%lg %lg\n", &x, &z) ; x = fix_inf (x) ; z = fix_inf (z) ; break ; } nitems = (nitems == EOF) ? 0 : nitems ; /* -------------------------------------------------------------- */ /* for first entry: determine type and allocate dense matrix */ /* -------------------------------------------------------------- */ if (first) { first = FALSE ; if (nitems < 1 || nitems > 2) { /* invalid matrix */ ERROR (CHOLMOD_INVALID, "invalid format") ; return (NULL) ; } else if (nitems == 1) { /* a real matrix */ xtype = CHOLMOD_REAL ; } else if (nitems == 2) { /* a complex matrix */ xtype = CHOLMOD_COMPLEX ; } /* the rest of the lines should have same number of entries */ nshould = nitems ; /* allocate the result */ X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } Xx = X->x ; } /* -------------------------------------------------------------- */ /* save the entry in the dense matrix */ /* -------------------------------------------------------------- */ if (nitems != nshould) { /* wrong format or premature end-of-file */ CHOLMOD(free_dense) (&X, Common) ; ERROR (CHOLMOD_INVALID, "invalid matrix file") ; return (NULL) ; } k = i + j*nrow ; kup = j + i*nrow ; if (xtype == CHOLMOD_REAL) { /* real matrix */ Xx [k] = x ; if (k != kup) { if (stype == STYPE_SYMMETRIC_LOWER) { /* real symmetric matrix */ Xx [kup] = x ; } else if (stype == STYPE_SKEW_SYMMETRIC) { /* real skew symmetric matrix */ Xx [kup] = -x ; } } } else if (xtype == CHOLMOD_COMPLEX) { Xx [2*k ] = x ; /* real part */ Xx [2*k+1] = z ; /* imaginary part */ if (k != kup) { if (stype == STYPE_SYMMETRIC_LOWER) { /* complex Hermitian */ Xx [2*kup ] = x ; /* real part */ Xx [2*kup+1] = -z ; /* imaginary part */ } else if (stype == STYPE_SKEW_SYMMETRIC) { /* complex skew symmetric */ Xx [2*kup ] = -x ; /* real part */ Xx [2*kup+1] = -z ; /* imaginary part */ } if (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) { /* complex symmetric */ Xx [2*kup ] = x ; /* real part */ Xx [2*kup+1] = z ; /* imaginary part */ } } } } } /* ---------------------------------------------------------------------- */ /* return the new dense matrix */ /* ---------------------------------------------------------------------- */ return (X) ; } /* ========================================================================== */ /* === cholmod_read_triplet ================================================= */ /* ========================================================================== */ /* Read in a triplet matrix from a file. */ cholmod_triplet *CHOLMOD(read_triplet) ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ /* --------------- */ cholmod_common *Common ) { char buf [MAXLINE+1] ; size_t nrow, ncol, nnz ; int stype, mtype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* read the header and first data line */ /* ---------------------------------------------------------------------- */ if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) || mtype != CHOLMOD_TRIPLET) { /* invalid matrix - this function can only read in a triplet matrix */ ERROR (CHOLMOD_INVALID, "invalid format") ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* read the triplet matrix */ /* ---------------------------------------------------------------------- */ return (read_triplet (f, nrow, ncol, nnz, stype, FALSE, buf, Common)) ; } /* ========================================================================== */ /* === cholmod_read_sparse ================================================== */ /* ========================================================================== */ /* Read a sparse matrix from a file. See cholmod_read_triplet for a discussion * of the file format. * * If Common->prefer_upper is TRUE (the default case), a symmetric matrix is * returned stored in upper-triangular form (A->stype == 1). */ cholmod_sparse *CHOLMOD(read_sparse) ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *A, *A2 ; cholmod_triplet *T ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* convert to a sparse matrix in compressed-column form */ /* ---------------------------------------------------------------------- */ T = CHOLMOD(read_triplet) (f, Common) ; A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ; CHOLMOD(free_triplet) (&T, Common) ; if (Common->prefer_upper && A != NULL && A->stype == -1) { /* A=A' */ A2 = CHOLMOD(transpose) (A, 2, Common) ; CHOLMOD(free_sparse) (&A, Common) ; A = A2 ; } return (A) ; } /* ========================================================================== */ /* === cholmod_read_dense =================================================== */ /* ========================================================================== */ /* Read a dense matrix from a file. */ cholmod_dense *CHOLMOD(read_dense) ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ /* --------------- */ cholmod_common *Common ) { char buf [MAXLINE+1] ; size_t nrow, ncol, nnz ; int stype, mtype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* read the header and first data line */ /* ---------------------------------------------------------------------- */ if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) || mtype != CHOLMOD_DENSE) { /* invalid matrix - this function can only read in a dense matrix */ ERROR (CHOLMOD_INVALID, "invalid format") ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* read the dense matrix */ /* ---------------------------------------------------------------------- */ return (read_dense (f, nrow, ncol, stype, buf, Common)) ; } /* ========================================================================== */ /* === cholmod_read_matrix ================================================== */ /* ========================================================================== */ /* Read a triplet matrix, sparse matrix or a dense matrix from a file. Returns * a void pointer to either a cholmod_triplet, cholmod_sparse, or cholmod_dense * object. The type of object is passed back to the caller as the mtype * argument. */ void *CHOLMOD(read_matrix) ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ int prefer, /* If 0, a sparse matrix is always return as a * cholmod_triplet form. It can have any stype * (symmetric-lower, unsymmetric, or * symmetric-upper). * If 1, a sparse matrix is returned as an unsymmetric * cholmod_sparse form (A->stype == 0), with both * upper and lower triangular parts present. * This is what the MATLAB mread mexFunction does, * since MATLAB does not have an stype. * If 2, a sparse matrix is returned with an stype of 0 * or 1 (unsymmetric, or symmetric with upper part * stored). * This argument has no effect for dense matrices. */ /* ---- output---- */ int *mtype, /* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */ /* --------------- */ cholmod_common *Common ) { void *G = NULL ; cholmod_sparse *A, *A2 ; cholmod_triplet *T ; char buf [MAXLINE+1] ; size_t nrow, ncol, nnz ; int stype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (f, NULL) ; RETURN_IF_NULL (mtype, NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* read the header to determine the mtype */ /* ---------------------------------------------------------------------- */ if (!read_header (f, buf, mtype, &nrow, &ncol, &nnz, &stype)) { /* invalid matrix */ ERROR (CHOLMOD_INVALID, "invalid format") ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* read a matrix */ /* ---------------------------------------------------------------------- */ if (*mtype == CHOLMOD_TRIPLET) { /* read in the triplet matrix, converting to unsymmetric format if * prefer == 1 */ T = read_triplet (f, nrow, ncol, nnz, stype, prefer == 1, buf, Common) ; if (prefer == 0) { /* return matrix in its original triplet form */ G = T ; } else { /* return matrix in a compressed-column form */ A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ; CHOLMOD(free_triplet) (&T, Common) ; if (A != NULL && prefer == 2 && A->stype == -1) { /* convert A from symmetric-lower to symmetric-upper */ A2 = CHOLMOD(transpose) (A, 2, Common) ; CHOLMOD(free_sparse) (&A, Common) ; A = A2 ; } *mtype = CHOLMOD_SPARSE ; G = A ; } } else if (*mtype == CHOLMOD_DENSE) { /* return a dense matrix */ G = read_dense (f, nrow, ncol, stype, buf, Common) ; } return (G) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Check/cholmod_check.c0000644000175000017500000017530011674452555022362 0ustar sonnesonne/* ========================================================================== */ /* === Check/cholmod_check ================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Check Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Routines to check and print the contents of the 5 CHOLMOD objects: * * No CHOLMOD routine calls the check or print routines. If a user wants to * check CHOLMOD's input parameters, a separate call to the appropriate check * routine should be used before calling other CHOLMOD routines. * * cholmod_check_common check statistics and workspace in Common * cholmod_check_sparse check sparse matrix in compressed column form * cholmod_check_dense check dense matrix * cholmod_check_factor check factorization * cholmod_check_triplet check sparse matrix in triplet form * * cholmod_print_common print statistics in Common * cholmod_print_sparse print sparse matrix in compressed column form * cholmod_print_dense print dense matrix * cholmod_print_factor print factorization * cholmod_print_triplet print sparse matrix in triplet form * * In addition, this file contains routines to check and print three types of * integer vectors: * * cholmod_check_perm check a permutation of 0:n-1 (no duplicates) * cholmod_check_subset check a subset of 0:n-1 (duplicates OK) * cholmod_check_parent check an elimination tree * * cholmod_print_perm print a permutation * cholmod_print_subset print a subset * cholmod_print_parent print an elimination tree * * Each Common->print level prints the items at or below the given level: * * 0: print nothing; just check the data structures and return TRUE/FALSE * 1: error messages * 2: warning messages * 3: one-line summary of each object printed * 4: short summary of each object (first and last few entries) * 5: entire contents of the object * * No CHOLMOD routine calls these routines, so no printing occurs unless * the user specifically calls a cholmod_print_* routine. Thus, the default * print level is 3. * * Common->precise controls the # of digits printed for numerical entries * (5 if FALSE, 15 if TRUE). * * If Common->print_function is NULL, then no printing occurs. The * cholmod_check_* and cholmod_print_* routines still check their inputs and * return TRUE/FALSE if the object is valid or not. * * This file also includes debugging routines that are enabled only when * NDEBUG is defined in cholmod_internal.h (cholmod_dump_*). */ #ifndef NCHECK #include "cholmod_internal.h" #include "cholmod_check.h" /* ========================================================================== */ /* === printing definitions ================================================= */ /* ========================================================================== */ #ifdef LONG #define I8 "%8ld" #define I_8 "%-8ld" #else #define I8 "%8d" #define I_8 "%-8d" #endif #define PR(i,format,arg) \ { \ if (print >= i && Common->print_function != NULL) \ { \ (Common->print_function) (format, arg) ; \ } \ } #define P1(format,arg) PR(1,format,arg) #define P2(format,arg) PR(2,format,arg) #define P3(format,arg) PR(3,format,arg) #define P4(format,arg) PR(4,format,arg) #define ERR(msg) \ { \ P1 ("\nCHOLMOD ERROR: %s: ", type) ; \ if (name != NULL) \ { \ P1 ("%s", name) ; \ } \ P1 (": %s\n", msg) ; \ ERROR (CHOLMOD_INVALID, "invalid") ; \ return (FALSE) ; \ } /* print a numerical value */ #define PRINTVALUE(value) \ { \ if (Common->precise) \ { \ P4 (" %23.15e", value) ; \ } \ else \ { \ P4 (" %.5g", value) ; \ } \ } /* start printing */ #define ETC_START(count,limit) \ { \ count = (init_print == 4) ? (limit) : (-1) ; \ } /* re-enable printing if condition is met */ #define ETC_ENABLE(condition,count,limit) \ { \ if ((condition) && init_print == 4) \ { \ count = limit ; \ print = 4 ; \ } \ } /* turn off printing if limit is reached */ #define ETC_DISABLE(count) \ { \ if ((count >= 0) && (count-- == 0) && print == 4) \ { \ P4 ("%s", " ...\n") ; \ print = 3 ; \ } \ } /* re-enable printing, or turn if off after limit is reached */ #define ETC(condition,count,limit) \ { \ ETC_ENABLE (condition, count, limit) ; \ ETC_DISABLE (count) ; \ } #define BOOLSTR(x) ((x) ? "true " : "false") /* ========================================================================== */ /* === print_value ========================================================== */ /* ========================================================================== */ static void print_value ( Int print, Int xtype, double *Xx, double *Xz, Int p, cholmod_common *Common) { if (xtype == CHOLMOD_REAL) { PRINTVALUE (Xx [p]) ; } else if (xtype == CHOLMOD_COMPLEX) { P4 ("%s", "(") ; PRINTVALUE (Xx [2*p ]) ; P4 ("%s", " , ") ; PRINTVALUE (Xx [2*p+1]) ; P4 ("%s", ")") ; } else if (xtype == CHOLMOD_ZOMPLEX) { P4 ("%s", "(") ; PRINTVALUE (Xx [p]) ; P4 ("%s", " , ") ; PRINTVALUE (Xz [p]) ; P4 ("%s", ")") ; } } /* ========================================================================== */ /* === cholmod_check_common ================================================= */ /* ========================================================================== */ /* Print and verify the contents of Common */ static int check_common ( Int print, const char *name, cholmod_common *Common ) { double fl, lnz ; double *Xwork ; Int *Flag, *Head ; UF_long mark ; Int i, nrow, nmethods, ordering, xworksize, amd_backup, init_print ; const char *type = "common" ; /* ---------------------------------------------------------------------- */ /* print control parameters and statistics */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; init_print = print ; P2 ("%s", "\n") ; P1 ("CHOLMOD version %d", CHOLMOD_MAIN_VERSION) ; P1 (".%d", CHOLMOD_SUB_VERSION) ; P1 (".%d", CHOLMOD_SUBSUB_VERSION) ; P1 (", %s: ", CHOLMOD_DATE) ; if (name != NULL) { P1 ("%s: ", name) ; } switch (Common->status) { case CHOLMOD_OK: P1 ("%s", "status: OK\n") ; break ; case CHOLMOD_OUT_OF_MEMORY: P1 ("%s", "status: ERROR, out of memory\n") ; break ; case CHOLMOD_INVALID: P1 ("%s", "status: ERROR, invalid parameter\n") ; break ; case CHOLMOD_TOO_LARGE: P1 ("%s", "status: ERROR, problem too large\n") ; break ; case CHOLMOD_NOT_INSTALLED: P1 ("%s", "status: ERROR, method not installed\n") ; break ; case CHOLMOD_NOT_POSDEF: P1 ("%s", "status: warning, matrix not positive definite\n") ; break ; case CHOLMOD_DSMALL: P1 ("%s", "status: warning, diagonal entry has tiny abs. value\n") ; break ; default: ERR ("unknown status") ; } P2 (" Architecture: %s\n", CHOLMOD_ARCHITECTURE) ; P3 (" sizeof(int): %d\n", (int) sizeof (int)) ; P3 (" sizeof(UF_long): %d\n", (int) sizeof (UF_long)) ; P3 (" sizeof(void *): %d\n", (int) sizeof (void *)) ; P3 (" sizeof(double): %d\n", (int) sizeof (double)) ; P3 (" sizeof(Int): %d (CHOLMOD's basic integer)\n", (int) sizeof (Int)) ; P3 (" sizeof(BLAS_INT): %d (integer used in the BLAS)\n", (int) sizeof (BLAS_INT)) ; if (Common->fl != EMPTY) { P2 ("%s", " Results from most recent analysis:\n") ; P2 (" Cholesky flop count: %.5g\n", Common->fl) ; P2 (" Nonzeros in L: %.5g\n", Common->lnz) ; } if (Common->modfl != EMPTY) { P2 (" Update/downdate flop count: %.5g\n", Common->modfl) ; } P2 (" memory blocks in use: %8.0f\n", (double) (Common->malloc_count)) ; P2 (" memory in use (MB): %8.1f\n", (double) (Common->memory_inuse) / 1048576.) ; P2 (" peak memory usage (MB): %8.1f\n", (double) (Common->memory_usage) / 1048576.) ; /* ---------------------------------------------------------------------- */ /* primary control parameters and related ordering statistics */ /* ---------------------------------------------------------------------- */ P3 (" maxrank: update/downdate rank: "ID"\n", (Int) CHOLMOD(maxrank) (0, Common)) ; P3 (" supernodal control: %d", Common->supernodal) ; P3 (" %g ", Common->supernodal_switch) ; if (Common->supernodal <= CHOLMOD_SIMPLICIAL) { P3 ("%s", "(always do simplicial)\n") ; } else if (Common->supernodal == CHOLMOD_AUTO) { P3 ("(supernodal if flops/lnz >= %g)\n", Common->supernodal_switch) ; } else { P3 ("%s", "(always do supernodal)\n") ; } nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ; nmethods = MAX (0, nmethods) ; if (nmethods > 0) { P3 ("%s", " nmethods: number of ordering methods to try: ") ; P3 (""ID"\n", nmethods) ; amd_backup = (nmethods > 1) || (nmethods == 1 && (Common->method [0].ordering == CHOLMOD_METIS || Common->method [0].ordering == CHOLMOD_NESDIS)) ; } else { P3 ("%s", " nmethods=0: default strategy: Try user permutation if " "given. Try AMD.\n") ; #ifndef NPARTITION if (Common->default_nesdis) { P3 ("%s", " Try NESDIS if AMD reports flops/nnz(L) >= 500 and " "nnz(L)/nnz(A) >= 5.\n") ; } else { P3 ("%s", " Try METIS if AMD reports flops/nnz(L) >= 500 and " "nnz(L)/nnz(A) >= 5.\n") ; } #endif P3 ("%s", " Select best ordering tried.\n") ; Common->method [0].ordering = CHOLMOD_GIVEN ; Common->method [1].ordering = CHOLMOD_AMD ; Common->method [2].ordering = (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ; amd_backup = FALSE ; #ifndef NPARTITION nmethods = 3 ; #else nmethods = 2 ; #endif } for (i = 0 ; i < nmethods ; i++) { P3 (" method "ID": ", i) ; ordering = Common->method [i].ordering ; fl = Common->method [i].fl ; lnz = Common->method [i].lnz ; switch (ordering) { case CHOLMOD_NATURAL: P3 ("%s", "natural\n") ; break ; case CHOLMOD_GIVEN: P3 ("%s", "user permutation (if given)\n") ; break ; case CHOLMOD_AMD: P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ; amd_backup = FALSE ; break ; case CHOLMOD_COLAMD: P3 ("%s", "AMD if factorizing A, COLAMD if factorizing AA')\n"); amd_backup = FALSE ; break ; case CHOLMOD_METIS: P3 ("%s", "METIS_NodeND nested dissection\n") ; break ; case CHOLMOD_NESDIS: P3 ("%s", "CHOLMOD nested dissection\n") ; P3 (" nd_small: # nodes in uncut subgraph: "ID"\n", (Int) (Common->method [i].nd_small)) ; P3 (" nd_compress: compress the graph: %s\n", BOOLSTR (Common->method [i].nd_compress)) ; P3 (" nd_camd: use constrained min degree: %s\n", BOOLSTR (Common->method [i].nd_camd)) ; break ; default: P3 (ID, ordering) ; ERR ("unknown ordering method") ; break ; } if (!(ordering == CHOLMOD_NATURAL || ordering == CHOLMOD_GIVEN)) { if (Common->method [i].prune_dense < 0) { P3 (" prune_dense: for pruning dense nodes: %s\n", " none pruned") ; } else { P3 (" prune_dense: for pruning dense nodes: " "%.5g\n", Common->method [i].prune_dense) ; P3 (" a dense node has degree " ">= max(16,(%.5g)*sqrt(n))\n", Common->method [i].prune_dense) ; } } if (ordering == CHOLMOD_COLAMD || ordering == CHOLMOD_NESDIS) { if (Common->method [i].prune_dense2 < 0) { P3 (" prune_dense2: for pruning dense rows for AA':" " %s\n", " none pruned") ; } else { P3 (" prune_dense2: for pruning dense rows for AA':" " %.5g\n", Common->method [i].prune_dense2) ; P3 (" a dense row has degree " ">= max(16,(%.5g)*sqrt(ncol))\n", Common->method [i].prune_dense2) ; } } if (fl != EMPTY) P3 (" flop count: %.5g\n", fl) ; if (lnz != EMPTY) P3 (" nnz(L): %.5g\n", lnz) ; } /* backup AMD results, if any */ if (amd_backup) { P3 ("%s", " backup method: ") ; P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ; fl = Common->method [nmethods].fl ; lnz = Common->method [nmethods].lnz ; if (fl != EMPTY) P3 (" AMD flop count: %.5g\n", fl) ; if (lnz != EMPTY) P3 (" AMD nnz(L): %.5g\n", lnz) ; } /* ---------------------------------------------------------------------- */ /* arcane control parameters */ /* ---------------------------------------------------------------------- */ if (Common->final_asis) { P4 ("%s", " final_asis: TRUE, leave as is\n") ; } else { P4 ("%s", " final_asis: FALSE, convert when done\n") ; if (Common->final_super) { P4 ("%s", " final_super: TRUE, leave in supernodal form\n") ; } else { P4 ("%s", " final_super: FALSE, convert to simplicial form\n") ; } if (Common->final_ll) { P4 ("%s", " final_ll: TRUE, convert to LL' form\n") ; } else { P4 ("%s", " final_ll: FALSE, convert to LDL' form\n") ; } if (Common->final_pack) { P4 ("%s", " final_pack: TRUE, pack when done\n") ; } else { P4 ("%s", " final_pack: FALSE, do not pack when done\n") ; } if (Common->final_monotonic) { P4 ("%s", " final_monotonic: TRUE, ensure L is monotonic\n") ; } else { P4 ("%s", " final_monotonic: FALSE, do not ensure L is monotonic\n") ; } P4 (" final_resymbol: remove zeros from amalgamation: %s\n", BOOLSTR (Common->final_resymbol)) ; } P4 (" dbound: LDL' diagonal threshold: % .5g\n Entries with abs. value" " less than dbound are replaced with +/- dbound.\n", Common->dbound) ; P4 (" grow0: memory reallocation: % .5g\n", Common->grow0) ; P4 (" grow1: memory reallocation: % .5g\n", Common->grow1) ; P4 (" grow2: memory reallocation: %g\n", (double) (Common->grow2)) ; P4 ("%s", " nrelax, zrelax: supernodal amalgamation rule:\n") ; P4 ("%s", " s = # columns in two adjacent supernodes\n") ; P4 ("%s", " z = % of zeros in new supernode if they are merged.\n") ; P4 ("%s", " Two supernodes are merged if") ; P4 (" (s <= %g) or (no new zero entries) or\n", (double) (Common->nrelax [0])) ; P4 (" (s <= %g and ", (double) (Common->nrelax [1])) ; P4 ("z < %.5g%%) or", Common->zrelax [0] * 100) ; P4 (" (s <= %g and ", (double) (Common->nrelax [2])) ; P4 ("z < %.5g%%) or", Common->zrelax [1] * 100) ; P4 (" (z < %.5g%%)\n", Common->zrelax [2] * 100) ; /* ---------------------------------------------------------------------- */ /* check workspace */ /* ---------------------------------------------------------------------- */ mark = Common->mark ; nrow = Common->nrow ; Flag = Common->Flag ; Head = Common->Head ; if (nrow > 0) { if (mark < 0 || Flag == NULL || Head == NULL) { ERR ("workspace corrupted (Flag and/or Head missing)") ; } for (i = 0 ; i < nrow ; i++) { if (Flag [i] >= mark) { PRINT0 (("Flag ["ID"]="ID", mark = %ld\n", i, Flag [i], mark)) ; ERR ("workspace corrupted (Flag)") ; } } for (i = 0 ; i <= nrow ; i++) { if (Head [i] != EMPTY) { PRINT0 (("Head ["ID"] = "ID",\n", i, Head [i])) ; ERR ("workspace corrupted (Head)") ; } } } xworksize = Common->xworksize ; Xwork = Common->Xwork ; if (xworksize > 0) { if (Xwork == NULL) { ERR ("workspace corrupted (Xwork missing)") ; } for (i = 0 ; i < xworksize ; i++) { if (Xwork [i] != 0.) { PRINT0 (("Xwork ["ID"] = %g\n", i, Xwork [i])) ; ERR ("workspace corrupted (Xwork)") ; } } } /* workspace and parameters are valid */ P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } int CHOLMOD(check_common) ( cholmod_common *Common ) { return (check_common (0, NULL, Common)) ; } int CHOLMOD(print_common) ( /* ---- input ---- */ const char *name, /* printed name of Common object */ /* --------------- */ cholmod_common *Common ) { Int print = (Common == NULL) ? 3 : (Common->print) ; return (check_common (print, name, Common)) ; } /* ========================================================================== */ /* === cholmod_check_sparse ================================================= */ /* ========================================================================== */ /* Ensure that a sparse matrix in column-oriented form is valid, and optionally * print it. Returns the number of entries on the diagonal or -1 if error. * * workspace: Iwork (nrow) */ static UF_long check_sparse ( Int *Wi, Int print, const char *name, cholmod_sparse *A, UF_long *nnzdiag, cholmod_common *Common ) { double *Ax, *Az ; Int *Ap, *Ai, *Anz ; Int nrow, ncol, nzmax, sorted, packed, j, p, pend, i, nz, ilast, space, init_print, dnz, count, xtype ; const char *type = "sparse" ; /* ---------------------------------------------------------------------- */ /* print header information */ /* ---------------------------------------------------------------------- */ P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD sparse: ") ; if (name != NULL) { P3 ("%s: ", name) ; } if (A == NULL) { ERR ("null") ; } nrow = A->nrow ; ncol = A->ncol ; nzmax = A->nzmax ; sorted = A->sorted ; packed = A->packed ; xtype = A->xtype ; Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; Anz = A->nz ; nz = CHOLMOD(nnz) (A, Common) ; P3 (" "ID"", nrow) ; P3 ("-by-"ID", ", ncol) ; P3 ("nz "ID",", nz) ; if (A->stype > 0) { P3 ("%s", " upper.") ; } else if (A->stype < 0) { P3 ("%s", " lower.") ; } else { P3 ("%s", " up/lo.") ; } P4 ("\n nzmax "ID", ", nzmax) ; if (nz > nzmax) { ERR ("nzmax too small") ; } if (!sorted) { P4 ("%s", "un") ; } P4 ("%s", "sorted, ") ; if (!packed) { P4 ("%s", "un") ; } P4 ("%s", "packed, ") ; switch (A->itype) { case CHOLMOD_INT: P4 ("%s", "\n scalar types: int, ") ; break ; case CHOLMOD_INTLONG: ERR ("mixed int/UF_long type unsupported") ; case CHOLMOD_LONG: P4 ("%s", "\n scalar types: UF_long, ") ; break ; default: ERR ("unknown itype") ; } switch (A->xtype) { case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; case CHOLMOD_REAL: P4 ("%s", "real") ; break ; case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; default: ERR ("unknown xtype") ; } switch (A->dtype) { case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; case CHOLMOD_SINGLE: ERR ("float unsupported") ; default: ERR ("unknown dtype") ; } if (A->itype != ITYPE || A->dtype != DTYPE) { ERR ("integer and real type must match routine") ; } if (A->stype && nrow != ncol) { ERR ("symmetric but not square") ; } /* check for existence of Ap, Ai, Anz, Ax, and Az arrays */ if (Ap == NULL) { ERR ("p array not present") ; } if (Ai == NULL) { ERR ("i array not present") ; } if (!packed && Anz == NULL) { ERR ("nz array not present") ; } if (xtype != CHOLMOD_PATTERN && Ax == NULL) { ERR ("x array not present") ; } if (xtype == CHOLMOD_ZOMPLEX && Az == NULL) { ERR ("z array not present") ; } /* packed matrices must start at Ap [0] = 0 */ if (packed && Ap [0] != 0) { ERR ("p [0] must be zero") ; } if (packed && (Ap [ncol] < Ap [0] || Ap [ncol] > nzmax)) { ERR ("p [ncol] invalid") ; } /* ---------------------------------------------------------------------- */ /* allocate workspace if needed */ /* ---------------------------------------------------------------------- */ if (!sorted) { if (Wi == NULL) { CHOLMOD(allocate_work) (0, nrow, 0, Common) ; Wi = Common->Iwork ; /* size nrow, (i/i/l) */ } if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } for (i = 0 ; i < nrow ; i++) { Wi [i] = EMPTY ; } } /* ---------------------------------------------------------------------- */ /* check and print each column */ /* ---------------------------------------------------------------------- */ init_print = print ; dnz = 0 ; ETC_START (count, 8) ; for (j = 0 ; j < ncol ; j++) { ETC (j == ncol-1, count, 4) ; p = Ap [j] ; if (packed) { pend = Ap [j+1] ; nz = pend - p ; } else { /* Note that Anz [j] < 0 is treated as zero */ nz = MAX (0, Anz [j]) ; pend = p + nz ; } /* Note that space can be negative if the matrix is non-monotonic */ space = Ap [j+1] - p ; P4 (" col "ID":", j) ; P4 (" nz "ID"", nz) ; P4 (" start "ID"", p) ; P4 (" end "ID"", pend) ; if (!packed) { P4 (" space "ID"", space) ; } P4 ("%s", ":\n") ; if (p < 0 || pend > nzmax) { ERR ("pointer invalid") ; } if (nz < 0 || nz > nrow) { ERR ("nz invalid") ; } ilast = EMPTY ; for ( ; p < pend ; p++) { ETC (j == ncol-1 && p >= pend-4, count, -1) ; i = Ai [p] ; P4 (" "I8":", i) ; print_value (print, xtype, Ax, Az, p, Common) ; if (i == j) { dnz++ ; } if (i < 0 || i >= nrow) { ERR ("row index out of range") ; } if (sorted && i <= ilast) { ERR ("row indices out of order") ; } if (!sorted && Wi [i] == j) { ERR ("duplicate row index") ; } P4 ("%s", "\n") ; ilast = i ; if (!sorted) { Wi [i] = j ; } } } /* matrix is valid */ P4 (" nnz on diagonal: "ID"\n", dnz) ; P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; *nnzdiag = dnz ; return (TRUE) ; } int CHOLMOD(check_sparse) ( /* ---- input ---- */ cholmod_sparse *A, /* sparse matrix to check */ /* --------------- */ cholmod_common *Common ) { UF_long nnzdiag ; RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_sparse (NULL, 0, NULL, A, &nnzdiag, Common)) ; } int CHOLMOD(print_sparse) ( /* ---- input ---- */ cholmod_sparse *A, /* sparse matrix to print */ const char *name, /* printed name of sparse matrix */ /* --------------- */ cholmod_common *Common ) { UF_long nnzdiag ; RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_sparse (NULL, Common->print, name, A, &nnzdiag, Common)) ; } /* ========================================================================== */ /* === cholmod_check_dense ================================================== */ /* ========================================================================== */ /* Ensure a dense matrix is valid, and optionally print it. */ static int check_dense ( Int print, const char *name, cholmod_dense *X, cholmod_common *Common ) { double *Xx, *Xz ; Int i, j, d, nrow, ncol, nzmax, nz, init_print, count, xtype ; const char *type = "dense" ; /* ---------------------------------------------------------------------- */ /* print header information */ /* ---------------------------------------------------------------------- */ P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD dense: ") ; if (name != NULL) { P3 ("%s: ", name) ; } if (X == NULL) { ERR ("null") ; } nrow = X->nrow ; ncol = X->ncol ; nzmax = X->nzmax ; d = X->d ; Xx = X->x ; Xz = X->z ; xtype = X->xtype ; P3 (" "ID"", nrow) ; P3 ("-by-"ID", ", ncol) ; P4 ("\n leading dimension "ID", ", d) ; P4 ("nzmax "ID", ", nzmax) ; if (d * ncol > nzmax) { ERR ("nzmax too small") ; } if (d < nrow) { ERR ("leading dimension must be >= # of rows") ; } if (Xx == NULL) { ERR ("null") ; } switch (X->xtype) { case CHOLMOD_PATTERN: ERR ("pattern unsupported") ; break ; case CHOLMOD_REAL: P4 ("%s", "real") ; break ; case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; default: ERR ("unknown xtype") ; } switch (X->dtype) { case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; case CHOLMOD_SINGLE: ERR ("single unsupported") ; default: ERR ("unknown dtype") ; } /* ---------------------------------------------------------------------- */ /* check and print each entry */ /* ---------------------------------------------------------------------- */ if (print >= 4) { init_print = print ; ETC_START (count, 9) ; nz = nrow * ncol ; for (j = 0 ; j < ncol ; j++) { ETC (j == ncol-1, count, 5) ; P4 (" col "ID":\n", j) ; for (i = 0 ; i < nrow ; i++) { ETC (j == ncol-1 && i >= nrow-4, count, -1) ; P4 (" "I8":", i) ; print_value (print, xtype, Xx, Xz, i+j*d, Common) ; P4 ("%s", "\n") ; } } } /* dense is valid */ P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } int CHOLMOD(check_dense) ( /* ---- input ---- */ cholmod_dense *X, /* dense matrix to check */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_dense (0, NULL, X, Common)) ; } int CHOLMOD(print_dense) ( /* ---- input ---- */ cholmod_dense *X, /* dense matrix to print */ const char *name, /* printed name of dense matrix */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_dense (Common->print, name, X, Common)) ; } /* ========================================================================== */ /* === cholmod_check_subset ================================================= */ /* ========================================================================== */ /* Ensure S (0:len-1) is a subset of 0:n-1. Duplicates are allowed. S may be * NULL. A negative len denotes the set 0:n-1. * * To check the rset and cset for A(rset,cset), where nc and nr are the length * of cset and rset respectively: * * cholmod_check_subset (cset, nc, A->ncol, Common) ; * cholmod_check_subset (rset, nr, A->nrow, Common) ; * * workspace: none */ static int check_subset ( Int *S, UF_long len, size_t n, Int print, const char *name, cholmod_common *Common ) { Int i, k, init_print, count ; const char *type = "subset" ; init_print = print ; if (S == NULL) { /* zero len denotes S = [ ], negative len denotes S = 0:n-1 */ len = (len < 0) ? (-1) : 0 ; } P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD subset: ") ; if (name != NULL) { P3 ("%s: ", name) ; } P3 (" len: %ld ", len) ; if (len < 0) { P3 ("%s", "(denotes 0:n-1) ") ; } P3 ("n: "ID"", (Int) n) ; P4 ("%s", "\n") ; if (len <= 0 || S == NULL) { P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } if (print >= 4) { ETC_START (count, 8) ; for (k = 0 ; k < ((Int) len) ; k++) { ETC (k == ((Int) len) - 4, count, -1) ; i = S [k] ; P4 (" "I8":", k) ; P4 (" "ID"\n", i) ; if (i < 0 || i >= ((Int) n)) { ERR ("entry out range") ; } } } else { for (k = 0 ; k < ((Int) len) ; k++) { i = S [k] ; if (i < 0 || i >= ((Int) n)) { ERR ("entry out range") ; } } } P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } int CHOLMOD(check_subset) ( /* ---- input ---- */ Int *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ UF_long len, /* size of Set (an integer array), or < 0 if 0:n-1 */ size_t n, /* 0:n-1 is valid range */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_subset (Set, len, n, 0, NULL, Common)) ; } int CHOLMOD(print_subset) ( /* ---- input ---- */ Int *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ UF_long len, /* size of Set (an integer array), or < 0 if 0:n-1 */ size_t n, /* 0:n-1 is valid range */ const char *name, /* printed name of Set */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_subset (Set, len, n, Common->print, name, Common)) ; } /* ========================================================================== */ /* === cholmod_check_perm =================================================== */ /* ========================================================================== */ /* Ensure that Perm [0..len-1] is a permutation of a subset of 0:n-1. Perm * may be NULL, which is interpreted as the identity permutation. There can * be no duplicate entries (len must be <= n). * * If n <= Common->nrow, then this routine takes O(len) time and does not * allocate any memory, by using Common->Flag. Otherwise, it takes O(n) time * and ensures that Common->Iwork is at least n*sizeof(Int) in size. * * To check the fset: cholmod_check_perm (fset, fsize, ncol, Common) ; * To check a permutation: cholmod_check_perm (Perm, n, n, Common) ; * * workspace: Flag (n) if n <= Common->nrow, Iwork (n) otherwise. */ static int check_perm ( Int *Wi, Int print, const char *name, Int *Perm, size_t len, size_t n, cholmod_common *Common ) { Int *Flag ; Int i, k, mark, init_print, count ; const char *type = "perm" ; /* ---------------------------------------------------------------------- */ /* checks that take O(1) time */ /* ---------------------------------------------------------------------- */ if (Perm == NULL || n == 0) { /* Perm is valid implicit identity, or empty */ return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* checks that take O(n) time or require memory allocation */ /* ---------------------------------------------------------------------- */ init_print = print ; ETC_START (count, 8) ; if (Wi == NULL && n <= Common->nrow) { /* use the Common->Flag array if it's big enough */ mark = CHOLMOD(clear_flag) (Common) ; Flag = Common->Flag ; ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ; if (print >= 4) { for (k = 0 ; k < ((Int) len) ; k++) { ETC (k >= ((Int) len) - 4, count, -1) ; i = Perm [k] ; P4 (" "I8":", k) ; P4 (""ID"\n", i) ; if (i < 0 || i >= ((Int) n) || Flag [i] == mark) { CHOLMOD(clear_flag) (Common) ; ERR ("invalid permutation") ; } Flag [i] = mark ; } } else { for (k = 0 ; k < ((Int) len) ; k++) { i = Perm [k] ; if (i < 0 || i >= ((Int) n) || Flag [i] == mark) { CHOLMOD(clear_flag) (Common) ; ERR ("invalid permutation") ; } Flag [i] = mark ; } } CHOLMOD(clear_flag) (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ; } else { if (Wi == NULL) { /* use Common->Iwork instead, but initialize it first */ CHOLMOD(allocate_work) (0, n, 0, Common) ; Wi = Common->Iwork ; /* size n, (i/i/i) is OK */ } if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } for (i = 0 ; i < ((Int) n) ; i++) { Wi [i] = FALSE ; } if (print >= 4) { for (k = 0 ; k < ((Int) len) ; k++) { ETC (k >= ((Int) len) - 4, count, -1) ; i = Perm [k] ; P4 (" "I8":", k) ; P4 (""ID"\n", i) ; if (i < 0 || i >= ((Int) n) || Wi [i]) { ERR ("invalid permutation") ; } Wi [i] = TRUE ; } } else { for (k = 0 ; k < ((Int) len) ; k++) { i = Perm [k] ; if (i < 0 || i >= ((Int) n) || Wi [i]) { ERR ("invalid permutation") ; } Wi [i] = TRUE ; } } } /* perm is valid */ return (TRUE) ; } int CHOLMOD(check_perm) ( /* ---- input ---- */ Int *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ size_t len, /* size of Perm (an integer array) */ size_t n, /* 0:n-1 is valid range */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_perm (NULL, 0, NULL, Perm, len, n, Common)) ; } int CHOLMOD(print_perm) ( /* ---- input ---- */ Int *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ size_t len, /* size of Perm (an integer array) */ size_t n, /* 0:n-1 is valid range */ const char *name, /* printed name of Perm */ /* --------------- */ cholmod_common *Common ) { Int ok, print ; RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; print = Common->print ; P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD perm: ") ; if (name != NULL) { P3 ("%s: ", name) ; } P3 (" len: "ID"", (Int) len) ; P3 (" n: "ID"", (Int) n) ; P4 ("%s", "\n") ; ok = check_perm (NULL, print, name, Perm, len, n, Common) ; if (ok) { P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; } return (ok) ; } /* ========================================================================== */ /* === cholmod_check_parent ================================================= */ /* ========================================================================== */ /* Ensure that Parent is a valid elimination tree of nodes 0 to n-1. * If j is a root of the tree then Parent [j] is EMPTY (-1). * * NOTE: this check will fail if applied to the component tree (CParent) in * cholmod_nested_dissection, unless it has been postordered and renumbered. * * workspace: none */ static int check_parent ( Int *Parent, size_t n, Int print, const char *name, cholmod_common *Common ) { Int j, p, init_print, count ; const char *type = "parent" ; init_print = print ; P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD parent: ") ; if (name != NULL) { P3 ("%s: ", name) ; } P3 (" n: "ID"", (Int) n) ; P4 ("%s", "\n") ; if (Parent == NULL) { ERR ("null") ; } /* ---------------------------------------------------------------------- */ /* checks that take O(n) time */ /* ---------------------------------------------------------------------- */ ETC_START (count, 8) ; for (j = 0 ; j < ((Int) n) ; j++) { ETC (j == ((Int) n) - 4, count, -1) ; p = Parent [j] ; P4 (" "I8":", j) ; P4 (" "ID"\n", p) ; if (!(p == EMPTY || p > j)) { ERR ("invalid") ; } } P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } int CHOLMOD(check_parent) ( /* ---- input ---- */ Int *Parent, /* Parent [0:n-1] is an elimination tree */ size_t n, /* size of Parent */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_parent (Parent, n, 0, NULL, Common)) ; } int CHOLMOD(print_parent) ( /* ---- input ---- */ Int *Parent, /* Parent [0:n-1] is an elimination tree */ size_t n, /* size of Parent */ const char *name, /* printed name of Parent */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_parent (Parent, n, Common->print, name, Common)) ; } /* ========================================================================== */ /* === cholmod_check_factor ================================================= */ /* ========================================================================== */ static int check_factor ( Int *Wi, Int print, const char *name, cholmod_factor *L, cholmod_common *Common ) { double *Lx, *Lz ; Int *Lp, *Li, *Lnz, *Lnext, *Lprev, *Perm, *ColCount, *Lpi, *Lpx, *Super, *Ls ; Int n, nzmax, j, p, pend, i, nz, ordering, space, is_monotonic, minor, count, precise, init_print, ilast, lnz, head, tail, jprev, plast, jnext, examine_super, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol, ps2, psxend, ssize, xsize, maxcsize, maxesize, nsrow2, jj, ii, xtype ; Int for_cholesky ; const char *type = "factor" ; /* ---------------------------------------------------------------------- */ /* print header information */ /* ---------------------------------------------------------------------- */ P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD factor: ") ; if (name != NULL) { P3 ("%s: ", name) ; } if (L == NULL) { ERR ("null") ; } n = L->n ; minor = L->minor ; ordering = L->ordering ; xtype = L->xtype ; Perm = L->Perm ; ColCount = L->ColCount ; lnz = 0 ; precise = Common->precise ; P3 (" "ID"", n) ; P3 ("-by-"ID"", n) ; if (minor < n) { P3 (" not positive definite (column "ID")", minor) ; } switch (L->itype) { case CHOLMOD_INT: P4 ("%s", "\n scalar types: int, ") ; break ; case CHOLMOD_INTLONG: ERR ("mixed int/UF_long type unsupported") ; case CHOLMOD_LONG: P4 ("%s", "\n scalar types: UF_long, ") ; break ; default: ERR ("unknown itype") ; } switch (L->xtype) { case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; case CHOLMOD_REAL: P4 ("%s", "real") ; break ; case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; default: ERR ("unknown xtype") ; } switch (L->dtype) { case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; case CHOLMOD_SINGLE: ERR ("single unsupported") ; default: ERR ("unknown dtype") ; } if (L->itype != ITYPE || L->dtype != DTYPE) { ERR ("integer and real type must match routine") ; } if (L->is_super) { P3 ("%s", " supernodal") ; } else { P3 ("%s", " simplicial") ; } if (L->is_ll) { P3 ("%s", ", LL'.") ; } else { P3 ("%s", ", LDL'.") ; } P4 ("%s", "\n ordering method used: ") ; switch (L->ordering) { case CHOLMOD_POSTORDERED:P4 ("%s", "natural (postordered)") ; break ; case CHOLMOD_NATURAL: P4 ("%s", "natural") ; break ; case CHOLMOD_GIVEN: P4 ("%s", "user-provided") ; break ; case CHOLMOD_AMD: P4 ("%s", "AMD") ; break ; case CHOLMOD_COLAMD: P4 ("%s", "AMD for A, COLAMD for A*A'") ;break ; #ifndef NPARTITION case CHOLMOD_METIS: P4 ("%s", "METIS NodeND") ; break ; case CHOLMOD_NESDIS: P4 ("%s", "CHOLMOD nested dissection") ; break ; #endif default: ERR ("unknown ordering") ; } P4 ("%s", "\n") ; init_print = print ; if (L->is_super && L->xtype == CHOLMOD_ZOMPLEX) { ERR ("Supernodal zomplex L not supported") ; } /* ---------------------------------------------------------------------- */ /* check L->Perm */ /* ---------------------------------------------------------------------- */ if (!check_perm (Wi, print, name, Perm, n, n, Common)) { return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* check L->ColCount */ /* ---------------------------------------------------------------------- */ if (ColCount == NULL) { ERR ("ColCount vector invalid") ; } ETC_START (count, 8) ; for (j = 0 ; j < n ; j++) { ETC (j >= n-4, count, -1) ; P4 (" col: "ID" ", j) ; nz = ColCount [j] ; P4 ("colcount: "ID"\n", nz) ; if (nz < 0 || nz > n-j) { ERR ("ColCount out of range") ; } } /* ---------------------------------------------------------------------- */ /* check factor */ /* ---------------------------------------------------------------------- */ if (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) { /* ------------------------------------------------------------------ */ /* check simplicial symbolic factor */ /* ------------------------------------------------------------------ */ /* nothing else to do */ ; } else if (L->xtype != CHOLMOD_PATTERN && !(L->is_super)) { /* ------------------------------------------------------------------ */ /* check simplicial numerical factor */ /* ------------------------------------------------------------------ */ P4 ("monotonic: %d\n", L->is_monotonic) ; nzmax = L->nzmax ; P3 (" nzmax "ID".", nzmax) ; P4 ("%s", "\n") ; Lp = L->p ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lnz = L->nz ; Lnext = L->next ; Lprev = L->prev ; /* check for existence of Lp, Li, Lnz, Lnext, Lprev, and Lx arrays */ if (Lp == NULL) { ERR ("p array not present") ; } if (Li == NULL) { ERR ("i array not present") ; } if (Lnz == NULL) { ERR ("nz array not present") ; } if (Lx == NULL) { ERR ("x array not present") ; } if (xtype == CHOLMOD_ZOMPLEX && Lz == NULL) { ERR ("z array not present") ; } if (Lnext == NULL) { ERR ("next array not present") ; } if (Lprev == NULL) { ERR ("prev array not present") ; } ETC_START (count, 8) ; /* check each column of L */ plast = 0 ; is_monotonic = TRUE ; for (j = 0 ; j < n ; j++) { ETC (j >= n-3, count, -1) ; p = Lp [j] ; nz = Lnz [j] ; pend = p + nz ; lnz += nz ; P4 (" col "ID":", j) ; P4 (" nz "ID"", nz) ; P4 (" start "ID"", p) ; P4 (" end "ID"", pend) ; if (Lnext [j] < 0 || Lnext [j] > n) { ERR ("invalid link list") ; } space = Lp [Lnext [j]] - p ; P4 (" space "ID"", space) ; P4 (" free "ID":\n", space - nz) ; if (p < 0 || pend > nzmax || space < 1) { ERR ("pointer invalid") ; } if (nz < 1 || nz > (n-j) || nz > space) { ERR ("nz invalid") ; } ilast = j-1 ; if (p < plast) { is_monotonic = FALSE ; } plast = p ; i = Li [p] ; P4 (" "I8":", i) ; if (i != j) { ERR ("diagonal missing") ; } print_value (print, xtype, Lx, Lz, p, Common) ; P4 ("%s", "\n") ; ilast = j ; for (p++ ; p < pend ; p++) { ETC_DISABLE (count) ; i = Li [p] ; P4 (" "I8":", i) ; if (i < j || i >= n) { ERR ("row index out of range") ; } if (i <= ilast) { ERR ("row indices out of order") ; } print_value (print, xtype, Lx, Lz, p, Common) ; P4 ("%s", "\n") ; ilast = i ; } } if (L->is_monotonic && !is_monotonic) { ERR ("columns not monotonic") ; } /* check the link list */ head = n+1 ; tail = n ; j = head ; jprev = EMPTY ; count = 0 ; for ( ; ; ) { if (j < 0 || j > n+1 || count > n+2) { ERR ("invalid link list") ; } jnext = Lnext [j] ; if (j >= 0 && j < n) { if (jprev != Lprev [j]) { ERR ("invalid link list") ; } } count++ ; if (j == tail) { break ; } jprev = j ; j = jnext ; } if (Lnext [tail] != EMPTY || count != n+2) { ERR ("invalid link list") ; } } else { /* ------------------------------------------------------------------ */ /* check supernodal numeric or symbolic factor */ /* ------------------------------------------------------------------ */ nsuper = L->nsuper ; ssize = L->ssize ; xsize = L->xsize ; maxcsize = L->maxcsize ; maxesize = L->maxesize ; Ls = L->s ; Lpi = L->pi ; Lpx = L->px ; Super = L->super ; Lx = L->x ; ETC_START (count, 8) ; P4 (" ssize "ID" ", ssize) ; P4 ("xsize "ID" ", xsize) ; P4 ("maxcsize "ID" ", maxcsize) ; P4 ("maxesize "ID"\n", maxesize) ; if (Ls == NULL) { ERR ("invalid: L->s missing") ; } if (Lpi == NULL) { ERR ("invalid: L->pi missing") ; } if (Lpx == NULL) { ERR ("invalid: L->px missing") ; } if (Super == NULL) { ERR ("invalid: L->super missing") ; } if (L->xtype != CHOLMOD_PATTERN) { /* numerical supernodal factor */ if (Lx == NULL) { ERR ("invalid: L->x missing") ; } if (Ls [0] == EMPTY) { ERR ("invalid: L->s not defined") ; } examine_super = TRUE ; } else { /* symbolic supernodal factor, but only if it has been computed */ examine_super = (Ls [0] != EMPTY) ; } if (examine_super) { if (Lpi [0] != 0 || MAX (1, Lpi [nsuper]) != ssize) { PRINT0 (("Lpi [0] "ID", Lpi [nsuper = "ID"] = "ID"\n", Lpi [0], nsuper, Lpi [nsuper])) ; ERR ("invalid: L->pi invalid") ; } for_cholesky = (Lpx [0] != 123456) ; if (for_cholesky && (Lpx [0] != 0 || MAX (1, Lpx[nsuper]) != xsize)) { ERR ("invalid: L->px invalid") ; } /* check and print each supernode */ for (s = 0 ; s < nsuper ; s++) { k1 = Super [s] ; k2 = Super [s+1] ; psi = Lpi [s] ; psend = Lpi [s+1] ; nsrow = psend - psi ; nscol = k2 - k1 ; nsrow2 = nsrow - nscol ; ps2 = psi + nscol ; if (for_cholesky) { psx = Lpx [s] ; psxend = Lpx [s+1] ; } ETC (s == nsuper-1, count, 4) ; P4 (" supernode "ID", ", s) ; P4 ("col "ID" ", k1) ; P4 ("to "ID". ", k2-1) ; P4 ("nz in first col: "ID".\n", nsrow) ; if (for_cholesky) { P4 (" values start "ID", ", psx) ; P4 ("end "ID"\n", psxend) ; } if (k1 > k2 || k1 < 0 || k2 > n || nsrow < nscol || nsrow2 < 0 || (for_cholesky && psxend - psx != nsrow * nscol)) { ERR ("invalid supernode") ; } lnz += nscol * nsrow - (nscol*nscol - nscol)/2 ; if (L->xtype != CHOLMOD_PATTERN) { /* print each column of the supernode */ for (jj = 0 ; jj < nscol ; jj++) { ETC_ENABLE (s == nsuper-1 && jj >= nscol-3, count, -1) ; j = k1 + jj ; P4 (" col "ID"\n", j) ; ilast = j ; i = Ls [psi + jj] ; P4 (" "I8":", i) ; if (i != j) { ERR ("row index invalid") ; } /* PRINTVALUE (Lx [psx + jj + jj*nsrow]) ; */ print_value (print, xtype, Lx, NULL, psx + jj + jj*nsrow, Common) ; P4 ("%s", "\n") ; for (ii = jj + 1 ; ii < nsrow ; ii++) { ETC_DISABLE (count) ; i = Ls [psi + ii] ; P4 (" "I8":", i) ; if (i <= ilast || i > n) { ERR ("row index out of range") ; } /* PRINTVALUE (Lx [psx + ii + jj*nsrow]) ; */ print_value (print, xtype, Lx, NULL, psx + ii + jj*nsrow, Common) ; P4 ("%s", "\n") ; ilast = i ; } } } else { /* just print the leading column of the supernode */ P4 (" col "ID"\n", k1) ; for (jj = 0 ; jj < nscol ; jj++) { ETC (s == nsuper-1 && jj >= nscol-3, count, -1) ; j = k1 + jj ; i = Ls [psi + jj] ; P4 (" "I8"", i) ; if (i != j) { ERR ("row index invalid") ; } P4 ("%s", "\n") ; } ilast = j ; for (ii = nscol ; ii < nsrow ; ii++) { ETC_DISABLE (count) ; i = Ls [psi + ii] ; P4 (" "I8"", i) ; if (i <= ilast || i > n) { ERR ("row index out of range") ; } P4 ("%s", "\n") ; ilast = i ; } } } } } /* factor is valid */ P3 (" nz "ID"", lnz) ; P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } int CHOLMOD(check_factor) ( /* ---- input ---- */ cholmod_factor *L, /* factor to check */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_factor (NULL, 0, NULL, L, Common)) ; } int CHOLMOD(print_factor) ( /* ---- input ---- */ cholmod_factor *L, /* factor to print */ const char *name, /* printed name of factor */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_factor (NULL, Common->print, name, L, Common)) ; } /* ========================================================================== */ /* === cholmod_check_triplet ================================================ */ /* ========================================================================== */ /* Ensure a triplet matrix is valid, and optionally print it. */ static int check_triplet ( Int print, const char *name, cholmod_triplet *T, cholmod_common *Common ) { double *Tx, *Tz ; Int *Ti, *Tj ; Int i, j, p, nrow, ncol, nzmax, nz, xtype, init_print, count ; const char *type = "triplet" ; /* ---------------------------------------------------------------------- */ /* print header information */ /* ---------------------------------------------------------------------- */ P4 ("%s", "\n") ; P3 ("%s", "CHOLMOD triplet: ") ; if (name != NULL) { P3 ("%s: ", name) ; } if (T == NULL) { ERR ("null") ; } nrow = T->nrow ; ncol = T->ncol ; nzmax = T->nzmax ; nz = T->nnz ; Ti = T->i ; Tj = T->j ; Tx = T->x ; Tz = T->z ; xtype = T->xtype ; P3 (" "ID"", nrow) ; P3 ("-by-"ID", ", ncol) ; P3 ("nz "ID",", nz) ; if (T->stype > 0) { P3 ("%s", " upper.") ; } else if (T->stype < 0) { P3 ("%s", " lower.") ; } else { P3 ("%s", " up/lo.") ; } P4 ("\n nzmax "ID", ", nzmax) ; if (nz > nzmax) { ERR ("nzmax too small") ; } switch (T->itype) { case CHOLMOD_INT: P4 ("%s", "\n scalar types: int, ") ; break ; case CHOLMOD_INTLONG: ERR ("mixed int/UF_long type unsupported") ; case CHOLMOD_LONG: P4 ("%s", "\n scalar types: UF_long, ") ; break ; default: ERR ("unknown itype") ; } switch (T->xtype) { case CHOLMOD_PATTERN: P4 ("%s", "pattern") ; break ; case CHOLMOD_REAL: P4 ("%s", "real") ; break ; case CHOLMOD_COMPLEX: P4 ("%s", "complex") ; break ; case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ; break ; default: ERR ("unknown xtype") ; } switch (T->dtype) { case CHOLMOD_DOUBLE: P4 ("%s", ", double\n") ; break ; case CHOLMOD_SINGLE: ERR ("single unsupported") ; default: ERR ("unknown dtype") ; } if (T->itype != ITYPE || T->dtype != DTYPE) { ERR ("integer and real type must match routine") ; } if (T->stype && nrow != ncol) { ERR ("symmetric but not square") ; } /* check for existence of Ti, Tj, Tx arrays */ if (Tj == NULL) { ERR ("j array not present") ; } if (Ti == NULL) { ERR ("i array not present") ; } if (xtype != CHOLMOD_PATTERN && Tx == NULL) { ERR ("x array not present") ; } if (xtype == CHOLMOD_ZOMPLEX && Tz == NULL) { ERR ("z array not present") ; } /* ---------------------------------------------------------------------- */ /* check and print each entry */ /* ---------------------------------------------------------------------- */ init_print = print ; ETC_START (count, 8) ; for (p = 0 ; p < nz ; p++) { ETC (p >= nz-4, count, -1) ; i = Ti [p] ; P4 (" "I8":", p) ; P4 (" "I_8"", i) ; if (i < 0 || i >= nrow) { ERR ("row index out of range") ; } j = Tj [p] ; P4 (" "I_8"", j) ; if (j < 0 || j >= ncol) { ERR ("column index out of range") ; } print_value (print, xtype, Tx, Tz, p, Common) ; P4 ("%s", "\n") ; } /* triplet matrix is valid */ P3 ("%s", " OK\n") ; P4 ("%s", "\n") ; return (TRUE) ; } int CHOLMOD(check_triplet) ( /* ---- input ---- */ cholmod_triplet *T, /* triplet matrix to check */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_triplet (0, NULL, T, Common)) ; } int CHOLMOD(print_triplet) ( /* ---- input ---- */ cholmod_triplet *T, /* triplet matrix to print */ const char *name, /* printed name of triplet matrix */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; return (check_triplet (Common->print, name, T, Common)) ; } /* ========================================================================== */ /* === CHOLMOD debugging routines =========================================== */ /* ========================================================================== */ #ifndef NDEBUG /* The global variables present only when debugging enabled. */ int CHOLMOD(dump) = 0 ; int CHOLMOD(dump_malloc) = -1 ; /* workspace: no debug routines use workspace in Common */ /* ========================================================================== */ /* === cholmod_dump_init ==================================================== */ /* ========================================================================== */ void CHOLMOD(dump_init) (const char *s, cholmod_common *Common) { FILE *f ; f = fopen ("debug", "r") ; if (f == NULL) { CHOLMOD(dump) = 0 ; } else { fscanf (f, "%d", &CHOLMOD(dump)) ; fclose (f) ; } PRINT1 (("%s: cholmod_dump_init, D = %d\n", s, CHOLMOD(dump))) ; } /* ========================================================================== */ /* === cholmod_dump_sparse ================================================== */ /* ========================================================================== */ UF_long CHOLMOD(dump_sparse) /* returns nnz (diag (A)) or EMPTY if error */ ( cholmod_sparse *A, const char *name, cholmod_common *Common ) { Int *Wi ; UF_long nnzdiag ; Int ok ; if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (0) ; } RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; Wi = malloc (MAX (1, A->nrow) * sizeof (Int)) ; ok = check_sparse (Wi, CHOLMOD(dump), name, A, &nnzdiag, Common) ; if (Wi != NULL) free (Wi) ; return (ok ? nnzdiag : EMPTY) ; } /* ========================================================================== */ /* === cholmod_dump_factor ================================================== */ /* ========================================================================== */ int CHOLMOD(dump_factor) ( cholmod_factor *L, const char *name, cholmod_common *Common ) { Int *Wi ; int ok ; if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; Wi = malloc (MAX (1, L->n) * sizeof (Int)) ; ok = check_factor (Wi, CHOLMOD(dump), name, L, Common) ; if (Wi != NULL) free (Wi) ; return (ok) ; } /* ========================================================================== */ /* === cholmod_dump_perm ==================================================== */ /* ========================================================================== */ int CHOLMOD(dump_perm) ( Int *Perm, size_t len, size_t n, const char *name, cholmod_common *Common ) { Int *Wi ; int ok ; if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; Wi = malloc (MAX (1, n) * sizeof (Int)) ; ok = check_perm (Wi, CHOLMOD(dump), name, Perm, len, n,Common) ; if (Wi != NULL) free (Wi) ; return (ok) ; } /* ========================================================================== */ /* === cholmod_dump_dense =================================================== */ /* ========================================================================== */ int CHOLMOD(dump_dense) ( cholmod_dense *X, const char *name, cholmod_common *Common ) { if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_dense (CHOLMOD(dump), name, X, Common)) ; } /* ========================================================================== */ /* === cholmod_dump_triplet ================================================= */ /* ========================================================================== */ int CHOLMOD(dump_triplet) ( cholmod_triplet *T, const char *name, cholmod_common *Common ) { if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_triplet (CHOLMOD(dump), name, T, Common)) ; } /* ========================================================================== */ /* === cholmod_dump_subset ================================================== */ /* ========================================================================== */ int CHOLMOD(dump_subset) ( Int *S, size_t len, size_t n, const char *name, cholmod_common *Common ) { if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_subset (S, len, n, CHOLMOD(dump), name, Common)) ; } /* ========================================================================== */ /* === cholmod_dump_parent ================================================== */ /* ========================================================================== */ int CHOLMOD(dump_parent) ( Int *Parent, size_t n, const char *name, cholmod_common *Common ) { if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; return (check_parent (Parent, n, CHOLMOD(dump), name, Common)) ; } /* ========================================================================== */ /* === cholmod_dump_real ==================================================== */ /* ========================================================================== */ void CHOLMOD(dump_real) ( const char *name, Real *X, UF_long nrow, UF_long ncol, int lower, int xentry, cholmod_common *Common ) { /* dump an nrow-by-ncol real dense matrix */ UF_long i, j ; double x, z ; if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return ; } PRINT1 (("%s: dump_real, nrow: %ld ncol: %ld lower: %d\n", name, nrow, ncol, lower)) ; for (j = 0 ; j < ncol ; j++) { PRINT2 ((" col %ld\n", j)) ; for (i = 0 ; i < nrow ; i++) { /* X is stored in column-major form */ if (lower && i < j) { PRINT2 ((" %5ld: -", i)) ; } else { x = *X ; PRINT2 ((" %5ld: %e", i, x)) ; if (xentry == 2) { z = *(X+1) ; PRINT2 ((", %e", z)) ; } } PRINT2 (("\n")) ; X += xentry ; } } } /* ========================================================================== */ /* === cholmod_dump_super =================================================== */ /* ========================================================================== */ void CHOLMOD(dump_super) ( UF_long s, Int *Super, Int *Lpi, Int *Ls, Int *Lpx, double *Lx, int xentry, cholmod_common *Common ) { Int k1, k2, do_values, psi, psx, nsrow, nscol, psend, ilast, p, i ; if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return ; } k1 = Super [s] ; k2 = Super [s+1] ; nscol = k2 - k1 ; do_values = (Lpx != NULL) && (Lx != NULL) ; psi = Lpi [s] ; psend = Lpi [s+1] ; nsrow = psend - psi ; PRINT1 (("\nSuper %ld, columns "ID" to "ID", "ID" rows "ID" cols\n", s, k1, k2-1, nsrow, nscol)) ; ilast = -1 ; for (p = psi ; p < psend ; p++) { i = Ls [p] ; PRINT2 ((" "ID" : p-psi "ID"\n", i, p-psi)) ; ASSERT (IMPLIES (p-psi < nscol, i == k1 + (p-psi))) ; if (p-psi == nscol-1) PRINT2 (("------\n")) ; ASSERT (i > ilast) ; ilast = i ; } if (do_values) { psx = Lpx [s] ; CHOLMOD(dump_real) ("Supernode", Lx + xentry*psx, nsrow, nscol, TRUE, xentry, Common) ; } } /* ========================================================================== */ /* === cholmod_dump_mem ===================================================== */ /* ========================================================================== */ int CHOLMOD(dump_mem) ( const char *where, UF_long should, cholmod_common *Common ) { UF_long diff = should - Common->memory_inuse ; if (diff != 0) { PRINT0 (("mem: %-15s peak %10g inuse %10g should %10g\n", where, (double) Common->memory_usage, (double) Common->memory_inuse, (double) should)) ; PRINT0 (("mem: %s diff %ld !\n", where, diff)) ; } return (diff == 0) ; } /* ========================================================================== */ /* === cholmod_dump_partition =============================================== */ /* ========================================================================== */ /* make sure we have a proper separator (for debugging only) * * workspace: none */ int CHOLMOD(dump_partition) ( UF_long n, Int *Cp, Int *Ci, Int *Cnw, Int *Part, UF_long sepsize, cholmod_common *Common ) { Int chek [3], which, ok, i, j, p ; PRINT1 (("bisect sepsize %ld\n", sepsize)) ; ok = TRUE ; chek [0] = 0 ; chek [1] = 0 ; chek [2] = 0 ; for (j = 0 ; j < n ; j++) { PRINT2 (("--------j "ID" in part "ID" nw "ID"\n", j, Part [j], Cnw[j])); which = Part [j] ; for (p = Cp [j] ; p < Cp [j+1] ; p++) { i = Ci [p] ; PRINT3 (("i "ID", part "ID"\n", i, Part [i])) ; if (which == 0) { if (Part [i] == 1) { PRINT0 (("Error! "ID" "ID"\n", i, j)) ; ok = FALSE ; } } else if (which == 1) { if (Part [i] == 0) { PRINT0 (("Error! "ID" "ID"\n", i, j)) ; ok = FALSE ; } } } if (which < 0 || which > 2) { PRINT0 (("Part out of range\n")) ; ok = FALSE ; } chek [which] += Cnw [j] ; } PRINT1 (("sepsize %ld check "ID" "ID" "ID"\n", sepsize, chek[0], chek[1],chek[2])); if (sepsize != chek[2]) { PRINT0 (("mismatch!\n")) ; ok = FALSE ; } return (ok) ; } /* ========================================================================== */ /* === cholmod_dump_work ==================================================== */ /* ========================================================================== */ int CHOLMOD(dump_work) (int flag, int head, UF_long wsize, cholmod_common *Common) { double *W ; Int *Flag, *Head ; Int k, nrow, mark ; if (CHOLMOD(dump) < -1) { /* no checks if debug level is -2 or less */ return (TRUE) ; } RETURN_IF_NULL_COMMON (FALSE) ; nrow = Common->nrow ; Flag = Common->Flag ; Head = Common->Head ; W = Common->Xwork ; mark = Common->mark ; if (wsize < 0) { /* check all of Xwork */ wsize = Common->xworksize ; } else { /* check on the first wsize doubles in Xwork */ wsize = MIN (wsize, (Int) (Common->xworksize)) ; } if (flag) { for (k = 0 ; k < nrow ; k++) { if (Flag [k] >= mark) { PRINT0 (("Flag invalid, Flag ["ID"] = "ID", mark = "ID"\n", k, Flag [k], mark)) ; ASSERT (0) ; return (FALSE) ; } } } if (head) { for (k = 0 ; k < nrow ; k++) { if (Head [k] != EMPTY) { PRINT0 (("Head invalid, Head ["ID"] = "ID"\n", k, Head [k])) ; ASSERT (0) ; return (FALSE) ; } } } for (k = 0 ; k < wsize ; k++) { if (W [k] != 0.) { PRINT0 (("W invalid, W ["ID"] = %g\n", k, W [k])) ; ASSERT (0) ; return (FALSE) ; } } return (TRUE) ; } #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Check/lesser.txt0000644000175000017500000006350011674452555021470 0ustar sonnesonne GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Check/cholmod_write.c0000644000175000017500000005124211674452555022435 0ustar sonnesonne/* ========================================================================== */ /* === Check/cholmod_write ================================================== */ /* ========================================================================== */ /* Write a matrix to a file in Matrix Market form. * * A can be sparse or full. * * If present and non-empty, A and Z must have the same dimension. Z contains * the explicit zero entries in the matrix (which MATLAB drops). The entries * of Z appear as explicit zeros in the output file. Z is optional. If it is * an empty matrix it is ignored. Z must be sparse or empty, if present. * It is ignored if A is full. * * filename is the name of the output file. comments is file whose * contents are include after the Matrix Market header and before the first * data line. Ignored if an empty string or not present. * * Except for the workspace used by cholmod_symmetry (ncol integers) for * the sparse case, these routines use no workspace at all. */ #ifndef NCHECK #include "cholmod_internal.h" #include "cholmod_check.h" #include "cholmod_matrixops.h" #include #include #define MMLEN 1024 #define MAXLINE MMLEN+6 /* ========================================================================== */ /* === include_comments ===================================================== */ /* ========================================================================== */ /* Read in the comments file, if it exists, and copy it to the Matrix Market * file. A "%" is prepended to each line. Returns TRUE if successful, FALSE * otherwise. */ static int include_comments (FILE *f, const char *comments) { FILE *cf = NULL ; char buffer [MAXLINE] ; int ok = TRUE ; if (comments != NULL && comments [0] != '\0') { cf = fopen (comments, "r") ; if (cf == NULL) { return (FALSE) ; } while (ok && fgets (buffer, MAXLINE, cf) != NULL) { /* ensure the line is not too long */ buffer [MMLEN-1] = '\0' ; buffer [MMLEN-2] = '\n' ; ok = ok && (fprintf (f, "%%%s", buffer) > 0) ; } fclose (cf) ; } return (ok) ; } /* ========================================================================== */ /* === get_value ============================================================ */ /* ========================================================================== */ /* Get the pth value in the matrix. */ static void get_value ( double *Ax, /* real values, or real/imag. for CHOLMOD_COMPLEX type */ double *Az, /* imaginary values for CHOLMOD_ZOMPLEX type */ Int p, /* get the pth entry */ Int xtype, /* A->xtype: pattern, real, complex, or zomplex */ double *x, /* the real part */ double *z /* the imaginary part */ ) { switch (xtype) { case CHOLMOD_PATTERN: *x = 1 ; *z = 0 ; break ; case CHOLMOD_REAL: *x = Ax [p] ; *z = 0 ; break ; case CHOLMOD_COMPLEX: *x = Ax [2*p] ; *z = Ax [2*p+1] ; break ; case CHOLMOD_ZOMPLEX: *x = Ax [p] ; *z = Az [p] ; break ; } } /* ========================================================================== */ /* === print_value ========================================================== */ /* ========================================================================== */ /* Print a numeric value to the file, using the shortest format that ensures * the value is written precisely. Returns TRUE if successful, FALSE otherwise. */ static int print_value ( FILE *f, /* file to print to */ double x, /* value to print */ Int is_integer /* TRUE if printing as an integer */ ) { double y ; char s [MAXLINE], *p ; Int i, dest = 0, src = 0 ; int width, ok ; if (is_integer) { i = (Int) x ; ok = (fprintf (f, ID, i) > 0) ; return (ok) ; } /* ---------------------------------------------------------------------- */ /* handle Inf and NaN */ /* ---------------------------------------------------------------------- */ /* change -inf to -HUGE_DOUBLE, and change +inf and nan to +HUGE_DOUBLE */ if (CHOLMOD_IS_NAN (x) || x >= HUGE_DOUBLE) { x = HUGE_DOUBLE ; } else if (x <= -HUGE_DOUBLE) { x = -HUGE_DOUBLE ; } /* ---------------------------------------------------------------------- */ /* find the smallest acceptable precision */ /* ---------------------------------------------------------------------- */ for (width = 6 ; width < 20 ; width++) { sprintf (s, "%.*g", width, x) ; sscanf (s, "%lg", &y) ; if (x == y) break ; } /* ---------------------------------------------------------------------- */ /* shorten the string */ /* ---------------------------------------------------------------------- */ /* change "e+0" to "e", change "e+" to "e", and change "e-0" to "e-" */ for (i = 0 ; i < MAXLINE && s [i] != '\0' ; i++) { if (s [i] == 'e') { if (s [i+1] == '+') { dest = i+1 ; if (s [i+2] == '0') { /* delete characters s[i+1] and s[i+2] */ src = i+3 ; } else { /* delete characters s[i+1] */ src = i+2 ; } } else if (s [i+1] == '-') { dest = i+2 ; if (s [i+2] == '0') { /* delete character s[i+2] */ src = i+3 ; } else { /* no change */ break ; } } while (s [src] != '\0') { s [dest++] = s [src++] ; } s [dest] = '\0' ; break ; } } /* delete the leading "0" if present and not necessary */ p = s ; s [MAXLINE-1] = '\0' ; i = strlen (s) ; if (i > 2 && s [0] == '0' && s [1] == '.') { /* change "0.x" to ".x" */ p = s + 1 ; } else if (i > 3 && s [0] == '-' && s [1] == '0' && s [2] == '.') { /* change "-0.x" to "-.x" */ s [1] = '-' ; p = s + 1 ; } #if 0 /* double-check */ i = sscanf (p, "%lg", &z) ; if (i != 1 || y != z) { /* oops! something went wrong in the "e+0" edit, above. */ /* this "cannot" happen */ sprintf (s, "%.*g", width, x) ; p = s ; } #endif /* ---------------------------------------------------------------------- */ /* print the value to the file */ /* ---------------------------------------------------------------------- */ ok = (fprintf (f, "%s", p) > 0) ; return (ok) ; } /* ========================================================================== */ /* === print_triplet ======================================================== */ /* ========================================================================== */ /* Print a triplet, converting it to one-based. Returns TRUE if successful, * FALSE otherwise. */ static int print_triplet ( FILE *f, /* file to print to */ Int is_binary, /* TRUE if file is "pattern" */ Int is_complex, /* TRUE if file is "complex" */ Int is_integer, /* TRUE if file is "integer" */ Int i, /* row index (zero-based) */ Int j, /* column index (zero-based) */ double x, /* real part */ double z /* imaginary part */ ) { int ok ; ok = (fprintf (f, ID " " ID, 1+i, 1+j) > 0) ; if (!is_binary) { fprintf (f, " ") ; ok = ok && print_value (f, x, is_integer) ; if (is_complex) { fprintf (f, " ") ; ok = ok && print_value (f, z, is_integer) ; } } ok = ok && (fprintf (f, "\n") > 0) ; return (ok) ; } /* ========================================================================== */ /* === ntriplets ============================================================ */ /* ========================================================================== */ /* Compute the number of triplets that will be printed to the file * from the matrix A. */ static Int ntriplets ( cholmod_sparse *A, /* matrix that will be printed */ Int is_sym /* TRUE if the file is symmetric (lower part only)*/ ) { Int *Ap, *Ai, *Anz, packed, i, j, p, pend, ncol, stype, nz = 0 ; if (A == NULL) { /* the Z matrix is NULL */ return (0) ; } stype = A->stype ; Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; ncol = A->ncol ; for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? Ap [j+1] : p + Anz [j] ; for ( ; p < pend ; p++) { i = Ai [p] ; if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym))) { /* CHOLMOD matrix is symmetric-lower (and so is the file); * or CHOLMOD matrix is unsymmetric and either A(i,j) is in * the lower part or the file is unsymmetric. */ nz++ ; } else if (stype > 0 && i <= j) { /* CHOLMOD matrix is symmetric-upper, but the file is * symmetric-lower. Need to transpose the entry. */ nz++ ; } } } return (nz) ; } /* ========================================================================== */ /* === cholmod_write_sparse ================================================= */ /* ========================================================================== */ /* Write a sparse matrix to a file in Matrix Market format. Optionally include * comments, and print explicit zero entries given by the pattern of the Z * matrix. If not NULL, the Z matrix must have the same dimensions and stype * as A. * * Returns the symmetry in which the matrix was printed (1 to 7, see the * CHOLMOD_MM_* codes in CHOLMOD/Include/cholmod_core.h), or -1 on failure. * * If A and Z are sorted on input, and either unsymmetric (stype = 0) or * symmetric-lower (stype < 0), and if A and Z do not overlap, then the triplets * are sorted, first by column and then by row index within each column, with * no duplicate entries. If all the above holds except stype > 0, then the * triplets are sorted by row first and then column. */ int CHOLMOD(write_sparse) ( /* ---- input ---- */ FILE *f, /* file to write to, must already be open */ cholmod_sparse *A, /* matrix to print */ cholmod_sparse *Z, /* optional matrix with pattern of explicit zeros */ const char *comments, /* optional filename of comments to include */ /* --------------- */ cholmod_common *Common ) { double x = 0, z = 0 ; double *Ax, *Az ; Int *Ap, *Ai, *Anz, *Zp, *Zi, *Znz ; Int nrow, ncol, is_complex, symmetry, i, j, q, iz, p, nz, is_binary, stype, is_integer, asym, is_sym, xtype, apacked, zpacked, pend, qend, zsym ; int ok ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (f, EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; if (Z != NULL && (Z->nrow == 0 || Z->ncol == 0)) { /* Z is non-NULL but empty, so treat it as a NULL matrix */ Z = NULL ; } if (Z != NULL) { RETURN_IF_XTYPE_INVALID (Z, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; if (Z->nrow != A->nrow || Z->ncol != A->ncol || Z->stype != A->stype) { ERROR (CHOLMOD_INVALID, "dimension or type of A and Z mismatch") ; return (EMPTY) ; } } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get the A matrix */ /* ---------------------------------------------------------------------- */ Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; Anz = A->nz ; nrow = A->nrow ; ncol = A->ncol ; xtype = A->xtype ; apacked = A->packed ; if (xtype == CHOLMOD_PATTERN) { /* a CHOLMOD pattern matrix is printed as "pattern" in the file */ is_binary = TRUE ; is_integer = FALSE ; is_complex = FALSE ; } else if (xtype == CHOLMOD_REAL) { /* determine if a real matrix is in fact binary or integer */ is_binary = TRUE ; is_integer = TRUE ; is_complex = FALSE ; for (j = 0 ; (is_binary || is_integer) && j < ncol ; j++) { p = Ap [j] ; pend = (apacked) ? Ap [j+1] : p + Anz [j] ; for ( ; (is_binary || is_integer) && p < pend ; p++) { x = Ax [p] ; if (x != 1) { is_binary = FALSE ; } /* convert to Int and then back to double */ i = (Int) x ; z = (double) i ; if (z != x) { is_integer = FALSE ; } } } } else { /* a CHOLMOD complex matrix is printed as "complex" in the file */ is_binary = FALSE ; is_integer = FALSE ; is_complex = TRUE ; } /* ---------------------------------------------------------------------- */ /* get the Z matrix (only consider the pattern) */ /* ---------------------------------------------------------------------- */ Zp = NULL ; Zi = NULL ; Znz = NULL ; zpacked = TRUE ; if (Z != NULL) { Zp = Z->p ; Zi = Z->i ; Znz = Z->nz ; zpacked = Z->packed ; } /* ---------------------------------------------------------------------- */ /* determine the symmetry of A and Z */ /* ---------------------------------------------------------------------- */ stype = A->stype ; if (A->nrow != A->ncol) { asym = CHOLMOD_MM_RECTANGULAR ; } else if (stype != 0) { /* CHOLMOD's A and Z matrices have a symmetric (and matching) stype. * Note that the diagonal is not checked. */ asym = is_complex ? CHOLMOD_MM_HERMITIAN : CHOLMOD_MM_SYMMETRIC ; } else if (!A->sorted) { /* A is in unsymmetric storage, but unsorted */ asym = CHOLMOD_MM_UNSYMMETRIC ; } else { /* CHOLMOD's stype is zero (stored in unsymmetric form) */ asym = EMPTY ; zsym = EMPTY ; #ifndef NMATRIXOPS /* determine if the matrices are in fact symmetric or Hermitian */ asym = CHOLMOD(symmetry) (A, 1, NULL, NULL, NULL, NULL, Common) ; zsym = (Z == NULL) ? 999 : CHOLMOD(symmetry) (Z, 1, NULL, NULL, NULL, NULL, Common) ; #endif if (asym == EMPTY || zsym <= CHOLMOD_MM_UNSYMMETRIC) { /* not computed, out of memory, or Z is unsymmetric */ asym = CHOLMOD_MM_UNSYMMETRIC ; } } /* ---------------------------------------------------------------------- */ /* write the Matrix Market header */ /* ---------------------------------------------------------------------- */ ok = fprintf (f, "%%%%MatrixMarket matrix coordinate") > 0 ; if (is_complex) { ok = ok && (fprintf (f, " complex") > 0) ; } else if (is_binary) { ok = ok && (fprintf (f, " pattern") > 0) ; } else if (is_integer) { ok = ok && (fprintf (f, " integer") > 0) ; } else { ok = ok && (fprintf (f, " real") > 0) ; } is_sym = FALSE ; switch (asym) { case CHOLMOD_MM_RECTANGULAR: case CHOLMOD_MM_UNSYMMETRIC: /* A is rectangular or unsymmetric */ ok = ok && (fprintf (f, " general\n") > 0) ; is_sym = FALSE ; symmetry = CHOLMOD_MM_UNSYMMETRIC ; break ; case CHOLMOD_MM_SYMMETRIC: case CHOLMOD_MM_SYMMETRIC_POSDIAG: /* A is symmetric */ ok = ok && (fprintf (f, " symmetric\n") > 0) ; is_sym = TRUE ; symmetry = CHOLMOD_MM_SYMMETRIC ; break ; case CHOLMOD_MM_HERMITIAN: case CHOLMOD_MM_HERMITIAN_POSDIAG: /* A is Hermitian */ ok = ok && (fprintf (f, " Hermitian\n") > 0) ; is_sym = TRUE ; symmetry = CHOLMOD_MM_HERMITIAN ; break ; case CHOLMOD_MM_SKEW_SYMMETRIC: /* A is skew symmetric */ ok = ok && (fprintf (f, " skew-symmetric\n") > 0) ; is_sym = TRUE ; symmetry = CHOLMOD_MM_SKEW_SYMMETRIC ; break ; } /* ---------------------------------------------------------------------- */ /* include the comments if present */ /* ---------------------------------------------------------------------- */ ok = ok && include_comments (f, comments) ; /* ---------------------------------------------------------------------- */ /* write a sparse matrix (A and Z) */ /* ---------------------------------------------------------------------- */ nz = ntriplets (A, is_sym) + ntriplets (Z, is_sym) ; /* write the first data line, with nrow, ncol, and # of triplets */ ok = ok && (fprintf (f, ID " " ID " " ID "\n", nrow, ncol, nz) > 0) ; for (j = 0 ; ok && j < ncol ; j++) { /* merge column of A and Z */ p = Ap [j] ; pend = (apacked) ? Ap [j+1] : p + Anz [j] ; q = (Z == NULL) ? 0 : Zp [j] ; qend = (Z == NULL) ? 0 : ((zpacked) ? Zp [j+1] : q + Znz [j]) ; while (ok) { /* get the next row index from A and Z */ i = (p < pend) ? Ai [p] : (nrow+1) ; iz = (q < qend) ? Zi [q] : (nrow+2) ; if (i <= iz) { /* get A(i,j), or quit if both A and Z are exhausted */ if (i == nrow+1) break ; get_value (Ax, Az, p, xtype, &x, &z) ; p++ ; } else { /* get Z(i,j) */ i = iz ; x = 0 ; z = 0 ; q++ ; } if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym))) { /* CHOLMOD matrix is symmetric-lower (and so is the file); * or CHOLMOD matrix is unsymmetric and either A(i,j) is in * the lower part or the file is unsymmetric. */ ok = ok && print_triplet (f, is_binary, is_complex, is_integer, i,j, x,z) ; } else if (stype > 0 && i <= j) { /* CHOLMOD matrix is symmetric-upper, but the file is * symmetric-lower. Need to transpose the entry. If the * matrix is real, the complex part is ignored. If the matrix * is complex, it Hermitian. */ ASSERT (IMPLIES (is_complex, asym == CHOLMOD_MM_HERMITIAN)) ; if (z != 0) { z = -z ; } ok = ok && print_triplet (f, is_binary, is_complex, is_integer, j,i, x,z) ; } } } if (!ok) { ERROR (CHOLMOD_INVALID, "error reading/writing file") ; return (EMPTY) ; } return (asym) ; } /* ========================================================================== */ /* === cholmod_write_dense ================================================== */ /* ========================================================================== */ /* Write a dense matrix to a file in Matrix Market format. Optionally include * comments. Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if * square). Future versions may return 1 to 7 on success (a CHOLMOD_MM_* code, * just as cholmod_write_sparse does). * * A dense matrix is written in "general" format; symmetric formats in the * Matrix Market standard are not exploited. */ int CHOLMOD(write_dense) ( /* ---- input ---- */ FILE *f, /* file to write to, must already be open */ cholmod_dense *X, /* matrix to print */ const char *comments, /* optional filename of comments to include */ /* --------------- */ cholmod_common *Common ) { double x = 0, z = 0 ; double *Xx, *Xz ; Int nrow, ncol, is_complex, i, j, xtype, p ; int ok ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (f, EMPTY) ; RETURN_IF_NULL (X, EMPTY) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get the X matrix */ /* ---------------------------------------------------------------------- */ Xx = X->x ; Xz = X->z ; nrow = X->nrow ; ncol = X->ncol ; xtype = X->xtype ; is_complex = (xtype == CHOLMOD_COMPLEX) || (xtype == CHOLMOD_ZOMPLEX) ; /* ---------------------------------------------------------------------- */ /* write the Matrix Market header */ /* ---------------------------------------------------------------------- */ ok = (fprintf (f, "%%%%MatrixMarket matrix array") > 0) ; if (is_complex) { ok = ok && (fprintf (f, " complex general\n") > 0) ; } else { ok = ok && (fprintf (f, " real general\n") > 0) ; } /* ---------------------------------------------------------------------- */ /* include the comments if present */ /* ---------------------------------------------------------------------- */ ok = ok && include_comments (f, comments) ; /* ---------------------------------------------------------------------- */ /* write a dense matrix */ /* ---------------------------------------------------------------------- */ /* write the first data line, with nrow and ncol */ ok = ok && (fprintf (f, ID " " ID "\n", nrow, ncol) > 0) ; Xx = X->x ; Xz = X->z ; for (j = 0 ; ok && j < ncol ; j++) { for (i = 0 ; ok && i < nrow ; i++) { p = i + j*nrow ; get_value (Xx, Xz, p, xtype, &x, &z) ; ok = ok && print_value (f, x, FALSE) ; if (is_complex) { ok = ok && (fprintf (f, " ") > 0) ; ok = ok && print_value (f, z, FALSE) ; } ok = ok && (fprintf (f, "\n") > 0) ; } } if (!ok) { ERROR (CHOLMOD_INVALID, "error reading/writing file") ; return (EMPTY) ; } return ((nrow == ncol) ? CHOLMOD_MM_UNSYMMETRIC : CHOLMOD_MM_RECTANGULAR) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/0000755000175000017500000000000011674452555017116 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/getmproto0000755000175000017500000000011211674452555021056 0ustar sonnesonne#!/bin/sh cat mheader.tex expand -8 $1 | awk -f mfile.awk cat mfooter.tex cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/mheader.tex0000644000175000017500000000014411674452555021244 0ustar sonnesonne \noindent\hspace{0.85in}\rule[0.05in]{5.2in}{1pt} \vspace{-0.15in} {\footnotesize \begin{verbatim} cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/mfile.awk0000644000175000017500000000005511674452555020716 0ustar sonnesonne/^%/ { print " ", substr ($0,2) } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/getproto0000755000175000017500000000017111674452555020706 0ustar sonnesonne#!/bin/sh echo -n $1 > _temp.awk cat rule.awk >> _temp.awk cat header.tex expand -8 $2 | awk -f _temp.awk cat footer.tex cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/Makefile0000644000175000017500000004014211674452555020557 0ustar sonnesonnedefault: all include ../../UFconfig/UFconfig.mk all: UserGuide.pdf I = \ ../Include/cholmod.h \ ../Include/cholmod_blas.h \ ../Include/cholmod_check.h \ ../Include/cholmod_cholesky.h \ ../Include/cholmod_complexity.h \ ../Include/cholmod_config.h \ ../Include/cholmod_core.h \ ../Include/cholmod_internal.h \ ../Include/cholmod_matrixops.h \ ../Include/cholmod_modify.h \ ../Include/cholmod_partition.h \ ../Include/cholmod_supernodal.h \ ../Include/cholmod_template.h C = ../Demo/cholmod_simple.c M = \ ../MATLAB/analyze.m \ ../MATLAB/bisect.m \ ../MATLAB/chol2.m \ ../MATLAB/cholmod2.m \ ../MATLAB/cholmod_demo.m \ ../MATLAB/cholmod_make.m \ ../MATLAB/etree2.m \ ../MATLAB/graph_demo.m \ ../MATLAB/lchol.m \ ../MATLAB/ldlchol.m \ ../MATLAB/ldl_normest.m \ ../MATLAB/ldlsolve.m \ ../MATLAB/ldlsplit.m \ ../MATLAB/ldlupdate.m \ ../MATLAB/metis.m \ ../MATLAB/nesdis.m \ ../MATLAB/resymbol.m \ ../MATLAB/sdmult.m \ ../MATLAB/sparse2.m \ ../MATLAB/spsym.m \ ../MATLAB/mread.m \ ../MATLAB/mwrite.m \ ../MATLAB/symbfact2.m UserGuide.pdf: UserGuide.tex UserGuide.bib $(I) $(C) $(M) Makefile getproto rule.awk header.tex footer.tex getmproto mfooter.tex mheader.tex mfile.awk ./getmproto ../MATLAB/analyze.m > _analyze_m.tex ./getmproto ../MATLAB/bisect.m > _bisect_m.tex ./getmproto ../MATLAB/chol2.m > _chol2_m.tex ./getmproto ../MATLAB/cholmod2.m > _cholmod2_m.tex ./getmproto ../MATLAB/cholmod_demo.m > _cholmod_demo_m.tex ./getmproto ../MATLAB/cholmod_make.m > _cholmod_make_m.tex ./getmproto ../MATLAB/etree2.m > _etree2_m.tex ./getmproto ../MATLAB/graph_demo.m > _graph_demo_m.tex ./getmproto ../MATLAB/lchol.m > _lchol_m.tex ./getmproto ../MATLAB/ldlchol.m > _ldlchol_m.tex ./getmproto ../MATLAB/ldl_normest.m > _ldl_normest_m.tex ./getmproto ../MATLAB/ldlsolve.m > _ldlsolve_m.tex ./getmproto ../MATLAB/ldlsplit.m > _ldlsplit_m.tex ./getmproto ../MATLAB/ldlupdate.m > _ldlupdate_m.tex ./getmproto ../MATLAB/metis.m > _metis_m.tex ./getmproto ../MATLAB/mread.m > _mread_m.tex ./getmproto ../MATLAB/spsym.m > _spsym_m.tex ./getmproto ../MATLAB/mwrite.m > _mwrite_m.tex ./getmproto ../MATLAB/nesdis.m > _nesdis_m.tex ./getmproto ../MATLAB/resymbol.m > _resymbol_m.tex ./getmproto ../MATLAB/sdmult.m > _sdmult_m.tex ./getmproto ../MATLAB/sparse2.m > _sparse2_m.tex ./getmproto ../MATLAB/symbfact2.m > _symbfact2_m.tex ./getproto '/include/, /^}/' ../Demo/cholmod_simple.c > _simple.tex ./getproto '/typedef struct cholmod_common/, /^}/' ../Include/cholmod_core.h > _common.tex ./getproto '/int cholmod_start/, /\*\) ;/' ../Include/cholmod_core.h > _start.tex ./getproto '/int cholmod_finish/, /\*\) ;/' ../Include/cholmod_core.h > _finish.tex ./getproto '/int cholmod_defaults/, /\*\) ;/' ../Include/cholmod_core.h > _defaults.tex ./getproto '/size_t cholmod_maxrank/, /\*\) ;/' ../Include/cholmod_core.h > _maxrank.tex ./getproto '/int cholmod_allocate_work/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_work.tex ./getproto '/int cholmod_free_work/, /\*\) ;/' ../Include/cholmod_core.h > _free_work.tex ./getproto '/long cholmod_clear_flag/, /\*\) ;/' ../Include/cholmod_core.h > _clear_flag.tex ./getproto '/int cholmod_error/, /\*\) ;/' ../Include/cholmod_core.h > _error.tex ./getproto '/double cholmod_dbound/, /\*\) ;/' ../Include/cholmod_core.h > _dbound.tex ./getproto '/double cholmod_hypot/, /double\) ;/' ../Include/cholmod_core.h > _hypot.tex ./getproto '/int cholmod_divcomplex/, /\*\) ;/' ../Include/cholmod_core.h > _divcomplex.tex ./getproto '/typedef struct cholmod_sparse/, /^}/' ../Include/cholmod_core.h > _sparse.tex ./getproto '/cholmod_sparse \*cholmod_allocate_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_sparse.tex ./getproto '/int cholmod_free_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _free_sparse.tex ./getproto '/int cholmod_reallocate_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_sparse.tex ./getproto '/long cholmod_nnz/, /\*\) ;/' ../Include/cholmod_core.h > _nnz.tex ./getproto '/cholmod_sparse \*cholmod_speye/, /\*\) ;/' ../Include/cholmod_core.h > _speye.tex ./getproto '/cholmod_sparse \*cholmod_spzeros/, /\*\) ;/' ../Include/cholmod_core.h > _spzeros.tex ./getproto '/cholmod_sparse \*cholmod_transpose/, /\*\) ;/' ../Include/cholmod_core.h > _transpose.tex ./getproto '/int cholmod_transpose_unsym/, /\*\) ;/' ../Include/cholmod_core.h > _transpose_unsym.tex ./getproto '/int cholmod_transpose_sym/, /\*\) ;/' ../Include/cholmod_core.h > _transpose_sym.tex ./getproto '/cholmod_sparse \*cholmod_ptranspose/, /\*\) ;/' ../Include/cholmod_core.h > _ptranspose.tex ./getproto '/int cholmod_sort/, /\*\) ;/' ../Include/cholmod_core.h > _sort.tex ./getproto '/cholmod_sparse \*cholmod_band/, /\*\) ;/' ../Include/cholmod_core.h > _band.tex ./getproto '/int cholmod_band_inplace/, /\*\) ;/' ../Include/cholmod_core.h > _band_inplace.tex ./getproto '/cholmod_sparse \*cholmod_aat/, /\*\) ;/' ../Include/cholmod_core.h > _aat.tex ./getproto '/cholmod_sparse \*cholmod_copy_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _copy_sparse.tex ./getproto '/cholmod_sparse \*cholmod_copy /, /\*\) ;/' ../Include/cholmod_core.h > _copy.tex ./getproto '/cholmod_sparse \*cholmod_add/, /\*\) ;/' ../Include/cholmod_core.h > _add.tex ./getproto '/int cholmod_sparse_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _sparse_xtype.tex ./getproto '/typedef struct cholmod_factor/, /^}/' ../Include/cholmod_core.h > _factor.tex ./getproto '/cholmod_factor \*cholmod_allocate_factor/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_factor.tex ./getproto '/int cholmod_free_factor/, /\*\) ;/' ../Include/cholmod_core.h > _free_factor.tex ./getproto '/int cholmod_reallocate_factor/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_factor.tex ./getproto '/int cholmod_change_factor/, /\*\) ;/' ../Include/cholmod_core.h > _change_factor.tex ./getproto '/int cholmod_pack_factor/, /\*\) ;/' ../Include/cholmod_core.h > _pack_factor.tex ./getproto '/int cholmod_reallocate_column/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_column.tex ./getproto '/cholmod_sparse \*cholmod_factor_to_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _factor_to_sparse.tex ./getproto '/cholmod_factor \*cholmod_copy_factor/, /\*\) ;/' ../Include/cholmod_core.h > _copy_factor.tex ./getproto '/int cholmod_factor_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _factor_xtype.tex ./getproto '/typedef struct cholmod_dense/, /^}/' ../Include/cholmod_core.h > _dense.tex ./getproto '/cholmod_dense \*cholmod_allocate_dense/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_dense.tex ./getproto '/cholmod_dense \*cholmod_zeros/, /\*\) ;/' ../Include/cholmod_core.h > _zeros.tex ./getproto '/cholmod_dense \*cholmod_ones/, /\*\) ;/' ../Include/cholmod_core.h > _ones.tex ./getproto '/cholmod_dense \*cholmod_eye/, /\*\) ;/' ../Include/cholmod_core.h > _eye.tex ./getproto '/int cholmod_free_dense/, /\*\) ;/' ../Include/cholmod_core.h > _free_dense.tex ./getproto '/cholmod_dense \*cholmod_sparse_to_dense/, /\*\) ;/' ../Include/cholmod_core.h > _sparse_to_dense.tex ./getproto '/cholmod_sparse \*cholmod_dense_to_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _dense_to_sparse.tex ./getproto '/cholmod_dense \*cholmod_copy_dense/, /\*\) ;/' ../Include/cholmod_core.h > _copy_dense.tex ./getproto '/int cholmod_copy_dense2/, /\*\) ;/' ../Include/cholmod_core.h > _copy_dense2.tex ./getproto '/int cholmod_dense_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _dense_xtype.tex ./getproto '/typedef struct cholmod_triplet/, /^}/' ../Include/cholmod_core.h > _triplet.tex ./getproto '/cholmod_triplet \*cholmod_allocate_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _allocate_triplet.tex ./getproto '/int cholmod_free_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _free_triplet.tex ./getproto '/int cholmod_reallocate_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _reallocate_triplet.tex ./getproto '/cholmod_triplet \*cholmod_sparse_to_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _sparse_to_triplet.tex ./getproto '/cholmod_sparse \*cholmod_triplet_to_sparse/, /\*\) ;/' ../Include/cholmod_core.h > _triplet_to_sparse.tex ./getproto '/cholmod_triplet \*cholmod_copy_triplet/, /\*\) ;/' ../Include/cholmod_core.h > _copy_triplet.tex ./getproto '/int cholmod_triplet_xtype/, /\*\) ;/' ../Include/cholmod_core.h > _triplet_xtype.tex ./getproto '/void \*cholmod_malloc/, /\*\) ;/' ../Include/cholmod_core.h > _malloc.tex ./getproto '/void \*cholmod_calloc/, /\*\) ;/' ../Include/cholmod_core.h > _calloc.tex ./getproto '/void \*cholmod_free/, /\*\) ;/' ../Include/cholmod_core.h > _free.tex ./getproto '/void \*cholmod_realloc/, /\*\) ;/' ../Include/cholmod_core.h > _realloc.tex ./getproto '/int cholmod_realloc_multiple/, /\*\) ;/' ../Include/cholmod_core.h > _realloc_multiple.tex ./getproto '/itype defines the/, /define CHOLMOD_SUPERNODAL/' ../Include/cholmod_core.h > _defn.tex ./getproto '/int cholmod_check_common/, /\*\) ;/' ../Include/cholmod_check.h > _check_common.tex ./getproto '/int cholmod_print_common/, /\*\) ;/' ../Include/cholmod_check.h > _print_common.tex ./getproto '/int cholmod_check_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _check_sparse.tex ./getproto '/int cholmod_print_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _print_sparse.tex ./getproto '/int cholmod_check_dense/, /\*\) ;/' ../Include/cholmod_check.h > _check_dense.tex ./getproto '/int cholmod_print_dense/, /\*\) ;/' ../Include/cholmod_check.h > _print_dense.tex ./getproto '/int cholmod_check_factor/, /\*\) ;/' ../Include/cholmod_check.h > _check_factor.tex ./getproto '/int cholmod_print_factor/, /\*\) ;/' ../Include/cholmod_check.h > _print_factor.tex ./getproto '/int cholmod_check_triplet/, /\*\) ;/' ../Include/cholmod_check.h > _check_triplet.tex ./getproto '/int cholmod_print_triplet/, /\*\) ;/' ../Include/cholmod_check.h > _print_triplet.tex ./getproto '/int cholmod_check_subset/, /\*\) ;/' ../Include/cholmod_check.h > _check_subset.tex ./getproto '/int cholmod_print_subset/, /\*\) ;/' ../Include/cholmod_check.h > _print_subset.tex ./getproto '/int cholmod_check_perm/, /\*\) ;/' ../Include/cholmod_check.h > _check_perm.tex ./getproto '/int cholmod_print_perm/, /\*\) ;/' ../Include/cholmod_check.h > _print_perm.tex ./getproto '/int cholmod_check_parent/, /\*\) ;/' ../Include/cholmod_check.h > _check_parent.tex ./getproto '/int cholmod_print_parent/, /\*\) ;/' ../Include/cholmod_check.h > _print_parent.tex ./getproto '/cholmod_triplet \*cholmod_read_triplet/, /\*\) ;/' ../Include/cholmod_check.h > _read_triplet.tex ./getproto '/cholmod_sparse \*cholmod_read_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _read_sparse.tex ./getproto '/cholmod_dense \*cholmod_read_dense/, /\*\) ;/' ../Include/cholmod_check.h > _read_dense.tex ./getproto '/void \*cholmod_read_matrix/, /\*\) ;/' ../Include/cholmod_check.h > _read_matrix.tex ./getproto '/int cholmod_write_sparse/, /\*\) ;/' ../Include/cholmod_check.h > _write_sparse.tex ./getproto '/int cholmod_write_dense/, /\*\) ;/' ../Include/cholmod_check.h > _write_dense.tex ./getproto '/cholmod_factor \*cholmod_analyze /, /\*\) ;/' ../Include/cholmod_cholesky.h > _analyze.tex ./getproto '/cholmod_factor \*cholmod_analyze_p/, /\*\) ;/' ../Include/cholmod_cholesky.h > _analyze_p.tex ./getproto '/int cholmod_factorize /, /\*\) ;/' ../Include/cholmod_cholesky.h > _factorize.tex ./getproto '/int cholmod_factorize_p/, /\*\) ;/' ../Include/cholmod_cholesky.h > _factorize_p.tex ./getproto '/cholmod_dense \*cholmod_solve/, /\*\) ;/' ../Include/cholmod_cholesky.h > _solve.tex ./getproto '/cholmod_sparse \*cholmod_spsolve/, /\*\) ;/' ../Include/cholmod_cholesky.h > _spsolve.tex ./getproto '/int cholmod_etree/, /\*\) ;/' ../Include/cholmod_cholesky.h > _etree.tex ./getproto '/int cholmod_rowcolcounts/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rowcolcounts.tex ./getproto '/int cholmod_analyze_ordering/, /\*\) ;/' ../Include/cholmod_cholesky.h > _analyze_ordering.tex ./getproto '/int cholmod_amd/, /\*\) ;/' ../Include/cholmod_cholesky.h > _amd.tex ./getproto '/int cholmod_colamd/, /\*\) ;/' ../Include/cholmod_cholesky.h > _colamd.tex ./getproto '/int cholmod_rowfac/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rowfac.tex ./getproto '/int cholmod_rowfac_mask/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rowfac_mask.tex ./getproto '/int cholmod_row_subtree/, /\*\) ;/' ../Include/cholmod_cholesky.h > _row_subtree.tex ./getproto '/int cholmod_row_lsubtree/, /\*\) ;/' ../Include/cholmod_cholesky.h > _row_lsubtree.tex ./getproto '/int cholmod_resymbol /, /\*\) ;/' ../Include/cholmod_cholesky.h > _resymbol.tex ./getproto '/int cholmod_resymbol_noperm/, /\*\) ;/' ../Include/cholmod_cholesky.h > _resymbol_noperm.tex ./getproto '/double cholmod_rcond/, /\*\) ;/' ../Include/cholmod_cholesky.h > _rcond.tex ./getproto '/long cholmod_postorder/, /\*\) ;/' ../Include/cholmod_cholesky.h > _postorder.tex ./getproto '/int cholmod_updown /, /\*\) ;/' ../Include/cholmod_modify.h > _updown.tex ./getproto '/int cholmod_updown_solve/, /\*\) ;/' ../Include/cholmod_modify.h > _updown_solve.tex ./getproto '/int cholmod_updown_mark/, /\*\) ;/' ../Include/cholmod_modify.h > _updown_mark.tex ./getproto '/int cholmod_updown_mask/, /\*\) ;/' ../Include/cholmod_modify.h > _updown_mask.tex ./getproto '/int cholmod_rowadd /, /\*\) ;/' ../Include/cholmod_modify.h > _rowadd.tex ./getproto '/int cholmod_rowadd_solve/, /\*\) ;/' ../Include/cholmod_modify.h > _rowadd_solve.tex ./getproto '/int cholmod_rowadd_mark/, /\*\) ;/' ../Include/cholmod_modify.h > _rowadd_mark.tex ./getproto '/int cholmod_rowdel /, /\*\) ;/' ../Include/cholmod_modify.h > _rowdel.tex ./getproto '/int cholmod_rowdel_solve/, /\*\) ;/' ../Include/cholmod_modify.h > _rowdel_solve.tex ./getproto '/int cholmod_rowdel_mark/, /\*\) ;/' ../Include/cholmod_modify.h > _rowdel_mark.tex ./getproto '/int cholmod_drop/, /\*\) ;/' ../Include/cholmod_matrixops.h > _drop.tex ./getproto '/double cholmod_norm_dense/, /\*\) ;/' ../Include/cholmod_matrixops.h > _norm_dense.tex ./getproto '/double cholmod_norm_sparse/, /\*\) ;/' ../Include/cholmod_matrixops.h > _norm_sparse.tex ./getproto '/cholmod_sparse \*cholmod_horzcat/, /\*\) ;/' ../Include/cholmod_matrixops.h > _horzcat.tex ./getproto '/define CHOLMOD_SCALAR/, /\*\) ;/' ../Include/cholmod_matrixops.h > _scale.tex ./getproto '/int cholmod_sdmult/, /\*\) ;/' ../Include/cholmod_matrixops.h > _sdmult.tex ./getproto '/cholmod_sparse \*cholmod_ssmult/, /\*\) ;/' ../Include/cholmod_matrixops.h > _ssmult.tex ./getproto '/cholmod_sparse \*cholmod_submatrix/, /\*\) ;/' ../Include/cholmod_matrixops.h > _submatrix.tex ./getproto '/cholmod_sparse \*cholmod_vertcat/, /\*\) ;/' ../Include/cholmod_matrixops.h > _vertcat.tex ./getproto '/int cholmod_symmetry/, /\*\) ;/' ../Include/cholmod_matrixops.h > _symmetry.tex ./getproto '/int cholmod_super_symbolic/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_symbolic.tex ./getproto '/int cholmod_super_numeric/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_numeric.tex ./getproto '/int cholmod_super_lsolve/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_lsolve.tex ./getproto '/int cholmod_super_ltsolve/, /\*\) ;/' ../Include/cholmod_supernodal.h > _super_ltsolve.tex ./getproto '/long cholmod_nested_dissection/, /\*\) ;/' ../Include/cholmod_partition.h > _nested_dissection.tex ./getproto '/int cholmod_metis/, /\*\) ;/' ../Include/cholmod_partition.h > _metis.tex ./getproto '/int cholmod_ccolamd/, /\*\) ;/' ../Include/cholmod_partition.h > _ccolamd.tex ./getproto '/int cholmod_camd/, /\*\) ;/' ../Include/cholmod_partition.h > _camd.tex ./getproto '/int cholmod_csymamd/, /\*\) ;/' ../Include/cholmod_partition.h > _csymamd.tex ./getproto '/int cholmod_csymamd/, /\*\) ;/' ../Include/cholmod_partition.h > _csymamd.tex ./getproto '/long cholmod_bisect/, /\*\) ;/' ../Include/cholmod_partition.h > _bisect.tex ./getproto '/long cholmod_metis_bisector/, /\*\) ;/' ../Include/cholmod_partition.h > _metis_bisector.tex ./getproto '/long cholmod_collapse_septree/, /\*\) ;/' ../Include/cholmod_partition.h > _collapse_septree.tex pdflatex UserGuide bibtex UserGuide pdflatex UserGuide pdflatex UserGuide distclean: purge purge: clean - $(RM) _temp.awk _*.tex *.dvi *.aux *.log *.lof *.lot *.toc *.bak *.bbl *.blg clean: - $(RM) $(CLEAN) cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/header.tex0000644000175000017500000000014311674452555021066 0ustar sonnesonne\noindent\hspace{0.85in}\rule[0.05in]{5.2in}{1pt} \vspace{-0.15in} {\footnotesize \begin{verbatim} cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/mfooter.tex0000644000175000017500000000012411674452555021310 0ustar sonnesonne\end{verbatim} } \noindent\hspace{0.85in}\rule[0.25in]{5.2in}{1pt} \vspace{-0.15in} cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/rule.awk0000644000175000017500000000003511674452555020567 0ustar sonnesonne{ print " ", $0 } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/footer.tex0000644000175000017500000000015611674452555021140 0ustar sonnesonne\end{verbatim} } \noindent\hspace{0.85in}\rule[0.25in]{5.2in}{1pt} \vspace{-0.15in} \noindent {\bf Purpose:} cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/ChangeLog0000644000175000017500000001737111674452555020701 0ustar sonnesonneSept 30, 2008, version 1.7.1 * bug fix to cholmod_symmetry; it reported incorrectly if the matrix had a zero-free diagonal or not. No effect on the use of CHOLMOD in MATLAB. No effect on the mwrite function, either, which uses cholmod_symmetry. Note that the number of nonzeros on the diagonal was (and still is) correctly computed. Only effect is on the UF_Index.cholcand statistic reported in the UFget index, and on the web pages, for the UF Sparse Matrix Collection (the UF_Index.cholcand field). This affects the output of spsym. Sept 20, 2008, version 1.7.0 * update for SuiteSparseQR: - add SuiteSparseQR knobs and stats to CHOLMOD Common - SuiteSparseQR uses CHOLMOD for its multifrontal symbolic analysis - changed (char *) input parameters to (const char *), to avoid spurious compiler warnings when C++ calls C. - minor change to the AMD backup strategy in cholmod_analyze, to better suit SuiteSparseQR - modified cholmod_analyze and cholmod_super_symbolic, to add "for_cholesky" parameter; new function cholmod_analyze_p2. This parameter is false for SuiteSparseQR. - minor correction to comments in cholmod_postorder.c - performance enhancement to supernodal symbolic analysis, when A or AA' is fairly dense Nov 1, 2007, version 1.6.0 * minor lint cleanup (no bugs) * new CHOLMOD_CLEAR_FLAG macro, which speeds up the calls to cholmod_clear_flag, avoiding the function call if not needed. Note that this leads to untested lines in the Tcov test, but the lines of the macro are tested in several places, just not everywhere it appers. * port to MATLAB 7.5 (mex -lmwblas option now required for Linux) * minor bug fix to cholmod_add.c to avoid potential Int overflow * extra option added to cholmod2 mexFunction * sparse2 mexFunction modified to ensure nnz(A) == nzmax(A) always holds (It didn't in v1.5.0 if numerically zero entries were dropped in A). * correction to Help comments for spsym function * bug fix to cholmod_symmetry.c: determination of Hermitian vs non-Hermitian matrices was incorrect if the diagonal was imaginary. * performance fix for cholmod_nesdis.c and nesdis mexFunction May 31, 2007, version 1.5.0 * 64-bit MATLAB interface * MATLAB interface back-ported to MATLAB 6.1. * bug fix: solving Dx=b using a supernodal factorization, in cholmod_l_solve, when sizeof(UF_long) > sizeof(BLAS integer) * changes to Makefiles to reflect directory changes in COLAMD and CCOLAMD v2.7.0 directory structure (CHOLMOD v1.5 requires v2.7.0 of those two packages) * update to Modify/cholmod_updown.c, to allow input vector R to be packed or unpacked. * bug fix to Tcov/huge.c test code, for 64-bit case (this has no effect on the CHOLMOD library itself, just the test code) Dec 12, 2006, version 1.4.0 * added support for large files (larger than 2GB) * minor MATLAB cleanup * renamed MATLAB function from cholmod to cholmod2, to avoid filename clash with itself (the built-in version of cholmod). Dec 2, 2006, version 1.3.0 * Major modification to cholmod_read.c; now fully supports all forms of the Matrix Market format. Added cholmod_read_dense and cholmod_read_matrix functions to cholmod_read.c. Major changes to mread MATLAB function. Added Common->prefer_binary option for cholmod_read. * Added cholmod_write.c (cholmod_write_sparse and cholmod_write_dense functions). Added mwrite MATLAB function. * Added 2nd output argument to sparse2 (Z, binary pattern of explicit zero entries). * Added the function cholmod_symmetry to the MatrixOps module. Added spsym MATLAB function. * 2nd argument to cholmod_triplet_to_sparse changed from int to size_t. * minor correction to cholmod_analyze_ordering, cholmod_dense.c * minor change to cholmod_rowfac.c, cholmod_solve.c, ... to allow for easier testing. Sept 28, 2006, version 1.2.1 * bug fix to cholmod_matlab.c, when working with sparse INT64 matrices in the "sparse2" function Aug 31, 2006, version 1.2 * Common->default_nesdis parameter and Common->called_nd statistic added. Otherwise, no change to user interface. v1.2 is fully upward compatible with v1.1 (even binary compatible). * non-supernodal Lx=b and L'x=b solves simplified, slight increase in performance. * update/downdate performance improved. * ordering options and output statistics added to MATLAB/cholmod mexFunction. July 27, 2006, version 1.1.1 * bug fix for cholmod_rowfac_mask, for the complex case. Has no effect on MATLAB. June 27, 2006: * trivial changes to nested dissection code, and cholmod_read.c (for debugging, and to add explicit typecasts so compilers don't complain). May, 2006: * Added new routines for LPDASA: cholmod_rowfac_mask, cholmod_updown_mask. Added cholmod_collapse_septree. Added nd_oksep, nd_components parameters to Common. Apr 30, 2006: version 1.1 * added interface to CAMD. cholmod_nested_dissection can now call CCOLAMD, CSYMAMD, and CAMD. Common->nd_camd usage extended. New argument added to nesdis mexFunction. New cholmod_camd function added. No other changes to CHOLMOD user interface. * more careful integer overflow checks. Added non-user-callable functions to add and multiply size_t integers, with overflow checks. * added Common->no_workspace_reallocate * flop count is now correct for A*A' case (Common->rowfacfl). Jan 18, 2006: version 1.0.2 * bug fix: MATLAB interface incorrect for full logical matrices. * Tcov tests modified to generate fewer intentional nan's, to make it easier to look for errors in BLAS libraries that incorrectly generate nan's. Dec 16, 2005: version 1.0.1 * bug fix: cholmod_amd allocated too small of a workspace when ordering A*A' Dec 8, 2005: version 1.0 * no real changes. Version 1.0 is the same as version 0.8. Version 1.0 is simply the formal stable release. * known issue: the floating point operation count, Common->rowfacfl, is statistic is incorrect when factorizing A*A'. This will be fixed in version 1.1. Nov 15, 2005: version 0.8 * bug fix in t_cholmod_super_numeric, for [R,p]=chol(A) usage. * Common->quick_return_if_not_posdef added. * Added cholmod_row_lsubtree (required for LPDASA) * bug fix: cholmod_rcond returned sqrt(1/cond) for an LL' factorization; 1/cond is required. * new statistics added: flop counts for cholmod_rowfac, # of factor column reallocations, # of factor reallocations due to column reallocations, and # of times the (non-default) bounds on diag(L) are hit. * factor column reallocation skipped if space already big enough. * bug fix: cholmod_copy_factor did not copy L->is_monotonic. * bug fix: cholmod_change_factor (diagonal entry was wrong in one case) * rcond added to cholmod mexFunction ([x,rcond] = cholmod(A,b)). * cholmod_rowadd, cholmod_rowdel modified. rowdel no longer removes entries from the matrix; it sets them to zero instead. Oct 10, 2005: version 0.7 * minor changes: minor change to Check/cholmod_check.c (coerce sizeof(...) to (int) when printing. Less strict check on A->p for unpacked matrices) , removed a few unused variables in Check/cholmod_read.c and Demo/cholmod*demo.c, changed "exit(0)" to "return(0)" in Demo/cholmod_simple.c. Changed Makefile so that "." is not assumed to be on the $path. Added Cygwin to architecture detection in Include/cholmod_blas.h. Added cparent and cmember to nesdis.m. Space for future expansion added to cholmod_common. * removed "rowmark" from the Modify module, which affects how partial updates to Lx=b solves are done during update/downdate. Should only affect LPDASA. * added CHOLMOD_SUBSUB_VERSION Aug 31, 2005: version 0.6 released. cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.tex0000644000175000017500000047510211674452555021545 0ustar sonnesonne%------------------------------------------------------------------------------- % The CHOLMOD/Doc/UserGuide.tex file. %------------------------------------------------------------------------------- \documentclass[11pt]{article} \newcommand{\m}[1]{{\bf{#1}}} % for matrices and vectors \newcommand{\tr}{^{\sf T}} % transpose \newcommand{\new}[1]{\overline{#1}} \topmargin 0in \textheight 9in \oddsidemargin 0pt \evensidemargin 0pt \textwidth 6.5in \begin{document} \author{Timothy A. Davis \\ Dept. of Computer and Information Science and Engineering \\ Univ. of Florida, Gainesville, FL} \title{User Guide for CHOLMOD: a sparse Cholesky factorization and modification package} \date{Version 1.7, Sept 20, 2008} \maketitle %------------------------------------------------------------------------------- \begin{abstract} CHOLMOD\footnote{CHOLMOD is short for CHOLesky MODification, since a key feature of the package is its ability to update/downdate a sparse Cholesky factorization} is a set of routines for factorizing sparse symmetric positive definite matrices of the form $\m{A}$ or $\m{AA}\tr$, updating/downdating a sparse Cholesky factorization, solving linear systems, updating/downdating the solution to the triangular system $\m{Lx}=\m{b}$, and many other sparse matrix functions for both symmetric and unsymmetric matrices. Its supernodal Cholesky factorization relies on LAPACK and the Level-3 BLAS, and obtains a substantial fraction of the peak performance of the BLAS. Both real and complex matrices are supported. CHOLMOD is written in ANSI/ISO C, with both C and MATLAB interfaces. This code works on Microsoft Windows and many versions of Unix and Linux. \end{abstract} %------------------------------------------------------------------------------- CHOLMOD Copyright\copyright 2005-2008 by Timothy A. Davis. Portions are also copyrighted by William W. Hager (the {\tt Modify} Module), and the University of Florida (the {\tt Partition} and {\tt Core} Modules). All Rights Reserved. Some of CHOLMOD's Modules are distributed under the GNU General Public License, and others under the GNU Lesser General Public License. Refer to each Module for details. CHOLMOD is also available under other licenses that permit its use in proprietary applications; contact the authors for details. See http://www.cise.ufl.edu/research/sparse for the code and all documentation, including this User Guide. \newpage \tableofcontents %------------------------------------------------------------------------------- \newpage \section{Overview} %------------------------------------------------------------------------------- CHOLMOD is a set of ANSI C routines for solving systems of linear equations, $\m{Ax}=\m{b}$, when $\m{A}$ is sparse and symmetric positive definite, and $\m{x}$ and $\m{b}$ can be either sparse or dense.\footnote{Some support is provided for symmetric indefinite matrices.} Complex matrices are supported, in two different formats. CHOLMOD includes high-performance left-looking supernodal factorization and solve methods \cite{NgPeyton91b}, based on LAPACK \cite{LAPACK} and the BLAS \cite{ACM679a}. After a matrix is factorized, its factors can be updated or downdated using the techniques described by Davis and Hager in \cite{DavisHager99,DavisHager01,DavisHager05}. Many additional sparse matrix operations are provided, for both symmetric and unsymmetric matrices (square or rectangular), including sparse matrix multiply, add, transpose, permutation, scaling, norm, concatenation, sub-matrix access, and converting to alternate data structures. Interfaces to many ordering methods are provided, including minimum degree (AMD \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}, COLAMD \cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00}), constrained minimum degree (CSYMAMD, CCOLAMD, CAMD), and graph-partitioning-based nested dissection (METIS \cite{KarypisKumar98}). Most of its operations are available within MATLAB via mexFunction interfaces. A pair of articles on CHOLMOD has been submitted to the ACM Transactions on Mathematical Softare: \cite{ChenDavisHagerRajamanickam06,DavisHager06}. CHOLMOD 1.0 replaces {\tt chol} (the sparse case), {\tt symbfact}, and {\tt etree} in MATLAB 7.2 (R2006a), and is used for {\tt x=A}$\backslash${\tt b} when {\tt A} is symmetric positive definite \cite{GilbertMolerSchreiber}. It will replace {\tt sparse} in a future version of MATLAB. The C-callable CHOLMOD library consists of 133 user-callable routines and one include file. Each routine comes in two versions, one for {\tt int} integers and another for {\tt long}. Many of the routines can support either real or complex matrices, simply by passing a matrix of the appropriate type. Nick Gould, Yifan Hu, and Jennifer Scott have independently tested CHOLMOD's performance, comparing it with nearly a dozen or so other solvers \cite{GouldHuScott05,GouldHuScott05b}. Its performance was quite competitive. %------------------------------------------------------------------------------- \newpage \section{Primary routines and data structures} %------------------------------------------------------------------------------- Five primary CHOLMOD routines are required to factorize $\m{A}$ or $\m{AA}\tr$ and solve the related system $\m{Ax}=\m{b}$ or $\m{AA}\tr\m{x}=\m{b}$, for either the real or complex cases: \begin{enumerate} \item {\tt cholmod\_start}: This must be the first call to CHOLMOD. \item {\tt cholmod\_analyze}: Finds a fill-reducing ordering, and performs the symbolic factorization, either simplicial (non-supernodal) or supernodal. \item {\tt cholmod\_factorize}: Numerical factorization, either simplicial or supernodal, $\m{LL}\tr$ or $\m{LDL}\tr$ using either the symbolic factorization from {\tt cholmod\_analyze} or the numerical factorization from a prior call to {\tt cholmod\_factorize}. \item {\tt cholmod\_solve}: Solves $\m{Ax}=\m{b}$, or many other related systems, where $\m{x}$ and $\m{b}$ are dense matrices. The {\tt cholmod\_spsolve} routine handles the sparse case. Any mixture of real and complex $\m{A}$ and $\m{b}$ are allowed. \item {\tt cholmod\_finish}: This must be the last call to CHOLMOD. \end{enumerate} Additional routines are also required to create and destroy the matrices $\m{A}$, $\m{x}$, $\m{b}$, and the $\m{LL}\tr$ or $\m{LDL}\tr$ factorization. CHOLMOD has five kinds of data structures, referred to as objects and implemented as pointers to {\tt struct}'s: \begin{enumerate} \item {\tt cholmod\_common}: parameter settings, statistics, and workspace used internally by CHOLMOD. See Section~\ref{cholmod_common} for details. \item {\tt cholmod\_sparse}: a sparse matrix in compressed-column form, either pattern-only, real, complex, or ``zomplex.'' In its basic form, the matrix {\tt A} contains: \begin{itemize} \item {\tt A->p}, an integer array of size {\tt A->ncol+1}. \item {\tt A->i}, an integer array of size {\tt A->nzmax}. \item {\tt A->x}, a {\tt double} array of size {\tt A->nzmax} or twice that for the complex case. This is compatible with the Fortran and ANSI C99 complex data type. \item {\tt A->z}, a {\tt double} array of size {\tt A->nzmax} if {\tt A} is zomplex. A zomplex matrix has a {\tt z} array, thus the name. This is compatible with the MATLAB representation of complex matrices. \end{itemize} For all four types of matrices, the row indices of entries of column {\tt j} are located in {\tt A->i [A->p [j] ... A->p [j+1]-1]}. For a real matrix, the corresponding numerical values are in {\tt A->x} at the same location. For a complex matrix, the entry whose row index is {\tt A->i [p]} is contained in {\tt A->x [2*p]} (the real part) and {\tt A->x [2*p+1]} (the imaginary part). For a zomplex matrix, the real part is in {\tt A->x [p]} and imaginary part is in {\tt A->z [p]}. See Section~\ref{cholmod_sparse} for more details. \item {\tt cholmod\_factor}: A symbolic or numeric factorization, either real, complex, or zomplex. It can be either an $\m{LL}\tr$ or $\m{LDL}\tr$ factorization, and either simplicial or supernodal. You will normally not need to examine its contents. See Section~\ref{cholmod_factor} for more details. \item {\tt cholmod\_dense}: A dense matrix, either real, complex or zomplex, in column-major order. This differs from the row-major convention used in C. A dense matrix {\tt X} contains \begin{itemize} \item {\tt X->x}, a double array of size {\tt X->nzmax} or twice that for the complex case. \item {\tt X->z}, a double array of size {\tt X->nzmax} if {\tt X} is zomplex. \end{itemize} For a real dense matrix $x_{ij}$ is {\tt X->x [i+j*d]} where {\tt d = X->d} is the leading dimension of {\tt X}. For a complex dense matrix, the real part of $x_{ij}$ is {\tt X->x [2*(i+j*d)]} and the imaginary part is {\tt X->x [2*(i+j*d)+1]}. For a zomplex dense matrix, the real part of $x_{ij}$ is {\tt X->x [i+j*d]} and the imaginary part is {\tt X->z [i+j*d]}. Real and complex dense matrices can be passed to LAPACK and the BLAS. See Section~\ref{cholmod_dense} for more details. \item {\tt cholmod\_triplet}: CHOLMOD's sparse matrix ({\tt cholmod\_sparse}) is the primary input for nearly all CHOLMOD routines, but it can be difficult for the user to construct. A simpler method of creating a sparse matrix is to first create a {\tt cholmod\_triplet} matrix, and then convert it to a {\tt cholmod\_sparse} matrix via the {\tt cholmod\_triplet\_to\_sparse} routine. In its basic form, the triplet matrix {\tt T} contains \begin{itemize} \item {\tt T->i} and {\tt T->j}, integer arrays of size {\tt T->nzmax}. \item {\tt T->x}, a double array of size {\tt T->nzmax} or twice that for the complex case. \item {\tt T->z}, a double array of size {\tt T->nzmax} if {\tt T} is zomplex. \end{itemize} The {\tt k}th entry in the data structure has row index {\tt T->i [k]} and column index {\tt T->j [k]}. For a real triplet matrix, its numerical value is {\tt T->x [k]}. For a complex triplet matrix, its real part is {\tt T->x [2*k]} and its imaginary part is {\tt T->x [2*k+1]}. For a zomplex matrix, the real part is {\tt T->x [k]} and imaginary part is {\tt T->z [k]}. The entries can be in any order, and duplicates are permitted. See Section~\ref{cholmod_triplet} for more details. \end{enumerate} Each of the five objects has a routine in CHOLMOD to create and destroy it. CHOLMOD provides many other operations on these objects as well. A few of the most important ones are illustrated in the sample program in the next section. %------------------------------------------------------------------------------- \newpage \section{Simple example program} %------------------------------------------------------------------------------- \input{_simple.tex} The {\tt Demo/cholmod\_simple.c} program illustrates the basic usage of CHOLMOD. It reads a triplet matrix from a file (in Matrix Market format), converts it into a sparse matrix, creates a linear system, solves it, and prints the norm of the residual. See the {\tt CHOLMOD/Demo/cholmod\_demo.c} program for a more elaborate example, and \newline {\tt CHOLMOD/Demo/cholmod\_l\_demo.c} for its {\tt long} integer version. %------------------------------------------------------------------------------- \newpage \section{Installation of the C-callable library} \label{Install} %------------------------------------------------------------------------------- CHOLMOD requires a suite of external packages, many of which are distributed along with CHOLMOD, but three of which are not. Those included with CHOLMOD are: \begin{itemize} \item AMD: an approximate minimum degree ordering algorithm, by Tim Davis, Patrick Amestoy, and Iain Duff \cite{AmestoyDavisDuff96,AmestoyDavisDuff03}. \item COLAMD: an approximate column minimum degree ordering algorithm, by Tim Davis, Stefan Larimore, John Gilbert, and Esmond Ng \cite{DavisGilbertLarimoreNg00_algo,DavisGilbertLarimoreNg00}. \item CCOLAMD: a constrained approximate column minimum degree ordering algorithm, by Tim Davis and Siva Rajamanickam, based directly on COLAMD. This package is not required if CHOLMOD is compiled with the {\tt -DNPARTITION} flag. \item CAMD: a constrained approximate minimum degree ordering algorithm, by Tim Davis and Yanqing Chen, based directly on AMD. This package is not required if CHOLMOD is compiled with the {\tt -DNPARTITION} flag. \item {\tt UFconfig}: a single place where all sparse matrix packages authored or co-authored by Davis are configured. Also includes a version of the {\tt xerbla} routine for the BLAS. \end{itemize} Three other packages are required for optimal performance: \begin{itemize} \item {\tt METIS 4.0.1}: a graph partitioning package by George Karypis, Univ. of Minnesota. Not needed if {\tt -DNPARTITION} is used. See http://www-users.cs.umn.edu/$\sim$karypis/metis. \item BLAS: the Basic Linear Algebra Subprograms. Not needed if {\tt -DNSUPERNODAL} is used. See http://www.netlib.org for the reference BLAS (not meant for production use). For Kazushige Goto's optimized BLAS (highly recommended for CHOLMOD) see \newline http://www.tacc.utexas.edu/$\sim$kgoto/ or http://www.cs.utexas.edu/users/flame/goto/. I recommend that you avoid the Intel MKL BLAS; one recent version returns NaN's, where both the Goto BLAS and the standard Fortran reference BLAS return the correct answer. See {\tt CHOLMOD/README} for more information. \item LAPACK: the Basic Linear Algebra Subprograms. Not needed if {\tt -DNSUPERNODAL} is used. See http://www.netlib.org. \end{itemize} You must first obtain and install METIS, LAPACK, and the BLAS. Next edit the system-dependent configurations in the {\tt UFconfig/UFconfig.mk} file. Sample configurations are provided for Linux, Macintosh, Sun Solaris, SGI IRIX, IBM AIX, and the DEC/Compaq Alpha. The most important configuration is the location of the BLAS, LAPACK, and METIS packages, since in its default configuration CHOLMOD cannot be compiled without them. \noindent Here are the various parameters that you can control in your {\tt UFconfig/UFconfig.mk} file: \begin{itemize} \item {\tt CC = } your C compiler, such as {\tt cc}. \item {\tt CFLAGS = } optimization flags, such as {\tt -O}. \item {\tt RANLIB = } your system's {\tt ranlib} program, if needed. \item {\tt AR =} the command to create a library (such as {\tt ar}). \item {\tt RM =} the command to delete a file. \item {\tt MV =} the command to rename a file. \item {\tt F77 =} the command to compile a Fortran program (optional). \item {\tt F77FLAGS =} the Fortran compiler flags (optional). \item {\tt F77LIB =} the Fortran libraries (optional). \item {\tt LIB = } basic libraries, such as {\tt -lm}. \item {\tt MEX =} the command to compile a MATLAB mexFunction. \item {\tt BLAS =} your BLAS library. \item {\tt LAPACK =} your LAPACK library. \item {\tt XERBLA =} a library containing the BLAS {\tt xerbla} routine, if required. \item {\tt METIS\_PATH =} the path to your copy of the METIS 4.0.1 source code. \item {\tt METIS =} your METIS library. \item {\tt CHOLMOD\_CONFIG = } configuration settings specific to CHOLMOD. \end{itemize} \noindent CHOLMOD's specific settings are given by the {\tt CHOLMOD\_CONFIG} string: \begin{itemize} \item {\tt -DNCHECK}: do not include the Check module. License: GNU LGPL. \item {\tt -DNCHOLESKY}: do not include the Cholesky module. License: GNU LGPL. \item {\tt -DNPARTITION}: do not include the Partition module. License: GNU LGPL. \item {\tt -DNGPL}: do not include any GNU GPL Modules in the CHOLMOD library. \item {\tt -DNMATRIXOPS}: do not include the MatrixOps module. License: GNU GPL. \item {\tt -DNMODIFY}: do not include the Modify module. License: GNU GPL. \item {\tt -DNSUPERNODAL}: do not include the Supernodal module. License: GNU GPL. \item {\tt -DNPRINT}: do not print anything. \item {\tt -D'LONGBLAS=long'} or {\tt -DLONGBLAS='long long'} defines the integers used by LAPACK and the BLAS (defaults to {\tt int}). \item {\tt -DNSUNPERF}: for Solaris only. If defined, do not use the Sun Performance Library. \item {\tt -DNLARGEFILE}: CHOLMOD now assumes support for large files (2GB or larger). If this causes problems, you can compile CHOLMOD with -DNLARGEFILE. To use large files, you should {\tt \#include "cholmod.h"} (or at least {\tt \#include "cholmod\_io64.h"}) before any other {\tt \#include} statements, in your application that uses CHOLMOD. You may need to use {\tt fopen64} to create a file pointer to pass to CHOLMOD, if you are using a non-gcc compiler. \end{itemize} Type {\tt make} in the {\tt CHOLMOD} directory. The AMD, COLAMD, CAMD, CCOLAMD, and {\tt CHOLMOD} libraries will be compiled, as will the C version of the null-output {\tt xerbla} routine in case you need it. No Fortran compiler is required in this case. A short demo program will be compiled and tested on a few matrices. The residuals should all be small. Compare your output with the {\tt CHOLMOD/Demo/make.out} file. CHOLMOD is now ready for use in your own applications. You must link your programs with the {\tt CHOLMOD/Lib/libcholmod.a}, {\tt AMD/Lib/libamd.a}, {\tt COLAMD/libcolamd.a}, {\tt CAMD/libcamd.a}, \newline {\tt CCOLAMD/libccolamd.a}, {\tt metis-4.0/libmetis.a}, LAPACK, and BLAS libraries, as well as the {\tt xerbla} library if you need it ({\tt UFconfig/xerlib/libcerbla.a} for the C version or \newline {\tt UFconfig/xerlib/libxerbla.a} for the Fortran version). Your compiler needs to know the location of the CHOLMOD {\tt Include} directory, so that it can find the {\tt cholmod.h} include file, by adding the {\tt -ICHOLMOD/Include} to your C compiler options (modified appropriately to reflect the location of your copy of CHOLMOD). %------------------------------------------------------------------------------- \newpage \section{Using CHOLMOD in MATLAB} %------------------------------------------------------------------------------- CHOLMOD includes a set of m-files and mexFunctions in the CHOLMOD/MATLAB directory. The following functions are provided: \vspace{0.1in} \begin{tabular}{ll} \hline {\tt analyze} & order and analyze a matrix \\ {\tt bisect} & find a node separator \\ {\tt chol2} & same as {\tt chol} \\ {\tt cholmod2} & same as {\tt x=A}$\backslash${\tt b} if {\tt A} is symmetric positive definite \\ {\tt cholmod\_demo} & a short demo program \\ {\tt cholmod\_make} & compiles CHOLMOD for use in MATLAB \\ {\tt etree2} & same as {\tt etree} \\ {\tt graph\_demo} & graph partitioning demo \\ {\tt lchol} & {\tt L*L'} factorization \\ {\tt ldlchol} & {\tt L*D*L'} factorization \\ {\tt ldl\_normest} & estimate {\tt norm(A-L*D*L')} \\ {\tt ldlsolve} & {\tt x = L'}$\backslash${\tt (D}$\backslash${\tt (L}$\backslash${\tt b))} \\ {\tt ldlsplit} & split the output of {\tt ldlchol} into {\tt L} and {\tt D} \\ {\tt ldlupdate} & update/downdate an {\tt L*D*L'} factorization \\ {\tt metis} & interface to {\tt METIS\_NodeND} ordering \\ {\tt mread} & read a sparse or dense Matrix Market file \\ {\tt mwrite} & write a sparse or dense Matrix Market file \\ {\tt nesdis} & CHOLMOD's nested dissection ordering \\ {\tt resymbol} & recomputes the symbolic factorization \\ {\tt sdmult} & {\tt S*F} where {\tt S} is sparse and {\tt F} is dense \\ {\tt spsym} & determine symmetry \\ {\tt sparse2} & same as {\tt sparse} \\ {\tt symbfact2} & same as {\tt symbfact} \\ \hline \end{tabular} \vspace{0.1in}\noindent Each function is described in the next sections. \newpage \subsection{{\tt analyze}: order and analyze} \input{_analyze_m.tex} \subsection{{\tt bisect}: find a node separator} \input{_bisect_m.tex} \subsection{{\tt chol2}: same as {\tt chol}} \input{_chol2_m.tex} \newpage \subsection{{\tt cholmod2}: supernodal backslash} \input{_cholmod2_m.tex} \newpage \subsection{{\tt cholmod\_demo}: a short demo program} \input{_cholmod_demo_m.tex} \subsection{{\tt cholmod\_make}: compile CHOLMOD in MATLAB} \input{_cholmod_make_m.tex} \newpage \subsection{{\tt etree2}: same as {\tt etree}} \input{_etree2_m.tex} \subsection{{\tt graph\_demo}: graph partitioning demo} \input{_graph_demo_m.tex} \newpage \subsection{{\tt lchol}: $\m{LL}\tr$ factorization} \input{_lchol_m.tex} \subsection{{\tt ldlchol}: $\m{LDL}\tr$ factorization} \input{_ldlchol_m.tex} \newpage \subsection{{\tt ldlsolve}: solve using an $\m{LDL}\tr$ factorization} \input{_ldlsolve_m.tex} \subsection{{\tt ldlsplit}: split an $\m{LDL}\tr$ factorization} \input{_ldlsplit_m.tex} \newpage \subsection{{\tt ldlupdate}: update/downdate an $\m{LDL}\tr$ factorization} \input{_ldlupdate_m.tex} \newpage \subsection{{\tt mread}: read a sparse or dense matrix from a Matrix Market file}\input{_mread_m.tex} \subsection{{\tt mwrite}: write a sparse or densematrix to a Matrix Market file} \input{_mwrite_m.tex} \newpage \subsection{{\tt metis}: order with METIS} \input{_metis_m.tex} \newpage \subsection{{\tt nesdis}: order with CHOLMOD nested dissection} \input{_nesdis_m.tex} \newpage \subsection{{\tt resymbol}: re-do symbolic factorization} \input{_resymbol_m.tex} \subsection{{\tt sdmult}: sparse matrix times dense matrix} \input{_sdmult_m.tex} \newpage \subsection{{\tt spsym}: determine symmetry} \input{_spsym_m.tex} \newpage \subsection{{\tt sparse2}: same as {\tt sparse}} \input{_sparse2_m.tex} \newpage \subsection{{\tt symbfact2}: same as {\tt symbfact}} \input{_symbfact2_m.tex} %------------------------------------------------------------------------------- \newpage \section{Installation for use in MATLAB} %------------------------------------------------------------------------------- If you wish to use METIS within CHOLMOD, you should first obtain a copy of METIS 4.0.1. See http://www-users.cs.umn.edu/$\sim$karypis/metis. Place your copy of the {\tt metis-4.0} directory (folder, for Windows users) in the same directory that contains your copy of the {\tt CHOLMOD} directory. If you do not have METIS, however, you can still use CHOLMOD. Some of the CHOLMOD functions will not be available ({\tt metis}, {\tt bisect}, and {\tt nesdis}), and you may experience higher fill-in for large matrices (particularly those arising in 3D finite-element problems) when using {\tt analyze}, {\tt chol2}, {\tt cholmod2}, {\tt lchol}, and {\tt ldlchol}. There are two methods for compiling CHOLMOD for use in MATLAB; both are described below. %------------------------------------------------------------------------------- \subsection{{\tt cholmod\_make}: compiling CHOLMOD in MATLAB} %------------------------------------------------------------------------------- This is the preferred method, since it allows METIS to be reconfigured to use the MATLAB memory-management functions instead of {\tt malloc} and {\tt free}; this avoids the issue of METIS terminating MATLAB if it runs out of memory. It is also simpler for Windows users, who do not have the {\tt make} command (unless you obtain a copy of {\tt Cygwin}). Start MATLAB, {\tt cd} to the {\tt CHOLMOD/MATLAB} directory, and type {\tt cholmod\_make} in the MATLAB command window. This will compile the MATLAB interfaces for AMD, COLAMD, CAMD, CCOLAMD, METIS, and CHOLMOD. If you do not have METIS, type {\tt cholmod\_make('')}. If your copy of METIS is in another location, type {\tt cholmod\_make ('path')} where {\tt path} is the pathname of your copy of the {\tt metis-4.0} directory. When METIS is compiled {\tt malloc}, {\tt free}, {\tt calloc}, and {\tt realloc} are redefined to the MATLAB-equivalents ({\tt mxMalloc}, ...). These memory-management functions safely terminate a mexFunction if they fail, and will free all memory allocated by the mexFunction. Thus, METIS will safely abort without terminating MATLAB, if it runs out of memory. The {\tt cholmod\_make} handles this redefinition without making any changes to your METIS source code. %------------------------------------------------------------------------------- \subsection{Unix {\tt make} for compiling CHOLMOD} %------------------------------------------------------------------------------- You can also compile the CHOLMOD mexFunctions using the Unix/Linux {\tt make} command. When using the {\tt gcc} compiler, I strongly recommend editing the {\tt metis-4.0/Makefile.in} file and changing {\tt COPTIONS} to \begin{verbatim} COPTIONS = -fexceptions \end{verbatim} Also ensure {\tt -fexceptions} is in the {\tt CFLAGS} option in the {\tt UFconfig/UFconfig.mk} file that comes with CHOLMOD. If you do not make these modifications, the CHOLMOD mexFunctions will terminate MATLAB if they encounter an error. If you have MATLAB 7.2 or earlier and use {\tt make mex} in the {\tt CHOLMOD} directory (equivalently, {\tt make} in {\tt CHOLMOD/MATLAB}), you must first edit {\tt UFconfig/UFconfig.h} to remove the {\tt -largeArrayDims} option from the MEX command (or just use {\tt cholmod\_make.m} inside MATLAB). Next, compile your METIS 4.0.1 library by typing {\tt make} in the {\tt metis-4.0} directory. Then type {\tt make} in the {\tt CHOLMOD/MATLAB} directory. This will compile the C-callable libraries for AMD, COLAMD, CAMD, CCOLAMD, METIS, and CHOLMOD, and then compile the mexFunction interfaces to those libraries. If METIS tries {\tt malloc} and encounters an out-of-memory condition, it calls {\tt abort}, which will terminate MATLAB. This problem does not occur using the method described in the previous section. %------------------------------------------------------------------------------- \newpage \section{Integer and floating-point types, and notation used} %------------------------------------------------------------------------------- CHOLMOD supports both {\tt int} and {\tt long} integers. CHOLMOD routines with the prefix {\tt cholmod\_} use {\tt int} integers, {\tt cholmod\_l\_} routines use {\tt long}. All floating-point values are {\tt double}. The {\tt long} integer is redefinable, via {\tt UFconfig.h}. That file defines a C preprocessor token {\tt UF\_long} which is {\tt long} on all systems except for Windows-64, in which case it is defined as {\tt \_\_int64}. The intent is that with suitable compile-time switches, {\tt int} is a 32-bit integer and {\tt UF\_long} is a 64-bit integer. The term {\tt long} is used to describe the latter integer throughout this document (except in the prototypes). Two kinds of complex matrices are supported: complex and zomplex. A complex matrix is held in a manner that is compatible with the Fortran and ANSI C99 complex data type. A complex array of size {\tt n} is a {\tt double} array {\tt x} of size {\tt 2*n}, with the real and imaginary parts interleaved (the real part comes first, as a {\tt double}, followed the imaginary part, also as a {\tt double}. Thus, the real part of the {\tt k}th entry is {\tt x[2*k]} and the imaginary part is {\tt x[2*k+1]}. A zomplex matrix of size {\tt n} stores its real part in one {\tt double} array of size {\tt n} called {\tt x} and its imaginary part in another {\tt double} array of size {\tt n} called {\tt z} (thus the name ``zomplex''). This also how MATLAB stores its complex matrices. The real part of the {\tt k}th entry is {\tt x[k]} and the imaginary part is {\tt z[k]}. Unlike {\tt UMFPACK}, the same routine name in CHOLMOD is used for pattern-only, real, complex, and zomplex matrices. For example, the statement \begin{verbatim} C = cholmod_copy_sparse (A, &Common) ; \end{verbatim} creates a copy of a pattern, real, complex, or zomplex sparse matrix {\tt A}. The xtype (pattern, real, complex, or zomplex) of the resulting sparse matrix {\tt C} is the same as {\tt A} (a pattern-only sparse matrix contains no floating-point values). In the above case, {\tt C} and {\tt A} use {\tt int} integers. For {\tt long} integers, the statement would become: \begin{verbatim} C = cholmod_l_copy_sparse (A, &Common) ; \end{verbatim} The last parameter of all CHOLMOD routines is always {\tt \&Common}, a pointer to the {\tt cholmod\_common} object, which contains parameters, statistics, and workspace used throughout CHOLMOD. The {\tt xtype} of a CHOLMOD object (sparse matrix, triplet matrix, dense matrix, or factorization) determines whether it is pattern-only, real, complex, or zomplex. The names of the {\tt int} versions are primarily used in this document. To obtain the name of the {\tt long} version of the same routine, simply replace {\tt cholmod\_} with {\tt cholmod\_l\_}. MATLAB matrix notation is used throughout this document and in the comments in the CHOLMOD code itself. If you are not familiar with MATLAB, here is a short introduction to the notation, and a few minor variations used in CHOLMOD: \begin{itemize} \item {\tt C=A+B} and {\tt C=A*B}, respectively are a matrix add and multiply if both {\tt A} and {\tt B} are matrices of appropriate size. If {\tt A} is a scalar, then it is added to or multiplied with every entry in {\tt B}. \item {\tt a:b} where {\tt a} and {\tt b} are integers refers to the sequence {\tt a}, {\tt a+1}, ... {\tt b}. \item {\tt [A B]} and {\tt [A,B]} are the horizontal concatenation of {\tt A} and {\tt B}. \item {\tt [A;B]} is the vertical concatenation of {\tt A} and {\tt B}. \item {\tt A(i,j)} can refer either to a scalar or a submatrix. For example: \newline \vspace{0.05in} \begin{tabular}{ll} \hline {\tt A(1,1)} & a scalar. \\ {\tt A(:,j)} & column {\tt j} of {\tt A}. \\ {\tt A(i,:)} & row {\tt i} of {\tt A}. \\ {\tt A([1 2], [1 2])} & a 2-by-2 matrix containing the 2-by-2 leading minor of {\tt A}. \\ \hline \end{tabular} \newline \vspace{0.1in} If {\tt p} is a permutation of {\tt 1:n}, and {\tt A} is {\tt n}-by-{\tt n}, then {\tt A(p,p)} corresponds to the permuted matrix $\m{PAP}\tr$. \item {\tt tril(A)} is the lower triangular part of {\tt A}, including the diagonal. \item {\tt tril(A,k)} is the lower triangular part of {\tt A}, including entries on and below the $k$th diagonal. \item {\tt triu(A)} is the upper triangular part of {\tt A}, including the diagonal. \item {\tt triu(A,k)} is the upper triangular part of {\tt A}, including entries on and above the $k$th diagonal. \item {\tt size(A)} returns the dimensions of {\tt A}. \item {\tt find(x)} if {\tt x} is a vector returns a list of indices {\tt i} for which {\tt x(i)} is nonzero. \item {\tt A'} is the transpose of {\tt A} if {\tt A} is real, or the complex conjugate transpose if {\tt A} is complex. \item {\tt A.'} is the array transpose of {\tt A}. \item {\tt diag(A)} is the diagonal of {\tt A} if {\tt A} is a matrix. \item {\tt C=diag(s)} is a diagonal matrix if {\tt s} is a vector, with the values of {\tt s} on the diagonal of {\tt C}. \item {\tt S=spones(A)} returns a binary matrix {\tt S} with the same nonzero pattern of {\tt A}. \item {\tt nnz(A)} is the number of nonzero entries in {\tt A}. \end{itemize} \noindent Variations to MATLAB notation used in this document: \begin{itemize} \item CHOLMOD uses 0-based notation (the first entry in the matrix is {\tt A(0,0)}). MATLAB is 1-based. The context is usually clear. \item {\tt I} is the identity matrix. \item {\tt A(:,f)}, where {\tt f} is a set of columns, is interpreted differently in CHOLMOD, but just for the set named {\tt f}. See {\tt cholmod\_transpose\_unsym} for details. \end{itemize} %------------------------------------------------------------------------------- \newpage \section{The CHOLMOD Modules, objects, and functions} \label{Modules} %------------------------------------------------------------------------------- CHOLMOD contains a total of 133 {\tt int}-based routines (and the same number of {\tt long} routines), divided into a set of inter-related Modules. Each Module contains a set of related functions. The functions are divided into two types: Primary and Secondary, to reflect how a user will typically use CHOLMOD. Most users will find the Primary routines to be sufficient to use CHOLMOD in their programs. Each Module exists as a sub-directory (a folder for Windows users) within the CHOLMOD directory (or folder). \vspace{0.1in} \noindent There are seven Modules that provide user-callable routines for CHOLMOD. \begin{enumerate} \item {\tt Core}: basic data structures and definitions \item {\tt Check}: prints/checks each of CHOLMOD's objects \item {\tt Cholesky}: sparse Cholesky factorization \item {\tt Modify}: sparse Cholesky update/downdate and row-add/row-delete \item {\tt MatrixOps}: sparse matrix operators (add, multiply, norm, scale) \item {\tt Supernodal}: supernodal sparse Cholesky factorization \item {\tt Partition}: graph-partitioning-based orderings \end{enumerate} \noindent Two additional Modules are required to compile the CHOLMOD library: \begin{enumerate} \item {\tt Include}: include files for CHOLMOD and programs that use CHOLMOD \item {\tt Lib}: where the CHOLMOD library is built \end{enumerate} \noindent Five additional Modules provide support functions and documentation: \begin{enumerate} \item {\tt Demo}: simple programs that illustrate the use of CHOLMOD \item {\tt Doc}: documentation (including this document) \item {\tt MATLAB}: CHOLMOD's interface to MATLAB \item {\tt Tcov}: an exhaustive test coverage (requires Linux or Solaris) \item {\tt Valgrind}: runs the {\tt Tcov} test under {\tt valgrind} (requires Linux) \end{enumerate} The following Modules are licensed under the GNU Lesser General Public License: {\tt Check}, {\tt Cholesky}, {\tt Core}, and {\tt Partition}. The following Modules are licensed under the GNU General Public License: {\tt Demo}, {\tt Modify}, {\tt MatrixOps}, {\tt Supernodal}, the {\tt MATLAB} Module (not MATLAB itself!), {\tt Tcov}, and {\tt Valgrind}. The files in the {\tt Include} Module are licensed according to their respective Modules. The {\tt Lib} and {\tt Doc} Modules need no license; the compiled binaries are licensed the same as their source code. %------------------------------------------------------------------------------- \newpage \subsection{{\tt Core} Module: basic data structures and definitions} %------------------------------------------------------------------------------- CHOLMOD includes five basic objects, defined in the {\tt Core} Module. The {\tt Core Module} provides basic operations for these objects and is required by all six other CHOLMOD library Modules: \subsubsection{{\tt cholmod\_common}: parameters, statistics, and workspace} You must call {\tt cholmod\_start} before calling any other CHOLMOD routine, and you must call {\tt cholmod\_finish} as your last call to CHOLMOD (with the exception of {\tt cholmod\_print\_common} and {\tt cholmod\_check\_common} in the {\tt Check} Module). Once the {\tt cholmod\_common} object is initialized, the user may modify CHOLMOD's parameters held in this object, and obtain statistics on CHOLMOD's activity. \vspace{0.1in} \noindent Primary routines for the {\tt cholmod\_common} object: % 2 \begin{itemize} \item {\tt cholmod\_start}: the first call to CHOLMOD. \item {\tt cholmod\_finish}: the last call to CHOLMOD (frees workspace in the {\tt cholmod\_common} object). \end{itemize} \noindent Secondary routines for the {\tt cholmod\_common} object: % 9 \begin{itemize} \item {\tt cholmod\_defaults}: restores default parameters \item {\tt cholmod\_maxrank}: determine maximum rank for update/downdate. \item {\tt cholmod\_allocate\_work}: allocate workspace. \item {\tt cholmod\_free\_work}: free workspace. \item {\tt cholmod\_clear\_flag}: clear {\tt Flag} array. \item {\tt cholmod\_error}: called when CHOLMOD encounters and error. \item {\tt cholmod\_dbound}: bounds the diagonal of $\m{L}$ or $\m{D}$. \item {\tt cholmod\_hypot}: compute {\tt sqrt(x*x+y*y)} accurately. \item {\tt cholmod\_divcomplex}: complex divide. \end{itemize} %------------------------------------------------------------------------------- \newpage \subsubsection{{\tt cholmod\_sparse}: a sparse matrix in compressed column form} %------------------------------------------------------------------------------- A sparse matrix {\tt A} is held in compressed column form. In the basic type (``packed,'' which corresponds to how MATLAB stores its sparse matrices), and {\tt nrow}-by-{\tt ncol} matrix with {\tt nzmax} entries is held in three arrays: {\tt p} of size {\tt ncol+1}, {\tt i} of size {\tt nzmax}, and {\tt x} of size {\tt nzmax}. Row indices of nonzero entries in column {\tt j} are held in {\tt i [p[j] ... p[j+1]-1]}, and their corresponding numerical values are held in {\tt x [p[j] ... p[j+1]-1]}. The first column starts at location zero ({\tt p[0]=0}). There may be no duplicate entries. Row indices in each column may be sorted or unsorted (the {\tt A->sorted} flag must be false if the columns are unsorted). The {\tt A->stype} determines the storage mode: 0 if the matrix is unsymmetric, 1 if the matrix is symmetric with just the upper triangular part stored, and -1 if the matrix is symmetric with just the lower triangular part stored. In ``unpacked'' form, an additional array {\tt nz} of size {\tt ncol} is used. The end of column {\tt j} in {\tt i} and {\tt x} is given by {\tt p[j]+nz[j]}. Columns not need be in any particular order ({\tt p[0]} need not be zero), and there may be gaps between the columns. \vspace{0.1in} \noindent Primary routines for the {\tt cholmod\_sparse} object: % 2 \begin{itemize} \item {\tt cholmod\_allocate\_sparse}: allocate a sparse matrix \item {\tt cholmod\_free\_sparse}: free a sparse matrix \end{itemize} \noindent Secondary routines for the {\tt cholmod\_sparse} object: % 16 \begin{itemize} \item {\tt cholmod\_reallocate\_sparse}: change the size (number of entries) of a sparse matrix. \item {\tt cholmod\_nnz}: number of nonzeros in a sparse matrix. \item {\tt cholmod\_speye}: sparse identity matrix. \item {\tt cholmod\_spzeros}: sparse zero matrix. \item {\tt cholmod\_transpose}: transpose a sparse matrix. \item {\tt cholmod\_ptranspose}: transpose/permute a sparse matrix. \item {\tt cholmod\_transpose\_unsym}: transpose/permute an unsymmetric sparse matrix. \item {\tt cholmod\_transpose\_sym}: transpose/permute a symmetric sparse matrix. \item {\tt cholmod\_sort}: sort row indices in each column of a sparse matrix. \item {\tt cholmod\_band}: extract a band of a sparse matrix. \item {\tt cholmod\_band\_inplace}: remove entries not with a band. \item {\tt cholmod\_aat}: {\tt C = A*A'}. \item {\tt cholmod\_copy\_sparse}: {\tt C = A}, create an exact copy of a sparse matrix. \item {\tt cholmod\_copy}: {\tt C = A}, with possible change of {\tt stype}. \item {\tt cholmod\_add}: {\tt C = alpha*A + beta*B}. \item {\tt cholmod\_sparse\_xtype}: change the {\tt xtype} of a sparse matrix. \end{itemize} %------------------------------------------------------------------------------- \newpage \subsubsection{{\tt cholmod\_factor}: a symbolic or numeric factorization} %------------------------------------------------------------------------------- A factor can be in $\m{LL}\tr$ or $\m{LDL}\tr$ form, and either supernodal or simplicial form. In simplicial form, this is very much like a packed or unpacked {\tt cholmod\_sparse} matrix. In supernodal form, adjacent columns with similar nonzero pattern are stored as a single block (a supernode). \vspace{0.1in} \noindent Primary routine for the {\tt cholmod\_factor} object: % 1 \begin{itemize} \item {\tt cholmod\_free\_factor}: free a factor \end{itemize} \noindent Secondary routines for the {\tt cholmod\_factor} object: % 8 \begin{itemize} \item {\tt cholmod\_allocate\_factor}: allocate a factor. You will normally use {\tt cholmod\_analyze} to create a factor. \item {\tt cholmod\_reallocate\_factor}: change the number of entries in a factor. \item {\tt cholmod\_change\_factor}: change the type of a factor ($\m{LDL}\tr$ to $\m{LL}\tr$, supernodal to simplicial, etc.). \item {\tt cholmod\_pack\_factor}: pack the columns of a factor. \item {\tt cholmod\_reallocate\_column}: resize a single column of a factor. \item {\tt cholmod\_factor\_to\_sparse}: create a sparse matrix copy of a factor. \item {\tt cholmod\_copy\_factor}: create a copy of a factor. \item {\tt cholmod\_factor\_xtype}: change the xtype of a factor. \end{itemize} %------------------------------------------------------------------------------- \subsubsection{{\tt cholmod\_dense}: a dense matrix} %------------------------------------------------------------------------------- This consists of a dense array of numerical values and its dimensions. \vspace{0.1in} \noindent Primary routines for the {\tt cholmod\_dense} object: % 2 \begin{itemize} \item {\tt cholmod\_allocate\_dense}: allocate a dense matrix. \item {\tt cholmod\_free\_dense}: free a dense matrix. \end{itemize} \vspace{0.1in} \noindent Secondary routines for the {\tt cholmod\_dense} object: % 8 \begin{itemize} \item {\tt cholmod\_zeros}: allocate a dense matrix of all zeros. \item {\tt cholmod\_ones}: allocate a dense matrix of all ones. \item {\tt cholmod\_eye}: allocate a dense identity matrix . \item {\tt cholmod\_sparse\_to\_dense}: create a dense matrix copy of a sparse matrix. \item {\tt cholmod\_dense\_to\_sparse}: create a sparse matrix copy of a dense matrix. \item {\tt cholmod\_copy\_dense}: create a copy of a dense matrix. \item {\tt cholmod\_copy\_dense2}: copy a dense matrix (pre-allocated). \item {\tt cholmod\_dense\_xtype}: change the {\tt xtype} of a dense matrix. \end{itemize} %------------------------------------------------------------------------------- \newpage \subsubsection{{\tt cholmod\_triplet}: a sparse matrix in ``triplet'' form} %------------------------------------------------------------------------------- The {\tt cholmod\_sparse} matrix is the basic sparse matrix used in CHOLMOD, but it can be difficult for the user to construct. It also does not easily support the inclusion of new entries in the matrix. The {\tt cholmod\_triplet} matrix is provided to address these issues. A sparse matrix in triplet form consists of three arrays of size {\tt nzmax}: {\tt i}, {\tt j}, and {\tt x}, and a {\tt z} array for the zomplex case. \vspace{0.1in} \noindent Primary routines for the {\tt cholmod\_triplet} object: % 3 \begin{itemize} \item {\tt cholmod\_allocate\_triplet}: allocate a triplet matrix. \item {\tt cholmod\_free\_triplet}: free a triplet matrix. \item {\tt cholmod\_triplet\_to\_sparse}: create a sparse matrix copy of a triplet matrix. \end{itemize} \noindent Secondary routines for the {\tt cholmod\_triplet} object: % 4 \begin{itemize} \item {\tt cholmod\_reallocate\_triplet}: change the number of entries in a triplet matrix. \item {\tt cholmod\_sparse\_to\_triplet}: create a triplet matrix copy of a sparse matrix. \item {\tt cholmod\_copy\_triplet}: create a copy of a triplet matrix. \item {\tt cholmod\_triplet\_xtype}: change the {\tt xtype} of a triplet matrix. \end{itemize} %------------------------------------------------------------------------------- \subsubsection{Memory management routines} %------------------------------------------------------------------------------- By default, CHOLMOD uses the ANSI C {\tt malloc}, {\tt free}, {\tt calloc}, and {\tt realloc} routines. You may use different routines by modifying function pointers in the {\tt cholmod\_common} object. \vspace{0.1in} \noindent Primary routines: % 2 \begin{itemize} \item {\tt cholmod\_malloc}: {\tt malloc} wrapper. \item {\tt cholmod\_free}: {\tt free} wrapper. \end{itemize} \noindent Secondary routines: % 3 \begin{itemize} \item {\tt cholmod\_calloc}: {\tt calloc} wrapper. \item {\tt cholmod\_realloc}: {\tt realloc} wrapper. \item {\tt cholmod\_realloc\_multiple}: {\tt realloc} wrapper for multiple objects. \end{itemize} %------------------------------------------------------------------------------- \newpage \subsection{{\tt Check} Module: print/check the CHOLMOD objects} %------------------------------------------------------------------------------- The {\tt Check} Module contains routines that check and print the five basic objects in CHOLMOD, and three kinds of integer vectors (a set, a permutation, and a tree). It also provides a routine to read a sparse matrix from a file in Matrix Market format (http://www.nist.gov/MatrixMarket). Requires the {\tt Core} Module. \vspace{0.1in} \noindent Primary routines: % 4 \begin{itemize} \item {\tt cholmod\_print\_common}: print the {\tt cholmod\_common} object, including statistics on CHOLMOD's behavior (fill-in, flop count, ordering methods used, and so on). \item {\tt cholmod\_write\_sparse}: write a sparse matrix to a file in Matrix Market format. \item {\tt cholmod\_write\_dense}: write a sparse matrix to a file in Matrix Market format. \item {\tt cholmod\_read\_matrix}: read a sparse or dense matrix from a file in Matrix Market format. \end{itemize} \vspace{0.1in} \noindent Secondary routines: % 18 \begin{itemize} \item {\tt cholmod\_check\_common}: check the {\tt cholmod\_common} object \item {\tt cholmod\_check\_sparse}: check a sparse matrix \item {\tt cholmod\_print\_sparse}: print a sparse matrix \item {\tt cholmod\_check\_dense}: check a dense matrix \item {\tt cholmod\_print\_dense}: print a dense matrix \item {\tt cholmod\_check\_factor}: check a Cholesky factorization \item {\tt cholmod\_print\_factor}: print a Cholesky factorization \item {\tt cholmod\_check\_triplet}: check a triplet matrix \item {\tt cholmod\_print\_triplet}: print a triplet matrix \item {\tt cholmod\_check\_subset}: check a subset (integer vector in given range) \item {\tt cholmod\_print\_subset}: print a subset (integer vector in given range) \item {\tt cholmod\_check\_perm}: check a permutation (an integer vector) \item {\tt cholmod\_print\_perm}: print a permutation (an integer vector) \item {\tt cholmod\_check\_parent}: check an elimination tree (an integer vector) \item {\tt cholmod\_print\_parent}: print an elimination tree (an integer vector) \item {\tt cholmod\_read\_triplet}: read a triplet matrix from a file \item {\tt cholmod\_read\_sparse}: read a sparse matrix from a file \item {\tt cholmod\_read\_dense}: read a dense matrix from a file \end{itemize} %------------------------------------------------------------------------------- \newpage \subsection{{\tt Cholesky} Module: sparse Cholesky factorization} %------------------------------------------------------------------------------- The primary routines are all that a user requires to order, analyze, and factorize a sparse symmetric positive definite matrix $\m{A}$ (or $\m{AA}\tr$), and to solve $\m{Ax}=\m{b}$ (or $\m{AA}\tr\m{x}=\m{b}$). The primary routines rely on the secondary routines, the {\tt Core} Module, and the AMD and COLAMD packages. They make optional use of the {\tt Supernodal} and {\tt Partition} Modules, the METIS package, the CAMD package, and the CCOLAMD package. The {\tt Cholesky} Module is required by the {\tt Partition} Module. \vspace{0.1in} \noindent Primary routines: % 4 \begin{itemize} \item {\tt cholmod\_analyze}: order and analyze (simplicial or supernodal). \item {\tt cholmod\_factorize}: simplicial or supernodal Cholesky factorization. \item {\tt cholmod\_solve}: solve a linear system (simplicial or supernodal, dense $\m{x}$ and $\m{b}$). \item {\tt cholmod\_spsolve}: solve a linear system (simplicial or supernodal, sparse $\m{x}$ and $\m{b}$ ). \end{itemize} \noindent Secondary routines: % 15 \begin{itemize} \item {\tt cholmod\_analyze\_p}: analyze, with user-provided permutation or $\m{f}$ set. \item {\tt cholmod\_factorize\_p}: factorize, with user-provided permutation or $\m{f}$. \item {\tt cholmod\_analyze\_ordering}: analyze a permutation \item {\tt cholmod\_etree}: find the elimination tree. \item {\tt cholmod\_rowcolcounts}: compute the row/column counts of $\m{L}$. \item {\tt cholmod\_amd}: order using AMD. \item {\tt cholmod\_colamd}: order using COLAMD. \item {\tt cholmod\_rowfac}: incremental simplicial factorization. \item {\tt cholmod\_row\_subtree}: find the nonzero pattern of a row of $\m{L}$. \item {\tt cholmod\_row\_lsubtree}: find the nonzero pattern of a row of $\m{L}$. \item {\tt cholmod\_resymbol}: recompute the symbolic pattern of $\m{L}$. \item {\tt cholmod\_resymbol\_noperm}: recompute the symbolic pattern of $\m{L}$, no permutation. \item {\tt cholmod\_postorder}: postorder a tree. \item {\tt cholmod\_rcond}: compute the reciprocal condition number estimate. \item {\tt cholmod\_rowfac\_mask}: for use in LPDASA only. \end{itemize} %------------------------------------------------------------------------------- \newpage \subsection{{\tt Modify} Module: update/downdate a sparse Cholesky factorization} %------------------------------------------------------------------------------- The {\tt Modify} Module contains sparse Cholesky modification routines: update, downdate, row-add, and row-delete. It can also modify a corresponding solution to $\m{Lx}=\m{b}$ when L is modified. This module is most useful when applied on a Cholesky factorization computed by the {\tt Cholesky} module, but it does not actually require the {\tt Cholesky} module. The {\tt Core} module can create an identity Cholesky factorization ($\m{LDL}\tr$ where $\m{L}=\m{D}=\m{I}$) that can then be modified by these routines. Requires the {\tt Core} module. Not required by any other CHOLMOD Module. \vspace{0.1in} \noindent Primary routine: % 1 \begin{itemize} \item {\tt cholmod\_updown}: multiple rank update/downdate \end{itemize} \noindent Secondary routines: % 8 \begin{itemize} \item {\tt cholmod\_updown\_solve}: update/downdate, and modify solution to $\m{Lx=b}$ \item {\tt cholmod\_updown\_mark}: update/downdate, and modify solution to partial $\m{Lx=b}$ \item {\tt cholmod\_updown\_mask}: for use in LPDASA only. \item {\tt cholmod\_rowadd}: add a row to an $\m{LDL}\tr$ factorization \item {\tt cholmod\_rowadd\_solve}: add a row, and update solution to $\m{Lx=b}$ \item {\tt cholmod\_rowadd\_mark}: add a row, and update solution to partial $\m{Lx=b}$ \item {\tt cholmod\_rowdel}: delete a row from an $\m{LDL}\tr$ factorization \item {\tt cholmod\_rowdel\_solve}: delete a row, and downdate $\m{Lx=b}$ \item {\tt cholmod\_rowdel\_mark}: delete a row, and downdate solution to partial $\m{Lx=b}$ \end{itemize} %------------------------------------------------------------------------------- \subsection{{\tt MatrixOps} Module: basic sparse matrix operations} %------------------------------------------------------------------------------- The {\tt MatrixOps} Module provides basic operations on sparse and dense matrices. Requires the {\tt Core} module. Not required by any other CHOLMOD module. In the descriptions below, {\tt A}, {\tt B}, and {\tt C:} are sparse matrices ({\tt cholmod\_sparse}), {\tt X} and {\tt Y} are dense matrices ({\tt cholmod\_dense}), {\tt s} is a scalar or vector, and {\tt alpha} {\tt beta} are scalars. % 10 \begin{itemize} \item {\tt cholmod\_drop}: drop entries from A with absolute value $\ge$ a given tolerance. \item {\tt cholmod\_norm\_dense}: {\tt s = norm (X)}, 1-norm, infinity-norm, or 2-norm \item {\tt cholmod\_norm\_sparse}: {\tt s = norm (A)}, 1-norm or infinity-norm \item {\tt cholmod\_horzcat}: {\tt C = [A,B]} \item {\tt cholmod\_scale}: {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A} or {\tt diag(s)*A*diag(s)}. \item {\tt cholmod\_sdmult}: {\tt Y = alpha*(A*X) + beta*Y} or {\tt alpha*(A'*X) + beta*Y}. \item {\tt cholmod\_ssmult}: {\tt C = A*B} \item {\tt cholmod\_submatrix}: {\tt C = A (i,j)}, where {\tt i} and {\tt j} are arbitrary integer vectors. \item {\tt cholmod\_vertcat}: {\tt C = [A ; B]}. \item {\tt cholmod\_symmetry}: determine symmetry of a matrix. \end{itemize} %------------------------------------------------------------------------------- \newpage \subsection{{\tt Supernodal} Module: supernodal sparse Cholesky factorization} %------------------------------------------------------------------------------- The {\tt Supernodal} Module performs supernodal analysis, factorization, and solve. The simplest way to use these routines is via the {\tt Cholesky} Module. This Module does not provide any fill-reducing orderings. It normally operates on matrices ordered by the {\tt Cholesky} Module. It does not require the {\tt Cholesky} Module itself, however. Requires the {\tt Core} Module, and two external packages: LAPACK and the BLAS. Optionally used by the {\tt Cholesky} Module. All are secondary routines since these functions are more easily used via the {\tt Cholesky} Module. \vspace{0.1in} \noindent Secondary routines: % 4 \begin{itemize} \item {\tt cholmod\_super\_symbolic}: supernodal symbolic analysis \item {\tt cholmod\_super\_numeric}: supernodal numeric factorization \item {\tt cholmod\_super\_lsolve}: supernodal $\m{Lx}=\m{b}$ solve \item {\tt cholmod\_super\_ltsolve}: supernodal $\m{L}\tr\m{x}=\m{b}$ solve \end{itemize} %------------------------------------------------------------------------------- \subsection{{\tt Partition} Module: graph-partitioning-based orderings} %------------------------------------------------------------------------------- The {\tt Partition} Module provides graph partitioning and graph-partition-based orderings. It includes an interface to CAMD, CCOLAMD, and CSYMAMD, constrained minimum degree ordering methods which order a matrix following constraints determined via nested dissection. Requires the {\tt Core} and {\tt Cholesky} Modules, and two packages: {\tt METIS 4.0.1}, CAMD, and CCOLAMD. Optionally used by the {\tt Cholesky} Module. All are secondary routines since these are more easily used by the {\tt Cholesky} Module. Note that METIS does not have a version that uses {\tt long} integers. If you try to use these routines (except the CAMD, CCOLAMD, and CSYMAMD interfaces) on a matrix that is too large, an error code will be returned. \vspace{0.1in} \noindent Secondary routines: % 8 \begin{itemize} \item {\tt cholmod\_nested\_dissection}: CHOLMOD nested dissection ordering \item {\tt cholmod\_metis}: METIS nested dissection ordering ({\tt METIS\_NodeND}) \item {\tt cholmod\_camd}: interface to CAMD ordering \item {\tt cholmod\_ccolamd}: interface to CCOLAMD ordering \item {\tt cholmod\_csymamd}: interface to CSYMAMD ordering \item {\tt cholmod\_bisect}: graph partitioner (currently based on METIS) \item {\tt cholmod\_metis\_bisector}: direct interface to {\tt METIS\_NodeComputeSeparator}. \item {\tt cholmod\_collapse\_septree}: pruned a separator tree from {\tt cholmod\_nested\_dissection}. \end{itemize} %------------------------------------------------------------------------------- \newpage \section{CHOLMOD naming convention, parameters, and return values} %------------------------------------------------------------------------------- All routine names, data types, and CHOLMOD library files use the {\tt cholmod\_} prefix. All macros and other {\tt \#define} statements visible to the user program use the {\tt CHOLMOD} prefix. The {\tt cholmod.h} file must be included in user programs that use CHOLMOD: {\footnotesize \begin{verbatim} #include "cholmod.h" \end{verbatim} } \noindent All CHOLMOD routines (in all modules) use the following protocol for return values: \begin{itemize} \item {\tt int}: {\tt TRUE} (1) if successful, or {\tt FALSE} (0) otherwise. (exception: {\tt cholmod\_divcomplex}). \item {\tt long}: a value $\ge 0$ if successful, or -1 otherwise. \item {\tt double}: a value $\ge 0$ if successful, or -1 otherwise. \item {\tt size\_t}: a value $>$ 0 if successful, or 0 otherwise. \item {\tt void *}: a non-{\tt NULL} pointer to newly allocated memory if successful, or {\tt NULL} otherwise. \item {\tt cholmod\_sparse *}: a non-{\tt NULL} pointer to a newly allocated sparse matrix if successful, or {\tt NULL} otherwise. \item {\tt cholmod\_factor *}: a non-{\tt NULL} pointer to a newly allocated factor if successful, or {\tt NULL} otherwise. \item {\tt cholmod\_triplet *}: a non-{\tt NULL} pointer to a newly allocated triplet matrix if successful, or {\tt NULL} otherwise. \item {\tt cholmod\_dense *}: a non-{\tt NULL} pointer to a newly allocated dense matrix if successful, or {\tt NULL} otherwise. \end{itemize} {\tt TRUE} and {\tt FALSE} are not defined in {\tt cholmod.h}, since they may conflict with the user program. A routine that described here returning {\tt TRUE} or {\tt FALSE} returns 1 or 0, respectively. Any {\tt TRUE}/{\tt FALSE} parameter is true if nonzero, false if zero. \noindent Input, output, and input/output parameters: \begin{itemize} \item Input parameters appear first in the parameter lists of all CHOLMOD routines. They are not modified by CHOLMOD. \item Input/output parameters (except for {\tt Common}) appear next. They must be defined on input, and are modified on output. \item Output parameters are listed next. If they are pointers, they must point to allocated space on input, but their contents are not defined on input. \item Workspace parameters appear next. They are used in only two routines in the Supernodal module. \item The {\tt cholmod\_common *Common} parameter always appears as the last parameter (with two exceptions: {\tt cholmod\_hypot} and {\tt cholmod\_divcomplex}). It is always an input/output parameter. \end{itemize} A floating-point scalar is passed to CHOLMOD as a pointer to a {\tt double} array of size two. The first entry in this array is the real part of the scalar, and the second entry is the imaginary part. The imaginary part is only accessed if the other inputs are complex or zomplex. In some cases the imaginary part is always ignored ({\tt cholmod\_factor\_p}, for example). %------------------------------------------------------------------------------- \newpage \section{{\tt Core} Module: {\tt cholmod\_common} object} \label{cholmod_common} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{Constant definitions} %--------------------------------------- \input{_defn.tex} These definitions are used within the {\tt cholmod\_common} object, called {\tt Common} both here and throughout the code. %--------------------------------------- \newpage \subsection{{\tt cholmod\_common}: parameters, statistics, and workspace} %--------------------------------------- \input{_common.tex} The {\tt cholmod\_common Common} object contains parameters, statistics, and workspace used within CHOLMOD. The first call to CHOLMOD must be {\tt cholmod\_start}, which initializes this object. %--------------------------------------- \newpage \subsection{{\tt cholmod\_start}: start CHOLMOD} %--------------------------------------- \input{_start.tex} Sets the default parameters, clears the statistics, and initializes all workspace pointers to {\tt NULL}. The {\tt int}/{\tt long} type is set in {\tt Common->itype}. %--------------------------------------- \subsection{{\tt cholmod\_finish}: finish CHOLMOD} %--------------------------------------- \input{_finish.tex} This must be the last call to CHOLMOD. %--------------------------------------- \subsection{{\tt cholmod\_defaults}: set default parameters} %--------------------------------------- \input{_defaults.tex} Sets the default parameters. %--------------------------------------- \subsection{{\tt cholmod\_maxrank}: maximum update/downdate rank} %--------------------------------------- \input{_maxrank.tex} Returns the maximum rank for an update/downdate. %--------------------------------------- \subsection{{\tt cholmod\_allocate\_work}: allocate workspace} %--------------------------------------- \input{_allocate_work.tex} Allocates workspace in {\tt Common}. The workspace consists of the integer {\tt Head}, {\tt Flag}, and {\tt Iwork} arrays, of size {\tt nrow+1}, {\tt nrow}, and {\tt iworksize}, respectively, and a {\tt double} array {\tt Xwork} of size {\tt xworksize}. The {\tt Head} array is normally equal to -1 when it is cleared. If the {\tt Flag} array is cleared, all entries are less than {\tt Common->mark}. The {\tt Iwork} array is not kept in any particular state. The integer type is {\tt int} or {\tt long}, depending on whether the {\tt cholmod\_} or {\tt cholmod\_l\_} routines are used. %--------------------------------------- \subsection{{\tt cholmod\_free\_work}: free workspace} %--------------------------------------- \input{_free_work.tex} Frees the workspace in {\tt Common}. %--------------------------------------- \subsection{{\tt cholmod\_clear\_flag}: clear Flag array} %--------------------------------------- \input{_clear_flag.tex} Increments {\tt Common->mark} so that the {\tt Flag} array is now cleared. %--------------------------------------- \newpage \subsection{{\tt cholmod\_error}: report error} %--------------------------------------- \input{_error.tex} This routine is called when CHOLMOD encounters an error. It prints a message (if printing is enabled), sets {\tt Common->status}. It then calls the user error handler routine {\tt Common->error\_handler}, if it is not {\tt NULL}. %--------------------------------------- \subsection{{\tt cholmod\_dbound}: bound diagonal of $\m{L}$} %--------------------------------------- \input{_dbound.tex} Ensures that entries on the diagonal of $\m{L}$ for an $\m{LL}\tr$ factorization are greater than or equal to {\tt Common->dbound}. For an $\m{LDL}\tr$ factorization, it ensures that the magnitude of the entries of $\m{D}$ are greater than or equal to {\tt Common->dbound}. %--------------------------------------- \subsection{{\tt cholmod\_hypot}: {\tt sqrt(x*x+y*y)}} %--------------------------------------- \input{_hypot.tex} Computes the magnitude of a complex number. This routine is the default value for the {\tt Common->hypotenuse} function pointer. See also {\tt hypot}, in the standard {\tt math.h} header. If you have the ANSI C99 {\tt hypot}, you can use {\tt Common->hypotenuse = hypot}. The {\tt cholmod\_hypot} routine is provided in case you are using the ANSI C89 standard, which does not have {\tt hypot}. %--------------------------------------- \subsection{{\tt cholmod\_divcomplex}: complex divide} %--------------------------------------- \input{_divcomplex.tex} Divides two complex numbers. It returns 1 if a divide-by-zero occurred, or 0 otherwise. This routine is the default value for the {\tt Common->complex\_divide} function pointer. This return value is the single exception to the CHOLMOD rule that states all {\tt int} return values are {\tt TRUE} if successful or {\tt FALSE} otherwise. The exception is made to match the return value of a different complex divide routine that is not a part of CHOLMOD, but can be used via the function pointer. %------------------------------------------------------------------------------- \newpage \section{{\tt Core} Module: {\tt cholmod\_sparse} object} \label{cholmod_sparse} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_sparse}: compressed-column sparse matrix} %--------------------------------------- \input{_sparse.tex} Stores a sparse matrix in compressed-column form. %--------------------------------------- \newpage \subsection{{\tt cholmod\_allocate\_sparse}: allocate sparse matrix} %--------------------------------------- \input{_allocate_sparse.tex} Allocates a sparse matrix. {\tt A->i}, {\tt A->x}, and {\tt A->z} are not initialized. The matrix returned is all zero, but it contains space enough for {\tt nzmax} entries. %--------------------------------------- \subsection{{\tt cholmod\_free\_sparse}: free sparse matrix} %--------------------------------------- \input{_free_sparse.tex} Frees a sparse matrix. %--------------------------------------- \subsection{{\tt cholmod\_reallocate\_sparse}: reallocate sparse matrix} %--------------------------------------- \input{_reallocate_sparse.tex} Reallocates a sparse matrix, so that it can contain {\tt nznew} entries. %--------------------------------------- \newpage \subsection{{\tt cholmod\_nnz}: number of entries in sparse matrix} %--------------------------------------- \input{_nnz.tex} Returns the number of entries in a sparse matrix. %--------------------------------------- \subsection{{\tt cholmod\_speye}: sparse identity matrix} %--------------------------------------- \input{_speye.tex} Returns the sparse identity matrix. %--------------------------------------- \subsection{{\tt cholmod\_spzeros}: sparse zero matrix} %--------------------------------------- \input{_spzeros.tex} Returns the sparse zero matrix. This is another name for {\tt cholmod\_allocate\_sparse}, but with fewer parameters (the matrix is packed, sorted, and unsymmetric). %--------------------------------------- \newpage \subsection{{\tt cholmod\_transpose}: transpose sparse matrix} %--------------------------------------- \input{_transpose.tex} Returns the transpose or complex conjugate transpose of a sparse matrix. %--------------------------------------- \subsection{{\tt cholmod\_ptranspose}: transpose/permute sparse matrix} %--------------------------------------- \input{_ptranspose.tex} Returns {\tt A'} or {\tt A(p,p)'} if {\tt A} is symmetric. Returns {\tt A'}, {\tt A(:,f)'}, or {\tt A(p,f)'} if {\tt A} is unsymmetric. See {\tt cholmod\_transpose\_unsym} for a discussion of how {\tt f} is used; this usage deviates from the MATLAB notation. Can also return the array transpose. %--------------------------------------- \subsection{{\tt cholmod\_sort}: sort columns of a sparse matrix} %--------------------------------------- \input{_sort.tex} Sorts the columns of the matrix {\tt A}. Returns {\tt A} in packed form, even if it starts as unpacked. Removes entries in the ignored part of a symmetric matrix. %--------------------------------------- \newpage \subsection{{\tt cholmod\_transpose\_unsym}: transpose/permute unsymmetric sparse matrix} %--------------------------------------- \input{_transpose_unsym.tex} Transposes and optionally permutes an unsymmetric sparse matrix. The output matrix must be preallocated before calling this routine. Computes {\tt F=A'}, {\tt F=A(:,f)'} or {\tt F=A(p,f)'}, except that the indexing by {\tt f} does not work the same as the MATLAB notation (see below). {\tt A->stype} is zero, which denotes that both the upper and lower triangular parts of A are present (and used). The matrix {\tt A} may in fact be symmetric in pattern and/or value; {\tt A->stype} just denotes which part of {\tt A} are stored. {\tt A} may be rectangular. The integer vector {\tt p} is a permutation of {\tt 0:m-1}, and {\tt f} is a subset of {\tt 0:n-1}, where A is {\tt m}-by-{\tt n}. There can be no duplicate entries in {\tt p} or {\tt f}. \noindent Three kinds of transposes are available, depending on the {\tt values} parameter: \begin{itemize} \item 0: do not transpose the numerical values; create a {\tt CHOLMOD\_PATTERN} matrix \item 1: array transpose \item 2: complex conjugate transpose (same as 2 if input is real or pattern) \end{itemize} \noindent The set {\tt f} is held in fset and fsize: \begin{itemize} \item {\tt fset = NULL} means ``{\tt :}'' in MATLAB. {\tt fset} is ignored. \item {\tt fset != NULL} means {\tt f = fset [0..fsize-1]}. \item {\tt fset != NULL} and {\tt fsize = 0} means {\tt f} is the empty set. \end{itemize} Columns not in the set {\tt f} are considered to be zero. That is, if {\tt A} is 5-by-10 then {\tt F=A(:,[3 4])'} is not 2-by-5, but 10-by-5, and rows 3 and 4 of {\tt F} are equal to columns 3 and 4 of {\tt A} (the other rows of {\tt F} are zero). More precisely, in MATLAB notation: \begin{verbatim} [m n] = size (A) F = A notf = ones (1,n) notf (f) = 0 F (:, find (notf)) = 0 F = F' \end{verbatim} If you want the MATLAB equivalent {\tt F=A(p,f)} operation, use {\tt cholmod\_submatrix} instead (which does not compute the transpose). {\tt F->nzmax} must be large enough to hold the matrix {\tt F}. If {\tt F->nz} is present then {\tt F->nz [j]} is equal to the number of entries in column {\tt j} of {\tt F}. {\tt A} can be sorted or unsorted, with packed or unpacked columns. If {\tt f} is present and not sorted in ascending order, then {\tt F} is unsorted (that is, it may contain columns whose row indices do not appear in ascending order). Otherwise, {\tt F} is sorted (the row indices in each column of {\tt F} appear in strictly ascending order). {\tt F} is returned in packed or unpacked form, depending on {\tt F->packed} on input. If {\tt F->packed} is {\tt FALSE}, then {\tt F} is returned in unpacked form ({\tt F->nz} must be present). Each row {\tt i} of {\tt F} is large enough to hold all the entries in row {\tt i} of {\tt A}, even if {\tt f} is provided. That is, {\tt F->i} and {\tt F->x [F->p [i] .. F->p [i] + F->nz [i] - 1]} contain all entries in {\tt A(i,f)}, but {\tt F->p [i+1] - F->p [i]} is equal to the number of nonzeros in {\tt A (i,:)}, not just {\tt A (i,f)}. The {\tt cholmod\_transpose\_unsym} routine is the only operation in CHOLMOD that can produce an unpacked matrix. %--------------------------------------- \subsection{{\tt cholmod\_transpose\_sym}: transpose/permute symmetric sparse matrix} %--------------------------------------- \input{_transpose_sym.tex} Computes {\tt F = A'} or {\tt F = A(p,p)'}, the transpose or permuted transpose, where {\tt A->stype} is nonzero. {\tt A} must be square and symmetric. If {\tt A->stype} $> 0$, then {\tt A} is a symmetric matrix where just the upper part of the matrix is stored. Entries in the lower triangular part may be present, but are ignored. If {\tt A->stype} $< 0$, then {\tt A} is a symmetric matrix where just the lower part of the matrix is stored. Entries in the upper triangular part may be present, but are ignored. If {\tt F=A'}, then {\tt F} is returned sorted; otherwise {\tt F} is unsorted for the {\tt F=A(p,p)'} case. There can be no duplicate entries in {\tt p}. Three kinds of transposes are available, depending on the {\tt values} parameter: \begin{itemize} \item 0: do not transpose the numerical values; create a {\tt CHOLMOD\_PATTERN} matrix \item 1: array transpose \item 2: complex conjugate transpose (same as 2 if input is real or pattern) \end{itemize} For {\tt cholmod\_transpose\_unsym} and {\tt cholmod\_transpose\_sym}, the output matrix {\tt F} must already be pre-allocated by the caller, with the correct dimensions. If {\tt F} is not valid or has the wrong dimensions, it is not modified. Otherwise, if {\tt F} is too small, the transpose is not computed; the contents of {\tt F->p} contain the column pointers of the resulting matrix, where {\tt F->p [F->ncol] > F->nzmax}. In this case, the remaining contents of {\tt F} are not modified. {\tt F} can still be properly freed with {\tt cholmod\_free\_sparse}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_band}: extract band of a sparse matrix} %--------------------------------------- \input{_band.tex} Returns {\tt C = tril (triu (A,k1), k2)}. {\tt C} is a matrix consisting of the diagonals of A from {\tt k1} to {\tt k2}. {\tt k=0} is the main diagonal of {\tt A}, {\tt k=1} is the superdiagonal, {\tt k=-1} is the subdiagonal, and so on. If {\tt A} is {\tt m}-by-{\tt n}, then: \begin{itemize} \item {\tt k1=-m} means {\tt C = tril (A,k2)} \item {\tt k2=n} means {\tt C = triu (A,k1)} \item {\tt k1=0} and {\tt k2=0} means {\tt C = diag(A)}, except {\tt C} is a matrix, not a vector \end{itemize} Values of {\tt k1} and {\tt k2} less than {\tt -m} are treated as {\tt -m}, and values greater than {\tt n} are treated as {\tt n}. {\tt A} can be of any symmetry (upper, lower, or unsymmetric); {\tt C} is returned in the same form, and packed. If {\tt A->stype} $> 0$, entries in the lower triangular part of {\tt A} are ignored, and the opposite is true if {\tt A->stype} $< 0$. If {\tt A} has sorted columns, then so does {\tt C}. {\tt C} has the same size as {\tt A}. {\tt C} can be returned as a numerical valued matrix (if {\tt A} has numerical values and {\tt mode} $> 0$), as a pattern-only ({\tt mode} $=0$), or as a pattern-only but with the diagonal entries removed ({\tt mode} $< 0$). The xtype of {\tt A} can be pattern or real. Complex or zomplex cases are supported only if {\tt mode} is $\le 0$ (in which case the numerical values are ignored). %--------------------------------------- \subsection{{\tt cholmod\_band\_inplace}: extract band, in place} %--------------------------------------- \input{_band_inplace.tex} Same as {\tt cholmod\_band}, except that it always operates in place. Only packed matrices can be converted in place. %--------------------------------------- \newpage \subsection{{\tt cholmod\_aat}: compute $\m{AA}\tr$} %--------------------------------------- \input{_aat.tex} Computes {\tt C = A*A'} or {\tt C = A(:,f)*A(:,f)'}. {\tt A} can be packed or unpacked, sorted or unsorted, but must be stored with both upper and lower parts ({\tt A->stype} of zero). {\tt C} is returned as packed, {\tt C->stype} of zero (both upper and lower parts present), and unsorted. See {\tt cholmod\_ssmult} in the {\tt MatrixOps} Module for a more general matrix-matrix multiply. The xtype of {\tt A} can be pattern or real. Complex or zomplex cases are supported only if {\tt mode} is $\le 0$ (in which case the numerical values are ignored). You can trivially convert {\tt C} to a symmetric upper/lower matrix by changing {\tt C->stype} to 1 or -1, respectively, after calling this routine. %--------------------------------------- \subsection{{\tt cholmod\_copy\_sparse}: copy sparse matrix} %--------------------------------------- \input{_copy_sparse.tex} Returns an exact copy of the input sparse matrix {\tt A}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_copy}: copy (and change) sparse matrix} %--------------------------------------- \input{_copy.tex} {\tt C = A}, which allocates {\tt C} and copies {\tt A} into {\tt C}, with possible change of {\tt stype}. The diagonal can optionally be removed. The numerical entries can optionally be copied. This routine differs from {\tt cholmod\_copy\_sparse}, which makes an exact copy of a sparse matrix. {\tt A} can be of any type (packed/unpacked, upper/lower/unsymmetric). {\tt C} is packed and can be of any stype (upper/lower/unsymmetric), except that if {\tt A} is rectangular {\tt C} can only be unsymmetric. If the stype of A and C differ, then the appropriate conversion is made. \noindent There are three cases for {\tt A->stype}: \begin{itemize} \item $<0$, lower: assume {\tt A} is symmetric with just {\tt tril(A)} stored; the rest of {\tt A} is ignored \item $ 0$, unsymmetric: assume {\tt A} is unsymmetric; consider all entries in A \item $>0$, upper: assume {\tt A} is symmetric with just {\tt triu(A)} stored; the rest of {\tt A} is ignored \end{itemize} \noindent There are three cases for the requested symmetry of {\tt C} ({\tt stype} parameter): \begin{itemize} \item $<0$, lower: return just {\tt tril(C)} \item $0$, unsymmetric: return all of {\tt C} \item $>0$, upper: return just {\tt triu(C)} \end{itemize} \noindent This gives a total of nine combinations: \newline \begin{tabular}{ll} \hline Equivalent MATLAB statements & Using {\tt cholmod\_copy} \\ \hline {\tt C = A ; }& {\tt A} unsymmetric, {\tt C} unsymmetric \\ {\tt C = tril (A) ; }& {\tt A} unsymmetric, {\tt C} lower \\ {\tt C = triu (A) ; }& {\tt A} unsymmetric, {\tt C} upper \\ {\tt U = triu (A) ; L = tril (U',-1) ; C = L+U ; }& {\tt A} upper, {\tt C} unsymmetric \\ {\tt C = triu (A)' ; }& {\tt A} upper, {\tt C} lower \\ {\tt C = triu (A) ; }& {\tt A} upper, {\tt C} upper \\ {\tt L = tril (A) ; U = triu (L',1) ; C = L+U ; }& {\tt A} lower, {\tt C} unsymmetric \\ {\tt C = tril (A) ; }& {\tt A} lower, {\tt C} lower \\ {\tt C = tril (A)' ; }& {\tt A} lower, {\tt C} upper \\ \hline \end{tabular} \vspace{0.1in} The xtype of {\tt A} can be pattern or real. Complex or zomplex cases are supported only if {\tt values} is {\tt FALSE} (in which case the numerical values are ignored). %--------------------------------------- \newpage \subsection{{\tt cholmod\_add}: add sparse matrices} %--------------------------------------- \input{_add.tex} Returns {\tt C = alpha*A + beta*B}. If the {\tt stype} of {\tt A} and {\tt B} match, then {\tt C} has the same {\tt stype}. Otherwise, {\tt C->stype} is zero ({\tt C} is unsymmetric). %--------------------------------------- \subsection{{\tt cholmod\_sparse\_xtype}: change sparse xtype} %--------------------------------------- \input{_sparse_xtype.tex} Changes the {\tt xtype} of a sparse matrix, to pattern, real, complex, or zomplex. Changing from complex or zomplex to real discards the imaginary part. %------------------------------------------------------------------------------- \newpage \section{{\tt Core} Module: {\tt cholmod\_factor} object} \label{cholmod_factor} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_factor} object: a sparse Cholesky factorization} %--------------------------------------- \input{_factor.tex} An $\m{LL}\tr$ or $\m{LDL}\tr$ factorization in simplicial or supernodal form. A simplicial factor is very similar to a {\tt cholmod\_sparse} matrix. For an $\m{LDL}\tr$ factorization, the diagonal matrix $\m{D}$ is stored as the diagonal of $\m{L}$; the unit-diagonal of $\m{L}$ is not stored. %--------------------------------------- \newpage \subsection{{\tt cholmod\_free\_factor}: free factor} %--------------------------------------- \input{_free_factor.tex} Frees a factor. %--------------------------------------- \subsection{{\tt cholmod\_allocate\_factor}: allocate factor} %--------------------------------------- \input{_allocate_factor.tex} Allocates a factor and sets it to identity. %--------------------------------------- \subsection{{\tt cholmod\_reallocate\_factor}: reallocate factor} %--------------------------------------- \input{_reallocate_factor.tex} Reallocates a simplicial factor so that it can contain {\tt nznew} entries. %--------------------------------------- \newpage \subsection{{\tt cholmod\_change\_factor}: change factor} %--------------------------------------- \input{_change_factor.tex} Change the numeric or symbolic, $\m{LL}\tr$ or $\m{LDL}\tr$, simplicial or super, packed or unpacked, and monotonic or non-monotonic status of a {\tt cholmod\_factor} object. There are four basic classes of factor types: \begin{enumerate} \item simplicial symbolic: Consists of two size-{\tt n} arrays: the fill-reducing permutation ({\tt L->Perm}) and the nonzero count for each column of L ({\tt L->ColCount}). All other factor types also include this information. {\tt L->ColCount} may be exact (obtained from the analysis routines), or it may be a guess. During factorization, and certainly after update/downdate, the columns of {\tt L} can have a different number of nonzeros. {\tt L->ColCount} is used to allocate space. {\tt L->ColCount} is exact for the supernodal factorizations. The nonzero pattern of {\tt L} is not kept. \item simplicial numeric: These represent {\tt L} in a compressed column form. The variants of this type are: \begin{itemize} \item $\m{LDL}\tr$: {\tt L} is unit diagonal. Row indices in column {\tt j} are located in {\tt L->i [L->p [j] ... L->p [j] + L->nz [j]]}, and corresponding numeric values are in the same locations in {\tt L->x}. The total number of entries is the sum of {\tt L->nz [j]}. The unit diagonal is not stored; {\tt D} is stored on the diagonal of {\tt L} instead. {\tt L->p} may or may not be monotonic. The order of storage of the columns in {\tt L->i} and {\tt L->x} is given by a doubly-linked list ({\tt L->prev} and {\tt L->next}). {\tt L->p} is of size {\tt n+1}, but only the first {\tt n} entries are used. For the complex case, {\tt L->x} is stored interleaved with real and imaginary parts, and is of size {\tt 2*lnz*sizeof(double)}. For the zomplex case, {\tt L->x} is of size {\tt lnz*sizeof(double)} and holds the real part; {\tt L->z} is the same size and holds the imaginary part. \item $\m{LL}\tr$: This is identical to the $\m{LDL}\tr$ form, except that the non-unit diagonal of {\tt L} is stored as the first entry in each column of {\tt L}. \end{itemize} \item supernodal symbolic: A representation of the nonzero pattern of the supernodes for a supernodal factorization. There are {\tt L->nsuper} supernodes. Columns {\tt L->super [k]} to {\tt L->super [k+1]-1} are in the {\tt k}th supernode. The row indices for the {\tt k}th supernode are in {\tt L->s [L->pi [k] ... L->pi [k+1]-1]}. The numerical values are not allocated ({\tt L->x}), but when they are they will be located in {\tt L->x [L->px [k] ... L->px [k+1]-1]}, and the {\tt L->px} array is defined in this factor type. For the complex case, {\tt L->x} is stored interleaved with real/imaginary parts, and is of size \newline {\tt 2*L->xsize*sizeof(double)}. The zomplex supernodal case is not supported, since it is not compatible with LAPACK and the BLAS. \item supernodal numeric: Always an $\m{LL}\tr$ factorization. {\tt L} has a non-unit diagonal. {\tt L->x} contains the numerical values of the supernodes, as described above for the supernodal symbolic factor. For the complex case, {\tt L->x} is stored interleaved, and is of size {\tt 2*L->xsize*sizeof(double)}. The zomplex supernodal case is not supported, since it is not compatible with LAPACK and the BLAS. \end{enumerate} In all cases, the row indices in each column ({\tt L->i} for simplicial {\tt L} and {\tt L->s} for supernodal {\tt L}) are kept sorted from low indices to high indices. This means the diagonal of {\tt L} (or {\tt D} for a $\m{LDL}\tr$ factorization) is always kept as the first entry in each column. The elimination tree is not kept. The parent of node {\tt j} can be found as the second row index in the {\tt j}th column. If column {\tt j} has no off-diagonal entries then node {\tt j} is a root of the elimination tree. The {\tt cholmod\_change\_factor} routine can do almost all possible conversions. It cannot do the following conversions: \begin{itemize} \item Simplicial numeric types cannot be converted to a supernodal symbolic type. This would simultaneously deallocate the simplicial pattern and numeric values and reallocate uninitialized space for the supernodal pattern. This isn't useful for the user, and not needed by CHOLMOD's own routines either. \item Only a symbolic factor (simplicial to supernodal) can be converted to a supernodal numeric factor. \end{itemize} Some conversions are meant only to be used internally by other CHOLMOD routines, and should not be performed by the end user. They allocate space whose contents are undefined: \begin{itemize} \item converting from simplicial symbolic to supernodal symbolic. \item converting any factor to supernodal numeric. \end{itemize} Supports all xtypes, except that there is no supernodal zomplex L. The {\tt to\_xtype} parameter is used only when converting from symbolic to numeric or numeric to symbolic. It cannot be used to convert a numeric xtype (real, complex, or zomplex) to a different numeric xtype. For that conversion, use {\tt cholmod\_factor\_xtype} instead. %--------------------------------------- \newpage \subsection{{\tt cholmod\_pack\_factor}: pack the columns of a factor} %--------------------------------------- \input{_pack_factor.tex} Pack the columns of a simplicial $\m{LDL}\tr$ or $\m{LL}\tr$ factorization. This can be followed by a call to {\tt cholmod\_reallocate\_factor} to reduce the size of {\tt L} to the exact size required by the factor, if desired. Alternatively, you can leave the size of {\tt L->i} and {\tt L->x} the same, to allow space for future updates/rowadds. Each column is reduced in size so that it has at most {\tt Common->grow2} free space at the end of the column. Does nothing and returns silently if given any other type of factor. Does not force the columns of {\tt L} to be monotonic. It thus differs from \begin{verbatim} cholmod_change_factor (xtype, L->is_ll, FALSE, TRUE, TRUE, L, Common) \end{verbatim} which packs the columns and ensures that they appear in monotonic order. %--------------------------------------- \subsection{{\tt cholmod\_reallocate\_column}: reallocate one column of a factor} %--------------------------------------- \input{_reallocate_column.tex} Reallocates the space allotted to a single column of $\m{L}$. %--------------------------------------- \newpage \subsection{{\tt cholmod\_factor\_to\_sparse}: sparse matrix copy of a factor} %--------------------------------------- \input{_factor_to_sparse.tex} Returns a column-oriented sparse matrix containing the pattern and values of a simplicial or supernodal numerical factor, and then converts the factor into a simplicial symbolic factor. If {\tt L} is already packed, monotonic, and simplicial (which is the case when {\tt cholmod\_factorize} uses the simplicial Cholesky factorization algorithm) then this routine requires only a small amount of time and memory, independent of {\tt n}. It only operates on numeric factors (real, complex, or zomplex). It does not change {\tt L->xtype} (the resulting sparse matrix has the same {\tt xtype} as {\tt L}). If this routine fails, {\tt L} is left unmodified. %--------------------------------------- \subsection{{\tt cholmod\_copy\_factor}: copy factor} %--------------------------------------- \input{_copy_factor.tex} Returns an exact copy of a factor. %--------------------------------------- \subsection{{\tt cholmod\_factor\_xtype}: change factor xtype} %--------------------------------------- \input{_factor_xtype.tex} Changes the {\tt xtype} of a factor, to pattern, real, complex, or zomplex. Changing from complex or zomplex to real discards the imaginary part. You cannot change a supernodal factor to the zomplex xtype. %------------------------------------------------------------------------------- \newpage \section{{\tt Core} Module: {\tt cholmod\_dense} object} \label{cholmod_dense} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_dense} object: a dense matrix} %--------------------------------------- \input{_dense.tex} Contains a dense matrix. %--------------------------------------- \subsection{{\tt cholmod\_allocate\_dense}: allocate dense matrix} %--------------------------------------- \input{_allocate_dense.tex} Allocates a dense matrix. %--------------------------------------- \subsection{{\tt cholmod\_free\_dense}: free dense matrix} %--------------------------------------- \input{_free_dense.tex} Frees a dense matrix. %--------------------------------------- \newpage \subsection{{\tt cholmod\_zeros}: dense zero matrix} %--------------------------------------- \input{_zeros.tex} Returns an all-zero dense matrix. %--------------------------------------- \subsection{{\tt cholmod\_ones}: dense matrix, all ones} %--------------------------------------- \input{_ones.tex} Returns a dense matrix with each entry equal to one. %--------------------------------------- \subsection{{\tt cholmod\_eye}: dense identity matrix} %--------------------------------------- \input{_eye.tex} Returns a dense identity matrix. %--------------------------------------- \newpage \subsection{{\tt cholmod\_sparse\_to\_dense}: dense matrix copy of a sparse matrix} %--------------------------------------- \input{_sparse_to_dense.tex} Returns a dense copy of a sparse matrix. %--------------------------------------- \subsection{{\tt cholmod\_dense\_to\_sparse}: sparse matrix copy of a dense matrix} %--------------------------------------- \input{_dense_to_sparse.tex} Returns a sparse copy of a dense matrix. %--------------------------------------- \subsection{{\tt cholmod\_copy\_dense}: copy dense matrix} %--------------------------------------- \input{_copy_dense.tex} Returns a copy of a dense matrix. %--------------------------------------- \newpage \subsection{{\tt cholmod\_copy\_dense2}: copy dense matrix (preallocated)} %--------------------------------------- \input{_copy_dense2.tex} Returns a copy of a dense matrix, placing the result in a preallocated matrix {\tt Y}. %--------------------------------------- \subsection{{\tt cholmod\_dense\_xtype}: change dense matrix xtype} %--------------------------------------- \input{_dense_xtype.tex} Changes the {\tt xtype} of a dense matrix, to real, complex, or zomplex. Changing from complex or zomplex to real discards the imaginary part. %------------------------------------------------------------------------------- \newpage \section{{\tt Core} Module: {\tt cholmod\_triplet} object} \label{cholmod_triplet} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_triplet} object: sparse matrix in triplet form} %--------------------------------------- \input{_triplet.tex} Contains a sparse matrix in triplet form. %--------------------------------------- \subsection{{\tt cholmod\_allocate\_triplet}: allocate triplet matrix} %--------------------------------------- \input{_allocate_triplet.tex} Allocates a triplet matrix. %--------------------------------------- \subsection{{\tt cholmod\_free\_triplet}: free triplet matrix} %--------------------------------------- \input{_free_triplet.tex} Frees a triplet matrix. %--------------------------------------- \newpage \subsection{{\tt cholmod\_reallocate\_triplet}: reallocate triplet matrix} %--------------------------------------- \input{_reallocate_triplet.tex} Reallocates a triplet matrix so that it can hold {\tt nznew} entries. %--------------------------------------- \subsection{{\tt cholmod\_sparse\_to\_triplet}: triplet matrix copy of a sparse matrix} %--------------------------------------- \input{_sparse_to_triplet.tex} Returns a triplet matrix copy of a sparse matrix. %--------------------------------------- \subsection{{\tt cholmod\_triplet\_to\_sparse}: sparse matrix copy of a triplet matrix} %--------------------------------------- \input{_triplet_to_sparse.tex} Returns a sparse matrix copy of a triplet matrix. If the triplet matrix is symmetric with just the lower part present ({\tt T->stype} $< 0$), then entries in the upper part are transposed and placed in the lower part when converting to a sparse matrix. Similarly, if the triplet matrix is symmetric with just the upper part present ({\tt T->stype} $> 0$), then entries in the lower part are transposed and placed in the upper part when converting to a sparse matrix. Any duplicate entries are summed. %--------------------------------------- \newpage \subsection{{\tt cholmod\_copy\_triplet}: copy triplet matrix} %--------------------------------------- \input{_copy_triplet.tex} Returns an exact copy of a triplet matrix. %--------------------------------------- \subsection{{\tt cholmod\_triplet\_xtype}: change triplet xtype} %--------------------------------------- \input{_triplet_xtype.tex} Changes the {\tt xtype} of a dense matrix, to real, complex, or zomplex. Changing from complex or zomplex to real discards the imaginary part. %------------------------------------------------------------------------------- \newpage \section{{\tt Core} Module: memory management} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_malloc}: allocate memory} %--------------------------------------- \input{_malloc.tex} Allocates a block of memory of size {\tt n*size}, using the {\tt Common->malloc\_memory} function pointer (default is to use the ANSI C {\tt malloc} routine). A value of {\tt n=0} is treated as {\tt n=1}. If not successful, {\tt NULL} is returned and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}. %--------------------------------------- \subsection{{\tt cholmod\_calloc}: allocate and clear memory} %--------------------------------------- \input{_calloc.tex} Allocates a block of memory of size {\tt n*size}, using the {\tt Common->calloc\_memory} function pointer (default is to use the ANSI C {\tt calloc} routine). A value of {\tt n=0} is treated as {\tt n=1}. If not successful, {\tt NULL} is returned and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_free}: free memory} %--------------------------------------- \input{_free.tex} Frees a block of memory of size {\tt n*size}, using the {\tt Common->free\_memory} function pointer (default is to use the ANSI C {\tt free} routine). The size of the block ({\tt n} and {\tt size}) is only required so that CHOLMOD can keep track of its current and peak memory usage. This is a useful statistic, and it can also help in tracking down memory leaks. After the call to {\tt cholmod\_finish}, the count of allocated blocks ({\tt Common->malloc\_count}) should be zero, and the count of bytes in use ({\tt Common->memory\_inuse}) also should be zero. If you allocate a block with one size and free it with another, the {\tt Common->memory\_inuse} count will be wrong, but CHOLMOD will not have a memory leak. %--------------------------------------- \subsection{{\tt cholmod\_realloc}: reallocate memory} %--------------------------------------- \input{_realloc.tex} Reallocates a block of memory whose current size {\tt n*size}, and whose new size will be {\tt nnew*size} if successful, using the {\tt Common->calloc\_memory} function pointer (default is to use the ANSI C {\tt realloc} routine). If the reallocation is not successful, {\tt p} is returned unchanged and {\tt Common->status} is set to {\tt CHOLMOD\_OUT\_OF\_MEMORY}. The value of {\tt n} is set to {\tt nnew} if successful, or left unchanged otherwise. A value of {\tt nnew=0} is treated as {\tt nnew=1}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_realloc\_multiple}: reallocate memory} %--------------------------------------- \input{_realloc_multiple.tex} Reallocates multiple blocks of memory, all with the same number of items (but with different item sizes). Either all reallocations succeed, or all are returned to their original size. %------------------------------------------------------------------------------- \newpage \section{{\tt Check} Module routines} %------------------------------------------------------------------------------- No CHOLMOD routines print anything, except for the {\tt cholmod\_print\_*} routines in the {\tt Check} Module, and the {\tt cholmod\_error} routine. The {\tt Common->print\_function} is a pointer to {\tt printf} by default; you can redirect the output of CHOLMOD by redefining this pointer. If {\tt Common->print\_function} is {\tt NULL}, CHOLMOD does not print anything. The {\tt Common->print} parameter determines how much detail is printed. Each value of {\tt Common->print} listed below also prints the items listed for smaller values of {\tt Common->print}: \begin{itemize} \item 0: print nothing; check the data structures and return {\tt TRUE} or {\tt FALSE}. \item 1: print error messages. \item 2: print warning messages. \item 3: print a one-line summary of the object. \item 4: print a short summary of the object (first and last few entries). \item 5: print the entire contents of the object. \end{itemize} Values less than zero are treated as zero, and values greater than five are treated as five. %--------------------------------------- \subsection{{\tt cholmod\_check\_common}: check Common object} %--------------------------------------- \input{_check_common.tex} Check if the {\tt Common} object is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_common}: print Common object} %--------------------------------------- \input{_print_common.tex} Print the {\tt Common} object and check if it is valid. This prints the CHOLMOD parameters and statistics. %--------------------------------------- \newpage \subsection{{\tt cholmod\_check\_sparse}: check sparse matrix} %--------------------------------------- \input{_check_sparse.tex} Check if a sparse matrix is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_sparse}: print sparse matrix} %--------------------------------------- \input{_print_sparse.tex} Print a sparse matrix and check if it is valid. %--------------------------------------- \newpage \subsection{{\tt cholmod\_check\_dense}: check dense matrix} %--------------------------------------- \input{_check_dense.tex} Check if a dense matrix is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_dense}: print dense matrix} %--------------------------------------- \input{_print_dense.tex} Print a dense matrix and check if it is valid. %--------------------------------------- \newpage \subsection{{\tt cholmod\_check\_factor}: check factor} %--------------------------------------- \input{_check_factor.tex} Check if a factor is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_factor}: print factor} %--------------------------------------- \input{_print_factor.tex} Print a factor and check if it is valid. %--------------------------------------- \newpage \subsection{{\tt cholmod\_check\_triplet}: check triplet matrix} %--------------------------------------- \input{_check_triplet.tex} Check if a triplet matrix is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_triplet}: print triplet matrix} %--------------------------------------- \input{_print_triplet.tex} Print a triplet matrix and check if it is valid. %--------------------------------------- \newpage \subsection{{\tt cholmod\_check\_subset}: check subset} %--------------------------------------- \input{_check_subset.tex} Check if a subset is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_subset}: print subset} %--------------------------------------- \input{_print_subset.tex} Print a subset and check if it is valid. %--------------------------------------- \newpage \subsection{{\tt cholmod\_check\_perm}: check permutation} %--------------------------------------- \input{_check_perm.tex} Check if a permutation is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_perm}: print permutation} %--------------------------------------- \input{_print_perm.tex} Print a permutation and check if it is valid. %--------------------------------------- \newpage \subsection{{\tt cholmod\_check\_parent}: check elimination tree} %--------------------------------------- \input{_check_parent.tex} Check if an elimination tree is valid. %--------------------------------------- \subsection{{\tt cholmod\_print\_parent}: print elimination tree} %--------------------------------------- \input{_print_parent.tex} Print an elimination tree and check if it is valid. %--------------------------------------- \newpage \subsection{{\tt cholmod\_read\_triplet}: read triplet matrix from file} %--------------------------------------- \input{_read_triplet.tex} Read a sparse matrix in triplet form, using the the {\tt coord} Matrix Market format (http://www.nist.gov/MatrixMarket). Skew-symmetric and complex symmetric matrices are returned with both upper and lower triangular parts present (an stype of zero). Real symmetric and complex Hermitian matrices are returned with just their upper or lower triangular part, depending on their stype. The Matrix Market {\tt array} data type for dense matrices is not supported (use {\tt cholmod\_read\_dense} for that case). If the first line of the file starts with {\tt \%\%MatrixMarket}, then it is interpreted as a file in Matrix Market format. The header line is optional. If present, this line must have the following format: \vspace{0.1in} {\tt \%\%MatrixMarket matrix coord} {\em type storage} \vspace{0.1in} \noindent where {\em type} is one of: {\tt real}, {\tt complex}, {\tt pattern}, or {\tt integer}, and {\em storage} is one of: {\tt general}, {\tt hermitian}, {\tt symmetric}, or {\tt skew-symmetric}. In CHOLMOD, these roughly correspond to the {\tt xtype} (pattern, real, complex, or zomplex) and {\tt stype} (unsymmetric, symmetric/upper, and symmetric/lower). The strings are case-insensitive. Only the first character (or the first two for skew-symmetric) is significant. The {\tt coord} token can be replaced with {\tt array} in the Matrix Market format, but this format not supported by {\tt cholmod\_read\_triplet}. The {\tt integer} type is converted to real. The {\em type} is ignored; the actual type (real, complex, or pattern) is inferred from the number of tokens in each line of the file (2: pattern, 3: real, 4: complex). This is compatible with the Matrix Market format. A storage of {\tt general} implies an stype of zero (see below). A storage of {\tt symmetric} and {\tt hermitian} imply an stype of -1. Skew-symmetric and complex symmetric matrices are returned with an stype of 0. Blank lines, any other lines starting with ``{\tt \%}'' are treated as comments, and are ignored. The first non-comment line contains 3 or 4 integers: \vspace{0.1in} {\em nrow ncol nnz stype} \vspace{0.1in} \noindent where {\em stype} is optional (stype does not appear in the Matrix Market format). The matrix is {\em nrow}-by-{\em ncol}. The following {\em nnz} lines (excluding comments) each contain a single entry. Duplicates are permitted, and are summed in the output matrix. If stype is present, it denotes the storage format for the matrix. \begin{itemize} \item stype = 0 denotes an unsymmetric matrix (same as Matrix Market {\tt general}). \item stype = -1 denotes a symmetric or Hermitian matrix whose lower triangular entries are stored. Entries may be present in the upper triangular part, but these are ignored (same as Matrix Market {\tt symmetric} for the real case, {\tt hermitian} for the complex case). \item stype = 1 denotes a symmetric or Hermitian matrix whose upper triangular entries are stored. Entries may be present in the lower triangular part, but these are ignored. This format is not available in the Matrix Market format. \end{itemize} If neither the stype nor the Matrix Market header are present, then the stype is inferred from the rest of the data. If the matrix is rectangular, or has entries in both the upper and lower triangular parts, then it is assumed to be unsymmetric (stype=0). If only entries in the lower triangular part are present, the matrix is assumed to have stype = -1. If only entries in the upper triangular part are present, the matrix is assumed to have stype = 1. Each nonzero consists of one line with 2, 3, or 4 entries. All lines must have the same number of entries. The first two entries are the row and column indices of the nonzero. If 3 entries are present, the 3rd entry is the numerical value, and the matrix is real. If 4 entries are present, the 3rd and 4th entries in the line are the real and imaginary parts of a complex value. The matrix can be either 0-based or 1-based. It is first assumed to be one-based (compatible with Matrix Market), with row indices in the range 1 to ncol and column indices in the range 1 to nrow. If a row or column index of zero is found, the matrix is assumed to be zero-based (with row indices in the range 0 to ncol-1 and column indices in the range 0 to nrow-1). This test correctly determines that all Matrix Market matrices are in 1-based form. For symmetric pattern-only matrices, the kth diagonal (if present) is set to one plus the degree of the row k or column k (whichever is larger), and the off-diagonals are set to -1. A symmetric pattern-only matrix with a zero-free diagonal is thus converted into a symmetric positive definite matrix. All entries are set to one for an unsymmetric pattern-only matrix. This differs from the MatrixMarket format ({\tt A = mmread ('file')} returns a binary pattern for A for symmetric pattern-only matrices). To return a binary format for all pattern-only matrices, use {\tt A = mread('file',1)}. Example matrices that follow this format can be found in the {\tt CHOLMOD/Demo/Matrix} and \newline {\tt CHOLMOD/Tcov/Matrix} directories. You can also try any of the matrices in the Matrix Market collection at http://www.nist.gov/MatrixMarket. %--------------------------------------- \subsection{{\tt cholmod\_read\_sparse}: read sparse matrix from file} %--------------------------------------- \input{_read_sparse.tex} Read a sparse matrix in triplet form from a file (using {\tt cholmod\_read\_triplet}) and convert to a CHOLMOD sparse matrix. The Matrix Market format is used. If {\tt Common->prefer\_upper} is {\tt TRUE} (the default case), a symmetric matrix is returned stored in upper-triangular form ({\tt A->stype} is 1). Otherwise, it is left in its original form, either upper or lower. %--------------------------------------- \newpage \subsection{{\tt cholmod\_read\_dense}: read dense matrix from file} %--------------------------------------- \input{_read_dense.tex} Read a dense matrix from a file, using the the {\tt array} Matrix Market format \newline (http://www.nist.gov/MatrixMarket). %--------------------------------------- \subsection{{\tt cholmod\_read\_matrix}: read a matrix from file} %--------------------------------------- \input{_read_matrix.tex} Read a sparse or dense matrix from a file, in Matrix Market format. Returns a {\tt void} pointer to either a {\tt cholmod\_triplet}, {\tt cholmod\_sparse}, or {\tt cholmod\_dense} object. %--------------------------------------- \newpage \subsection{{\tt cholmod\_write\_sparse}: write a sparse matrix to a file} %--------------------------------------- \input{_write_sparse.tex} Write a sparse matrix to a file in Matrix Market format. Optionally include comments, and print explicit zero entries given by the pattern of the {\tt Z} matrix. If not NULL, the {\tt Z} matrix must have the same dimensions and stype as {\tt A}. Returns the symmetry in which the matrix was printed (1 to 7) or -1 on failure. See the {\tt cholmod\_symmetry} function for a description of the return codes. If {\tt A} and {\tt Z} are sorted on input, and either unsymmetric (stype = 0) or symmetric-lower (stype < 0), and if {\tt A} and {\tt Z} do not overlap, then the triplets are sorted, first by column and then by row index within each column, with no duplicate entries. If all the above holds except stype > 0, then the triplets are sorted by row first and then column. %--------------------------------------- \subsection{{\tt cholmod\_write\_dense}: write a dense matrix to a file} %--------------------------------------- \input{_write_dense.tex} Write a dense matrix to a file in Matrix Market format. Optionally include comments. Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if square). A dense matrix is written in "general" format; symmetric formats in the Matrix Market standard are not exploited. %------------------------------------------------------------------------------- \newpage \section{{\tt Cholesky} Module routines} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_analyze}: symbolic factorization} %--------------------------------------- \input{_analyze.tex} Orders and analyzes a matrix (either simplicial or supernodal), in preparation for numerical factorization via {\tt cholmod\_factorize} or via the ``expert'' routines {\tt cholmod\_rowfac} and {\tt cholmod\_super\_numeric}. In the symmetric case, {\tt A} or {\tt A(p,p)} is analyzed, where {\tt p} is the fill-reducing ordering. In the unsymmetric case, {\tt A*A'} or {\tt A(p,:)*A(p,:)'} is analyzed. The {\tt cholmod\_analyze\_p} routine can be given a user-provided permutation {\tt p} (see below). The default ordering strategy is to first try AMD. The ordering quality is analyzed, and if AMD obtains an ordering where {\tt nnz(L)} is greater than or equal to {\tt 5*nnz(tril(A))} (or {\tt 5*nnz(tril(A*A'))} if {\tt A} is unsymmetric) and the floating-point operation count for the subsequent factorization is greater than or equal to {\tt 500*nnz(L)}, then METIS is tried (if installed). For {\tt cholmod\_analyze\_p}, the user-provided ordering is also tried. This default behavior is obtained when {\tt Common->nmethods} is zero. In this case, methods 0, 1, and 2 in {\tt Common->method[...]} are reset to user-provided, AMD, and METIS, respectively. The ordering with the smallest {\tt nnz(L)} is kept. If {\tt Common->default\_nesdis} is true (nonzero), then CHOLMOD's nested dissection (NESDIS) is used for the default strategy described above, in place of METIS. Other ordering options can be requested. These include: \begin{enumerate} \item natural: A is not permuted to reduce fill-in. \item user-provided: a permutation can be provided to {\tt cholmod\_analyze\_p}. \item AMD: approximate minimum degree (AMD for the symmetric case, COLAMD for the {\tt A*A'} case). \item METIS: nested dissection with {\tt METIS\_NodeND} \item {\tt NESDIS}: CHOLMOD's nested dissection using {\tt METIS\_NodeComputeSeparator}, followed by a constrained minimum degree (CAMD or CSYMAMD for the symmetric case, CCOLAMD for the {\tt A*A'} case). This is typically slower than METIS, but typically provides better orderings. \end{enumerate} Multiple ordering options can be tried (up to 9 of them), and the best one is selected (the one that gives the smallest number of nonzeros in the simplicial factor L). If one method fails, {\tt cholmod\_analyze} keeps going, and picks the best among the methods that succeeded. This routine fails (and returns {\tt NULL}) if either the initial memory allocation fails, all ordering methods fail, or the supernodal analysis (if requested) fails. Change {\tt Common->nmethods} to the number of methods you wish to try. By default, the 9 methods available are: \begin{enumerate} \item user-provided permutation (only for {\tt cholmod\_analyze\_p}). \item AMD with default parameters. \item METIS with default parameters. \item {\tt NESDIS} with default parameters: stopping the partitioning when the graph is of size {\tt nd\_small} = 200 or less, remove nodes with more than {\tt max (16, prune\_dense * sqrt (n))} nodes where {\tt prune\_dense} = 10, and follow partitioning with constrained minimum degree ordering (CAMD for the symmetric case, CCOLAMD for the unsymmetric case). \item natural ordering (with weighted postorder). \item NESDIS, {\tt nd\_small} = 20000, {\tt prune\_dense} = 10. \item NESDIS, {\tt nd\_small} = 4, {\tt prune\_dense} = 10, no constrained minimum degree. \item NESDIS, {\tt nd\_small} = 200, {\tt prune\_dense} = 0. \item COLAMD for {\tt A*A'} or AMD for {\tt A} \end{enumerate} You can modify these 9 methods and the number of methods tried by changing parameters in the {\tt Common} argument. If you know the best ordering for your matrix, set {\tt Common->nmethods} to 1 and set {\tt Common->method[0].ordering} to the requested ordering method. Parameters for each method can also be modified (refer to the description of {\tt cholmod\_common} for details). Note that it is possible for METIS to terminate your program if it runs out of memory. This is not the case for any CHOLMOD or minimum degree ordering routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD). Since {\tt NESDIS} relies on METIS, it too can terminate your program. The selected ordering is followed by a weighted postorder of the elimination tree by default (see {\tt cholmod\_postorder} for details), unless {\tt Common->postorder} is set to {\tt FALSE}. The postorder does not change the number of nonzeros in $\m{L}$ or the floating-point operation count. It does improve performance, particularly for the supernodal factorization. If you truly want the natural ordering with no postordering, you must set {\tt Common->postorder} to {\tt FALSE}. The factor {\tt L} is returned as simplicial symbolic if {\tt Common->supernodal} is {\tt CHOLMOD\_SIMPLICIAL} (zero) or as supernodal symbolic if {\tt Common->supernodal} is {\tt CHOLMOD\_SUPERNODAL} (two). If \newline {\tt Common->supernodal} is {\tt CHOLMOD\_AUTO} (one), then {\tt L} is simplicial if the flop count per nonzero in {\tt L} is less than {\tt Common->supernodal\_switch} (default: 40), and supernodal otherwise. In both cases, {\tt L->xtype} is {\tt CHOLMOD\_PATTERN}. A subsequent call to {\tt cholmod\_factorize} will perform a simplicial or supernodal factorization, depending on the type of {\tt L}. For the simplicial case, {\tt L} contains the fill-reducing permutation ({\tt L->Perm}) and the counts of nonzeros in each column of {\tt L} ({\tt L->ColCount}). For the supernodal case, {\tt L} also contains the nonzero pattern of each supernode. If a simplicial factorization is selected, it will be $\m{LDL}\tr$ by default, since this is the kind required by the {\tt Modify} Module. CHOLMOD does not include a supernodal $\m{LDL}\tr$ factorization, so if a supernodal factorization is selected, it will be in the form $\m{LL}\tr$. The $\m{LDL}\tr$ method can be used to factorize positive definite matrices and indefinite matrices whose leading minors are well-conditioned (2-by-2 pivoting is not supported). The $\m{LL}\tr$ method is restricted to positive definite matrices. To factorize a large indefinite matrix, set {\tt Common->supernodal} to {\tt CHOLMOD\_SIMPLICIAL}, and the simplicial $\m{LDL}\tr$ method will always be used. This will be significantly slower than a supernodal $\m{LL}\tr$ factorization, however. Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_factorize}: numeric factorization} %--------------------------------------- \input{_factorize.tex} Computes the numerical factorization of a symmetric matrix. The % primary inputs to this routine are a sparse matrix {\tt A} and the symbolic factor {\tt L} from {\tt cholmod\_analyze} or a prior numerical factor {\tt L}. If {\tt A} is symmetric, this routine factorizes {\tt A(p,p)}. %+beta*I (beta can be zero), where p is the fill-reducing permutation ({\tt L->Perm}). If {\tt A} is unsymmetric, % either {\tt A(p,:)*A(p,:)'} % +beta*I or A(p,f)*A(p,f)'+beta*I is factorized. % The set f and The nonzero pattern of the matrix {\tt A} must be the same as the matrix passed to {\tt cholmod\_analyze} for the supernodal case. For the simplicial case, it can be different, but it should be the same for best performance. % beta is real. A simplicial factorization or supernodal factorization is chosen, based on the type of the factor {\tt L}. If {\tt L->is\_super} is {\tt TRUE}, a supernodal $\m{LL}\tr$ factorization is computed. Otherwise, a simplicial numeric factorization is computed, either $\m{LL}\tr$ or $\m{LDL}\tr$, depending on {\tt Common->final\_ll} (the default for the simplicial case is to compute an $\m{LDL}\tr$ factorization). Once the factorization is complete, it can be left as is or optionally converted into any simplicial numeric type, depending on the {\tt Common->final\_*} parameters. If converted from a supernodal to simplicial type, and {\tt Common->final\_resymbol} is {\tt TRUE}, then numerically zero entries in {\tt L} due to relaxed supernodal amalgamation are removed from the simplicial factor (they are always left in the supernodal form of {\tt L}). Entries that are numerically zero but present in the simplicial symbolic pattern of {\tt L} are left in place (the graph of {\tt L} remains chordal). This is required for the update/downdate/rowadd/rowdel routines to work properly. If the matrix is not positive definite the routine returns {\tt TRUE}, but {\tt Common->status} is set to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set to the column at which the failure occurred. Columns {\tt L->minor} to {\tt L->n-1} are set to zero. Supports any xtype (pattern, real, complex, or zomplex), except that the input matrix {\tt A} cannot be pattern-only. If {\tt L} is simplicial, its numeric xtype matches {\tt A} on output. If {\tt L} is supernodal, its xtype is real if {\tt A} is real, or complex if {\tt A} is complex or zomplex. CHOLMOD does not provide a supernodal zomplex factor, since it is incompatible with how complex numbers are stored in LAPACK and the BLAS. %--------------------------------------- \newpage \subsection{{\tt cholmod\_analyze\_p}: symbolic factorization, given permutation} %--------------------------------------- \input{_analyze_p.tex} Identical to {\tt cholmod\_analyze}, except that a user-provided permutation {\tt p} can be provided, and the set {\tt f} for the unsymmetric case can be provided. The matrices {\tt A(:,f)*A(:,f)'} or {\tt A(p,f)*A(p,f)'} can be analyzed in the the unsymmetric case. %--------------------------------------- \subsection{{\tt cholmod\_factorize\_p}: numeric factorization, given permutation} %--------------------------------------- \input{_factorize_p.tex} Identical to {\tt cholmod\_factorize}, but with additional options. The set {\tt f} can be provided for the unsymmetric case; {\tt A(p,f)*A(p,f)'} is factorized. The term {\tt beta*I} can be added to the matrix before it is factorized, where {\tt beta} is real. Only the real part, {\tt beta[0]}, is used. %--------------------------------------- \newpage \subsection{{\tt cholmod\_solve}: solve a linear system} %--------------------------------------- \input{_solve.tex} Returns a solution {\tt X} that solves one of the following systems: \begin{tabular}{ll|ll} \hline system & {\tt sys} parameter & system & {\tt sys} parameter \\ $\m{Ax}=\m{b}$ & 0: {\tt CHOLMOD\_A} & & \\ $\m{LDL}\tr\m{x}=\m{b}$ & 1: {\tt CHOLMOD\_LDLt} & $\m{L}\tr\m{x}=\m{b}$ & 5: {\tt CHOLMOD\_Lt} \\ $\m{LDx}=\m{b}$ & 2: {\tt CHOLMOD\_LD} & $\m{Dx}=\m{b}$ & 6: {\tt CHOLMOD\_D} \\ $\m{DL}\tr\m{x}=\m{b}$ & 3: {\tt CHOLMOD\_DLt} & $\m{x}=\m{Pb}$ & 7: {\tt CHOLMOD\_P} \\ $\m{Lx}=\m{b}$ & 4: {\tt CHOLMOD\_L} & $\m{x}=\m{P}\tr\m{b}$ & 8: {\tt CHOLMOD\_Pt} \\ \hline \end{tabular} The factorization can be simplicial $\m{LDL}\tr$, simplicial $\m{LL}\tr$, or supernodal $\m{LL}\tr$. For an $\m{LL}\tr$ factorization, $\m{D}$ is the identity matrix. Thus {\tt CHOLMOD\_LD} and {\tt CHOLMOD\_L} solve the same system if an $\m{LL}\tr$ factorization was performed, for example. This is one of the few routines in CHOLMOD for which the xtype of the input arguments need not match. If both {\tt L} and {\tt B} are real, then {\tt X} is returned real. If either is complex or zomplex, {\tt X} is returned as either complex or zomplex, depending on the {\tt Common->prefer\_zomplex} parameter (default is complex). This routine does not check to see if the diagonal of $\m{L}$ or $\m{D}$ is zero, because sometimes a partial solve can be done with an indefinite or singular matrix. If you wish to check in your own code, test {\tt L->minor}. If {\tt L->minor == L->n}, then the matrix has no zero diagonal entries. If {\tt k = L->minor < L->n}, then {\tt L(k,k)} is zero for an $\m{LL}\tr$ factorization, or {\tt D(k,k)} is zero for an $\m{LDL}\tr$ factorization. Iterative refinement is not performed, but this can be easily done with the {\tt MatrixOps} Module. See {\tt Demo/cholmod\_demo.c} for an example. %--------------------------------------- \subsection{{\tt cholmod\_spsolve}: solve a linear system} %--------------------------------------- \input{_spsolve.tex} Identical to {\tt cholmod\_spsolve}, except that {\tt B} and {\tt X} are sparse. %--------------------------------------- \newpage \subsection{{\tt cholmod\_etree}: find elimination tree} %--------------------------------------- \input{_etree.tex} Computes the elimination tree of {\tt A} or {\tt A'*A}. In the symmetric case, the upper triangular part of {\tt A} is used. Entries not in this part of the matrix are ignored. Computing the etree of a symmetric matrix from just its lower triangular entries is not supported. In the unsymmetric case, all of {\tt A} is used, and the etree of {\tt A'*A} is computed. Refer to \cite{Liu90a} for a discussion of the elimination tree and its use in sparse Cholesky factorization. % J. Liu, "The role of elimination trees in sparse factorization", SIAM J. % Matrix Analysis \& Applic., vol 11, 1990, pp. 134-172. %--------------------------------------- \subsection{{\tt cholmod\_rowcolcounts}: nonzeros counts of a factor} %--------------------------------------- \input{_rowcolcounts.tex} Compute the row and column counts of the Cholesky factor {\tt L} of the matrix {\tt A} or {\tt A*A'}. The etree and its postordering must already be computed (see {\tt cholmod\_etree} and {\tt cholmod\_postorder}) and given as inputs to this routine. For the symmetric case ($\m{LL}\tr=\m{A}$), {\tt A} must be stored in symmetric/lower form ({\tt A->stype = -1}). In the unsymmetric case, {\tt A*A'} or {\tt A(:,f)*A(:,f)'} can be analyzed. The fundamental floating-point operation count is returned in {\tt Common->fl} (this excludes extra flops due to relaxed supernodal amalgamation). Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. The algorithm is described in \cite{GilbertLiNgPeyton01,GilbertNgPeyton94}. % J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and % column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis \& % Applic., vol 15, 1994, pp. 1075-1091. % % J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for % sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710. %--------------------------------------- \newpage \subsection{{\tt cholmod\_analyze\_ordering}: analyze a permutation} %--------------------------------------- \input{_analyze_ordering.tex} Given a matrix {\tt A} and its fill-reducing permutation, compute the elimination tree, its (non-weighted) postordering, and the number of nonzeros in each column of {\tt L}. Also computes the flop count, the total nonzeros in {\tt L}, and the nonzeros in {\tt tril(A)} ({\tt Common->fl}, {\tt Common->lnz}, and {\tt Common->anz}). In the unsymmetric case, {\tt A(p,f)*A(p,f)'} is analyzed, and {\tt Common->anz} is the number of nonzero entries in the lower triangular part of the product, not in {\tt A} itself. Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. The column counts of {\tt L}, flop count, and other statistics from {\tt cholmod\_rowcolcounts} are not computed if {\tt ColCount} is {\tt NULL}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_amd}: interface to AMD} %--------------------------------------- \input{_amd.tex} CHOLMOD interface to the AMD ordering package. Orders {\tt A} if the matrix is symmetric. On output, {\tt Perm [k] = i} if row/column {\tt i} of {\tt A} is the {\tt k}th row/column of {\tt P*A*P'}. This corresponds to {\tt A(p,p)} in MATLAB notation. If A is unsymmetric, {\tt cholmod\_amd} orders {\tt A*A'} or {\tt A(:,f)*A(:,f)'}. On output, {\tt Perm [k] = i} if row/column {\tt i} of {\tt A*A'} is the {\tt k}th row/column of {\tt P*A*A'*P'}. This corresponds to {\tt A(p,:)*A(p,:)'} in MATLAB notation. If {\tt f} is present, {\tt A(p,f)*A(p,f)'} is the permuted matrix. Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. Computes the flop count for a subsequent $\m{LL}\tr$ factorization, the number of nonzeros in {\tt L}, and the number of nonzeros in the matrix ordered ({\tt A}, {\tt A*A'} or {\tt A(:,f)*A(:,f)'}). These statistics are returned in {\tt Common->fl}, {\tt Common->lnz}, and {\tt Common->anz}, respectively. %--------------------------------------- \subsection{{\tt cholmod\_colamd}: interface to COLAMD} %--------------------------------------- \input{_colamd.tex} CHOLMOD interface to the COLAMD ordering package. Finds a permutation {\tt p} such that the Cholesky factorization of {\tt P*A*A'*P'} is sparser than {\tt A*A'}, using COLAMD. If the {\tt postorder} input parameter is {\tt TRUE}, the column elimination tree is found and postordered, and the COLAMD ordering is then combined with its postordering (COLAMD itself does not perform this postordering). {\tt A} must be unsymmetric ({\tt A->stype = 0}). %--------------------------------------- \newpage \subsection{{\tt cholmod\_rowfac}: row-oriented Cholesky factorization} %--------------------------------------- \input{_rowfac.tex} Full or incremental numerical $\m{LDL}\tr$ or $\m{LL}\tr$ factorization (simplicial, not supernodal). {\tt cholmod\_factorize} is the ``easy'' wrapper for this code, but it does not provide access to incremental factorization. The algorithm is the row-oriented, up-looking method described in \cite{Davis05}. See also \cite{Liu86c}. No 2-by-2 pivoting (or any other pivoting) is performed. {\tt cholmod\_rowfac} computes the full or incremental $\m{LDL}\tr$ or $\m{LL}\tr$ factorization of {\tt A+beta*I} (where {\tt A} is symmetric) or {\tt A*F+beta*I} (where {\tt A} and {\tt F} are unsymmetric and only the upper triangular part of {\tt A*F+beta*I} is used). It computes {\tt L} (and {\tt D}, for $\m{LDL}\tr$) one row at a time. The input scalar {\tt beta} is real; only the real part ({\tt beta[0]}) is used. {\tt L} can be a simplicial symbolic or numeric ({\tt L->is\_super} must be {\tt FALSE}). A symbolic factor is converted immediately into a numeric factor containing the identity matrix. For a full factorization, use {\tt kstart = 0} and {\tt kend = nrow}. The existing nonzero entries (numerical values in {\tt L->x} and {\tt L->z} for the zomplex case, and indices in {\tt L->i}) are overwritten. To compute an incremental factorization, select {\tt kstart} and {\tt kend} as the range of rows of {\tt L} you wish to compute. Rows {\tt kstart} to {\tt kend-1} of {\tt L} will be computed. A correct factorization will be computed only if all descendants of all nodes {\tt kstart} to {\tt kend-1} in the elimination tree have been factorized by a prior call to this routine, and if rows {\tt kstart} to {\tt kend-1} have not been factorized. This condition is {\bf not} checked on input. In the symmetric case, {\tt A} must be stored in upper form ({\tt A->stype} is greater than zero). The matrix {\tt F} is not accessed and may be {\tt NULL}. Only columns {\tt kstart} to {\tt kend-1} of {\tt A} are accessed. In the unsymmetric case, the typical case is {\tt F=A'}. Alternatively, if {\tt F=A(:,f)'}, then this routine factorizes the matrix {\tt S = beta*I + A(:,f)*A(:,f)'}. The product {\tt A*F} is assumed to be symmetric; only the upper triangular part of {\tt A*F} is used. {\tt F} must be of size {\tt A->ncol} by {\tt A->nrow}. % J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans. % Math. Software, vol 12, 1986, pp. 127-148. %--------------------------------------- \subsection{{\tt cholmod\_rowfac\_mask}: row-oriented Cholesky factorization} %--------------------------------------- \input{_rowfac_mask.tex} For use in LPDASA only. %--------------------------------------- \newpage \subsection{{\tt cholmod\_row\_subtree}: pattern of row of a factor} %--------------------------------------- \input{_row_subtree.tex} Compute the nonzero pattern of the solution to the lower triangular system \begin{verbatim} L(0:k-1,0:k-1) * x = A (0:k-1,k) \end{verbatim} if {\tt A} is symmetric, or \begin{verbatim} L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)' \end{verbatim} if {\tt A} is unsymmetric. This gives the nonzero pattern of row {\tt k} of {\tt L} (excluding the diagonal). The pattern is returned postordered, according to the subtree of the elimination tree rooted at node {\tt k}. The symmetric case requires {\tt A} to be in symmetric-upper form. The result is returned in {\tt R}, a pre-allocated sparse matrix of size {\tt nrow}-by-1, with {\tt R->nzmax >= nrow}. {\tt R} is assumed to be packed ({\tt Rnz [0]} is not updated); the number of entries in {\tt R} is given by {\tt Rp [0]}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_row\_lsubtree}: pattern of row of a factor} %--------------------------------------- \input{_row_lsubtree.tex} Identical to {\tt cholmod\_row\_subtree}, except the elimination tree is found from {\tt L} itself, not {\tt Parent}. Also, {\tt F=A'} is not provided; the nonzero pattern of the {\tt k}th column of {\tt F} is given by {\tt Fi} and {\tt fnz} instead. %--------------------------------------- \newpage \subsection{{\tt cholmod\_resymbol}: re-do symbolic factorization} %--------------------------------------- \input{_resymbol.tex} Recompute the symbolic pattern of {\tt L}. Entries not in the symbolic pattern of the factorization of {\tt A(p,p)} or {\tt F*F'}, where {\tt F=A(p,f)} or {\tt F=A(:,f)}, are dropped, where {\tt p = L->Perm} is used to permute the input matrix {\tt A}. Refer to {\tt cholmod\_transpose\_unsym} for a description of {\tt f}. If an entry in {\tt L} is kept, its numerical value does not change. This routine is used after a supernodal factorization is converted into a simplicial one, to remove zero entries that were added due to relaxed supernode amalgamation. It can also be used after a series of downdates to remove entries that would no longer be present if the matrix were factorized from scratch. A downdate ({\tt cholmod\_updown}) does not remove any entries from {\tt L}. %--------------------------------------- \subsection{{\tt cholmod\_resymbol\_noperm}: re-do symbolic factorization} %--------------------------------------- \input{_resymbol_noperm.tex} Identical to {\tt cholmod\_resymbol}, except that the fill-reducing ordering {\tt L->Perm} is not used. %--------------------------------------- \newpage \subsection{{\tt cholmod\_postorder}: tree postorder} %--------------------------------------- \input{_postorder.tex} Postorder a tree. The tree is either an elimination tree (the output from {\tt cholmod\_etree}) or a component tree (from {\tt cholmod\_nested\_dissection}). An elimination tree is a complete tree of {\tt n} nodes with {\tt Parent [j] > j} or {\tt Parent [j] = -1} if j is a root. On output {\tt Post [0..n-1]} is a complete permutation vector; {\tt Post [k] = j} if node {\tt j} is the {\tt k}th node in the postordered elimination tree, where {\tt k} is in the range 0 to {\tt n-1}. A component tree is a subset of {\tt 0:n-1}. {\tt Parent [j] = -2} if node {\tt j} is not in the component tree. {\tt Parent [j] = -1} if {\tt j} is a root of the component tree, and {\tt Parent [j]} is in the range 0 to {\tt n-1} if {\tt j} is in the component tree but not a root. On output, {\tt Post [k]} is defined only for nodes in the component tree. {\tt Post [k] = j} if node {\tt j} is the {\tt k}th node in the postordered component tree, where {\tt k} is in the range 0 to the number of components minus 1. Node {\tt j} is ignored and not included in the postorder if {\tt Parent [j] < -1}. As a result, {\tt cholmod\_check\_parent (Parent, ...)} and {\tt cholmod\_check\_perm (Post, ...)} fail if used for a component tree and its postordering. An optional node weight can be given. When starting a postorder at node {\tt j}, the children of {\tt j} are ordered in decreasing order of their weight. If no weights are given ({\tt Weight} is {\tt NULL}) then children are ordered in decreasing order of their node number. The weight of a node must be in the range 0 to {\tt n-1}. Weights outside that range are silently converted to that range (weights $<$ 0 are treated as zero, and weights $\ge$ {\tt n} are treated as {\tt n-1}). %--------------------------------------- \subsection{{\tt cholmod\_rcond}: reciprocal condition number} %--------------------------------------- \input{_rcond.tex} Returns a rough estimate of the reciprocal of the condition number: the minimum entry on the diagonal of {\tt L} (or absolute entry of {\tt D} for an $\m{LDL}\tr$ factorization) divided by the maximum entry. {\tt L} can be real, complex, or zomplex. Returns -1 on error, 0 if the matrix is singular or has a zero or NaN entry on the diagonal of {\tt L}, 1 if the matrix is 0-by-0, or {\tt min(diag(L))/max(diag(L))} otherwise. Never returns NaN; if {\tt L} has a NaN on the diagonal it returns zero instead. %------------------------------------------------------------------------------- \newpage \section{{\tt Modify} Module routines} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_updown}: update/downdate} %--------------------------------------- \input{_updown.tex} Updates/downdates the $\m{LDL}\tr$ factorization (symbolic, then numeric), by computing a new factorization of \[ \new{\m{L}}\new{\m{D}}\new{\m{L}}\tr = \m{LDL}\tr \pm \m{CC}\tr \] where $\new{\m{L}}$ denotes the new factor. {\tt C} must be sorted. It can be either packed or unpacked. As in all CHOLMOD routines, the columns of {\tt L} are sorted on input, and also on output. If {\tt L} does not contain a simplicial numeric $\m{LDL}\tr$ factorization, it is converted into one. Thus, a supernodal $\m{LL}\tr$ factorization can be passed to {\tt cholmod\_updown}. A symbolic {\tt L} is converted into a numeric identity matrix. If the initial conversion fails, the factor is returned unchanged. If memory runs out during the update, the factor is returned as a simplicial symbolic factor. That is, everything is freed except for the fill-reducing ordering and its corresponding column counts (typically computed by {\tt cholmod\_analyze}). Note that the fill-reducing permutation {\tt L->Perm} is not used. The row indices of {\tt C} refer to the rows of {\tt L}, not {\tt A}. If your original system is $\m{LDL}\tr = \m{PAP}\tr$ (where $\m{P} =$ {\tt L->Perm}), and you want to compute the $\m{LDL}\tr$ factorization of $\m{A}+\m{CC}\tr$, then you must permute $\m{C}$ first. That is, if \[ \m{PAP}\tr = \m{LDL}\tr \] is the initial factorization, then \[ \m{P}(\m{A}+\m{CC}\tr)\m{P}\tr = \m{PAP}\tr+\m{PCC}\tr\m{P}\tr = \m{LDL}\tr + (\m{PC})(\m{PC})\tr = \m{LDL}\tr + \new{\m{C}}\new{\m{C}}\tr \] where $\new{\m{C}} = \m{PC}$. You can use the {\tt cholmod\_submatrix} routine in the {\tt MatrixOps} Module to permute {\tt C}, with: \begin{verbatim} Cnew = cholmod_submatrix (C, L->Perm, L->n, NULL, -1, TRUE, TRUE, Common) ; \end{verbatim} Note that the {\tt sorted} input parameter to {\tt cholmod\_submatrix} must be {\tt TRUE}, because {\tt cholmod\_updown} requires {\tt C} with sorted columns. Only real matrices are supported. The algorithms are described in \cite{DavisHager99,DavisHager01}. %--------------------------------------- \subsection{{\tt cholmod\_updown\_solve}: update/downdate} %--------------------------------------- \input{_updown_solve.tex} Identical to {\tt cholmod\_updown}, except the system $\m{Lx}=\m{b}$ is also updated/downdated. The new system is $\new{\m{L}}\new{\m{x}}=\m{b} + \Delta \m{b}$. The old solution $\m{x}$ is overwritten with $\new{\m{x}}$. Note that as in the update/downdate of $\m{L}$ itself, the fill- reducing permutation {\tt L->Perm} is not used. The vectors $\m{x}$ and $\m{b}$ are in the permuted ordering, not your original ordering. This routine does not handle multiple right-hand-sides. %--------------------------------------- \newpage \subsection{{\tt cholmod\_updown\_mark}: update/downdate} %--------------------------------------- \input{_updown_mark.tex} Identical to {\tt cholmod\_updown\_solve}, except that only part of $\m{L}$ is used in the update of the solution to $\m{Lx}=\m{b}$. For more details, see the source code file {\tt CHOLMOD/Modify/cholmod\_updown.c}. This routine is meant for use in the {\tt LPDASA} linear program solver only, by Hager and Davis. %--------------------------------------- \subsection{{\tt cholmod\_updown\_mask}: update/downdate} %--------------------------------------- \input{_updown_mask.tex} For use in LPDASA only. %--------------------------------------- \newpage \subsection{{\tt cholmod\_rowadd}: add row to factor} %--------------------------------------- \input{_rowadd.tex} Adds a row and column to an $\m{LDL}\tr$ factorization. The {\tt k}th row and column of {\tt L} must be equal to the {\tt k}th row and column of the identity matrix on input. Only real matrices are supported. The algorithm is described in \cite{DavisHager05}. %--------------------------------------- \subsection{{\tt cholmod\_rowadd\_solve}: add row to factor} %--------------------------------------- \input{_rowadd_solve.tex} Identical to {\tt cholmod\_rowadd}, except the system $\m{Lx}=\m{b}$ is also updated/downdated, just like {\tt cholmod\_updown\_solve}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_rowdel}: delete row from factor} %--------------------------------------- \input{_rowdel.tex} Deletes a row and column from an $\m{LDL}\tr$ factorization. The {\tt k}th row and column of {\tt L} is equal to the {\tt k}th row and column of the identity matrix on output. Only real matrices are supported. %--------------------------------------- \subsection{{\tt cholmod\_rowdel\_solve}: delete row from factor} %--------------------------------------- \input{_rowdel_solve.tex} Identical to {\tt cholmod\_rowdel}, except the system $\m{Lx}=\m{b}$ is also updated/downdated, just like {\tt cholmod\_updown\_solve}. When row/column $k$ of $\m{A}$ is deleted from the system $\m{Ay}=\m{b}$, this can induce a change to $\m{x}$, in addition to changes arising when $\m{L}$ and $\m{b}$ are modified. If this is the case, the kth entry of $\m{y}$ is required as input ({\tt yk}). The algorithm is described in \cite{DavisHager05}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_rowadd\_mark}: add row to factor} %--------------------------------------- \input{_rowadd_mark.tex} Identical to {\tt cholmod\_rowadd\_solve}, except that only part of $\m{L}$ is used in the update of the solution to $\m{Lx}=\m{b}$. For more details, see the source code file {\tt CHOLMOD/Modify/cholmod\_rowadd.c}. This routine is meant for use in the {\tt LPDASA} linear program solver only. %--------------------------------------- \subsection{{\tt cholmod\_rowdel\_mark}: delete row from factor} %--------------------------------------- \input{_rowdel_mark.tex} Identical to {\tt cholmod\_rowadd\_solve}, except that only part of $\m{L}$ is used in the update of the solution to $\m{Lx}=\m{b}$. For more details, see the source code file {\tt CHOLMOD/Modify/cholmod\_rowdel.c}. This routine is meant for use in the {\tt LPDASA} linear program solver only. %------------------------------------------------------------------------------- \newpage \section{{\tt MatrixOps} Module routines} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_drop}: drop small entries} %--------------------------------------- \input{_drop.tex} Drop small entries from {\tt A}, and entries in the ignored part of {\tt A} if {\tt A} is symmetric. No CHOLMOD routine drops small numerical entries from a matrix, except for this one. NaN's and Inf's are kept. Supports pattern and real matrices; complex and zomplex matrices are not supported. %--------------------------------------- \subsection{{\tt cholmod\_norm\_dense}: dense matrix norm} %--------------------------------------- \input{_norm_dense.tex} Returns the infinity-norm, 1-norm, or 2-norm of a dense matrix. Can compute the 2-norm only for a dense column vector. All xtypes are supported. %--------------------------------------- \subsection{{\tt cholmod\_norm\_sparse}: sparse matrix norm} %--------------------------------------- \input{_norm_sparse.tex} Returns the infinity-norm or 1-norm of a sparse matrix. All xtypes are supported. %--------------------------------------- \newpage \subsection{{\tt cholmod\_scale}: scale sparse matrix} %--------------------------------------- \input{_scale.tex} Scales a matrix: {\tt A = diag(s)*A}, {\tt A*diag(s)}, {\tt s*A}, or {\tt diag(s)*A*diag(s)}. {\tt A} can be of any type (packed/unpacked, upper/lower/unsymmetric). The symmetry of {\tt A} is ignored; all entries in the matrix are modified. If {\tt A} is {\tt m}-by-{\tt n} unsymmetric but scaled symmetrically, the result is \begin{verbatim} A = diag (s (1:m)) * A * diag (s (1:n)) \end{verbatim} Row or column scaling of a symmetric matrix still results in a symmetric matrix, since entries are still ignored by other routines. For example, when row-scaling a symmetric matrix where just the upper triangular part is stored (and lower triangular entries ignored) {\tt A = diag(s)*triu(A)} is performed, where the result {\tt A} is also symmetric-upper. This has the effect of modifying the implicit lower triangular part. In MATLAB notation: \begin{verbatim} U = diag(s)*triu(A) ; L = tril (U',-1) A = L + U ; \end{verbatim} The scale parameter determines the kind of scaling to perform and the size of {\tt S}: \begin{tabular}{lll} \hline {\tt scale} & operation & size of {\tt S} \\ \hline {\tt CHOLMOD\_SCALAR} & {\tt s[0]*A} & 1 \\ {\tt CHOLMOD\_ROW} & {\tt diag(s)*A} & {\tt nrow}-by-1 or 1-by-{\tt nrow} \\ {\tt CHOLMOD\_COL} & {\tt A*diag(s)} & {\tt ncol}-by-1 or 1-by-{\tt ncol} \\ {\tt CHOLMOD\_SYM} & {\tt diag(s)*A*diag(s)} & {\tt max(nrow,ncol)}-by-1, or 1-by-{\tt max(nrow,ncol)} \\ \hline \end{tabular} Only real matrices are supported. %--------------------------------------- \newpage \subsection{{\tt cholmod\_sdmult}: sparse-times-dense matrix} %--------------------------------------- \input{_sdmult.tex} Sparse matrix times dense matrix: {\tt Y = alpha*(A*X) + beta*Y} or {\tt Y = alpha*(A'*X) + beta*Y}, where {\tt A} is sparse and {\tt X} and {\tt Y} are dense. When using {\tt A}, {\tt X} has {\tt A->ncol} columns and {\tt Y} has {\tt A->nrow} rows. When using {\tt A'}, {\tt X} has {\tt A->nrow} columns and {\tt Y} has {\tt A->ncol} rows. If {\tt transpose = 0}, then {\tt A} is used; otherwise, {\tt A'} is used (the complex conjugate transpose). The {\tt transpose} parameter is ignored if the matrix is symmetric or Hermitian. (the array transpose {\tt A.'} is not supported). Supports real, complex, and zomplex matrices, but the xtypes of {\tt A}, {\tt X}, and {\tt Y} must all match. %--------------------------------------- \subsection{{\tt cholmod\_ssmult}: sparse-times-sparse matrix} %--------------------------------------- \input{_ssmult.tex} Computes {\tt C = A*B}; multiplying two sparse matrices. {\tt C} is returned as packed, and either unsorted or sorted, depending on the {\tt sorted} input parameter. If {\tt C} is returned sorted, then either {\tt C = (B'*A')'} or {\tt C = (A*B)''} is computed, depending on the number of nonzeros in {\tt A}, {\tt B}, and {\tt C}. The stype of {\tt C} is determined by the {\tt stype} parameter. Only pattern and real matrices are supported. Complex and zomplex matrices are supported only when the numerical values are not computed ({\tt values} is {\tt FALSE}). %--------------------------------------- \newpage \subsection{{\tt cholmod\_submatrix}: sparse submatrix} %--------------------------------------- \input{_submatrix.tex} Returns {\tt C = A (rset,cset)}, where {\tt C} becomes {\tt length(rset)}-by-{\tt length(cset)} in dimension. {\tt rset} and {\tt cset} can have duplicate entries. {\tt A} must be unsymmetric. {\tt C} unsymmetric and is packed. If {\tt sorted} is {\tt TRUE} on input, or {\tt rset} is sorted and {\tt A} is sorted, then {\tt C} is sorted; otherwise {\tt C} is unsorted. If {\tt rset} is {\tt NULL}, it means ``{\tt [ ]}'' in MATLAB notation, the empty set. The number of rows in the result {\tt C} will be zero if {\tt rset} is {\tt NULL}. Likewise if {\tt cset} means the empty set; the number of columns in the result {\tt C} will be zero if {\tt cset} is {\tt NULL}. If {\tt rsize} or {\tt csize} is negative, it denotes ``{\tt :}'' in MATLAB notation. Thus, if both {\tt rsize} and {\tt csize} are negative {\tt C = A(:,:) = A} is returned. For permuting a matrix, this routine is an alternative to {\tt cholmod\_ptranspose} (which permutes and transposes a matrix and can work on symmetric matrices). The time taken by this routine is O({\tt A->nrow}) if the {\tt Common} workspace needs to be initialized, plus O({\tt C->nrow + C->ncol + nnz (A (:,cset))}). Thus, if {\tt C} is small and the workspace is not initialized, the time can be dominated by the call to {\tt cholmod\_allocate\_work}. However, once the workspace is allocated, subsequent calls take less time. Only pattern and real matrices are supported. Complex and zomplex matrices are supported only when {\tt values} is {\tt FALSE}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_horzcat}: horizontal concatenation} %--------------------------------------- \input{_horzcat.tex} Horizontal concatenation, returns {\tt C = [A,B]} in MATLAB notation. {\tt A} and {\tt B} can have any stype. {\tt C} is returned unsymmetric and packed. {\tt A} and {\tt B} must have the same number of rows. {\tt C} is sorted if both {\tt A} and {\tt B} are sorted. {\tt A} and {\tt B} must have the same numeric xtype, unless {\tt values} is {\tt FALSE}. {\tt A} and {\tt B} cannot be complex or zomplex, unless {\tt values} is {\tt FALSE}. %--------------------------------------- \subsection{{\tt cholmod\_vertcat}: vertical concatenation} %--------------------------------------- \input{_vertcat.tex} Vertical concatenation, returns {\tt C = [A;B]} in MATLAB notation. {\tt A} and {\tt B} can have any stype. {\tt C} is returned unsymmetric and packed. {\tt A} and {\tt B} must have the same number of columns. {\tt C} is sorted if both {\tt A} and {\tt B} are sorted. {\tt A} and {\tt B} must have the same numeric xtype, unless {\tt values} is {\tt FALSE}. {\tt A} and {\tt B} cannot be complex or zomplex, unless {\tt values} is {\tt FALSE}. %--------------------------------------- \newpage \subsection{{\tt cholmod\_symmetry}: compute the symmetry of a matrix} %--------------------------------------- \input{_symmetry.tex} Determines if a sparse matrix is rectangular, unsymmetric, symmetric, skew-symmetric, or Hermitian. It does so by looking at its numerical values of both upper and lower triangular parts of a CHOLMOD "unsymmetric" matrix, where A->stype == 0. The transpose of A is NOT constructed. If not unsymmetric, it also determines if the matrix has a diagonal whose entries are all real and positive (and thus a candidate for sparse Cholesky if A->stype is changed to a nonzero value). Note that a Matrix Market "general" matrix is either rectangular or unsymmetric. The row indices in the column of each matrix MUST be sorted for this function to work properly (A->sorted must be TRUE). This routine returns EMPTY if A->stype is not zero, or if A->sorted is FALSE. The exception to this rule is if A is rectangular. If option == 0, then this routine returns immediately when it finds a non-positive diagonal entry (or one with nonzero imaginary part). If the matrix is not a candidate for sparse Cholesky, it returns the value {\tt CHOLMOD\_MM\_UNSYMMETRIC}, even if the matrix might in fact be symmetric or Hermitian. This routine is useful inside the MATLAB backslash, which must look at an arbitrary matrix (A->stype == 0) and determine if it is a candidate for sparse Cholesky. In that case, option should be 0. This routine is also useful when writing a MATLAB matrix to a file in Rutherford/Boeing or Matrix Market format. Those formats require a determination as to the symmetry of the matrix, and thus this routine should not return upon encountering the first non-positive diagonal. In this case, option should be 1. If option is 2, this function can be used to compute the numerical and pattern symmetry, where 0 is a completely unsymmetric matrix, and 1 is a perfectly symmetric matrix. This option is used when computing the following statistics for the matrices in the UF Sparse Matrix Collection. numerical symmetry: number of matched offdiagonal nonzeros over the total number of offdiagonal entries. A real entry $a_{ij}$, $i \ne j$, is matched if $a_{ji} = a_{ij}$, but this is only counted if both $a_{ji}$ and $a_{ij}$ are nonzero. This does not depend on {\tt Z}. (If A is complex, then the above test is modified; $a_{ij}$ is matched if $\mbox{conj}(a_{ji}) = a_{ij}$. Then numeric symmetry = xmatched / nzoffdiag, or 1 if nzoffdiag = 0. pattern symmetry: number of matched offdiagonal entries over the total number of offdiagonal entries. An entry $a_{ij}$, $i \ne j$, is matched if $a_{ji}$ is also an entry. Then pattern symmetry = pmatched / nzoffdiag, or 1 if nzoffdiag = 0. The symmetry of a matrix with no offdiagonal entries is equal to 1. A workspace of size ncol integers is allocated; EMPTY is returned if this allocation fails. Summary of return values: \begin{tabular}{ll} {\tt EMPTY (-1)} & out of memory, stype not zero, A not sorted \\ {\tt CHOLMOD\_MM\_RECTANGULAR 1} & A is rectangular \\ {\tt CHOLMOD\_MM\_UNSYMMETRIC 2} & A is unsymmetric \\ {\tt CHOLMOD\_MM\_SYMMETRIC 3} & A is symmetric, but with non-pos. diagonal \\ {\tt CHOLMOD\_MM\_HERMITIAN 4} & A is Hermitian, but with non-pos. diagonal \\ {\tt CHOLMOD\_MM\_SKEW\_SYMMETRIC 5} & A is skew symmetric \\ {\tt CHOLMOD\_MM\_SYMMETRIC\_POSDIAG 6} & A is symmetric with positive diagonal \\ {\tt CHOLMOD\_MM\_HERMITIAN\_POSDIAG 7} & A is Hermitian with positive diagonal \\ \end{tabular} See also the {\tt spsym} mexFunction, which is a MATLAB interface for this code. If the matrix is a candidate for sparse Cholesky, it will return a result \newline {\tt CHOLMOD\_MM\_SYMMETRIC\_POSDIAG} if real, or {\tt CHOLMOD\_MM\_HERMITIAN\_POSDIAG} if complex. Otherwise, it will return a value less than this. This is true regardless of the value of the option parameter. %------------------------------------------------------------------------------- \newpage \section{{\tt Supernodal} Module routines} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_super\_symbolic}: supernodal symbolic factorization} %--------------------------------------- \input{_super_symbolic.tex} Supernodal symbolic analysis of the $\m{LL}\tr$ factorization of {\tt A}, {\tt A*A'}, or {\tt A(:,f)*A(:,f)'}. This routine must be preceded by a simplicial symbolic analysis ({\tt cholmod\_rowcolcounts}). See {\tt Cholesky/cholmod\_analyze.c} for an example of how to use this routine. The user need not call this directly; {\tt cholmod\_analyze} is a ``simple'' wrapper for this routine. {\tt A} can be symmetric (upper), or unsymmetric. The symmetric/lower form is not supported. In the unsymmetric case {\tt F} is the normally transpose of {\tt A}. Alternatively, if {\tt F=A(:,f)'} then {\tt F*F'} is analyzed. Requires {\tt Parent} and {\tt L->ColCount} to be defined on input; these are the simplicial {\tt Parent} and {\tt ColCount} arrays as computed by {\tt cholmod\_rowcolcounts}. Does not use {\tt L->Perm}; the input matrices {\tt A} and {\tt F} must already be properly permuted. Allocates and computes the supernodal pattern of {\tt L} ({\tt L->super}, {\tt L->pi}, {\tt L->px}, and {\tt L->s}). Does not allocate the real part ({\tt L->x}). %--------------------------------------- \newpage \subsection{{\tt cholmod\_super\_numeric}: supernodal numeric factorization} %--------------------------------------- \input{_super_numeric.tex} Computes the numerical Cholesky factorization of {\tt A+beta*I} or {\tt A*F+beta*I}. Only the lower triangular part of {\tt A+beta*I} or {\tt A*F+beta*I} is accessed. The matrices {\tt A} and {\tt F} must already be permuted according to the fill-reduction permutation {\tt L->Perm}. {\tt cholmod\_factorize} is an "easy" wrapper for this code which applies that permutation. The input scalar {\tt beta} is real; only the real part ({\tt beta[0]} is used. Symmetric case: {\tt A} is a symmetric (lower) matrix. {\tt F} is not accessed and may be {\tt NULL}. With a fill-reducing permutation, {\tt A(p,p)} should be passed for {\tt A}, where is {\tt p} is {\tt L->Perm}. Unsymmetric case: {\tt A} is unsymmetric, and {\tt F} must be present. Normally, {\tt F=A'}. With a fill-reducing permutation, {\tt A(p,f)} and {\tt A(p,f)'} should be passed as the parameters {\tt A} and {\tt F}, respectively, where {\tt f} is a list of the subset of the columns of {\tt A}. The input factorization {\tt L} must be supernodal ({\tt L->is\_super} is {\tt TRUE}). It can either be symbolic or numeric. In the first case, {\tt L} has been analyzed by {\tt cholmod\_analyze} or {\tt cholmod\_super\_symbolic}, but the matrix has not yet been numerically factorized. The numerical values are allocated here and the factorization is computed. In the second case, a prior matrix has been analyzed and numerically factorized, and a new matrix is being factorized. The numerical values of {\tt L} are replaced with the new numerical factorization. {\tt L->is\_ll} is ignored on input, and set to {\tt TRUE} on output. This routine always computes an $\m{LL}\tr$ factorization. Supernodal $\m{LDL}\tr$ factorization is not supported. If the matrix is not positive definite the routine returns {\tt TRUE}, but sets {\tt Common->status} to {\tt CHOLMOD\_NOT\_POSDEF} and {\tt L->minor} is set to the column at which the failure occurred. Columns {\tt L->minor} to {\tt L->n-1} are set to zero. If {\tt L} is supernodal symbolic on input, it is converted to a supernodal numeric factor on output, with an xtype of real if {\tt A} is real, or complex if {\tt A} is complex or zomplex. If {\tt L} is supernodal numeric on input, its xtype must match {\tt A} (except that {\tt L} can be complex and {\tt A} zomplex). The xtype of {\tt A} and {\tt F} must match. %--------------------------------------- \newpage \subsection{{\tt cholmod\_super\_lsolve}: supernodal forward solve} %--------------------------------------- \input{_super_lsolve.tex} Solve $\m{Lx}=\m{b}$ for a supernodal factorization. This routine does not apply the permutation {\tt L->Perm}. See {\tt cholmod\_solve} for a more general interface that performs that operation. Only real and complex xtypes are supported. {\tt L}, {\tt X}, and {\tt E} must have the same xtype. %--------------------------------------- \subsection{{\tt cholmod\_super\_ltsolve}: supernodal backsolve} %--------------------------------------- \input{_super_ltsolve.tex} Solve $\m{L}\tr\m{x}=\m{b}$ for a supernodal factorization. This routine does not apply the permutation {\tt L->Perm}. See {\tt cholmod\_solve} for a more general interface that performs that operation. Only real and complex xtypes are supported. {\tt L}, {\tt X}, and {\tt E} must have the same xtype. %------------------------------------------------------------------------------- \newpage \section{{\tt Partition} Module routines} %------------------------------------------------------------------------------- %--------------------------------------- \subsection{{\tt cholmod\_nested\_dissection}: nested dissection ordering} %--------------------------------------- \input{_nested_dissection.tex} CHOLMOD's nested dissection algorithm: using its own compression and connected-components algorithms, an external graph partitioner (METIS), and a constrained minimum degree ordering algorithm (CAMD, CCOLAMD, or CSYMAMD). Typically gives better orderings than {\tt METIS\_NodeND} (about 5\% to 10\% fewer nonzeros in {\tt L}). This method uses a node bisector, applied recursively (but using a non-recursive implementation). Once the graph is partitioned, it calls a constrained minimum degree code (CAMD or CSYMAMD for {\tt A+A'}, and CCOLAMD for {\tt A*A'}) to order all the nodes in the graph - but obeying the constraints determined by the separators. This routine is similar to {\tt METIS\_NodeND}, except for how it treats the leaf nodes. {\tt METIS\_NodeND} orders the leaves of the separator tree with {\tt MMD}, ignoring the rest of the matrix when ordering a single leaf. This routine orders the whole matrix with CAMD, CSYMAMD, or CCOLAMD, all at once, when the graph partitioning is done. %--------------------------------------- \newpage \subsection{{\tt cholmod\_metis}: interface to METIS nested dissection} %--------------------------------------- \input{_metis.tex} CHOLMOD wrapper for the {\tt METIS\_NodeND} ordering routine. Creates {\tt A+A'}, {\tt A*A'} or {\tt A(:,f)*A(:,f)'} and then calls {\tt METIS\_NodeND} on the resulting graph. This routine is comparable to {\tt cholmod\_nested\_dissection}, except that it calls {\tt METIS\_NodeND} directly, and it does not return the separator tree. %--------------------------------------- \newpage \subsection{{\tt cholmod\_camd}: interface to CAMD} %--------------------------------------- \input{_camd.tex} CHOLMOD interface to the CAMD ordering routine. Finds a permutation {\tt p} such that the Cholesky factorization of {\tt A(p,p)} is sparser than {\tt A}. If {\tt A} is unsymmetric, {\tt A*A'} is ordered. If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}. All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on. %--------------------------------------- \newpage \subsection{{\tt cholmod\_ccolamd}: interface to CCOLAMD} %--------------------------------------- \input{_ccolamd.tex} CHOLMOD interface to the CCOLAMD ordering routine. Finds a permutation {\tt p} such that the Cholesky factorization of {\tt A(p,:)*A(p,:)'} is sparser than {\tt A*A'}. The column elimination is found and postordered, and the CCOLAMD ordering is then combined with its postordering. {\tt A} must be unsymmetric. If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}. All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on. %--------------------------------------- \subsection{{\tt cholmod\_csymamd}: interface to CSYMAMD} %--------------------------------------- \input{_csymamd.tex} CHOLMOD interface to the CSYMAMD ordering routine. Finds a permutation {\tt p} such that the Cholesky factorization of {\tt A(p,p)} is sparser than {\tt A}. The elimination tree is found and postordered, and the CSYMAMD ordering is then combined with its postordering. If {\tt A} is unsymmetric, {\tt A+A'} is ordered ({\tt A} must be square). If {\tt Cmember[i]=c} then node {\tt i} is in set {\tt c}. All nodes in set 0 are ordered first, followed by all nodes in set 1, and so on. %--------------------------------------- \newpage \subsection{{\tt cholmod\_bisect}: graph bisector} %--------------------------------------- \input{_bisect.tex} Finds a node bisector of {\tt A}, {\tt A*A'}, {\tt A(:,f)*A(:,f)'}: a set of nodes that partitions the graph into two parts. Compresses the graph first, and then calls METIS. %--------------------------------------- \subsection{{\tt cholmod\_metis\_bisector}: interface to METIS node bisector} %--------------------------------------- \input{_metis_bisector.tex} Finds a set of nodes that bisects the graph of {\tt A} or {\tt A*A'} (a direct interface to \newline {\tt METIS\_NodeComputeSeparator}). The input matrix {\tt A} must be square, symmetric (with both upper and lower parts present) and with no diagonal entries. These conditions are not checked. %--------------------------------------- \newpage \subsection{{\tt cholmod\_collapse\_septree}: prune a separator tree} %--------------------------------------- \input{_collapse_septree.tex} Prunes a separator tree obtained from {\tt cholmod\_nested\_dissection}. \newpage \bibliographystyle{plain} \bibliography{UserGuide} \end{document} cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Doc/UserGuide.bib0000644000175000017500000001212111674452555021465 0ustar sonnesonne@string{SIMAX = "{SIAM} J. Matrix Anal. Applic."} @string{TOMS = "{ACM} Trans. Math. Softw."} @string{SIAMJSC = "{SIAM} J. Sci. Comput."} @article{DavisHager06, author={Davis, T. A. and Hager, W. W.}, title={Dynamic supernodes in sparse {Cholesky} update/downdate and triangular solves}, journal=TOMS, year={submitted in 2006} } @article{ChenDavisHagerRajamanickam06, author={Chen, Y. and Davis, T. A. and Hager, W. W. and Rajamanickam, S.}, title={Algorithm 8xx: {CHOLMOD}, supernodal sparse {Cholesky} factorization and update/downdate}, journal=TOMS, year={submitted in 2006} } @article{DavisHager99, author={Davis, T. A. and Hager, W. W.}, title={Modifying a sparse {C}holesky factorization}, journal=SIMAX, year={1999} ,volume={20} ,number={3} ,pages={606--627} } @article{DavisHager01, author={Davis, T. A. and Hager, W. W.}, title={Multiple-Rank Modifications of a Sparse {C}holesky Factorization}, journal=SIMAX, year={2001} ,volume={22} ,number={4} ,pages={997--1013} } @article{DavisHager05, author={Davis, T. A. and Hager, W. W.}, title={Row modifications of a sparse {Cholesky} factorization}, journal=SIMAX, year={2005} ,volume={26} ,number={3} ,pages={621--639} } @article{AmestoyDavisDuff96, author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.}, title={An approximate minimum degree ordering algorithm}, journal=SIMAX, year={1996} ,volume={17} ,number={4} ,pages={886--905} } @article{Davis05, author={Davis, T. A.}, title={Algorithm 849: A concise sparse {Cholesky} algorithm}, journal=TOMS, year={2005},volume={31},number={4},pages={587--591}} @article{DavisGilbertLarimoreNg00, author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.}, title={A column approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,number={3} ,pages={353--376}} @article{DavisGilbertLarimoreNg00_algo, author={Davis, T. A. and Gilbert, J. R. and Larimore, S. I. and Ng, E. G.}, title={Algorithm 836: {COLAMD}, a column approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,number={3} ,pages={377--380}} @article{NgPeyton91b, author={Ng, E. and Peyton, B.}, title={Block sparse {C}holesky algorithms on advanced uniprocessor computers}, journal=SIAMJSC, year={1993} ,volume={14} ,pages={1034--1056} } @article{Liu86c, author={Liu, J. W. H.}, title={A Compact Row Storage Scheme for {C}holesky Factors Using Elimination Trees}, journal=TOMS, year={1986}, volume={12}, number={2}, pages={127--148}, } @article{Liu90a, author={Liu, J. W. H.}, title={The Role of Elimination Trees in Sparse Factorization}, journal=SIMAX, year={1990} ,volume={11} ,number={1} ,pages={134--172} } @article{GilbertNgPeyton94, author={Gilbert, J. R. and Ng, E. G. and Peyton, B. W.}, title={An efficient algorithm to compute row and column counts for sparse {C}holesky factorization}, journal=SIMAX, year={1994} ,volume={15} ,number={4} ,pages={1075--1091} } @article{GilbertLiNgPeyton01, author={Gilbert, J. R. and Li, X. S. and Ng, E. G. and Peyton, B. W.}, title={Computing row and column counts for sparse {QR} and {LU} factorization}, journal={{BIT}}, year={2001} ,volume={41} ,number={4} ,pages={693--710} } @book{LAPACK, author={Anderson, E. and Bai, Z. and Bischof, C. and Blackford, S. and Demmel, J. and Dongarra, J. and {Du Croz}, J. and Greenbaum, A. and Hammarling, S. and McKenny, A. and Sorensen, D.}, title={{LAPACK} Users' Guide, 3rd ed.}, publisher={{SIAM}}, year={1999} } @article{ACM679a, author={Dongarra, J. J. and {Du Croz}, J. and Duff, I. S. and Hammarling, S.}, title={A set of level-3 basic linear algebra subprograms}, journal=TOMS, year={1990} ,volume={16} ,number={1} ,pages={1--17} } @article{KarypisKumar98, author={Karypis, G. and Kumar, V.}, title={A fast and high quality multilevel scheme for partitioning irregular graphs}, journal=SIAMJSC, year=1998 ,volume={20} ,number={1} ,pages={359--392} } @article{GilbertMolerSchreiber, author={Gilbert, J. R. and Moler, C. and Schreiber, R.}, title={Sparse matrices in {MATLAB}: design and implementation}, journal=SIMAX, year={1992} ,volume={13} ,number={1} ,pages={333--356} } @article{AmestoyDavisDuff03, author={Amestoy, P. R. and Davis, T. A. and Duff, I. S.}, title={Algorithm 837: {AMD}, an approximate minimum degree ordering algorithm}, journal=TOMS, year={2004} ,volume={30} ,number={3} ,pages={381-388}} @article{GouldHuScott05, author={Gould, N. I. M. and Hu, Y. and Scott, J. A.}, title={A numerical evaluation of sparse direct solvers for the solution of large sparse, symmetric linear systems of equations}, journal=TOMS, year={to appear} } @techreport{GouldHuScott05b, author={Gould, N. I. M. and Hu, Y. and Scott, J. A.}, title={Complete results from a numerical evaluation of sparse direct solvers for the solution of large sparse, symmetric linear systems of equations}, institution={CCLRC, Rutherford Appleton Laboratory}, number={Internal report 2005-1 (revision 1)}, year={2005}, howpublished={www.numerical.rl.ac.uk/reports/reports.shtml} } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/0000755000175000017500000000000011674452555017774 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_cholesky.h0000644000175000017500000004717311674452555023507 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_cholesky.h =========================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_cholesky.h. Copyright (C) 2005-2006, Timothy A. Davis * CHOLMOD/Include/cholmod_cholesky.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD Cholesky module. * * Sparse Cholesky routines: analysis, factorization, and solve. * * The primary routines are all that a user requires to order, analyze, and * factorize a sparse symmetric positive definite matrix A (or A*A'), and * to solve Ax=b (or A*A'x=b). The primary routines rely on the secondary * routines, the CHOLMOD Core module, and the AMD and COLAMD packages. They * make optional use of the CHOLMOD Supernodal and Partition modules, the * METIS package, and the CCOLAMD package. * * Primary routines: * ----------------- * * cholmod_analyze order and analyze (simplicial or supernodal) * cholmod_factorize simplicial or supernodal Cholesky factorization * cholmod_solve solve a linear system (simplicial or supernodal) * cholmod_spsolve solve a linear system (sparse x and b) * * Secondary routines: * ------------------ * * cholmod_analyze_p analyze, with user-provided permutation or f set * cholmod_factorize_p factorize, with user-provided permutation or f * cholmod_analyze_ordering analyze a fill-reducing ordering * cholmod_etree find the elimination tree * cholmod_rowcolcounts compute the row/column counts of L * cholmod_amd order using AMD * cholmod_colamd order using COLAMD * cholmod_rowfac incremental simplicial factorization * cholmod_rowfac_mask rowfac, specific to LPDASA * cholmod_row_subtree find the nonzero pattern of a row of L * cholmod_resymbol recompute the symbolic pattern of L * cholmod_resymbol_noperm recompute the symbolic pattern of L, no L->Perm * cholmod_postorder postorder a tree * * Requires the Core module, and two packages: AMD and COLAMD. * Optionally uses the Supernodal and Partition modules. * Required by the Partition module. */ #ifndef CHOLMOD_CHOLESKY_H #define CHOLMOD_CHOLESKY_H #include "cholmod_config.h" #include "cholmod_core.h" #ifndef NPARTITION #include "cholmod_partition.h" #endif #ifndef NSUPERNODAL #include "cholmod_supernodal.h" #endif /* -------------------------------------------------------------------------- */ /* cholmod_analyze: order and analyze (simplicial or supernodal) */ /* -------------------------------------------------------------------------- */ /* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor * that can later be passed to cholmod_factorize. */ cholmod_factor *cholmod_analyze ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order and analyze */ /* --------------- */ cholmod_common *Common ) ; cholmod_factor *cholmod_l_analyze (cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_analyze_p: analyze, with user-provided permutation or f set */ /* -------------------------------------------------------------------------- */ /* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a * symbolic factor that can later be passed to cholmod_factorize, where * F = A(:,fset) if fset is not NULL and A->stype is zero. * UserPerm is tried if non-NULL. */ cholmod_factor *cholmod_analyze_p ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order and analyze */ int *UserPerm, /* user-provided permutation, size A->nrow */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* --------------- */ cholmod_common *Common ) ; cholmod_factor *cholmod_l_analyze_p (cholmod_sparse *, UF_long *, UF_long *, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_analyze_p2: analyze for sparse Cholesky or sparse QR */ /* -------------------------------------------------------------------------- */ cholmod_factor *cholmod_analyze_p2 ( /* ---- input ---- */ int for_cholesky, /* if TRUE, then analyze for Cholesky; else for QR */ cholmod_sparse *A, /* matrix to order and analyze */ int *UserPerm, /* user-provided permutation, size A->nrow */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* --------------- */ cholmod_common *Common ) ; cholmod_factor *cholmod_l_analyze_p2 (int, cholmod_sparse *, UF_long *, UF_long *, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_factorize: simplicial or supernodal Cholesky factorization */ /* -------------------------------------------------------------------------- */ /* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained * from cholmod_analyze. The analysis can be re-used simply by calling this * routine a second time with another matrix. A must have the same nonzero * pattern as that passed to cholmod_analyze. */ int cholmod_factorize ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ /* ---- in/out --- */ cholmod_factor *L, /* resulting factorization */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_factorize (cholmod_sparse *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_factorize_p: factorize, with user-provided permutation or fset */ /* -------------------------------------------------------------------------- */ /* Same as cholmod_factorize, but with more options. */ int cholmod_factorize_p ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ double beta [2], /* factorize beta*I+A or beta*I+A'*A */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- in/out --- */ cholmod_factor *L, /* resulting factorization */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_factorize_p (cholmod_sparse *, double *, UF_long *, size_t, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_solve: solve a linear system (simplicial or supernodal) */ /* -------------------------------------------------------------------------- */ /* Solves one of many linear systems with a dense right-hand-side, using the * factorization from cholmod_factorize (or as modified by any other CHOLMOD * routine). D is identity for LL' factorizations. */ #define CHOLMOD_A 0 /* solve Ax=b */ #define CHOLMOD_LDLt 1 /* solve LDL'x=b */ #define CHOLMOD_LD 2 /* solve LDx=b */ #define CHOLMOD_DLt 3 /* solve DL'x=b */ #define CHOLMOD_L 4 /* solve Lx=b */ #define CHOLMOD_Lt 5 /* solve L'x=b */ #define CHOLMOD_D 6 /* solve Dx=b */ #define CHOLMOD_P 7 /* permute x=Px */ #define CHOLMOD_Pt 8 /* permute x=P'x */ cholmod_dense *cholmod_solve /* returns the solution X */ ( /* ---- input ---- */ int sys, /* system to solve */ cholmod_factor *L, /* factorization to use */ cholmod_dense *B, /* right-hand-side */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_solve (int, cholmod_factor *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_spsolve: solve a linear system with a sparse right-hand-side */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_spsolve ( /* ---- input ---- */ int sys, /* system to solve */ cholmod_factor *L, /* factorization to use */ cholmod_sparse *B, /* right-hand-side */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_spsolve (int, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_etree: find the elimination tree of A or A'*A */ /* -------------------------------------------------------------------------- */ int cholmod_etree ( /* ---- input ---- */ cholmod_sparse *A, /* ---- output --- */ int *Parent, /* size ncol. Parent [j] = p if p is the parent of j */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_etree (cholmod_sparse *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowcolcounts: compute the row/column counts of L */ /* -------------------------------------------------------------------------- */ int cholmod_rowcolcounts ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int *Parent, /* size nrow. Parent [i] = p if p is the parent of i */ int *Post, /* size nrow. Post [k] = i if i is the kth node in * the postordered etree. */ /* ---- output --- */ int *RowCount, /* size nrow. RowCount [i] = # entries in the ith row of * L, including the diagonal. */ int *ColCount, /* size nrow. ColCount [i] = # entries in the ith * column of L, including the diagonal. */ int *First, /* size nrow. First [i] = k is the least postordering * of any descendant of i. */ int *Level, /* size nrow. Level [i] is the length of the path from * i to the root, with Level [root] = 0. */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowcolcounts (cholmod_sparse *, UF_long *, size_t, UF_long *, UF_long *, UF_long *, UF_long *, UF_long *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_analyze_ordering: analyze a fill-reducing ordering */ /* -------------------------------------------------------------------------- */ int cholmod_analyze_ordering ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ int ordering, /* ordering method used */ int *Perm, /* size n, fill-reducing permutation to analyze */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ int *Parent, /* size n, elimination tree */ int *Post, /* size n, postordering of elimination tree */ int *ColCount, /* size n, nnz in each column of L */ /* ---- workspace */ int *First, /* size nworkspace for cholmod_postorder */ int *Level, /* size n workspace for cholmod_postorder */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_analyze_ordering (cholmod_sparse *, int, UF_long *, UF_long *, size_t, UF_long *, UF_long *, UF_long *, UF_long *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_amd: order using AMD */ /* -------------------------------------------------------------------------- */ /* Finds a permutation P to reduce fill-in in the factorization of P*A*P' * or P*A*A'P' */ int cholmod_amd ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_amd (cholmod_sparse *, UF_long *, size_t, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_colamd: order using COLAMD */ /* -------------------------------------------------------------------------- */ /* Finds a permutation P to reduce fill-in in the factorization of P*A*A'*P'. * Orders F*F' where F = A (:,fset) if fset is not NULL */ int cholmod_colamd ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int postorder, /* if TRUE, follow with a coletree postorder */ /* ---- output --- */ int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_colamd (cholmod_sparse *, UF_long *, size_t, int, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowfac: incremental simplicial factorization */ /* -------------------------------------------------------------------------- */ /* Partial or complete simplicial factorization. Rows and columns kstart:kend-1 * of L and D must be initially equal to rows/columns kstart:kend-1 of the * identity matrix. Row k can only be factorized if all descendants of node * k in the elimination tree have been factorized. */ int cholmod_rowfac ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ double beta [2], /* factorize beta*I+A or beta*I+A'*A */ size_t kstart, /* first row to factorize */ size_t kend, /* last row to factorize is kend-1 */ /* ---- in/out --- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowfac (cholmod_sparse *, cholmod_sparse *, double *, size_t, size_t, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowfac_mask: incremental simplicial factorization */ /* -------------------------------------------------------------------------- */ /* cholmod_rowfac_mask is a version of cholmod_rowfac that is specific to * LPDASA. It is unlikely to be needed by any other application. */ int cholmod_rowfac_mask ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ double beta [2], /* factorize beta*I+A or beta*I+A'*A */ size_t kstart, /* first row to factorize */ size_t kend, /* last row to factorize is kend-1 */ int *mask, /* if mask[i] >= 0, then set row i to zero */ int *RLinkUp, /* link list of rows to compute */ /* ---- in/out --- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowfac_mask (cholmod_sparse *, cholmod_sparse *, double *, size_t, size_t, UF_long *, UF_long *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_row_subtree: find the nonzero pattern of a row of L */ /* -------------------------------------------------------------------------- */ /* Find the nonzero pattern of x for the system Lx=b where L = (0:k-1,0:k-1) * and b = kth column of A or A*A' (rows 0 to k-1 only) */ int cholmod_row_subtree ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ cholmod_sparse *F, /* used for A*A' case only. F=A' or A(:,fset)' */ size_t k, /* row k of L */ int *Parent, /* elimination tree */ /* ---- output --- */ cholmod_sparse *R, /* pattern of L(k,:), 1-by-n with R->nzmax >= n */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_row_subtree (cholmod_sparse *, cholmod_sparse *, size_t, UF_long *, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_row_lsubtree: find the nonzero pattern of a row of L */ /* -------------------------------------------------------------------------- */ /* Identical to cholmod_row_subtree, except that it finds the elimination tree * from L itself. */ int cholmod_row_lsubtree ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ int *Fi, size_t fnz, /* nonzero pattern of kth row of A', not required * for the symmetric case. Need not be sorted. */ size_t k, /* row k of L */ cholmod_factor *L, /* the factor L from which parent(i) is derived */ /* ---- output --- */ cholmod_sparse *R, /* pattern of L(k,:), 1-by-n with R->nzmax >= n */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_row_lsubtree (cholmod_sparse *, UF_long *, size_t, size_t, cholmod_factor *, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_resymbol: recompute the symbolic pattern of L */ /* -------------------------------------------------------------------------- */ /* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P', * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not). * * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it * first permutes A according to L->Perm. A can be upper/lower/unsymmetric, * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */ int cholmod_resymbol ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int pack, /* if TRUE, pack the columns of L */ /* ---- in/out --- */ cholmod_factor *L, /* factorization, entries pruned on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_resymbol (cholmod_sparse *, UF_long *, size_t, int, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_resymbol_noperm: recompute the symbolic pattern of L, no L->Perm */ /* -------------------------------------------------------------------------- */ /* Remove entries from L that are not in the factorization of A, A*A', * or F*F' (depending on A->stype and whether fset is NULL or not). */ int cholmod_resymbol_noperm ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int pack, /* if TRUE, pack the columns of L */ /* ---- in/out --- */ cholmod_factor *L, /* factorization, entries pruned on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_resymbol_noperm (cholmod_sparse *, UF_long *, size_t, int, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rcond: compute rough estimate of reciprocal of condition number */ /* -------------------------------------------------------------------------- */ double cholmod_rcond /* return min(diag(L)) / max(diag(L)) */ ( /* ---- input ---- */ cholmod_factor *L, /* --------------- */ cholmod_common *Common ) ; double cholmod_l_rcond (cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_postorder: Compute the postorder of a tree */ /* -------------------------------------------------------------------------- */ UF_long cholmod_postorder /* return # of nodes postordered */ ( /* ---- input ---- */ int *Parent, /* size n. Parent [j] = p if p is the parent of j */ size_t n, int *Weight_p, /* size n, optional. Weight [j] is weight of node j */ /* ---- output --- */ int *Post, /* size n. Post [k] = j is kth in postordered tree */ /* --------------- */ cholmod_common *Common ) ; UF_long cholmod_l_postorder (UF_long *, size_t, UF_long *, UF_long *, cholmod_common *) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/License.txt0000644000175000017500000000046211674452555022121 0ustar sonnesonneCHOLMOD/Include/* files. Copyright (C) 2005-2006, either Univ. of Florida or T. Davis, depending on the file. http://www.cise.ufl.edu/research/sparse Refer to each include file in this directory; each file is licensed separately, according to the Module for which it contains definitions and prototypes. cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_template.h0000644000175000017500000002200111674452555023460 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_template.h =========================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* undefine current xtype macros, and then define macros for current type */ /* -------------------------------------------------------------------------- */ #undef TEMPLATE #undef XTYPE #undef XTYPE2 #undef XTYPE_OK #undef ENTRY_IS_NONZERO #undef ENTRY_IS_ZERO #undef ENTRY_IS_ONE #undef IMAG_IS_NONZERO #undef ASSEMBLE #undef ASSIGN #undef ASSIGN_CONJ #undef ASSIGN2 #undef ASSIGN2_CONJ #undef ASSIGN_REAL #undef MULT #undef MULTADD #undef ADD #undef ADD_REAL #undef MULTSUB #undef MULTADDCONJ #undef MULTSUBCONJ #undef LLDOT #undef CLEAR #undef DIV #undef DIV_REAL #undef MULT_REAL #undef CLEAR_IMAG #undef LDLDOT #undef PREFIX #undef ENTRY_SIZE #undef XPRINT0 #undef XPRINT1 #undef XPRINT2 #undef XPRINT3 /* -------------------------------------------------------------------------- */ /* pattern */ /* -------------------------------------------------------------------------- */ #ifdef PATTERN #define PREFIX p_ #define TEMPLATE(name) P_TEMPLATE(name) #define XTYPE CHOLMOD_PATTERN #define XTYPE2 CHOLMOD_REAL #define XTYPE_OK(type) (TRUE) #define ENTRY_IS_NONZERO(ax,az,q) (TRUE) #define ENTRY_IS_ZERO(ax,az,q) (FALSE) #define ENTRY_IS_ONE(ax,az,q) (TRUE) #define IMAG_IS_NONZERO(ax,az,q) (FALSE) #define ENTRY_SIZE 0 #define ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) #define ASSIGN2(x,z,p,ax,az,q) P_ASSIGN2(x,z,p,ax,az,q) #define ASSIGN2_CONJ(x,z,p,ax,az,q) P_ASSIGN2(x,z,p,ax,az,q) #define ASSIGN_REAL(x,p,ax,q) #define MULT(x,z,p,ax,az,q,bx,bz,pb) #define MULTADD(x,z,p,ax,az,q,bx,bz,pb) #define ADD(x,z,p,ax,az,q,bx,bz,pb) #define ADD_REAL(x,p, ax,q, bx,r) #define MULTSUB(x,z,p,ax,az,q,bx,bz,pb) #define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) #define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) #define LLDOT(x,p,ax,az,q) #define CLEAR(x,z,p) #define CLEAR_IMAG(x,z,p) #define DIV(x,z,p,ax,az,q) #define DIV_REAL(x,z,p, ax,az,q, bx,r) #define MULT_REAL(x,z,p, ax,az,q, bx,r) #define LDLDOT(x,p, ax,az,q, bx,r) #define XPRINT0(x,z,p) P_PRINT(0,x,z,p) #define XPRINT1(x,z,p) P_PRINT(1,x,z,p) #define XPRINT2(x,z,p) P_PRINT(2,x,z,p) #define XPRINT3(x,z,p) P_PRINT(3,x,z,p) /* -------------------------------------------------------------------------- */ /* real */ /* -------------------------------------------------------------------------- */ #elif defined (REAL) #define PREFIX r_ #define TEMPLATE(name) R_TEMPLATE(name) #define XTYPE CHOLMOD_REAL #define XTYPE2 CHOLMOD_REAL #define XTYPE_OK(type) R_XTYPE_OK(type) #define ENTRY_IS_NONZERO(ax,az,q) R_IS_NONZERO(ax,az,q) #define ENTRY_IS_ZERO(ax,az,q) R_IS_ZERO(ax,az,q) #define ENTRY_IS_ONE(ax,az,q) R_IS_ONE(ax,az,q) #define IMAG_IS_NONZERO(ax,az,q) (FALSE) #define ENTRY_SIZE 1 #define ASSEMBLE(x,z,p,ax,az,q) R_ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) R_ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) R_ASSIGN(x,z,p,ax,az,q) #define ASSIGN2(x,z,p,ax,az,q) R_ASSIGN(x,z,p,ax,az,q) #define ASSIGN2_CONJ(x,z,p,ax,az,q) R_ASSIGN(x,z,p,ax,az,q) #define ASSIGN_REAL(x,p,ax,q) R_ASSIGN_REAL(x,p,ax,q) #define MULT(x,z,p,ax,az,q,bx,bz,pb) R_MULT(x,z,p,ax,az,q,bx,bz,pb) #define MULTADD(x,z,p,ax,az,q,bx,bz,pb) R_MULTADD(x,z,p,ax,az,q,bx,bz,pb) #define ADD(x,z,p,ax,az,q,bx,bz,pb) R_ADD(x,z,p,ax,az,q,bx,bz,pb) #define ADD_REAL(x,p, ax,q, bx,r) R_ADD_REAL(x,p, ax,q, bx,r) #define MULTSUB(x,z,p,ax,az,q,bx,bz,pb) R_MULTSUB(x,z,p,ax,az,q,bx,bz,pb) #define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \ R_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) #define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \ R_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) #define LLDOT(x,p,ax,az,q) R_LLDOT(x,p,ax,az,q) #define CLEAR(x,z,p) R_CLEAR(x,z,p) #define CLEAR_IMAG(x,z,p) R_CLEAR_IMAG(x,z,p) #define DIV(x,z,p,ax,az,q) R_DIV(x,z,p,ax,az,q) #define DIV_REAL(x,z,p, ax,az,q, bx,r) R_DIV_REAL(x,z,p, ax,az,q, bx,r) #define MULT_REAL(x,z,p, ax,az,q, bx,r) R_MULT_REAL(x,z,p, ax,az,q, bx,r) #define LDLDOT(x,p, ax,az,q, bx,r) R_LDLDOT(x,p, ax,az,q, bx,r) #define XPRINT0(x,z,p) R_PRINT(0,x,z,p) #define XPRINT1(x,z,p) R_PRINT(1,x,z,p) #define XPRINT2(x,z,p) R_PRINT(2,x,z,p) #define XPRINT3(x,z,p) R_PRINT(3,x,z,p) /* -------------------------------------------------------------------------- */ /* complex */ /* -------------------------------------------------------------------------- */ #elif defined (COMPLEX) #define PREFIX c_ #ifdef NCONJUGATE #define TEMPLATE(name) CT_TEMPLATE(name) #else #define TEMPLATE(name) C_TEMPLATE(name) #endif #define ASSEMBLE(x,z,p,ax,az,q) C_ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) C_ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) C_ASSIGN_CONJ(x,z,p,ax,az,q) #define ASSIGN2(x,z,p,ax,az,q) C_ASSIGN(x,z,p,ax,az,q) #define ASSIGN2_CONJ(x,z,p,ax,az,q) C_ASSIGN_CONJ(x,z,p,ax,az,q) #define ASSIGN_REAL(x,p,ax,q) C_ASSIGN_REAL(x,p,ax,q) #define XTYPE CHOLMOD_COMPLEX #define XTYPE2 CHOLMOD_COMPLEX #define XTYPE_OK(type) C_XTYPE_OK(type) #define ENTRY_IS_NONZERO(ax,az,q) C_IS_NONZERO(ax,az,q) #define ENTRY_IS_ZERO(ax,az,q) C_IS_ZERO(ax,az,q) #define ENTRY_IS_ONE(ax,az,q) C_IS_ONE(ax,az,q) #define IMAG_IS_NONZERO(ax,az,q) C_IMAG_IS_NONZERO(ax,az,q) #define ENTRY_SIZE 2 #define MULTADD(x,z,p,ax,az,q,bx,bz,pb) C_MULTADD(x,z,p,ax,az,q,bx,bz,pb) #define MULT(x,z,p,ax,az,q,bx,bz,pb) C_MULT(x,z,p,ax,az,q,bx,bz,pb) #define ADD(x,z,p,ax,az,q,bx,bz,pb) C_ADD(x,z,p,ax,az,q,bx,bz,pb) #define ADD_REAL(x,p, ax,q, bx,r) C_ADD_REAL(x,p, ax,q, bx,r) #define MULTSUB(x,z,p,ax,az,q,bx,bz,pb) C_MULTSUB(x,z,p,ax,az,q,bx,bz,pb) #define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \ C_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) #define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \ C_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) #define LLDOT(x,p,ax,az,q) C_LLDOT(x,p,ax,az,q) #define CLEAR(x,z,p) C_CLEAR(x,z,p) #define CLEAR_IMAG(x,z,p) C_CLEAR_IMAG(x,z,p) #define DIV(x,z,p,ax,az,q) C_DIV(x,z,p,ax,az,q) #define DIV_REAL(x,z,p, ax,az,q, bx,r) C_DIV_REAL(x,z,p, ax,az,q, bx,r) #define MULT_REAL(x,z,p, ax,az,q, bx,r) C_MULT_REAL(x,z,p, ax,az,q, bx,r) #define LDLDOT(x,p, ax,az,q, bx,r) C_LDLDOT(x,p, ax,az,q, bx,r) #define XPRINT0(x,z,p) C_PRINT(0,x,z,p) #define XPRINT1(x,z,p) C_PRINT(1,x,z,p) #define XPRINT2(x,z,p) C_PRINT(2,x,z,p) #define XPRINT3(x,z,p) C_PRINT(3,x,z,p) /* -------------------------------------------------------------------------- */ /* zomplex */ /* -------------------------------------------------------------------------- */ #elif defined (ZOMPLEX) #define PREFIX z_ #ifdef NCONJUGATE #define TEMPLATE(name) ZT_TEMPLATE(name) #else #define TEMPLATE(name) Z_TEMPLATE(name) #endif #define ASSEMBLE(x,z,p,ax,az,q) Z_ASSEMBLE(x,z,p,ax,az,q) #define ASSIGN(x,z,p,ax,az,q) Z_ASSIGN(x,z,p,ax,az,q) #define ASSIGN_CONJ(x,z,p,ax,az,q) Z_ASSIGN_CONJ(x,z,p,ax,az,q) #define ASSIGN2(x,z,p,ax,az,q) Z_ASSIGN(x,z,p,ax,az,q) #define ASSIGN2_CONJ(x,z,p,ax,az,q) Z_ASSIGN_CONJ(x,z,p,ax,az,q) #define ASSIGN_REAL(x,p,ax,q) Z_ASSIGN_REAL(x,p,ax,q) #define XTYPE CHOLMOD_ZOMPLEX #define XTYPE2 CHOLMOD_ZOMPLEX #define XTYPE_OK(type) Z_XTYPE_OK(type) #define ENTRY_IS_NONZERO(ax,az,q) Z_IS_NONZERO(ax,az,q) #define ENTRY_IS_ZERO(ax,az,q) Z_IS_ZERO(ax,az,q) #define ENTRY_IS_ONE(ax,az,q) Z_IS_ONE(ax,az,q) #define IMAG_IS_NONZERO(ax,az,q) Z_IMAG_IS_NONZERO(ax,az,q) #define ENTRY_SIZE 1 #define MULTADD(x,z,p,ax,az,q,bx,bz,pb) Z_MULTADD(x,z,p,ax,az,q,bx,bz,pb) #define MULT(x,z,p,ax,az,q,bx,bz,pb) Z_MULT(x,z,p,ax,az,q,bx,bz,pb) #define ADD(x,z,p,ax,az,q,bx,bz,pb) Z_ADD(x,z,p,ax,az,q,bx,bz,pb) #define ADD_REAL(x,p, ax,q, bx,r) Z_ADD_REAL(x,p, ax,q, bx,r) #define MULTSUB(x,z,p,ax,az,q,bx,bz,pb) Z_MULTSUB(x,z,p,ax,az,q,bx,bz,pb) #define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \ Z_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) #define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \ Z_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) #define LLDOT(x,p,ax,az,q) Z_LLDOT(x,p,ax,az,q) #define CLEAR(x,z,p) Z_CLEAR(x,z,p) #define CLEAR_IMAG(x,z,p) Z_CLEAR_IMAG(x,z,p) #define DIV(x,z,p,ax,az,q) Z_DIV(x,z,p,ax,az,q) #define DIV_REAL(x,z,p, ax,az,q, bx,r) Z_DIV_REAL(x,z,p, ax,az,q, bx,r) #define MULT_REAL(x,z,p, ax,az,q, bx,r) Z_MULT_REAL(x,z,p, ax,az,q, bx,r) #define LDLDOT(x,p, ax,az,q, bx,r) Z_LDLDOT(x,p, ax,az,q, bx,r) #define XPRINT0(x,z,p) Z_PRINT(0,x,z,p) #define XPRINT1(x,z,p) Z_PRINT(1,x,z,p) #define XPRINT2(x,z,p) Z_PRINT(2,x,z,p) #define XPRINT3(x,z,p) Z_PRINT(3,x,z,p) #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_complexity.h0000644000175000017500000002224411674452555024053 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_complexity.h ========================================= */ /* ========================================================================== */ /* Define operations on pattern, real, complex, and zomplex objects. * * The xtype of an object defines it numerical type. A qttern object has no * numerical values (A->x and A->z are NULL). A real object has no imaginary * qrt (A->x is used, A->z is NULL). A complex object has an imaginary qrt * that is stored interleaved with its real qrt (A->x is of size 2*nz, A->z * is NULL). A zomplex object has both real and imaginary qrts, which are * stored seqrately, as in MATLAB (A->x and A->z are both used). * * XTYPE is CHOLMOD_PATTERN, _REAL, _COMPLEX or _ZOMPLEX, and is the xtype of * the template routine under construction. XTYPE2 is equal to XTYPE, except * if XTYPE is CHOLMOD_PATTERN, in which case XTYPE is CHOLMOD_REAL. * XTYPE and XTYPE2 are defined in cholmod_template.h. */ /* -------------------------------------------------------------------------- */ /* pattern */ /* -------------------------------------------------------------------------- */ #define P_TEMPLATE(name) p_ ## name #define P_ASSIGN2(x,z,p,ax,az,q) x [p] = 1 #define P_PRINT(k,x,z,p) PRK(k, ("1")) /* -------------------------------------------------------------------------- */ /* real */ /* -------------------------------------------------------------------------- */ #define R_TEMPLATE(name) r_ ## name #define R_ASSEMBLE(x,z,p,ax,az,q) x [p] += ax [q] #define R_ASSIGN(x,z,p,ax,az,q) x [p] = ax [q] #define R_ASSIGN_CONJ(x,z,p,ax,az,q) x [p] = ax [q] #define R_ASSIGN_REAL(x,p,ax,q) x [p] = ax [q] #define R_XTYPE_OK(type) ((type) == CHOLMOD_REAL) #define R_IS_NONZERO(ax,az,q) IS_NONZERO (ax [q]) #define R_IS_ZERO(ax,az,q) IS_ZERO (ax [q]) #define R_IS_ONE(ax,az,q) (ax [q] == 1) #define R_MULT(x,z,p, ax,az,q, bx,bz,r) x [p] = ax [q] * bx [r] #define R_MULTADD(x,z,p, ax,az,q, bx,bz,r) x [p] += ax [q] * bx [r] #define R_MULTSUB(x,z,p, ax,az,q, bx,bz,r) x [p] -= ax [q] * bx [r] #define R_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) x [p] += ax [q] * bx [r] #define R_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) x [p] -= ax [q] * bx [r] #define R_ADD(x,z,p, ax,az,q, bx,bz,r) x [p] = ax [q] + bx [r] #define R_ADD_REAL(x,p, ax,q, bx,r) x [p] = ax [q] + bx [r] #define R_CLEAR(x,z,p) x [p] = 0 #define R_CLEAR_IMAG(x,z,p) #define R_DIV(x,z,p,ax,az,q) x [p] /= ax [q] #define R_LLDOT(x,p, ax,az,q) x [p] -= ax [q] * ax [q] #define R_PRINT(k,x,z,p) PRK(k, ("%24.16e", x [p])) #define R_DIV_REAL(x,z,p, ax,az,q, bx,r) x [p] = ax [q] / bx [r] #define R_MULT_REAL(x,z,p, ax,az,q, bx,r) x [p] = ax [q] * bx [r] #define R_LDLDOT(x,p, ax,az,q, bx,r) x [p] -=(ax[q] * ax[q])/ bx[r] /* -------------------------------------------------------------------------- */ /* complex */ /* -------------------------------------------------------------------------- */ #define C_TEMPLATE(name) c_ ## name #define CT_TEMPLATE(name) ct_ ## name #define C_ASSEMBLE(x,z,p,ax,az,q) \ x [2*(p) ] += ax [2*(q) ] ; \ x [2*(p)+1] += ax [2*(q)+1] #define C_ASSIGN(x,z,p,ax,az,q) \ x [2*(p) ] = ax [2*(q) ] ; \ x [2*(p)+1] = ax [2*(q)+1] #define C_ASSIGN_REAL(x,p,ax,q) x [2*(p)] = ax [2*(q)] #define C_ASSIGN_CONJ(x,z,p,ax,az,q) \ x [2*(p) ] = ax [2*(q) ] ; \ x [2*(p)+1] = -ax [2*(q)+1] #define C_XTYPE_OK(type) ((type) == CHOLMOD_COMPLEX) #define C_IS_NONZERO(ax,az,q) \ (IS_NONZERO (ax [2*(q)]) || IS_NONZERO (ax [2*(q)+1])) #define C_IS_ZERO(ax,az,q) \ (IS_ZERO (ax [2*(q)]) && IS_ZERO (ax [2*(q)+1])) #define C_IS_ONE(ax,az,q) \ ((ax [2*(q)] == 1) && IS_ZERO (ax [2*(q)+1])) #define C_IMAG_IS_NONZERO(ax,az,q) (IS_NONZERO (ax [2*(q)+1])) #define C_MULT(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] = ax [2*(q) ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \ x [2*(p)+1] = ax [2*(q)+1] * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] #define C_MULTADD(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] += ax [2*(q) ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \ x [2*(p)+1] += ax [2*(q)+1] * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] #define C_MULTSUB(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] -= ax [2*(q) ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \ x [2*(p)+1] -= ax [2*(q)+1] * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] /* s += conj(a)*b */ #define C_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] += ax [2*(q) ] * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ; \ x [2*(p)+1] += (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] /* s -= conj(a)*b */ #define C_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] -= ax [2*(q) ] * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ; \ x [2*(p)+1] -= (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q) ] * bx [2*(r)+1] #define C_ADD(x,z,p, ax,az,q, bx,bz,r) \ x [2*(p) ] = ax [2*(q) ] + bx [2*(r) ] ; \ x [2*(p)+1] = ax [2*(q)+1] + bx [2*(r)+1] #define C_ADD_REAL(x,p, ax,q, bx,r) \ x [2*(p)] = ax [2*(q)] + bx [2*(r)] #define C_CLEAR(x,z,p) \ x [2*(p) ] = 0 ; \ x [2*(p)+1] = 0 #define C_CLEAR_IMAG(x,z,p) \ x [2*(p)+1] = 0 /* s = s / a */ #define C_DIV(x,z,p,ax,az,q) \ Common->complex_divide ( \ x [2*(p)], x [2*(p)+1], \ ax [2*(q)], ax [2*(q)+1], \ &x [2*(p)], &x [2*(p)+1]) /* s -= conj(a)*a ; note that the result of conj(a)*a is real */ #define C_LLDOT(x,p, ax,az,q) \ x [2*(p)] -= ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1] #define C_PRINT(k,x,z,p) PRK(k, ("(%24.16e,%24.16e)", x [2*(p)], x [2*(p)+1])) #define C_DIV_REAL(x,z,p, ax,az,q, bx,r) \ x [2*(p) ] = ax [2*(q) ] / bx [2*(r)] ; \ x [2*(p)+1] = ax [2*(q)+1] / bx [2*(r)] #define C_MULT_REAL(x,z,p, ax,az,q, bx,r) \ x [2*(p) ] = ax [2*(q) ] * bx [2*(r)] ; \ x [2*(p)+1] = ax [2*(q)+1] * bx [2*(r)] /* s -= conj(a)*a/t */ #define C_LDLDOT(x,p, ax,az,q, bx,r) \ x [2*(p)] -= (ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1]) / bx[r] /* -------------------------------------------------------------------------- */ /* zomplex */ /* -------------------------------------------------------------------------- */ #define Z_TEMPLATE(name) z_ ## name #define ZT_TEMPLATE(name) zt_ ## name #define Z_ASSEMBLE(x,z,p,ax,az,q) \ x [p] += ax [q] ; \ z [p] += az [q] #define Z_ASSIGN(x,z,p,ax,az,q) \ x [p] = ax [q] ; \ z [p] = az [q] #define Z_ASSIGN_REAL(x,p,ax,q) x [p] = ax [q] #define Z_ASSIGN_CONJ(x,z,p,ax,az,q) \ x [p] = ax [q] ; \ z [p] = -az [q] #define Z_XTYPE_OK(type) ((type) == CHOLMOD_ZOMPLEX) #define Z_IS_NONZERO(ax,az,q) \ (IS_NONZERO (ax [q]) || IS_NONZERO (az [q])) #define Z_IS_ZERO(ax,az,q) \ (IS_ZERO (ax [q]) && IS_ZERO (az [q])) #define Z_IS_ONE(ax,az,q) \ ((ax [q] == 1) && IS_ZERO (az [q])) #define Z_IMAG_IS_NONZERO(ax,az,q) (IS_NONZERO (az [q])) #define Z_MULT(x,z,p, ax,az,q, bx,bz,r) \ x [p] = ax [q] * bx [r] - az [q] * bz [r] ; \ z [p] = az [q] * bx [r] + ax [q] * bz [r] #define Z_MULTADD(x,z,p, ax,az,q, bx,bz,r) \ x [p] += ax [q] * bx [r] - az [q] * bz [r] ; \ z [p] += az [q] * bx [r] + ax [q] * bz [r] #define Z_MULTSUB(x,z,p, ax,az,q, bx,bz,r) \ x [p] -= ax [q] * bx [r] - az [q] * bz [r] ; \ z [p] -= az [q] * bx [r] + ax [q] * bz [r] #define Z_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) \ x [p] += ax [q] * bx [r] + az [q] * bz [r] ; \ z [p] += (-az [q]) * bx [r] + ax [q] * bz [r] #define Z_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) \ x [p] -= ax [q] * bx [r] + az [q] * bz [r] ; \ z [p] -= (-az [q]) * bx [r] + ax [q] * bz [r] #define Z_ADD(x,z,p, ax,az,q, bx,bz,r) \ x [p] = ax [q] + bx [r] ; \ z [p] = az [q] + bz [r] #define Z_ADD_REAL(x,p, ax,q, bx,r) \ x [p] = ax [q] + bx [r] #define Z_CLEAR(x,z,p) \ x [p] = 0 ; \ z [p] = 0 #define Z_CLEAR_IMAG(x,z,p) \ z [p] = 0 /* s = s/a */ #define Z_DIV(x,z,p,ax,az,q) \ Common->complex_divide (x [p], z [p], ax [q], az [q], &x [p], &z [p]) /* s -= conj(a)*a ; note that the result of conj(a)*a is real */ #define Z_LLDOT(x,p, ax,az,q) \ x [p] -= ax [q] * ax [q] + az [q] * az [q] #define Z_PRINT(k,x,z,p) PRK(k, ("(%24.16e,%24.16e)", x [p], z [p])) #define Z_DIV_REAL(x,z,p, ax,az,q, bx,r) \ x [p] = ax [q] / bx [r] ; \ z [p] = az [q] / bx [r] #define Z_MULT_REAL(x,z,p, ax,az,q, bx,r) \ x [p] = ax [q] * bx [r] ; \ z [p] = az [q] * bx [r] /* s -= conj(a)*a/t */ #define Z_LDLDOT(x,p, ax,az,q, bx,r) \ x [p] -= (ax [q] * ax [q] + az [q] * az [q]) / bx[r] /* -------------------------------------------------------------------------- */ /* all classes */ /* -------------------------------------------------------------------------- */ /* Check if A->xtype and the two arrays A->x and A->z are valid. Set status to * invalid, unless status is already "out of memory". A can be a sparse matrix, * dense matrix, factor, or triplet. */ #define RETURN_IF_XTYPE_INVALID(A,xtype1,xtype2,result) \ { \ if ((A)->xtype < (xtype1) || (A)->xtype > (xtype2) || \ ((A)->xtype != CHOLMOD_PATTERN && ((A)->x) == NULL) || \ ((A)->xtype == CHOLMOD_ZOMPLEX && ((A)->z) == NULL)) \ { \ if (Common->status != CHOLMOD_OUT_OF_MEMORY) \ { \ ERROR (CHOLMOD_INVALID, "invalid xtype") ; \ } \ return (result) ; \ } \ } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_config.h0000644000175000017500000000613211674452555023121 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_config.h ============================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_config.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod_config.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD configuration file, for inclusion in user programs. * * You do not have to edit any CHOLMOD files to compile and install CHOLMOD. * However, if you do not use all of CHOLMOD's modules, you need to compile * with the appropriate flag, or edit this file to add the appropriate #define. * * If you wish to use CHOLMOD under the GNU LGPL license only, then you must * compile CHOLMOD with -DNMATRIXOPS -DNSUPERNODAL and -DNMODIFY. This can * be done using just -DNGPL. * * Compiler flags for CHOLMOD: * * -DNCHECK do not include the Check module. License: GNU LGPL * -DNCHOLESKY do not include the Cholesky module. License: GNU LGPL * -DNPARTITION do not include the Partition module. License: GNU LGPL * * -DNGPL do not include any GNU GPL Modules in the CHOLMOD library. * -DNMATRIXOPS do not include the MatrixOps module. License: GNU GPL * -DNMODIFY do not include the Modify module. License: GNU GPL * -DNSUPERNODAL do not include the Supernodal module. License: GNU GPL * * -DNPRINT do not print anything * * -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by * LAPACK and the BLAS. Use LONGBLAS=long on Solaris to use * the 64-bit Sun Performance BLAS in cholmod_l_* routines. * You may need to use -D'LONGBLAS=long long' on the SGI * (this is not tested). * * -DNSUNPERF for Solaris only. If defined, do not use the Sun * Performance Library. The default is to use SunPerf. * You must compile CHOLMOD with -xlic_lib=sunperf. * * The Core Module (License GNU LGPL) is always included in the CHOLMOD library. */ #ifndef CHOLMOD_CONFIG_H #define CHOLMOD_CONFIG_H /* Use the compiler flag, or uncomment the definition(s), if you want to use * one or more non-default installation options: */ /* #define NCHECK #define NCHOLESKY #define NPARTITION #define NGPL #define NMATRIXOPS #define NMODIFY #define NSUPERNODAL #define NPRINT #define LONGBLAS long #define LONGBLAS long long #define NSUNPERF */ /* -------------------------------------------------------------------------- */ /* if NGPL is defined, disable all GNU GPL Modules */ /* -------------------------------------------------------------------------- */ #ifdef NGPL #define NMATRIXOPS #define NMODIFY #define NSUPERNODAL #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod.h0000644000175000017500000000742211674452555021577 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod.h ==================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * * Portions of CHOLMOD (the Core and Partition Modules) are copyrighted by the * University of Florida. The Modify Module is co-authored by William W. * Hager, Univ. of Florida. * * Acknowledgements: this work was supported in part by the National Science * Foundation (NFS CCR-0203270 and DMS-9803599), and a grant from Sandia * National Laboratories (Dept. of Energy) which supported the development of * CHOLMOD's Partition Module. * -------------------------------------------------------------------------- */ /* CHOLMOD include file, for inclusion user programs. * * The include files listed below include a short description of each user- * callable routine. Each routine in CHOLMOD has a consistent interface. * More details about the CHOLMOD data types is in the cholmod_core.h file. * * Naming convention: * ------------------ * * All routine names, data types, and CHOLMOD library files use the * cholmod_ prefix. All macros and other #define's use the CHOLMOD * prefix. * * Return value: * ------------- * * Most CHOLMOD routines return an int (TRUE (1) if successful, or FALSE * (0) otherwise. A UF_long or double return value is >= 0 if successful, * or -1 otherwise. A size_t return value is > 0 if successful, or 0 * otherwise. * * If a routine returns a pointer, it is a pointer to a newly allocated * object or NULL if a failure occured, with one exception. cholmod_free * always returns NULL. * * "Common" parameter: * ------------------ * * The last parameter in all CHOLMOD routines is a pointer to the CHOLMOD * "Common" object. This contains control parameters, statistics, and * workspace used between calls to CHOLMOD. It is always an input/output * parameter. * * Input, Output, and Input/Output parameters: * ------------------------------------------- * * Input parameters are listed first. They are not modified by CHOLMOD. * * Input/output are listed next. They must be defined on input, and * are modified on output. * * Output parameters are listed next. If they are pointers, they must * point to allocated space on input, but their contents are not defined * on input. * * Workspace parameters appear next. They are used in only two routines * in the Supernodal module. * * The cholmod_common *Common parameter always appears as the last * parameter. It is always an input/output parameter. */ #ifndef CHOLMOD_H #define CHOLMOD_H /* make it easy for C++ programs to include CHOLMOD */ #ifdef __cplusplus extern "C" { #endif /* assume large file support. If problems occur, compile with -DNLARGEFILE */ #include "cholmod_io64.h" /* define UF_long */ #include "UFconfig.h" #include "cholmod_config.h" /* CHOLMOD always includes the Core module. */ #include "cholmod_core.h" #ifndef NCHECK #include "cholmod_check.h" #endif #ifndef NCHOLESKY #include "cholmod_cholesky.h" #endif #ifndef NMATRIXOPS #include "cholmod_matrixops.h" #endif #ifndef NMODIFY #include "cholmod_modify.h" #endif #ifndef NPARTITION #include "cholmod_partition.h" #endif #ifndef NSUPERNODAL #include "cholmod_supernodal.h" #endif #ifdef __cplusplus } #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_internal.h0000644000175000017500000003446511674452555023502 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_internal.h =========================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_internal.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod_internal.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD internal include file. * * This file contains internal definitions for CHOLMOD, not meant to be included * in user code. They define macros that are not prefixed with CHOLMOD_. This * file can safely #include'd in user code if you want to make use of the * macros defined here, and don't mind the possible name conflicts with your * code, however. * * Required by all CHOLMOD routines. Not required by any user routine that * uses CHOLMOMD. Unless debugging is enabled, this file does not require any * CHOLMOD module (not even the Core module). * * If debugging is enabled, all CHOLMOD modules require the Check module. * Enabling debugging requires that this file be editted. Debugging cannot be * enabled with a compiler flag. This is because CHOLMOD is exceedingly slow * when debugging is enabled. Debugging is meant for development of CHOLMOD * itself, not by users of CHOLMOD. */ #ifndef CHOLMOD_INTERNAL_H #define CHOLMOD_INTERNAL_H /* ========================================================================== */ /* === large file I/O ======================================================= */ /* ========================================================================== */ /* Definitions for large file I/O must come before any other #includes. If * this causes problems (may not be portable to all platforms), then compile * CHOLMOD with -DNLARGEFILE. You must do this for MATLAB 6.5 and earlier, * for example. */ #include "cholmod_io64.h" /* ========================================================================== */ /* === debugging and basic includes ========================================= */ /* ========================================================================== */ /* turn off debugging */ #ifndef NDEBUG #define NDEBUG #endif /* Uncomment this line to enable debugging. CHOLMOD will be very slow. #undef NDEBUG */ #ifdef MATLAB_MEX_FILE #include "mex.h" #endif #if !defined(NPRINT) || !defined(NDEBUG) #include #endif #include #include #include #include #include /* ========================================================================== */ /* === basic definitions ==================================================== */ /* ========================================================================== */ /* Some non-conforming compilers insist on defining TRUE and FALSE. */ #undef TRUE #undef FALSE #define TRUE 1 #define FALSE 0 #define BOOLEAN(x) ((x) ? TRUE : FALSE) /* NULL should already be defined, but ensure it is here. */ #ifndef NULL #define NULL ((void *) 0) #endif /* FLIP is a "negation about -1", and is used to mark an integer i that is * normally non-negative. FLIP (EMPTY) is EMPTY. FLIP of a number > EMPTY * is negative, and FLIP of a number < EMTPY is positive. FLIP (FLIP (i)) = i * for all integers i. UNFLIP (i) is >= EMPTY. */ #define EMPTY (-1) #define FLIP(i) (-(i)-2) #define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i)) /* MAX and MIN are not safe to use for NaN's */ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MAX3(a,b,c) (((a) > (b)) ? (MAX (a,c)) : (MAX (b,c))) #define MAX4(a,b,c,d) (((a) > (b)) ? (MAX3 (a,c,d)) : (MAX3 (b,c,d))) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define IMPLIES(p,q) (!(p) || (q)) /* find the sign: -1 if x < 0, 1 if x > 0, zero otherwise. * Not safe for NaN's */ #define SIGN(x) (((x) < 0) ? (-1) : (((x) > 0) ? 1 : 0)) /* round up an integer x to a multiple of s */ #define ROUNDUP(x,s) ((s) * (((x) + ((s) - 1)) / (s))) #define ERROR(status,msg) \ CHOLMOD(error) (status, __FILE__, __LINE__, msg, Common) /* Check a pointer and return if null. Set status to invalid, unless the * status is already "out of memory" */ #define RETURN_IF_NULL(A,result) \ { \ if ((A) == NULL) \ { \ if (Common->status != CHOLMOD_OUT_OF_MEMORY) \ { \ ERROR (CHOLMOD_INVALID, "argument missing") ; \ } \ return (result) ; \ } \ } /* Return if Common is NULL or invalid */ #define RETURN_IF_NULL_COMMON(result) \ { \ if (Common == NULL) \ { \ return (result) ; \ } \ if (Common->itype != ITYPE || Common->dtype != DTYPE) \ { \ Common->status = CHOLMOD_INVALID ; \ return (result) ; \ } \ } #define IS_NAN(x) CHOLMOD_IS_NAN(x) #define IS_ZERO(x) CHOLMOD_IS_ZERO(x) #define IS_NONZERO(x) CHOLMOD_IS_NONZERO(x) #define IS_LT_ZERO(x) CHOLMOD_IS_LT_ZERO(x) #define IS_GT_ZERO(x) CHOLMOD_IS_GT_ZERO(x) #define IS_LE_ZERO(x) CHOLMOD_IS_LE_ZERO(x) /* 1e308 is a huge number that doesn't take many characters to print in a * file, in CHOLMOD/Check/cholmod_read and _write. Numbers larger than this * are interpretted as Inf, since sscanf doesn't read in Inf's properly. * This assumes IEEE double precision arithmetic. DBL_MAX would be a little * better, except that it takes too many digits to print in a file. */ #define HUGE_DOUBLE 1e308 /* ========================================================================== */ /* === int/UF_long and double/float definitions ============================= */ /* ========================================================================== */ /* CHOLMOD is designed for 3 types of integer variables: * * (1) all integers are int * (2) most integers are int, some are UF_long * (3) all integers are UF_long * * and two kinds of floating-point values: * * (1) double * (2) float * * the complex types (ANSI-compatible complex, and MATLAB-compatable zomplex) * are based on the double or float type, and are not selected here. They * are typically selected via template routines. * * This gives 6 different modes in which CHOLMOD can be compiled (only the * first two are currently supported): * * DINT double, int prefix: cholmod_ * DLONG double, UF_long prefix: cholmod_l_ * DMIX double, mixed int/UF_long prefix: cholmod_m_ * SINT float, int prefix: cholmod_si_ * SLONG float, UF_long prefix: cholmod_sl_ * SMIX float, mixed int/log prefix: cholmod_sm_ * * These are selected with compile time flags (-DDLONG, for example). If no * flag is selected, the default is DINT. * * All six versions use the same include files. The user-visible include files * are completely independent of which int/UF_long/double/float version is being * used. The integer / real types in all data structures (sparse, triplet, * dense, common, and triplet) are defined at run-time, not compile-time, so * there is only one "cholmod_sparse" data type. Void pointers are used inside * that data structure to point to arrays of the proper type. Each data * structure has an itype and dtype field which determines the kind of basic * types used. These are defined in Include/cholmod_core.h. * * FUTURE WORK: support all six types (float, and mixed int/UF_long) * * UF_long is normally defined as long. However, for WIN64 it is __int64. * It can also be redefined for other platforms, by modifying UFconfig.h. */ #include "UFconfig.h" /* -------------------------------------------------------------------------- */ /* Size_max: the largest value of size_t */ /* -------------------------------------------------------------------------- */ #define Size_max ((size_t) (-1)) /* routines for doing arithmetic on size_t, and checking for overflow */ size_t cholmod_add_size_t (size_t a, size_t b, int *ok) ; size_t cholmod_mult_size_t (size_t a, size_t k, int *ok) ; size_t cholmod_l_add_size_t (size_t a, size_t b, int *ok) ; size_t cholmod_l_mult_size_t (size_t a, size_t k, int *ok) ; /* -------------------------------------------------------------------------- */ /* double (also complex double), UF_long */ /* -------------------------------------------------------------------------- */ #ifdef DLONG #define Real double #define Int UF_long #define Int_max UF_long_max #define CHOLMOD(name) cholmod_l_ ## name #define LONG #define DOUBLE #define ITYPE CHOLMOD_LONG #define DTYPE CHOLMOD_DOUBLE #define ID UF_long_id /* -------------------------------------------------------------------------- */ /* double, int/UF_long */ /* -------------------------------------------------------------------------- */ #elif defined (DMIX) #error "mixed int/UF_long not yet supported" /* -------------------------------------------------------------------------- */ /* single, int */ /* -------------------------------------------------------------------------- */ #elif defined (SINT) #error "single-precision not yet supported" /* -------------------------------------------------------------------------- */ /* single, UF_long */ /* -------------------------------------------------------------------------- */ #elif defined (SLONG) #error "single-precision not yet supported" /* -------------------------------------------------------------------------- */ /* single, int/UF_long */ /* -------------------------------------------------------------------------- */ #elif defined (SMIX) #error "single-precision not yet supported" /* -------------------------------------------------------------------------- */ /* double (also complex double), int: this is the default */ /* -------------------------------------------------------------------------- */ #else #ifndef DINT #define DINT #endif #define INT #define DOUBLE #define Real double #define Int int #define Int_max INT_MAX #define CHOLMOD(name) cholmod_ ## name #define ITYPE CHOLMOD_INT #define DTYPE CHOLMOD_DOUBLE #define ID "%d" #endif /* ========================================================================== */ /* === real/complex arithmetic ============================================== */ /* ========================================================================== */ #include "cholmod_complexity.h" /* ========================================================================== */ /* === Architecture and BLAS ================================================ */ /* ========================================================================== */ #include "cholmod_blas.h" /* ========================================================================== */ /* === debugging definitions ================================================ */ /* ========================================================================== */ #ifndef NDEBUG #include #include "cholmod.h" /* The cholmod_dump routines are in the Check module. No CHOLMOD routine * calls the cholmod_check_* or cholmod_print_* routines in the Check module, * since they use Common workspace that may already be in use. Instead, they * use the cholmod_dump_* routines defined there, which allocate their own * workspace if they need it. */ #ifndef EXTERN #define EXTERN extern #endif /* double, int */ EXTERN int cholmod_dump ; EXTERN int cholmod_dump_malloc ; UF_long cholmod_dump_sparse (cholmod_sparse *, const char *, cholmod_common *); int cholmod_dump_factor (cholmod_factor *, const char *, cholmod_common *) ; int cholmod_dump_triplet (cholmod_triplet *, const char *, cholmod_common *) ; int cholmod_dump_dense (cholmod_dense *, const char *, cholmod_common *) ; int cholmod_dump_subset (int *, size_t, size_t, const char *, cholmod_common *) ; int cholmod_dump_perm (int *, size_t, size_t, const char *, cholmod_common *) ; int cholmod_dump_parent (int *, size_t, const char *, cholmod_common *) ; void cholmod_dump_init (const char *, cholmod_common *) ; int cholmod_dump_mem (const char *, UF_long, cholmod_common *) ; void cholmod_dump_real (const char *, Real *, UF_long, UF_long, int, int, cholmod_common *) ; void cholmod_dump_super (UF_long, int *, int *, int *, int *, double *, int, cholmod_common *) ; int cholmod_dump_partition (UF_long, int *, int *, int *, int *, UF_long, cholmod_common *) ; int cholmod_dump_work(int, int, UF_long, cholmod_common *) ; /* double, UF_long */ EXTERN int cholmod_l_dump ; EXTERN int cholmod_l_dump_malloc ; UF_long cholmod_l_dump_sparse (cholmod_sparse *, const char *, cholmod_common *) ; int cholmod_l_dump_factor (cholmod_factor *, const char *, cholmod_common *) ; int cholmod_l_dump_triplet (cholmod_triplet *, const char *, cholmod_common *); int cholmod_l_dump_dense (cholmod_dense *, const char *, cholmod_common *) ; int cholmod_l_dump_subset (UF_long *, size_t, size_t, const char *, cholmod_common *) ; int cholmod_l_dump_perm (UF_long *, size_t, size_t, const char *, cholmod_common *) ; int cholmod_l_dump_parent (UF_long *, size_t, const char *, cholmod_common *) ; void cholmod_l_dump_init (const char *, cholmod_common *) ; int cholmod_l_dump_mem (const char *, UF_long, cholmod_common *) ; void cholmod_l_dump_real (const char *, Real *, UF_long, UF_long, int, int, cholmod_common *) ; void cholmod_l_dump_super (UF_long, UF_long *, UF_long *, UF_long *, UF_long *, double *, int, cholmod_common *) ; int cholmod_l_dump_partition (UF_long, UF_long *, UF_long *, UF_long *, UF_long *, UF_long, cholmod_common *) ; int cholmod_l_dump_work(int, int, UF_long, cholmod_common *) ; #define DEBUG_INIT(s,Common) { CHOLMOD(dump_init)(s, Common) ; } #define ASSERT(expression) (assert (expression)) #define PRK(k,params) \ { \ if (CHOLMOD(dump) >= (k) && Common->print_function != NULL) \ { \ (Common->print_function) params ; \ } \ } #define PRINT0(params) PRK (0, params) #define PRINT1(params) PRK (1, params) #define PRINT2(params) PRK (2, params) #define PRINT3(params) PRK (3, params) #define PRINTM(params) \ { \ if (CHOLMOD(dump_malloc) > 0) \ { \ printf params ; \ } \ } #define DEBUG(statement) statement #else /* Debugging disabled (the normal case) */ #define PRK(k,params) #define DEBUG_INIT(s,Common) #define PRINT0(params) #define PRINT1(params) #define PRINT2(params) #define PRINT3(params) #define PRINTM(params) #define ASSERT(expression) #define DEBUG(statement) #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_core.h0000644000175000017500000027455111674452555022620 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_core.h =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_core.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod_core.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD Core module: basic CHOLMOD objects and routines. * Required by all CHOLMOD modules. Requires no other module or package. * * The CHOLMOD modules are: * * Core basic data structures and definitions * Check check/print the 5 CHOLMOD objects, & 3 types of integer vectors * Cholesky sparse Cholesky factorization * Modify sparse Cholesky update/downdate/row-add/row-delete * MatrixOps sparse matrix functions (add, multiply, norm, ...) * Supernodal supernodal sparse Cholesky factorization * Partition graph-partitioning based orderings * * The CHOLMOD objects: * -------------------- * * cholmod_common parameters, statistics, and workspace * cholmod_sparse a sparse matrix in compressed column form * cholmod_factor an LL' or LDL' factorization * cholmod_dense a dense matrix * cholmod_triplet a sparse matrix in "triplet" form * * The Core module described here defines the CHOLMOD data structures, and * basic operations on them. To create and solve a sparse linear system Ax=b, * the user must create A and b, populate them with values, and then pass them * to the routines in the CHOLMOD Cholesky module. There are two primary * methods for creating A: (1) allocate space for a column-oriented sparse * matrix and fill it with pattern and values, or (2) create a triplet form * matrix and convert it to a sparse matrix. The latter option is simpler. * * The matrices b and x are typically dense matrices, but can also be sparse. * You can allocate and free them as dense matrices with the * cholmod_allocate_dense and cholmod_free_dense routines. * * The cholmod_factor object contains the symbolic and numeric LL' or LDL' * factorization of sparse symmetric matrix. The matrix must be positive * definite for an LL' factorization. It need only be symmetric and have well- * conditioned leading submatrices for it to have an LDL' factorization * (CHOLMOD does not pivot for numerical stability). It is typically created * with the cholmod_factorize routine in the Cholesky module, but can also * be initialized to L=D=I in the Core module and then modified by the Modify * module. It must be freed with cholmod_free_factor, defined below. * * The Core routines for each object are described below. Each list is split * into two parts: the primary routines and secondary routines. * * ============================================================================ * === cholmod_common ========================================================= * ============================================================================ * * The Common object contains control parameters, statistics, and * You must call cholmod_start before calling any other CHOLMOD routine, and * must call cholmod_finish as your last call to CHOLMOD, with two exceptions: * you may call cholmod_print_common and cholmod_check_common in the Check * module after calling cholmod_finish. * * cholmod_start first call to CHOLMOD * cholmod_finish last call to CHOLMOD * ----------------------------- * cholmod_defaults restore default parameters * cholmod_maxrank maximum rank for update/downdate * cholmod_allocate_work allocate workspace in Common * cholmod_free_work free workspace in Common * cholmod_clear_flag clear Flag workspace in Common * cholmod_error called when CHOLMOD encounters an error * cholmod_dbound for internal use in CHOLMOD only * cholmod_hypot compute sqrt (x*x + y*y) accurately * cholmod_divcomplex complex division, c = a/b * * ============================================================================ * === cholmod_sparse ========================================================= * ============================================================================ * * A sparse matrix is held in compressed column form. In the basic type * ("packed", which corresponds to a MATLAB sparse matrix), an n-by-n matrix * with nz entries is held in three arrays: p of size n+1, i of size nz, and x * of size nz. Row indices of column j are held in i [p [j] ... p [j+1]-1] and * in the same locations in x. There may be no duplicate entries in a column. * Row indices in each column may be sorted or unsorted (CHOLMOD keeps track). * A->stype determines the storage mode: 0 if both upper/lower parts are stored, * -1 if A is symmetric and just tril(A) is stored, +1 if symmetric and triu(A) * is stored. * * cholmod_allocate_sparse allocate a sparse matrix * cholmod_free_sparse free a sparse matrix * ----------------------------- * cholmod_reallocate_sparse change the size (# entries) of sparse matrix * cholmod_nnz number of nonzeros in a sparse matrix * cholmod_speye sparse identity matrix * cholmod_spzeros sparse zero matrix * cholmod_transpose transpose a sparse matrix * cholmod_ptranspose transpose/permute a sparse matrix * cholmod_transpose_unsym transpose/permute an unsymmetric sparse matrix * cholmod_transpose_sym transpose/permute a symmetric sparse matrix * cholmod_sort sort row indices in each column of sparse matrix * cholmod_band C = tril (triu (A,k1), k2) * cholmod_band_inplace A = tril (triu (A,k1), k2) * cholmod_aat C = A*A' * cholmod_copy_sparse C = A, create an exact copy of a sparse matrix * cholmod_copy C = A, with possible change of stype * cholmod_add C = alpha*A + beta*B * cholmod_sparse_xtype change the xtype of a sparse matrix * * ============================================================================ * === cholmod_factor ========================================================= * ============================================================================ * * The data structure for an LL' or LDL' factorization is too complex to * describe in one sentence. This object can hold the symbolic analysis alone, * or in combination with a "simplicial" (similar to a sparse matrix) or * "supernodal" form of the numerical factorization. Only the routine to free * a factor is primary, since a factor object is created by the factorization * routine (cholmod_factorize). It must be freed with cholmod_free_factor. * * cholmod_free_factor free a factor * ----------------------------- * cholmod_allocate_factor allocate a factor (LL' or LDL') * cholmod_reallocate_factor change the # entries in a factor * cholmod_change_factor change the type of factor (e.g., LDL' to LL') * cholmod_pack_factor pack the columns of a factor * cholmod_reallocate_column resize a single column of a factor * cholmod_factor_to_sparse create a sparse matrix copy of a factor * cholmod_copy_factor create a copy of a factor * cholmod_factor_xtype change the xtype of a factor * * Note that there is no cholmod_sparse_to_factor routine to create a factor * as a copy of a sparse matrix. It could be done, after a fashion, but a * lower triangular sparse matrix would not necessarily have a chordal graph, * which would break the many CHOLMOD routines that rely on this property. * * ============================================================================ * === cholmod_dense ========================================================== * ============================================================================ * * The solve routines and some of the MatrixOps and Modify routines use dense * matrices as inputs. These are held in column-major order. With a leading * dimension of d, the entry in row i and column j is held in x [i+j*d]. * * cholmod_allocate_dense allocate a dense matrix * cholmod_free_dense free a dense matrix * ----------------------------- * cholmod_zeros allocate a dense matrix of all zeros * cholmod_ones allocate a dense matrix of all ones * cholmod_eye allocate a dense identity matrix * cholmod_sparse_to_dense create a dense matrix copy of a sparse matrix * cholmod_dense_to_sparse create a sparse matrix copy of a dense matrix * cholmod_copy_dense create a copy of a dense matrix * cholmod_copy_dense2 copy a dense matrix (pre-allocated) * cholmod_dense_xtype change the xtype of a dense matrix * * ============================================================================ * === cholmod_triplet ======================================================== * ============================================================================ * * A sparse matrix held in triplet form is the simplest one for a user to * create. It consists of a list of nz entries in arbitrary order, held in * three arrays: i, j, and x, each of length nk. The kth entry is in row i[k], * column j[k], with value x[k]. There may be duplicate values; if A(i,j) * appears more than once, its value is the sum of the entries with those row * and column indices. * * cholmod_allocate_triplet allocate a triplet matrix * cholmod_triplet_to_sparse create a sparse matrix copy of a triplet matrix * cholmod_free_triplet free a triplet matrix * ----------------------------- * cholmod_reallocate_triplet change the # of entries in a triplet matrix * cholmod_sparse_to_triplet create a triplet matrix copy of a sparse matrix * cholmod_copy_triplet create a copy of a triplet matrix * cholmod_triplet_xtype change the xtype of a triplet matrix * * ============================================================================ * === memory management ====================================================== * ============================================================================ * * cholmod_malloc malloc wrapper * cholmod_calloc calloc wrapper * cholmod_free free wrapper * cholmod_realloc realloc wrapper * cholmod_realloc_multiple realloc wrapper for multiple objects * * ============================================================================ * === Core CHOLMOD prototypes ================================================ * ============================================================================ * * All CHOLMOD routines (in all modules) use the following protocol for return * values, with one exception: * * int TRUE (1) if successful, or FALSE (0) otherwise. * (exception: cholmod_divcomplex) * UF_long a value >= 0 if successful, or -1 otherwise. * double a value >= 0 if successful, or -1 otherwise. * size_t a value > 0 if successful, or 0 otherwise. * void * a non-NULL pointer to newly allocated memory if * successful, or NULL otherwise. * cholmod_sparse * a non-NULL pointer to a newly allocated matrix * if successful, or NULL otherwise. * cholmod_factor * a non-NULL pointer to a newly allocated factor * if successful, or NULL otherwise. * cholmod_triplet * a non-NULL pointer to a newly allocated triplet * matrix if successful, or NULL otherwise. * cholmod_dense * a non-NULL pointer to a newly allocated triplet * matrix if successful, or NULL otherwise. * * The last parameter to all routines is always a pointer to the CHOLMOD * Common object. * * TRUE and FALSE are not defined here, since they may conflict with the user * program. A routine that described here returning TRUE or FALSE returns 1 * or 0, respectively. Any TRUE/FALSE parameter is true if nonzero, false if * zero. */ #ifndef CHOLMOD_CORE_H #define CHOLMOD_CORE_H /* ========================================================================== */ /* === CHOLMOD version ====================================================== */ /* ========================================================================== */ /* All versions of CHOLMOD will include the following definitions. * As an example, to test if the version you are using is 1.3 or later: * * if (CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3)) ... * * This also works during compile-time: * * #if CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3) * printf ("This is version 1.3 or later\n") ; * #else * printf ("This is version is earlier than 1.3\n") ; * #endif */ #define CHOLMOD_DATE "Sept 30, 2008" #define CHOLMOD_VER_CODE(main,sub) ((main) * 1000 + (sub)) #define CHOLMOD_MAIN_VERSION 1 #define CHOLMOD_SUB_VERSION 7 #define CHOLMOD_SUBSUB_VERSION 1 #define CHOLMOD_VERSION \ CHOLMOD_VER_CODE(CHOLMOD_MAIN_VERSION,CHOLMOD_SUB_VERSION) /* ========================================================================== */ /* === non-CHOLMOD include files ============================================ */ /* ========================================================================== */ /* This is the only non-CHOLMOD include file imposed on the user program. * It required for size_t definition used here. CHOLMOD itself includes other * ANSI C89 standard #include files, but does not expose them to the user. * * CHOLMOD assumes that your C compiler is ANSI C89 compliant. It does not make * use of ANSI C99 features. */ #include #include /* ========================================================================== */ /* === CHOLMOD objects ====================================================== */ /* ========================================================================== */ /* Each CHOLMOD object has its own type code. */ #define CHOLMOD_COMMON 0 #define CHOLMOD_SPARSE 1 #define CHOLMOD_FACTOR 2 #define CHOLMOD_DENSE 3 #define CHOLMOD_TRIPLET 4 /* ========================================================================== */ /* === CHOLMOD Common ======================================================= */ /* ========================================================================== */ /* itype defines the types of integer used: */ #define CHOLMOD_INT 0 /* all integer arrays are int */ #define CHOLMOD_INTLONG 1 /* most are int, some are UF_long */ #define CHOLMOD_LONG 2 /* all integer arrays are UF_long */ /* The itype of all parameters for all CHOLMOD routines must match. * FUTURE WORK: CHOLMOD_INTLONG is not yet supported. */ /* dtype defines what the numerical type is (double or float): */ #define CHOLMOD_DOUBLE 0 /* all numerical values are double */ #define CHOLMOD_SINGLE 1 /* all numerical values are float */ /* The dtype of all parameters for all CHOLMOD routines must match. * * Scalar floating-point values are always passed as double arrays of size 2 * (for the real and imaginary parts). They are typecast to float as needed. * FUTURE WORK: the float case is not supported yet. */ /* xtype defines the kind of numerical values used: */ #define CHOLMOD_PATTERN 0 /* pattern only, no numerical values */ #define CHOLMOD_REAL 1 /* a real matrix */ #define CHOLMOD_COMPLEX 2 /* a complex matrix (ANSI C99 compatible) */ #define CHOLMOD_ZOMPLEX 3 /* a complex matrix (MATLAB compatible) */ /* The xtype of all parameters for all CHOLMOD routines must match. * * CHOLMOD_PATTERN: x and z are ignored. * CHOLMOD_DOUBLE: x is non-null of size nzmax, z is ignored. * CHOLMOD_COMPLEX: x is non-null of size 2*nzmax doubles, z is ignored. * CHOLMOD_ZOMPLEX: x and z are non-null of size nzmax * * In the real case, z is ignored. The kth entry in the matrix is x [k]. * There are two methods for the complex case. In the ANSI C99-compatible * CHOLMOD_COMPLEX case, the real and imaginary parts of the kth entry * are in x [2*k] and x [2*k+1], respectively. z is ignored. In the * MATLAB-compatible CHOLMOD_ZOMPLEX case, the real and imaginary * parts of the kth entry are in x [k] and z [k]. * * Scalar floating-point values are always passed as double arrays of size 2 * (real and imaginary parts). The imaginary part of a scalar is ignored if * the routine operates on a real matrix. * * These Modules support complex and zomplex matrices, with a few exceptions: * * Check all routines * Cholesky all routines * Core all except cholmod_aat, add, band, copy * Demo all routines * Partition all routines * Supernodal all routines support any real, complex, or zomplex input. * There will never be a supernodal zomplex L; a complex * supernodal L is created if A is zomplex. * Tcov all routines * Valgrind all routines * * These Modules provide partial support for complex and zomplex matrices: * * MATLAB all routines support real and zomplex only, not complex, * with the exception of ldlupdate, which supports * real matrices only. This is a minor constraint since * MATLAB's matrices are all real or zomplex. * MatrixOps only norm_dense, norm_sparse, and sdmult support complex * and zomplex * * These Modules do not support complex and zomplex matrices at all: * * Modify all routines support real matrices only */ /* Definitions for cholmod_common: */ #define CHOLMOD_MAXMETHODS 9 /* maximum number of different methods that */ /* cholmod_analyze can try. Must be >= 9. */ /* Common->status values. zero means success, negative means a fatal error, * positive is a warning. */ #define CHOLMOD_OK 0 /* success */ #define CHOLMOD_NOT_INSTALLED (-1) /* failure: method not installed */ #define CHOLMOD_OUT_OF_MEMORY (-2) /* failure: out of memory */ #define CHOLMOD_TOO_LARGE (-3) /* failure: integer overflow occured */ #define CHOLMOD_INVALID (-4) /* failure: invalid input */ #define CHOLMOD_NOT_POSDEF (1) /* warning: matrix not pos. def. */ #define CHOLMOD_DSMALL (2) /* warning: D for LDL' or diag(L) or */ /* LL' has tiny absolute value */ /* ordering method (also used for L->ordering) */ #define CHOLMOD_NATURAL 0 /* use natural ordering */ #define CHOLMOD_GIVEN 1 /* use given permutation */ #define CHOLMOD_AMD 2 /* use minimum degree (AMD) */ #define CHOLMOD_METIS 3 /* use METIS' nested dissection */ #define CHOLMOD_NESDIS 4 /* use CHOLMOD's version of nested dissection:*/ /* node bisector applied recursively, followed * by constrained minimum degree (CSYMAMD or * CCOLAMD) */ #define CHOLMOD_COLAMD 5 /* use AMD for A, COLAMD for A*A' */ /* POSTORDERED is not a method, but a result of natural ordering followed by a * weighted postorder. It is used for L->ordering, not method [ ].ordering. */ #define CHOLMOD_POSTORDERED 6 /* natural ordering, postordered. */ /* supernodal strategy (for Common->supernodal) */ #define CHOLMOD_SIMPLICIAL 0 /* always do simplicial */ #define CHOLMOD_AUTO 1 /* select simpl/super depending on matrix */ #define CHOLMOD_SUPERNODAL 2 /* always do supernodal */ typedef struct cholmod_common_struct { /* ---------------------------------------------------------------------- */ /* parameters for symbolic/numeric factorization and update/downdate */ /* ---------------------------------------------------------------------- */ double dbound ; /* Smallest absolute value of diagonal entries of D * for LDL' factorization and update/downdate/rowadd/ * rowdel, or the diagonal of L for an LL' factorization. * Entries in the range 0 to dbound are replaced with dbound. * Entries in the range -dbound to 0 are replaced with -dbound. No * changes are made to the diagonal if dbound <= 0. Default: zero */ double grow0 ; /* For a simplicial factorization, L->i and L->x can * grow if necessary. grow0 is the factor by which * it grows. For the initial space, L is of size MAX (1,grow0) times * the required space. If L runs out of space, the new size of L is * MAX(1.2,grow0) times the new required space. If you do not plan on * modifying the LDL' factorization in the Modify module, set grow0 to * zero (or set grow2 to 0, see below). Default: 1.2 */ double grow1 ; size_t grow2 ; /* For a simplicial factorization, each column j of L * is initialized with space equal to * grow1*L->ColCount[j] + grow2. If grow0 < 1, grow1 < 1, or grow2 == 0, * then the space allocated is exactly equal to L->ColCount[j]. If the * column j runs out of space, it increases to grow1*need + grow2 in * size, where need is the total # of nonzeros in that column. If you do * not plan on modifying the factorization in the Modify module, set * grow2 to zero. Default: grow1 = 1.2, grow2 = 5. */ size_t maxrank ; /* rank of maximum update/downdate. Valid values: * 2, 4, or 8. A value < 2 is set to 2, and a * value > 8 is set to 8. It is then rounded up to the next highest * power of 2, if not already a power of 2. Workspace (Xwork, below) of * size nrow-by-maxrank double's is allocated for the update/downdate. * If an update/downdate of rank-k is requested, with k > maxrank, * it is done in steps of maxrank. Default: 8, which is fastest. * Memory usage can be reduced by setting maxrank to 2 or 4. */ double supernodal_switch ; /* supernodal vs simplicial factorization */ int supernodal ; /* If Common->supernodal <= CHOLMOD_SIMPLICIAL * (0) then cholmod_analyze performs a * simplicial analysis. If >= CHOLMOD_SUPERNODAL (2), then a supernodal * analysis is performed. If == CHOLMOD_AUTO (1) and * flop/nnz(L) < Common->supernodal_switch, then a simplicial analysis * is done. A supernodal analysis done otherwise. * Default: CHOLMOD_AUTO. Default supernodal_switch = 40 */ int final_asis ; /* If TRUE, then ignore the other final_* parameters * (except for final_pack). * The factor is left as-is when done. Default: TRUE.*/ int final_super ; /* If TRUE, leave a factor in supernodal form when * supernodal factorization is finished. If FALSE, * then convert to a simplicial factor when done. * Default: TRUE */ int final_ll ; /* If TRUE, leave factor in LL' form when done. * Otherwise, leave in LDL' form. Default: FALSE */ int final_pack ; /* If TRUE, pack the columns when done. If TRUE, and * cholmod_factorize is called with a symbolic L, L is * allocated with exactly the space required, using L->ColCount. If you * plan on modifying the factorization, set Common->final_pack to FALSE, * and each column will be given a little extra slack space for future * growth in fill-in due to updates. Default: TRUE */ int final_monotonic ; /* If TRUE, ensure columns are monotonic when done. * Default: TRUE */ int final_resymbol ;/* if cholmod_factorize performed a supernodal * factorization, final_resymbol is true, and * final_super is FALSE (convert a simplicial numeric factorization), * then numerically zero entries that resulted from relaxed supernodal * amalgamation are removed. This does not remove entries that are zero * due to exact numeric cancellation, since doing so would break the * update/downdate rowadd/rowdel routines. Default: FALSE. */ /* supernodal relaxed amalgamation parameters: */ double zrelax [3] ; size_t nrelax [3] ; /* Let ns be the total number of columns in two adjacent supernodes. * Let z be the fraction of zero entries in the two supernodes if they * are merged (z includes zero entries from prior amalgamations). The * two supernodes are merged if: * (ns <= nrelax [0]) || (no new zero entries added) || * (ns <= nrelax [1] && z < zrelax [0]) || * (ns <= nrelax [2] && z < zrelax [1]) || (z < zrelax [2]) * * Default parameters result in the following rule: * (ns <= 4) || (no new zero entries added) || * (ns <= 16 && z < 0.8) || (ns <= 48 && z < 0.1) || (z < 0.05) */ int prefer_zomplex ; /* X = cholmod_solve (sys, L, B, Common) computes * x=A\b or solves a related system. If L and B are * both real, then X is real. Otherwise, X is returned as * CHOLMOD_COMPLEX if Common->prefer_zomplex is FALSE, or * CHOLMOD_ZOMPLEX if Common->prefer_zomplex is TRUE. This parameter * is needed because there is no supernodal zomplex L. Suppose the * caller wants all complex matrices to be stored in zomplex form * (MATLAB, for example). A supernodal L is returned in complex form * if A is zomplex. B can be real, and thus X = cholmod_solve (L,B) * should return X as zomplex. This cannot be inferred from the input * arguments L and B. Default: FALSE, since all data types are * supported in CHOLMOD_COMPLEX form and since this is the native type * of LAPACK and the BLAS. Note that the MATLAB/cholmod.c mexFunction * sets this parameter to TRUE, since MATLAB matrices are in * CHOLMOD_ZOMPLEX form. */ int prefer_upper ; /* cholmod_analyze and cholmod_factorize work * fastest when a symmetric matrix is stored in * upper triangular form when a fill-reducing ordering is used. In * MATLAB, this corresponds to how x=A\b works. When the matrix is * ordered as-is, they work fastest when a symmetric matrix is in lower * triangular form. In MATLAB, R=chol(A) does the opposite. This * parameter affects only how cholmod_read returns a symmetric matrix. * If TRUE (the default case), a symmetric matrix is always returned in * upper-triangular form (A->stype = 1). */ int quick_return_if_not_posdef ; /* if TRUE, the supernodal numeric * factorization will return quickly if * the matrix is not positive definite. Default: FALSE. */ /* ---------------------------------------------------------------------- */ /* printing and error handling options */ /* ---------------------------------------------------------------------- */ int print ; /* print level. Default: 3 */ int precise ; /* if TRUE, print 16 digits. Otherwise print 5 */ int (*print_function) (const char *, ...) ; /* pointer to printf */ int try_catch ; /* if TRUE, then ignore errors; CHOLMOD is in the middle * of a try/catch block. No error message is printed * and the Common->error_handler function is not called. */ void (*error_handler) (int status, const char *file, int line, const char *message) ; /* Common->error_handler is the user's error handling routine. If not * NULL, this routine is called if an error occurs in CHOLMOD. status * can be CHOLMOD_OK (0), negative for a fatal error, and positive for * a warning. file is a string containing the name of the source code * file where the error occured, and line is the line number in that * file. message is a string describing the error in more detail. */ /* ---------------------------------------------------------------------- */ /* ordering options */ /* ---------------------------------------------------------------------- */ /* The cholmod_analyze routine can try many different orderings and select * the best one. It can also try one ordering method multiple times, with * different parameter settings. The default is to use three orderings, * the user's permutation (if provided), AMD which is the fastest ordering * and generally gives good fill-in, and METIS. CHOLMOD's nested dissection * (METIS with a constrained AMD) usually gives a better ordering than METIS * alone (by about 5% to 10%) but it takes more time. * * If you know the method that is best for your matrix, set Common->nmethods * to 1 and set Common->method [0] to the set of parameters for that method. * If you set it to 1 and do not provide a permutation, then only AMD will * be called. * * If METIS is not available, the default # of methods tried is 2 (the user * permutation, if any, and AMD). * * To try other methods, set Common->nmethods to the number of methods you * want to try. The suite of default methods and their parameters is * described in the cholmod_defaults routine, and summarized here: * * Common->method [i]: * i = 0: user-provided ordering (cholmod_analyze_p only) * i = 1: AMD (for both A and A*A') * i = 2: METIS * i = 3: CHOLMOD's nested dissection (NESDIS), default parameters * i = 4: natural * i = 5: NESDIS with nd_small = 20000 * i = 6: NESDIS with nd_small = 4, no constrained minimum degree * i = 7: NESDIS with no dense node removal * i = 8: AMD for A, COLAMD for A*A' * * You can modify the suite of methods you wish to try by modifying * Common.method [...] after calling cholmod_start or cholmod_defaults. * * For example, to use AMD, followed by a weighted postordering: * * Common->nmethods = 1 ; * Common->method [0].ordering = CHOLMOD_AMD ; * Common->postorder = TRUE ; * * To use the natural ordering (with no postordering): * * Common->nmethods = 1 ; * Common->method [0].ordering = CHOLMOD_NATURAL ; * Common->postorder = FALSE ; * * If you are going to factorize hundreds or more matrices with the same * nonzero pattern, you may wish to spend a great deal of time finding a * good permutation. In this case, try setting Common->nmethods to 9. * The time spent in cholmod_analysis will be very high, but you need to * call it only once. * * cholmod_analyze sets Common->current to a value between 0 and nmethods-1. * Each ordering method uses the set of options defined by this parameter. */ int nmethods ; /* The number of ordering methods to try. Default: 0. * nmethods = 0 is a special case. cholmod_analyze * will try the user-provided ordering (if given) and AMD. Let fl and * lnz be the flop count and nonzeros in L from AMD's ordering. Let * anz be the number of nonzeros in the upper or lower triangular part * of the symmetric matrix A. If fl/lnz < 500 or lnz/anz < 5, then this * is a good ordering, and METIS is not attempted. Otherwise, METIS is * tried. The best ordering found is used. If nmethods > 0, the * methods used are given in the method[ ] array, below. The first * three methods in the default suite of orderings is (1) use the given * permutation (if provided), (2) use AMD, and (3) use METIS. Maximum * allowed value is CHOLMOD_MAXMETHODS. */ int current ; /* The current method being tried. Default: 0. Valid * range is 0 to nmethods-1. */ int selected ; /* The best method found. */ /* The suite of ordering methods and parameters: */ struct cholmod_method_struct { /* statistics for this method */ double lnz ; /* nnz(L) excl. zeros from supernodal amalgamation, * for a "pure" L */ double fl ; /* flop count for a "pure", real simplicial LL' * factorization, with no extra work due to * amalgamation. Subtract n to get the LDL' flop count. Multiply * by about 4 if the matrix is complex or zomplex. */ /* ordering method parameters */ double prune_dense ;/* dense row/col control for AMD, SYMAMD, CSYMAMD, * and NESDIS (cholmod_nested_dissection). For a * symmetric n-by-n matrix, rows/columns with more than * MAX (16, prune_dense * sqrt (n)) entries are removed prior to * ordering. They appear at the end of the re-ordered matrix. * * If prune_dense < 0, only completely dense rows/cols are removed. * * This paramater is also the dense column control for COLAMD and * CCOLAMD. For an m-by-n matrix, columns with more than * MAX (16, prune_dense * sqrt (MIN (m,n))) entries are removed prior * to ordering. They appear at the end of the re-ordered matrix. * CHOLMOD factorizes A*A', so it calls COLAMD and CCOLAMD with A', * not A. Thus, this parameter affects the dense *row* control for * CHOLMOD's matrix, and the dense *column* control for COLAMD and * CCOLAMD. * * Removing dense rows and columns improves the run-time of the * ordering methods. It has some impact on ordering quality * (usually minimal, sometimes good, sometimes bad). * * Default: 10. */ double prune_dense2 ;/* dense row control for COLAMD and CCOLAMD. * Rows with more than MAX (16, dense2 * sqrt (n)) * for an m-by-n matrix are removed prior to ordering. CHOLMOD's * matrix is transposed before ordering it with COLAMD or CCOLAMD, * so this controls the dense *columns* of CHOLMOD's matrix, and * the dense *rows* of COLAMD's or CCOLAMD's matrix. * * If prune_dense2 < 0, only completely dense rows/cols are removed. * * Default: -1. Note that this is not the default for COLAMD and * CCOLAMD. -1 is best for Cholesky. 10 is best for LU. */ double nd_oksep ; /* in NESDIS, when a node separator is computed, it * discarded if nsep >= nd_oksep*n, where nsep is * the number of nodes in the separator, and n is the size of the * graph being cut. Valid range is 0 to 1. If 1 or greater, the * separator is discarded if it consists of the entire graph. * Default: 1 */ double other1 [4] ; /* future expansion */ size_t nd_small ; /* do not partition graphs with fewer nodes than * nd_small, in NESDIS. Default: 200 (same as * METIS) */ size_t other2 [4] ; /* future expansion */ int aggressive ; /* Aggresive absorption in AMD, COLAMD, SYMAMD, * CCOLAMD, and CSYMAMD. Default: TRUE */ int order_for_lu ; /* CCOLAMD can be optimized to produce an ordering * for LU or Cholesky factorization. CHOLMOD only * performs a Cholesky factorization. However, you may wish to use * CHOLMOD as an interface for CCOLAMD but use it for your own LU * factorization. In this case, order_for_lu should be set to FALSE. * When factorizing in CHOLMOD itself, you should *** NEVER *** set * this parameter FALSE. Default: TRUE. */ int nd_compress ; /* If TRUE, compress the graph and subgraphs before * partitioning them in NESDIS. Default: TRUE */ int nd_camd ; /* If 1, follow the nested dissection ordering * with a constrained minimum degree ordering that * respects the partitioning just found (using CAMD). If 2, use * CSYMAMD instead. If you set nd_small very small, you may not need * this ordering, and can save time by setting it to zero (no * constrained minimum degree ordering). Default: 1. */ int nd_components ; /* The nested dissection ordering finds a node * separator that splits the graph into two parts, * which may be unconnected. If nd_components is TRUE, each of * these connected components is split independently. If FALSE, * each part is split as a whole, even if it consists of more than * one connected component. Default: FALSE */ /* fill-reducing ordering to use */ int ordering ; size_t other3 [4] ; /* future expansion */ } method [CHOLMOD_MAXMETHODS + 1] ; int postorder ; /* If TRUE, cholmod_analyze follows the ordering with a * weighted postorder of the elimination tree. Improves * supernode amalgamation. Does not affect fundamental nnz(L) and * flop count. Default: TRUE. */ /* ---------------------------------------------------------------------- */ /* memory management routines */ /* ---------------------------------------------------------------------- */ void *(*malloc_memory) (size_t) ; /* pointer to malloc */ void *(*realloc_memory) (void *, size_t) ; /* pointer to realloc */ void (*free_memory) (void *) ; /* pointer to free */ void *(*calloc_memory) (size_t, size_t) ; /* pointer to calloc */ /* ---------------------------------------------------------------------- */ /* routines for complex arithmetic */ /* ---------------------------------------------------------------------- */ int (*complex_divide) (double ax, double az, double bx, double bz, double *cx, double *cz) ; /* flag = complex_divide (ax, az, bx, bz, &cx, &cz) computes the complex * division c = a/b, where ax and az hold the real and imaginary part * of a, and b and c are stored similarly. flag is returned as 1 if * a divide-by-zero occurs, or 0 otherwise. By default, the function * pointer Common->complex_divide is set equal to cholmod_divcomplex. */ double (*hypotenuse) (double x, double y) ; /* s = hypotenuse (x,y) computes s = sqrt (x*x + y*y), but does so more * accurately. By default, the function pointer Common->hypotenuse is * set equal to cholmod_hypot. See also the hypot function in the C99 * standard, which has an identical syntax and function. If you have * a C99-compliant compiler, you can set Common->hypotenuse = hypot. */ /* ---------------------------------------------------------------------- */ /* METIS workarounds */ /* ---------------------------------------------------------------------- */ double metis_memory ; /* This is a parameter for CHOLMOD's interface to * METIS, not a parameter to METIS itself. METIS * uses an amount of memory that is difficult to estimate precisely * beforehand. If it runs out of memory, it terminates your program. * All routines in CHOLMOD except for CHOLMOD's interface to METIS * return an error status and safely return to your program if they run * out of memory. To mitigate this problem, the CHOLMOD interface * can allocate a single block of memory equal in size to an empirical * upper bound of METIS's memory usage times the Common->metis_memory * parameter, and then immediately free it. It then calls METIS. If * this pre-allocation fails, it is possible that METIS will fail as * well, and so CHOLMOD returns with an out-of-memory condition without * calling METIS. * * METIS_NodeND (used in the CHOLMOD_METIS ordering option) with its * default parameter settings typically uses about (4*nz+40n+4096) * times sizeof(int) memory, where nz is equal to the number of entries * in A for the symmetric case or AA' if an unsymmetric matrix is * being ordered (where nz includes both the upper and lower parts * of A or AA'). The observed "upper bound" (with 2 exceptions), * measured in an instrumented copy of METIS 4.0.1 on thousands of * matrices, is (10*nz+50*n+4096) * sizeof(int). Two large matrices * exceeded this bound, one by almost a factor of 2 (Gupta/gupta2). * * If your program is terminated by METIS, try setting metis_memory to * 2.0, or even higher if needed. By default, CHOLMOD assumes that METIS * does not have this problem (so that CHOLMOD will work correctly when * this issue is fixed in METIS). Thus, the default value is zero. * This work-around is not guaranteed anyway. * * If a matrix exceeds this predicted memory usage, AMD is attempted * instead. It, too, may run out of memory, but if it does so it will * not terminate your program. */ double metis_dswitch ; /* METIS_NodeND in METIS 4.0.1 gives a seg */ size_t metis_nswitch ; /* fault with one matrix of order n = 3005 and * nz = 6,036,025. This is a very dense graph. * The workaround is to use AMD instead of METIS for matrices of dimension * greater than Common->metis_nswitch (default 3000) or more and with * density of Common->metis_dswitch (default 0.66) or more. * cholmod_nested_dissection has no problems with the same matrix, even * though it uses METIS_NodeComputeSeparator on this matrix. If this * seg fault does not affect you, set metis_nswitch to zero or less, * and CHOLMOD will not switch to AMD based just on the density of the * matrix (it will still switch to AMD if the metis_memory parameter * causes the switch). */ /* ---------------------------------------------------------------------- */ /* workspace */ /* ---------------------------------------------------------------------- */ /* CHOLMOD has several routines that take less time than the size of * workspace they require. Allocating and initializing the workspace would * dominate the run time, unless workspace is allocated and initialized * just once. CHOLMOD allocates this space when needed, and holds it here * between calls to CHOLMOD. cholmod_start sets these pointers to NULL * (which is why it must be the first routine called in CHOLMOD). * cholmod_finish frees the workspace (which is why it must be the last * call to CHOLMOD). */ size_t nrow ; /* size of Flag and Head */ UF_long mark ; /* mark value for Flag array */ size_t iworksize ; /* size of Iwork. Upper bound: 6*nrow+ncol */ size_t xworksize ; /* size of Xwork, in bytes. * maxrank*nrow*sizeof(double) for update/downdate. * 2*nrow*sizeof(double) otherwise */ /* initialized workspace: contents needed between calls to CHOLMOD */ void *Flag ; /* size nrow, an integer array. Kept cleared between * calls to cholmod rouines (Flag [i] < mark) */ void *Head ; /* size nrow+1, an integer array. Kept cleared between * calls to cholmod routines (Head [i] = EMPTY) */ void *Xwork ; /* a double array. Its size varies. It is nrow for * most routines (cholmod_rowfac, cholmod_add, * cholmod_aat, cholmod_norm, cholmod_ssmult) for the real case, twice * that when the input matrices are complex or zomplex. It is of size * 2*nrow for cholmod_rowadd and cholmod_rowdel. For cholmod_updown, * its size is maxrank*nrow where maxrank is 2, 4, or 8. Kept cleared * between calls to cholmod (set to zero). */ /* uninitialized workspace, contents not needed between calls to CHOLMOD */ void *Iwork ; /* size iworksize, 2*nrow+ncol for most routines, * up to 6*nrow+ncol for cholmod_analyze. */ int itype ; /* If CHOLMOD_LONG, Flag, Head, and Iwork are UF_long. * Otherwise all three arrays are int. */ int dtype ; /* double or float */ /* Common->itype and Common->dtype are used to define the types of all * sparse matrices, triplet matrices, dense matrices, and factors * created using this Common struct. The itypes and dtypes of all * parameters to all CHOLMOD routines must match. */ int no_workspace_reallocate ; /* this is an internal flag, used as a * precaution by cholmod_analyze. It is normally false. If true, * cholmod_allocate_work is not allowed to reallocate any workspace; * they must use the existing workspace in Common (Iwork, Flag, Head, * and Xwork). Added for CHOLMOD v1.1 */ /* ---------------------------------------------------------------------- */ /* statistics */ /* ---------------------------------------------------------------------- */ /* fl and lnz are set only in cholmod_analyze and cholmod_rowcolcounts, * in the Cholesky modudle. modfl is set only in the Modify module. */ int status ; /* error code */ double fl ; /* LL' flop count from most recent analysis */ double lnz ; /* fundamental nz in L */ double anz ; /* nonzeros in tril(A) if A is symmetric/lower, * triu(A) if symmetric/upper, or tril(A*A') if * unsymmetric, in last call to cholmod_analyze. */ double modfl ; /* flop count from most recent update/downdate/ * rowadd/rowdel (excluding flops to modify the * solution to Lx=b, if computed) */ size_t malloc_count ; /* # of objects malloc'ed minus the # free'd*/ size_t memory_usage ; /* peak memory usage in bytes */ size_t memory_inuse ; /* current memory usage in bytes */ double nrealloc_col ; /* # of column reallocations */ double nrealloc_factor ;/* # of factor reallocations due to col. reallocs */ double ndbounds_hit ; /* # of times diagonal modified by dbound */ double rowfacfl ; /* # of flops in last call to cholmod_rowfac */ double aatfl ; /* # of flops to compute A(:,f)*A(:,f)' */ /* ---------------------------------------------------------------------- */ /* future expansion */ /* ---------------------------------------------------------------------- */ /* To allow CHOLMOD to be updated without recompiling the user application, * additional space is set aside here for future statistics, parameters, * and workspace. Note: additional entries were added in v1.1 to the * method array, above, and thus v1.0 and v1.1 are not binary compatible. * * v1.1 to the current version are binary compatible. */ /* ---------------------------------------------------------------------- */ double other1 [12] ; /* reduced from size 16 in v1.6 */ double SPQR_xstat [2] ; /* for SuiteSparseQR statistics */ /* SuiteSparseQR control parameters: */ double SPQR_grain ; /* task size is >= max (total flops / grain) */ double SPQR_small ; /* task size is >= small */ /* ---------------------------------------------------------------------- */ UF_long SPQR_istat [10] ; /* for SuiteSparseQR statistics */ UF_long other2 [6] ; /* reduced from size 16 in v1.6 */ /* ---------------------------------------------------------------------- */ int other3 [10] ; /* reduced from size 16 in v1.1. */ int prefer_binary ; /* cholmod_read_triplet converts a symmetric * pattern-only matrix into a real matrix. If * prefer_binary is FALSE, the diagonal entries are set to 1 + the degree * of the row/column, and off-diagonal entries are set to -1 (resulting * in a positive definite matrix if the diagonal is zero-free). Most * symmetric patterns are the pattern a positive definite matrix. If * this parameter is TRUE, then the matrix is returned with a 1 in each * entry, instead. Default: FALSE. Added in v1.3. */ /* control parameter (added for v1.2): */ int default_nesdis ; /* Default: FALSE. If FALSE, then the default * ordering strategy (when Common->nmethods == 0) * is to try the given ordering (if present), AMD, and then METIS if AMD * reports high fill-in. If Common->default_nesdis is TRUE then NESDIS * is used instead in the default strategy. */ /* statistic (added for v1.2): */ int called_nd ; /* TRUE if the last call to * cholmod_analyze called NESDIS or METIS. */ int blas_ok ; /* FALSE if BLAS int overflow; TRUE otherwise */ /* SuiteSparseQR control parameters: */ int SPQR_shrink ; /* controls stack realloc method */ int SPQR_nthreads ; /* number of TBB threads, 0 = auto */ /* ---------------------------------------------------------------------- */ size_t other4 [16] ; /* ---------------------------------------------------------------------- */ void *other5 [16] ; } cholmod_common ; /* -------------------------------------------------------------------------- */ /* cholmod_start: first call to CHOLMOD */ /* -------------------------------------------------------------------------- */ int cholmod_start ( cholmod_common *Common ) ; int cholmod_l_start (cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_finish: last call to CHOLMOD */ /* -------------------------------------------------------------------------- */ int cholmod_finish ( cholmod_common *Common ) ; int cholmod_l_finish (cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_defaults: restore default parameters */ /* -------------------------------------------------------------------------- */ int cholmod_defaults ( cholmod_common *Common ) ; int cholmod_l_defaults (cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_maxrank: return valid maximum rank for update/downdate */ /* -------------------------------------------------------------------------- */ size_t cholmod_maxrank /* returns validated value of Common->maxrank */ ( /* ---- input ---- */ size_t n, /* A and L will have n rows */ /* --------------- */ cholmod_common *Common ) ; size_t cholmod_l_maxrank (size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_allocate_work: allocate workspace in Common */ /* -------------------------------------------------------------------------- */ int cholmod_allocate_work ( /* ---- input ---- */ size_t nrow, /* size: Common->Flag (nrow), Common->Head (nrow+1) */ size_t iworksize, /* size of Common->Iwork */ size_t xworksize, /* size of Common->Xwork */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_allocate_work (size_t, size_t, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_free_work: free workspace in Common */ /* -------------------------------------------------------------------------- */ int cholmod_free_work ( cholmod_common *Common ) ; int cholmod_l_free_work (cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_clear_flag: clear Flag workspace in Common */ /* -------------------------------------------------------------------------- */ /* use a macro for speed */ #define CHOLMOD_CLEAR_FLAG(Common) \ { \ Common->mark++ ; \ if (Common->mark <= 0) \ { \ Common->mark = EMPTY ; \ CHOLMOD (clear_flag) (Common) ; \ } \ } UF_long cholmod_clear_flag ( cholmod_common *Common ) ; UF_long cholmod_l_clear_flag (cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_error: called when CHOLMOD encounters an error */ /* -------------------------------------------------------------------------- */ int cholmod_error ( /* ---- input ---- */ int status, /* error status */ const char *file, /* name of source code file where error occured */ int line, /* line number in source code file where error occured*/ const char *message,/* error message */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_error (int, const char *, int, const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_dbound: for internal use in CHOLMOD only */ /* -------------------------------------------------------------------------- */ double cholmod_dbound /* returns modified diagonal entry of D or L */ ( /* ---- input ---- */ double dj, /* diagonal entry of D for LDL' or L for LL' */ /* --------------- */ cholmod_common *Common ) ; double cholmod_l_dbound (double, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_hypot: compute sqrt (x*x + y*y) accurately */ /* -------------------------------------------------------------------------- */ double cholmod_hypot ( /* ---- input ---- */ double x, double y ) ; double cholmod_l_hypot (double, double) ; /* -------------------------------------------------------------------------- */ /* cholmod_divcomplex: complex division, c = a/b */ /* -------------------------------------------------------------------------- */ int cholmod_divcomplex /* return 1 if divide-by-zero, 0 otherise */ ( /* ---- input ---- */ double ar, double ai, /* real and imaginary parts of a */ double br, double bi, /* real and imaginary parts of b */ /* ---- output --- */ double *cr, double *ci /* real and imaginary parts of c */ ) ; int cholmod_l_divcomplex (double, double, double, double, double *, double *) ; /* ========================================================================== */ /* === Core/cholmod_sparse ================================================== */ /* ========================================================================== */ /* A sparse matrix stored in compressed-column form. */ typedef struct cholmod_sparse_struct { size_t nrow ; /* the matrix is nrow-by-ncol */ size_t ncol ; size_t nzmax ; /* maximum number of entries in the matrix */ /* pointers to int or UF_long: */ void *p ; /* p [0..ncol], the column pointers */ void *i ; /* i [0..nzmax-1], the row indices */ /* for unpacked matrices only: */ void *nz ; /* nz [0..ncol-1], the # of nonzeros in each col. In * packed form, the nonzero pattern of column j is in * A->i [A->p [j] ... A->p [j+1]-1]. In unpacked form, column j is in * A->i [A->p [j] ... A->p [j]+A->nz[j]-1] instead. In both cases, the * numerical values (if present) are in the corresponding locations in * the array x (or z if A->xtype is CHOLMOD_ZOMPLEX). */ /* pointers to double or float: */ void *x ; /* size nzmax or 2*nzmax, if present */ void *z ; /* size nzmax, if present */ int stype ; /* Describes what parts of the matrix are considered: * * 0: matrix is "unsymmetric": use both upper and lower triangular parts * (the matrix may actually be symmetric in pattern and value, but * both parts are explicitly stored and used). May be square or * rectangular. * >0: matrix is square and symmetric, use upper triangular part. * Entries in the lower triangular part are ignored. * <0: matrix is square and symmetric, use lower triangular part. * Entries in the upper triangular part are ignored. * * Note that stype>0 and stype<0 are different for cholmod_sparse and * cholmod_triplet. See the cholmod_triplet data structure for more * details. */ int itype ; /* CHOLMOD_INT: p, i, and nz are int. * CHOLMOD_INTLONG: p is UF_long, i and nz are int. * CHOLMOD_LONG: p, i, and nz are UF_long. */ int xtype ; /* pattern, real, complex, or zomplex */ int dtype ; /* x and z are double or float */ int sorted ; /* TRUE if columns are sorted, FALSE otherwise */ int packed ; /* TRUE if packed (nz ignored), FALSE if unpacked * (nz is required) */ } cholmod_sparse ; /* -------------------------------------------------------------------------- */ /* cholmod_allocate_sparse: allocate a sparse matrix */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_allocate_sparse ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ size_t nzmax, /* max # of nonzeros of A */ int sorted, /* TRUE if columns of A sorted, FALSE otherwise */ int packed, /* TRUE if A will be packed, FALSE otherwise */ int stype, /* stype of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_allocate_sparse (size_t, size_t, size_t, int, int, int, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_free_sparse: free a sparse matrix */ /* -------------------------------------------------------------------------- */ int cholmod_free_sparse ( /* ---- in/out --- */ cholmod_sparse **A, /* matrix to deallocate, NULL on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_free_sparse (cholmod_sparse **, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_reallocate_sparse: change the size (# entries) of sparse matrix */ /* -------------------------------------------------------------------------- */ int cholmod_reallocate_sparse ( /* ---- input ---- */ size_t nznew, /* new # of entries in A */ /* ---- in/out --- */ cholmod_sparse *A, /* matrix to reallocate */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_reallocate_sparse ( size_t, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_nnz: return number of nonzeros in a sparse matrix */ /* -------------------------------------------------------------------------- */ UF_long cholmod_nnz ( /* ---- input ---- */ cholmod_sparse *A, /* --------------- */ cholmod_common *Common ) ; UF_long cholmod_l_nnz (cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_speye: sparse identity matrix */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_speye ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_speye (size_t, size_t, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_spzeros: sparse zero matrix */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_spzeros ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ size_t nzmax, /* max # of nonzeros of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_spzeros (size_t, size_t, size_t, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_transpose: transpose a sparse matrix */ /* -------------------------------------------------------------------------- */ /* Return A' or A.' The "values" parameter is 0, 1, or 2 to denote the pattern * transpose, the array transpose (A.'), and the complex conjugate transpose * (A'). */ cholmod_sparse *cholmod_transpose ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_transpose_unsym: transpose an unsymmetric sparse matrix */ /* -------------------------------------------------------------------------- */ /* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is * already allocated. See cholmod_transpose for a simpler routine. */ int cholmod_transpose_unsym ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ int *Perm, /* size nrow, if present (can be NULL) */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ cholmod_sparse *F, /* F = A', A(:,f)', or A(p,f)' */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_transpose_unsym (cholmod_sparse *, int, UF_long *, UF_long *, size_t, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_transpose_sym: transpose a symmetric sparse matrix */ /* -------------------------------------------------------------------------- */ /* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated. * See cholmod_transpose for a simpler routine. */ int cholmod_transpose_sym ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ int *Perm, /* size nrow, if present (can be NULL) */ /* ---- output --- */ cholmod_sparse *F, /* F = A' or A(p,p)' */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_transpose_sym (cholmod_sparse *, int, UF_long *, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_ptranspose: transpose a sparse matrix */ /* -------------------------------------------------------------------------- */ /* Return A' or A(p,p)' if A is symmetric. Return A', A(:,f)', or A(p,f)' if * A is unsymmetric. */ cholmod_sparse *cholmod_ptranspose ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 0: pattern, 1: array transpose, 2: conj. transpose */ int *Perm, /* if non-NULL, F = A(p,f) or A(p,p) */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_ptranspose (cholmod_sparse *, int, UF_long *, UF_long *, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_sort: sort row indices in each column of sparse matrix */ /* -------------------------------------------------------------------------- */ int cholmod_sort ( /* ---- in/out --- */ cholmod_sparse *A, /* matrix to sort */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_sort (cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_band: C = tril (triu (A,k1), k2) */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_band ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to extract band matrix from */ UF_long k1, /* ignore entries below the k1-st diagonal */ UF_long k2, /* ignore entries above the k2-nd diagonal */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_band (cholmod_sparse *, UF_long, UF_long, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_band_inplace: A = tril (triu (A,k1), k2) */ /* -------------------------------------------------------------------------- */ int cholmod_band_inplace ( /* ---- input ---- */ UF_long k1, /* ignore entries below the k1-st diagonal */ UF_long k2, /* ignore entries above the k2-nd diagonal */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ /* ---- in/out --- */ cholmod_sparse *A, /* matrix from which entries not in band are removed */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_band_inplace (UF_long, UF_long, int, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_aat: C = A*A' or A(:,f)*A(:,f)' */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_aat ( /* ---- input ---- */ cholmod_sparse *A, /* input matrix; C=A*A' is constructed */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag), * -2: pattern only, no diagonal, add 50%+n extra * space to C */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_aat (cholmod_sparse *, UF_long *, size_t, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_copy_sparse: C = A, create an exact copy of a sparse matrix */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_copy_sparse ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_copy_sparse (cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_copy: C = A, with possible change of stype */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_copy ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ int stype, /* requested stype of C */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_copy (cholmod_sparse *, int, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_add: C = alpha*A + beta*B */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_add ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to add */ cholmod_sparse *B, /* matrix to add */ double alpha [2], /* scale factor for A */ double beta [2], /* scale factor for B */ int values, /* if TRUE compute the numerical values of C */ int sorted, /* if TRUE, sort columns of C */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_add (cholmod_sparse *, cholmod_sparse *, double *, double *, int, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_sparse_xtype: change the xtype of a sparse matrix */ /* -------------------------------------------------------------------------- */ int cholmod_sparse_xtype ( /* ---- input ---- */ int to_xtype, /* requested xtype (pattern, real, complex, zomplex) */ /* ---- in/out --- */ cholmod_sparse *A, /* sparse matrix to change */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_sparse_xtype (int, cholmod_sparse *, cholmod_common *) ; /* ========================================================================== */ /* === Core/cholmod_factor ================================================== */ /* ========================================================================== */ /* A symbolic and numeric factorization, either simplicial or supernodal. * In all cases, the row indices in the columns of L are kept sorted. */ typedef struct cholmod_factor_struct { /* ---------------------------------------------------------------------- */ /* for both simplicial and supernodal factorizations */ /* ---------------------------------------------------------------------- */ size_t n ; /* L is n-by-n */ size_t minor ; /* If the factorization failed, L->minor is the column * at which it failed (in the range 0 to n-1). A value * of n means the factorization was successful or * the matrix has not yet been factorized. */ /* ---------------------------------------------------------------------- */ /* symbolic ordering and analysis */ /* ---------------------------------------------------------------------- */ void *Perm ; /* size n, permutation used */ void *ColCount ; /* size n, column counts for simplicial L */ /* ---------------------------------------------------------------------- */ /* simplicial factorization */ /* ---------------------------------------------------------------------- */ size_t nzmax ; /* size of i and x */ void *p ; /* p [0..ncol], the column pointers */ void *i ; /* i [0..nzmax-1], the row indices */ void *x ; /* x [0..nzmax-1], the numerical values */ void *z ; void *nz ; /* nz [0..ncol-1], the # of nonzeros in each column. * i [p [j] ... p [j]+nz[j]-1] contains the row indices, * and the numerical values are in the same locatins * in x. The value of i [p [k]] is always k. */ void *next ; /* size ncol+2. next [j] is the next column in i/x */ void *prev ; /* size ncol+2. prev [j] is the prior column in i/x. * head of the list is ncol+1, and the tail is ncol. */ /* ---------------------------------------------------------------------- */ /* supernodal factorization */ /* ---------------------------------------------------------------------- */ /* Note that L->x is shared with the simplicial data structure. L->x has * size L->nzmax for a simplicial factor, and size L->xsize for a supernodal * factor. */ size_t nsuper ; /* number of supernodes */ size_t ssize ; /* size of s, integer part of supernodes */ size_t xsize ; /* size of x, real part of supernodes */ size_t maxcsize ; /* size of largest update matrix */ size_t maxesize ; /* max # of rows in supernodes, excl. triangular part */ void *super ; /* size nsuper+1, first col in each supernode */ void *pi ; /* size nsuper+1, pointers to integer patterns */ void *px ; /* size nsuper+1, pointers to real parts */ void *s ; /* size ssize, integer part of supernodes */ /* ---------------------------------------------------------------------- */ /* factorization type */ /* ---------------------------------------------------------------------- */ int ordering ; /* ordering method used */ int is_ll ; /* TRUE if LL', FALSE if LDL' */ int is_super ; /* TRUE if supernodal, FALSE if simplicial */ int is_monotonic ; /* TRUE if columns of L appear in order 0..n-1. * Only applicable to simplicial numeric types. */ /* There are 8 types of factor objects that cholmod_factor can represent * (only 6 are used): * * Numeric types (xtype is not CHOLMOD_PATTERN) * -------------------------------------------- * * simplicial LDL': (is_ll FALSE, is_super FALSE). Stored in compressed * column form, using the simplicial components above (nzmax, p, i, * x, z, nz, next, and prev). The unit diagonal of L is not stored, * and D is stored in its place. There are no supernodes. * * simplicial LL': (is_ll TRUE, is_super FALSE). Uses the same storage * scheme as the simplicial LDL', except that D does not appear. * The first entry of each column of L is the diagonal entry of * that column of L. * * supernodal LDL': (is_ll FALSE, is_super TRUE). Not used. * FUTURE WORK: add support for supernodal LDL' * * supernodal LL': (is_ll TRUE, is_super TRUE). A supernodal factor, * using the supernodal components described above (nsuper, ssize, * xsize, maxcsize, maxesize, super, pi, px, s, x, and z). * * * Symbolic types (xtype is CHOLMOD_PATTERN) * ----------------------------------------- * * simplicial LDL': (is_ll FALSE, is_super FALSE). Nothing is present * except Perm and ColCount. * * simplicial LL': (is_ll TRUE, is_super FALSE). Identical to the * simplicial LDL', except for the is_ll flag. * * supernodal LDL': (is_ll FALSE, is_super TRUE). Not used. * FUTURE WORK: add support for supernodal LDL' * * supernodal LL': (is_ll TRUE, is_super TRUE). A supernodal symbolic * factorization. The simplicial symbolic information is present * (Perm and ColCount), as is all of the supernodal factorization * except for the numerical values (x and z). */ int itype ; /* The integer arrays are Perm, ColCount, p, i, nz, * next, prev, super, pi, px, and s. If itype is * CHOLMOD_INT, all of these are int arrays. * CHOLMOD_INTLONG: p, pi, px are UF_long, others int. * CHOLMOD_LONG: all integer arrays are UF_long. */ int xtype ; /* pattern, real, complex, or zomplex */ int dtype ; /* x and z double or float */ } cholmod_factor ; /* -------------------------------------------------------------------------- */ /* cholmod_allocate_factor: allocate a factor (symbolic LL' or LDL') */ /* -------------------------------------------------------------------------- */ cholmod_factor *cholmod_allocate_factor ( /* ---- input ---- */ size_t n, /* L is n-by-n */ /* --------------- */ cholmod_common *Common ) ; cholmod_factor *cholmod_l_allocate_factor (size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_free_factor: free a factor */ /* -------------------------------------------------------------------------- */ int cholmod_free_factor ( /* ---- in/out --- */ cholmod_factor **L, /* factor to free, NULL on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_free_factor (cholmod_factor **, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_reallocate_factor: change the # entries in a factor */ /* -------------------------------------------------------------------------- */ int cholmod_reallocate_factor ( /* ---- input ---- */ size_t nznew, /* new # of entries in L */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_reallocate_factor (size_t, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_change_factor: change the type of factor (e.g., LDL' to LL') */ /* -------------------------------------------------------------------------- */ int cholmod_change_factor ( /* ---- input ---- */ int to_xtype, /* to CHOLMOD_PATTERN, _REAL, _COMPLEX, _ZOMPLEX */ int to_ll, /* TRUE: convert to LL', FALSE: LDL' */ int to_super, /* TRUE: convert to supernodal, FALSE: simplicial */ int to_packed, /* TRUE: pack simplicial columns, FALSE: do not pack */ int to_monotonic, /* TRUE: put simplicial columns in order, FALSE: not */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_change_factor ( int, int, int, int, int, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_pack_factor: pack the columns of a factor */ /* -------------------------------------------------------------------------- */ /* Pack the columns of a simplicial factor. Unlike cholmod_change_factor, * it can pack the columns of a factor even if they are not stored in their * natural order (non-monotonic). */ int cholmod_pack_factor ( /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_pack_factor (cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_reallocate_column: resize a single column of a factor */ /* -------------------------------------------------------------------------- */ int cholmod_reallocate_column ( /* ---- input ---- */ size_t j, /* the column to reallocate */ size_t need, /* required size of column j */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_reallocate_column (size_t, size_t, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_factor_to_sparse: create a sparse matrix copy of a factor */ /* -------------------------------------------------------------------------- */ /* Only operates on numeric factors, not symbolic ones */ cholmod_sparse *cholmod_factor_to_sparse ( /* ---- in/out --- */ cholmod_factor *L, /* factor to copy, converted to symbolic on output */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_factor_to_sparse (cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_copy_factor: create a copy of a factor */ /* -------------------------------------------------------------------------- */ cholmod_factor *cholmod_copy_factor ( /* ---- input ---- */ cholmod_factor *L, /* factor to copy */ /* --------------- */ cholmod_common *Common ) ; cholmod_factor *cholmod_l_copy_factor (cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_factor_xtype: change the xtype of a factor */ /* -------------------------------------------------------------------------- */ int cholmod_factor_xtype ( /* ---- input ---- */ int to_xtype, /* requested xtype (real, complex, or zomplex) */ /* ---- in/out --- */ cholmod_factor *L, /* factor to change */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_factor_xtype (int, cholmod_factor *, cholmod_common *) ; /* ========================================================================== */ /* === Core/cholmod_dense =================================================== */ /* ========================================================================== */ /* A dense matrix in column-oriented form. It has no itype since it contains * no integers. Entry in row i and column j is located in x [i+j*d]. */ typedef struct cholmod_dense_struct { size_t nrow ; /* the matrix is nrow-by-ncol */ size_t ncol ; size_t nzmax ; /* maximum number of entries in the matrix */ size_t d ; /* leading dimension (d >= nrow must hold) */ void *x ; /* size nzmax or 2*nzmax, if present */ void *z ; /* size nzmax, if present */ int xtype ; /* pattern, real, complex, or zomplex */ int dtype ; /* x and z double or float */ } cholmod_dense ; /* -------------------------------------------------------------------------- */ /* cholmod_allocate_dense: allocate a dense matrix (contents uninitialized) */ /* -------------------------------------------------------------------------- */ cholmod_dense *cholmod_allocate_dense ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ size_t d, /* leading dimension */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_allocate_dense (size_t, size_t, size_t, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_zeros: allocate a dense matrix and set it to zero */ /* -------------------------------------------------------------------------- */ cholmod_dense *cholmod_zeros ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_zeros (size_t, size_t, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_ones: allocate a dense matrix and set it to all ones */ /* -------------------------------------------------------------------------- */ cholmod_dense *cholmod_ones ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_ones (size_t, size_t, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_eye: allocate a dense matrix and set it to the identity matrix */ /* -------------------------------------------------------------------------- */ cholmod_dense *cholmod_eye ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_eye (size_t, size_t, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_free_dense: free a dense matrix */ /* -------------------------------------------------------------------------- */ int cholmod_free_dense ( /* ---- in/out --- */ cholmod_dense **X, /* dense matrix to deallocate, NULL on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_free_dense (cholmod_dense **, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_sparse_to_dense: create a dense matrix copy of a sparse matrix */ /* -------------------------------------------------------------------------- */ cholmod_dense *cholmod_sparse_to_dense ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_sparse_to_dense (cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_dense_to_sparse: create a sparse matrix copy of a dense matrix */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_dense_to_sparse ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ int values, /* TRUE if values to be copied, FALSE otherwise */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_copy_dense: create a copy of a dense matrix */ /* -------------------------------------------------------------------------- */ cholmod_dense *cholmod_copy_dense ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_copy_dense (cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_copy_dense2: copy a dense matrix (pre-allocated) */ /* -------------------------------------------------------------------------- */ int cholmod_copy_dense2 ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ /* ---- output --- */ cholmod_dense *Y, /* copy of matrix X */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_copy_dense2 (cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_dense_xtype: change the xtype of a dense matrix */ /* -------------------------------------------------------------------------- */ int cholmod_dense_xtype ( /* ---- input ---- */ int to_xtype, /* requested xtype (real, complex,or zomplex) */ /* ---- in/out --- */ cholmod_dense *X, /* dense matrix to change */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_dense_xtype (int, cholmod_dense *, cholmod_common *) ; /* ========================================================================== */ /* === Core/cholmod_triplet ================================================= */ /* ========================================================================== */ /* A sparse matrix stored in triplet form. */ typedef struct cholmod_triplet_struct { size_t nrow ; /* the matrix is nrow-by-ncol */ size_t ncol ; size_t nzmax ; /* maximum number of entries in the matrix */ size_t nnz ; /* number of nonzeros in the matrix */ void *i ; /* i [0..nzmax-1], the row indices */ void *j ; /* j [0..nzmax-1], the column indices */ void *x ; /* size nzmax or 2*nzmax, if present */ void *z ; /* size nzmax, if present */ int stype ; /* Describes what parts of the matrix are considered: * * 0: matrix is "unsymmetric": use both upper and lower triangular parts * (the matrix may actually be symmetric in pattern and value, but * both parts are explicitly stored and used). May be square or * rectangular. * >0: matrix is square and symmetric. Entries in the lower triangular * part are transposed and added to the upper triangular part when * the matrix is converted to cholmod_sparse form. * <0: matrix is square and symmetric. Entries in the upper triangular * part are transposed and added to the lower triangular part when * the matrix is converted to cholmod_sparse form. * * Note that stype>0 and stype<0 are different for cholmod_sparse and * cholmod_triplet. The reason is simple. You can permute a symmetric * triplet matrix by simply replacing a row and column index with their * new row and column indices, via an inverse permutation. Suppose * P = L->Perm is your permutation, and Pinv is an array of size n. * Suppose a symmetric matrix A is represent by a triplet matrix T, with * entries only in the upper triangular part. Then the following code: * * Ti = T->i ; * Tj = T->j ; * for (k = 0 ; k < n ; k++) Pinv [P [k]] = k ; * for (k = 0 ; k < nz ; k++) Ti [k] = Pinv [Ti [k]] ; * for (k = 0 ; k < nz ; k++) Tj [k] = Pinv [Tj [k]] ; * * creates the triplet form of C=P*A*P'. However, if T initially * contains just the upper triangular entries (T->stype = 1), after * permutation it has entries in both the upper and lower triangular * parts. These entries should be transposed when constructing the * cholmod_sparse form of A, which is what cholmod_triplet_to_sparse * does. Thus: * * C = cholmod_triplet_to_sparse (T, 0, &Common) ; * * will return the matrix C = P*A*P'. * * Since the triplet matrix T is so simple to generate, it's quite easy * to remove entries that you do not want, prior to converting T to the * cholmod_sparse form. So if you include these entries in T, CHOLMOD * assumes that there must be a reason (such as the one above). Thus, * no entry in a triplet matrix is ever ignored. */ int itype ; /* CHOLMOD_LONG: i and j are UF_long. Otherwise int. */ int xtype ; /* pattern, real, complex, or zomplex */ int dtype ; /* x and z are double or float */ } cholmod_triplet ; /* -------------------------------------------------------------------------- */ /* cholmod_allocate_triplet: allocate a triplet matrix */ /* -------------------------------------------------------------------------- */ cholmod_triplet *cholmod_allocate_triplet ( /* ---- input ---- */ size_t nrow, /* # of rows of T */ size_t ncol, /* # of columns of T */ size_t nzmax, /* max # of nonzeros of T */ int stype, /* stype of T */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) ; cholmod_triplet *cholmod_l_allocate_triplet (size_t, size_t, size_t, int, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_free_triplet: free a triplet matrix */ /* -------------------------------------------------------------------------- */ int cholmod_free_triplet ( /* ---- in/out --- */ cholmod_triplet **T, /* triplet matrix to deallocate, NULL on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_free_triplet (cholmod_triplet **, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_reallocate_triplet: change the # of entries in a triplet matrix */ /* -------------------------------------------------------------------------- */ int cholmod_reallocate_triplet ( /* ---- input ---- */ size_t nznew, /* new # of entries in T */ /* ---- in/out --- */ cholmod_triplet *T, /* triplet matrix to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_reallocate_triplet (size_t, cholmod_triplet *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_sparse_to_triplet: create a triplet matrix copy of a sparse matrix*/ /* -------------------------------------------------------------------------- */ cholmod_triplet *cholmod_sparse_to_triplet ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) ; cholmod_triplet *cholmod_l_sparse_to_triplet (cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_triplet_to_sparse: create a sparse matrix copy of a triplet matrix*/ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_triplet_to_sparse ( /* ---- input ---- */ cholmod_triplet *T, /* matrix to copy */ size_t nzmax, /* allocate at least this much space in output matrix */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_triplet_to_sparse (cholmod_triplet *, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_copy_triplet: create a copy of a triplet matrix */ /* -------------------------------------------------------------------------- */ cholmod_triplet *cholmod_copy_triplet ( /* ---- input ---- */ cholmod_triplet *T, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) ; cholmod_triplet *cholmod_l_copy_triplet (cholmod_triplet *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_triplet_xtype: change the xtype of a triplet matrix */ /* -------------------------------------------------------------------------- */ int cholmod_triplet_xtype ( /* ---- input ---- */ int to_xtype, /* requested xtype (pattern, real, complex,or zomplex)*/ /* ---- in/out --- */ cholmod_triplet *T, /* triplet matrix to change */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ; /* ========================================================================== */ /* === Core/cholmod_memory ================================================== */ /* ========================================================================== */ /* The user may make use of these, just like malloc and free. You can even * malloc an object and safely free it with cholmod_free, and visa versa * (except that the memory usage statistics will be corrupted). These routines * do differ from malloc and free. If cholmod_free is given a NULL pointer, * for example, it does nothing (unlike the ANSI free). cholmod_realloc does * not return NULL if given a non-NULL pointer and a nonzero size, even if it * fails (it returns the original pointer and sets an error code in * Common->status instead). * * CHOLMOD keeps track of the amount of memory it has allocated, and so the * cholmod_free routine also takes the size of the object being freed. This * is only used for statistics. If you, the user of CHOLMOD, pass the wrong * size, the only consequence is that the memory usage statistics will be * corrupted. */ void *cholmod_malloc /* returns pointer to the newly malloc'd block */ ( /* ---- input ---- */ size_t n, /* number of items */ size_t size, /* size of each item */ /* --------------- */ cholmod_common *Common ) ; void *cholmod_l_malloc (size_t, size_t, cholmod_common *) ; void *cholmod_calloc /* returns pointer to the newly calloc'd block */ ( /* ---- input ---- */ size_t n, /* number of items */ size_t size, /* size of each item */ /* --------------- */ cholmod_common *Common ) ; void *cholmod_l_calloc (size_t, size_t, cholmod_common *) ; void *cholmod_free /* always returns NULL */ ( /* ---- input ---- */ size_t n, /* number of items */ size_t size, /* size of each item */ /* ---- in/out --- */ void *p, /* block of memory to free */ /* --------------- */ cholmod_common *Common ) ; void *cholmod_l_free (size_t, size_t, void *, cholmod_common *) ; void *cholmod_realloc /* returns pointer to reallocated block */ ( /* ---- input ---- */ size_t nnew, /* requested # of items in reallocated block */ size_t size, /* size of each item */ /* ---- in/out --- */ void *p, /* block of memory to realloc */ size_t *n, /* current size on input, nnew on output if successful*/ /* --------------- */ cholmod_common *Common ) ; void *cholmod_l_realloc (size_t, size_t, void *, size_t *, cholmod_common *) ; int cholmod_realloc_multiple ( /* ---- input ---- */ size_t nnew, /* requested # of items in reallocated blocks */ int nint, /* number of int/UF_long blocks */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* ---- in/out --- */ void **I, /* int or UF_long block */ void **J, /* int or UF_long block */ void **X, /* complex, double, or float block */ void **Z, /* zomplex case only: double or float block */ size_t *n, /* current size of the I,J,X,Z blocks on input, * nnew on output if successful */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **, void **, size_t *, cholmod_common *) ; /* ========================================================================== */ /* === symmetry types ======================================================= */ /* ========================================================================== */ #define CHOLMOD_MM_RECTANGULAR 1 #define CHOLMOD_MM_UNSYMMETRIC 2 #define CHOLMOD_MM_SYMMETRIC 3 #define CHOLMOD_MM_HERMITIAN 4 #define CHOLMOD_MM_SKEW_SYMMETRIC 5 #define CHOLMOD_MM_SYMMETRIC_POSDIAG 6 #define CHOLMOD_MM_HERMITIAN_POSDIAG 7 /* ========================================================================== */ /* === Numerical relop macros =============================================== */ /* ========================================================================== */ /* These macros correctly handle the NaN case. * * CHOLMOD_IS_NAN(x): * True if x is NaN. False otherwise. The commonly-existing isnan(x) * function could be used, but it's not in Kernighan & Ritchie 2nd edition * (ANSI C89). It may appear in , but I'm not certain about * portability. The expression x != x is true if and only if x is NaN, * according to the IEEE 754 floating-point standard. * * CHOLMOD_IS_ZERO(x): * True if x is zero. False if x is nonzero, NaN, or +/- Inf. * This is (x == 0) if the compiler is IEEE 754 compliant. * * CHOLMOD_IS_NONZERO(x): * True if x is nonzero, NaN, or +/- Inf. False if x zero. * This is (x != 0) if the compiler is IEEE 754 compliant. * * CHOLMOD_IS_LT_ZERO(x): * True if x is < zero or -Inf. False if x is >= 0, NaN, or +Inf. * This is (x < 0) if the compiler is IEEE 754 compliant. * * CHOLMOD_IS_GT_ZERO(x): * True if x is > zero or +Inf. False if x is <= 0, NaN, or -Inf. * This is (x > 0) if the compiler is IEEE 754 compliant. * * CHOLMOD_IS_LE_ZERO(x): * True if x is <= zero or -Inf. False if x is > 0, NaN, or +Inf. * This is (x <= 0) if the compiler is IEEE 754 compliant. */ #ifdef CHOLMOD_WINDOWS /* Yes, this is exceedingly ugly. Blame Microsoft, which hopelessly */ /* violates the IEEE 754 floating-point standard in a bizarre way. */ /* If you're using an IEEE 754-compliant compiler, then x != x is true */ /* iff x is NaN. For Microsoft, (x < x) is true iff x is NaN. */ /* So either way, this macro safely detects a NaN. */ #define CHOLMOD_IS_NAN(x) (((x) != (x)) || (((x) < (x)))) #define CHOLMOD_IS_ZERO(x) (((x) == 0.) && !CHOLMOD_IS_NAN(x)) #define CHOLMOD_IS_NONZERO(x) (((x) != 0.) || CHOLMOD_IS_NAN(x)) #define CHOLMOD_IS_LT_ZERO(x) (((x) < 0.) && !CHOLMOD_IS_NAN(x)) #define CHOLMOD_IS_GT_ZERO(x) (((x) > 0.) && !CHOLMOD_IS_NAN(x)) #define CHOLMOD_IS_LE_ZERO(x) (((x) <= 0.) && !CHOLMOD_IS_NAN(x)) #else /* These all work properly, according to the IEEE 754 standard ... except on */ /* a PC with windows. Works fine in Linux on the same PC... */ #define CHOLMOD_IS_NAN(x) ((x) != (x)) #define CHOLMOD_IS_ZERO(x) ((x) == 0.) #define CHOLMOD_IS_NONZERO(x) ((x) != 0.) #define CHOLMOD_IS_LT_ZERO(x) ((x) < 0.) #define CHOLMOD_IS_GT_ZERO(x) ((x) > 0.) #define CHOLMOD_IS_LE_ZERO(x) ((x) <= 0.) #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/README.txt0000644000175000017500000000235111674452555021473 0ustar sonnesonneCHOLMOD: a sparse Cholesky factorization package. The Include/*.h files in this directory provide a basic documentation of all user-callable routines and user-visible data structures in the CHOLMOD package. Start with cholmod.h, which describes the general structure of the parameter lists of CHOLMOD routines. cholmod_core.h describes the data structures and basic operations on them (creating and deleting them). cholmod.h single include file for all user programs cholmod_config.h CHOLMOD compile-time configuration cholmod_core.h Core module: data structures and basic support routines cholmod_check.h Check module: check/print CHOLMOD data structures cholmod_cholesky.h Cholesky module: LL' and LDL' factorization cholmod_matrixops.h MatrixOps module: sparse matrix operators (add, mult,..) cholmod_modify.h Modify module: update/downdate/... cholmod_partition.h Partition module: nested dissection ordering cholmod_supernodal.h Supernodal module: supernodal Cholesky These include files are not used in user programs, but in CHOLMOD only: cholmod_blas.h BLAS definitions cholmod_complexity.h complex arithmetic cholmod_template.h complex arithmetic for template routines cholmod_internal.h internal definitions, not visible to user program cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_blas.h0000644000175000017500000003406311674452555022601 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_blas.h =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_blas.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod_blas.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* This does not need to be included in the user's program. */ #ifndef CHOLMOD_BLAS_H #define CHOLMOD_BLAS_H /* ========================================================================== */ /* === Architecture ========================================================= */ /* ========================================================================== */ #if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2) #define CHOLMOD_SOL2 #define CHOLMOD_ARCHITECTURE "Sun Solaris" #elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI) #define CHOLMOD_SGI #define CHOLMOD_ARCHITECTURE "SGI Irix" #elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86) #define CHOLMOD_LINUX #define CHOLMOD_ARCHITECTURE "Linux" #elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS) #define CHOLMOD_AIX #define CHOLMOD_ARCHITECTURE "IBM AIX" /* recent reports from IBM AIX seem to indicate that this is not needed: */ /* #define BLAS_NO_UNDERSCORE */ #elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA) #define CHOLMOD_ALPHA #define CHOLMOD_ARCHITECTURE "Compaq Alpha" #elif defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64) #if defined (__MINGW32__) || defined (__MINGW32__) #define CHOLMOD_MINGW #elif defined (__CYGWIN32__) || defined (__CYGWIN32__) #define CHOLMOD_CYGWIN #else #define CHOLMOD_WINDOWS #define BLAS_NO_UNDERSCORE #endif #define CHOLMOD_ARCHITECTURE "Microsoft Windows" #elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX) #define CHOLMOD_HP #define CHOLMOD_ARCHITECTURE "HP Unix" #define BLAS_NO_UNDERSCORE #elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700) #define CHOLMOD_HP #define CHOLMOD_ARCHITECTURE "HP 700 Unix" #define BLAS_NO_UNDERSCORE #else /* If the architecture is unknown, and you call the BLAS, you may need to */ /* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */ #define CHOLMOD_ARCHITECTURE "unknown" #endif /* ========================================================================== */ /* === BLAS and LAPACK names ================================================ */ /* ========================================================================== */ /* Prototypes for the various versions of the BLAS. */ /* Determine if the 64-bit Sun Performance BLAS is to be used */ #if defined(CHOLMOD_SOL2) && !defined(NSUNPERF) && defined(LONG) && defined(LONGBLAS) #define SUN64 #endif #ifdef SUN64 #define BLAS_DTRSV dtrsv_64_ #define BLAS_DGEMV dgemv_64_ #define BLAS_DTRSM dtrsm_64_ #define BLAS_DGEMM dgemm_64_ #define BLAS_DSYRK dsyrk_64_ #define BLAS_DGER dger_64_ #define BLAS_DSCAL dscal_64_ #define LAPACK_DPOTRF dpotrf_64_ #define BLAS_ZTRSV ztrsv_64_ #define BLAS_ZGEMV zgemv_64_ #define BLAS_ZTRSM ztrsm_64_ #define BLAS_ZGEMM zgemm_64_ #define BLAS_ZHERK zherk_64_ #define BLAS_ZGER zgeru_64_ #define BLAS_ZSCAL zscal_64_ #define LAPACK_ZPOTRF zpotrf_64_ #elif defined (BLAS_NO_UNDERSCORE) #define BLAS_DTRSV dtrsv #define BLAS_DGEMV dgemv #define BLAS_DTRSM dtrsm #define BLAS_DGEMM dgemm #define BLAS_DSYRK dsyrk #define BLAS_DGER dger #define BLAS_DSCAL dscal #define LAPACK_DPOTRF dpotrf #define BLAS_ZTRSV ztrsv #define BLAS_ZGEMV zgemv #define BLAS_ZTRSM ztrsm #define BLAS_ZGEMM zgemm #define BLAS_ZHERK zherk #define BLAS_ZGER zgeru #define BLAS_ZSCAL zscal #define LAPACK_ZPOTRF zpotrf #else #define BLAS_DTRSV dtrsv_ #define BLAS_DGEMV dgemv_ #define BLAS_DTRSM dtrsm_ #define BLAS_DGEMM dgemm_ #define BLAS_DSYRK dsyrk_ #define BLAS_DGER dger_ #define BLAS_DSCAL dscal_ #define LAPACK_DPOTRF dpotrf_ #define BLAS_ZTRSV ztrsv_ #define BLAS_ZGEMV zgemv_ #define BLAS_ZTRSM ztrsm_ #define BLAS_ZGEMM zgemm_ #define BLAS_ZHERK zherk_ #define BLAS_ZGER zgeru_ #define BLAS_ZSCAL zscal_ #define LAPACK_ZPOTRF zpotrf_ #endif /* ========================================================================== */ /* === BLAS and LAPACK integer arguments ==================================== */ /* ========================================================================== */ /* CHOLMOD can be compiled with -D'LONGBLAS=long' for the Sun Performance * Library, or -D'LONGBLAS=long long' for SGI's SCSL BLAS. This defines the * integer used in the BLAS for the cholmod_l_* routines. * * The "int" version of CHOLMOD always uses the "int" version of the BLAS. */ #if defined (LONGBLAS) && defined (LONG) #define BLAS_INT LONGBLAS #else #define BLAS_INT int #endif /* If the BLAS integer is smaller than the basic CHOLMOD integer, then we need * to check for integer overflow when converting from Int to BLAS_INT. If * any integer overflows, the externally-defined Common->blas_ok variable is * set to FALSE. Common->blas_ok should be set to TRUE before calling any * BLAS_* macro. */ #define CHECK_BLAS_INT (sizeof (BLAS_INT) < sizeof (Int)) #define EQ(K,k) (((BLAS_INT) K) == ((Int) k)) /* ========================================================================== */ /* === BLAS and LAPACK prototypes and macros ================================ */ /* ========================================================================== */ void BLAS_DGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta, double *Y, BLAS_INT *incy) ; #define BLAS_dgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ EQ (INCX,incx) && EQ (INCY,incy))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_DGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \ } \ } void BLAS_ZGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta, double *Y, BLAS_INT *incy) ; #define BLAS_zgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ EQ (INCX,incx) && EQ (INCY,incy))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_ZGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \ } \ } void BLAS_DTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx) ; #define BLAS_dtrsv(uplo,trans,diag,n,A,lda,X,incx) \ { \ BLAS_INT N = n, LDA = lda, INCX = incx ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_DTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \ } \ } void BLAS_ZTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A, BLAS_INT *lda, double *X, BLAS_INT *incx) ; #define BLAS_ztrsv(uplo,trans,diag,n,A,lda,X,incx) \ { \ BLAS_INT N = n, LDA = lda, INCX = incx ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_ZTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \ } \ } void BLAS_DTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb) ; #define BLAS_dtrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \ { \ BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ EQ (LDB,ldb))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_DTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\ } \ } void BLAS_ZTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m, BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb) ; #define BLAS_ztrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \ { \ BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ EQ (LDB,ldb))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_ZTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\ } \ } void BLAS_DGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_dgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \ { \ BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (K,k) && \ EQ (LDA,lda) && EQ (LDB,ldb) && EQ (LDC,ldc))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_DGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \ C, &LDC) ; \ } \ } void BLAS_ZGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B, BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \ { \ BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (K,k) && \ EQ (LDA,lda) && EQ (LDB,ldb) && EQ (LDC,ldc))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_ZGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \ C, &LDC) ; \ } \ } void BLAS_DSYRK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \ { \ BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && \ EQ (LDC,ldc))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_DSYRK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \ } \ } \ void BLAS_ZHERK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *beta, double *C, BLAS_INT *ldc) ; #define BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \ { \ BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && \ EQ (LDC,ldc))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_ZHERK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \ } \ } \ void LAPACK_DPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda, BLAS_INT *info) ; #define LAPACK_dpotrf(uplo,n,A,lda,info) \ { \ BLAS_INT N = n, LDA = lda, INFO = 1 ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ LAPACK_DPOTRF (uplo, &N, A, &LDA, &INFO) ; \ } \ info = INFO ; \ } void LAPACK_ZPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda, BLAS_INT *info) ; #define LAPACK_zpotrf(uplo,n,A,lda,info) \ { \ BLAS_INT N = n, LDA = lda, INFO = 1 ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ LAPACK_ZPOTRF (uplo, &N, A, &LDA, &INFO) ; \ } \ info = INFO ; \ } /* ========================================================================== */ void BLAS_DSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ; #define BLAS_dscal(n,alpha,Y,incy) \ { \ BLAS_INT N = n, INCY = incy ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (INCY,incy))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_DSCAL (&N, alpha, Y, &INCY) ; \ } \ } void BLAS_ZSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ; #define BLAS_zscal(n,alpha,Y,incy) \ { \ BLAS_INT N = n, INCY = incy ; \ if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (INCY,incy))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_ZSCAL (&N, alpha, Y, &INCY) ; \ } \ } void BLAS_DGER (BLAS_INT *m, BLAS_INT *n, double *alpha, double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy, double *A, BLAS_INT *lda) ; #define BLAS_dger(m,n,alpha,X,incx,Y,incy,A,lda) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ EQ (INCX,incx) && EQ (INCY,incy))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_DGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \ } \ } void BLAS_ZGER (BLAS_INT *m, BLAS_INT *n, double *alpha, double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy, double *A, BLAS_INT *lda) ; #define BLAS_zgeru(m,n,alpha,X,incx,Y,incy,A,lda) \ { \ BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \ if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \ EQ (INCX,incx) && EQ (INCY,incy))) \ { \ Common->blas_ok = FALSE ; \ } \ if (!CHECK_BLAS_INT || Common->blas_ok) \ { \ BLAS_ZGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \ } \ } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_matrixops.h0000644000175000017500000002063611674452555023707 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_matrixops.h ========================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_matrixops.h. * Copyright (C) 2005-2006, Timothy A. Davis * CHOLMOD/Include/cholmod_matrixops.h is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD MatrixOps module. * * Basic operations on sparse and dense matrices. * * cholmod_drop A = entries in A with abs. value >= tol * cholmod_norm_dense s = norm (X), 1-norm, inf-norm, or 2-norm * cholmod_norm_sparse s = norm (A), 1-norm or inf-norm * cholmod_horzcat C = [A,B] * cholmod_scale A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) * cholmod_sdmult Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y * cholmod_ssmult C = A*B * cholmod_submatrix C = A (i,j), where i and j are arbitrary vectors * cholmod_vertcat C = [A ; B] * * A, B, C: sparse matrices (cholmod_sparse) * X, Y: dense matrices (cholmod_dense) * s: scalar or vector * * Requires the Core module. Not required by any other CHOLMOD module. */ #ifndef CHOLMOD_MATRIXOPS_H #define CHOLMOD_MATRIXOPS_H #include "cholmod_core.h" /* -------------------------------------------------------------------------- */ /* cholmod_drop: drop entries with small absolute value */ /* -------------------------------------------------------------------------- */ int cholmod_drop ( /* ---- input ---- */ double tol, /* keep entries with absolute value > tol */ /* ---- in/out --- */ cholmod_sparse *A, /* matrix to drop entries from */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_drop (double, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_norm_dense: s = norm (X), 1-norm, inf-norm, or 2-norm */ /* -------------------------------------------------------------------------- */ double cholmod_norm_dense ( /* ---- input ---- */ cholmod_dense *X, /* matrix to compute the norm of */ int norm, /* type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm */ /* --------------- */ cholmod_common *Common ) ; double cholmod_l_norm_dense (cholmod_dense *, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_norm_sparse: s = norm (A), 1-norm or inf-norm */ /* -------------------------------------------------------------------------- */ double cholmod_norm_sparse ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to compute the norm of */ int norm, /* type of norm: 0: inf. norm, 1: 1-norm */ /* --------------- */ cholmod_common *Common ) ; double cholmod_l_norm_sparse (cholmod_sparse *, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_horzcat: C = [A,B] */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_horzcat ( /* ---- input ---- */ cholmod_sparse *A, /* left matrix to concatenate */ cholmod_sparse *B, /* right matrix to concatenate */ int values, /* if TRUE compute the numerical values of C */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_horzcat (cholmod_sparse *, cholmod_sparse *, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_scale: A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) */ /* -------------------------------------------------------------------------- */ /* scaling modes, selected by the scale input parameter: */ #define CHOLMOD_SCALAR 0 /* A = s*A */ #define CHOLMOD_ROW 1 /* A = diag(s)*A */ #define CHOLMOD_COL 2 /* A = A*diag(s) */ #define CHOLMOD_SYM 3 /* A = diag(s)*A*diag(s) */ int cholmod_scale ( /* ---- input ---- */ cholmod_dense *S, /* scale factors (scalar or vector) */ int scale, /* type of scaling to compute */ /* ---- in/out --- */ cholmod_sparse *A, /* matrix to scale */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_scale (cholmod_dense *, int, cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_sdmult: Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y */ /* -------------------------------------------------------------------------- */ /* Sparse matrix times dense matrix */ int cholmod_sdmult ( /* ---- input ---- */ cholmod_sparse *A, /* sparse matrix to multiply */ int transpose, /* use A if 0, or A' otherwise */ double alpha [2], /* scale factor for A */ double beta [2], /* scale factor for Y */ cholmod_dense *X, /* dense matrix to multiply */ /* ---- in/out --- */ cholmod_dense *Y, /* resulting dense matrix */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_sdmult (cholmod_sparse *, int, double *, double *, cholmod_dense *, cholmod_dense *Y, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_ssmult: C = A*B */ /* -------------------------------------------------------------------------- */ /* Sparse matrix times sparse matrix */ cholmod_sparse *cholmod_ssmult ( /* ---- input ---- */ cholmod_sparse *A, /* left matrix to multiply */ cholmod_sparse *B, /* right matrix to multiply */ int stype, /* requested stype of C */ int values, /* TRUE: do numerical values, FALSE: pattern only */ int sorted, /* if TRUE then return C with sorted columns */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_ssmult (cholmod_sparse *, cholmod_sparse *, int, int, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_submatrix: C = A (r,c), where i and j are arbitrary vectors */ /* -------------------------------------------------------------------------- */ /* rsize < 0 denotes ":" in MATLAB notation, or more precisely 0:(A->nrow)-1. * In this case, r can be NULL. An rsize of zero, or r = NULL and rsize >= 0, * denotes "[ ]" in MATLAB notation (the empty set). * Similar rules hold for csize. */ cholmod_sparse *cholmod_submatrix ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to subreference */ int *rset, /* set of row indices, duplicates OK */ UF_long rsize, /* size of r; rsize < 0 denotes ":" */ int *cset, /* set of column indices, duplicates OK */ UF_long csize, /* size of c; csize < 0 denotes ":" */ int values, /* if TRUE compute the numerical values of C */ int sorted, /* if TRUE then return C with sorted columns */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_submatrix (cholmod_sparse *, UF_long *, UF_long, UF_long *, UF_long, int, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_vertcat: C = [A ; B] */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_vertcat ( /* ---- input ---- */ cholmod_sparse *A, /* left matrix to concatenate */ cholmod_sparse *B, /* right matrix to concatenate */ int values, /* if TRUE compute the numerical values of C */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_vertcat (cholmod_sparse *, cholmod_sparse *, int, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_symmetry: determine if a sparse matrix is symmetric */ /* -------------------------------------------------------------------------- */ int cholmod_symmetry ( /* ---- input ---- */ cholmod_sparse *A, int option, /* ---- output ---- */ int *xmatched, int *pmatched, int *nzoffdiag, int *nzdiag, /* --------------- */ cholmod_common *Common ) ; int cholmod_l_symmetry (cholmod_sparse *, int, UF_long *, UF_long *, UF_long *, UF_long *, cholmod_common *) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_check.h0000644000175000017500000003453511674452555022741 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_check.h ============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_check.h. Copyright (C) 2005-2006, Timothy A. Davis * CHOLMOD/Include/cholmod_check.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD Check module. * * Routines that check and print the 5 basic data types in CHOLMOD, and 3 kinds * of integer vectors (subset, perm, and parent), and read in matrices from a * file: * * cholmod_check_common check/print the Common object * cholmod_print_common * * cholmod_check_sparse check/print a sparse matrix in column-oriented form * cholmod_print_sparse * * cholmod_check_dense check/print a dense matrix * cholmod_print_dense * * cholmod_check_factor check/print a Cholesky factorization * cholmod_print_factor * * cholmod_check_triplet check/print a sparse matrix in triplet form * cholmod_print_triplet * * cholmod_check_subset check/print a subset (integer vector in given range) * cholmod_print_subset * * cholmod_check_perm check/print a permutation (an integer vector) * cholmod_print_perm * * cholmod_check_parent check/print an elimination tree (an integer vector) * cholmod_print_parent * * cholmod_read_triplet read a matrix in triplet form (any Matrix Market * "coordinate" format, or a generic triplet format). * * cholmod_read_sparse read a matrix in sparse form (same file format as * cholmod_read_triplet). * * cholmod_read_dense read a dense matrix (any Matrix Market "array" * format, or a generic dense format). * * cholmod_write_sparse write a sparse matrix to a Matrix Market file. * * cholmod_write_dense write a dense matrix to a Matrix Market file. * * cholmod_print_common and cholmod_check_common are the only two routines that * you may call after calling cholmod_finish. * * Requires the Core module. Not required by any CHOLMOD module, except when * debugging is enabled (in which case all modules require the Check module). * * See cholmod_read.c for a description of the file formats supported by the * cholmod_read_* routines. */ #ifndef CHOLMOD_CHECK_H #define CHOLMOD_CHECK_H #include "cholmod_core.h" #include /* -------------------------------------------------------------------------- */ /* cholmod_check_common: check the Common object */ /* -------------------------------------------------------------------------- */ int cholmod_check_common ( cholmod_common *Common ) ; int cholmod_l_check_common (cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_common: print the Common object */ /* -------------------------------------------------------------------------- */ int cholmod_print_common ( /* ---- input ---- */ const char *name, /* printed name of Common object */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_common (const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_check_sparse: check a sparse matrix */ /* -------------------------------------------------------------------------- */ int cholmod_check_sparse ( /* ---- input ---- */ cholmod_sparse *A, /* sparse matrix to check */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_check_sparse (cholmod_sparse *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_sparse */ /* -------------------------------------------------------------------------- */ int cholmod_print_sparse ( /* ---- input ---- */ cholmod_sparse *A, /* sparse matrix to print */ const char *name, /* printed name of sparse matrix */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_sparse (cholmod_sparse *, const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_check_dense: check a dense matrix */ /* -------------------------------------------------------------------------- */ int cholmod_check_dense ( /* ---- input ---- */ cholmod_dense *X, /* dense matrix to check */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_check_dense (cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_dense: print a dense matrix */ /* -------------------------------------------------------------------------- */ int cholmod_print_dense ( /* ---- input ---- */ cholmod_dense *X, /* dense matrix to print */ const char *name, /* printed name of dense matrix */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_dense (cholmod_dense *, const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_check_factor: check a factor */ /* -------------------------------------------------------------------------- */ int cholmod_check_factor ( /* ---- input ---- */ cholmod_factor *L, /* factor to check */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_check_factor (cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_factor: print a factor */ /* -------------------------------------------------------------------------- */ int cholmod_print_factor ( /* ---- input ---- */ cholmod_factor *L, /* factor to print */ const char *name, /* printed name of factor */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_factor (cholmod_factor *, const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_check_triplet: check a sparse matrix in triplet form */ /* -------------------------------------------------------------------------- */ int cholmod_check_triplet ( /* ---- input ---- */ cholmod_triplet *T, /* triplet matrix to check */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_check_triplet (cholmod_triplet *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_triplet: print a triplet matrix */ /* -------------------------------------------------------------------------- */ int cholmod_print_triplet ( /* ---- input ---- */ cholmod_triplet *T, /* triplet matrix to print */ const char *name, /* printed name of triplet matrix */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_triplet (cholmod_triplet *, const char *, cholmod_common *); /* -------------------------------------------------------------------------- */ /* cholmod_check_subset: check a subset */ /* -------------------------------------------------------------------------- */ int cholmod_check_subset ( /* ---- input ---- */ int *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ UF_long len, /* size of Set (an integer array) */ size_t n, /* 0:n-1 is valid range */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_check_subset (UF_long *, UF_long, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_subset: print a subset */ /* -------------------------------------------------------------------------- */ int cholmod_print_subset ( /* ---- input ---- */ int *Set, /* Set [0:len-1] is a subset of 0:n-1. Duplicates OK */ UF_long len, /* size of Set (an integer array) */ size_t n, /* 0:n-1 is valid range */ const char *name, /* printed name of Set */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_subset (UF_long *, UF_long, size_t, const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_check_perm: check a permutation */ /* -------------------------------------------------------------------------- */ int cholmod_check_perm ( /* ---- input ---- */ int *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ size_t len, /* size of Perm (an integer array) */ size_t n, /* 0:n-1 is valid range */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_check_perm (UF_long *, size_t, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_perm: print a permutation vector */ /* -------------------------------------------------------------------------- */ int cholmod_print_perm ( /* ---- input ---- */ int *Perm, /* Perm [0:len-1] is a permutation of subset of 0:n-1 */ size_t len, /* size of Perm (an integer array) */ size_t n, /* 0:n-1 is valid range */ const char *name, /* printed name of Perm */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_perm (UF_long *, size_t, size_t, const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_check_parent: check an elimination tree */ /* -------------------------------------------------------------------------- */ int cholmod_check_parent ( /* ---- input ---- */ int *Parent, /* Parent [0:n-1] is an elimination tree */ size_t n, /* size of Parent */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_check_parent (UF_long *, size_t, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_print_parent */ /* -------------------------------------------------------------------------- */ int cholmod_print_parent ( /* ---- input ---- */ int *Parent, /* Parent [0:n-1] is an elimination tree */ size_t n, /* size of Parent */ const char *name, /* printed name of Parent */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_print_parent (UF_long *, size_t, const char *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_read_sparse: read a sparse matrix from a file */ /* -------------------------------------------------------------------------- */ cholmod_sparse *cholmod_read_sparse ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ /* --------------- */ cholmod_common *Common ) ; cholmod_sparse *cholmod_l_read_sparse (FILE *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_read_triplet: read a triplet matrix from a file */ /* -------------------------------------------------------------------------- */ cholmod_triplet *cholmod_read_triplet ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ /* --------------- */ cholmod_common *Common ) ; cholmod_triplet *cholmod_l_read_triplet (FILE *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_read_dense: read a dense matrix from a file */ /* -------------------------------------------------------------------------- */ cholmod_dense *cholmod_read_dense ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ /* --------------- */ cholmod_common *Common ) ; cholmod_dense *cholmod_l_read_dense (FILE *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_read_matrix: read a sparse or dense matrix from a file */ /* -------------------------------------------------------------------------- */ void *cholmod_read_matrix ( /* ---- input ---- */ FILE *f, /* file to read from, must already be open */ int prefer, /* If 0, a sparse matrix is always return as a * cholmod_triplet form. It can have any stype * (symmetric-lower, unsymmetric, or * symmetric-upper). * If 1, a sparse matrix is returned as an unsymmetric * cholmod_sparse form (A->stype == 0), with both * upper and lower triangular parts present. * This is what the MATLAB mread mexFunction does, * since MATLAB does not have an stype. * If 2, a sparse matrix is returned with an stype of 0 * or 1 (unsymmetric, or symmetric with upper part * stored). * This argument has no effect for dense matrices. */ /* ---- output---- */ int *mtype, /* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */ /* --------------- */ cholmod_common *Common ) ; void *cholmod_l_read_matrix (FILE *, int, int *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_write_sparse: write a sparse matrix to a file */ /* -------------------------------------------------------------------------- */ int cholmod_write_sparse ( /* ---- input ---- */ FILE *f, /* file to write to, must already be open */ cholmod_sparse *A, /* matrix to print */ cholmod_sparse *Z, /* optional matrix with pattern of explicit zeros */ const char *comments, /* optional filename of comments to include */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_write_sparse (FILE *, cholmod_sparse *, cholmod_sparse *, const char *c, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_write_dense: write a dense matrix to a file */ /* -------------------------------------------------------------------------- */ int cholmod_write_dense ( /* ---- input ---- */ FILE *f, /* file to write to, must already be open */ cholmod_dense *X, /* matrix to print */ const char *comments, /* optional filename of comments to include */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_write_dense (FILE *, cholmod_dense *, const char *, cholmod_common *) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_partition.h0000644000175000017500000002122211674452555023662 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_partition.h ========================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_partition.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod_partition.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD Partition module. * * Graph partitioning and graph-partition-based orderings. Includes an * interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering * methods which order a matrix following constraints determined via nested * dissection. * * cholmod_nested_dissection CHOLMOD nested dissection ordering * cholmod_metis METIS nested dissection ordering (METIS_NodeND) * cholmod_ccolamd interface to CCOLAMD ordering * cholmod_csymamd interface to CSYMAMD ordering * cholmod_camd interface to CAMD ordering * cholmod_bisect graph partitioner (currently based on METIS) * cholmod_metis_bisector direct interface to METIS_NodeComputeSeparator * * Requires the Core and Cholesky modules, and three packages: METIS, CAMD, * and CCOLAMD. Optionally used by the Cholesky module. * * Note that METIS does not have a version that uses UF_long integers. If you * try to use cholmod_nested_dissection, cholmod_metis, cholmod_bisect, or * cholmod_metis_bisector on a matrix that is too large, an error code will be * returned. METIS does have an "idxtype", which could be redefined as UF_long, * if you wish to edit METIS or use compile-time flags to redefine idxtype. */ #ifndef CHOLMOD_PARTITION_H #define CHOLMOD_PARTITION_H #include "cholmod_core.h" /* -------------------------------------------------------------------------- */ /* cholmod_nested_dissection */ /* -------------------------------------------------------------------------- */ /* Order A, AA', or A(:,f)*A(:,f)' using CHOLMOD's nested dissection method * (METIS's node bisector applied recursively to compute the separator tree * and constraint sets, followed by CCOLAMD using the constraints). Usually * finds better orderings than METIS_NodeND, but takes longer. */ UF_long cholmod_nested_dissection /* returns # of components */ ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ int *Perm, /* size A->nrow, output permutation */ int *CParent, /* size A->nrow. On output, CParent [c] is the parent * of component c, or EMPTY if c is a root, and where * c is in the range 0 to # of components minus 1 */ int *Cmember, /* size A->nrow. Cmember [j] = c if node j of A is * in component c */ /* --------------- */ cholmod_common *Common ) ; UF_long cholmod_l_nested_dissection (cholmod_sparse *, UF_long *, size_t, UF_long *, UF_long *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_metis */ /* -------------------------------------------------------------------------- */ /* Order A, AA', or A(:,f)*A(:,f)' using METIS_NodeND. */ int cholmod_metis ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int postorder, /* if TRUE, follow with etree or coletree postorder */ /* ---- output --- */ int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_metis (cholmod_sparse *, UF_long *, size_t, int, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_ccolamd */ /* -------------------------------------------------------------------------- */ /* Order AA' or A(:,f)*A(:,f)' using CCOLAMD. */ int cholmod_ccolamd ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int *Cmember, /* size A->nrow. Cmember [i] = c if row i is in the * constraint set c. c must be >= 0. The # of * constraint sets is max (Cmember) + 1. If Cmember is * NULL, then it is interpretted as Cmember [i] = 0 for * all i */ /* ---- output --- */ int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_ccolamd (cholmod_sparse *, UF_long *, size_t, UF_long *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_csymamd */ /* -------------------------------------------------------------------------- */ /* Order A using CSYMAMD. */ int cholmod_csymamd ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ /* ---- output --- */ int *Cmember, /* size nrow. see cholmod_ccolamd above */ int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_csymamd (cholmod_sparse *, UF_long *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_camd */ /* -------------------------------------------------------------------------- */ /* Order A using CAMD. */ int cholmod_camd ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to order */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ int *Cmember, /* size nrow. see cholmod_ccolamd above */ int *Perm, /* size A->nrow, output permutation */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_camd (cholmod_sparse *, UF_long *, size_t, UF_long *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_bisect */ /* -------------------------------------------------------------------------- */ /* Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. */ UF_long cholmod_bisect /* returns # of nodes in separator */ ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to bisect */ int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int compress, /* if TRUE, compress the graph first */ /* ---- output --- */ int *Partition, /* size A->nrow. Node i is in the left graph if * Partition [i] = 0, the right graph if 1, and in the * separator if 2. */ /* --------------- */ cholmod_common *Common ) ; UF_long cholmod_l_bisect (cholmod_sparse *, UF_long *, size_t, int, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_metis_bisector */ /* -------------------------------------------------------------------------- */ /* Find a set of nodes that bisects the graph of A or AA' (direct interface * to METIS_NodeComputeSeparator). */ UF_long cholmod_metis_bisector /* returns separator size */ ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to bisect */ int *Anw, /* size A->nrow, node weights */ int *Aew, /* size nz, edge weights */ /* ---- output --- */ int *Partition, /* size A->nrow. see cholmod_bisect above. */ /* --------------- */ cholmod_common *Common ) ; UF_long cholmod_l_metis_bisector (cholmod_sparse *, UF_long *, UF_long *, UF_long *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_collapse_septree */ /* -------------------------------------------------------------------------- */ /* Collapse nodes in a separator tree. */ UF_long cholmod_collapse_septree ( /* ---- input ---- */ size_t n, /* # of nodes in the graph */ size_t ncomponents, /* # of nodes in the separator tree (must be <= n) */ double nd_oksep, /* collapse if #sep >= nd_oksep * #nodes in subtree */ size_t nd_small, /* collapse if #nodes in subtree < nd_small */ /* ---- in/out --- */ int *CParent, /* size ncomponents; from cholmod_nested_dissection */ int *Cmember, /* size n; from cholmod_nested_dissection */ /* --------------- */ cholmod_common *Common ) ; UF_long cholmod_l_collapse_septree (size_t, size_t, double, size_t, UF_long *, UF_long *, cholmod_common *) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_io64.h0000644000175000017500000000325611674452555022441 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_io64 ================================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_io64.h. * Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis * CHOLMOD/Include/cholmod_io64.h is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Definitions required for large file I/O, which must come before any other * #includes. These are not used if -DNLARGEFILE is defined at compile time. * Large file support may not be portable across all platforms and compilers; * if you encounter an error here, compile your code with -DNLARGEFILE. In * particular, you must use -DNLARGEFILE for MATLAB 6.5 or earlier (which does * not have the io64.h include file). */ #ifndef CHOLMOD_IO_H #define CHOLMOD_IO_H /* skip all of this if NLARGEFILE is defined at the compiler command line */ #ifndef NLARGEFILE #if defined(MATLAB_MEX_FILE) || defined(MATHWORKS) /* CHOLMOD is being compiled as a MATLAB MEX file, or for use inside MATLAB */ #include "io64.h" #else /* CHOLMOD is being compiled in a stand-alone library */ #undef _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE #undef _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #endif #endif #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_modify.h0000644000175000017500000003125111674452555023143 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_modify.h ============================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_modify.h. * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager * CHOLMOD/Include/cholmod_modify.h is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD Modify module. * * Sparse Cholesky modification routines: update / downdate / rowadd / rowdel. * Can also modify a corresponding solution to Lx=b when L is modified. This * module is most useful when applied on a Cholesky factorization computed by * the Cholesky module, but it does not actually require the Cholesky module. * The Core module can create an identity Cholesky factorization (LDL' where * L=D=I) that can then by modified by these routines. * * Primary routines: * ----------------- * * cholmod_updown multiple rank update/downdate * cholmod_rowadd add a row to an LDL' factorization * cholmod_rowdel delete a row from an LDL' factorization * * Secondary routines: * ------------------- * * cholmod_updown_solve update/downdate, and modify solution to Lx=b * cholmod_updown_mark update/downdate, and modify solution to partial Lx=b * cholmod_updown_mask update/downdate for LPDASA * cholmod_rowadd_solve add a row, and update solution to Lx=b * cholmod_rowadd_mark add a row, and update solution to partial Lx=b * cholmod_rowdel_solve delete a row, and downdate Lx=b * cholmod_rowdel_mark delete a row, and downdate solution to partial Lx=b * * Requires the Core module. Not required by any other CHOLMOD module. */ #ifndef CHOLMOD_MODIFY_H #define CHOLMOD_MODIFY_H #include "cholmod_core.h" /* -------------------------------------------------------------------------- */ /* cholmod_updown: multiple rank update/downdate */ /* -------------------------------------------------------------------------- */ /* Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC' * (a downdate). The factor object L need not be an LDL' factorization; it * is converted to one if it isn't. */ int cholmod_updown ( /* ---- input ---- */ int update, /* TRUE for update, FALSE for downdate */ cholmod_sparse *C, /* the incoming sparse update */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_updown (int, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_updown_solve: update/downdate, and modify solution to Lx=b */ /* -------------------------------------------------------------------------- */ /* Does the same as cholmod_updown, except that it also updates/downdates the * solution to Lx=b+DeltaB. x and b must be n-by-1 dense matrices. b is not * need as input to this routine, but a sparse change to b is (DeltaB). Only * entries in DeltaB corresponding to columns modified in L are accessed; the * rest must be zero. */ int cholmod_updown_solve ( /* ---- input ---- */ int update, /* TRUE for update, FALSE for downdate */ cholmod_sparse *C, /* the incoming sparse update */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ cholmod_dense *DeltaB, /* change in b, zero on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_updown_solve (int, cholmod_sparse *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_updown_mark: update/downdate, and modify solution to partial Lx=b */ /* -------------------------------------------------------------------------- */ /* Does the same as cholmod_updown_solve, except only part of L is used in * the update/downdate of the solution to Lx=b. This routine is an "expert" * routine. It is meant for use in LPDASA only. See cholmod_updown.c for * a description of colmark. */ int cholmod_updown_mark ( /* ---- input ---- */ int update, /* TRUE for update, FALSE for downdate */ cholmod_sparse *C, /* the incoming sparse update */ int *colmark, /* int array of size n. See cholmod_updown.c */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ cholmod_dense *DeltaB, /* change in b, zero on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_updown_mark (int, cholmod_sparse *, UF_long *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_updown_mask: update/downdate, for LPDASA */ /* -------------------------------------------------------------------------- */ /* Does the same as cholmod_updown_mark, except has an additional "mask" * argument. This routine is an "expert" routine. It is meant for use in * LPDASA only. See cholmod_updown.c for a description of mask. */ int cholmod_updown_mask ( /* ---- input ---- */ int update, /* TRUE for update, FALSE for downdate */ cholmod_sparse *C, /* the incoming sparse update */ int *colmark, /* int array of size n. See cholmod_updown.c */ int *mask, /* size n */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ cholmod_dense *DeltaB, /* change in b, zero on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_updown_mask (int, cholmod_sparse *, UF_long *, UF_long *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowadd: add a row to an LDL' factorization (a rank-2 update) */ /* -------------------------------------------------------------------------- */ /* cholmod_rowadd adds a row to the LDL' factorization. It computes the kth * row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n) * accordingly. The kth row and column of L must originally be equal to the * kth row and column of the identity matrix. The kth row/column of L is * computed as the factorization of the kth row/column of the matrix to * factorize, which is provided as a single n-by-1 sparse matrix R. */ int cholmod_rowadd ( /* ---- input ---- */ size_t k, /* row/column index to add */ cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowadd (size_t, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowadd_solve: add a row, and update solution to Lx=b */ /* -------------------------------------------------------------------------- */ /* Does the same as cholmod_rowadd, and also updates the solution to Lx=b * See cholmod_updown for a description of how Lx=b is updated. There is on * additional parameter: bk specifies the new kth entry of b. */ int cholmod_rowadd_solve ( /* ---- input ---- */ size_t k, /* row/column index to add */ cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ double bk [2], /* kth entry of the right-hand-side b */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ cholmod_dense *DeltaB, /* change in b, zero on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowadd_solve (size_t, cholmod_sparse *, double *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowadd_mark: add a row, and update solution to partial Lx=b */ /* -------------------------------------------------------------------------- */ /* Does the same as cholmod_rowadd_solve, except only part of L is used in * the update/downdate of the solution to Lx=b. This routine is an "expert" * routine. It is meant for use in LPDASA only. */ int cholmod_rowadd_mark ( /* ---- input ---- */ size_t k, /* row/column index to add */ cholmod_sparse *R, /* row/column of matrix to factorize (n-by-1) */ double bk [2], /* kth entry of the right hand side, b */ int *colmark, /* int array of size n. See cholmod_updown.c */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ cholmod_dense *DeltaB, /* change in b, zero on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowadd_mark (size_t, cholmod_sparse *, double *, UF_long *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowdel: delete a row from an LDL' factorization (a rank-2 update) */ /* -------------------------------------------------------------------------- */ /* Sets the kth row and column of L to be the kth row and column of the identity * matrix, and updates L(k+1:n,k+1:n) accordingly. To reduce the running time, * the caller can optionally provide the nonzero pattern (or an upper bound) of * kth row of L, as the sparse n-by-1 vector R. Provide R as NULL if you want * CHOLMOD to determine this itself, which is easier for the caller, but takes * a little more time. */ int cholmod_rowdel ( /* ---- input ---- */ size_t k, /* row/column index to delete */ cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowdel (size_t, cholmod_sparse *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowdel_solve: delete a row, and downdate Lx=b */ /* -------------------------------------------------------------------------- */ /* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b. * When row/column k of A is "deleted" from the system A*y=b, this can induce * a change to x, in addition to changes arising when L and b are modified. * If this is the case, the kth entry of y is required as input (yk) */ int cholmod_rowdel_solve ( /* ---- input ---- */ size_t k, /* row/column index to delete */ cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ double yk [2], /* kth entry in the solution to A*y=b */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ cholmod_dense *DeltaB, /* change in b, zero on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowdel_solve (size_t, cholmod_sparse *, double *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_rowdel_mark: delete a row, and downdate solution to partial Lx=b */ /* -------------------------------------------------------------------------- */ /* Does the same as cholmod_rowdel_solve, except only part of L is used in * the update/downdate of the solution to Lx=b. This routine is an "expert" * routine. It is meant for use in LPDASA only. */ int cholmod_rowdel_mark ( /* ---- input ---- */ size_t k, /* row/column index to delete */ cholmod_sparse *R, /* NULL, or the nonzero pattern of kth row of L */ double yk [2], /* kth entry in the solution to A*y=b */ int *colmark, /* int array of size n. See cholmod_updown.c */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ cholmod_dense *X, /* solution to Lx=b (size n-by-1) */ cholmod_dense *DeltaB, /* change in b, zero on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *, UF_long *, cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Include/cholmod_supernodal.h0000644000175000017500000001444311674452555024034 0ustar sonnesonne/* ========================================================================== */ /* === Include/cholmod_supernodal.h ========================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Include/cholmod_supernodal.h. * Copyright (C) 2005-2006, Timothy A. Davis * CHOLMOD/Include/cholmod_supernodal.h is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD Supernodal module. * * Supernodal analysis, factorization, and solve. The simplest way to use * these routines is via the Cholesky module. It does not provide any * fill-reducing orderings, but does accept the orderings computed by the * Cholesky module. It does not require the Cholesky module itself, however. * * Primary routines: * ----------------- * cholmod_super_symbolic supernodal symbolic analysis * cholmod_super_numeric supernodal numeric factorization * cholmod_super_lsolve supernodal Lx=b solve * cholmod_super_ltsolve supernodal L'x=b solve * * Prototypes for the BLAS and LAPACK routines that CHOLMOD uses are listed * below, including how they are used in CHOLMOD. * * BLAS routines: * -------------- * dtrsv solve Lx=b or L'x=b, L non-unit diagonal, x and b stride-1 * dtrsm solve LX=B or L'X=b, L non-unit diagonal * dgemv y=y-A*x or y=y-A'*x (x and y stride-1) * dgemm C=A*B', C=C-A*B, or C=C-A'*B * dsyrk C=tril(A*A') * * LAPACK routines: * ---------------- * dpotrf LAPACK: A=chol(tril(A)) * * Requires the Core module, and two external packages: LAPACK and the BLAS. * Optionally used by the Cholesky module. */ #ifndef CHOLMOD_SUPERNODAL_H #define CHOLMOD_SUPERNODAL_H #include "cholmod_core.h" /* -------------------------------------------------------------------------- */ /* cholmod_super_symbolic */ /* -------------------------------------------------------------------------- */ /* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric * factorization. The user need not call this directly; cholmod_analyze is * a "simple" wrapper for this routine. */ int cholmod_super_symbolic ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ cholmod_sparse *F, /* F = A' or A(:,f)' */ int *Parent, /* elimination tree */ /* ---- in/out --- */ cholmod_factor *L, /* simplicial symbolic on input, * supernodal symbolic on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_super_symbolic (cholmod_sparse *, cholmod_sparse *, UF_long *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_super_symbolic2 */ /* -------------------------------------------------------------------------- */ /* Analyze for supernodal Cholesky or multifrontal QR. CHOLMOD itself always * analyzes for supernodal Cholesky, of course. This "for_cholesky = TRUE" * option is used by SuiteSparseQR only. Added for V1.7 */ int cholmod_super_symbolic2 ( /* ---- input ---- */ int for_cholesky, /* Cholesky if TRUE, QR if FALSE */ cholmod_sparse *A, /* matrix to analyze */ cholmod_sparse *F, /* F = A' or A(:,f)' */ int *Parent, /* elimination tree */ /* ---- in/out --- */ cholmod_factor *L, /* simplicial symbolic on input, * supernodal symbolic on output */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_super_symbolic2 (int, cholmod_sparse *, cholmod_sparse *, UF_long *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_super_numeric */ /* -------------------------------------------------------------------------- */ /* Computes the numeric LL' factorization of A, AA', or A(:,f)*A(:,f)' using * a BLAS-based supernodal method. The user need not call this directly; * cholmod_factorize is a "simple" wrapper for this routine. */ int cholmod_super_numeric ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* F = A' or A(:,f)' */ double beta [2], /* beta*I is added to diagonal of matrix to factorize */ /* ---- in/out --- */ cholmod_factor *L, /* factorization */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_super_numeric (cholmod_sparse *, cholmod_sparse *, double *, cholmod_factor *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_super_lsolve */ /* -------------------------------------------------------------------------- */ /* Solve Lx=b where L is from a supernodal numeric factorization. The user * need not call this routine directly. cholmod_solve is a "simple" wrapper * for this routine. */ int cholmod_super_lsolve ( /* ---- input ---- */ cholmod_factor *L, /* factor to use for the forward solve */ /* ---- output ---- */ cholmod_dense *X, /* b on input, solution to Lx=b on output */ /* ---- workspace */ cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_super_lsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; /* -------------------------------------------------------------------------- */ /* cholmod_super_ltsolve */ /* -------------------------------------------------------------------------- */ /* Solve L'x=b where L is from a supernodal numeric factorization. The user * need not call this routine directly. cholmod_solve is a "simple" wrapper * for this routine. */ int cholmod_super_ltsolve ( /* ---- input ---- */ cholmod_factor *L, /* factor to use for the backsolve */ /* ---- output ---- */ cholmod_dense *X, /* b on input, solution to L'x=b on output */ /* ---- workspace */ cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ /* --------------- */ cholmod_common *Common ) ; int cholmod_l_super_ltsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ; #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Lib/0000755000175000017500000000000011674452555017117 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Lib/Makefile0000644000175000017500000003327711674452555020573 0ustar sonnesonne#=============================================================================== # CHOLOMD/Lib/Makefile: for compiling the CHOLMOD library #=============================================================================== default: all ccode: all include ../../UFconfig/UFconfig.mk C = $(CC) $(CFLAGS) $(CHOLMOD_CONFIG) all: libcholmod.a library: libcholmod.a purge: distclean distclean: clean - $(RM) libcholmod.a clean: - $(RM) $(CLEAN) #------------------------------------------------------------------------------- # ../Include/ directory contains all include files: #------------------------------------------------------------------------------- INC = ../Include/cholmod.h \ ../Include/cholmod_blas.h \ ../Include/cholmod_check.h \ ../Include/cholmod_cholesky.h \ ../Include/cholmod_complexity.h \ ../Include/cholmod_config.h \ ../Include/cholmod_core.h \ ../Include/cholmod_internal.h \ ../Include/cholmod_matrixops.h \ ../Include/cholmod_modify.h \ ../Include/cholmod_partition.h \ ../Include/cholmod_supernodal.h \ ../Include/cholmod_template.h #------------------------------------------------------------------------------- # The 7 CHOLMOD library modules (int, double) #------------------------------------------------------------------------------- CORE = cholmod_aat.o cholmod_add.o cholmod_band.o \ cholmod_change_factor.o cholmod_common.o cholmod_complex.o \ cholmod_copy.o cholmod_dense.o cholmod_error.o cholmod_factor.o \ cholmod_memory.o cholmod_sparse.o \ cholmod_transpose.o cholmod_triplet.o CHECK = cholmod_check.o cholmod_read.o cholmod_write.o CHOLESKY = cholmod_amd.o cholmod_analyze.o cholmod_colamd.o \ cholmod_etree.o cholmod_factorize.o cholmod_postorder.o \ cholmod_rcond.o cholmod_resymbol.o cholmod_rowcolcounts.o \ cholmod_rowfac.o cholmod_solve.o cholmod_spsolve.o MATRIXOPS = cholmod_drop.o cholmod_horzcat.o cholmod_norm.o \ cholmod_scale.o cholmod_sdmult.o cholmod_ssmult.o \ cholmod_submatrix.o cholmod_vertcat.o cholmod_symmetry.o PARTITION = cholmod_ccolamd.o cholmod_csymamd.o \ cholmod_metis.o cholmod_nesdis.o cholmod_camd.o MODIFY = cholmod_rowadd.o cholmod_rowdel.o cholmod_updown.o SUPERNODAL = cholmod_super_numeric.o cholmod_super_solve.o \ cholmod_super_symbolic.o DI = $(CORE) $(CHECK) $(CHOLESKY) $(MATRIXOPS) $(MODIFY) $(SUPERNODAL) \ $(PARTITION) #------------------------------------------------------------------------------- # CHOLMOD library modules (long, double) #------------------------------------------------------------------------------- LCORE = cholmod_l_aat.o cholmod_l_add.o cholmod_l_band.o \ cholmod_l_change_factor.o cholmod_l_common.o cholmod_l_complex.o \ cholmod_l_copy.o cholmod_l_dense.o cholmod_l_error.o \ cholmod_l_factor.o cholmod_l_memory.o \ cholmod_l_sparse.o cholmod_l_transpose.o cholmod_l_triplet.o LCHECK = cholmod_l_check.o cholmod_l_read.o cholmod_l_write.o LCHOLESKY = cholmod_l_amd.o cholmod_l_analyze.o cholmod_l_colamd.o \ cholmod_l_etree.o cholmod_l_factorize.o cholmod_l_postorder.o \ cholmod_l_rcond.o cholmod_l_resymbol.o cholmod_l_rowcolcounts.o \ cholmod_l_rowfac.o cholmod_l_solve.o cholmod_l_spsolve.o LMATRIXOPS = cholmod_l_drop.o cholmod_l_horzcat.o cholmod_l_norm.o \ cholmod_l_scale.o cholmod_l_sdmult.o cholmod_l_ssmult.o \ cholmod_l_submatrix.o cholmod_l_vertcat.o cholmod_l_symmetry.o LPARTITION = cholmod_l_ccolamd.o cholmod_l_csymamd.o \ cholmod_l_metis.o cholmod_l_nesdis.o cholmod_l_camd.o LMODIFY = cholmod_l_rowadd.o cholmod_l_rowdel.o cholmod_l_updown.o LSUPERNODAL = cholmod_l_super_numeric.o cholmod_l_super_solve.o \ cholmod_l_super_symbolic.o DL = $(LCORE) $(LCHECK) $(LCHOLESKY) $(LMATRIXOPS) $(LMODIFY) $(LSUPERNODAL) \ $(LPARTITION) #------------------------------------------------------------------------------- # to compile just the double/int version, use OBJ = $(DI) OBJ = $(DI) $(DL) libcholmod.a: $(OBJ) $(AR) libcholmod.a $(OBJ) $(RANLIB) libcholmod.a $(OBJ): $(INC) I = -I../../AMD/Include -I../../AMD/Source -I../../COLAMD/Include \ -I$(METIS_PATH)/Lib -I../../CCOLAMD/Include -I../../CAMD/Include \ -I../Include -I../../UFconfig #------------------------------------------------------------------------------- # Check Module: #------------------------------------------------------------------------------- cholmod_check.o: ../Check/cholmod_check.c $(C) -c $(I) $< cholmod_read.o: ../Check/cholmod_read.c $(C) -c $(I) $< cholmod_write.o: ../Check/cholmod_write.c $(C) -c $(I) $< #------------------------------------------------------------------------------- cholmod_l_check.o: ../Check/cholmod_check.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_read.o: ../Check/cholmod_read.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_write.o: ../Check/cholmod_write.c $(C) -DDLONG -c $(I) $< -o $@ #------------------------------------------------------------------------------- # Core Module: #------------------------------------------------------------------------------- cholmod_common.o: ../Core/cholmod_common.c $(C) -c $(I) $< cholmod_dense.o: ../Core/cholmod_dense.c ../Core/t_cholmod_dense.c $(C) -c $(I) $< cholmod_factor.o: ../Core/cholmod_factor.c $(C) -c $(I) $< cholmod_change_factor.o: ../Core/cholmod_change_factor.c \ ../Core/t_cholmod_change_factor.c $(C) -c $(I) $< cholmod_memory.o: ../Core/cholmod_memory.c $(C) -c $(I) $< cholmod_sparse.o: ../Core/cholmod_sparse.c $(C) -c $(I) $< cholmod_complex.o: ../Core/cholmod_complex.c $(C) -c $(I) $< cholmod_transpose.o: ../Core/cholmod_transpose.c ../Core/t_cholmod_transpose.c $(C) -c $(I) $< cholmod_band.o: ../Core/cholmod_band.c $(C) -c $(I) $< cholmod_copy.o: ../Core/cholmod_copy.c $(C) -c $(I) $< cholmod_triplet.o: ../Core/cholmod_triplet.c ../Core/t_cholmod_triplet.c $(C) -c $(I) $< cholmod_error.o: ../Core/cholmod_error.c $(C) -c $(I) $< cholmod_aat.o: ../Core/cholmod_aat.c $(C) -c $(I) $< cholmod_add.o: ../Core/cholmod_add.c $(C) -c $(I) $< #------------------------------------------------------------------------------- cholmod_l_common.o: ../Core/cholmod_common.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_dense.o: ../Core/cholmod_dense.c ../Core/t_cholmod_dense.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_factor.o: ../Core/cholmod_factor.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_change_factor.o: ../Core/cholmod_change_factor.c \ ../Core/t_cholmod_change_factor.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_memory.o: ../Core/cholmod_memory.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_sparse.o: ../Core/cholmod_sparse.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_complex.o: ../Core/cholmod_complex.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_transpose.o: ../Core/cholmod_transpose.c ../Core/t_cholmod_transpose.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_band.o: ../Core/cholmod_band.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_copy.o: ../Core/cholmod_copy.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_triplet.o: ../Core/cholmod_triplet.c ../Core/t_cholmod_triplet.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_error.o: ../Core/cholmod_error.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_aat.o: ../Core/cholmod_aat.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_add.o: ../Core/cholmod_add.c $(C) -DDLONG -c $(I) $< -o $@ #------------------------------------------------------------------------------- # Cholesky Module: #------------------------------------------------------------------------------- cholmod_amd.o: ../Cholesky/cholmod_amd.c $(C) -c $(I) $< cholmod_analyze.o: ../Cholesky/cholmod_analyze.c $(C) -c $(I) $< cholmod_colamd.o: ../Cholesky/cholmod_colamd.c $(C) -c $(I) $< cholmod_etree.o: ../Cholesky/cholmod_etree.c $(C) -c $(I) $< cholmod_factorize.o: ../Cholesky/cholmod_factorize.c $(C) -c $(I) $< cholmod_postorder.o: ../Cholesky/cholmod_postorder.c $(C) -c $(I) $< cholmod_rcond.o: ../Cholesky/cholmod_rcond.c $(C) -c $(I) $< cholmod_resymbol.o: ../Cholesky/cholmod_resymbol.c $(C) -c $(I) $< cholmod_rowcolcounts.o: ../Cholesky/cholmod_rowcolcounts.c $(C) -c $(I) $< cholmod_solve.o: ../Cholesky/cholmod_solve.c ../Cholesky/t_cholmod_lsolve.c \ ../Cholesky/t_cholmod_ltsolve.c ../Cholesky/t_cholmod_solve.c $(C) -c $(I) $< cholmod_spsolve.o: ../Cholesky/cholmod_spsolve.c $(C) -c $(I) $< cholmod_rowfac.o: ../Cholesky/cholmod_rowfac.c ../Cholesky/t_cholmod_rowfac.c $(C) -c $(I) $< #------------------------------------------------------------------------------- cholmod_l_amd.o: ../Cholesky/cholmod_amd.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_analyze.o: ../Cholesky/cholmod_analyze.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_colamd.o: ../Cholesky/cholmod_colamd.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_etree.o: ../Cholesky/cholmod_etree.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_factorize.o: ../Cholesky/cholmod_factorize.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_postorder.o: ../Cholesky/cholmod_postorder.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_rcond.o: ../Cholesky/cholmod_rcond.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_resymbol.o: ../Cholesky/cholmod_resymbol.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_rowcolcounts.o: ../Cholesky/cholmod_rowcolcounts.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_solve.o: ../Cholesky/cholmod_solve.c ../Cholesky/t_cholmod_lsolve.c \ ../Cholesky/t_cholmod_ltsolve.c ../Cholesky/t_cholmod_solve.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_spsolve.o: ../Cholesky/cholmod_spsolve.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_rowfac.o: ../Cholesky/cholmod_rowfac.c ../Cholesky/t_cholmod_rowfac.c $(C) -DDLONG -c $(I) $< -o $@ #------------------------------------------------------------------------------- # Partition Module: #------------------------------------------------------------------------------- cholmod_ccolamd.o: ../Partition/cholmod_ccolamd.c $(C) -c $(I) $< cholmod_csymamd.o: ../Partition/cholmod_csymamd.c $(C) -c $(I) $< cholmod_camd.o: ../Partition/cholmod_camd.c $(C) -c $(I) $< cholmod_metis.o: ../Partition/cholmod_metis.c $(C) -c $(I) $< cholmod_nesdis.o: ../Partition/cholmod_nesdis.c $(C) -c $(I) $< #------------------------------------------------------------------------------- cholmod_l_ccolamd.o: ../Partition/cholmod_ccolamd.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_csymamd.o: ../Partition/cholmod_csymamd.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_camd.o: ../Partition/cholmod_camd.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_metis.o: ../Partition/cholmod_metis.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_nesdis.o: ../Partition/cholmod_nesdis.c $(C) -DDLONG -c $(I) $< -o $@ #------------------------------------------------------------------------------- # MatrixOps Module: #------------------------------------------------------------------------------- cholmod_horzcat.o: ../MatrixOps/cholmod_horzcat.c $(C) -c $(I) $< cholmod_norm.o: ../MatrixOps/cholmod_norm.c $(C) -c $(I) $< cholmod_scale.o: ../MatrixOps/cholmod_scale.c $(C) -c $(I) $< cholmod_drop.o: ../MatrixOps/cholmod_drop.c $(C) -c $(I) $< cholmod_sdmult.o: ../MatrixOps/cholmod_sdmult.c \ ../MatrixOps/t_cholmod_sdmult.c $(C) -c $(I) $< cholmod_ssmult.o: ../MatrixOps/cholmod_ssmult.c $(C) -c $(I) $< cholmod_submatrix.o: ../MatrixOps/cholmod_submatrix.c $(C) -c $(I) $< cholmod_vertcat.o: ../MatrixOps/cholmod_vertcat.c $(C) -c $(I) $< cholmod_symmetry.o: ../MatrixOps/cholmod_symmetry.c $(C) -c $(I) $< #------------------------------------------------------------------------------- cholmod_l_horzcat.o: ../MatrixOps/cholmod_horzcat.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_norm.o: ../MatrixOps/cholmod_norm.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_scale.o: ../MatrixOps/cholmod_scale.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_drop.o: ../MatrixOps/cholmod_drop.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_sdmult.o: ../MatrixOps/cholmod_sdmult.c \ ../MatrixOps/t_cholmod_sdmult.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_ssmult.o: ../MatrixOps/cholmod_ssmult.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_submatrix.o: ../MatrixOps/cholmod_submatrix.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_vertcat.o: ../MatrixOps/cholmod_vertcat.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_symmetry.o: ../MatrixOps/cholmod_symmetry.c $(C) -DDLONG -c $(I) $< -o $@ #------------------------------------------------------------------------------- # Modify Module: #------------------------------------------------------------------------------- cholmod_rowadd.o: ../Modify/cholmod_rowadd.c $(C) -c $(I) $< cholmod_rowdel.o: ../Modify/cholmod_rowdel.c $(C) -c $(I) $< cholmod_updown.o: ../Modify/cholmod_updown.c \ ../Modify/t_cholmod_updown.c ../Modify/t_cholmod_updown_numkr.c $(C) -c $(I) $< #------------------------------------------------------------------------------- cholmod_l_rowadd.o: ../Modify/cholmod_rowadd.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_rowdel.o: ../Modify/cholmod_rowdel.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_updown.o: ../Modify/cholmod_updown.c \ ../Modify/t_cholmod_updown.c ../Modify/t_cholmod_updown_numkr.c $(C) -DDLONG -c $(I) $< -o $@ #------------------------------------------------------------------------------- # Supernodal Module: #------------------------------------------------------------------------------- cholmod_super_numeric.o: ../Supernodal/cholmod_super_numeric.c \ ../Supernodal/t_cholmod_super_numeric.c $(C) -c $(I) $< cholmod_super_symbolic.o: ../Supernodal/cholmod_super_symbolic.c $(C) -c $(I) $< cholmod_super_solve.o: ../Supernodal/cholmod_super_solve.c \ ../Supernodal/t_cholmod_super_solve.c $(C) -c $(I) $< #------------------------------------------------------------------------------- cholmod_l_super_numeric.o: ../Supernodal/cholmod_super_numeric.c \ ../Supernodal/t_cholmod_super_numeric.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_super_symbolic.o: ../Supernodal/cholmod_super_symbolic.c $(C) -DDLONG -c $(I) $< -o $@ cholmod_l_super_solve.o: ../Supernodal/cholmod_super_solve.c \ ../Supernodal/t_cholmod_super_solve.c $(C) -DDLONG -c $(I) $< -o $@ cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/0000755000175000017500000000000011674452555020525 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_numeric.c0000644000175000017500000006107211674452555025607 0ustar sonnesonne/* ========================================================================== */ /* === Supernodal/t_cholmod_super_numeric =================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_super_numeric. All xtypes supported, except * that a zomplex A and F result in a complex L (there is no supernodal * zomplex L). */ /* ========================================================================== */ /* === complex arithmetic =================================================== */ /* ========================================================================== */ #include "cholmod_template.h" #undef L_ENTRY #undef L_CLEAR #undef L_ASSIGN #undef L_MULTADD #undef L_ASSEMBLE #undef L_ASSEMBLESUB #ifdef REAL /* -------------------------------------------------------------------------- */ /* A, F, and L are all real */ /* -------------------------------------------------------------------------- */ #define L_ENTRY 1 #define L_CLEAR(Lx,p) Lx [p] = 0 #define L_ASSIGN(Lx,q, Ax,Az,p) Lx [q] = Ax [p] #define L_MULTADD(Lx,q, Ax,Az,p, f) Lx [q] += Ax [p] * f [0] #define L_ASSEMBLE(Lx,q,b) Lx [q] += b [0] #define L_ASSEMBLESUB(Lx,q,C,p) Lx [q] -= C [p] #else /* -------------------------------------------------------------------------- */ /* A and F are complex or zomplex, L and C are complex */ /* -------------------------------------------------------------------------- */ #define L_ENTRY 2 #define L_CLEAR(Lx,p) Lx [2*(p)] = 0 ; Lx [2*(p)+1] = 0 #define L_ASSEMBLE(Lx,q,b) Lx [2*(q)] += b [0] ; #define L_ASSEMBLESUB(Lx,q,C,p) \ Lx [2*(q) ] -= C [2*(p) ] ; \ Lx [2*(q)+1] -= C [2*(p)+1] ; #ifdef COMPLEX /* -------------------------------------------------------------------------- */ /* A, F, L, and C are all complex */ /* -------------------------------------------------------------------------- */ #define L_ASSIGN(Lx,q, Ax,Az,p) \ Lx [2*(q) ] = Ax [2*(p) ] ; \ Lx [2*(q)+1] = Ax [2*(p)+1] #define L_MULTADD(Lx,q, Ax,Az,p, f) \ Lx [2*(q) ] += Ax [2*(p) ] * f [0] - Ax [2*(p)+1] * f [1] ; \ Lx [2*(q)+1] += Ax [2*(p)+1] * f [0] + Ax [2*(p) ] * f [1] #else /* -------------------------------------------------------------------------- */ /* A and F are zomplex, L and C is complex */ /* -------------------------------------------------------------------------- */ #define L_ASSIGN(Lx,q, Ax,Az,p) \ Lx [2*(q) ] = Ax [p] ; \ Lx [2*(q)+1] = Az [p] ; #define L_MULTADD(Lx,q, Ax,Az,p, f) \ Lx [2*(q) ] += Ax [p] * f [0] - Az [p] * f [1] ; \ Lx [2*(q)+1] += Az [p] * f [0] + Ax [p] * f [1] #endif #endif /* ========================================================================== */ /* === t_cholmod_super_numeric ============================================== */ /* ========================================================================== */ /* This function returns FALSE only if integer overflow occurs in the BLAS. * It returns TRUE otherwise whether or not the matrix is positive definite. */ static int TEMPLATE (cholmod_super_numeric) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* F = A' or A(:,f)' */ double beta [2], /* beta*I is added to diagonal of matrix to factorize */ /* ---- in/out --- */ cholmod_factor *L, /* factorization */ /* -- workspace -- */ cholmod_dense *Cwork, /* size (L->maxcsize)-by-1 */ /* --------------- */ cholmod_common *Common ) { double one [2], zero [2], fjk [2] ; double *Lx, *Ax, *Fx, *Az, *Fz, *C ; Int *Super, *Head, *Ls, *Lpi, *Lpx, *Map, *SuperMap, *RelativeMap, *Next, *Lpos, *Fp, *Fi, *Fnz, *Ap, *Ai, *Anz, *Iwork, *Next_save, *Lpos_save ; Int nsuper, n, j, i, k, s, p, pend, k1, k2, nscol, psi, psx, psend, nsrow, pj, d, kd1, kd2, info, ndcol, ndrow, pdi, pdx, pdend, pdi1, pdi2, pdx1, ndrow1, ndrow2, px, dancestor, sparent, dnext, nsrow2, ndrow3, pk, pf, pfend, stype, Apacked, Fpacked, q, imap, repeat_supernode, nscol2, ss, nscol_new = 0 ; /* If integer overflow occurs in the BLAS, Common->status is set to * CHOLMOD_TOO_LARGE, and the contents of Lx are undefined. */ Common->blas_ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nsuper = L->nsuper ; n = L->n ; C = Cwork->x ; /* workspace of size L->maxcsize */ one [0] = 1.0 ; /* ALPHA for *syrk, *herk, *gemm, and *trsm */ one [1] = 0. ; zero [0] = 0. ; /* BETA for *syrk, *herk, and *gemm */ zero [1] = 0. ; Iwork = Common->Iwork ; SuperMap = Iwork ; /* size n (i/i/l) */ RelativeMap = Iwork + n ; /* size n (i/i/l) */ Next = Iwork + 2*((size_t) n) ; /* size nsuper*/ Lpos = Iwork + 2*((size_t) n) + nsuper ; /* size nsuper*/ Next_save = Iwork + 2*((size_t) n) + 2*((size_t) nsuper) ;/* size nsuper*/ Lpos_save = Iwork + 2*((size_t) n) + 3*((size_t) nsuper) ;/* size nsuper*/ Map = Common->Flag ; /* size n, use Flag as workspace for Map array */ Head = Common->Head ; /* size n+1, only Head [0..nsuper-1] used */ Ls = L->s ; Lpi = L->pi ; Lpx = L->px ; Super = L->super ; Lx = L->x ; stype = A->stype ; if (stype != 0) { /* F not accessed */ Fp = NULL ; Fi = NULL ; Fx = NULL ; Fz = NULL ; Fnz = NULL ; Fpacked = TRUE ; } else { Fp = F->p ; Fi = F->i ; Fx = F->x ; Fz = F->z ; Fnz = F->nz ; Fpacked = F->packed ; } Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; Anz = A->nz ; Apacked = A->packed ; /* clear the Map so that changes in the pattern of A can be detected */ for (i = 0 ; i < n ; i++) { Map [i] = EMPTY ; } /* If the matrix is not positive definite, the supernode s containing the * first zero or negative diagonal entry of L is repeated (but factorized * only up to just before the problematic diagonal entry). The purpose is * to provide MATLAB with [R,p]=chol(A); columns 1 to p-1 of L=R' are * required, where L(p,p) is the problematic diagonal entry. The * repeat_supernode flag tells us whether this is the repeated supernode. * Once supernode s is repeated, the factorization is terminated. */ repeat_supernode = FALSE ; /* ---------------------------------------------------------------------- */ /* supernodal numerical factorization */ /* ---------------------------------------------------------------------- */ for (s = 0 ; s < nsuper ; s++) { /* ------------------------------------------------------------------ */ /* get the size of supernode s */ /* ------------------------------------------------------------------ */ k1 = Super [s] ; /* s contains columns k1 to k2-1 of L */ k2 = Super [s+1] ; nscol = k2 - k1 ; /* # of columns in all of s */ psi = Lpi [s] ; /* pointer to first row of s in Ls */ psx = Lpx [s] ; /* pointer to first row of s in Lx */ psend = Lpi [s+1] ; /* pointer just past last row of s in Ls */ nsrow = psend - psi ; /* # of rows in all of s */ PRINT1 (("====================================================\n" "S "ID" k1 "ID" k2 "ID" nsrow "ID" nscol "ID" psi "ID" psend " ""ID" psx "ID"\n", s, k1, k2, nsrow, nscol, psi, psend, psx)) ; /* ------------------------------------------------------------------ */ /* zero the supernode s */ /* ------------------------------------------------------------------ */ ASSERT ((size_t) (psx + nsrow*nscol) <= L->xsize) ; pend = psx + nsrow * nscol ; /* s is nsrow-by-nscol */ for (p = psx ; p < pend ; p++) { /* Lx [p] = 0 ; */ L_CLEAR (Lx,p) ; } /* ------------------------------------------------------------------ */ /* construct the scattered Map for supernode s */ /* ------------------------------------------------------------------ */ /* If row i is the kth row in s, then Map [i] = k. Similarly, if * column j is the kth column in s, then Map [j] = k. */ for (k = 0 ; k < nsrow ; k++) { PRINT1 ((" "ID" map "ID"\n", Ls [psi+k], k)) ; Map [Ls [psi + k]] = k ; } /* ------------------------------------------------------------------ */ /* copy matrix into supernode s (lower triangular part only) */ /* ------------------------------------------------------------------ */ pk = psx ; for (k = k1 ; k < k2 ; k++) { if (stype != 0) { /* copy the kth column of A into the supernode */ p = Ap [k] ; pend = (Apacked) ? (Ap [k+1]) : (p + Anz [k]) ; for ( ; p < pend ; p++) { /* row i of L is located in row Map [i] of s */ i = Ai [p] ; if (i >= k) { /* This test is here simply to avoid a segfault. If * the test is false, the numeric factorization of A * is undefined. It does not detect all invalid * entries, only some of them (when debugging is * enabled, and Map is cleared after each step, then * all entries not in the pattern of L are detected). */ imap = Map [i] ; if (imap >= 0 && imap < nsrow) { /* Lx [Map [i] + pk] = Ax [p] ; */ L_ASSIGN (Lx,(imap+pk), Ax,Az,p) ; } } } } else { /* copy the kth column of A*F into the supernode */ pf = Fp [k] ; pfend = (Fpacked) ? (Fp [k+1]) : (p + Fnz [k]) ; for ( ; pf < pfend ; pf++) { j = Fi [pf] ; /* fjk = Fx [pf] ; */ L_ASSIGN (fjk,0, Fx,Fz,pf) ; p = Ap [j] ; pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i >= k) { /* See the discussion of imap above. */ imap = Map [i] ; if (imap >= 0 && imap < nsrow) { /* Lx [Map [i] + pk] += Ax [p] * fjk ; */ L_MULTADD (Lx,(imap+pk), Ax,Az,p, fjk) ; } } } } } pk += nsrow ; /* advance to the next column of the supernode */ } /* add beta to the diagonal of the supernode, if nonzero */ if (beta [0] != 0.0) { /* note that only the real part of beta is used */ pk = psx ; for (k = k1 ; k < k2 ; k++) { /* Lx [pk] += beta [0] ; */ L_ASSEMBLE (Lx,pk, beta) ; pk += nsrow + 1 ; /* advance to the next diagonal entry */ } } PRINT1 (("Supernode with just A: repeat: "ID"\n", repeat_supernode)) ; DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, Common)) ; PRINT1 (("\n\n")) ; /* ------------------------------------------------------------------ */ /* save/restore the list of supernodes */ /* ------------------------------------------------------------------ */ if (!repeat_supernode) { /* Save the list of pending descendants in case s is not positive * definite. Also save Lpos for each descendant d, so that we can * find which part of d is used to update s. */ for (d = Head [s] ; d != EMPTY ; d = Next [d]) { Lpos_save [d] = Lpos [d] ; Next_save [d] = Next [d] ; } } else { /* s is not positive definite, and is being repeated. Restore * the list of supernodes. This can be done with pointer assignment * because all 4 arrays are held within Common->Iwork. */ Lpos = Lpos_save ; Next = Next_save ; } /* ------------------------------------------------------------------ */ /* update supernode s with each pending descendant d */ /* ------------------------------------------------------------------ */ #ifndef NDEBUG for (d = Head [s] ; d != EMPTY ; d = Next [d]) { PRINT1 (("\nWill update "ID" with Child: "ID"\n", s, d)) ; DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, Common)) ; } PRINT1 (("\nNow factorizing supernode "ID":\n", s)) ; #endif for (d = Head [s] ; d != EMPTY ; d = dnext) { /* -------------------------------------------------------------- */ /* get the size of supernode d */ /* -------------------------------------------------------------- */ kd1 = Super [d] ; /* d contains cols kd1 to kd2-1 of L */ kd2 = Super [d+1] ; ndcol = kd2 - kd1 ; /* # of columns in all of d */ pdi = Lpi [d] ; /* pointer to first row of d in Ls */ pdx = Lpx [d] ; /* pointer to first row of d in Lx */ pdend = Lpi [d+1] ; /* pointer just past last row of d in Ls */ ndrow = pdend - pdi ; /* # rows in all of d */ PRINT1 (("Child: ")) ; DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, Common)) ; /* -------------------------------------------------------------- */ /* find the range of rows of d that affect rows k1 to k2-1 of s */ /* -------------------------------------------------------------- */ p = Lpos [d] ; /* offset of 1st row of d affecting s */ pdi1 = pdi + p ; /* ptr to 1st row of d affecting s in Ls */ pdx1 = pdx + p ; /* ptr to 1st row of d affecting s in Lx */ /* there must be at least one row remaining in d to update s */ ASSERT (pdi1 < pdend) ; PRINT1 (("Lpos[d] "ID" pdi1 "ID" Ls[pdi1] "ID"\n", Lpos[d], pdi1, Ls [pdi1])) ; ASSERT (Ls [pdi1] >= k1 && Ls [pdi1] < k2) ; for (pdi2 = pdi1 ; pdi2 < pdend && Ls [pdi2] < k2 ; pdi2++) ; ndrow1 = pdi2 - pdi1 ; /* # rows in first part of d */ ndrow2 = pdend - pdi1 ; /* # rows in remaining d */ /* rows Ls [pdi1 ... pdi2-1] are in the range k1 to k2-1. Since d * affects s, this set cannot be empty. */ ASSERT (pdi1 < pdi2 && pdi2 <= pdend) ; PRINT1 (("ndrow1 "ID" ndrow2 "ID"\n", ndrow1, ndrow2)) ; DEBUG (for (p = pdi1 ; p < pdi2 ; p++) PRINT1 (("Ls["ID"] "ID"\n", p, Ls[p]))) ; /* -------------------------------------------------------------- */ /* construct the update matrix C for this supernode d */ /* -------------------------------------------------------------- */ /* C = L (k1:n-1, kd1:kd2-1) * L (k1:k2-1, kd1:kd2-1)', except * that k1:n-1 refers to all of the rows in L, but many of the * rows are all zero. Supernode d holds columns kd1 to kd2-1 of L. * Nonzero rows in the range k1:k2-1 are in the list * Ls [pdi1 ... pdi2-1], of size ndrow1. Nonzero rows in the range * k2:n-1 are in the list Ls [pdi2 ... pdend], of size ndrow2. Let * L1 = L (Ls [pdi1 ... pdi2-1], kd1:kd2-1), and let * L2 = L (Ls [pdi2 ... pdend], kd1:kd2-1). C is ndrow2-by-ndcol. * Let C1 be the first ndrow1 rows of C and let C2 be the last * ndrow2-ndrow1 rows of C. Only the lower triangular part of C1 * needs to be computed since C1 is symmetric. */ /* maxcsize is the largest size of C for all pairs (d,s) */ ASSERT (ndrow2 * ndrow1 <= ((Int) L->maxcsize)) ; /* compute leading ndrow1-by-ndrow1 lower triangular block of C, * C1 = L1*L1' */ #ifdef REAL BLAS_dsyrk ("L", "N", ndrow1, ndcol, /* N, K: L1 is ndrow1-by-ndcol*/ one, /* ALPHA: 1 */ Lx + L_ENTRY*pdx1, ndrow, /* A, LDA: L1, ndrow */ zero, /* BETA: 0 */ C, ndrow2) ; /* C, LDC: C1 */ #else BLAS_zherk ("L", "N", ndrow1, ndcol, /* N, K: L1 is ndrow1-by-ndcol*/ one, /* ALPHA: 1 */ Lx + L_ENTRY*pdx1, ndrow, /* A, LDA: L1, ndrow */ zero, /* BETA: 0 */ C, ndrow2) ; /* C, LDC: C1 */ #endif /* compute remaining (ndrow3-ndrow1)-by-ndrow1 block of C, * C2 = L2*L1' */ ndrow3 = ndrow2 - ndrow1 ; if (ndrow3 > 0) { #ifdef REAL BLAS_dgemm ("N", "C", ndrow3, ndrow1, ndcol, /* M, N, K */ one, /* ALPHA: 1 */ Lx + L_ENTRY*(pdx1 + ndrow1),/* A, LDA: L2, ndrow */ ndrow, Lx + L_ENTRY*pdx1, /* B, LDB: L1, ndrow */ ndrow, zero, /* BETA: 0 */ C + L_ENTRY*ndrow1, /* C, LDC: C2 */ ndrow2) ; #else BLAS_zgemm ("N", "C", ndrow3, ndrow1, ndcol, /* M, N, K */ one, /* ALPHA: 1 */ Lx + L_ENTRY*(pdx1 + ndrow1),/* A, LDA: L2, ndrow */ ndrow, Lx + L_ENTRY*pdx1, /* B, LDB: L1, ndrow */ ndrow, zero, /* BETA: 0 */ C + L_ENTRY*ndrow1, /* C, LDC: C2 */ ndrow2) ; #endif } DEBUG (CHOLMOD(dump_real) ("C", C, ndrow2, ndrow1, TRUE, L_ENTRY, Common)) ; /* -------------------------------------------------------------- */ /* construct relative map to assemble d into s */ /* -------------------------------------------------------------- */ for (i = 0 ; i < ndrow2 ; i++) { RelativeMap [i] = Map [Ls [pdi1 + i]] ; ASSERT (RelativeMap [i] >= 0 && RelativeMap [i] < nsrow) ; } /* -------------------------------------------------------------- */ /* assemble C into supernode s using the relative map */ /* -------------------------------------------------------------- */ pj = 0 ; for (j = 0 ; j < ndrow1 ; j++) /* cols k1:k2-1 */ { ASSERT (RelativeMap [j] == Map [Ls [pdi1 + j]]) ; ASSERT (RelativeMap [j] >= 0 && RelativeMap [j] < nscol) ; px = psx + RelativeMap [j] * nsrow ; for (i = j ; i < ndrow2 ; i++) /* rows k1:n-1 */ { ASSERT (RelativeMap [i] == Map [Ls [pdi1 + i]]) ; ASSERT (RelativeMap [i] >= j && RelativeMap [i] < nsrow) ; /* Lx [px + RelativeMap [i]] -= C [i + pj] ; */ q = px + RelativeMap [i] ; L_ASSEMBLESUB (Lx,q, C, i+pj) ; } pj += ndrow2 ; } /* -------------------------------------------------------------- */ /* prepare this supernode d for its next ancestor */ /* -------------------------------------------------------------- */ dnext = Next [d] ; if (!repeat_supernode) { /* If node s is being repeated, Head [dancestor] has already * been cleared (set to EMPTY). It must remain EMPTY. The * dancestor will not be factorized since the factorization * terminates at node s. */ Lpos [d] = pdi2 - pdi ; if (Lpos [d] < ndrow) { dancestor = SuperMap [Ls [pdi2]] ; ASSERT (dancestor > s && dancestor < nsuper) ; /* place d in the link list of its next ancestor */ Next [d] = Head [dancestor] ; Head [dancestor] = d ; } } } PRINT1 (("\nSupernode with contributions A: repeat: "ID"\n", repeat_supernode)) ; DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, Common)) ; PRINT1 (("\n\n")) ; /* ------------------------------------------------------------------ */ /* factorize diagonal block of supernode s in LL' */ /* ------------------------------------------------------------------ */ /* The current supernode s is ready to factorize. It has been updated * by all descendant supernodes. Let S = the current supernode, which * holds rows k1:n-1 and columns k1:k2-1 of the updated matrix. It * splits into two parts: the square diagonal block S1, and the * rectangular part S2. Here, S1 is factorized into L1*L1' and * overwritten by S1. * * If supernode s is being repeated, only factorize it up to but not * including the column containing the problematic entry. */ nscol2 = (repeat_supernode) ? (nscol_new) : (nscol) ; #ifdef REAL LAPACK_dpotrf ("L", nscol2, /* N: nscol2 */ Lx + L_ENTRY*psx, nsrow, /* A, LDA: S1, nsrow */ info) ; /* INFO */ #else LAPACK_zpotrf ("L", nscol2, /* N: nscol2 */ Lx + L_ENTRY*psx, nsrow, /* A, LDA: S1, nsrow */ info) ; /* INFO */ #endif /* ------------------------------------------------------------------ */ /* check if the matrix is not positive definite */ /* ------------------------------------------------------------------ */ if (repeat_supernode) { /* the leading part has been refactorized; it must have succeeded */ info = 0 ; /* zero out the rest of this supernode */ p = psx + nsrow * nscol_new ; pend = psx + nsrow * nscol ; /* s is nsrow-by-nscol */ for ( ; p < pend ; p++) { /* Lx [p] = 0 ; */ L_CLEAR (Lx,p) ; } } /* info is set to one in LAPACK_*potrf if blas_ok is FALSE. It is * set to zero in dpotrf/zpotrf if the factorization was successful. */ if (CHECK_BLAS_INT && !Common->blas_ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; } if (info != 0) { /* Matrix is not positive definite. dpotrf/zpotrf do NOT report an * error if the diagonal of L has NaN's, only if it has a zero. */ if (Common->status == CHOLMOD_OK) { ERROR (CHOLMOD_NOT_POSDEF, "matrix not positive definite") ; } /* L->minor is the column of L that contains a zero or negative * diagonal term. */ L->minor = k1 + info - 1 ; /* clear the link lists of all subsequent supernodes */ for (ss = s+1 ; ss < nsuper ; ss++) { Head [ss] = EMPTY ; } /* zero this supernode, and all remaining supernodes */ pend = L->xsize ; for (p = psx ; p < pend ; p++) { /* Lx [p] = 0. ; */ L_CLEAR (Lx,p) ; } /* If L is indefinite, it still contains useful information. * Supernodes 0 to s-1 are valid, similar to MATLAB [R,p]=chol(A), * where the 1-based p is identical to the 0-based L->minor. Since * L->minor is in the current supernode s, it and any columns to the * left of it in supernode s are also all zero. This differs from * [R,p]=chol(A), which contains nonzero rows 1 to p-1. Fix this * by setting repeat_supernode to TRUE, and repeating supernode s. * * If Common->quick_return_if_not_posdef is true, then the entire * supernode s is not factorized; it is left as all zero. */ if (info == 1 || Common->quick_return_if_not_posdef) { /* If the first column of supernode s contains a zero or * negative diagonal entry, then it is already properly set to * zero. Also, info will be 1 if integer overflow occured in * the BLAS. */ Head [s] = EMPTY ; return (Common->status >= CHOLMOD_OK) ; } else { /* Repeat supernode s, but only factorize it up to but not * including the column containing the problematic diagonal * entry. */ repeat_supernode = TRUE ; s-- ; nscol_new = info - 1 ; continue ; } } /* ------------------------------------------------------------------ */ /* compute the subdiagonal block and prepare supernode for its parent */ /* ------------------------------------------------------------------ */ nsrow2 = nsrow - nscol2 ; if (nsrow2 > 0) { /* The current supernode is columns k1 to k2-1 of L. Let L1 be the * diagonal block (factorized by dpotrf/zpotrf above; rows/cols * k1:k2-1), and L2 be rows k2:n-1 and columns k1:k2-1 of L. The * triangular system to solve is L2*L1' = S2, where S2 is * overwritten with L2. More precisely, L2 = S2 / L1' in MATLAB * notation. */ #ifdef REAL BLAS_dtrsm ("R", "L", "C", "N", nsrow2, nscol2, /* M, N */ one, /* ALPHA: 1 */ Lx + L_ENTRY*psx, nsrow, /* A, LDA: L1, nsrow */ Lx + L_ENTRY*(psx + nscol2), /* B, LDB, L2, nsrow */ nsrow) ; #else BLAS_ztrsm ("R", "L", "C", "N", nsrow2, nscol2, /* M, N */ one, /* ALPHA: 1 */ Lx + L_ENTRY*psx, nsrow, /* A, LDA: L1, nsrow */ Lx + L_ENTRY*(psx + nscol2), /* B, LDB, L2, nsrow */ nsrow) ; #endif if (CHECK_BLAS_INT && !Common->blas_ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; } if (!repeat_supernode) { /* Lpos [s] is offset of first row of s affecting its parent */ Lpos [s] = nscol ; sparent = SuperMap [Ls [psi + nscol]] ; ASSERT (sparent != EMPTY) ; ASSERT (Ls [psi + nscol] >= Super [sparent]) ; ASSERT (Ls [psi + nscol] < Super [sparent+1]) ; ASSERT (SuperMap [Ls [psi + nscol]] == sparent) ; ASSERT (sparent > s && sparent < nsuper) ; /* place s in link list of its parent */ Next [s] = Head [sparent] ; Head [sparent] = s ; } } Head [s] = EMPTY ; /* link list for supernode s no longer needed */ /* clear the Map (debugging only, to detect changes in pattern of A) */ DEBUG (for (k = 0 ; k < nsrow ; k++) Map [Ls [psi + k]] = EMPTY) ; DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY, Common)) ; if (repeat_supernode) { /* matrix is not positive definite; finished clean-up for supernode * containing negative diagonal */ return (Common->status >= CHOLMOD_OK) ; } } /* success; matrix is positive definite */ L->minor = n ; return (Common->status >= CHOLMOD_OK) ; } #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/License.txt0000644000175000017500000000204611674452555022652 0ustar sonnesonneCHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://www.cise.ufl.edu/research/sparse Note that this license is for the CHOLMOD/Supernodal module only. All CHOLMOD modules are licensed separately. -------------------------------------------------------------------------------- This Module is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This Module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_numeric.c0000644000175000017500000002516611674452555025270 0ustar sonnesonne/* ========================================================================== */ /* === Supernodal/cholmod_super_numeric ===================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Computes the Cholesky factorization of A+beta*I or A*F+beta*I. Only the * the lower triangular part of A+beta*I or A*F+beta*I is accessed. The * matrices A and F must already be permuted according to the fill-reduction * permutation L->Perm. cholmod_factorize is an "easy" wrapper for this code * which applies that permutation. beta is real. * * Symmetric case: A is a symmetric (lower) matrix. F is not accessed. * With a fill-reducing permutation, A(p,p) should be passed instead, where is * p is L->Perm. * * Unsymmetric case: A is unsymmetric, and F must be present. Normally, F=A'. * With a fill-reducing permutation, A(p,f) and A(p,f)' should be passed as A * and F, respectively, where f is a list of the subset of the columns of A. * * The input factorization L must be supernodal (L->is_super is TRUE). It can * either be symbolic or numeric. In the first case, L has been analyzed by * cholmod_analyze or cholmod_super_symbolic, but the matrix has not yet been * numerically factorized. The numerical values are allocated here and the * factorization is computed. In the second case, a prior matrix has been * analyzed and numerically factorized, and a new matrix is being factorized. * The numerical values of L are replaced with the new numerical factorization. * * L->is_ll is ignored, and set to TRUE. This routine always computes an LL' * factorization. Supernodal LDL' factorization is not (yet) supported. * FUTURE WORK: perform a supernodal LDL' factorization if L->is_ll is FALSE. * * Uses BLAS routines dsyrk, dgemm, dtrsm, and the LAPACK routine dpotrf. * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm. * * If the matrix is not positive definite the routine returns TRUE, but sets * Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the column at * which the failure occurred. The supernode containing the non-positive * diagonal entry is set to zero (this includes columns to the left of L->minor * in the same supernode), as are all subsequent supernodes. * * workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow + 4*nsuper). * Allocates temporary space of size L->maxcsize * sizeof(double) * (twice that for the complex/zomplex case). * * If L is supernodal symbolic on input, it is converted to a supernodal numeric * factor on output, with an xtype of real if A is real, or complex if A is * complex or zomplex. If L is supernodal numeric on input, its xtype must * match A (except that L can be complex and A zomplex). The xtype of A and F * must match. */ #ifndef NSUPERNODAL #include "cholmod_internal.h" #include "cholmod_supernodal.h" /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define REAL #include "t_cholmod_super_numeric.c" #define COMPLEX #include "t_cholmod_super_numeric.c" #define ZOMPLEX #include "t_cholmod_super_numeric.c" /* ========================================================================== */ /* === cholmod_super_numeric ================================================ */ /* ========================================================================== */ /* Returns TRUE if successful, or if the matrix is not positive definite. * Returns FALSE if out of memory, inputs are invalid, or other fatal error * occurs. */ int CHOLMOD(super_numeric) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to factorize */ cholmod_sparse *F, /* F = A' or A(:,f)' */ double beta [2], /* beta*I is added to diagonal of matrix to factorize */ /* ---- in/out --- */ cholmod_factor *L, /* factorization */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *C ; Int *Super, *Map, *SuperMap ; size_t maxcsize ; Int nsuper, n, i, k, s, stype, nrow ; int ok = TRUE, symbolic ; size_t t, w ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_COMPLEX, FALSE) ; stype = A->stype ; if (stype < 0) { if (A->nrow != A->ncol || A->nrow != L->n) { ERROR (CHOLMOD_INVALID, "invalid dimensions") ; return (FALSE) ; } } else if (stype == 0) { if (A->nrow != L->n) { ERROR (CHOLMOD_INVALID, "invalid dimensions") ; return (FALSE) ; } RETURN_IF_NULL (F, FALSE) ; RETURN_IF_XTYPE_INVALID (F, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; if (A->nrow != F->ncol || A->ncol != F->nrow || F->stype != 0) { ERROR (CHOLMOD_INVALID, "F invalid") ; return (FALSE) ; } if (A->xtype != F->xtype) { ERROR (CHOLMOD_INVALID, "A and F must have same xtype") ; return (FALSE) ; } } else { /* symmetric upper case not suppored */ ERROR (CHOLMOD_INVALID, "symmetric upper case not supported") ; return (FALSE) ; } if (!(L->is_super)) { ERROR (CHOLMOD_INVALID, "L not supernodal") ; return (FALSE) ; } if (L->xtype != CHOLMOD_PATTERN) { if (! ((A->xtype == CHOLMOD_REAL && L->xtype == CHOLMOD_REAL) || (A->xtype == CHOLMOD_COMPLEX && L->xtype == CHOLMOD_COMPLEX) || (A->xtype == CHOLMOD_ZOMPLEX && L->xtype == CHOLMOD_COMPLEX))) { ERROR (CHOLMOD_INVALID, "complex type mismatch") ; return (FALSE) ; } } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace in Common */ /* ---------------------------------------------------------------------- */ nsuper = L->nsuper ; maxcsize = L->maxcsize ; nrow = A->nrow ; n = nrow ; PRINT1 (("nsuper "ID" maxcsize %g\n", nsuper, (double) maxcsize)) ; ASSERT (nsuper >= 0 && maxcsize > 0) ; /* w = 2*n + 4*nsuper */ w = CHOLMOD(mult_size_t) (n, 2, &ok) ; t = CHOLMOD(mult_size_t) (nsuper, 4, &ok) ; w = CHOLMOD(add_size_t) (w, t, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (n, w, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get the current factor L and allocate numerical part, if needed */ /* ---------------------------------------------------------------------- */ Super = L->super ; symbolic = (L->xtype == CHOLMOD_PATTERN) ; if (symbolic) { /* convert to supernodal numeric by allocating L->x */ CHOLMOD(change_factor) ( (A->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX, TRUE, TRUE, TRUE, TRUE, L, Common) ; if (Common->status < CHOLMOD_OK) { /* the factor L remains in symbolic supernodal form */ return (FALSE) ; } } ASSERT (L->dtype == DTYPE) ; ASSERT (L->xtype == CHOLMOD_REAL || L->xtype == CHOLMOD_COMPLEX) ; /* supernodal LDL' is not supported */ L->is_ll = TRUE ; /* ---------------------------------------------------------------------- */ /* get more workspace */ /* ---------------------------------------------------------------------- */ C = CHOLMOD(allocate_dense) (maxcsize, 1, maxcsize, L->xtype, Common) ; if (Common->status < CHOLMOD_OK) { int status = Common->status ; if (symbolic) { /* Change L back to symbolic, since the numeric values are not * initialized. This cannot fail. */ CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, Common) ; } /* the factor L is now back to the form it had on input */ Common->status = status ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ SuperMap = Common->Iwork ; /* size n (i/i/l) */ Map = Common->Flag ; /* size n, use Flag as workspace for Map array */ for (i = 0 ; i < n ; i++) { Map [i] = EMPTY ; } /* ---------------------------------------------------------------------- */ /* find the mapping of nodes to relaxed supernodes */ /* ---------------------------------------------------------------------- */ /* SuperMap [k] = s if column k is contained in supernode s */ for (s = 0 ; s < nsuper ; s++) { PRINT1 (("Super ["ID"] "ID" ncols "ID"\n", s, Super[s], Super[s+1]-Super[s])); for (k = Super [s] ; k < Super [s+1] ; k++) { SuperMap [k] = s ; PRINT2 (("relaxed SuperMap ["ID"] = "ID"\n", k, SuperMap [k])) ; } } /* ---------------------------------------------------------------------- */ /* supernodal numerical factorization, using template routine */ /* ---------------------------------------------------------------------- */ switch (A->xtype) { case CHOLMOD_REAL: ok = r_cholmod_super_numeric (A, F, beta, L, C, Common) ; break ; case CHOLMOD_COMPLEX: ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ; break ; case CHOLMOD_ZOMPLEX: /* This operates on complex L, not zomplex */ ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ; break ; } /* ---------------------------------------------------------------------- */ /* clear Common workspace, free temp workspace C, and return */ /* ---------------------------------------------------------------------- */ /* Flag array was used as workspace, clear it */ Common->mark = EMPTY ; /* CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; CHOLMOD(free_dense) (&C, Common) ; return (ok) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_solve.c0000644000175000017500000001571711674452555024757 0ustar sonnesonne/* ========================================================================== */ /* === Supernodal/cholmod_super_solve ======================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Solve Lx=b or L'x=b for a supernodal factorization. These routines do not * apply the permutation L->Perm. See cholmod_solve for a more general * interface that performs that operation. */ #ifndef NSUPERNODAL #include "cholmod_internal.h" #include "cholmod_supernodal.h" /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define REAL #include "t_cholmod_super_solve.c" #define COMPLEX #include "t_cholmod_super_solve.c" /* ========================================================================== */ /* === cholmod_super_lsolve ================================================= */ /* ========================================================================== */ /* Solve Lx=b where x and b are of size n-by-nrhs. b is overwritten by the * solution x. On input, b is stored in col-major order with leading dimension * of d, and on output x is stored in the same manner. * * The contents of the workspace E are undefined on both input and output. * * workspace: none */ int CHOLMOD(super_lsolve) /* TRUE if OK, FALSE if BLAS overflow occured */ ( /* ---- input ---- */ cholmod_factor *L, /* factor to use for the forward solve */ /* ---- output ---- */ cholmod_dense *X, /* b on input, solution to Lx=b on output */ /* ---- workspace ---- */ cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_NULL (X, FALSE) ; RETURN_IF_NULL (E, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; if (L->xtype != X->xtype) { ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ; return (FALSE) ; } if (L->xtype != E->xtype) { ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ; return (FALSE) ; } if (X->d < X->nrow || L->n != X->nrow) { ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ; return (FALSE) ; } if (E->nzmax < X->ncol * (L->maxesize)) { ERROR (CHOLMOD_INVALID, "workspace E not large enough") ; return (FALSE) ; } if (!(L->is_ll) || !(L->is_super)) { ERROR (CHOLMOD_INVALID, "L not supernodal") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ; if (L->n == 0 || X->ncol == 0) { /* nothing to do */ return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* solve Lx=b using template routine */ /* ---------------------------------------------------------------------- */ switch (L->xtype) { case CHOLMOD_REAL: r_cholmod_super_lsolve (L, X, E, Common) ; break ; case CHOLMOD_COMPLEX: c_cholmod_super_lsolve (L, X, E, Common) ; break ; } if (CHECK_BLAS_INT && !Common->blas_ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; } return (Common->blas_ok) ; } /* ========================================================================== */ /* === cholmod_super_ltsolve ================================================ */ /* ========================================================================== */ /* Solve L'x=b where x and b are of size n-by-nrhs. b is overwritten by the * solution x. On input, b is stored in col-major order with leading dimension * of d, and on output x is stored in the same manner. * * The contents of the workspace E are undefined on both input and output. * * workspace: none */ int CHOLMOD(super_ltsolve) /* TRUE if OK, FALSE if BLAS overflow occured */ ( /* ---- input ---- */ cholmod_factor *L, /* factor to use for the backsolve */ /* ---- output ---- */ cholmod_dense *X, /* b on input, solution to L'x=b on output */ /* ---- workspace ---- */ cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_NULL (X, FALSE) ; RETURN_IF_NULL (E, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ; if (L->xtype != X->xtype) { ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ; return (FALSE) ; } if (L->xtype != E->xtype) { ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ; return (FALSE) ; } if (X->d < X->nrow || L->n != X->nrow) { ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ; return (FALSE) ; } if (E->nzmax < X->ncol * (L->maxesize)) { ERROR (CHOLMOD_INVALID, "workspace E not large enough") ; return (FALSE) ; } if (!(L->is_ll) || !(L->is_super)) { ERROR (CHOLMOD_INVALID, "L not supernodal") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ; if (L->n == 0 || X->ncol == 0) { /* nothing to do */ return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* solve Lx=b using template routine */ /* ---------------------------------------------------------------------- */ switch (L->xtype) { case CHOLMOD_REAL: r_cholmod_super_ltsolve (L, X, E, Common) ; break ; case CHOLMOD_COMPLEX: c_cholmod_super_ltsolve (L, X, E, Common) ; break ; } if (CHECK_BLAS_INT && !Common->blas_ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ; } return (Common->blas_ok) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/t_cholmod_super_solve.c0000644000175000017500000002560211674452555025274 0ustar sonnesonne/* ========================================================================== */ /* === Supernodal/t_cholmod_super_solve ===================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_super_solve. Supports real or complex L. */ #include "cholmod_template.h" static void TEMPLATE (cholmod_super_lsolve) ( /* ---- input ---- */ cholmod_factor *L, /* factor to use for the forward solve */ /* ---- output ---- */ cholmod_dense *X, /* b on input, solution to Lx=b on output */ /* ---- workspace ---- */ cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ /* --------------- */ cholmod_common *Common ) { double *Lx, *Xx, *Ex ; double minus_one [2], one [2] ; Int *Lpi, *Lpx, *Ls, *Super ; Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s, nsrow2, n, ps2, j, i, d, nrhs ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrhs = X->ncol ; Ex = E->x ; Xx = X->x ; n = L->n ; d = X->d ; nsuper = L->nsuper ; Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; Super = L->super ; Lx = L->x ; minus_one [0] = -1.0 ; minus_one [1] = 0 ; one [0] = 1.0 ; one [1] = 0 ; /* ---------------------------------------------------------------------- */ /* solve Lx=b */ /* ---------------------------------------------------------------------- */ if (nrhs == 1) { for (s = 0 ; s < nsuper ; s++) { k1 = Super [s] ; k2 = Super [s+1] ; psi = Lpi [s] ; psend = Lpi [s+1] ; psx = Lpx [s] ; nsrow = psend - psi ; nscol = k2 - k1 ; nsrow2 = nsrow - nscol ; ps2 = psi + nscol ; ASSERT ((size_t) nsrow2 <= L->maxesize) ; /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal. * L2 is nsrow2-by-nscol. L1 and L2 have leading dimension of * nsrow. x1 is nscol-by-nsrow, with leading dimension n. * E is nsrow2-by-1, with leading dimension nsrow2. */ /* gather X into E */ for (ii = 0 ; ii < nsrow2 ; ii++) { /* Ex [ii] = Xx [Ls [ps2 + ii]] ; */ ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ; } #ifdef REAL /* solve L1*x1 (that is, x1 = L1\x1) */ BLAS_dtrsv ("L", "N", "N", nscol, /* N: L1 is nscol-by-nscol */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, 1) ; /* X, INCX: x1 */ /* E = E - L2*x1 */ BLAS_dgemv ("N", nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ one, /* BETA: 1 */ Ex, 1) ; /* Y, INCY: E */ #else /* solve L1*x1 (that is, x1 = L1\x1) */ BLAS_ztrsv ("L", "N", "N", nscol, /* N: L1 is nscol-by-nscol */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, 1) ; /* X, INCX: x1 */ /* E = E - L2*x1 */ BLAS_zgemv ("N", nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Xx + ENTRY_SIZE*k1, 1, /* X, INCX: x1 */ one, /* BETA: 1 */ Ex, 1) ; /* Y, INCY: E */ #endif /* scatter E back into X */ for (ii = 0 ; ii < nsrow2 ; ii++) { /* Xx [Ls [ps2 + ii]] = Ex [ii] ; */ ASSIGN (Xx,-,Ls [ps2 + ii], Ex,-,ii) ; } } } else { for (s = 0 ; s < nsuper ; s++) { k1 = Super [s] ; k2 = Super [s+1] ; psi = Lpi [s] ; psend = Lpi [s+1] ; psx = Lpx [s] ; nsrow = psend - psi ; nscol = k2 - k1 ; nsrow2 = nsrow - nscol ; ps2 = psi + nscol ; ASSERT ((size_t) nsrow2 <= L->maxesize) ; /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */ /* gather X into E */ for (ii = 0 ; ii < nsrow2 ; ii++) { i = Ls [ps2 + ii] ; for (j = 0 ; j < nrhs ; j++) { /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */ ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ; } } #ifdef REAL /* solve L1*x1 */ BLAS_dtrsm ("L", "L", "N", "N", nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ one, /* ALPHA: 1 */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, d) ; /* B, LDB: x1 */ /* E = E - L2*x1 */ if (nsrow2 > 0) { BLAS_dgemm ("N", "N", nsrow2, nrhs, nscol, /* M, N, K */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Xx + ENTRY_SIZE*k1, d, /* B, LDB: X1 */ one, /* BETA: 1 */ Ex, nsrow2) ; /* C, LDC: E */ } #else /* solve L1*x1 */ BLAS_ztrsm ("L", "L", "N", "N", nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ one, /* ALPHA: 1 */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, d) ; /* B, LDB: x1 */ /* E = E - L2*x1 */ if (nsrow2 > 0) { BLAS_zgemm ("N", "N", nsrow2, nrhs, nscol, /* M, N, K */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Xx + ENTRY_SIZE*k1, d, /* B, LDB: X1 */ one, /* BETA: 1 */ Ex, nsrow2) ; /* C, LDC: E */ } #endif /* scatter E back into X */ for (ii = 0 ; ii < nsrow2 ; ii++) { i = Ls [ps2 + ii] ; for (j = 0 ; j < nrhs ; j++) { /* Xx [i + j*d] = Ex [ii + j*nsrow2] ; */ ASSIGN (Xx,-,i+j*d, Ex,-,ii+j*nsrow2) ; } } } } } static void TEMPLATE (cholmod_super_ltsolve) ( /* ---- input ---- */ cholmod_factor *L, /* factor to use for the forward solve */ /* ---- output ---- */ cholmod_dense *X, /* b on input, solution to Lx=b on output */ /* ---- workspace ---- */ cholmod_dense *E, /* workspace of size nrhs*(L->maxesize) */ /* --------------- */ cholmod_common *Common ) { double *Lx, *Xx, *Ex ; double minus_one [2], one [2] ; Int *Lpi, *Lpx, *Ls, *Super ; Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s, nsrow2, n, ps2, j, i, d, nrhs ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrhs = X->ncol ; Ex = E->x ; Xx = X->x ; n = L->n ; d = X->d ; nsuper = L->nsuper ; Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; Super = L->super ; Lx = L->x ; minus_one [0] = -1.0 ; minus_one [1] = 0 ; one [0] = 1.0 ; one [1] = 0 ; /* ---------------------------------------------------------------------- */ /* solve L'x=b */ /* ---------------------------------------------------------------------- */ if (nrhs == 1) { for (s = nsuper-1 ; s >= 0 ; s--) { k1 = Super [s] ; k2 = Super [s+1] ; psi = Lpi [s] ; psend = Lpi [s+1] ; psx = Lpx [s] ; nsrow = psend - psi ; nscol = k2 - k1 ; nsrow2 = nsrow - nscol ; ps2 = psi + nscol ; ASSERT ((size_t) nsrow2 <= L->maxesize) ; /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal. * L2 is nsrow2-by-nscol. L1 and L2 have leading dimension of * nsrow. x1 is nscol-by-nsrow, with leading dimension n. * E is nsrow2-by-1, with leading dimension nsrow2. */ /* gather X into E */ for (ii = 0 ; ii < nsrow2 ; ii++) { /* Ex [ii] = Xx [Ls [ps2 + ii]] ; */ ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ; } #ifdef REAL /* x1 = x1 - L2'*E */ BLAS_dgemv ("C", nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Ex, 1, /* X, INCX: Ex */ one, /* BETA: 1 */ Xx + ENTRY_SIZE*k1, 1) ; /* Y, INCY: x1 */ /* solve L1'*x1 */ BLAS_dtrsv ("L", "C", "N", nscol, /* N: L1 is nscol-by-nscol */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, 1) ; /* X, INCX: x1 */ #else /* x1 = x1 - L2'*E */ BLAS_zgemv ("C", nsrow2, nscol, /* M, N: L2 is nsrow2-by-nscol */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Ex, 1, /* X, INCX: Ex */ one, /* BETA: 1 */ Xx + ENTRY_SIZE*k1, 1) ; /* Y, INCY: x1 */ /* solve L1'*x1 */ BLAS_ztrsv ("L", "C", "N", nscol, /* N: L1 is nscol-by-nscol */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, 1) ; /* X, INCX: x1 */ #endif } } else { for (s = nsuper-1 ; s >= 0 ; s--) { k1 = Super [s] ; k2 = Super [s+1] ; psi = Lpi [s] ; psend = Lpi [s+1] ; psx = Lpx [s] ; nsrow = psend - psi ; nscol = k2 - k1 ; nsrow2 = nsrow - nscol ; ps2 = psi + nscol ; ASSERT ((size_t) nsrow2 <= L->maxesize) ; /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */ /* gather X into E */ for (ii = 0 ; ii < nsrow2 ; ii++) { i = Ls [ps2 + ii] ; for (j = 0 ; j < nrhs ; j++) { /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */ ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ; } } #ifdef REAL /* x1 = x1 - L2'*E */ if (nsrow2 > 0) { BLAS_dgemm ("C", "N", nscol, nrhs, nsrow2, /* M, N, K */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Ex, nsrow2, /* B, LDB: E */ one, /* BETA: 1 */ Xx + ENTRY_SIZE*k1, d) ; /* C, LDC: x1 */ } /* solve L1'*x1 */ BLAS_dtrsm ("L", "L", "C", "N", nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ one, /* ALPHA: 1 */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, d) ; /* B, LDB: x1 */ #else /* x1 = x1 - L2'*E */ if (nsrow2 > 0) { BLAS_zgemm ("C", "N", nscol, nrhs, nsrow2, /* M, N, K */ minus_one, /* ALPHA: -1 */ Lx + ENTRY_SIZE*(psx + nscol), /* A, LDA: L2 */ nsrow, Ex, nsrow2, /* B, LDB: E */ one, /* BETA: 1 */ Xx + ENTRY_SIZE*k1, d) ; /* C, LDC: x1 */ } /* solve L1'*x1 */ BLAS_ztrsm ("L", "L", "C", "N", nscol, nrhs, /* M, N: x1 is nscol-by-nrhs */ one, /* ALPHA: 1 */ Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA: L1 */ Xx + ENTRY_SIZE*k1, d) ; /* B, LDB: x1 */ #endif } } } #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/gpl.txt0000644000175000017500000004313311674452555022054 0ustar sonnesonne GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Supernodal/cholmod_super_symbolic.c0000644000175000017500000007177611674452555025457 0ustar sonnesonne/* ========================================================================== */ /* === Supernodal/cholmod_super_symbolic ==================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU * General Public License. See gpl.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Supernodal symbolic analysis of the LL' factorization of A, A*A', * A(:,f)*A(:,f)'. * * This routine must be preceded by a simplicial symbolic analysis * (cholmod_rowcolcounts). See cholmod_analyze.c for an example of how to use * this routine. * * The user need not call this directly; cholmod_analyze is a "simple" wrapper * for this routine. * * Symmetric case: * * A is stored in column form, with entries stored in the upper triangular * part. Entries in the lower triangular part are ignored. * * Unsymmetric case: * * A is stored in column form. If F is equal to the transpose of A, then * A*A' is analyzed. F can include a subset of the columns of A * (F=A(:,f)'), in which case F*F' is analyzed. * * Requires Parent and L->ColCount to be defined on input; these are the * simplicial Parent and ColCount arrays as computed by cholmod_rowcolcounts. * Does not use L->Perm; the input matrices A and F must already be properly * permuted. Allocates and computes the supernodal pattern of L (L->super, * L->pi, L->px, and L->s). Does not allocate the real part (L->x). * * Supports any xtype (pattern, real, complex, or zomplex). */ #ifndef NSUPERNODAL #include "cholmod_internal.h" #include "cholmod_supernodal.h" /* ========================================================================== */ /* === subtree ============================================================== */ /* ========================================================================== */ /* In the symmetric case, traverse the kth row subtree from the nonzeros in * A (0:k1-1,k) and add the new entries found to the pattern of the kth row * of L. The current supernode s contains the diagonal block k1:k2-1, so it * can be skipped. * * In the unsymmetric case, the nonzero pattern of A*F is computed one column * at a time (thus, the total time spent in this function is bounded below by * the time taken to multiply A*F, which can be high if A is tall and thin). * The kth column is A*F(:,k), or the set union of all columns A(:,j) for which * F(j,k) is nonzero. This routine is called once for each entry j. Only the * upper triangular part is needed, so only A (0:k1-1,j) is accessed, where * k1:k2-1 are the columns of the current supernode s (k is in the range k1 to * k2-1). * * If A is sorted, then the total time taken by this function is proportional * to the number of nonzeros in the strictly block upper triangular part of A, * plus the number of entries in the strictly block lower triangular part of * the supernodal part of L. This excludes entries in the diagonal blocks * corresponding to the columns in each supernode. That is, if k1:k2-1 are * in a single supernode, then only A (0:k1-1,k1:k2-1) are accessed. * * For the unsymmetric case, only the strictly block upper triangular part * of A*F is constructed. * * Only adds column indices corresponding to the leading columns of each * relaxed supernode. */ static void subtree ( /* inputs, not modified: */ Int j, /* j = k for symmetric case */ Int k, Int Ap [ ], Int Ai [ ], Int Anz [ ], Int SuperMap [ ], Int Sparent [ ], Int mark, Int sorted, /* true if the columns of A are sorted */ Int k1, /* only consider A (0:k1-1,k) */ /* input/output: */ Int Flag [ ], Int Ls [ ], Int Lpi2 [ ] ) { Int p, pend, i, si ; p = Ap [j] ; pend = (Anz == NULL) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i < k1) { /* (i,k) is an entry in the upper triangular part of A or A*F'. * symmetric case: A(i,k) is nonzero (j=k). * unsymmetric case: A(i,j) and F(j,k) are both nonzero. * * Column i is in supernode si = SuperMap [i]. Follow path from si * to root of supernodal etree, stopping at the first flagged * supernode. The root of the row subtree is supernode SuperMap[k], * which is flagged already. This traversal will stop there, or it * might stop earlier if supernodes have been flagged by previous * calls to this routine for the same k. */ for (si = SuperMap [i] ; Flag [si] < mark ; si = Sparent [si]) { ASSERT (si <= SuperMap [k]) ; Ls [Lpi2 [si]++] = k ; Flag [si] = mark ; } } else if (sorted) { break ; } } } /* clear workspace used by cholmod_super_symbolic */ #define FREE_WORKSPACE \ { \ /* CHOLMOD(clear_flag) (Common) ; */ \ CHOLMOD_CLEAR_FLAG (Common) ; \ for (k = 0 ; k <= nfsuper ; k++) \ { \ Head [k] = EMPTY ; \ } \ ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \ } \ /* ========================================================================== */ /* === cholmod_super_symbolic2 ============================================== */ /* ========================================================================== */ /* Analyze for supernodal Cholesky or multifrontal QR. CHOLMOD itself always * analyzes for supernodal Cholesky, of course. The "for_cholesky = TRUE" * option is used by SuiteSparseQR only. */ int CHOLMOD(super_symbolic2) ( /* ---- input ---- */ int for_cholesky, /* Cholesky if TRUE, QR if FALSE */ cholmod_sparse *A, /* matrix to analyze */ cholmod_sparse *F, /* F = A' or A(:,f)' */ Int *Parent, /* elimination tree */ /* ---- in/out --- */ cholmod_factor *L, /* simplicial symbolic on input, * supernodal symbolic on output */ /* --------------- */ cholmod_common *Common ) { double zrelax0, zrelax1, zrelax2, xxsize ; Int *Wi, *Wj, *Super, *Snz, *Ap, *Ai, *Flag, *Head, *Ls, *Lpi, *Lpx, *Fnz, *Sparent, *Anz, *SuperMap, *Merged, *Nscol, *Zeros, *Fp, *Fj, *ColCount, *Lpi2, *Lsuper, *Iwork ; Int nsuper, d, n, j, k, s, mark, parent, p, pend, k1, k2, packed, nscol, nsrow, ndrow1, ndrow2, stype, ssize, xsize, sparent, plast, slast, csize, maxcsize, ss, nscol0, nscol1, ns, nfsuper, newzeros, totzeros, merge, snext, esize, maxesize, nrelax0, nrelax1, nrelax2, Asorted ; size_t w ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_NULL (Parent, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_PATTERN, FALSE) ; stype = A->stype ; if (stype < 0) { /* invalid symmetry; symmetric lower form not supported */ ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ; return (FALSE) ; } if (stype == 0) { /* F must be present in the unsymmetric case */ RETURN_IF_NULL (F, FALSE) ; } if (L->is_super) { /* L must be a simplicial symbolic factor */ ERROR (CHOLMOD_INVALID, "L must be symbolic on input") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ n = A->nrow ; /* w = 5*n */ w = CHOLMOD(mult_size_t) (n, 5, &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (n, w, 0, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (FALSE) ; } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ /* A is now either A or triu(A(p,p)) for the symmetric case. It is either * A or A(p,f) for the unsymmetric case (both in column form). It can be * either packed or unpacked, and either sorted or unsorted. Entries in * the lower triangular part may be present if A is symmetric, but these * are ignored. */ Ap = A->p ; Ai = A->i ; Anz = A->nz ; if (stype != 0) { /* F not accessed */ Fp = NULL ; Fj = NULL ; Fnz = NULL ; packed = TRUE ; } else { /* F = A(:,f) or A(p,f) in packed row form, either sorted or unsorted */ Fp = F->p ; Fj = F->i ; Fnz = F->nz ; packed = F->packed ; } ColCount = L->ColCount ; nrelax0 = Common->nrelax [0] ; nrelax1 = Common->nrelax [1] ; nrelax2 = Common->nrelax [2] ; zrelax0 = Common->zrelax [0] ; zrelax1 = Common->zrelax [1] ; zrelax2 = Common->zrelax [2] ; zrelax0 = IS_NAN (zrelax0) ? 0 : zrelax0 ; zrelax1 = IS_NAN (zrelax1) ? 0 : zrelax1 ; zrelax2 = IS_NAN (zrelax2) ? 0 : zrelax2 ; ASSERT (CHOLMOD(dump_parent) (Parent, n, "Parent", Common)) ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ /* Sparent, Snz, and Merged could be allocated later, of size nfsuper */ Iwork = Common->Iwork ; Wi = Iwork ; /* size n (i/l/l). Lpi2 is i/l/l */ Wj = Iwork + n ; /* size n (i/l/l). Zeros is i/l/l */ Sparent = Iwork + 2*((size_t) n) ; /* size nfsuper <= n [ */ Snz = Iwork + 3*((size_t) n) ; /* size nfsuper <= n [ */ Merged = Iwork + 4*((size_t) n) ; /* size nfsuper <= n [ */ Flag = Common->Flag ; /* size n */ Head = Common->Head ; /* size n+1 */ /* ---------------------------------------------------------------------- */ /* find the fundamental supernodes */ /* ---------------------------------------------------------------------- */ /* count the number of children of each node, using Wi [ */ for (j = 0 ; j < n ; j++) { Wi [j] = 0 ; } for (j = 0 ; j < n ; j++) { parent = Parent [j] ; if (parent != EMPTY) { Wi [parent]++ ; } } Super = Head ; /* use Head [0..nfsuper] as workspace for Super list ( */ /* column 0 always starts a new supernode */ nfsuper = (n == 0) ? 0 : 1 ; /* number of fundamental supernodes */ Super [0] = 0 ; for (j = 1 ; j < n ; j++) { /* check if j starts new supernode, or in the same supernode as j-1 */ if (Parent [j-1] != j /* parent of j-1 is not j */ || (ColCount [j-1] != ColCount [j] + 1) /* j-1 not subset of j*/ || Wi [j] > 1) /* j has more than one child */ { /* j is the leading node of a supernode */ Super [nfsuper++] = j ; } } Super [nfsuper] = n ; /* contents of Wi no longer needed for child count ] */ Nscol = Wi ; /* use Wi as size-nfsuper workspace for Nscol [ */ /* ---------------------------------------------------------------------- */ /* find the mapping of fundamental nodes to supernodes */ /* ---------------------------------------------------------------------- */ SuperMap = Wj ; /* use Wj as workspace for SuperMap [ */ /* SuperMap [k] = s if column k is contained in supernode s */ for (s = 0 ; s < nfsuper ; s++) { for (k = Super [s] ; k < Super [s+1] ; k++) { SuperMap [k] = s ; } } /* ---------------------------------------------------------------------- */ /* construct the fundamental supernodal etree */ /* ---------------------------------------------------------------------- */ for (s = 0 ; s < nfsuper ; s++) { j = Super [s+1] - 1 ; /* last node in supernode s */ parent = Parent [j] ; /* parent of last node */ Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ; PRINT1 (("Sparent ["ID"] = "ID"\n", s, Sparent [s])) ; } /* contents of Wj no longer needed as workspace for SuperMap ] * SuperMap will be recomputed below, for the relaxed supernodes. */ Zeros = Wj ; /* use Wj for Zeros, workspace of size nfsuper [ */ /* ---------------------------------------------------------------------- */ /* relaxed amalgamation */ /* ---------------------------------------------------------------------- */ for (s = 0 ; s < nfsuper ; s++) { Merged [s] = EMPTY ; /* s not merged into another */ Nscol [s] = Super [s+1] - Super [s] ; /* # of columns in s */ Zeros [s] = 0 ; /* # of zero entries in s */ ASSERT (s <= Super [s]) ; Snz [s] = ColCount [Super [s]] ; /* # of entries in leading col of s */ PRINT2 (("lnz ["ID"] "ID"\n", s, Snz [s])) ; } for (s = nfsuper-2 ; s >= 0 ; s--) { /* should supernodes s and s+1 merge into a new node s? */ PRINT1 (("\n========= Check relax of s "ID" and s+1 "ID"\n", s, s+1)) ; ss = Sparent [s] ; if (ss == EMPTY) { PRINT1 (("s "ID" is a root, no merge with s+1 = "ID"\n", s, s+1)) ; continue ; } /* find the current parent of s (perform path compression as needed) */ for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = Merged [ss]) ; sparent = ss ; PRINT2 (("Current sparent of s "ID" is "ID"\n", s, sparent)) ; /* ss is the current parent of s */ for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = snext) { snext = Merged [ss] ; PRINT2 (("ss "ID" is dead, merged into snext "ID"\n", ss, snext)) ; Merged [ss] = sparent ; } /* if s+1 is not the current parent of s, do not merge */ if (sparent != s+1) { continue ; } nscol0 = Nscol [s] ; /* # of columns in s */ nscol1 = Nscol [s+1] ; /* # of columns in s+1 */ ns = nscol0 + nscol1 ; PRINT2 (("ns "ID" nscol0 "ID" nscol1 "ID"\n", ns, nscol0, nscol1)) ; totzeros = Zeros [s+1] ; /* current # of zeros in s+1 */ /* determine if supernodes s and s+1 should merge */ if (ns <= nrelax0) { PRINT2 (("ns is tiny ("ID"), so go ahead and merge\n", ns)) ; merge = TRUE ; } else { /* use double to avoid integer overflow */ double lnz0 = Snz [s] ; /* # entries in leading column of s */ double lnz1 = Snz [s+1] ; /* # entries in leading column of s+1 */ double xnewzeros = nscol0 * (lnz1 + nscol0 - lnz0) ; /* use Int for the final update of Zeros [s] below */ newzeros = nscol0 * (Snz [s+1] + nscol0 - Snz [s]) ; ASSERT (newzeros == xnewzeros) ; PRINT2 (("lnz0 %g lnz1 %g xnewzeros %g\n", lnz0, lnz1, xnewzeros)) ; if (xnewzeros == 0) { /* no new zeros, so go ahead and merge */ PRINT2 (("no new fillin, so go ahead and merge\n")) ; merge = TRUE ; } else { /* # of zeros if merged */ double xtotzeros = ((double) totzeros) + xnewzeros ; /* xtotsize: total size of merged supernode, if merged: */ double xns = (double) ns ; double xtotsize = (xns * (xns+1) / 2) + xns * (lnz1 - nscol1) ; double z = xtotzeros / xtotsize ; Int totsize ; totsize = (ns * (ns+1) / 2) + ns * (Snz [s+1] - nscol1) ; PRINT2 (("oldzeros "ID" newzeros "ID" xtotsize %g z %g\n", Zeros [s+1], newzeros, xtotsize, z)) ; /* use Int for the final update of Zeros [s] below */ totzeros += newzeros ; /* do not merge if supernode would become too big * (Int overflow). Continue computing; not (yet) an error. */ /* fl.pt. compare, but no NaN's can occur here */ merge = ((ns <= nrelax1 && z < zrelax0) || (ns <= nrelax2 && z < zrelax1) || (z < zrelax2)) && (xtotsize < Int_max / sizeof (double)) ; } } if (merge) { PRINT1 (("Merge node s ("ID") and s+1 ("ID")\n", s, s+1)) ; Zeros [s] = totzeros ; Merged [s+1] = s ; Snz [s] = nscol0 + Snz [s+1] ; Nscol [s] += Nscol [s+1] ; } } /* contents of Wj no longer needed for Zeros ] */ /* contents of Wi no longer needed for Nscol ] */ /* contents of Sparent no longer needed (recomputed below) */ /* ---------------------------------------------------------------------- */ /* construct the relaxed supernode list */ /* ---------------------------------------------------------------------- */ nsuper = 0 ; for (s = 0 ; s < nfsuper ; s++) { if (Merged [s] == EMPTY) { PRINT1 (("live supernode: "ID" snz "ID"\n", s, Snz [s])) ; Super [nsuper] = Super [s] ; Snz [nsuper] = Snz [s] ; nsuper++ ; } } Super [nsuper] = n ; PRINT1 (("Fundamental supernodes: "ID" relaxed "ID"\n", nfsuper, nsuper)) ; /* Merged no longer needed ] */ /* ---------------------------------------------------------------------- */ /* find the mapping of relaxed nodes to supernodes */ /* ---------------------------------------------------------------------- */ /* use Wj as workspace for SuperMap { */ /* SuperMap [k] = s if column k is contained in supernode s */ for (s = 0 ; s < nsuper ; s++) { for (k = Super [s] ; k < Super [s+1] ; k++) { SuperMap [k] = s ; } } /* ---------------------------------------------------------------------- */ /* construct the relaxed supernodal etree */ /* ---------------------------------------------------------------------- */ for (s = 0 ; s < nsuper ; s++) { j = Super [s+1] - 1 ; /* last node in supernode s */ parent = Parent [j] ; /* parent of last node */ Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ; PRINT1 (("new Sparent ["ID"] = "ID"\n", s, Sparent [s])) ; } /* ---------------------------------------------------------------------- */ /* determine the size of L->s and L->x */ /* ---------------------------------------------------------------------- */ ssize = 0 ; xsize = 0 ; xxsize = 0 ; for (s = 0 ; s < nsuper ; s++) { nscol = Super [s+1] - Super [s] ; nsrow = Snz [s] ; ASSERT (nscol > 0) ; ssize += nsrow ; if (for_cholesky) { xsize += nscol * nsrow ; /* also compute xsize in double to guard against Int overflow */ xxsize += ((double) nscol) * ((double) nsrow) ; } if (ssize < 0 || (for_cholesky && xxsize > Int_max)) { /* Int overflow, clear workspace and return. QR factorization will not use xxsize, so that error is ignored. For Cholesky factorization, however, memory of space xxsize will be allocated, so this is a failure. Both QR and Cholesky fail if ssize overflows. */ ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; FREE_WORKSPACE ; return (FALSE) ; } ASSERT (ssize > 0) ; ASSERT (IMPLIES (for_cholesky, xsize > 0)) ; } xsize = MAX (1, xsize) ; ssize = MAX (1, ssize) ; PRINT1 (("ix sizes: "ID" "ID" nsuper "ID"\n", ssize, xsize, nsuper)) ; /* ---------------------------------------------------------------------- */ /* allocate L (all except real part L->x) */ /* ---------------------------------------------------------------------- */ L->ssize = ssize ; L->xsize = xsize ; L->nsuper = nsuper ; CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, Common); if (Common->status < CHOLMOD_OK) { /* out of memory; L is still a valid simplicial symbolic factor */ FREE_WORKSPACE ; return (FALSE) ; } DEBUG (CHOLMOD(dump_factor) (L, "L to symbolic super", Common)) ; ASSERT (L->is_ll && L->xtype == CHOLMOD_PATTERN && L->is_super) ; Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; Ls [0] = 0 ; /* flag for cholmod_check_factor; supernodes are defined */ Lpx [0] = for_cholesky ? 0 : 123456 ; /* magic number for sparse QR */ Lsuper = L->super ; /* copy the list of relaxed supernodes into the final list in L */ for (s = 0 ; s <= nsuper ; s++) { Lsuper [s] = Super [s] ; } /* Head no longer needed as workspace for fundamental Super list ) */ Super = Lsuper ; /* Super is now the list of relaxed supernodes */ /* ---------------------------------------------------------------------- */ /* construct column pointers of relaxed supernodal pattern (L->pi) */ /* ---------------------------------------------------------------------- */ p = 0 ; for (s = 0 ; s < nsuper ; s++) { Lpi [s] = p ; p += Snz [s] ; PRINT1 (("Snz ["ID"] = "ID", Super ["ID"] = "ID"\n", s, Snz [s], s, Super[s])) ; } Lpi [nsuper] = p ; ASSERT ((Int) (L->ssize) == MAX (1,p)) ; /* ---------------------------------------------------------------------- */ /* construct pointers for supernodal values (L->px) */ /* ---------------------------------------------------------------------- */ if (for_cholesky) { /* L->px is not needed for QR factorization (it may lead to Int overflow, anyway, if xsize caused Int overflow above) */ p = 0 ; for (s = 0 ; s < nsuper ; s++) { nscol = Super [s+1] - Super [s] ; /* number of columns in s */ nsrow = Snz [s] ; /* # of rows, incl triangular part*/ Lpx [s] = p ; /* pointer to numerical part of s */ p += nscol * nsrow ; } Lpx [s] = p ; ASSERT ((Int) (L->xsize) == MAX (1,p)) ; } /* Snz no longer needed ] */ /* ---------------------------------------------------------------------- */ /* symbolic analysis to construct the relaxed supernodal pattern (L->s) */ /* ---------------------------------------------------------------------- */ Lpi2 = Wi ; /* copy Lpi into Lpi2, using Wi as workspace for Lpi2 [ */ for (s = 0 ; s < nsuper ; s++) { Lpi2 [s] = Lpi [s] ; } Asorted = A->sorted ; for (s = 0 ; s < nsuper ; s++) { /* sth supernode is in columns k1 to k2-1. * compute nonzero pattern of L (k1:k2-1,:). */ /* place rows k1 to k2-1 in leading column of supernode s */ k1 = Super [s] ; k2 = Super [s+1] ; PRINT1 (("=========>>> Supernode "ID" k1 "ID" k2-1 "ID"\n", s, k1, k2-1)) ; for (k = k1 ; k < k2 ; k++) { Ls [Lpi2 [s]++] = k ; } /* compute nonzero pattern each row k1 to k2-1 */ for (k = k1 ; k < k2 ; k++) { /* compute row k of L. In the symmetric case, the pattern of L(k,:) * is the set of nodes reachable in the supernodal etree from any * row i in the nonzero pattern of A(0:k,k). In the unsymmetric * case, the pattern of the kth column of A*A' is the set union * of all columns A(0:k,j) for each nonzero F(j,k). */ /* clear the Flag array and mark the current supernode */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; Flag [s] = mark ; ASSERT (s == SuperMap [k]) ; /* traverse the row subtree for each nonzero in A or AA' */ if (stype != 0) { subtree (k, k, Ap, Ai, Anz, SuperMap, Sparent, mark, Asorted, k1, Flag, Ls, Lpi2) ; } else { /* for each j nonzero in F (:,k) do */ p = Fp [k] ; pend = (packed) ? (Fp [k+1]) : (p + Fnz [k]) ; for ( ; p < pend ; p++) { subtree (Fj [p], k, Ap, Ai, Anz, SuperMap, Sparent, mark, Asorted, k1, Flag, Ls, Lpi2) ; } } } } #ifndef NDEBUG for (s = 0 ; s < nsuper ; s++) { PRINT1 (("Lpi2[s] "ID" Lpi[s+1] "ID"\n", Lpi2 [s], Lpi [s+1])) ; ASSERT (Lpi2 [s] == Lpi [s+1]) ; CHOLMOD(dump_super) (s, Super, Lpi, Ls, NULL, NULL, 0, Common) ; } #endif /* contents of Wi no longer needed for Lpi2 ] */ /* Sparent no longer needed ] */ /* ---------------------------------------------------------------------- */ /* determine the largest update matrix (L->maxcsize) */ /* ---------------------------------------------------------------------- */ /* maxcsize could be determined before L->s is allocated and defined, which * would mean that all memory requirements for both the symbolic and numeric * factorizations could be computed using O(nnz(A)+O(n)) space. However, it * would require a lot of extra work. The analysis phase, above, would need * to be duplicated, but with Ls not kept; instead, the algorithm would keep * track of the current s and slast for each supernode d, and update them * when a new row index appears in supernode d. An alternative would be to * do this computation only if the allocation of L->s failed, in which case * the following code would be skipped. * * The csize for a supernode is the size of its largest contribution to * a subsequent ancestor supernode. For example, suppose the rows of #'s * in the figure below correspond to the columns of a subsequent supernode, * and the dots are the entries in that ancestore. * * c * c c * c c c * x x x * x x x * # # # . * # # # . . * * * * . . * * * * . . * * * * . . * . . * * Then for this update, the csize is 3-by-2, or 6, because there are 3 * rows of *'s which is the number of rows in the update, and there are * 2 rows of #'s, which is the number columns in the update. The csize * of a supernode is the largest such contribution for any ancestor * supernode. maxcsize, for the whole matrix, has a rough upper bound of * the maximum size of any supernode. This bound is loose, because the * the contribution must be less than the size of the ancestor supernodal * that it's updating. maxcsize of a completely dense matrix, with one * supernode, is zero. * * maxesize is the column dimension for the workspace E needed for the * solve. E is of size nrhs-by-maxesize, where the nrhs is the number of * columns in the right-hand-side. The maxesize is the largest esize of * any supernode. The esize of a supernode is the number of row indices * it contains, excluding the column indices of the supernode itself. * For the following example, esize is 4: * * c * c c * c c c * x x x * x x x * x x x * x x x * * maxesize can be no bigger than n. */ maxcsize = 1 ; maxesize = 1 ; /* Do not need to guard csize against Int overflow since xsize is OK. */ if (for_cholesky) { /* this is not needed for QR factorization */ for (d = 0 ; d < nsuper ; d++) { nscol = Super [d+1] - Super [d] ; p = Lpi [d] + nscol ; plast = p ; pend = Lpi [d+1] ; esize = pend - p ; maxesize = MAX (maxesize, esize) ; slast = (p == pend) ? (EMPTY) : (SuperMap [Ls [p]]) ; for ( ; p <= pend ; p++) { s = (p == pend) ? (EMPTY) : (SuperMap [Ls [p]]) ; if (s != slast) { /* row i is the start of a new supernode */ ndrow1 = p - plast ; ndrow2 = pend - plast ; csize = ndrow2 * ndrow1 ; PRINT1 (("Supernode "ID" ancestor "ID" C: "ID"-by-"ID " csize "ID"\n", d, slast, ndrow1, ndrow2, csize)) ; maxcsize = MAX (maxcsize, csize) ; plast = p ; slast = s ; } } } PRINT1 (("max csize "ID"\n", maxcsize)) ; } /* Wj no longer needed for SuperMap } */ L->maxcsize = maxcsize ; L->maxesize = maxesize ; L->is_super = TRUE ; ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_ll) ; /* ---------------------------------------------------------------------- */ /* supernodal symbolic factorization is complete */ /* ---------------------------------------------------------------------- */ FREE_WORKSPACE ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_super_symbolic =============================================== */ /* ========================================================================== */ /* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric * factorization. The user need not call this directly; cholmod_analyze is * a "simple" wrapper for this routine. * * This function does all the analysis for a supernodal Cholesky factorization. * * workspace: Flag (nrow), Head (nrow), Iwork (2*nrow), * and temporary space of size 3*nfsuper*sizeof(Int), where nfsuper <= n * is the number of fundamental supernodes. */ int CHOLMOD(super_symbolic) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to analyze */ cholmod_sparse *F, /* F = A' or A(:,f)' */ Int *Parent, /* elimination tree */ /* ---- in/out --- */ cholmod_factor *L, /* simplicial symbolic on input, * supernodal symbolic on output */ /* --------------- */ cholmod_common *Common ) { return (CHOLMOD(super_symbolic2) (TRUE, A, F, Parent, L, Common)) ; } #endif cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/0000755000175000017500000000000011674452555017301 5ustar sonnesonnecvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_copy.c0000644000175000017500000002737011674452555022135 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_copy ==================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* C = A, which allocates C and copies A into C, with possible change of * stype. The diagonal can optionally be removed. The numerical entries * can optionally be copied. This routine differs from cholmod_copy_sparse, * which makes an exact copy of a sparse matrix. * * A can be of any type (packed/unpacked, upper/lower/unsymmetric). C is * packed and can be of any stype (upper/lower/unsymmetric), except that if * A is rectangular C can only be unsymmetric. If the stype of A and C * differ, then the appropriate conversion is made. * * Symmetry of A (A->stype): * <0: lower: assume A is symmetric with just tril(A); the rest of A is ignored * 0 unsym: assume A is unsymmetric; consider all entries in A * >0 upper: assume A is symmetric with just triu(A); the rest of A is ignored * * Symmetry of C (stype parameter): * <0 lower: return just tril(C) * 0 unsym: return all of C * >0 upper: return just triu(C) * * In MATLAB: Using cholmod_copy: * ---------- ---------------------------- * C = A ; A unsymmetric, C unsymmetric * C = tril (A) ; A unsymmetric, C lower * C = triu (A) ; A unsymmetric, C upper * U = triu (A) ; L = tril (U',-1) ; C = L+U ; A upper, C unsymmetric * C = triu (A)' ; A upper, C lower * C = triu (A) ; A upper, C upper * L = tril (A) ; U = triu (L',1) ; C = L+U ; A lower, C unsymmetric * C = tril (A) ; A lower, C lower * C = tril (A)' ; A lower, C upper * * workspace: Iwork (max (nrow,ncol)) * * A can have an xtype of pattern or real. Complex and zomplex cases only * supported when mode <= 0 (in which case the numerical values are ignored). */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === copy_sym_to_unsym ==================================================== */ /* ========================================================================== */ /* Construct an unsymmetric copy of a symmetric sparse matrix. This does the * work for as C = cholmod_copy (A, 0, mode, Common) when A is symmetric. * In this case, extra space can be added to C. */ static cholmod_sparse *copy_sym_to_unsym ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) * -2: pattern only, no diagonal, add 50% + n extra * space to C */ /* --------------- */ cholmod_common *Common ) { double aij ; double *Ax, *Cx ; Int *Ap, *Ai, *Anz, *Cp, *Ci, *Wj, *Iwork ; cholmod_sparse *C ; Int nrow, ncol, nz, packed, j, p, pend, i, pc, up, lo, values, diag, astype, extra ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; Ap = A->p ; Anz = A->nz ; Ai = A->i ; Ax = A->x ; packed = A->packed ; values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ; diag = (mode >= 0) ; astype = SIGN (A->stype) ; up = (astype > 0) ; lo = (astype < 0) ; ASSERT (astype != 0) ; /* ---------------------------------------------------------------------- */ /* create an unsymmetric copy of a symmetric matrix */ /* ---------------------------------------------------------------------- */ Iwork = Common->Iwork ; Wj = Iwork ; /* size ncol (i/i/l) */ /* In MATLAB notation, for converting a symmetric/upper matrix: * U = triu (A) ; * L = tril (U',-1) ; * C = L + U ; * * For converting a symmetric/lower matrix to unsymmetric: * L = tril (A) ; * U = triu (L',1) ; * C = L + U ; */ ASSERT (up || lo) ; PRINT1 (("copy: convert symmetric to unsym\n")) ; /* count the number of entries in each column of C */ for (j = 0 ; j < ncol ; j++) { Wj [j] = 0 ; } for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i == j) { /* the diagonal entry A(i,i) will appear just once * (unless it is excluded with mode < 0) */ if (diag) { Wj [j]++ ; } } else if ((up && i < j) || (lo && i > j)) { /* upper case: A(i,j) is in the strictly upper part; * A(j,i) will be added to the strictly lower part of C. * lower case is the opposite. */ Wj [j]++ ; Wj [i]++ ; } } } nz = 0 ; for (j = 0 ; j < ncol ; j++) { nz += Wj [j] ; } extra = (mode == -2) ? (nz/2 + ncol) : 0 ; /* allocate C. C is sorted if and only if A is sorted */ C = CHOLMOD(allocate_sparse) (nrow, ncol, nz + extra, A->sorted, TRUE, 0, values ? A->xtype : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; } Cp = C->p ; Ci = C->i ; Cx = C->x ; /* construct the column pointers for C */ p = 0 ; for (j = 0 ; j < ncol ; j++) { Cp [j] = p ; p += Wj [j] ; } Cp [ncol] = p ; for (j = 0 ; j < ncol ; j++) { Wj [j] = Cp [j] ; } /* construct C */ if (values) { /* pattern and values */ ASSERT (diag) ; for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; aij = Ax [p] ; if (i == j) { /* add diagonal entry A(i,i) to column i */ pc = Wj [i]++ ; Ci [pc] = i ; Cx [pc] = aij ; } else if ((up && i < j) || (lo && i > j)) { /* add A(i,j) to column j */ pc = Wj [j]++ ; Ci [pc] = i ; Cx [pc] = aij ; /* add A(j,i) to column i */ pc = Wj [i]++ ; Ci [pc] = j ; Cx [pc] = aij ; } } } } else { /* pattern only, possibly excluding the diagonal */ for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i == j) { /* add diagonal entry A(i,i) to column i * (unless it is excluded with mode < 0) */ if (diag) { Ci [Wj [i]++] = i ; } } else if ((up && i < j) || (lo && i > j)) { /* add A(i,j) to column j */ Ci [Wj [j]++] = i ; /* add A(j,i) to column i */ Ci [Wj [i]++] = j ; } } } } /* ---------------------------------------------------------------------- */ /* return the result */ /* ---------------------------------------------------------------------- */ DEBUG (i = CHOLMOD(dump_sparse) (C, "copy_sym_to_unsym", Common)) ; PRINT1 (("mode %d nnzdiag "ID"\n", mode, i)) ; ASSERT (IMPLIES (mode < 0, i == 0)) ; return (C) ; } /* ========================================================================== */ /* === cholmod_copy ========================================================= */ /* ========================================================================== */ cholmod_sparse *CHOLMOD(copy) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ int stype, /* requested stype of C */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *C ; Int nrow, ncol, up, lo, values, diag, astype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; nrow = A->nrow ; ncol = A->ncol ; if ((stype || A->stype) && nrow != ncol) { /* inputs invalid */ ERROR (CHOLMOD_INVALID, "matrix invalid") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ CHOLMOD(allocate_work) (0, MAX (nrow,ncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ diag = (mode >= 0) ; astype = SIGN (A->stype) ; stype = SIGN (stype) ; up = (astype > 0) ; lo = (astype < 0) ; /* ---------------------------------------------------------------------- */ /* copy the matrix */ /* ---------------------------------------------------------------------- */ if (astype == stype) { /* ------------------------------------------------------------------ */ /* symmetry of A and C are the same */ /* ------------------------------------------------------------------ */ /* copy A into C, keeping the same symmetry. If A is symmetric * entries in the ignored part of A are not copied into C */ C = CHOLMOD(band) (A, -nrow, ncol, mode, Common) ; } else if (!astype) { /* ------------------------------------------------------------------ */ /* convert unsymmetric matrix A into a symmetric matrix C */ /* ------------------------------------------------------------------ */ if (stype > 0) { /* C = triu (A) */ C = CHOLMOD(band) (A, 0, ncol, mode, Common) ; } else { /* C = tril (A) */ C = CHOLMOD(band) (A, -nrow, 0, mode, Common) ; } if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } C->stype = stype ; } else if (astype == -stype) { /* ------------------------------------------------------------------ */ /* transpose a symmetric matrix */ /* ------------------------------------------------------------------ */ /* converting upper to lower or lower to upper */ /* workspace: Iwork (nrow) */ C = CHOLMOD(transpose) (A, values, Common) ; if (!diag) { /* remove diagonal, if requested */ CHOLMOD(band_inplace) (-nrow, ncol, -1, C, Common) ; } } else { /* ------------------------------------------------------------------ */ /* create an unsymmetric copy of a symmetric matrix */ /* ------------------------------------------------------------------ */ C = copy_sym_to_unsym (A, mode, Common) ; } /* ---------------------------------------------------------------------- */ /* return if error */ /* ---------------------------------------------------------------------- */ if (Common->status < CHOLMOD_OK) { /* out of memory */ return (NULL) ; } /* ---------------------------------------------------------------------- */ /* return the result */ /* ---------------------------------------------------------------------- */ DEBUG (diag = CHOLMOD(dump_sparse) (C, "copy", Common)) ; PRINT1 (("mode %d nnzdiag "ID"\n", mode, diag)) ; ASSERT (IMPLIES (mode < 0, diag == 0)) ; return (C) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/License.txt0000644000175000017500000000210711674452555021424 0ustar sonnesonneCHOLMOD/Core Module. Copyright (C) 2005-2006, Univ. of Florida. Author: Timothy A. Davis CHOLMOD is also available under other licenses; contact authors for details. http://www.cise.ufl.edu/research/sparse Note that this license is for the CHOLMOD/Core module only. All CHOLMOD modules are licensed separately. -------------------------------------------------------------------------------- This Module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This Module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this Module; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_dense.c0000644000175000017500000001626411674452555022604 0ustar sonnesonne/* ========================================================================== */ /* === Core/t_cholmod_dense ================================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_dense. All xtypes supported, except that there * are no dense matrices with an xtype of pattern. */ #include "cholmod_template.h" /* ========================================================================== */ /* === t_cholmod_sparse_to_dense ============================================ */ /* ========================================================================== */ static cholmod_dense *TEMPLATE (cholmod_sparse_to_dense) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Xx, *Az, *Xz ; Int *Ap, *Ai, *Anz ; cholmod_dense *X ; Int i, j, p, pend, nrow, ncol, packed ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; packed = A->packed ; Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; Anz = A->nz ; /* ---------------------------------------------------------------------- */ /* allocate result */ /* ---------------------------------------------------------------------- */ X = CHOLMOD(zeros) (nrow, ncol, XTYPE2, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } Xx = X->x ; Xz = X->z ; /* ---------------------------------------------------------------------- */ /* copy into dense matrix */ /* ---------------------------------------------------------------------- */ if (A->stype < 0) { /* A is symmetric with lower stored, but both parts of X are present */ for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i >= j) { ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ; ASSIGN2_CONJ (Xx, Xz, j+i*nrow, Ax, Az, p) ; } } } } else if (A->stype > 0) { /* A is symmetric with upper stored, but both parts of X are present */ for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i <= j) { ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ; ASSIGN2_CONJ (Xx, Xz, j+i*nrow, Ax, Az, p) ; } } } } else { /* both parts of A and X are present */ for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ; } } } return (X) ; } #ifndef PATTERN /* There are no dense matrices of xtype CHOLMOD_PATTERN */ /* ========================================================================== */ /* === t_cholmod_dense_to_sparse ============================================ */ /* ========================================================================== */ static cholmod_sparse *TEMPLATE (cholmod_dense_to_sparse) ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ int values, /* TRUE if values to be copied, FALSE otherwise */ /* --------------- */ cholmod_common *Common ) { double *Xx, *Cx, *Xz, *Cz ; Int *Ci, *Cp ; cholmod_sparse *C ; Int i, j, p, d, nrow, ncol, nz ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = X->nrow ; ncol = X->ncol ; d = X->d ; Xx = X->x ; Xz = X->z ; /* ---------------------------------------------------------------------- */ /* count the number of nonzeros in the result */ /* ---------------------------------------------------------------------- */ nz = 0 ; for (j = 0 ; j < ncol ; j++) { for (i = 0 ; i < nrow ; i++) { if (ENTRY_IS_NONZERO (Xx, Xz, i+j*d)) { nz++ ; } } } /* ---------------------------------------------------------------------- */ /* allocate the result C */ /* ---------------------------------------------------------------------- */ C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, TRUE, TRUE, 0, values ? XTYPE : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } Cp = C->p ; Ci = C->i ; Cx = C->x ; Cz = C->z ; /* ---------------------------------------------------------------------- */ /* copy the dense matrix X into the sparse matrix C */ /* ---------------------------------------------------------------------- */ p = 0 ; for (j = 0 ; j < ncol ; j++) { Cp [j] = p ; for (i = 0 ; i < nrow ; i++) { if (ENTRY_IS_NONZERO (Xx, Xz, i+j*d)) { Ci [p] = i ; if (values) { ASSIGN (Cx, Cz, p, Xx, Xz, i+j*d) ; } p++ ; } } } ASSERT (p == nz) ; Cp [ncol] = nz ; /* ---------------------------------------------------------------------- */ /* return result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_sparse) (C, "C", Common) >= 0) ; return (C) ; } /* ========================================================================== */ /* === t_cholmod_copy_dense2 ================================================ */ /* ========================================================================== */ /* Y = X, where X and Y are both already allocated. */ static int TEMPLATE (cholmod_copy_dense2) ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ /* ---- output --- */ cholmod_dense *Y /* copy of matrix X */ ) { double *Xx, *Xz, *Yx, *Yz ; Int i, j, nrow, ncol, dy, dx ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ Xx = X->x ; Xz = X->z ; Yx = Y->x ; Yz = Y->z ; dx = X->d ; dy = Y->d ; nrow = X->nrow ; ncol = X->ncol ; /* ---------------------------------------------------------------------- */ /* copy */ /* ---------------------------------------------------------------------- */ CLEAR (Yx, Yz, 0) ; for (j = 0 ; j < ncol ; j++) { for (i = 0 ; i < nrow ; i++) { ASSIGN (Yx, Yz, i+j*dy, Xx, Xz, i+j*dx) ; } } return (TRUE) ; } #endif #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_transpose.c0000644000175000017500000002131711674452555023517 0ustar sonnesonne/* ========================================================================== */ /* === Core/t_cholmod_transpose ============================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_transpose. All xtypes are supported. For * complex matrices, either the array tranpose or complex conjugate transpose * can be computed. */ #include "cholmod_template.h" /* ========================================================================== */ /* === t_cholmod_transpose_unsym ============================================ */ /* ========================================================================== */ /* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is * already allocated. The complex case performs either the array transpose * or complex conjugate transpose. * * workspace: * Iwork (MAX (nrow,ncol)) if fset is present * Iwork (nrow) if fset is NULL */ static int TEMPLATE (cholmod_transpose_unsym) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ Int *Perm, /* size nrow, if present (can be NULL) */ Int *fset, /* subset of 0:(A->ncol)-1 */ Int nf, /* size of fset */ /* ---- output --- */ cholmod_sparse *F, /* F = A', A(:,f)', or A(p,f)' */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Az, *Fx, *Fz ; Int *Ap, *Anz, *Ai, *Fp, *Fnz, *Fj, *Wi, *Iwork ; Int j, p, pend, nrow, ncol, Apacked, use_fset, fp, Fpacked, jj, permute ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ /* ensure the xtype of A and F match (ignored if this is pattern version) */ if (!XTYPE_OK (A->xtype)) { ERROR (CHOLMOD_INVALID, "real/complex mismatch") ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ use_fset = (fset != NULL) ; nrow = A->nrow ; ncol = A->ncol ; Ap = A->p ; /* size A->ncol+1, column pointers of A */ Ai = A->i ; /* size nz = Ap [A->ncol], row indices of A */ Ax = A->x ; /* size nz, real values of A */ Az = A->z ; /* size nz, imag values of A */ Anz = A->nz ; Apacked = A->packed ; ASSERT (IMPLIES (!Apacked, Anz != NULL)) ; permute = (Perm != NULL) ; Fp = F->p ; /* size A->nrow+1, row pointers of F */ Fj = F->i ; /* size nz, column indices of F */ Fx = F->x ; /* size nz, real values of F */ Fz = F->z ; /* size nz, imag values of F */ Fnz = F->nz ; Fpacked = F->packed ; ASSERT (IMPLIES (!Fpacked, Fnz != NULL)) ; nf = (use_fset) ? nf : ncol ; /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Iwork = Common->Iwork ; Wi = Iwork ; /* size nrow (i/l/l) */ /* ---------------------------------------------------------------------- */ /* construct the transpose */ /* ---------------------------------------------------------------------- */ for (jj = 0 ; jj < nf ; jj++) { j = (use_fset) ? (fset [jj]) : jj ; p = Ap [j] ; pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { fp = Wi [Ai [p]]++ ; Fj [fp] = j ; #ifdef NCONJUGATE ASSIGN (Fx, Fz, fp, Ax, Az, p) ; #else ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ; #endif } } return (TRUE) ; } /* ========================================================================== */ /* === t_cholmod_transpose_sym ============================================== */ /* ========================================================================== */ /* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated. * The complex case performs either the array transpose or complex conjugate * transpose. * * workspace: Iwork (nrow) if Perm NULL, Iwork (2*nrow) if Perm non-NULL. */ static int TEMPLATE (cholmod_transpose_sym) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ Int *Perm, /* size n, if present (can be NULL) */ /* ---- output --- */ cholmod_sparse *F, /* F = A' or A(p,p)' */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Az, *Fx, *Fz ; Int *Ap, *Anz, *Ai, *Fp, *Fj, *Wi, *Pinv, *Iwork ; Int p, pend, packed, fp, upper, permute, jold, n, i, j, iold ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ /* ensure the xtype of A and F match (ignored if this is pattern version) */ if (!XTYPE_OK (A->xtype)) { ERROR (CHOLMOD_INVALID, "real/complex mismatch") ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ permute = (Perm != NULL) ; n = A->nrow ; Ap = A->p ; /* size A->ncol+1, column pointers of A */ Ai = A->i ; /* size nz = Ap [A->ncol], row indices of A */ Ax = A->x ; /* size nz, real values of A */ Az = A->z ; /* size nz, imag values of A */ Anz = A->nz ; packed = A->packed ; ASSERT (IMPLIES (!packed, Anz != NULL)) ; upper = (A->stype > 0) ; Fp = F->p ; /* size A->nrow+1, row pointers of F */ Fj = F->i ; /* size nz, column indices of F */ Fx = F->x ; /* size nz, real values of F */ Fz = F->z ; /* size nz, imag values of F */ /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Iwork = Common->Iwork ; Wi = Iwork ; /* size n (i/l/l) */ Pinv = Iwork + n ; /* size n (i/i/l) , unused if Perm NULL */ /* ---------------------------------------------------------------------- */ /* construct the transpose */ /* ---------------------------------------------------------------------- */ if (permute) { if (upper) { /* permuted, upper */ for (j = 0 ; j < n ; j++) { jold = Perm [j] ; p = Ap [jold] ; pend = (packed) ? Ap [jold+1] : p + Anz [jold] ; for ( ; p < pend ; p++) { iold = Ai [p] ; if (iold <= jold) { i = Pinv [iold] ; if (i < j) { fp = Wi [i]++ ; Fj [fp] = j ; #ifdef NCONJUGATE ASSIGN (Fx, Fz, fp, Ax, Az, p) ; #else ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ; #endif } else { fp = Wi [j]++ ; Fj [fp] = i ; ASSIGN (Fx, Fz, fp, Ax, Az, p) ; } } } } } else { /* permuted, lower */ for (j = 0 ; j < n ; j++) { jold = Perm [j] ; p = Ap [jold] ; pend = (packed) ? Ap [jold+1] : p + Anz [jold] ; for ( ; p < pend ; p++) { iold = Ai [p] ; if (iold >= jold) { i = Pinv [iold] ; if (i > j) { fp = Wi [i]++ ; Fj [fp] = j ; #ifdef NCONJUGATE ASSIGN (Fx, Fz, fp, Ax, Az, p) ; #else ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ; #endif } else { fp = Wi [j]++ ; Fj [fp] = i ; ASSIGN (Fx, Fz, fp, Ax, Az, p) ; } } } } } } else { if (upper) { /* unpermuted, upper */ for (j = 0 ; j < n ; j++) { p = Ap [j] ; pend = (packed) ? Ap [j+1] : p + Anz [j] ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i <= j) { fp = Wi [i]++ ; Fj [fp] = j ; #ifdef NCONJUGATE ASSIGN (Fx, Fz, fp, Ax, Az, p) ; #else ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ; #endif } } } } else { /* unpermuted, lower */ for (j = 0 ; j < n ; j++) { p = Ap [j] ; pend = (packed) ? Ap [j+1] : p + Anz [j] ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i >= j) { fp = Wi [i]++ ; Fj [fp] = j ; #ifdef NCONJUGATE ASSIGN (Fx, Fz, fp, Ax, Az, p) ; #else ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ; #endif } } } } } return (TRUE) ; } #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX #undef NCONJUGATE cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_common.c0000644000175000017500000005246111674452555022452 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_common ================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Core utility routines for the cholmod_common object: * * Primary routines: * ----------------- * cholmod_start the first call to CHOLMOD * cholmod_finish the last call to CHOLMOD * * Secondary routines: * ------------------- * cholmod_defaults restore (most) default control parameters * cholmod_allocate_work allocate (or reallocate) workspace in Common * cholmod_free_work free workspace in Common * cholmod_clear_flag clear Common->Flag in workspace * cholmod_maxrank column dimension of Common->Xwork workspace * * The Common object is unique. It cannot be allocated or deallocated by * CHOLMOD, since it contains the definition of the memory management routines * used (pointers to malloc, free, realloc, and calloc, or their equivalent). * The Common object contains workspace that is used between calls to * CHOLMOD routines. This workspace allocated by CHOLMOD as needed, by * cholmod_allocate_work and cholmod_free_work. */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === cholmod_start ======================================================== */ /* ========================================================================== */ /* Initialize Common default parameters and statistics. Sets workspace * pointers to NULL. * * This routine must be called just once, prior to calling any other CHOLMOD * routine. Do not call this routine after any other CHOLMOD routine (except * cholmod_finish, to start a new CHOLMOD session), or a memory leak will * occur. * * workspace: none */ int CHOLMOD(start) ( cholmod_common *Common ) { int k ; if (Common == NULL) { return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* user error handling routine */ /* ---------------------------------------------------------------------- */ Common->error_handler = NULL ; /* ---------------------------------------------------------------------- */ /* integer and numerical types */ /* ---------------------------------------------------------------------- */ Common->itype = ITYPE ; Common->dtype = DTYPE ; /* ---------------------------------------------------------------------- */ /* default control parameters */ /* ---------------------------------------------------------------------- */ CHOLMOD(defaults) (Common) ; Common->try_catch = FALSE ; /* ---------------------------------------------------------------------- */ /* memory management routines */ /* ---------------------------------------------------------------------- */ /* The user can replace cholmod's memory management routines by redefining * these function pointers. */ #ifndef NMALLOC /* stand-alone ANSI C program */ Common->malloc_memory = malloc ; Common->free_memory = free ; Common->realloc_memory = realloc ; Common->calloc_memory = calloc ; #else /* no memory manager defined at compile-time; MUST define one at run-time */ Common->malloc_memory = NULL ; Common->free_memory = NULL ; Common->realloc_memory = NULL ; Common->calloc_memory = NULL ; #endif /* ---------------------------------------------------------------------- */ /* complex arithmetic routines */ /* ---------------------------------------------------------------------- */ Common->complex_divide = CHOLMOD(divcomplex) ; Common->hypotenuse = CHOLMOD(hypot) ; /* ---------------------------------------------------------------------- */ /* print routine */ /* ---------------------------------------------------------------------- */ #ifndef NPRINT /* stand-alone ANSI C program */ Common->print_function = printf ; #else /* printing disabled */ Common->print_function = NULL ; #endif /* ---------------------------------------------------------------------- */ /* workspace */ /* ---------------------------------------------------------------------- */ /* This code assumes the workspace held in Common is not initialized. If * it is, then a memory leak will occur because the pointers are * overwritten with NULL. */ Common->nrow = 0 ; Common->mark = EMPTY ; Common->xworksize = 0 ; Common->iworksize = 0 ; Common->Flag = NULL ; Common->Head = NULL ; Common->Iwork = NULL ; Common->Xwork = NULL ; Common->no_workspace_reallocate = FALSE ; /* ---------------------------------------------------------------------- */ /* statistics */ /* ---------------------------------------------------------------------- */ /* fl and lnz are computed in cholmod_analyze and cholmod_rowcolcounts */ Common->fl = EMPTY ; Common->lnz = EMPTY ; /* modfl is computed in cholmod_updown, cholmod_rowadd, and cholmod_rowdel*/ Common->modfl = EMPTY ; /* all routines use status as their error-report code */ Common->status = CHOLMOD_OK ; Common->malloc_count = 0 ; /* # calls to malloc minus # calls to free */ Common->memory_usage = 0 ; /* peak memory usage (in bytes) */ Common->memory_inuse = 0 ; /* current memory in use (in bytes) */ Common->nrealloc_col = 0 ; Common->nrealloc_factor = 0 ; Common->ndbounds_hit = 0 ; Common->rowfacfl = 0 ; Common->aatfl = EMPTY ; /* Common->called_nd is TRUE if cholmod_analyze called or NESDIS */ Common->called_nd = FALSE ; Common->blas_ok = TRUE ; /* false if BLAS int overflow occurs */ /* ---------------------------------------------------------------------- */ /* default SuiteSparseQR knobs and statististics */ /* ---------------------------------------------------------------------- */ for (k = 0 ; k < 2 ; k++) Common->SPQR_xstat [k] = 0 ; for (k = 0 ; k < 10 ; k++) Common->SPQR_istat [k] = 0 ; Common->SPQR_grain = 1 ; /* no Intel TBB multitasking, by default */ Common->SPQR_small = 1e6 ; /* target min task size for TBB */ Common->SPQR_shrink = 1 ; /* controls SPQR shrink realloc */ Common->SPQR_nthreads = 0 ; /* 0: let TBB decide how many threads to use */ DEBUG_INIT ("cholmod start", Common) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_defaults ===================================================== */ /* ========================================================================== */ /* Set Common default parameters, except for the function pointers. * * workspace: none */ int CHOLMOD(defaults) ( cholmod_common *Common ) { Int i ; RETURN_IF_NULL_COMMON (FALSE) ; /* ---------------------------------------------------------------------- */ /* default control parameters */ /* ---------------------------------------------------------------------- */ Common->dbound = 0.0 ; Common->grow0 = 1.2 ; Common->grow1 = 1.2 ; Common->grow2 = 5 ; Common->maxrank = 8 ; Common->final_asis = TRUE ; Common->final_super = TRUE ; Common->final_ll = FALSE ; Common->final_pack = TRUE ; Common->final_monotonic = TRUE ; Common->final_resymbol = FALSE ; /* use simplicial factorization if flop/nnz(L) < 40, supernodal otherwise */ Common->supernodal = CHOLMOD_AUTO ; Common->supernodal_switch = 40 ; Common->nrelax [0] = 4 ; Common->nrelax [1] = 16 ; Common->nrelax [2] = 48 ; Common->zrelax [0] = 0.8 ; Common->zrelax [1] = 0.1 ; Common->zrelax [2] = 0.05 ; Common->prefer_zomplex = FALSE ; Common->prefer_upper = TRUE ; Common->prefer_binary = FALSE ; Common->quick_return_if_not_posdef = FALSE ; /* METIS workarounds */ Common->metis_memory = 0.0 ; /* > 0 for memory guard (2 is reasonable) */ Common->metis_nswitch = 3000 ; Common->metis_dswitch = 0.66 ; Common->print = 3 ; Common->precise = FALSE ; /* ---------------------------------------------------------------------- */ /* default ordering methods */ /* ---------------------------------------------------------------------- */ /* Note that if the Partition module is not installed, the CHOLMOD_METIS * and CHOLMOD_NESDIS methods will not be available. cholmod_analyze will * report the CHOLMOD_NOT_INSTALLED error, and safely skip over them. */ #if (CHOLMOD_MAXMETHODS < 9) #error "CHOLMOD_MAXMETHODS must be 9 or more (defined in cholmod_core.h)." #endif /* default strategy: try given, AMD, and then METIS if AMD reports high * fill-in. NESDIS can be used instead, if Common->default_nesdis is TRUE. */ Common->nmethods = 0 ; /* use default strategy */ Common->default_nesdis = FALSE ; /* use METIS in default strategy */ Common->current = 0 ; /* current method being tried */ Common->selected = 0 ; /* the best method selected */ /* first, fill each method with default parameters */ for (i = 0 ; i <= CHOLMOD_MAXMETHODS ; i++) { /* CHOLMOD's default method is AMD for A or AA' */ Common->method [i].ordering = CHOLMOD_AMD ; /* CHOLMOD nested dissection and minimum degree parameter */ Common->method [i].prune_dense = 10.0 ; /* dense row/col control */ /* min degree parameters (AMD, COLAMD, SYMAMD, CAMD, CCOLAMD, CSYMAMD)*/ Common->method [i].prune_dense2 = -1 ; /* COLAMD dense row control */ Common->method [i].aggressive = TRUE ; /* aggressive absorption */ Common->method [i].order_for_lu = FALSE ;/* order for Cholesky not LU */ /* CHOLMOD's nested dissection (METIS + constrained AMD) */ Common->method [i].nd_small = 200 ; /* small graphs aren't cut */ Common->method [i].nd_compress = TRUE ; /* compress graph & subgraphs */ Common->method [i].nd_camd = 1 ; /* use CAMD */ Common->method [i].nd_components = FALSE ; /* lump connected comp. */ Common->method [i].nd_oksep = 1.0 ; /* sep ok if < oksep*n */ /* statistics for each method are not yet computed */ Common->method [i].fl = EMPTY ; Common->method [i].lnz = EMPTY ; } Common->postorder = TRUE ; /* follow ordering with weighted postorder */ /* Next, define some methods. The first five use default parameters. */ Common->method [0].ordering = CHOLMOD_GIVEN ; /* skip if UserPerm NULL */ Common->method [1].ordering = CHOLMOD_AMD ; Common->method [2].ordering = CHOLMOD_METIS ; Common->method [3].ordering = CHOLMOD_NESDIS ; Common->method [4].ordering = CHOLMOD_NATURAL ; /* CHOLMOD's nested dissection with large leaves of separator tree */ Common->method [5].ordering = CHOLMOD_NESDIS ; Common->method [5].nd_small = 20000 ; /* CHOLMOD's nested dissection with tiny leaves, and no AMD ordering */ Common->method [6].ordering = CHOLMOD_NESDIS ; Common->method [6].nd_small = 4 ; Common->method [6].nd_camd = 0 ; /* no CSYMAMD or CAMD */ /* CHOLMOD's nested dissection with no dense node removal */ Common->method [7].ordering = CHOLMOD_NESDIS ; Common->method [7].prune_dense = -1. ; /* COLAMD for A*A', AMD for A */ Common->method [8].ordering = CHOLMOD_COLAMD ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_finish ======================================================= */ /* ========================================================================== */ /* The last call to CHOLMOD must be cholmod_finish. You may call this routine * more than once, and can safely call any other CHOLMOD routine after calling * it (including cholmod_start). * * The statistics and parameter settings in Common are preserved. The * workspace in Common is freed. This routine is just another name for * cholmod_free_work. */ int CHOLMOD(finish) ( cholmod_common *Common ) { return (CHOLMOD(free_work) (Common)) ; } /* ========================================================================== */ /* === cholmod_allocate_work ================================================ */ /* ========================================================================== */ /* Allocate and initialize workspace for CHOLMOD routines, or increase the size * of already-allocated workspace. If enough workspace is already allocated, * then nothing happens. * * workspace: Flag (nrow), Head (nrow+1), Iwork (iworksize), Xwork (xworksize) */ int CHOLMOD(allocate_work) ( /* ---- input ---- */ size_t nrow, /* # of rows in the matrix A */ size_t iworksize, /* size of Iwork */ size_t xworksize, /* size of Xwork */ /* --------------- */ cholmod_common *Common ) { double *W ; Int *Head ; Int i ; size_t nrow1 ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* Allocate Flag (nrow) and Head (nrow+1) */ /* ---------------------------------------------------------------------- */ nrow = MAX (1, nrow) ; /* nrow1 = nrow + 1 */ nrow1 = CHOLMOD(add_size_t) (nrow, 1, &ok) ; if (!ok) { /* nrow+1 causes size_t overflow ; problem is too large */ Common->status = CHOLMOD_TOO_LARGE ; CHOLMOD(free_work) (Common) ; return (FALSE) ; } if (nrow > Common->nrow) { if (Common->no_workspace_reallocate) { /* CHOLMOD is not allowed to change the workspace here */ Common->status = CHOLMOD_INVALID ; return (FALSE) ; } /* free the old workspace (if any) and allocate new space */ Common->Flag = CHOLMOD(free) (Common->nrow, sizeof (Int), Common->Flag, Common) ; Common->Head = CHOLMOD(free) (Common->nrow+1,sizeof (Int), Common->Head, Common) ; Common->Flag = CHOLMOD(malloc) (nrow, sizeof (Int), Common) ; Common->Head = CHOLMOD(malloc) (nrow1, sizeof (Int), Common) ; /* record the new size of Flag and Head */ Common->nrow = nrow ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_work) (Common) ; return (FALSE) ; } /* initialize Flag and Head */ Common->mark = EMPTY ; CHOLMOD(clear_flag) (Common) ; Head = Common->Head ; for (i = 0 ; i <= (Int) (nrow) ; i++) { Head [i] = EMPTY ; } } /* ---------------------------------------------------------------------- */ /* Allocate Iwork (iworksize) */ /* ---------------------------------------------------------------------- */ iworksize = MAX (1, iworksize) ; if (iworksize > Common->iworksize) { if (Common->no_workspace_reallocate) { /* CHOLMOD is not allowed to change the workspace here */ Common->status = CHOLMOD_INVALID ; return (FALSE) ; } /* free the old workspace (if any) and allocate new space. * integer overflow safely detected in cholmod_malloc */ CHOLMOD(free) (Common->iworksize, sizeof (Int), Common->Iwork, Common) ; Common->Iwork = CHOLMOD(malloc) (iworksize, sizeof (Int), Common) ; /* record the new size of Iwork */ Common->iworksize = iworksize ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_work) (Common) ; return (FALSE) ; } /* note that Iwork does not need to be initialized */ } /* ---------------------------------------------------------------------- */ /* Allocate Xwork (xworksize) and set it to ((double) 0.) */ /* ---------------------------------------------------------------------- */ /* make sure xworksize is >= 1 */ xworksize = MAX (1, xworksize) ; if (xworksize > Common->xworksize) { if (Common->no_workspace_reallocate) { /* CHOLMOD is not allowed to change the workspace here */ Common->status = CHOLMOD_INVALID ; return (FALSE) ; } /* free the old workspace (if any) and allocate new space */ CHOLMOD(free) (Common->xworksize, sizeof (double), Common->Xwork, Common) ; Common->Xwork = CHOLMOD(malloc) (xworksize, sizeof (double), Common) ; /* record the new size of Xwork */ Common->xworksize = xworksize ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_work) (Common) ; return (FALSE) ; } /* initialize Xwork */ W = Common->Xwork ; for (i = 0 ; i < (Int) xworksize ; i++) { W [i] = 0. ; } } return (TRUE) ; } /* ========================================================================== */ /* === cholmod_free_work ==================================================== */ /* ========================================================================== */ /* Deallocate the CHOLMOD workspace. * * workspace: deallocates all workspace in Common */ int CHOLMOD(free_work) ( cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->Flag = CHOLMOD(free) (Common->nrow, sizeof (Int), Common->Flag, Common) ; Common->Head = CHOLMOD(free) (Common->nrow+1, sizeof (Int), Common->Head, Common) ; Common->Iwork = CHOLMOD(free) (Common->iworksize, sizeof (Int), Common->Iwork, Common) ; Common->Xwork = CHOLMOD(free) (Common->xworksize, sizeof (double), Common->Xwork, Common) ; Common->nrow = 0 ; Common->iworksize = 0 ; Common->xworksize = 0 ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_clear_flag =================================================== */ /* ========================================================================== */ /* Increment mark to ensure Flag [0..nrow-1] < mark. If integer overflow * occurs, or mark was initially negative, reset the entire array. This is * not an error condition, but an intended function of the Flag workspace. * * workspace: Flag (nrow). Does not modify Flag if nrow is zero. */ UF_long CHOLMOD(clear_flag) ( cholmod_common *Common ) { Int i, nrow, *Flag ; RETURN_IF_NULL_COMMON (-1) ; Common->mark++ ; if (Common->mark <= 0) { nrow = Common->nrow ; Flag = Common->Flag ; PRINT2 (("reset Flag: nrow "ID"\n", nrow)) ; PRINT2 (("reset Flag: mark %ld\n", Common->mark)) ; for (i = 0 ; i < nrow ; i++) { Flag [i] = EMPTY ; } Common->mark = 0 ; } return (Common->mark) ; } /* ========================================================================== */ /* ==== cholmod_maxrank ===================================================== */ /* ========================================================================== */ /* Find a valid value of Common->maxrank. Returns 0 if error, or 2, 4, or 8 * if successful. */ size_t CHOLMOD(maxrank) /* returns validated value of Common->maxrank */ ( /* ---- input ---- */ size_t n, /* A and L will have n rows */ /* --------------- */ cholmod_common *Common ) { size_t maxrank ; RETURN_IF_NULL_COMMON (0) ; maxrank = Common->maxrank ; if (n > 0) { /* Ensure maxrank*n*sizeof(double) does not result in integer overflow. * If n is so large that 2*n*sizeof(double) results in integer overflow * (n = 268,435,455 if an Int is 32 bits), then maxrank will be 0 or 1, * but maxrank will be set to 2 below. 2*n will not result in integer * overflow, and CHOLMOD will run out of memory or safely detect integer * overflow elsewhere. */ maxrank = MIN (maxrank, Size_max / (n * sizeof (double))) ; } if (maxrank <= 2) { maxrank = 2 ; } else if (maxrank <= 4) { maxrank = 4 ; } else { maxrank = 8 ; } return (maxrank) ; } /* ========================================================================== */ /* === cholmod_dbound ======================================================= */ /* ========================================================================== */ /* Ensure the absolute value of a diagonal entry, D (j,j), is greater than * Common->dbound. This routine is not meant for the user to call. It is used * by the various LDL' factorization and update/downdate routines. The * default value of Common->dbound is zero, and in that case this routine is not * called at all. No change is made if D (j,j) is NaN. CHOLMOD does not call * this routine if Common->dbound is NaN. */ double CHOLMOD(dbound) /* returns modified diagonal entry of D */ ( /* ---- input ---- */ double dj, /* diagonal entry of D, for LDL' factorization */ /* --------------- */ cholmod_common *Common ) { double dbound ; RETURN_IF_NULL_COMMON (0) ; if (!IS_NAN (dj)) { dbound = Common->dbound ; if (dj < 0) { if (dj > -dbound) { dj = -dbound ; Common->ndbounds_hit++ ; if (Common->status == CHOLMOD_OK) { ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ; } } } else { if (dj < dbound) { dj = dbound ; Common->ndbounds_hit++ ; if (Common->status == CHOLMOD_OK) { ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ; } } } } return (dj) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_band.c0000644000175000017500000002327711674452555022071 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_band ==================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* C = tril (triu (A,k1), k2) * * C is a matrix consisting of the diagonals of A from k1 to k2. * * k=0 is the main diagonal of A, k=1 is the superdiagonal, k=-1 is the * subdiagonal, and so on. If A is m-by-n, then: * * k1=-m C = tril (A,k2) * k2=n C = triu (A,k1) * k1=0 and k2=0 C = diag(A), except C is a matrix, not a vector * * Values of k1 and k2 less than -m are treated as -m, and values greater * than n are treated as n. * * A can be of any symmetry (upper, lower, or unsymmetric); C is returned in * the same form, and packed. If A->stype > 0, entries in the lower * triangular part of A are ignored, and the opposite is true if * A->stype < 0. If A has sorted columns, then so does C. * C has the same size as A. * * If inplace is TRUE, then the matrix A is modified in place. * Only packed matrices can be converted in place. * * C can be returned as a numerical valued matrix (if A has numerical values * and mode > 0), as a pattern-only (mode == 0), or as a pattern-only but with * the diagonal entries removed (mode < 0). * * workspace: none * * A can have an xtype of pattern or real. Complex and zomplex cases supported * only if mode <= 0 (in which case the numerical values are ignored). */ #include "cholmod_internal.h" #include "cholmod_core.h" static cholmod_sparse *band /* returns C, or NULL if failure */ ( /* ---- input or in/out if inplace is TRUE --- */ cholmod_sparse *A, /* ---- input ---- */ UF_long k1, /* ignore entries below the k1-st diagonal */ UF_long k2, /* ignore entries above the k2-nd diagonal */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diagonal) */ int inplace, /* if TRUE, then convert A in place */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Cx ; Int packed, nz, j, p, pend, i, ncol, nrow, jlo, jhi, ilo, ihi, sorted, values, diag ; Int *Ap, *Anz, *Ai, *Cp, *Ci ; cholmod_sparse *C ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; packed = A->packed ; diag = (mode >= 0) ; if (inplace && !packed) { /* cannot operate on an unpacked matrix in place */ ERROR (CHOLMOD_INVALID, "cannot operate on unpacked matrix in-place") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ PRINT1 (("k1 %ld k2 %ld\n", k1, k2)) ; Ap = A->p ; Anz = A->nz ; Ai = A->i ; Ax = A->x ; sorted = A->sorted ; if (A->stype > 0) { /* ignore any entries in strictly lower triangular part of A */ k1 = MAX (k1, 0) ; } if (A->stype < 0) { /* ignore any entries in strictly upper triangular part of A */ k2 = MIN (k2, 0) ; } ncol = A->ncol ; nrow = A->nrow ; /* ensure k1 and k2 are in the range -nrow to +ncol to * avoid possible integer overflow if k1 and k2 are huge */ k1 = MAX (-nrow, k1) ; k1 = MIN (k1, ncol) ; k2 = MAX (-nrow, k2) ; k2 = MIN (k2, ncol) ; /* consider columns jlo to jhi. columns outside this range are empty */ jlo = MAX (k1, 0) ; jhi = MIN (k2+nrow, ncol) ; if (k1 > k2) { /* nothing to do */ jlo = ncol ; jhi = ncol ; } /* ---------------------------------------------------------------------- */ /* allocate C, or operate on A in place */ /* ---------------------------------------------------------------------- */ if (inplace) { /* convert A in place */ C = A ; } else { /* count the number of entries in the result C */ nz = 0 ; if (sorted) { for (j = jlo ; j < jhi ; j++) { ilo = j-k2 ; ihi = j-k1 ; p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i > ihi) { break ; } if (i >= ilo && (diag || i != j)) { nz++ ; } } } } else { for (j = jlo ; j < jhi ; j++) { ilo = j-k2 ; ihi = j-k1 ; p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i >= ilo && i <= ihi && (diag || i != j)) { nz++ ; } } } } /* allocate C; A will not be modified. C is sorted if A is sorted */ C = CHOLMOD(allocate_sparse) (A->nrow, ncol, nz, sorted, TRUE, A->stype, values ? A->xtype : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } } Cp = C->p ; Ci = C->i ; Cx = C->x ; /* ---------------------------------------------------------------------- */ /* construct C */ /* ---------------------------------------------------------------------- */ /* columns 0 to jlo-1 are empty */ for (j = 0 ; j < jlo ; j++) { Cp [j] = 0 ; } nz = 0 ; if (sorted) { if (values) { /* pattern and values */ ASSERT (diag) ; for (j = jlo ; j < jhi ; j++) { ilo = j-k2 ; ihi = j-k1 ; p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; Cp [j] = nz ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i > ihi) { break ; } if (i >= ilo) { Ci [nz] = i ; Cx [nz] = Ax [p] ; nz++ ; } } } } else { /* pattern only, perhaps with no diagonal */ for (j = jlo ; j < jhi ; j++) { ilo = j-k2 ; ihi = j-k1 ; p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; Cp [j] = nz ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i > ihi) { break ; } if (i >= ilo && (diag || i != j)) { Ci [nz++] = i ; } } } } } else { if (values) { /* pattern and values */ ASSERT (diag) ; for (j = jlo ; j < jhi ; j++) { ilo = j-k2 ; ihi = j-k1 ; p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; Cp [j] = nz ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i >= ilo && i <= ihi) { Ci [nz] = i ; Cx [nz] = Ax [p] ; nz++ ; } } } } else { /* pattern only, perhaps with no diagonal */ for (j = jlo ; j < jhi ; j++) { ilo = j-k2 ; ihi = j-k1 ; p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; Cp [j] = nz ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i >= ilo && i <= ihi && (diag || i != j)) { Ci [nz++] = i ; } } } } } /* columns jhi to ncol-1 are empty */ for (j = jhi ; j <= ncol ; j++) { Cp [j] = nz ; } /* ---------------------------------------------------------------------- */ /* reduce A in size if done in place */ /* ---------------------------------------------------------------------- */ if (inplace) { /* free the unused parts of A, and reduce A->i and A->x in size */ ASSERT (MAX (1,nz) <= A->nzmax) ; CHOLMOD(reallocate_sparse) (nz, A, Common) ; ASSERT (Common->status >= CHOLMOD_OK) ; } /* ---------------------------------------------------------------------- */ /* return the result C */ /* ---------------------------------------------------------------------- */ DEBUG (i = CHOLMOD(dump_sparse) (C, "band", Common)) ; ASSERT (IMPLIES (mode < 0, i == 0)) ; return (C) ; } /* ========================================================================== */ /* === cholmod_band ========================================================= */ /* ========================================================================== */ cholmod_sparse *CHOLMOD(band) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to extract band matrix from */ UF_long k1, /* ignore entries below the k1-st diagonal */ UF_long k2, /* ignore entries above the k2-nd diagonal */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ /* --------------- */ cholmod_common *Common ) { return (band (A, k1, k2, mode, FALSE, Common)) ; } /* ========================================================================== */ /* === cholmod_band_inplace ================================================= */ /* ========================================================================== */ int CHOLMOD(band_inplace) ( /* ---- input ---- */ UF_long k1, /* ignore entries below the k1-st diagonal */ UF_long k2, /* ignore entries above the k2-nd diagonal */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) */ /* ---- in/out --- */ cholmod_sparse *A, /* matrix from which entries not in band are removed */ /* --------------- */ cholmod_common *Common ) { return (band (A, k1, k2, mode, TRUE, Common) != NULL) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_aat.c0000644000175000017500000002077011674452555021725 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_aat ===================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* C = A*A' or C = A(:,f)*A(:,f)' * * A can be packed or unpacked, sorted or unsorted, but must be stored with * both upper and lower parts (A->stype of zero). C is returned as packed, * C->stype of zero (both upper and lower parts present), and unsorted. See * cholmod_ssmult in the MatrixOps Module for a more general matrix-matrix * multiply. * * You can trivially convert C into a symmetric upper/lower matrix by * changing C->stype = 1 or -1 after calling this routine. * * workspace: * Flag (A->nrow), * Iwork (max (A->nrow, A->ncol)) if fset present, * Iwork (A->nrow) if no fset, * W (A->nrow) if mode > 0, * allocates temporary copy for A'. * * A can be pattern or real. Complex or zomplex cases are supported only * if the mode is <= 0 (in which case the numerical values are ignored). */ #include "cholmod_internal.h" #include "cholmod_core.h" cholmod_sparse *CHOLMOD(aat) ( /* ---- input ---- */ cholmod_sparse *A, /* input matrix; C=A*A' is constructed */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ int mode, /* >0: numerical, 0: pattern, <0: pattern (no diag) * -2: pattern only, no diagonal, add 50% + n extra * space to C */ /* --------------- */ cholmod_common *Common ) { double fjt ; double *Ax, *Fx, *Cx, *W ; Int *Ap, *Anz, *Ai, *Fp, *Fi, *Cp, *Ci, *Flag ; cholmod_sparse *C, *F ; Int packed, j, i, pa, paend, pf, pfend, n, mark, cnz, t, p, values, diag, extra ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; if (A->stype) { ERROR (CHOLMOD_INVALID, "matrix cannot be symmetric") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ diag = (mode >= 0) ; n = A->nrow ; CHOLMOD(allocate_work) (n, MAX (A->ncol, A->nrow), values ? n : 0, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n : 0, Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ; /* get the A matrix */ Ap = A->p ; Anz = A->nz ; Ai = A->i ; Ax = A->x ; packed = A->packed ; /* get workspace */ W = Common->Xwork ; /* size n, unused if values is FALSE */ Flag = Common->Flag ; /* size n, Flag [0..n-1] < mark on input*/ /* ---------------------------------------------------------------------- */ /* F = A' or A(:,f)' */ /* ---------------------------------------------------------------------- */ /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/ F = CHOLMOD(ptranspose) (A, values, NULL, fset, fsize, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } Fp = F->p ; Fi = F->i ; Fx = F->x ; /* ---------------------------------------------------------------------- */ /* count the number of entries in the result C */ /* ---------------------------------------------------------------------- */ cnz = 0 ; for (j = 0 ; j < n ; j++) { /* clear the Flag array */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; /* exclude the diagonal, if requested */ if (!diag) { Flag [j] = mark ; } /* for each nonzero F(t,j) in column j, do: */ pfend = Fp [j+1] ; for (pf = Fp [j] ; pf < pfend ; pf++) { /* F(t,j) is nonzero */ t = Fi [pf] ; /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */ pa = Ap [t] ; paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ; for ( ; pa < paend ; pa++) { i = Ai [pa] ; if (Flag [i] != mark) { Flag [i] = mark ; cnz++ ; } } } if (cnz < 0) { break ; /* integer overflow case */ } } extra = (mode == -2) ? (cnz/2 + n) : 0 ; mark = CHOLMOD(clear_flag) (Common) ; /* ---------------------------------------------------------------------- */ /* check for integer overflow */ /* ---------------------------------------------------------------------- */ if (cnz < 0 || (cnz + extra) < 0) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; CHOLMOD(clear_flag) (Common) ; CHOLMOD(free_sparse) (&F, Common) ; return (NULL) ; /* problem too large */ } /* ---------------------------------------------------------------------- */ /* allocate C */ /* ---------------------------------------------------------------------- */ C = CHOLMOD(allocate_sparse) (n, n, cnz + extra, FALSE, TRUE, 0, values ? A->xtype : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&F, Common) ; return (NULL) ; /* out of memory */ } Cp = C->p ; Ci = C->i ; Cx = C->x ; /* ---------------------------------------------------------------------- */ /* C = A*A' */ /* ---------------------------------------------------------------------- */ cnz = 0 ; if (values) { /* pattern and values */ for (j = 0 ; j < n ; j++) { /* clear the Flag array */ mark = CHOLMOD(clear_flag) (Common) ; /* start column j of C */ Cp [j] = cnz ; /* for each nonzero F(t,j) in column j, do: */ pfend = Fp [j+1] ; for (pf = Fp [j] ; pf < pfend ; pf++) { /* F(t,j) is nonzero */ t = Fi [pf] ; fjt = Fx [pf] ; /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) * and scatter the values into W */ pa = Ap [t] ; paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ; for ( ; pa < paend ; pa++) { i = Ai [pa] ; if (Flag [i] != mark) { Flag [i] = mark ; Ci [cnz++] = i ; } W [i] += Ax [pa] * fjt ; } } /* gather the values into C(:,j) */ for (p = Cp [j] ; p < cnz ; p++) { i = Ci [p] ; Cx [p] = W [i] ; W [i] = 0 ; } } } else { /* pattern only */ for (j = 0 ; j < n ; j++) { /* clear the Flag array */ mark = CHOLMOD(clear_flag) (Common) ; /* exclude the diagonal, if requested */ if (!diag) { Flag [j] = mark ; } /* start column j of C */ Cp [j] = cnz ; /* for each nonzero F(t,j) in column j, do: */ pfend = Fp [j+1] ; for (pf = Fp [j] ; pf < pfend ; pf++) { /* F(t,j) is nonzero */ t = Fi [pf] ; /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */ pa = Ap [t] ; paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ; for ( ; pa < paend ; pa++) { i = Ai [pa] ; if (Flag [i] != mark) { Flag [i] = mark ; Ci [cnz++] = i ; } } } } } Cp [n] = cnz ; ASSERT (IMPLIES (mode != -2, MAX (1,cnz) == C->nzmax)) ; /* ---------------------------------------------------------------------- */ /* clear workspace and free temporary matrices and return result */ /* ---------------------------------------------------------------------- */ CHOLMOD(free_sparse) (&F, Common) ; CHOLMOD(clear_flag) (Common) ; ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n : 0, Common)) ; DEBUG (i = CHOLMOD(dump_sparse) (C, "aat", Common)) ; ASSERT (IMPLIES (mode < 0, i == 0)) ; return (C) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_memory.c0000644000175000017500000004134311674452555022467 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_memory ================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Core memory management routines: * * Primary routines: * ----------------- * cholmod_malloc malloc wrapper * cholmod_free free wrapper * * Secondary routines: * ------------------- * cholmod_calloc calloc wrapper * cholmod_realloc realloc wrapper * cholmod_realloc_multiple realloc wrapper for multiple objects * * The user may make use of these, just like malloc and free. You can even * malloc an object and safely free it with cholmod_free, and visa versa * (except that the memory usage statistics will be corrupted). These routines * do differ from malloc and free. If cholmod_free is given a NULL pointer, * for example, it does nothing (unlike the ANSI free). cholmod_realloc does * not return NULL if given a non-NULL pointer and a nonzero size, even if it * fails (it sets an error code in Common->status instead). * * CHOLMOD keeps track of the amount of memory it has allocated, and so the * cholmod_free routine includes as a parameter the size of the object being * freed. This is only used for memory usage statistics, which are very useful * in finding memory leaks in your program. If you, the user of CHOLMOD, pass * the wrong size, the only consequence is that the memory usage statistics * will be invalid. This will causes assertions to fail if CHOLMOD is * compiled with debugging enabled, but otherwise it will cause no errors. * * The cholmod_free_* routines for each CHOLMOD object keep track of the size * of the blocks they free, so they do not require you to pass their sizes * as a parameter. * * If a block of size zero is requested, these routines allocate a block of * size one instead. */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === cholmod_add_size_t =================================================== */ /* ========================================================================== */ /* Safely compute a+b, and check for integer overflow. If overflow occurs, * return 0 and set OK to FALSE. Also return 0 if OK is FALSE on input. */ size_t CHOLMOD(add_size_t) (size_t a, size_t b, int *ok) { size_t s = a + b ; (*ok) = (*ok) && (s >= a) ; return ((*ok) ? s : 0) ; } /* ========================================================================== */ /* === cholmod_mult_size_t ================================================== */ /* ========================================================================== */ /* Safely compute a*k, where k should be small, and check for integer overflow. * If overflow occurs, return 0 and set OK to FALSE. Also return 0 if OK is * FALSE on input. */ size_t CHOLMOD(mult_size_t) (size_t a, size_t k, int *ok) { size_t p = 0, s ; while (*ok) { if (k % 2) { p = p + a ; (*ok) = (*ok) && (p >= a) ; } k = k / 2 ; if (!k) return (p) ; s = a + a ; (*ok) = (*ok) && (s >= a) ; a = s ; } return (0) ; } /* ========================================================================== */ /* === cholmod_malloc ======================================================= */ /* ========================================================================== */ /* Wrapper around malloc routine. Allocates space of size MAX(1,n)*size, where * size is normally a sizeof (...). * * This routine, cholmod_calloc, and cholmod_realloc do not set Common->status * to CHOLMOD_OK on success, so that a sequence of cholmod_malloc's, _calloc's, * or _realloc's can be used. If any of them fails, the Common->status will * hold the most recent error status. * * Usage, for a pointer to int: * * p = cholmod_malloc (n, sizeof (int), Common) * * Uses a pointer to the malloc routine (or its equivalent) defined in Common. */ void *CHOLMOD(malloc) /* returns pointer to the newly malloc'd block */ ( /* ---- input ---- */ size_t n, /* number of items */ size_t size, /* size of each item */ /* --------------- */ cholmod_common *Common ) { void *p ; size_t s ; int ok = TRUE ; RETURN_IF_NULL_COMMON (NULL) ; if (size == 0) { ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ; p = NULL ; } else if (n >= (Size_max / size) || n >= Int_max) { /* object is too big to allocate without causing integer overflow */ ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; p = NULL ; } else { /* call malloc, or its equivalent */ s = CHOLMOD(mult_size_t) (MAX (1,n), size, &ok) ; p = ok ? ((Common->malloc_memory) (s)) : NULL ; if (p == NULL) { /* failure: out of memory */ ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; } else { /* success: increment the count of objects allocated */ Common->malloc_count++ ; Common->memory_inuse += (n * size) ; Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse) ; PRINTM (("cholmod_malloc %p %d cnt: %d inuse %d\n", p, n*size, Common->malloc_count, Common->memory_inuse)) ; } } return (p) ; } /* ========================================================================== */ /* === cholmod_free ========================================================= */ /* ========================================================================== */ /* Wrapper around free routine. Returns NULL, which can be assigned to the * pointer being freed, as in: * * p = cholmod_free (n, sizeof (int), p, Common) ; * * In CHOLMOD, the syntax: * * cholmod_free (n, sizeof (int), p, Common) ; * * is used if p is a local pointer and the routine is returning shortly. * Uses a pointer to the free routine (or its equivalent) defined in Common. * Nothing is freed if the pointer is NULL. */ void *CHOLMOD(free) /* always returns NULL */ ( /* ---- input ---- */ size_t n, /* number of items */ size_t size, /* size of each item */ /* ---- in/out --- */ void *p, /* block of memory to free */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (NULL) ; if (p != NULL) { /* only free the object if the pointer is not NULL */ /* call free, or its equivalent */ (Common->free_memory) (p) ; Common->malloc_count-- ; Common->memory_inuse -= (n * size) ; PRINTM (("cholmod_free %p %d cnt: %d inuse %d\n", p, n*size, Common->malloc_count, Common->memory_inuse)) ; /* This assertion will fail if the user calls cholmod_malloc and * cholmod_free with mismatched memory sizes. It shouldn't fail * otherwise. */ ASSERT (IMPLIES (Common->malloc_count == 0, Common->memory_inuse == 0)); } /* return NULL, and the caller should assign this to p. This avoids * freeing the same pointer twice. */ return (NULL) ; } /* ========================================================================== */ /* === cholmod_calloc ======================================================= */ /* ========================================================================== */ /* Wrapper around calloc routine. * * Uses a pointer to the calloc routine (or its equivalent) defined in Common. * This routine is identical to malloc, except that it zeros the newly allocated * block to zero. */ void *CHOLMOD(calloc) /* returns pointer to the newly calloc'd block */ ( /* ---- input ---- */ size_t n, /* number of items */ size_t size, /* size of each item */ /* --------------- */ cholmod_common *Common ) { void *p ; RETURN_IF_NULL_COMMON (NULL) ; if (size == 0) { ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ; p = NULL ; } else if (n >= (Size_max / size) || n >= Int_max) { /* object is too big to allocate without causing integer overflow */ ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; p = NULL ; } else { /* call calloc, or its equivalent */ p = (Common->calloc_memory) (MAX (1,n), size) ; if (p == NULL) { /* failure: out of memory */ ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; } else { /* success: increment the count of objects allocated */ Common->malloc_count++ ; Common->memory_inuse += (n * size) ; Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse) ; PRINTM (("cholmod_malloc %p %d cnt: %d inuse %d\n", p, n*size, Common->malloc_count, Common->memory_inuse)) ; } } return (p) ; } /* ========================================================================== */ /* === cholmod_realloc ====================================================== */ /* ========================================================================== */ /* Wrapper around realloc routine. Given a pointer p to a block of size * (*n)*size memory, it changes the size of the block pointed to by p to be * MAX(1,nnew)*size in size. It may return a pointer different than p. This * should be used as (for a pointer to int): * * p = cholmod_realloc (nnew, sizeof (int), p, *n, Common) ; * * If p is NULL, this is the same as p = cholmod_malloc (...). * A size of nnew=0 is treated as nnew=1. * * If the realloc fails, p is returned unchanged and Common->status is set * to CHOLMOD_OUT_OF_MEMORY. If successful, Common->status is not modified, * and p is returned (possibly changed) and pointing to a large block of memory. * * Uses a pointer to the realloc routine (or its equivalent) defined in Common. */ void *CHOLMOD(realloc) /* returns pointer to reallocated block */ ( /* ---- input ---- */ size_t nnew, /* requested # of items in reallocated block */ size_t size, /* size of each item */ /* ---- in/out --- */ void *p, /* block of memory to realloc */ size_t *n, /* current size on input, nnew on output if successful*/ /* --------------- */ cholmod_common *Common ) { size_t nold = (*n) ; void *pnew ; size_t s ; int ok = TRUE ; RETURN_IF_NULL_COMMON (NULL) ; if (size == 0) { ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ; p = NULL ; } else if (p == NULL) { /* A fresh object is being allocated. */ PRINT1 (("realloc fresh: %d %d\n", nnew, size)) ; p = CHOLMOD(malloc) (nnew, size, Common) ; *n = (p == NULL) ? 0 : nnew ; } else if (nold == nnew) { /* Nothing to do. Do not change p or n. */ PRINT1 (("realloc nothing: %d %d\n", nnew, size)) ; } else if (nnew >= (Size_max / size) || nnew >= Int_max) { /* failure: nnew is too big. Do not change p or n. */ ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; } else { /* The object exists, and is changing to some other nonzero size. */ /* call realloc, or its equivalent */ PRINT1 (("realloc : %d to %d, %d\n", nold, nnew, size)) ; pnew = NULL ; s = CHOLMOD(mult_size_t) (MAX (1,nnew), size, &ok) ; pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ; if (pnew == NULL) { /* Do not change p, since it still points to allocated memory */ if (nnew <= nold) { /* The attempt to reduce the size of the block from n to * nnew has failed. The current block is not modified, so * pretend to succeed, but do not change p. Do change * CHOLMOD's notion of the size of the block, however. */ *n = nnew ; PRINTM (("nnew <= nold failed, pretend to succeed\n")) ; PRINTM (("cholmod_free %p %d cnt: %d inuse %d\n" "cholmod_malloc %p %d cnt: %d inuse %d\n", p, nold*size, Common->malloc_count-1, Common->memory_inuse - nold*size, p, nnew*size, Common->malloc_count, Common->memory_inuse + (nnew-nold)*size)) ; Common->memory_inuse += ((nnew-nold) * size) ; } else { /* Increasing the size of the block has failed. * Do not change n. */ ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; } } else { /* success: return revised p and change the size of the block */ PRINTM (("cholmod_free %p %d cnt: %d inuse %d\n" "cholmod_malloc %p %d cnt: %d inuse %d\n", p, nold*size, Common->malloc_count-1, Common->memory_inuse - nold*size, pnew, nnew*size, Common->malloc_count, Common->memory_inuse + (nnew-nold)*size)) ; p = pnew ; *n = nnew ; Common->memory_inuse += ((nnew-nold) * size) ; } Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse); } return (p) ; } /* ========================================================================== */ /* === cholmod_realloc_multiple ============================================= */ /* ========================================================================== */ /* reallocate multiple blocks of memory, all of the same size (up to two integer * and two real blocks). Either reallocations all succeed, or all are returned * in the original size (they are freed if the original size is zero). The nnew * blocks are of size 1 or more. */ int CHOLMOD(realloc_multiple) ( /* ---- input ---- */ size_t nnew, /* requested # of items in reallocated blocks */ int nint, /* number of int/UF_long blocks */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* ---- in/out --- */ void **I, /* int or UF_long block */ void **J, /* int or UF_long block */ void **X, /* complex or double block */ void **Z, /* zomplex case only: double block */ size_t *nold_p, /* current size of the I,J,X,Z blocks on input, * nnew on output if successful */ /* --------------- */ cholmod_common *Common ) { double *xx, *zz ; size_t i, j, x, z, nold ; RETURN_IF_NULL_COMMON (FALSE) ; if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "invalid xtype") ; return (FALSE) ; } nold = *nold_p ; if (nint < 1 && xtype == CHOLMOD_PATTERN) { /* nothing to do */ return (TRUE) ; } i = nold ; j = nold ; x = nold ; z = nold ; if (nint > 0) { *I = CHOLMOD(realloc) (nnew, sizeof (Int), *I, &i, Common) ; } if (nint > 1) { *J = CHOLMOD(realloc) (nnew, sizeof (Int), *J, &j, Common) ; } switch (xtype) { case CHOLMOD_REAL: *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ; break ; case CHOLMOD_COMPLEX: *X = CHOLMOD(realloc) (nnew, 2*sizeof (double), *X, &x, Common) ; break ; case CHOLMOD_ZOMPLEX: *X = CHOLMOD(realloc) (nnew, sizeof (double), *X, &x, Common) ; *Z = CHOLMOD(realloc) (nnew, sizeof (double), *Z, &z, Common) ; break ; } if (Common->status < CHOLMOD_OK) { /* one or more realloc's failed. Resize all back down to nold. */ if (nold == 0) { if (nint > 0) { *I = CHOLMOD(free) (i, sizeof (Int), *I, Common) ; } if (nint > 1) { *J = CHOLMOD(free) (j, sizeof (Int), *J, Common) ; } switch (xtype) { case CHOLMOD_REAL: *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ; break ; case CHOLMOD_COMPLEX: *X = CHOLMOD(free) (x, 2*sizeof (double), *X, Common) ; break ; case CHOLMOD_ZOMPLEX: *X = CHOLMOD(free) (x, sizeof (double), *X, Common) ; *Z = CHOLMOD(free) (x, sizeof (double), *Z, Common) ; break ; } } else { if (nint > 0) { *I = CHOLMOD(realloc) (nold, sizeof (Int), *I, &i, Common) ; } if (nint > 1) { *J = CHOLMOD(realloc) (nold, sizeof (Int), *J, &j, Common) ; } switch (xtype) { case CHOLMOD_REAL: *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x, Common) ; break ; case CHOLMOD_COMPLEX: *X = CHOLMOD(realloc) (nold, 2*sizeof (double), *X, &x, Common) ; break ; case CHOLMOD_ZOMPLEX: *X = CHOLMOD(realloc) (nold, sizeof (double), *X, &x, Common) ; *Z = CHOLMOD(realloc) (nold, sizeof (double), *Z, &z, Common) ; break ; } } return (FALSE) ; } if (nold == 0) { /* New space was allocated. Clear the first entry so that valgrind * doesn't complain about its access in change_complexity * (Core/cholmod_complex.c). */ xx = *X ; zz = *Z ; switch (xtype) { case CHOLMOD_REAL: xx [0] = 0 ; break ; case CHOLMOD_COMPLEX: xx [0] = 0 ; xx [1] = 0 ; break ; case CHOLMOD_ZOMPLEX: xx [0] = 0 ; zz [0] = 0 ; break ; } } /* all realloc's succeeded, change size to reflect realloc'ed size. */ *nold_p = nnew ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_complex.c0000644000175000017500000004002411674452555022621 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_complex ================================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* If you convert a matrix that contains uninitialized data, valgrind will * complain. This can occur in a factor L which has gaps (a partial * factorization, or after updates that change the nonzero pattern), an * unpacked sparse matrix, a dense matrix with leading dimension d > # of rows, * or any matrix (dense, sparse, triplet, or factor) with more space allocated * than is used. You can safely ignore any of these complaints by valgrind. */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === cholmod_hypot ======================================================== */ /* ========================================================================== */ /* There is an equivalent routine called hypot in , which conforms * to ANSI C99. However, CHOLMOD does not assume that ANSI C99 is available. * You can use the ANSI C99 hypot routine with: * * #include * Common->hypotenuse = hypot ; * * Default value of the Common->hypotenuse pointer is cholmod_hypot. * * s = hypot (x,y) computes s = sqrt (x*x + y*y) but does so more accurately. * The NaN cases for the double relops x >= y and x+y == x are safely ignored. * * Source: Algorithm 312, "Absolute value and square root of a complex number," * P. Friedland, Comm. ACM, vol 10, no 10, October 1967, page 665. */ double CHOLMOD(hypot) (double x, double y) { double s, r ; x = fabs (x) ; y = fabs (y) ; if (x >= y) { if (x + y == x) { s = x ; } else { r = y / x ; s = x * sqrt (1.0 + r*r) ; } } else { if (y + x == y) { s = y ; } else { r = x / y ; s = y * sqrt (1.0 + r*r) ; } } return (s) ; } /* ========================================================================== */ /* === cholmod_divcomplex =================================================== */ /* ========================================================================== */ /* c = a/b where c, a, and b are complex. The real and imaginary parts are * passed as separate arguments to this routine. The NaN case is ignored * for the double relop br >= bi. Returns 1 if the denominator is zero, * 0 otherwise. Note that this return value is the single exception to the * rule that all CHOLMOD routines that return int return TRUE if successful * or FALSE otherise. * * This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid * underflow and overflow. * * c can be the same variable as a or b. * * Default value of the Common->complex_divide pointer is cholmod_divcomplex. */ int CHOLMOD(divcomplex) ( double ar, double ai, /* real and imaginary parts of a */ double br, double bi, /* real and imaginary parts of b */ double *cr, double *ci /* real and imaginary parts of c */ ) { double tr, ti, r, den ; if (fabs (br) >= fabs (bi)) { r = bi / br ; den = br + r * bi ; tr = (ar + ai * r) / den ; ti = (ai - ar * r) / den ; } else { r = br / bi ; den = r * br + bi ; tr = (ar * r + ai) / den ; ti = (ai * r - ar) / den ; } *cr = tr ; *ci = ti ; return (IS_ZERO (den)) ; } /* ========================================================================== */ /* === change_complexity ==================================================== */ /* ========================================================================== */ /* X and Z represent an array of size nz, with numeric xtype given by xtype_in. * * If xtype_in is: * CHOLMOD_PATTERN: X and Z must be NULL. * CHOLMOD_REAL: X is of size nz, Z must be NULL. * CHOLMOD_COMPLEX: X is of size 2*nz, Z must be NULL. * CHOLMOD_ZOMPLEX: X is of size nz, Z is of size nz. * * The array is changed into the numeric xtype given by xtype_out, with the * same definitions of X and Z above. Note that the input conditions, above, * are not checked. These are checked in the caller routine. * * Returns TRUE if successful, FALSE otherwise. X and Z are not modified if * not successful. */ static int change_complexity ( /* ---- input ---- */ Int nz, /* size of X and/or Z */ int xtype_in, /* xtype of X and Z on input */ int xtype_out, /* requested xtype of X and Z on output */ int xtype1, /* xtype_out must be in the range [xtype1 .. xtype2] */ int xtype2, /* ---- in/out --- */ void **XX, /* old X on input, new X on output */ void **ZZ, /* old Z on input, new Z on output */ /* --------------- */ cholmod_common *Common ) { double *Xold, *Zold, *Xnew, *Znew ; Int k ; size_t nz2 ; if (xtype_out < xtype1 || xtype_out > xtype2) { ERROR (CHOLMOD_INVALID, "invalid xtype") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; Xold = *XX ; Zold = *ZZ ; switch (xtype_in) { /* ------------------------------------------------------------------ */ /* converting from pattern */ /* ------------------------------------------------------------------ */ case CHOLMOD_PATTERN: switch (xtype_out) { /* ---------------------------------------------------------- */ /* pattern -> real */ /* ---------------------------------------------------------- */ case CHOLMOD_REAL: /* allocate X and set to all ones */ Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } for (k = 0 ; k < nz ; k++) { Xnew [k] = 1 ; } *XX = Xnew ; break ; /* ---------------------------------------------------------- */ /* pattern -> complex */ /* ---------------------------------------------------------- */ case CHOLMOD_COMPLEX: /* allocate X and set to all ones */ Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } for (k = 0 ; k < nz ; k++) { Xnew [2*k ] = 1 ; Xnew [2*k+1] = 0 ; } *XX = Xnew ; break ; /* ---------------------------------------------------------- */ /* pattern -> zomplex */ /* ---------------------------------------------------------- */ case CHOLMOD_ZOMPLEX: /* allocate X and Z and set to all ones */ Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ; Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free) (nz, sizeof (double), Xnew, Common) ; CHOLMOD(free) (nz, sizeof (double), Znew, Common) ; return (FALSE) ; } for (k = 0 ; k < nz ; k++) { Xnew [k] = 1 ; Znew [k] = 0 ; } *XX = Xnew ; *ZZ = Znew ; break ; } break ; /* ------------------------------------------------------------------ */ /* converting from real */ /* ------------------------------------------------------------------ */ case CHOLMOD_REAL: switch (xtype_out) { /* ---------------------------------------------------------- */ /* real -> pattern */ /* ---------------------------------------------------------- */ case CHOLMOD_PATTERN: /* free X */ *XX = CHOLMOD(free) (nz, sizeof (double), *XX, Common) ; break ; /* ---------------------------------------------------------- */ /* real -> complex */ /* ---------------------------------------------------------- */ case CHOLMOD_COMPLEX: /* allocate a new X and copy the old X */ Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } for (k = 0 ; k < nz ; k++) { Xnew [2*k ] = Xold [k] ; Xnew [2*k+1] = 0 ; } CHOLMOD(free) (nz, sizeof (double), *XX, Common) ; *XX = Xnew ; break ; /* ---------------------------------------------------------- */ /* real -> zomplex */ /* ---------------------------------------------------------- */ case CHOLMOD_ZOMPLEX: /* allocate a new Z and set it to zero */ Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } for (k = 0 ; k < nz ; k++) { Znew [k] = 0 ; } *ZZ = Znew ; break ; } break ; /* ------------------------------------------------------------------ */ /* converting from complex */ /* ------------------------------------------------------------------ */ case CHOLMOD_COMPLEX: switch (xtype_out) { /* ---------------------------------------------------------- */ /* complex -> pattern */ /* ---------------------------------------------------------- */ case CHOLMOD_PATTERN: /* free X */ *XX = CHOLMOD(free) (nz, 2*sizeof (double), *XX, Common) ; break ; /* ---------------------------------------------------------- */ /* complex -> real */ /* ---------------------------------------------------------- */ case CHOLMOD_REAL: /* pack the real part of X, discarding the imaginary part */ for (k = 0 ; k < nz ; k++) { Xold [k] = Xold [2*k] ; } /* shrink X in half (this cannot fail) */ nz2 = 2*nz ; *XX = CHOLMOD(realloc) (nz, sizeof (double), *XX, &nz2, Common) ; break ; /* ---------------------------------------------------------- */ /* complex -> zomplex */ /* ---------------------------------------------------------- */ case CHOLMOD_ZOMPLEX: /* allocate X and Z and copy the old X into them */ Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ; Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free) (nz, sizeof (double), Xnew, Common) ; CHOLMOD(free) (nz, sizeof (double), Znew, Common) ; return (FALSE) ; } for (k = 0 ; k < nz ; k++) { Xnew [k] = Xold [2*k ] ; Znew [k] = Xold [2*k+1] ; } CHOLMOD(free) (nz, 2*sizeof (double), *XX, Common) ; *XX = Xnew ; *ZZ = Znew ; break ; } break ; /* ------------------------------------------------------------------ */ /* converting from zomplex */ /* ------------------------------------------------------------------ */ case CHOLMOD_ZOMPLEX: switch (xtype_out) { /* ---------------------------------------------------------- */ /* zomplex -> pattern */ /* ---------------------------------------------------------- */ case CHOLMOD_PATTERN: /* free X and Z */ *XX = CHOLMOD(free) (nz, sizeof (double), *XX, Common) ; *ZZ = CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ; break ; /* ---------------------------------------------------------- */ /* zomplex -> real */ /* ---------------------------------------------------------- */ case CHOLMOD_REAL: /* free the imaginary part */ *ZZ = CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ; break ; /* ---------------------------------------------------------- */ /* zomplex -> complex */ /* ---------------------------------------------------------- */ case CHOLMOD_COMPLEX: Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; } for (k = 0 ; k < nz ; k++) { Xnew [2*k ] = Xold [k] ; Xnew [2*k+1] = Zold [k] ; } CHOLMOD(free) (nz, sizeof (double), *XX, Common) ; CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ; *XX = Xnew ; *ZZ = NULL ; break ; } break ; } return (TRUE) ; } /* ========================================================================== */ /* === cholmod_sparse_xtype ================================================= */ /* ========================================================================== */ /* Change the numeric xtype of a sparse matrix. Supports any type on input * and output (pattern, real, complex, or zomplex). */ int CHOLMOD(sparse_xtype) ( /* ---- input ---- */ int to_xtype, /* requested xtype */ /* ---- in/out --- */ cholmod_sparse *A, /* sparse matrix to change */ /* --------------- */ cholmod_common *Common ) { Int ok ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; ok = change_complexity (A->nzmax, A->xtype, to_xtype, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, &(A->x), &(A->z), Common) ; if (ok) { A->xtype = to_xtype ; } return (ok) ; } /* ========================================================================== */ /* === cholmod_triplet_xtype ================================================ */ /* ========================================================================== */ /* Change the numeric xtype of a triplet matrix. Supports any type on input * and output (pattern, real, complex, or zomplex). */ int CHOLMOD(triplet_xtype) ( /* ---- input ---- */ int to_xtype, /* requested xtype */ /* ---- in/out --- */ cholmod_triplet *T, /* triplet matrix to change */ /* --------------- */ cholmod_common *Common ) { Int ok ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (T, FALSE) ; RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; ok = change_complexity (T->nzmax, T->xtype, to_xtype, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, &(T->x), &(T->z), Common) ; if (ok) { T->xtype = to_xtype ; } return (ok) ; } /* ========================================================================== */ /* === cholmod_dense_xtype ================================================= */ /* ========================================================================== */ /* Change the numeric xtype of a dense matrix. Supports real, complex or * zomplex on input and output */ int CHOLMOD(dense_xtype) ( /* ---- input ---- */ int to_xtype, /* requested xtype */ /* ---- in/out --- */ cholmod_dense *X, /* dense matrix to change */ /* --------------- */ cholmod_common *Common ) { Int ok ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (X, FALSE) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; ok = change_complexity (X->nzmax, X->xtype, to_xtype, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, &(X->x), &(X->z), Common) ; if (ok) { X->xtype = to_xtype ; } return (ok) ; } /* ========================================================================== */ /* === cholmod_factor_xtype ================================================= */ /* ========================================================================== */ /* Change the numeric xtype of a factor. Supports real, complex or zomplex on * input and output. Supernodal zomplex factors are not supported. */ int CHOLMOD(factor_xtype) ( /* ---- input ---- */ int to_xtype, /* requested xtype */ /* ---- in/out --- */ cholmod_factor *L, /* factor to change */ /* --------------- */ cholmod_common *Common ) { Int ok ; RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; if (L->is_super && (L->xtype == CHOLMOD_ZOMPLEX || to_xtype == CHOLMOD_ZOMPLEX)) { ERROR (CHOLMOD_INVALID, "invalid xtype for supernodal L") ; return (FALSE) ; } ok = change_complexity ((L->is_super ? L->xsize : L->nzmax), L->xtype, to_xtype, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, &(L->x), &(L->z), Common) ; if (ok) { L->xtype = to_xtype ; } return (ok) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_add.c0000644000175000017500000002031311674452555021701 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_add ===================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* C = alpha*A + beta*B, or spones(A+B). Result is packed, with sorted or * unsorted columns. This routine is much faster and takes less memory if C * is allowed to have unsorted columns. * * If A and B are both symmetric (in upper form) then C is the same. Likewise, * if A and B are both symmetric (in lower form) then C is the same. * Otherwise, C is unsymmetric. A and B must have the same dimension. * * workspace: Flag (nrow), W (nrow) if values, Iwork (max (nrow,ncol)). * allocates temporary copies for A and B if they are symmetric. * allocates temporary copy of C if it is to be returned sorted. * * A and B can have an xtype of pattern or real. Complex or zomplex cases * are supported only if the "values" input parameter is FALSE. */ #include "cholmod_internal.h" #include "cholmod_core.h" cholmod_sparse *CHOLMOD(add) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to add */ cholmod_sparse *B, /* matrix to add */ double alpha [2], /* scale factor for A */ double beta [2], /* scale factor for B */ int values, /* if TRUE compute the numerical values of C */ int sorted, /* if TRUE, sort columns of C */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Bx, *Cx, *W ; Int apacked, up, lo, nrow, ncol, bpacked, nzmax, pa, paend, pb, pbend, i, j, p, mark, nz ; Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Flag, *Cp, *Ci ; cholmod_sparse *A2, *B2, *C ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_NULL (B, NULL) ; values = values && (A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ; if (A->nrow != B->nrow || A->ncol != B->ncol) { /* A and B must have the same dimensions */ ERROR (CHOLMOD_INVALID, "A and B dimesions do not match") ; return (NULL) ; } /* A and B must have the same numerical type if values is TRUE (both must * be CHOLMOD_REAL, this is implicitly checked above) */ Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; CHOLMOD(allocate_work) (nrow, MAX (nrow,ncol), values ? nrow : 0, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ if (nrow <= 1) { /* C will be implicitly sorted, so no need to sort it here */ sorted = FALSE ; } /* convert A or B to unsymmetric, if necessary */ A2 = NULL ; B2 = NULL ; if (A->stype != B->stype) { if (A->stype) { /* workspace: Iwork (max (nrow,ncol)) */ A2 = CHOLMOD(copy) (A, 0, values, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } A = A2 ; } if (B->stype) { /* workspace: Iwork (max (nrow,ncol)) */ B2 = CHOLMOD(copy) (B, 0, values, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&A2, Common) ; return (NULL) ; /* out of memory */ } B = B2 ; } } /* get the A matrix */ ASSERT (A->stype == B->stype) ; up = (A->stype > 0) ; lo = (A->stype < 0) ; Ap = A->p ; Anz = A->nz ; Ai = A->i ; Ax = A->x ; apacked = A->packed ; /* get the B matrix */ Bp = B->p ; Bnz = B->nz ; Bi = B->i ; Bx = B->x ; bpacked = B->packed ; /* get workspace */ W = Common->Xwork ; /* size nrow, used if values is TRUE */ Flag = Common->Flag ; /* size nrow, Flag [0..nrow-1] < mark on input */ /* ---------------------------------------------------------------------- */ /* allocate the result C */ /* ---------------------------------------------------------------------- */ /* If integer overflow occurs, nzmax < 0 and the allocate fails properly * (likewise in most other matrix manipulation routines). */ nzmax = CHOLMOD(nnz) (A, Common) + CHOLMOD(nnz) (B, Common) ; C = CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, FALSE, TRUE, SIGN (A->stype), values ? A->xtype : CHOLMOD_PATTERN, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; return (NULL) ; /* out of memory */ } Cp = C->p ; Ci = C->i ; Cx = C->x ; /* ---------------------------------------------------------------------- */ /* compute C = alpha*A + beta*B */ /* ---------------------------------------------------------------------- */ nz = 0 ; for (j = 0 ; j < ncol ; j++) { Cp [j] = nz ; /* clear the Flag array */ /* mark = CHOLMOD(clear_flag) (Common) ; */ CHOLMOD_CLEAR_FLAG (Common) ; mark = Common->mark ; /* scatter B into W */ pb = Bp [j] ; pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ; for (p = pb ; p < pbend ; p++) { i = Bi [p] ; if ((up && i > j) || (lo && i < j)) { continue ; } Flag [i] = mark ; if (values) { W [i] = beta [0] * Bx [p] ; } } /* add A and gather from W into C(:,j) */ pa = Ap [j] ; paend = (apacked) ? (Ap [j+1]) : (pa + Anz [j]) ; for (p = pa ; p < paend ; p++) { i = Ai [p] ; if ((up && i > j) || (lo && i < j)) { continue ; } Flag [i] = EMPTY ; Ci [nz] = i ; if (values) { Cx [nz] = W [i] + alpha [0] * Ax [p] ; W [i] = 0 ; } nz++ ; } /* gather remaining entries into C(:,j), using pattern of B */ for (p = pb ; p < pbend ; p++) { i = Bi [p] ; if ((up && i > j) || (lo && i < j)) { continue ; } if (Flag [i] == mark) { Ci [nz] = i ; if (values) { Cx [nz] = W [i] ; W [i] = 0 ; } nz++ ; } } } Cp [ncol] = nz ; /* ---------------------------------------------------------------------- */ /* reduce C in size and free temporary matrices */ /* ---------------------------------------------------------------------- */ ASSERT (MAX (1,nz) <= C->nzmax) ; CHOLMOD(reallocate_sparse) (nz, C, Common) ; ASSERT (Common->status >= CHOLMOD_OK) ; /* clear the Flag array */ mark = CHOLMOD(clear_flag) (Common) ; CHOLMOD(free_sparse) (&A2, Common) ; CHOLMOD(free_sparse) (&B2, Common) ; /* ---------------------------------------------------------------------- */ /* sort C, if requested */ /* ---------------------------------------------------------------------- */ if (sorted) { /* workspace: Iwork (max (nrow,ncol)) */ if (!CHOLMOD(sort) (C, Common)) { CHOLMOD(free_sparse) (&C, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } } } /* ---------------------------------------------------------------------- */ /* return result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_sparse) (C, "add", Common) >= 0) ; return (C) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_change_factor.c0000644000175000017500000003756611674452555024301 0ustar sonnesonne/* ========================================================================== */ /* === Core/t_cholmod_change_factor ========================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_change_factor. All xtypes supported. */ #include "cholmod_template.h" /* ========================================================================== */ /* === t_change_simplicial_numeric ========================================== */ /* ========================================================================== */ static void TEMPLATE (change_simplicial_numeric) ( cholmod_factor *L, Int to_ll, Int to_packed, Int *newLi, double *newLx, double *newLz, Int lnz, Int grow, double grow1, Int grow2, Int make_ll, Int make_monotonic, Int make_ldl, cholmod_common *Common ) { double xlen, dj [1], ljj [1], lj2 [1] ; double *Lx, *Lz ; Int *Lp, *Li, *Lnz ; Int n, j, len, pnew, pold, k, p, pend ; n = L->n ; Lp = L->p ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lnz = L->nz ; if (make_ll) { L->minor = n ; } if (make_monotonic) { /* ------------------------------------------------------------------ */ /* reorder the columns to make them monotonic */ /* ------------------------------------------------------------------ */ pnew = 0 ; for (j = 0 ; j < n ; j++) { /* copy and pack column j */ len = Lnz [j] ; PRINT2 (("j: "ID" Lnz[j] "ID" len "ID" p "ID"\n", j, Lnz [j], len, pnew)) ; pold = Lp [j] ; ASSERT (Li [pold] == j) ; if (make_ll) { /* ---------------------------------------------------------- */ /* copy and convert LDL' to LL' */ /* ---------------------------------------------------------- */ /* dj = Lx [pold] ; */ ASSIGN_REAL (dj,0, Lx,pold) ; if (IS_LE_ZERO (dj [0])) { /* Conversion has failed; matrix is not positive definite. * Do not modify the column so that the LDL' factorization * can be restored if desired, by converting back to LDL'. * Continue the conversion, but flag the error. */ if (L->minor == (size_t) n) { ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ; L->minor = j ; } for (k = 0 ; k < len ; k++) { newLi [pnew + k] = Li [pold + k] ; /* newLx [pnew + k] = Lx [pold + k] ; */ ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ; } } else { ljj [0] = sqrt (dj [0]) ; newLi [pnew] = j ; /* newLx [pnew] = ljj ; */ ASSIGN_REAL (newLx, pnew, ljj, 0) ; CLEAR_IMAG (newLx, newLz, pnew) ; for (k = 1 ; k < len ; k++) { newLi [pnew + k] = Li [pold + k] ; /* newLx [pnew + k] = Lx [pold + k] * ljj ; */ MULT_REAL (newLx, newLz, pnew+k, Lx, Lz, pold+k, ljj,0); } } } else if (make_ldl) { /* ---------------------------------------------------------- */ /* copy and convert LL' to LDL' */ /* ---------------------------------------------------------- */ /* ljj = Lx [pold] ; */ ASSIGN_REAL (ljj, 0, Lx, pold) ; if (ljj [0] <= 0) { /* matrix is not positive-definite; copy column as-is */ for (k = 0 ; k < len ; k++) { newLi [pnew + k] = Li [pold + k] ; /* newLx [pnew + k] = Lx [pold + k] ; */ ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ; } } else { newLi [pnew] = j ; /* newLx [pnew] = ljj*ljj ; */ lj2 [0] = ljj [0] * ljj [0] ; ASSIGN_REAL (newLx, pnew, lj2, 0) ; CLEAR_IMAG (newLx, newLz, pnew) ; for (k = 1 ; k < len ; k++) { newLi [pnew + k] = Li [pold + k] ; /* newLx [pnew + k] = Lx [pold + k] / ljj ; */ DIV_REAL (newLx, newLz, pnew+k, Lx, Lz, pold+k, ljj,0) ; } } } else { /* ---------------------------------------------------------- */ /* copy and leave LL' or LDL' as-is */ /* ---------------------------------------------------------- */ for (k = 0 ; k < len ; k++) { newLi [pnew + k] = Li [pold + k] ; /* newLx [pnew + k] = Lx [pold + k] ; */ ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ; } } Lp [j] = pnew ; /* compute len in double to avoid integer overflow */ if (grow) { xlen = (double) len ; xlen = grow1 * xlen + grow2 ; xlen = MIN (xlen, n-j) ; len = (Int) xlen ; } ASSERT (len >= Lnz [j] && len <= n-j) ; pnew += len ; ASSERT (pnew > 0) ; /* integer overflow case already covered */ } Lp [n] = pnew ; PRINT1 (("final pnew = "ID", lnz "ID" lnzmax %g\n", pnew, lnz, (double) L->nzmax)) ; ASSERT (pnew <= lnz) ; /* free the old L->i and L->x and replace with the new ones */ CHOLMOD(free) (L->nzmax, sizeof (Int), L->i, Common) ; #ifdef REAL CHOLMOD(free) (L->nzmax, sizeof (double), L->x, Common) ; #elif defined (COMPLEX) CHOLMOD(free) (L->nzmax, 2*sizeof (double), L->x, Common) ; #else CHOLMOD(free) (L->nzmax, sizeof (double), L->x, Common) ; CHOLMOD(free) (L->nzmax, sizeof (double), L->z, Common) ; #endif L->i = newLi ; L->x = newLx ; L->z = newLz ; L->nzmax = lnz ; /* reconstruct the link list */ natural_list (L) ; } else if (to_packed) { /* ------------------------------------------------------------------ */ /* already monotonic, just pack the columns of L */ /* ------------------------------------------------------------------ */ pnew = 0 ; if (make_ll) { /* -------------------------------------------------------------- */ /* pack and convert LDL' to LL' */ /* -------------------------------------------------------------- */ for (j = 0 ; j < n ; j++) { /* pack column j */ pold = Lp [j] ; len = Lnz [j] ; ASSERT (len > 0) ; ASSERT (Li [pold] == j) ; PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ; /* dj = Lx [pold] ; */ ASSIGN_REAL (dj,0, Lx,pold) ; if (IS_LE_ZERO (dj [0])) { /* Conversion has failed; matrix is not positive definite. * Do not modify the column so that the LDL' factorization * can be restored if desired, by converting back to LDL'. * Continue the conversion, but flag the error. */ if (L->minor == (size_t) n) { ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ; L->minor = j ; } for (k = 0 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; /* Lx [pnew + k] = Lx [pold + k] ; */ ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ; } } else { ljj [0] = sqrt (dj [0]) ; Li [pnew] = j ; /* Lx [pnew] = ljj ; */ ASSIGN_REAL (Lx, pnew, ljj, 0) ; CLEAR_IMAG (Lx, Lz, pnew) ; for (k = 1 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; /* Lx [pnew + k] = Lx [pold + k] * ljj ; */ MULT_REAL (Lx, Lz, pnew+k, Lx, Lz, pold+k, ljj,0) ; } } Lp [j] = pnew ; pnew += len ; } } else if (make_ldl) { /* -------------------------------------------------------------- */ /* pack and convert LL' to LDL' */ /* -------------------------------------------------------------- */ for (j = 0 ; j < n ; j++) { /* pack column j */ pold = Lp [j] ; len = Lnz [j] ; /* ljj = Lx [pold] ; */ ASSIGN_REAL (ljj, 0, Lx, pold) ; ASSERT (len > 0) ; PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ; if (ljj [0] <= 0) { /* matrix is not positive-definite; pack column as-is */ for (k = 0 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; /* Lx [pnew + k] = Lx [pold + k] ; */ ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ; } } else { Li [pnew] = Li [pold] ; /* Lx [pnew] = ljj*ljj ; */ lj2 [0] = ljj [0] * ljj [0] ; ASSIGN_REAL (Lx, pnew, lj2, 0) ; CLEAR_IMAG (Lx, Lz, pnew) ; for (k = 1 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; /* Lx [pnew + k] = Lx [pold + k] / ljj ; */ DIV_REAL (Lx, Lz, pnew+k, Lx, Lz, pold+k, ljj,0) ; } } Lp [j] = pnew ; pnew += len ; } } else { /* ---------------------------------------------------------- */ /* pack and leave LL' or LDL' as-is */ /* ---------------------------------------------------------- */ for (j = 0 ; j < n ; j++) { /* pack column j */ pold = Lp [j] ; len = Lnz [j] ; ASSERT (len > 0) ; PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ; if (pnew < pold) { PRINT2 ((" pack this column\n")) ; for (k = 0 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; /* Lx [pnew + k] = Lx [pold + k] ; */ ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ; } Lp [j] = pnew ; } pnew += len ; } } Lp [n] = pnew ; PRINT2 (("Lp [n] = "ID"\n", pnew)) ; } else if (make_ll) { /* ------------------------------------------------------------------ */ /* convert LDL' to LL', but do so in-place */ /* ------------------------------------------------------------------ */ for (j = 0 ; j < n ; j++) { p = Lp [j] ; pend = p + Lnz [j] ; /* dj = Lx [p] ; */ ASSIGN_REAL (dj,0, Lx,p) ; if (IS_LE_ZERO (dj [0])) { /* Conversion has failed; matrix is not positive definite. * Do not modify the column so that the LDL' factorization * can be restored if desired, by converting back to LDL'. * Continue the conversion, but flag the error. */ if (L->minor == (size_t) n) { ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ; L->minor = j ; } } else { ljj [0] = sqrt (dj [0]) ; /* Lx [p] = ljj ; */ ASSIGN_REAL (Lx,p, ljj,0) ; CLEAR_IMAG (Lx, Lz, p) ; for (p++ ; p < pend ; p++) { /* Lx [p] *= ljj ; */ MULT_REAL (Lx,Lz,p, Lx,Lz,p, ljj,0) ; } } } } else if (make_ldl) { /* ------------------------------------------------------------------ */ /* convert LL' to LDL', but do so in-place */ /* ------------------------------------------------------------------ */ for (j = 0 ; j < n ; j++) { p = Lp [j] ; pend = p + Lnz [j] ; /* ljj = Lx [p] ; */ ASSIGN_REAL (ljj, 0, Lx, p) ; if (ljj [0] > 0) { /* Lx [p] = ljj*ljj ; */ lj2 [0] = ljj [0] * ljj [0] ; ASSIGN_REAL (Lx, p, lj2, 0) ; CLEAR_IMAG (Lx, Lz, p) ; for (p++ ; p < pend ; p++) { /* Lx [p] /= ljj ; */ DIV_REAL (Lx,Lz,p, Lx,Lz,p, ljj,0) ; } } } } L->is_ll = to_ll ; DEBUG (CHOLMOD(dump_factor) (L, "done change simplicial numeric", Common)) ; } /* ========================================================================== */ /* === t_ll_super_to_simplicial_numeric ===================================== */ /* ========================================================================== */ /* A supernodal L can only be real or complex, not zomplex */ #ifndef ZOMPLEX static void TEMPLATE (ll_super_to_simplicial_numeric) ( cholmod_factor *L, Int to_packed, Int to_ll, cholmod_common *Common ) { double ljj [1], lj2 [1] ; double *Lx ; Int *Ls, *Lpi, *Lpx, *Super, *Lp, *Li, *Lnz ; Int n, lnz, s, nsuper, p, psi, psx, psend, nsrow, nscol, ii, jj, j, k1, k2, q ; L->is_ll = to_ll ; Lp = L->p ; Li = L->i ; Lx = L->x ; Lnz = L->nz ; lnz = L->nzmax ; n = L->n ; nsuper = L->nsuper ; Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; Super = L->super ; p = 0 ; for (s = 0 ; s < nsuper ; s++) { k1 = Super [s] ; k2 = Super [s+1] ; psi = Lpi [s] ; psend = Lpi [s+1] ; psx = Lpx [s] ; nsrow = psend - psi ; nscol = k2 - k1 ; for (jj = 0 ; jj < nscol ; jj++) { /* column j of L starts here */ j = jj + k1 ; if (to_ll) { if (to_packed) { /* ------------------------------------------------------ */ /* convert to LL' packed */ /* ------------------------------------------------------ */ Lp [j] = p ; PRINT2 (("Col j "ID" p "ID"\n", j, p)) ; for (ii = jj ; ii < nsrow ; ii++) { /* get L(i,j) from supernode and store in column j */ ASSERT (p < (Int) (L->xsize) && p <= psx+ii+jj*nsrow) ; Li [p] = Ls [psi + ii] ; /* Lx [p] = Lx [psx + ii + jj*nsrow] ; */ q = psx + ii + jj*nsrow ; ASSIGN (Lx,-,p, Lx,-,q) ; PRINT2 ((" i "ID" ", Li [p])) ; XPRINT2 (Lx,-,q) ; PRINT2 (("\n")) ; p++ ; } Lnz [j] = p - Lp [j] ; } else { /* ------------------------------------------------------ */ /* convert to LL' unpacked */ /* ------------------------------------------------------ */ p = psx + jj + jj*nsrow ; Lp [j] = p ; Li [p] = j ; Lnz [j] = nsrow - jj ; p++ ; for (ii = jj + 1 ; ii < nsrow ; ii++) { /* get L(i,j) from supernode and store in column j */ Li [psx + ii + jj*nsrow] = Ls [psi + ii] ; } } } else { if (to_packed) { /* ------------------------------------------------------ */ /* convert to LDL' packed */ /* ------------------------------------------------------ */ Lp [j] = p ; PRINT2 (("Col j "ID" p "ID"\n", Lp [j], p)) ; /* ljj = Lx [psx + jj + jj*nsrow] ; */ ASSIGN_REAL (ljj, 0, Lx, psx + jj + jj*nsrow) ; if (ljj [0] <= 0) { /* the matrix is not positive definite; do not divide */ /* Lx [p] = ljj ; */ ASSIGN_REAL (Lx, p, ljj, 0) ; CLEAR_IMAG (Lx, Lz, p) ; ljj [0] = 1 ; } else { lj2 [0] = ljj [0] * ljj [0] ; /* Lx [p] = ljj*ljj ; */ ASSIGN_REAL (Lx, p, lj2, 0) ; CLEAR_IMAG (Lx, Lz, p) ; } Li [p] = j ; p++ ; for (ii = jj + 1 ; ii < nsrow ; ii++) { /* get L(i,j) from supernode and store in column j */ ASSERT (p < (Int) (L->xsize) && p <= psx+ii+jj*nsrow) ; Li [p] = Ls [psi + ii] ; /* Lx [p] = Lx [psx + ii + jj*nsrow] / ljj ; */ q = psx + ii + jj*nsrow ; DIV_REAL (Lx, Lz, p, Lx, Lz, q, ljj,0) ; PRINT2 ((" i "ID" %g\n", Li [p], Lx [p])) ; p++ ; } Lnz [j] = p - Lp [j] ; } else { /* ------------------------------------------------------ */ /* convert to LDL' unpacked */ /* ------------------------------------------------------ */ p = psx + jj + jj*nsrow ; Lp [j] = p ; /* ljj = Lx [p] ; */ ASSIGN_REAL (ljj,0, Lx,p) ; if (ljj [0] <= 0) { /* the matrix is not positive definite; do not divide */ /* Lx [p] = ljj ; */ ASSIGN_REAL (Lx, p, ljj, 0) ; CLEAR_IMAG (Lx, Lz, p) ; ljj [0] = 1 ; } else { lj2 [0] = ljj [0] * ljj [0] ; /* Lx [p] = ljj*ljj ; */ ASSIGN_REAL (Lx, p, lj2, 0) ; CLEAR_IMAG (Lx, Lz, p) ; } Li [p] = j ; Lnz [j] = nsrow - jj ; p++ ; for (ii = jj + 1 ; ii < nsrow ; ii++) { /* get L(i,j) from supernode and store in column j */ Li [psx + ii + jj*nsrow] = Ls [psi + ii] ; /* Lx [psx + ii + jj*nsrow] /= ljj ; */ q = psx + ii + jj*nsrow ; DIV_REAL (Lx, Lz, q, Lx, Lz, q, ljj,0) ; } } } } } if (to_packed) { Lp [n] = p ; PRINT1 (("Final Lp "ID" n "ID" lnz "ID"\n", p, n, lnz)) ; ASSERT (Lp [n] == lnz) ; ASSERT (lnz <= (Int) (L->xsize)) ; /* reduce size of L->x to match L->i. This cannot fail. */ L->x = CHOLMOD(realloc) (lnz, #ifdef COMPLEX 2 * #endif sizeof (double), L->x, &(L->xsize), Common) ; ASSERT (lnz == (Int) (L->xsize)) ; Common->status = CHOLMOD_OK ; } else { Lp [n] = Lpx [nsuper] ; ASSERT (MAX (1,Lp [n]) == (Int) (L->xsize)) ; ASSERT (MAX (1,Lp [n]) == (Int) (L->nzmax)) ; } } #endif #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_dense.c0000644000175000017500000004440611674452555022260 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_dense =================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Core utility routines for the cholmod_dense object: * * The solve routines and some of the MatrixOps and Modify routines use dense * matrices as inputs. These are held in column-major order. With a leading * dimension of d, the entry in row i and column j is held in x [i+j*d]. * * Primary routines: * ----------------- * cholmod_allocate_dense allocate a dense matrix * cholmod_free_dense free a dense matrix * * Secondary routines: * ------------------- * cholmod_zeros allocate a dense matrix of all zeros * cholmod_ones allocate a dense matrix of all ones * cholmod_eye allocate a dense identity matrix * cholmod_sparse_to_dense create a dense matrix copy of a sparse matrix * cholmod_dense_to_sparse create a sparse matrix copy of a dense matrix * cholmod_copy_dense create a copy of a dense matrix * cholmod_copy_dense2 copy a dense matrix (pre-allocated) * * All routines in this file can handle the real, complex, and zomplex cases. * Pattern-only dense matrices are not supported. cholmod_sparse_to_dense can * take a pattern-only input sparse matrix, however, and cholmod_dense_to_sparse * can generate a pattern-only output sparse matrix. */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define PATTERN #include "t_cholmod_dense.c" #define REAL #include "t_cholmod_dense.c" #define COMPLEX #include "t_cholmod_dense.c" #define ZOMPLEX #include "t_cholmod_dense.c" /* ========================================================================== */ /* === cholmod_allocate_dense =============================================== */ /* ========================================================================== */ /* Allocate a dense matrix with leading dimension d. The space is not * initialized. */ cholmod_dense *CHOLMOD(allocate_dense) ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ size_t d, /* leading dimension */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *X ; size_t nzmax, nzmax0 ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; if (d < nrow) { ERROR (CHOLMOD_INVALID, "leading dimension invalid") ; return (NULL) ; } if (xtype < CHOLMOD_REAL || xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "xtype invalid") ; return (NULL) ; } /* ensure the dimensions do not cause integer overflow */ (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ; /* nzmax = MAX (1, d*ncol) ; */ nzmax = CHOLMOD(mult_size_t) (d, ncol, &ok) ; nzmax = MAX (1, nzmax) ; if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate header */ /* ---------------------------------------------------------------------- */ X = CHOLMOD(malloc) (sizeof (cholmod_dense), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } PRINT1 (("cholmod_allocate_dense %d-by-%d nzmax %d xtype %d\n", nrow, ncol, nzmax, xtype)) ; X->nrow = nrow ; X->ncol = ncol ; X->nzmax = nzmax ; X->xtype = xtype ; X->dtype = DTYPE ; X->x = NULL ; X->z = NULL ; X->d = d ; /* ---------------------------------------------------------------------- */ /* allocate the matrix itself */ /* ---------------------------------------------------------------------- */ nzmax0 = 0 ; CHOLMOD(realloc_multiple) (nzmax, 0, xtype, NULL, NULL, &(X->x), &(X->z), &nzmax0, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_dense) (&X, Common) ; return (NULL) ; /* out of memory */ } return (X) ; } /* ========================================================================== */ /* === cholmod_zeros ======================================================== */ /* ========================================================================== */ /* Allocate a dense matrix and set it to zero */ cholmod_dense *CHOLMOD(zeros) ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *X ; double *Xx, *Xz ; Int i, nz ; /* ---------------------------------------------------------------------- */ /* allocate a dense matrix and set it to zero */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; X = CHOLMOD(allocate_dense) (nrow, ncol, nrow, xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* NULL Common, out of memory, or inputs invalid */ } Xx = X->x ; Xz = X->z ; nz = MAX (1, X->nzmax) ; switch (xtype) { case CHOLMOD_REAL: for (i = 0 ; i < nz ; i++) { Xx [i] = 0 ; } break ; case CHOLMOD_COMPLEX: for (i = 0 ; i < 2*nz ; i++) { Xx [i] = 0 ; } break ; case CHOLMOD_ZOMPLEX: for (i = 0 ; i < nz ; i++) { Xx [i] = 0 ; } for (i = 0 ; i < nz ; i++) { Xz [i] = 0 ; } break ; } return (X) ; } /* ========================================================================== */ /* === cholmod_ones ========================================================= */ /* ========================================================================== */ /* Allocate a dense matrix and set it to zero */ cholmod_dense *CHOLMOD(ones) ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *X ; double *Xx, *Xz ; Int i, nz ; /* ---------------------------------------------------------------------- */ /* allocate a dense matrix and set it to all ones */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; X = CHOLMOD(allocate_dense) (nrow, ncol, nrow, xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* NULL Common, out of memory, or inputs invalid */ } Xx = X->x ; Xz = X->z ; nz = MAX (1, X->nzmax) ; switch (xtype) { case CHOLMOD_REAL: for (i = 0 ; i < nz ; i++) { Xx [i] = 1 ; } break ; case CHOLMOD_COMPLEX: for (i = 0 ; i < nz ; i++) { Xx [2*i ] = 1 ; Xx [2*i+1] = 0 ; } break ; case CHOLMOD_ZOMPLEX: for (i = 0 ; i < nz ; i++) { Xx [i] = 1 ; } for (i = 0 ; i < nz ; i++) { Xz [i] = 0 ; } break ; } return (X) ; } /* ========================================================================== */ /* === cholmod_eye ========================================================== */ /* ========================================================================== */ /* Allocate a dense matrix and set it to the identity matrix */ cholmod_dense *CHOLMOD(eye) ( /* ---- input ---- */ size_t nrow, /* # of rows of matrix */ size_t ncol, /* # of columns of matrix */ int xtype, /* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *X ; double *Xx, *Xz ; Int i, n, nz ; /* ---------------------------------------------------------------------- */ /* allocate a dense matrix and set it to the identity matrix */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* NULL Common, out of memory, or inputs invalid */ } nz = MAX (1, nrow*ncol) ; Xx = X->x ; Xz = X->z ; n = MIN (nrow, ncol) ; switch (xtype) { case CHOLMOD_REAL: case CHOLMOD_ZOMPLEX: for (i = 0 ; i < n ; i++) { Xx [i + i*nrow] = 1 ; } break ; case CHOLMOD_COMPLEX: for (i = 0 ; i < n ; i++) { Xx [2 * (i + i*nrow)] = 1 ; } break ; } return (X) ; } /* ========================================================================== */ /* === cholmod_free_dense =================================================== */ /* ========================================================================== */ /* free a dense matrix * * workspace: none */ int CHOLMOD(free_dense) ( /* ---- in/out --- */ cholmod_dense **XHandle, /* dense matrix to deallocate, NULL on output */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *X ; RETURN_IF_NULL_COMMON (FALSE) ; if (XHandle == NULL) { /* nothing to do */ return (TRUE) ; } X = *XHandle ; if (X == NULL) { /* nothing to do */ return (TRUE) ; } switch (X->xtype) { case CHOLMOD_REAL: X->x = CHOLMOD(free) (X->nzmax, sizeof (double), X->x, Common) ; break ; case CHOLMOD_COMPLEX: X->x = CHOLMOD(free) (X->nzmax, 2*sizeof (double), X->x, Common) ; break ; case CHOLMOD_ZOMPLEX: X->x = CHOLMOD(free) (X->nzmax, sizeof (double), X->x, Common) ; X->z = CHOLMOD(free) (X->nzmax, sizeof (double), X->z, Common) ; break ; } *XHandle = CHOLMOD(free) (1, sizeof (cholmod_dense), (*XHandle), Common) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_sparse_to_dense ============================================== */ /* ========================================================================== */ /* Convert a sparse matrix to a dense matrix. * The output dense matrix has the same xtype as the input sparse matrix, * except that a pattern-only sparse matrix A is converted into a real dense * matrix X, with 1's and 0's. All xtypes are supported. */ cholmod_dense *CHOLMOD(sparse_to_dense) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *X = NULL ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; if (A->stype && A->nrow != A->ncol) { ERROR (CHOLMOD_INVALID, "matrix invalid") ; return (NULL) ; } Common->status = CHOLMOD_OK ; ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ; /* ---------------------------------------------------------------------- */ /* convert the matrix, using template routine */ /* ---------------------------------------------------------------------- */ switch (A->xtype) { case CHOLMOD_PATTERN: X = p_cholmod_sparse_to_dense (A, Common) ; break ; case CHOLMOD_REAL: X = r_cholmod_sparse_to_dense (A, Common) ; break ; case CHOLMOD_COMPLEX: X = c_cholmod_sparse_to_dense (A, Common) ; break ; case CHOLMOD_ZOMPLEX: X = z_cholmod_sparse_to_dense (A, Common) ; break ; } return (X) ; } /* ========================================================================== */ /* === cholmod_dense_to_sparse ============================================== */ /* ========================================================================== */ /* Convert a dense matrix to a sparse matrix, similar to the MATLAB statements: * * C = sparse (X) values = TRUE * C = spones (sparse (X)) values = FALSE * * except that X must be double (it can be of many different types in MATLAB) * * The resulting sparse matrix C has the same numeric xtype as the input dense * matrix X, unless "values" is FALSE (in which case C is real, where C(i,j)=1 * if (i,j) is an entry in X. */ cholmod_sparse *CHOLMOD(dense_to_sparse) ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ int values, /* TRUE if values to be copied, FALSE otherwise */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *C = NULL ; DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (X, NULL) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; if (X->d < X->nrow) { ERROR (CHOLMOD_INVALID, "matrix invalid") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* convert the matrix, using template routine */ /* ---------------------------------------------------------------------- */ switch (X->xtype) { case CHOLMOD_REAL: C = r_cholmod_dense_to_sparse (X, values, Common) ; break ; case CHOLMOD_COMPLEX: C = c_cholmod_dense_to_sparse (X, values, Common) ; break ; case CHOLMOD_ZOMPLEX: C = z_cholmod_dense_to_sparse (X, values, Common) ; break ; } return (C) ; } /* ========================================================================== */ /* === cholmod_copy_dense2 ================================================== */ /* ========================================================================== */ /* Y = X, where X and Y are both already allocated. The leading dimensions of * X and Y may differ, but both must be >= the # of rows in X and Y. * Entries in rows nrow to d-1 are not copied from X, since the space might not * be initialized. Y->nzmax is unchanged. X->nzmax is typically * (X->d)*(X->ncol), but a user might modify that condition outside of any * CHOLMOD routine. * * The two dense matrices X and Y must have the same numeric xtype. */ int CHOLMOD(copy_dense2) ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ /* ---- output --- */ cholmod_dense *Y, /* copy of matrix X */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (X, FALSE) ; RETURN_IF_NULL (Y, FALSE) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (Y, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; if (X->nrow != Y->nrow || X->ncol != Y->ncol || X->xtype != Y->xtype) { ERROR (CHOLMOD_INVALID, "X and Y must have same dimensions and xtype") ; return (FALSE) ; } if (X->d < X->nrow || Y->d < Y->nrow || (X->d * X->ncol) > X->nzmax || (Y->d * Y->ncol) > Y->nzmax) { ERROR (CHOLMOD_INVALID, "X and/or Y invalid") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* copy the matrix, using template routine */ /* ---------------------------------------------------------------------- */ switch (X->xtype) { case CHOLMOD_REAL: r_cholmod_copy_dense2 (X, Y) ; break ; case CHOLMOD_COMPLEX: c_cholmod_copy_dense2 (X, Y) ; break ; case CHOLMOD_ZOMPLEX: z_cholmod_copy_dense2 (X, Y) ; break ; } return (TRUE) ; } /* ========================================================================== */ /* === cholmod_copy_dense =================================================== */ /* ========================================================================== */ /* Y = X, copy a dense matrix */ cholmod_dense *CHOLMOD(copy_dense) ( /* ---- input ---- */ cholmod_dense *X, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) { cholmod_dense *Y ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (X, NULL) ; RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate result */ /* ---------------------------------------------------------------------- */ Y = CHOLMOD(allocate_dense) (X->nrow, X->ncol, X->d, X->xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory or X invalid */ } /* ---------------------------------------------------------------------- */ /* Y = X */ /* ---------------------------------------------------------------------- */ /* This cannot fail (X and Y are allocated, and have the same nrow, ncol * d, and xtype) */ CHOLMOD(copy_dense2) (X, Y, Common) ; /* ---------------------------------------------------------------------- */ /* return result */ /* ---------------------------------------------------------------------- */ return (Y) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_transpose.c0000644000175000017500000007541211674452555023201 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_transpose =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Core utility routines for the cholmod_sparse object to * compute the transpose or permuted transpose of a matrix: * * Primary routines: * ----------------- * cholmod_transpose transpose sparse matrix * cholmod_ptranspose transpose and permute sparse matrix * cholmod_sort sort row indices in each column of sparse matrix * * Secondary routines: * ------------------- * cholmod_transpose_unsym transpose unsymmetric sparse matrix * cholmod_transpose_sym transpose symmetric sparse matrix * * All xtypes (pattern, real, complex, and zomplex) are supported. * * --------------------------------------- * Unsymmetric case: A->stype is zero. * --------------------------------------- * * Computes F = A', F = A (:,f)' or F = A (p,f)', except that the indexing by * f does not work the same as the MATLAB notation (see below). A->stype * is zero, which denotes that both the upper and lower triangular parts of * A are present (and used). A may in fact be symmetric in pattern and/or * value; A->stype just denotes which part of A are stored. A may be * rectangular. * * p is a permutation of 0:m-1, and f is a subset of 0:n-1, where A is m-by-n. * There can be no duplicate entries in p or f. * * The set f is held in fset and fsize. * fset = NULL means ":" in MATLAB. fsize is ignored. * fset != NULL means f = fset [0..fsize-1]. * fset != NULL and fsize = 0 means f is the empty set. * * Columns not in the set f are considered to be zero. That is, * if A is 5-by-10 then F = A (:,[3 4])' is not 2-by-5, but 10-by-5, and rows * 3 and 4 of F are equal to columns 3 and 4 of A (the other rows of F are * zero). More precisely, in MATLAB notation: * * [m n] = size (A) ; * F = A ; * notf = ones (1,n) ; * notf (f) = 0 ; * F (:, find (notf)) = 0 * F = F' * * If you want the MATLAB equivalent F=A(p,f) operation, use cholmod_submatrix * instead (which does not compute the transpose). * * F->nzmax must be large enough to hold the matrix F. It is not modified. * If F->nz is present then F->nz [j] = # of entries in column j of F. * * A can be sorted or unsorted, with packed or unpacked columns. * * If f is present and not sorted in ascending order, then F is unsorted * (that is, it may contain columns whose row indices do not appear in * ascending order). Otherwise, F is sorted (the row indices in each * column of F appear in strictly ascending order). * * F is returned in packed or unpacked form, depending on F->packed on input. * If F->packed is false, then F is returned in unpacked form (F->nz must be * present). Each row i of F is large enough to hold all the entries in row i * of A, even if f is provided. That is, F->i and * F->x [F->p [i] .. F->p [i] + F->nz [i] - 1] contain all entries in A (i,f), * but F->p [i+1] - F->p [i] is equal to the number of nonzeros in A (i,:), * not just A (i,f). * * The cholmod_transpose_unsym routine is the only operation in CHOLMOD that * can produce an unpacked matrix. * * --------------------------------------- * Symmetric case: A->stype is nonzero. * --------------------------------------- * * Computes F = A' or F = A(p,p)', the transpose or permuted transpose, where * A->stype is nonzero. * * If A->stype > 0, then A is a symmetric matrix where just the upper part * of the matrix is stored. Entries in the lower triangular part may be * present, but are ignored. A must be square. If F=A', then F is returned * sorted; otherwise F is unsorted for the F=A(p,p)' case. * * There can be no duplicate entries in p. * The fset and fsize parameters are not used. * * Three kinds of transposes are available, depending on the "values" parameter: * 0: do not transpose the numerical values; create a CHOLMOD_PATTERN matrix * 1: array transpose * 2: complex conjugate transpose (same as 2 if input is real or pattern) * * ----------------------------------------------------------------------------- * * For cholmod_transpose_unsym and cholmod_transpose_sym, the output matrix * F must already be pre-allocated by the caller, with the correct dimensions. * If F is not valid or has the wrong dimensions, it is not modified. * Otherwise, if F is too small, the transpose is not computed; the contents * of F->p contain the column pointers of the resulting matrix, where * F->p [F->ncol] > F->nzmax. In this case, the remaining contents of F are * not modified. F can still be properly free'd with cholmod_free_sparse. */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define PATTERN #include "t_cholmod_transpose.c" #define REAL #include "t_cholmod_transpose.c" #define COMPLEX #include "t_cholmod_transpose.c" #define COMPLEX #define NCONJUGATE #include "t_cholmod_transpose.c" #define ZOMPLEX #include "t_cholmod_transpose.c" #define ZOMPLEX #define NCONJUGATE #include "t_cholmod_transpose.c" /* ========================================================================== */ /* === cholmod_transpose_unsym ============================================== */ /* ========================================================================== */ /* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is * already allocated. See cholmod_transpose for a simpler routine. * * workspace: * Iwork (MAX (nrow,ncol)) if fset is present * Iwork (nrow) if fset is NULL * * The xtype of A and F must match, unless values is zero or F->xtype is * CHOLMOD_PATTERN (in which case only the pattern of A is transpose into F). */ int CHOLMOD(transpose_unsym) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 2: complex conj. transpose, 1: array transpose, 0: do not transpose the numerical values */ Int *Perm, /* size nrow, if present (can be NULL) */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* ---- output --- */ cholmod_sparse *F, /* F = A', A(:,f)', or A(p,f)' */ /* --------------- */ cholmod_common *Common ) { Int *Fp, *Fnz, *Ap, *Ai, *Anz, *Wi ; Int nrow, ncol, permute, use_fset, Apacked, Fpacked, p, pend, i, j, k, Fsorted, nf, jj, jlast ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (F, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (A->nrow != F->ncol || A->ncol != F->nrow) { ERROR (CHOLMOD_INVALID, "F has the wrong dimensions") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nf = fsize ; use_fset = (fset != NULL) ; nrow = A->nrow ; ncol = A->ncol ; Ap = A->p ; /* size A->ncol+1, column pointers of A */ Ai = A->i ; /* size nz = Ap [A->ncol], row indices of A */ Anz = A->nz ; Apacked = A->packed ; ASSERT (IMPLIES (!Apacked, Anz != NULL)) ; permute = (Perm != NULL) ; Fp = F->p ; /* size A->nrow+1, row pointers of F */ Fnz = F->nz ; Fpacked = F->packed ; ASSERT (IMPLIES (!Fpacked, Fnz != NULL)) ; nf = (use_fset) ? nf : ncol ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* s = nrow + ((fset != NULL) ? ncol : 0) */ s = CHOLMOD(add_size_t) (nrow, ((fset != NULL) ? ncol : 0), &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } Wi = Common->Iwork ; /* size nrow (i/l/l) */ /* ---------------------------------------------------------------------- */ /* check Perm and fset */ /* ---------------------------------------------------------------------- */ if (permute) { for (i = 0 ; i < nrow ; i++) { Wi [i] = 1 ; } for (k = 0 ; k < nrow ; k++) { i = Perm [k] ; if (i < 0 || i > nrow || Wi [i] == 0) { ERROR (CHOLMOD_INVALID, "invalid permutation") ; return (FALSE) ; } Wi [i] = 0 ; } } if (use_fset) { for (j = 0 ; j < ncol ; j++) { Wi [j] = 1 ; } for (k = 0 ; k < nf ; k++) { j = fset [k] ; if (j < 0 || j > ncol || Wi [j] == 0) { ERROR (CHOLMOD_INVALID, "invalid fset") ; return (FALSE) ; } Wi [j] = 0 ; } } /* Perm and fset are now valid */ ASSERT (CHOLMOD(dump_perm) (Perm, nrow, nrow, "Perm", Common)) ; ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ; /* ---------------------------------------------------------------------- */ /* count the entries in each row of A or A(:,f) */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i < nrow ; i++) { Wi [i] = 0 ; } jlast = EMPTY ; Fsorted = TRUE ; if (use_fset) { /* count entries in each row of A(:,f) */ for (jj = 0 ; jj < nf ; jj++) { j = fset [jj] ; if (j <= jlast) { Fsorted = FALSE ; } p = Ap [j] ; pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { Wi [Ai [p]]++ ; } jlast = j ; } /* save the nz counts if F is unpacked, and recount all of A */ if (!Fpacked) { if (permute) { for (i = 0 ; i < nrow ; i++) { Fnz [i] = Wi [Perm [i]] ; } } else { for (i = 0 ; i < nrow ; i++) { Fnz [i] = Wi [i] ; } } for (i = 0 ; i < nrow ; i++) { Wi [i] = 0 ; } /* count entries in each row of A */ for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { Wi [Ai [p]]++ ; } } } } else { /* count entries in each row of A */ for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { Wi [Ai [p]]++ ; } } /* save the nz counts if F is unpacked */ if (!Fpacked) { if (permute) { for (i = 0 ; i < nrow ; i++) { Fnz [i] = Wi [Perm [i]] ; } } else { for (i = 0 ; i < nrow ; i++) { Fnz [i] = Wi [i] ; } } } } /* ---------------------------------------------------------------------- */ /* compute the row pointers */ /* ---------------------------------------------------------------------- */ p = 0 ; if (permute) { for (i = 0 ; i < nrow ; i++) { Fp [i] = p ; p += Wi [Perm [i]] ; } for (i = 0 ; i < nrow ; i++) { Wi [Perm [i]] = Fp [i] ; } } else { for (i = 0 ; i < nrow ; i++) { Fp [i] = p ; p += Wi [i] ; } for (i = 0 ; i < nrow ; i++) { Wi [i] = Fp [i] ; } } Fp [nrow] = p ; if (p > (Int) (F->nzmax)) { ERROR (CHOLMOD_INVALID, "F is too small") ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* transpose matrix, using template routine */ /* ---------------------------------------------------------------------- */ ok = FALSE ; if (values == 0 || F->xtype == CHOLMOD_PATTERN) { ok = p_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ; } else if (F->xtype == CHOLMOD_REAL) { ok = r_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ; } else if (F->xtype == CHOLMOD_COMPLEX) { if (values == 1) { /* array transpose */ ok = ct_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ; } else { /* complex conjugate transpose */ ok = c_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ; } } else if (F->xtype == CHOLMOD_ZOMPLEX) { if (values == 1) { /* array transpose */ ok = zt_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ; } else { /* complex conjugate transpose */ ok = z_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ; } } /* ---------------------------------------------------------------------- */ /* finalize result F */ /* ---------------------------------------------------------------------- */ if (ok) { F->sorted = Fsorted ; } ASSERT (CHOLMOD(dump_sparse) (F, "output F unsym", Common) >= 0) ; return (ok) ; } /* ========================================================================== */ /* === cholmod_transpose_sym ================================================ */ /* ========================================================================== */ /* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated. * See cholmod_transpose for a simpler routine. * * workspace: Iwork (nrow) if Perm NULL, Iwork (2*nrow) if Perm non-NULL. */ int CHOLMOD(transpose_sym) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 2: complex conj. transpose, 1: array transpose, 0: do not transpose the numerical values */ Int *Perm, /* size nrow, if present (can be NULL) */ /* ---- output --- */ cholmod_sparse *F, /* F = A' or A(p,p)' */ /* --------------- */ cholmod_common *Common ) { Int *Ap, *Anz, *Ai, *Fp, *Wi, *Pinv, *Iwork ; Int p, pend, packed, upper, permute, jold, n, i, j, k, iold ; size_t s ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_NULL (F, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (A->nrow != A->ncol || A->stype == 0) { /* this routine handles square symmetric matrices only */ ERROR (CHOLMOD_INVALID, "matrix must be symmetric") ; return (FALSE) ; } if (A->nrow != F->ncol || A->ncol != F->nrow) { ERROR (CHOLMOD_INVALID, "F has the wrong dimensions") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ permute = (Perm != NULL) ; n = A->nrow ; Ap = A->p ; /* size A->ncol+1, column pointers of A */ Ai = A->i ; /* size nz = Ap [A->ncol], row indices of A */ Anz = A->nz ; packed = A->packed ; ASSERT (IMPLIES (!packed, Anz != NULL)) ; upper = (A->stype > 0) ; Fp = F->p ; /* size A->nrow+1, row pointers of F */ /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ /* s = (Perm != NULL) ? 2*n : n */ s = CHOLMOD(add_size_t) (n, ((Perm != NULL) ? n : 0), &ok) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (FALSE) ; } CHOLMOD(allocate_work) (0, s, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* get workspace */ /* ---------------------------------------------------------------------- */ Iwork = Common->Iwork ; Wi = Iwork ; /* size n (i/l/l) */ Pinv = Iwork + n ; /* size n (i/i/l) , unused if Perm NULL */ /* ---------------------------------------------------------------------- */ /* check Perm and construct inverse permutation */ /* ---------------------------------------------------------------------- */ if (permute) { for (i = 0 ; i < n ; i++) { Pinv [i] = EMPTY ; } for (k = 0 ; k < n ; k++) { i = Perm [k] ; if (i < 0 || i > n || Pinv [i] != EMPTY) { ERROR (CHOLMOD_INVALID, "invalid permutation") ; return (FALSE) ; } Pinv [i] = k ; } } /* Perm is now valid */ ASSERT (CHOLMOD(dump_perm) (Perm, n, n, "Perm", Common)) ; /* ---------------------------------------------------------------------- */ /* count the entries in each row of F */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i < n ; i++) { Wi [i] = 0 ; } if (packed) { if (permute) { if (upper) { /* packed, permuted, upper */ for (j = 0 ; j < n ; j++) { jold = Perm [j] ; pend = Ap [jold+1] ; for (p = Ap [jold] ; p < pend ; p++) { iold = Ai [p] ; if (iold <= jold) { i = Pinv [iold] ; Wi [MIN (i, j)]++ ; } } } } else { /* packed, permuted, lower */ for (j = 0 ; j < n ; j++) { jold = Perm [j] ; pend = Ap [jold+1] ; for (p = Ap [jold] ; p < pend ; p++) { iold = Ai [p] ; if (iold >= jold) { i = Pinv [iold] ; Wi [MAX (i, j)]++ ; } } } } } else { if (upper) { /* packed, unpermuted, upper */ for (j = 0 ; j < n ; j++) { pend = Ap [j+1] ; for (p = Ap [j] ; p < pend ; p++) { i = Ai [p] ; if (i <= j) { Wi [i]++ ; } } } } else { /* packed, unpermuted, lower */ for (j = 0 ; j < n ; j++) { pend = Ap [j+1] ; for (p = Ap [j] ; p < pend ; p++) { i = Ai [p] ; if (i >= j) { Wi [i]++ ; } } } } } } else { if (permute) { if (upper) { /* unpacked, permuted, upper */ for (j = 0 ; j < n ; j++) { jold = Perm [j] ; p = Ap [jold] ; pend = p + Anz [jold] ; for ( ; p < pend ; p++) { iold = Ai [p] ; if (iold <= jold) { i = Pinv [iold] ; Wi [MIN (i, j)]++ ; } } } } else { /* unpacked, permuted, lower */ for (j = 0 ; j < n ; j++) { jold = Perm [j] ; p = Ap [jold] ; pend = p + Anz [jold] ; for ( ; p < pend ; p++) { iold = Ai [p] ; if (iold >= jold) { i = Pinv [iold] ; Wi [MAX (i, j)]++ ; } } } } } else { if (upper) { /* unpacked, unpermuted, upper */ for (j = 0 ; j < n ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i <= j) { Wi [i]++ ; } } } } else { /* unpacked, unpermuted, lower */ for (j = 0 ; j < n ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i >= j) { Wi [i]++ ; } } } } } } /* ---------------------------------------------------------------------- */ /* compute the row pointers */ /* ---------------------------------------------------------------------- */ p = 0 ; for (i = 0 ; i < n ; i++) { Fp [i] = p ; p += Wi [i] ; } Fp [n] = p ; for (i = 0 ; i < n ; i++) { Wi [i] = Fp [i] ; } if (p > (Int) (F->nzmax)) { ERROR (CHOLMOD_INVALID, "F is too small") ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* transpose matrix, using template routine */ /* ---------------------------------------------------------------------- */ ok = FALSE ; if (values == 0 || F->xtype == CHOLMOD_PATTERN) { PRINT2 (("\n:::: p_transpose_sym Perm %p\n", Perm)) ; ok = p_cholmod_transpose_sym (A, Perm, F, Common) ; } else if (F->xtype == CHOLMOD_REAL) { PRINT2 (("\n:::: r_transpose_sym Perm %p\n", Perm)) ; ok = r_cholmod_transpose_sym (A, Perm, F, Common) ; } else if (F->xtype == CHOLMOD_COMPLEX) { if (values == 1) { /* array transpose */ PRINT2 (("\n:::: ct_transpose_sym Perm %p\n", Perm)) ; ok = ct_cholmod_transpose_sym (A, Perm, F, Common) ; } else { /* complex conjugate transpose */ PRINT2 (("\n:::: c_transpose_sym Perm %p\n", Perm)) ; ok = c_cholmod_transpose_sym (A, Perm, F, Common) ; } } else if (F->xtype == CHOLMOD_ZOMPLEX) { if (values == 1) { /* array transpose */ PRINT2 (("\n:::: zt_transpose_sym Perm %p\n", Perm)) ; ok = zt_cholmod_transpose_sym (A, Perm, F, Common) ; } else { /* complex conjugate transpose */ PRINT2 (("\n:::: z_transpose_sym Perm %p\n", Perm)) ; ok = z_cholmod_transpose_sym (A, Perm, F, Common) ; } } /* ---------------------------------------------------------------------- */ /* finalize result F */ /* ---------------------------------------------------------------------- */ /* F is sorted if there is no permutation vector */ if (ok) { F->sorted = !permute ; F->packed = TRUE ; F->stype = - SIGN (A->stype) ; /* flip the stype */ ASSERT (CHOLMOD(dump_sparse) (F, "output F sym", Common) >= 0) ; } return (ok) ; } /* ========================================================================== */ /* === cholmod_transpose ==================================================== */ /* ========================================================================== */ /* Returns A'. See also cholmod_ptranspose below. */ cholmod_sparse *CHOLMOD(transpose) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 2: complex conj. transpose, 1: array transpose, 0: do not transpose the numerical values (returns its result as CHOLMOD_PATTERN) */ /* --------------- */ cholmod_common *Common ) { return (CHOLMOD(ptranspose) (A, values, NULL, NULL, 0, Common)) ; } /* ========================================================================== */ /* === cholmod_ptranspose =================================================== */ /* ========================================================================== */ /* Return A' or A(p,p)' if A is symmetric. Return A', A(:,f)', or A(p,f)' if * A is unsymmetric. * * workspace: * Iwork (MAX (nrow,ncol)) if unsymmetric and fset is non-NULL * Iwork (nrow) if unsymmetric and fset is NULL * Iwork (2*nrow) if symmetric and Perm is non-NULL. * Iwork (nrow) if symmetric and Perm is NULL. * * A simple worst-case upper bound on the workspace is nrow+ncol. */ cholmod_sparse *CHOLMOD(ptranspose) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to transpose */ int values, /* 2: complex conj. transpose, 1: array transpose, 0: do not transpose the numerical values */ Int *Perm, /* if non-NULL, F = A(p,f) or A(p,p) */ Int *fset, /* subset of 0:(A->ncol)-1 */ size_t fsize, /* size of fset */ /* --------------- */ cholmod_common *Common ) { Int *Ap, *Anz ; cholmod_sparse *F ; Int nrow, ncol, use_fset, j, jj, fnz, packed, stype, nf, xtype ; size_t ineed ; int ok = TRUE ; nf = fsize ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; stype = A->stype ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ nrow = A->nrow ; ncol = A->ncol ; if (stype != 0) { use_fset = FALSE ; if (Perm != NULL) { ineed = CHOLMOD(mult_size_t) (A->nrow, 2, &ok) ; } else { ineed = A->nrow ; } } else { use_fset = (fset != NULL) ; if (use_fset) { ineed = MAX (A->nrow, A->ncol) ; } else { ineed = A->nrow ; } } if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } CHOLMOD(allocate_work) (0, ineed, 0, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ Ap = A->p ; Anz = A->nz ; packed = A->packed ; ASSERT (IMPLIES (!packed, Anz != NULL)) ; xtype = values ? A->xtype : CHOLMOD_PATTERN ; /* ---------------------------------------------------------------------- */ /* allocate F */ /* ---------------------------------------------------------------------- */ /* determine # of nonzeros in F */ if (stype != 0) { /* F=A' or F=A(p,p)', fset is ignored */ fnz = CHOLMOD(nnz) (A, Common) ; } else { nf = (use_fset) ? nf : ncol ; if (use_fset) { fnz = 0 ; /* F=A(:,f)' or F=A(p,f)' */ for (jj = 0 ; jj < nf ; jj++) { /* The fset is not yet checked; it will be thoroughly checked * in cholmod_transpose_unsym. For now, just make sure we don't * access Ap and Anz out of bounds. */ j = fset [jj] ; if (j >= 0 && j < ncol) { fnz += packed ? (Ap [j+1] - Ap [j]) : MAX (0, Anz [j]) ; } } } else { /* F=A' or F=A(p,:)' */ fnz = CHOLMOD(nnz) (A, Common) ; } } /* F is ncol-by-nrow, fnz nonzeros, sorted unless f is present and unsorted, * packed, of opposite stype as A, and with/without numerical values */ F = CHOLMOD(allocate_sparse) (ncol, nrow, fnz, TRUE, TRUE, -SIGN(stype), xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* transpose and optionally permute the matrix A */ /* ---------------------------------------------------------------------- */ if (stype != 0) { /* F = A (p,p)', using upper or lower triangular part of A only */ ok = CHOLMOD(transpose_sym) (A, values, Perm, F, Common) ; } else { /* F = A (p,f)' */ ok = CHOLMOD(transpose_unsym) (A, values, Perm, fset, nf, F, Common) ; } /* ---------------------------------------------------------------------- */ /* return the matrix F, or NULL if an error occured */ /* ---------------------------------------------------------------------- */ if (!ok) { CHOLMOD(free_sparse) (&F, Common) ; } return (F) ; } /* ========================================================================== */ /* === cholmod_sort ========================================================= */ /* ========================================================================== */ /* Sort the columns of A, in place. Returns A in packed form, even if it * starts as unpacked. Removes entries in the ignored part of a symmetric * matrix. * * workspace: Iwork (max (nrow,ncol)). Allocates additional workspace for a * temporary copy of A'. */ int CHOLMOD(sort) ( /* ---- in/out --- */ cholmod_sparse *A, /* matrix to sort */ /* --------------- */ cholmod_common *Common ) { Int *Ap ; cholmod_sparse *F ; Int anz, ncol, nrow, stype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; nrow = A->nrow ; if (nrow <= 1) { /* a 1-by-n sparse matrix must be sorted */ A->sorted = TRUE ; return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ ncol = A->ncol ; CHOLMOD(allocate_work) (0, MAX (nrow, ncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ anz = CHOLMOD(nnz) (A, Common) ; stype = A->stype ; /* ---------------------------------------------------------------------- */ /* sort the columns of the matrix */ /* ---------------------------------------------------------------------- */ /* allocate workspace for transpose: ncol-by-nrow, same # of nonzeros as A, * sorted, packed, same stype as A, and of the same numeric type as A. */ F = CHOLMOD(allocate_sparse) (ncol, nrow, anz, TRUE, TRUE, stype, A->xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } if (stype != 0) { /* F = A', upper or lower triangular part only */ CHOLMOD(transpose_sym) (A, 1, NULL, F, Common) ; A->packed = TRUE ; /* A = F' */ CHOLMOD(transpose_sym) (F, 1, NULL, A, Common) ; } else { /* F = A' */ CHOLMOD(transpose_unsym) (A, 1, NULL, NULL, 0, F, Common) ; A->packed = TRUE ; /* A = F' */ CHOLMOD(transpose_unsym) (F, 1, NULL, NULL, 0, A, Common) ; } ASSERT (A->sorted && A->packed) ; ASSERT (CHOLMOD(dump_sparse) (A, "Asorted", Common) >= 0) ; /* ---------------------------------------------------------------------- */ /* reduce A in size, if needed. This must succeed. */ /* ---------------------------------------------------------------------- */ Ap = A->p ; anz = Ap [ncol] ; ASSERT ((size_t) anz <= A->nzmax) ; CHOLMOD(reallocate_sparse) (anz, A, Common) ; ASSERT (Common->status >= CHOLMOD_OK) ; /* ---------------------------------------------------------------------- */ /* free workspace */ /* ---------------------------------------------------------------------- */ CHOLMOD(free_sparse) (&F, Common) ; return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_triplet.c0000644000175000017500000005612411674452555022645 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_triplet ================================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Core utility routines for the cholmod_triplet object: * * A sparse matrix held in triplet form is the simplest one for a user to * create. It consists of a list of nz entries in arbitrary order, held in * three arrays: i, j, and x, each of length nk. The kth entry is in row i[k], * column j[k], with value x[k]. There may be duplicate values; if A(i,j) * appears more than once, its value is the sum of the entries with those row * and column indices. * * Primary routines: * ----------------- * cholmod_allocate_triplet allocate a triplet matrix * cholmod_free_triplet free a triplet matrix * * Secondary routines: * ------------------- * cholmod_reallocate_triplet reallocate a triplet matrix * cholmod_sparse_to_triplet create a triplet matrix copy of a sparse matrix * cholmod_triplet_to_sparse create a sparse matrix copy of a triplet matrix * cholmod_copy_triplet create a copy of a triplet matrix * * The relationship between an m-by-n cholmod_sparse matrix A and a * cholmod_triplet matrix (i, j, and x) is identical to how they are used in * the MATLAB "sparse" and "find" functions: * * [i j x] = find (A) * [m n] = size (A) * A = sparse (i,j,x,m,n) * * with the exception that the cholmod_sparse matrix may be "unpacked", may * have either sorted or unsorted columns (depending on the option selected), * and may be symmetric with just the upper or lower triangular part stored. * Likewise, the cholmod_triplet matrix may contain just the entries in the * upper or lower triangular part of a symmetric matrix. * * MATLAB sparse matrices are always "packed", always have sorted columns, * and always store both parts of a symmetric matrix. In some cases, MATLAB * behaves like CHOLMOD by ignoring entries in the upper or lower triangular * part of a matrix that is otherwise assumed to be symmetric (such as the * input to chol). In CHOLMOD, that option is a characteristic of the object. * In MATLAB, that option is based on how a matrix is used as the input to * a function. * * The triplet matrix is provided to give the user a simple way of constructing * a sparse matrix. There are very few operations supported for triplet * matrices. The assumption is that they will be converted to cholmod_sparse * matrix form first. * * Adding two triplet matrices simply involves concatenating the contents of * the three arrays (i, j, and x). To permute a triplet matrix, just replace * the row and column indices with their permuted values. For example, if * P is a permutation vector, then P [k] = j means row/column j is the kth * row/column in C=P*A*P'. In MATLAB notation, C=A(p,p). If Pinv is an array * of size n and T is the triplet form of A, then: * * Ti = T->i ; * Tj = T->j ; * for (k = 0 ; k < n ; k++) Pinv [P [k]] = k ; * for (k = 0 ; k < nz ; k++) Ti [k] = Pinv [Ti [k]] ; * for (k = 0 ; k < nz ; k++) Tj [k] = Pinv [Tj [k]] ; * * overwrites T with the triplet form of C=P*A*P'. The conversion * * C = cholmod_triplet_to_sparse (T, 0, &Common) ; * * will then return the matrix C = P*A*P'. * * Note that T->stype > 0 means that entries in the lower triangular part of * T are transposed into the upper triangular part when T is converted to * sparse matrix (cholmod_sparse) form with cholmod_triplet_to_sparse. The * opposite is true for T->stype < 0. * * Since the triplet matrix T is so simple to generate, it's quite easy * to remove entries that you do not want, prior to converting T to the * cholmod_sparse form. So if you include these entries in T, CHOLMOD * assumes that there must be a reason (such as the one above). Thus, * no entry in a triplet matrix is ever ignored. * * Other operations, such as extacting a submatrix, horizontal and vertical * concatenation, multiply a triplet matrix times a dense matrix, are also * simple. Multiplying two triplet matrices is not trivial; the simplest * method is to convert them to cholmod_sparse matrices first. * * Supports all xtypes (pattern, real, complex, and zomplex). */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define PATTERN #include "t_cholmod_triplet.c" #define REAL #include "t_cholmod_triplet.c" #define COMPLEX #include "t_cholmod_triplet.c" #define ZOMPLEX #include "t_cholmod_triplet.c" /* ========================================================================== */ /* === cholmod_allocate_triplet ============================================= */ /* ========================================================================== */ /* allocate space for a triplet matrix * * workspace: none */ cholmod_triplet *CHOLMOD(allocate_triplet) ( /* ---- input ---- */ size_t nrow, /* # of rows of T */ size_t ncol, /* # of columns of T */ size_t nzmax, /* max # of nonzeros of T */ int stype, /* stype of T */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_triplet *T ; size_t nzmax0 ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "xtype invalid") ; return (NULL) ; } /* ensure the dimensions do not cause integer overflow */ (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ; if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate header */ /* ---------------------------------------------------------------------- */ T = CHOLMOD(malloc) (sizeof (cholmod_triplet), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } PRINT1 (("cholmod_allocate_triplet %d-by-%d nzmax %d xtype %d\n", nrow, ncol, nzmax, xtype)) ; nzmax = MAX (1, nzmax) ; T->nrow = nrow ; T->ncol = ncol ; T->nzmax = nzmax ; T->nnz = 0 ; T->stype = stype ; T->itype = ITYPE ; T->xtype = xtype ; T->dtype = DTYPE ; T->j = NULL ; T->i = NULL ; T->x = NULL ; T->z = NULL ; /* ---------------------------------------------------------------------- */ /* allocate the matrix itself */ /* ---------------------------------------------------------------------- */ nzmax0 = 0 ; CHOLMOD(realloc_multiple) (nzmax, 2, xtype, &(T->i), &(T->j), &(T->x), &(T->z), &nzmax0, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_triplet) (&T, Common) ; return (NULL) ; /* out of memory */ } return (T) ; } /* ========================================================================== */ /* === cholmod_free_triplet ================================================= */ /* ========================================================================== */ /* free a triplet matrix * * workspace: none */ int CHOLMOD(free_triplet) ( /* ---- in/out --- */ cholmod_triplet **THandle, /* matrix to deallocate, NULL on output */ /* --------------- */ cholmod_common *Common ) { Int nz ; cholmod_triplet *T ; RETURN_IF_NULL_COMMON (FALSE) ; if (THandle == NULL) { /* nothing to do */ return (TRUE) ; } T = *THandle ; if (T == NULL) { /* nothing to do */ return (TRUE) ; } nz = T->nzmax ; T->j = CHOLMOD(free) (nz, sizeof (Int), T->j, Common) ; T->i = CHOLMOD(free) (nz, sizeof (Int), T->i, Common) ; if (T->xtype == CHOLMOD_REAL) { T->x = CHOLMOD(free) (nz, sizeof (double), T->x, Common) ; } else if (T->xtype == CHOLMOD_COMPLEX) { T->x = CHOLMOD(free) (nz, 2*sizeof (double), T->x, Common) ; } else if (T->xtype == CHOLMOD_ZOMPLEX) { T->x = CHOLMOD(free) (nz, sizeof (double), T->x, Common) ; T->z = CHOLMOD(free) (nz, sizeof (double), T->z, Common) ; } *THandle = CHOLMOD(free) (1, sizeof (cholmod_triplet), (*THandle), Common) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_reallocate_triplet =========================================== */ /* ========================================================================== */ /* Change the size of T->i, T->j, and T->x, or allocate them if their current * size is zero. T->x is not modified if T->xtype is CHOLMOD_PATTERN. * * workspace: none */ int CHOLMOD(reallocate_triplet) ( /* ---- input ---- */ size_t nznew, /* new # of entries in T */ /* ---- in/out --- */ cholmod_triplet *T, /* triplet matrix to modify */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (T, FALSE) ; RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; PRINT1 (("realloc triplet %d to %d, xtype: %d\n", T->nzmax, nznew, T->xtype)) ; /* ---------------------------------------------------------------------- */ /* resize the matrix */ /* ---------------------------------------------------------------------- */ CHOLMOD(realloc_multiple) (MAX (1,nznew), 2, T->xtype, &(T->i), &(T->j), &(T->x), &(T->z), &(T->nzmax), Common) ; return (Common->status == CHOLMOD_OK) ; } /* ========================================================================== */ /* === cholmod_triplet_to_sparse ============================================ */ /* ========================================================================== */ /* Convert a set of triplets into a cholmod_sparse matrix. In MATLAB notation, * for unsymmetric matrices: * * A = sparse (Ti, Tj, Tx, nrow, ncol, nzmax) ; * * For the symmetric upper case: * * A = sparse (min(Ti,Tj), max(Ti,Tj), Tx, nrow, ncol, nzmax) ; * * For the symmetric lower case: * * A = sparse (max(Ti,Tj), min(Ti,Tj), Tx, nrow, ncol, nzmax) ; * * If Tx is NULL, then A->x is not allocated, and only the pattern of A is * computed. A is returned in packed form, and can be of any stype * (upper/lower/unsymmetric). It has enough space to hold the values in T, * or nzmax, whichever is larger. * * workspace: Iwork (max (nrow,ncol)) * allocates a temporary copy of its output matrix. * * The resulting sparse matrix has the same xtype as the input triplet matrix. */ cholmod_sparse *CHOLMOD(triplet_to_sparse) ( /* ---- input ---- */ cholmod_triplet *T, /* matrix to copy */ size_t nzmax, /* allocate at least this much space in output matrix */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *R, *A = NULL ; Int *Wj, *Rp, *Ri, *Rnz, *Ti, *Tj ; Int i, j, p, k, stype, nrow, ncol, nz, ok ; size_t anz = 0 ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (T, NULL) ; Ti = T->i ; Tj = T->j ; RETURN_IF_NULL (Ti, NULL) ; RETURN_IF_NULL (Tj, NULL) ; RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; stype = SIGN (T->stype) ; if (stype && T->nrow != T->ncol) { /* inputs invalid */ ERROR (CHOLMOD_INVALID, "matrix invalid") ; return (NULL) ; } Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_triplet) (T, "T", Common)) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ nrow = T->nrow ; ncol = T->ncol ; nz = T->nnz ; /* ---------------------------------------------------------------------- */ /* allocate workspace */ /* ---------------------------------------------------------------------- */ CHOLMOD(allocate_work) (0, MAX (nrow, ncol), 0, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* allocate temporary matrix R */ /* ---------------------------------------------------------------------- */ R = CHOLMOD(allocate_sparse) (ncol, nrow, nz, FALSE, FALSE, -stype, T->xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } Rp = R->p ; Ri = R->i ; Rnz = R->nz ; /* ---------------------------------------------------------------------- */ /* count the entries in each row of A (also counting duplicates) */ /* ---------------------------------------------------------------------- */ for (i = 0 ; i < nrow ; i++) { Rnz [i] = 0 ; } if (stype > 0) { for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i < 0 || i >= nrow || j < 0 || j >= ncol) { ERROR (CHOLMOD_INVALID, "index out of range") ; break ; } /* A will be symmetric with just the upper triangular part stored. * Create a matrix R that is lower triangular. Entries in the * upper part of R are transposed to the lower part. */ Rnz [MIN (i,j)]++ ; } } else if (stype < 0) { for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i < 0 || i >= nrow || j < 0 || j >= ncol) { ERROR (CHOLMOD_INVALID, "index out of range") ; break ; } /* A will be symmetric with just the lower triangular part stored. * Create a matrix R that is upper triangular. Entries in the * lower part of R are transposed to the upper part. */ Rnz [MAX (i,j)]++ ; } } else { for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i < 0 || i >= nrow || j < 0 || j >= ncol) { ERROR (CHOLMOD_INVALID, "index out of range") ; break ; } /* constructing an unsymmetric matrix */ Rnz [i]++ ; } } if (Common->status < CHOLMOD_OK) { /* triplet matrix is invalid */ CHOLMOD(free_sparse) (&R, Common) ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* construct the row pointers */ /* ---------------------------------------------------------------------- */ p = 0 ; for (i = 0 ; i < nrow ; i++) { Rp [i] = p ; p += Rnz [i] ; } Rp [nrow] = p ; /* use Wj (i/l/l) as temporary row pointers */ Wj = Common->Iwork ; /* size MAX (nrow,ncol) FUTURE WORK: (i/l/l) */ for (i = 0 ; i < nrow ; i++) { Wj [i] = Rp [i] ; } /* ---------------------------------------------------------------------- */ /* construct triplet matrix, using template routine */ /* ---------------------------------------------------------------------- */ switch (T->xtype) { case CHOLMOD_PATTERN: anz = p_cholmod_triplet_to_sparse (T, R, Common) ; break ; case CHOLMOD_REAL: anz = r_cholmod_triplet_to_sparse (T, R, Common) ; break ; case CHOLMOD_COMPLEX: anz = c_cholmod_triplet_to_sparse (T, R, Common) ; break ; case CHOLMOD_ZOMPLEX: anz = z_cholmod_triplet_to_sparse (T, R, Common) ; break ; } /* ---------------------------------------------------------------------- */ /* A = R' (array transpose, not complex conjugate transpose) */ /* ---------------------------------------------------------------------- */ /* workspace: Iwork (R->nrow), which is A->ncol */ ASSERT (CHOLMOD(dump_sparse) (R, "R", Common) >= 0) ; A = CHOLMOD(allocate_sparse) (nrow, ncol, MAX (anz, nzmax), TRUE, TRUE, stype, T->xtype, Common) ; if (stype) { ok = CHOLMOD(transpose_sym) (R, 1, NULL, A, Common) ; } else { ok = CHOLMOD(transpose_unsym) (R, 1, NULL, NULL, 0, A, Common) ; } CHOLMOD(free_sparse) (&R, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&A, Common) ; } /* ---------------------------------------------------------------------- */ /* return result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_sparse) (A, "A = triplet(T) result", Common) >= 0) ; return (A) ; } /* ========================================================================== */ /* === cholmod_sparse_to_triplet ============================================ */ /* ========================================================================== */ /* Converts a sparse column-oriented matrix to triplet form. * The resulting triplet matrix has the same xtype as the sparse matrix. * * workspace: none */ cholmod_triplet *CHOLMOD(sparse_to_triplet) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Az, *Tx, *Tz ; Int *Ap, *Ai, *Ti, *Tj, *Anz ; cholmod_triplet *T ; Int i, xtype, p, pend, k, j, nrow, ncol, nz, stype, packed, up, lo, both ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; stype = SIGN (A->stype) ; nrow = A->nrow ; ncol = A->ncol ; if (stype && nrow != ncol) { /* inputs invalid */ ERROR (CHOLMOD_INVALID, "matrix invalid") ; return (NULL) ; } Ax = A->x ; Az = A->z ; xtype = A->xtype ; Common->status = CHOLMOD_OK ; ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ; /* ---------------------------------------------------------------------- */ /* allocate triplet matrix */ /* ---------------------------------------------------------------------- */ nz = CHOLMOD(nnz) (A, Common) ; T = CHOLMOD(allocate_triplet) (nrow, ncol, nz, A->stype, A->xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* convert to a sparse matrix */ /* ---------------------------------------------------------------------- */ Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; Ti = T->i ; Tj = T->j ; Tx = T->x ; Tz = T->z ; T->stype = A->stype ; both = (A->stype == 0) ; up = (A->stype > 0) ; lo = (A->stype < 0) ; k = 0 ; for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (both || (up && i <= j) || (lo && i >= j)) { Ti [k] = Ai [p] ; Tj [k] = j ; if (xtype == CHOLMOD_REAL) { Tx [k] = Ax [p] ; } else if (xtype == CHOLMOD_COMPLEX) { Tx [2*k ] = Ax [2*p ] ; Tx [2*k+1] = Ax [2*p+1] ; } else if (xtype == CHOLMOD_ZOMPLEX) { Tx [k] = Ax [p] ; Tz [k] = Az [p] ; } k++ ; ASSERT (k <= nz) ; } } } T->nnz = k ; /* ---------------------------------------------------------------------- */ /* return result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_triplet) (T, "T", Common)) ; return (T) ; } /* ========================================================================== */ /* === cholmod_copy_triplet ================================================= */ /* ========================================================================== */ /* Create an exact copy of a triplet matrix, except that entries in unused * space are not copied (they might not be initialized, and copying them would * cause program checkers such as purify and valgrind to complain). * The output triplet matrix has the same xtype as the input triplet matrix. */ cholmod_triplet *CHOLMOD(copy_triplet) ( /* ---- input ---- */ cholmod_triplet *T, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) { double *Tx, *Tz, *Cx, *Cz ; Int *Ci, *Cj, *Ti, *Tj ; cholmod_triplet *C ; Int xtype, k, nz ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (T, NULL) ; RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; nz = T->nnz ; Ti = T->i ; Tj = T->j ; Tx = T->x ; Tz = T->z ; xtype = T->xtype ; RETURN_IF_NULL (Ti, NULL) ; RETURN_IF_NULL (Tj, NULL) ; Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_triplet) (T, "T input", Common)) ; /* ---------------------------------------------------------------------- */ /* allocate copy */ /* ---------------------------------------------------------------------- */ C = CHOLMOD(allocate_triplet) (T->nrow, T->ncol, T->nzmax, T->stype, xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* copy the triplet matrix */ /* ---------------------------------------------------------------------- */ Ci = C->i ; Cj = C->j ; Cx = C->x ; Cz = C->z ; C->nnz = nz ; for (k = 0 ; k < nz ; k++) { Ci [k] = Ti [k] ; } for (k = 0 ; k < nz ; k++) { Cj [k] = Tj [k] ; } if (xtype == CHOLMOD_REAL) { for (k = 0 ; k < nz ; k++) { Cx [k] = Tx [k] ; } } else if (xtype == CHOLMOD_COMPLEX) { for (k = 0 ; k < nz ; k++) { Cx [2*k ] = Tx [2*k ] ; Cx [2*k+1] = Tx [2*k+1] ; } } else if (xtype == CHOLMOD_ZOMPLEX) { for (k = 0 ; k < nz ; k++) { Cx [k] = Tx [k] ; Cz [k] = Tz [k] ; } } /* ---------------------------------------------------------------------- */ /* return the result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_triplet) (C, "C triplet copy", Common)) ; return (C) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_error.c0000644000175000017500000000536711674452555022316 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_error =================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* CHOLMOD error-handling routine. */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* ==== cholmod_error ======================================================= */ /* ========================================================================== */ /* An error has occurred. Set the status, optionally print an error message, * and call the user error-handling routine (if it exists). If * Common->try_catch is TRUE, then CHOLMOD is inside a try/catch block. * The status is set, but no message is printed and the user error handler * is not called. This is not (yet) an error, since CHOLMOD may recover. * * In the current version, this try/catch mechanism is used internally only in * cholmod_analyze, which tries multiple ordering methods and picks the best * one. If one or more ordering method fails, it keeps going. Only one * ordering needs to succeed for cholmod_analyze to succeed. */ int CHOLMOD(error) ( /* ---- input ---- */ int status, /* error status */ const char *file, /* name of source code file where error occured */ int line, /* line number in source code file where error occured*/ const char *message, /* error message */ /* --------------- */ cholmod_common *Common ) { RETURN_IF_NULL_COMMON (FALSE) ; Common->status = status ; if (!(Common->try_catch)) { #ifndef NPRINT /* print a warning or error message */ if (Common->print_function != NULL) { if (status > 0 && Common->print > 1) { (Common->print_function) ("CHOLMOD warning: %s\n", message) ; fflush (stdout) ; fflush (stderr) ; } else if (Common->print > 0) { (Common->print_function) ("CHOLMOD error: %s\n", message) ; fflush (stdout) ; fflush (stderr) ; } } #endif /* call the user error handler, if it exists */ if (Common->error_handler != NULL) { Common->error_handler (status, file, line, message) ; } } return (TRUE) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_change_factor.c0000644000175000017500000011343011674452555023737 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_change_factor =========================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Change the numeric/symbolic, LL/LDL, simplicial/super, packed/unpacked, * monotonic/non-monotonic status of a cholmod_factor object. * * There are four basic classes of factor types: * * (1) simplicial symbolic: Consists of two size-n arrays: the fill-reducing * permutation (L->Perm) and the nonzero count for each column of L * (L->ColCount). All other factor types also include this information. * L->ColCount may be exact (obtained from the analysis routines), or * it may be a guess. During factorization, and certainly after update/ * downdate, the columns of L can have a different number of nonzeros. * L->ColCount is used to allocate space. L->ColCount is exact for the * supernodal factorizations. The nonzero pattern of L is not kept. * * (2) simplicial numeric: These represent L in a compressed column form. The * variants of this type are: * * LDL': L is unit diagonal. Row indices in column j are located in * L->i [L->p [j] ... L->p [j] + L->nz [j]], and corresponding numeric * values are in the same locations in L->x. The total number of * entries is the sum of L->nz [j]. The unit diagonal is not stored; * D is stored on the diagonal of L instead. L->p may or may not be * monotonic. The order of storage of the columns in L->i and L->x is * given by a doubly-linked list (L->prev and L->next). L->p is of * size n+1, but only the first n entries are used (it is used if L * is converted to a sparse matrix via cholmod_factor_to_sparse). * * For the complex case, L->x is stored interleaved with real/imag * parts, and is of size 2*lnz*sizeof(double). For the zomplex case, * L->x is of size lnz*sizeof(double) and holds the real part; L->z * is the same size and holds the imaginary part. * * LL': This is identical to the LDL' form, except that the non-unit * diagonal of L is stored as the first entry in each column of L. * * (3) supernodal symbolic: A representation of the nonzero pattern of the * supernodes for a supernodal factorization. There are L->nsuper * supernodes. Columns L->super [k] to L->super [k+1]-1 are in the kth * supernode. The row indices for the kth supernode are in * L->s [L->pi [k] ... L->pi [k+1]-1]. The numerical values are not * allocated (L->x), but when they are they will be located in * L->x [L->px [k] ... L->px [k+1]-1], and the L->px array is defined * in this factor type. * * For the complex case, L->x is stored interleaved with real/imag parts, * and is of size 2*L->xsize*sizeof(double). The zomplex supernodal case * is not supported, since it is not compatible with LAPACK and the BLAS. * * (4) supernodal numeric: Always an LL' factorization. L is non-unit * diagonal. L->x contains the numerical values of the supernodes, as * described above for the supernodal symbolic factor. * For the complex case, L->x is stored interleaved, and is of size * 2*L->xsize*sizeof(double). The zomplex supernodal case is not * supported, since it is not compatible with LAPACK and the BLAS. * * FUTURE WORK: support a supernodal LDL' factor. * * * In all cases, the row indices in each column (L->i for simplicial L and * L->s for supernodal L) are kept sorted from low indices to high indices. * This means the diagonal of L (or D for LDL' factors) is always kept as the * first entry in each column. * * The cholmod_change_factor routine can do almost all possible conversions. * It cannot do the following conversions: * * (1) Simplicial numeric types cannot be converted to a supernodal * symbolic type. This would simultaneously deallocate the * simplicial pattern and numeric values and reallocate uninitialized * space for the supernodal pattern. This isn't useful for the user, * and not needed by CHOLMOD's own routines either. * * (2) Only a symbolic factor (simplicial to supernodal) can be converted * to a supernodal numeric factor. * * Some conversions are meant only to be used internally by other CHOLMOD * routines, and should not be performed by the end user. They allocate space * whose contents are undefined: * * (1) converting from simplicial symbolic to supernodal symbolic. * (2) converting any factor to supernodal numeric. * * workspace: no conversion routine uses workspace in Common. No temporary * workspace is allocated. * * Supports all xtypes, except that there is no supernodal zomplex L. * * The to_xtype parameter is used only when converting from symbolic to numeric * or numeric to symbolic. It cannot be used to convert a numeric xtype (real, * complex, or zomplex) to a different numeric xtype. For that conversion, * use cholmod_factor_xtype instead. */ #include "cholmod_internal.h" #include "cholmod_core.h" static void natural_list (cholmod_factor *L) ; /* ========================================================================== */ /* === TEMPLATE ============================================================= */ /* ========================================================================== */ #define REAL #include "t_cholmod_change_factor.c" #define COMPLEX #include "t_cholmod_change_factor.c" #define ZOMPLEX #include "t_cholmod_change_factor.c" /* ========================================================================== */ /* === L_is_packed ========================================================== */ /* ========================================================================== */ /* Return TRUE if the columns of L are packed, FALSE otherwise. For debugging * only. */ #ifndef NDEBUG static int L_is_packed (cholmod_factor *L, cholmod_common *Common) { Int j ; Int *Lnz = L->nz ; Int *Lp = L->p ; Int n = L->n ; if (L->xtype == CHOLMOD_PATTERN || L->is_super) { return (TRUE) ; } if (Lnz == NULL || Lp == NULL) { return (TRUE) ; } for (j = 0 ; j < n ; j++) { PRINT3 (("j: "ID" Lnz "ID" Lp[j+1] "ID" Lp[j] "ID"\n", j, Lnz [j], Lp [j+1], Lp [j])) ; if (Lnz [j] != (Lp [j+1] - Lp [j])) { PRINT2 (("L is not packed\n")) ; return (FALSE) ; } } return (TRUE) ; } #endif /* ========================================================================== */ /* === natural_list ========================================================= */ /* ========================================================================== */ /* Create a naturally-ordered doubly-linked list of columns. */ static void natural_list (cholmod_factor *L) { Int head, tail, n, j ; Int *Lnext, *Lprev ; Lnext = L->next ; Lprev = L->prev ; ASSERT (Lprev != NULL && Lnext != NULL) ; n = L->n ; head = n+1 ; tail = n ; Lnext [head] = 0 ; Lprev [head] = EMPTY ; Lnext [tail] = EMPTY ; Lprev [tail] = n-1 ; for (j = 0 ; j < n ; j++) { Lnext [j] = j+1 ; Lprev [j] = j-1 ; } Lprev [0] = head ; L->is_monotonic = TRUE ; } /* ========================================================================== */ /* === allocate_simplicial_numeric ========================================== */ /* ========================================================================== */ /* Allocate O(n) arrays for simplicial numeric factorization. Initializes * the link lists only. Does not allocate the L->i, L->x, or L->z arrays. */ static int allocate_simplicial_numeric ( cholmod_factor *L, cholmod_common *Common ) { Int n ; Int *Lp, *Lnz, *Lprev, *Lnext ; size_t n1, n2 ; PRINT1 (("Allocate simplicial\n")) ; ASSERT (L->xtype == CHOLMOD_PATTERN || L->is_super) ; ASSERT (L->p == NULL) ; ASSERT (L->nz == NULL) ; ASSERT (L->prev == NULL) ; ASSERT (L->next == NULL) ; n = L->n ; /* this cannot cause size_t overflow */ n1 = ((size_t) n) + 1 ; n2 = ((size_t) n) + 2 ; Lp = CHOLMOD(malloc) (n1, sizeof (Int), Common) ; Lnz = CHOLMOD(malloc) (n, sizeof (Int), Common) ; Lprev = CHOLMOD(malloc) (n2, sizeof (Int), Common) ; Lnext = CHOLMOD(malloc) (n2, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free) (n1, sizeof (Int), Lp, Common) ; CHOLMOD(free) (n, sizeof (Int), Lnz, Common) ; CHOLMOD(free) (n2, sizeof (Int), Lprev, Common) ; CHOLMOD(free) (n2, sizeof (Int), Lnext, Common) ; PRINT1 (("Allocate simplicial failed\n")) ; return (FALSE) ; /* out of memory */ } /* ============================================== commit the changes to L */ L->p = Lp ; L->nz = Lnz ; L->prev = Lprev ; L->next = Lnext ; /* initialize a doubly linked list for columns in natural order */ natural_list (L) ; PRINT1 (("Allocate simplicial done\n")) ; return (TRUE) ; } /* ========================================================================== */ /* === simplicial_symbolic_to_super_symbolic ================================ */ /* ========================================================================== */ /* Convert a simplicial symbolic factor supernodal symbolic factor. Does not * initialize the new space. */ static int simplicial_symbolic_to_super_symbolic ( cholmod_factor *L, cholmod_common *Common ) { Int nsuper, xsize, ssize ; Int *Lsuper, *Lpi, *Lpx, *Ls ; size_t nsuper1 ; ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ; xsize = L->xsize ; ssize = L->ssize ; nsuper = L->nsuper ; nsuper1 = ((size_t) nsuper) + 1 ; PRINT1 (("simple sym to super sym: ssize "ID" xsize "ID" nsuper "ID"" " status %d\n", ssize, xsize, nsuper, Common->status)) ; /* O(nsuper) arrays, where nsuper <= n */ Lsuper = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ; Lpi = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ; Lpx = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ; /* O(ssize) array, where ssize <= nnz(L), and usually much smaller */ Ls = CHOLMOD(malloc) (ssize, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free) (nsuper1, sizeof (Int), Lsuper, Common) ; CHOLMOD(free) (nsuper1, sizeof (Int), Lpi, Common) ; CHOLMOD(free) (nsuper1, sizeof (Int), Lpx, Common) ; CHOLMOD(free) (ssize, sizeof (Int), Ls, Common) ; return (FALSE) ; /* out of memory */ } /* ============================================== commit the changes to L */ ASSERT (Lsuper != NULL && Lpi != NULL && Lpx != NULL && Ls != NULL) ; L->maxcsize = 0 ; L->maxesize = 0 ; L->super = Lsuper ; L->pi = Lpi ; L->px = Lpx ; L->s = Ls ; Ls [0] = EMPTY ; /* supernodal pattern undefined */ L->is_super = TRUE ; L->is_ll = TRUE ; /* supernodal LDL' not supported */ L->xtype = CHOLMOD_PATTERN ; L->dtype = DTYPE ; L->minor = L->n ; return (TRUE) ; } /* ========================================================================== */ /* === any_to_simplicial_symbolic =========================================== */ /* ========================================================================== */ /* Convert any factor L to a simplicial symbolic factor, leaving only L->Perm * and L->ColCount. Cannot fail. Any of the components of L (except Perm and * ColCount) may already be free'd. */ static void any_to_simplicial_symbolic ( cholmod_factor *L, int to_ll, cholmod_common *Common ) { Int n, lnz, xs, ss, s, e ; size_t n1, n2 ; /* ============================================== commit the changes to L */ n = L->n ; lnz = L->nzmax ; s = L->nsuper + 1 ; xs = (L->is_super) ? ((Int) (L->xsize)) : (lnz) ; e = (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) ; ss = L->ssize ; /* this cannot cause size_t overflow */ n1 = ((size_t) n) + 1 ; n2 = ((size_t) n) + 2 ; /* free all but the symbolic analysis (Perm and ColCount) */ L->p = CHOLMOD(free) (n1, sizeof (Int), L->p, Common) ; L->i = CHOLMOD(free) (lnz, sizeof (Int), L->i, Common) ; L->x = CHOLMOD(free) (xs, e*sizeof (double), L->x, Common) ; L->z = CHOLMOD(free) (lnz, sizeof (double), L->z, Common) ; L->nz = CHOLMOD(free) (n, sizeof (Int), L->nz, Common) ; L->next = CHOLMOD(free) (n2, sizeof (Int), L->next, Common) ; L->prev = CHOLMOD(free) (n2, sizeof (Int), L->prev, Common) ; L->super = CHOLMOD(free) (s, sizeof (Int), L->super, Common) ; L->pi = CHOLMOD(free) (s, sizeof (Int), L->pi, Common) ; L->px = CHOLMOD(free) (s, sizeof (Int), L->px, Common) ; L->s = CHOLMOD(free) (ss, sizeof (Int), L->s, Common) ; L->nzmax = 0 ; L->is_super = FALSE ; L->xtype = CHOLMOD_PATTERN ; L->dtype = DTYPE ; L->minor = n ; L->is_ll = to_ll ; } /* ========================================================================== */ /* === ll_super_to_super_symbolic =========================================== */ /* ========================================================================== */ /* Convert a numerical supernodal L to symbolic supernodal. Cannot fail. */ static void ll_super_to_super_symbolic ( cholmod_factor *L, cholmod_common *Common ) { /* ============================================== commit the changes to L */ /* free all but the supernodal numerical factor */ ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_super && L->is_ll) ; DEBUG (CHOLMOD(dump_factor) (L, "start to super symbolic", Common)) ; L->x = CHOLMOD(free) (L->xsize, (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) * sizeof (double), L->x, Common) ; L->xtype = CHOLMOD_PATTERN ; L->dtype = DTYPE ; L->minor = L->n ; L->is_ll = TRUE ; /* supernodal LDL' not supported */ DEBUG (CHOLMOD(dump_factor) (L, "done to super symbolic", Common)) ; } /* ========================================================================== */ /* === simplicial_symbolic_to_simplicial_numeric ============================ */ /* ========================================================================== */ /* Convert a simplicial symbolic L to a simplicial numeric L; allocate space * for L using L->ColCount from symbolic analysis, and set L to identity. * * If packed < 0, then this routine is creating a copy of another factor * (via cholmod_copy_factor). In this case, the space is not initialized. */ static void simplicial_symbolic_to_simplicial_numeric ( cholmod_factor *L, int to_ll, int packed, int to_xtype, cholmod_common *Common ) { double grow0, grow1, xlen, xlnz ; double *Lx, *Lz ; Int *Li, *Lp, *Lnz, *ColCount ; Int n, grow, grow2, p, j, lnz, len, ok, e ; ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ; if (!allocate_simplicial_numeric (L, Common)) { PRINT1 (("out of memory, allocate simplicial numeric\n")) ; return ; /* out of memory */ } ASSERT (L->ColCount != NULL && L->nz != NULL && L->p != NULL) ; ASSERT (L->x == NULL && L->z == NULL && L->i == NULL) ; ColCount = L->ColCount ; Lnz = L->nz ; Lp = L->p ; ok = TRUE ; n = L->n ; if (packed < 0) { /* ------------------------------------------------------------------ */ /* used by cholmod_copy_factor to allocate a copy of a factor object */ /* ------------------------------------------------------------------ */ lnz = L->nzmax ; L->nzmax = 0 ; } else if (packed) { /* ------------------------------------------------------------------ */ /* LDL' or LL' packed */ /* ------------------------------------------------------------------ */ PRINT1 (("convert to packed LL' or LDL'\n")) ; lnz = 0 ; for (j = 0 ; ok && j < n ; j++) { /* ensure len is in the range 1 to n-j */ len = ColCount [j] ; len = MAX (1, len) ; len = MIN (len, n-j) ; lnz += len ; ok = (lnz >= 0) ; } for (j = 0 ; j <= n ; j++) { Lp [j] = j ; } for (j = 0 ; j < n ; j++) { Lnz [j] = 1 ; } } else { /* ------------------------------------------------------------------ */ /* LDL' unpacked */ /* ------------------------------------------------------------------ */ PRINT1 (("convert to unpacked\n")) ; /* compute new lnzmax */ /* if any parameter is NaN, grow is false */ grow0 = Common->grow0 ; grow1 = Common->grow1 ; grow2 = Common->grow2 ; grow0 = IS_NAN (grow0) ? 1 : grow0 ; grow1 = IS_NAN (grow1) ? 1 : grow1 ; /* fl.pt. compare, but no NaN's: */ grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ; PRINT1 (("init, grow1 %g grow2 "ID"\n", grow1, grow2)) ; /* initialize Lp and Lnz for each column */ lnz = 0 ; for (j = 0 ; ok && j < n ; j++) { Lp [j] = lnz ; Lnz [j] = 1 ; /* ensure len is in the range 1 to n-j */ len = ColCount [j] ; len = MAX (1, len) ; len = MIN (len, n-j) ; /* compute len in double to avoid integer overflow */ PRINT1 (("ColCount ["ID"] = "ID"\n", j, len)) ; if (grow) { xlen = (double) len ; xlen = grow1 * xlen + grow2 ; xlen = MIN (xlen, n-j) ; len = (Int) xlen ; } ASSERT (len >= 1 && len <= n-j) ; lnz += len ; ok = (lnz >= 0) ; } if (ok) { Lp [n] = lnz ; if (grow) { /* add extra space */ xlnz = (double) lnz ; xlnz *= grow0 ; xlnz = MIN (xlnz, Size_max) ; xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ; lnz = (Int) xlnz ; } } } lnz = MAX (1, lnz) ; if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; } /* allocate L->i, L->x, and L->z */ PRINT1 (("resizing from zero size to lnz "ID"\n", lnz)) ; ASSERT (L->nzmax == 0) ; e = (to_xtype == CHOLMOD_COMPLEX ? 2 : 1) ; if (!ok || !CHOLMOD(realloc_multiple) (lnz, 1, to_xtype, &(L->i), NULL, &(L->x), &(L->z), &(L->nzmax), Common)) { L->p = CHOLMOD(free) (n+1, sizeof (Int), L->p, Common) ; L->nz = CHOLMOD(free) (n, sizeof (Int), L->nz, Common) ; L->prev = CHOLMOD(free) (n+2, sizeof (Int), L->prev, Common) ; L->next = CHOLMOD(free) (n+2, sizeof (Int), L->next, Common) ; L->i = CHOLMOD(free) (lnz, sizeof (Int), L->i, Common) ; L->x = CHOLMOD(free) (lnz, e*sizeof (double), L->x, Common) ; L->z = CHOLMOD(free) (lnz, sizeof (double), L->z, Common) ; PRINT1 (("cannot realloc simplicial numeric\n")) ; return ; /* out of memory */ } /* ============================================== commit the changes to L */ /* initialize L to be the identity matrix */ L->xtype = to_xtype ; L->dtype = DTYPE ; L->minor = n ; Li = L->i ; Lx = L->x ; Lz = L->z ; #if 0 if (lnz == 1) { /* the user won't expect to access this entry, but some CHOLMOD * routines may. Set it to zero so that valgrind doesn't complain. */ switch (to_xtype) { case CHOLMOD_REAL: Lx [0] = 0 ; break ; case CHOLMOD_COMPLEX: Lx [0] = 0 ; Lx [1] = 0 ; break ; case CHOLMOD_ZOMPLEX: Lx [0] = 0 ; Lz [0] = 0 ; break ; } } #endif if (packed >= 0) { /* create the unit diagonal for either the LL' or LDL' case */ switch (L->xtype) { case CHOLMOD_REAL: for (j = 0 ; j < n ; j++) { ASSERT (Lp [j] < Lp [j+1]) ; p = Lp [j] ; Li [p] = j ; Lx [p] = 1 ; } break ; case CHOLMOD_COMPLEX: for (j = 0 ; j < n ; j++) { ASSERT (Lp [j] < Lp [j+1]) ; p = Lp [j] ; Li [p] = j ; Lx [2*p ] = 1 ; Lx [2*p+1] = 0 ; } break ; case CHOLMOD_ZOMPLEX: for (j = 0 ; j < n ; j++) { ASSERT (Lp [j] < Lp [j+1]) ; p = Lp [j] ; Li [p] = j ; Lx [p] = 1 ; Lz [p] = 0 ; } break ; } } L->is_ll = to_ll ; PRINT1 (("done convert simplicial symbolic to numeric\n")) ; } /* ========================================================================== */ /* === change_simplicial_numeric ============================================ */ /* ========================================================================== */ /* Change LL' to LDL', LDL' to LL', or leave as-is. * * If to_packed is TRUE, then the columns of L are packed and made monotonic * (to_monotonic is ignored; it is implicitly TRUE). * * If to_monotonic is TRUE but to_packed is FALSE, the columns of L are made * monotonic but not packed. * * If both to_packed and to_monotonic are FALSE, then the columns of L are * left as-is, and the conversion is done in place. * * If L is already monotonic, or if it is to be left non-monotonic, then this * conversion always succeeds. * * When converting an LDL' to LL' factorization, any column with a negative * or zero diagonal entry is not modified so that conversion back to LDL' will * succeed. This can result in a matrix L with a negative entry on the diagonal * If the kth entry on the diagonal of D is negative, it and the kth column of * L are left unchanged. A subsequent conversion back to an LDL' form will also * leave the column unchanged, so the correct LDL' factorization will be * restored. L->minor is set to the smallest k for which D (k,k) is negative. */ static void change_simplicial_numeric ( cholmod_factor *L, int to_ll, int to_packed, int to_monotonic, cholmod_common *Common ) { double grow0, grow1, xlen, xlnz ; void *newLi, *newLx, *newLz ; double *Lx, *Lz ; Int *Lp, *Li, *Lnz ; Int make_monotonic, grow2, n, j, lnz, len, grow, ok, make_ll, make_ldl ; size_t nzmax0 ; PRINT1 (("\n===Change simplicial numeric: %d %d %d\n", to_ll, to_packed, to_monotonic)) ; DEBUG (CHOLMOD(dump_factor) (L, "change simplicial numeric", Common)) ; ASSERT (L->xtype != CHOLMOD_PATTERN && !(L->is_super)) ; make_monotonic = ((to_packed || to_monotonic) && !(L->is_monotonic)) ; make_ll = (to_ll && !(L->is_ll)) ; make_ldl = (!to_ll && L->is_ll) ; n = L->n ; Lp = L->p ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lnz = L->nz ; grow = FALSE ; grow0 = Common->grow0 ; grow1 = Common->grow1 ; grow2 = Common->grow2 ; grow0 = IS_NAN (grow0) ? 1 : grow0 ; grow1 = IS_NAN (grow1) ? 1 : grow1 ; ok = TRUE ; newLi = NULL ; newLx = NULL ; newLz = NULL ; lnz = 0 ; if (make_monotonic) { /* ------------------------------------------------------------------ */ /* Columns out of order, but will be reordered and optionally packed. */ /* ------------------------------------------------------------------ */ PRINT1 (("L is non-monotonic\n")) ; /* compute new L->nzmax */ if (!to_packed) { /* if any parameter is NaN, grow is false */ /* fl.pt. comparisons below are false if any parameter is NaN */ grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ; } for (j = 0 ; ok && j < n ; j++) { len = Lnz [j] ; ASSERT (len >= 1 && len <= n-j) ; /* compute len in double to avoid integer overflow */ if (grow) { xlen = (double) len ; xlen = grow1 * xlen + grow2 ; xlen = MIN (xlen, n-j) ; len = (Int) xlen ; } ASSERT (len >= Lnz [j] && len <= n-j) ; PRINT2 (("j: "ID" Lnz[j] "ID" len "ID" p "ID"\n", j, Lnz [j], len, lnz)) ; lnz += len ; ok = (lnz >= 0) ; } if (!ok) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return ; } if (grow) { xlnz = (double) lnz ; xlnz *= grow0 ; xlnz = MIN (xlnz, Size_max) ; xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ; lnz = (Int) xlnz ; } lnz = MAX (1, lnz) ; PRINT1 (("final lnz "ID"\n", lnz)) ; nzmax0 = 0 ; CHOLMOD(realloc_multiple) (lnz, 1, L->xtype, &newLi, NULL, &newLx, &newLz, &nzmax0, Common) ; if (Common->status < CHOLMOD_OK) { return ; /* out of memory */ } } /* ============================================== commit the changes to L */ /* ---------------------------------------------------------------------- */ /* convert the simplicial L, using template routine */ /* ---------------------------------------------------------------------- */ switch (L->xtype) { case CHOLMOD_REAL: r_change_simplicial_numeric (L, to_ll, to_packed, newLi, newLx, newLz, lnz, grow, grow1, grow2, make_ll, make_monotonic, make_ldl, Common) ; break ; case CHOLMOD_COMPLEX: c_change_simplicial_numeric (L, to_ll, to_packed, newLi, newLx, newLz, lnz, grow, grow1, grow2, make_ll, make_monotonic, make_ldl, Common) ; break ; case CHOLMOD_ZOMPLEX: z_change_simplicial_numeric (L, to_ll, to_packed, newLi, newLx, newLz, lnz, grow, grow1, grow2, make_ll, make_monotonic, make_ldl, Common) ; break ; } DEBUG (CHOLMOD(dump_factor) (L, "L simplicial changed", Common)) ; } /* ========================================================================== */ /* === ll_super_to_simplicial_numeric ======================================= */ /* ========================================================================== */ /* Convert a supernodal numeric factorization to any simplicial numeric one. * Leaves L->xtype unchanged (real or complex, not zomplex since there is * no supernodal zomplex L). */ static void ll_super_to_simplicial_numeric ( cholmod_factor *L, int to_packed, int to_ll, cholmod_common *Common ) { Int *Ls, *Lpi, *Lpx, *Super, *Li ; Int n, lnz, s, nsuper, psi, psend, nsrow, nscol, k1, k2, erows ; DEBUG (CHOLMOD(dump_factor) (L, "start LL super to simplicial", Common)) ; PRINT1 (("super -> simplicial (%d %d)\n", to_packed, to_ll)) ; ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_ll && L->is_super) ; ASSERT (L->x != NULL && L->i == NULL) ; n = L->n ; nsuper = L->nsuper ; Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; Super = L->super ; /* Int overflow cannot occur since supernodal L already exists */ if (to_packed) { /* count the number of nonzeros in L. Each supernode is of the form * * l . . . For this example, nscol = 4 (# columns). nsrow = 9. * l l . . The "." entries are allocated in the supernodal * l l l . factor, but not used. They are not copied to the * l l l l simplicial factor. Some "l" and "e" entries may be * e e e e numerically zero and even symbolically zero if a * e e e e tight simplicial factorization or resymbol were * e e e e done, because of numerical cancellation and relaxed * e e e e supernode amalgamation, respectively. * e e e e */ lnz = 0 ; for (s = 0 ; s < nsuper ; s++) { k1 = Super [s] ; k2 = Super [s+1] ; psi = Lpi [s] ; psend = Lpi [s+1] ; nsrow = psend - psi ; nscol = k2 - k1 ; ASSERT (nsrow >= nscol) ; erows = nsrow - nscol ; /* lower triangular part, including the diagonal, * counting the "l" terms in the figure above. */ lnz += nscol * (nscol+1) / 2 ; /* rectangular part, below the diagonal block (the "e" terms) */ lnz += nscol * erows ; } ASSERT (lnz <= (Int) (L->xsize)) ; } else { /* Li will be the same size as Lx */ lnz = L->xsize ; } ASSERT (lnz >= 0) ; PRINT1 (("simplicial lnz = "ID" to_packed: %d to_ll: %d L->xsize %g\n", lnz, to_ll, to_packed, (double) L->xsize)) ; Li = CHOLMOD(malloc) (lnz, sizeof (Int), Common) ; if (Common->status < CHOLMOD_OK) { return ; /* out of memory */ } if (!allocate_simplicial_numeric (L, Common)) { CHOLMOD(free) (lnz, sizeof (Int), Li, Common) ; return ; /* out of memory */ } /* ============================================== commit the changes to L */ L->i = Li ; L->nzmax = lnz ; /* ---------------------------------------------------------------------- */ /* convert the supernodal L, using template routine */ /* ---------------------------------------------------------------------- */ switch (L->xtype) { case CHOLMOD_REAL: r_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ; break ; case CHOLMOD_COMPLEX: c_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ; break ; } /* ---------------------------------------------------------------------- */ /* free unused parts of L */ /* ---------------------------------------------------------------------- */ L->super = CHOLMOD(free) (nsuper+1, sizeof (Int), L->super, Common) ; L->pi = CHOLMOD(free) (nsuper+1, sizeof (Int), L->pi, Common) ; L->px = CHOLMOD(free) (nsuper+1, sizeof (Int), L->px, Common) ; L->s = CHOLMOD(free) (L->ssize, sizeof (Int), L->s, Common) ; L->ssize = 0 ; L->xsize = 0 ; L->nsuper = 0 ; L->maxesize = 0 ; L->maxcsize = 0 ; L->is_super = FALSE ; DEBUG (CHOLMOD(dump_factor) (L, "done LL super to simplicial", Common)) ; } /* ========================================================================== */ /* === super_symbolic_to_ll_super =========================================== */ /* ========================================================================== */ /* Convert a supernodal symbolic factorization to a supernodal numeric * factorization by allocating L->x. Contents of L->x are undefined. */ static int super_symbolic_to_ll_super ( int to_xtype, cholmod_factor *L, cholmod_common *Common ) { double *Lx ; Int wentry = (to_xtype == CHOLMOD_REAL) ? 1 : 2 ; PRINT1 (("convert super sym to num\n")) ; ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_super) ; Lx = CHOLMOD(malloc) (L->xsize, wentry * sizeof (double), Common) ; PRINT1 (("xsize %g\n", (double) L->xsize)) ; if (Common->status < CHOLMOD_OK) { return (FALSE) ; /* out of memory */ } /* ============================================== commit the changes to L */ if (L->xsize == 1) { /* the caller won't expect to access this entry, but some CHOLMOD * routines may. Set it to zero so that valgrind doesn't complain. */ switch (to_xtype) { case CHOLMOD_REAL: Lx [0] = 0 ; break ; case CHOLMOD_COMPLEX: Lx [0] = 0 ; Lx [1] = 0 ; break ; } } L->x = Lx ; L->xtype = to_xtype ; L->dtype = DTYPE ; L->minor = L->n ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_change_factor ================================================ */ /* ========================================================================== */ /* Convert a factor L. Some conversions simply allocate uninitialized space * that meant to be filled later. * * If the conversion fails, the factor is left in its original form, with one * exception. Converting a supernodal symbolic factor to a simplicial numeric * one (with L=D=I) may leave the factor in simplicial symbolic form. * * Memory allocated for each conversion is listed below. */ int CHOLMOD(change_factor) ( /* ---- input ---- */ int to_xtype, /* convert to CHOLMOD_PATTERN, _REAL, _COMPLEX, or * _ZOMPLEX */ int to_ll, /* TRUE: convert to LL', FALSE: LDL' */ int to_super, /* TRUE: convert to supernodal, FALSE: simplicial */ int to_packed, /* TRUE: pack simplicial columns, FALSE: do not pack */ int to_monotonic, /* TRUE: put simplicial columns in order, FALSE: not */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; if (to_xtype < CHOLMOD_PATTERN || to_xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "xtype invalid") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; PRINT1 (("-----convert from (%d,%d,%d,%d,%d) to (%d,%d,%d,%d,%d)\n", L->xtype, L->is_ll, L->is_super, L_is_packed (L, Common), L->is_monotonic, to_xtype, to_ll, to_super, to_packed, to_monotonic)) ; /* ensure all parameters are TRUE/FALSE */ to_ll = BOOLEAN (to_ll) ; to_super = BOOLEAN (to_super) ; ASSERT (BOOLEAN (L->is_ll) == L->is_ll) ; ASSERT (BOOLEAN (L->is_super) == L->is_super) ; if (to_super && to_xtype == CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "supernodal zomplex L not supported") ; return (FALSE) ; } /* ---------------------------------------------------------------------- */ /* convert */ /* ---------------------------------------------------------------------- */ if (to_xtype == CHOLMOD_PATTERN) { /* ------------------------------------------------------------------ */ /* convert to symbolic */ /* ------------------------------------------------------------------ */ if (!to_super) { /* -------------------------------------------------------------- */ /* convert any factor into a simplicial symbolic factor */ /* -------------------------------------------------------------- */ any_to_simplicial_symbolic (L, to_ll, Common) ; /* cannot fail */ } else { /* -------------------------------------------------------------- */ /* convert to a supernodal symbolic factor */ /* -------------------------------------------------------------- */ if (L->xtype != CHOLMOD_PATTERN && L->is_super) { /* convert from supernodal numeric to supernodal symbolic. * this preserves symbolic pattern of L, discards numeric * values */ ll_super_to_super_symbolic (L, Common) ; /* cannot fail */ } else if (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) { /* convert from simplicial symbolic to supernodal symbolic. * contents of supernodal pattern are uninitialized. Not meant * for the end user. */ simplicial_symbolic_to_super_symbolic (L, Common) ; } else { /* cannot convert from simplicial numeric to supernodal * symbolic */ ERROR (CHOLMOD_INVALID, "cannot convert L to supernodal symbolic") ; } } } else { /* ------------------------------------------------------------------ */ /* convert to numeric */ /* ------------------------------------------------------------------ */ if (to_super) { /* -------------------------------------------------------------- */ /* convert to supernodal numeric factor */ /* -------------------------------------------------------------- */ if (L->xtype == CHOLMOD_PATTERN) { if (L->is_super) { /* Convert supernodal symbolic to supernodal numeric. * Contents of supernodal numeric values are uninitialized. * This is used by cholmod_super_numeric. Not meant for * the end user. */ super_symbolic_to_ll_super (to_xtype, L, Common) ; } else { /* Convert simplicial symbolic to supernodal numeric. * Contents not defined. This is used by * Core/cholmod_copy_factor only. Not meant for the end * user. */ if (!simplicial_symbolic_to_super_symbolic (L, Common)) { /* failure, convert back to simplicial symbolic */ any_to_simplicial_symbolic (L, to_ll, Common) ; } else { /* conversion to super symbolic OK, allocate numeric * part */ super_symbolic_to_ll_super (to_xtype, L, Common) ; } } } else { /* nothing to do if L is already in supernodal numeric form */ if (!(L->is_super)) { ERROR (CHOLMOD_INVALID, "cannot convert simplicial L to supernodal") ; } /* FUTURE WORK: convert to/from supernodal LL' and LDL' */ } } else { /* -------------------------------------------------------------- */ /* convert any factor to simplicial numeric */ /* -------------------------------------------------------------- */ if (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) { /* ---------------------------------------------------------- */ /* convert simplicial symbolic to simplicial numeric (L=I,D=I)*/ /* ---------------------------------------------------------- */ simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed, to_xtype, Common) ; } else if (L->xtype != CHOLMOD_PATTERN && L->is_super) { /* ---------------------------------------------------------- */ /* convert a supernodal LL' to simplicial numeric */ /* ---------------------------------------------------------- */ ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ; } else if (L->xtype == CHOLMOD_PATTERN && L->is_super) { /* ---------------------------------------------------------- */ /* convert a supernodal symbolic to simplicial numeric (L=D=I)*/ /* ---------------------------------------------------------- */ any_to_simplicial_symbolic (L, to_ll, Common) ; /* if the following fails, it leaves the factor in simplicial * symbolic form */ simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed, to_xtype, Common) ; } else { /* ---------------------------------------------------------- */ /* change a simplicial numeric factor */ /* ---------------------------------------------------------- */ /* change LL' to LDL', LDL' to LL', or leave as-is. pack the * columns of L, or leave as-is. Ensure the columns are * monotonic, or leave as-is. */ change_simplicial_numeric (L, to_ll, to_packed, to_monotonic, Common) ; } } } /* ---------------------------------------------------------------------- */ /* return result */ /* ---------------------------------------------------------------------- */ return (Common->status >= CHOLMOD_OK) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_sparse.c0000644000175000017500000004303411674452555022453 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_sparse ================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Core utility routines for the cholmod_sparse object: * * A sparse matrix is held in compressed column form. In the basic type * ("packed", which corresponds to a MATLAB sparse matrix), an n-by-n matrix * with nz entries is held in three arrays: p of size n+1, i of size nz, and x * of size nz. Row indices of column j are held in i [p [j] ... p [j+1]-1] and * in the same locations in x. There may be no duplicate entries in a column. * Row indices in each column may be sorted or unsorted (CHOLMOD keeps track). * * Primary routines: * ----------------- * cholmod_allocate_sparse allocate a sparse matrix * cholmod_free_sparse free a sparse matrix * * Secondary routines: * ------------------- * cholmod_reallocate_sparse change the size (# entries) of sparse matrix * cholmod_nnz number of nonzeros in a sparse matrix * cholmod_speye sparse identity matrix * cholmod_spzeros sparse zero matrix * cholmod_copy_sparse create a copy of a sparse matrix * * All xtypes are supported (pattern, real, complex, and zomplex) */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === cholmod_allocate_sparse ============================================== */ /* ========================================================================== */ /* Allocate space for a matrix. A->i and A->x are not initialized. A->p * (and A->nz if A is not packed) are set to zero, so a matrix containing no * entries (all zero) is returned. See also cholmod_spzeros. * * workspace: none */ cholmod_sparse *CHOLMOD(allocate_sparse) ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ size_t nzmax, /* max # of nonzeros of A */ int sorted, /* TRUE if columns of A sorted, FALSE otherwise */ int packed, /* TRUE if A will be packed, FALSE otherwise */ int stype, /* stype of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *A ; Int *Ap, *Anz ; size_t nzmax0 ; Int j ; int ok = TRUE ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; if (stype != 0 && nrow != ncol) { ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ; return (NULL) ; } if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX) { ERROR (CHOLMOD_INVALID, "xtype invalid") ; return (NULL) ; } /* ensure the dimensions do not cause integer overflow */ (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ; if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate header */ /* ---------------------------------------------------------------------- */ A = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } PRINT1 (("cholmod_allocate_sparse %d-by-%d nzmax %d sorted %d packed %d" " xtype %d\n", nrow, ncol, nzmax, sorted, packed, xtype)) ; nzmax = MAX (1, nzmax) ; A->nrow = nrow ; A->ncol = ncol ; A->nzmax = nzmax ; A->packed = packed ; /* default is packed (A->nz not present) */ A->stype = stype ; A->itype = ITYPE ; A->xtype = xtype ; A->dtype = DTYPE ; A->nz = NULL ; A->p = NULL ; A->i = NULL ; A->x = NULL ; A->z = NULL ; /* A 1-by-m matrix always has sorted columns */ A->sorted = (nrow <= 1) ? TRUE : sorted ; /* ---------------------------------------------------------------------- */ /* allocate the matrix itself */ /* ---------------------------------------------------------------------- */ /* allocate O(ncol) space */ A->p = CHOLMOD(malloc) (((size_t) ncol)+1, sizeof (Int), Common) ; if (!packed) { A->nz = CHOLMOD(malloc) (ncol, sizeof (Int), Common) ; } /* allocate O(nz) space */ nzmax0 = 0 ; CHOLMOD(realloc_multiple) (nzmax, 1, xtype, &(A->i), NULL, &(A->x), &(A->z), &nzmax0, Common) ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_sparse) (&A, Common) ; return (NULL) ; /* out of memory */ } /* ---------------------------------------------------------------------- */ /* initialize A->p and A->nz so that A is an empty matrix */ /* ---------------------------------------------------------------------- */ Ap = A->p ; for (j = 0 ; j <= (Int) ncol ; j++) { Ap [j] = 0 ; } if (!packed) { Anz = A->nz ; for (j = 0 ; j < (Int) ncol ; j++) { Anz [j] = 0 ; } } return (A) ; } /* ========================================================================== */ /* === cholmod_free_sparse ================================================== */ /* ========================================================================== */ /* free a sparse matrix * * workspace: none */ int CHOLMOD(free_sparse) ( /* ---- in/out --- */ cholmod_sparse **AHandle, /* matrix to deallocate, NULL on output */ /* --------------- */ cholmod_common *Common ) { Int n, nz ; cholmod_sparse *A ; RETURN_IF_NULL_COMMON (FALSE) ; if (AHandle == NULL) { /* nothing to do */ return (TRUE) ; } A = *AHandle ; if (A == NULL) { /* nothing to do */ return (TRUE) ; } n = A->ncol ; nz = A->nzmax ; A->p = CHOLMOD(free) (n+1, sizeof (Int), A->p, Common) ; A->i = CHOLMOD(free) (nz, sizeof (Int), A->i, Common) ; A->nz = CHOLMOD(free) (n, sizeof (Int), A->nz, Common) ; switch (A->xtype) { case CHOLMOD_REAL: A->x = CHOLMOD(free) (nz, sizeof (double), A->x, Common) ; break ; case CHOLMOD_COMPLEX: A->x = CHOLMOD(free) (nz, 2*sizeof (double), A->x, Common) ; break ; case CHOLMOD_ZOMPLEX: A->x = CHOLMOD(free) (nz, sizeof (double), A->x, Common) ; A->z = CHOLMOD(free) (nz, sizeof (double), A->z, Common) ; break ; } *AHandle = CHOLMOD(free) (1, sizeof (cholmod_sparse), (*AHandle), Common) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_reallocate_sparse ============================================ */ /* ========================================================================== */ /* Change the size of A->i, A->x, and A->z, or allocate them if their current * size is zero. A->x and A->z are not modified if A->xtype is CHOLMOD_PATTERN. * A->z is not modified unless A->xtype is CHOLMOD_ZOMPLEX. * * workspace: none */ int CHOLMOD(reallocate_sparse) ( /* ---- input ---- */ size_t nznew, /* new # of entries in A */ /* ---- in/out --- */ cholmod_sparse *A, /* matrix to reallocate */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (A, FALSE) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; PRINT1 (("realloc matrix %d to %d, xtype: %d\n", A->nzmax, nznew, A->xtype)) ; /* ---------------------------------------------------------------------- */ /* resize the matrix */ /* ---------------------------------------------------------------------- */ CHOLMOD(realloc_multiple) (MAX (1,nznew), 1, A->xtype, &(A->i), NULL, &(A->x), &(A->z), &(A->nzmax), Common) ; return (Common->status == CHOLMOD_OK) ; } /* ========================================================================== */ /* === cholmod_speye ======================================================== */ /* ========================================================================== */ /* Return a sparse identity matrix. */ cholmod_sparse *CHOLMOD(speye) ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Az ; cholmod_sparse *A ; Int *Ap, *Ai ; Int j, n ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate the matrix */ /* ---------------------------------------------------------------------- */ n = MIN (nrow, ncol) ; A = CHOLMOD(allocate_sparse) (nrow, ncol, n, TRUE, TRUE, 0, xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory or inputs invalid */ } /* ---------------------------------------------------------------------- */ /* create the identity matrix */ /* ---------------------------------------------------------------------- */ Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; for (j = 0 ; j < n ; j++) { Ap [j] = j ; } for (j = n ; j <= ((Int) ncol) ; j++) { Ap [j] = n ; } for (j = 0 ; j < n ; j++) { Ai [j] = j ; } switch (xtype) { case CHOLMOD_REAL: for (j = 0 ; j < n ; j++) { Ax [j] = 1 ; } break ; case CHOLMOD_COMPLEX: for (j = 0 ; j < n ; j++) { Ax [2*j ] = 1 ; Ax [2*j+1] = 0 ; } break ; case CHOLMOD_ZOMPLEX: for (j = 0 ; j < n ; j++) { Ax [j] = 1 ; } for (j = 0 ; j < n ; j++) { Az [j] = 0 ; } break ; } return (A) ; } /* ========================================================================== */ /* === cholmod_spzeros ====================================================== */ /* ========================================================================== */ /* Return a sparse zero matrix. */ cholmod_sparse *CHOLMOD(spzeros) ( /* ---- input ---- */ size_t nrow, /* # of rows of A */ size_t ncol, /* # of columns of A */ size_t nzmax, /* max # of nonzeros of A */ int xtype, /* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* allocate the matrix */ /* ---------------------------------------------------------------------- */ return (CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, TRUE, TRUE, 0, xtype, Common)) ; } /* ========================================================================== */ /* === cholmod_nnz ========================================================== */ /* ========================================================================== */ /* Return the number of entries in a sparse matrix. * * workspace: none * integer overflow cannot occur, since the matrix is already allocated. */ UF_long CHOLMOD(nnz) ( /* ---- input ---- */ cholmod_sparse *A, /* --------------- */ cholmod_common *Common ) { Int *Ap, *Anz ; size_t nz ; Int j, ncol ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (EMPTY) ; RETURN_IF_NULL (A, EMPTY) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ; Common->status = CHOLMOD_OK ; /* ---------------------------------------------------------------------- */ /* return nnz (A) */ /* ---------------------------------------------------------------------- */ ncol = A->ncol ; if (A->packed) { Ap = A->p ; RETURN_IF_NULL (Ap, EMPTY) ; nz = Ap [ncol] ; } else { Anz = A->nz ; RETURN_IF_NULL (Anz, EMPTY) ; nz = 0 ; for (j = 0 ; j < ncol ; j++) { nz += MAX (0, Anz [j]) ; } } return (nz) ; } /* ========================================================================== */ /* === cholmod_copy_sparse ================================================== */ /* ========================================================================== */ /* C = A. Create an exact copy of a sparse matrix, with one exception. * Entries in unused space are not copied (they might not be initialized, * and copying them would cause program checkers such as purify and * valgrind to complain). The xtype of the resulting matrix C is the same as * the xtype of the input matrix A. * * See also Core/cholmod_copy, which copies a matrix with possible changes * in stype, presence of diagonal entries, pattern vs. numerical values, * real and/or imaginary parts, and so on. */ cholmod_sparse *CHOLMOD(copy_sparse) ( /* ---- input ---- */ cholmod_sparse *A, /* matrix to copy */ /* --------------- */ cholmod_common *Common ) { double *Ax, *Cx, *Az, *Cz ; Int *Ap, *Ai, *Anz, *Cp, *Ci, *Cnz ; cholmod_sparse *C ; Int p, pend, j, ncol, packed, nzmax, nz, xtype ; /* ---------------------------------------------------------------------- */ /* check inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (A, NULL) ; RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; if (A->stype != 0 && A->nrow != A->ncol) { ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ; return (NULL) ; } Common->status = CHOLMOD_OK ; ASSERT (CHOLMOD(dump_sparse) (A, "A original", Common) >= 0) ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ ncol = A->ncol ; nzmax = A->nzmax ; packed = A->packed ; Ap = A->p ; Ai = A->i ; Ax = A->x ; Az = A->z ; Anz = A->nz ; xtype = A->xtype ; /* ---------------------------------------------------------------------- */ /* allocate the copy */ /* ---------------------------------------------------------------------- */ C = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, A->nzmax, A->sorted, A->packed, A->stype, A->xtype, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } Cp = C->p ; Ci = C->i ; Cx = C->x ; Cz = C->z ; Cnz = C->nz ; /* ---------------------------------------------------------------------- */ /* copy the matrix */ /* ---------------------------------------------------------------------- */ for (j = 0 ; j <= ncol ; j++) { Cp [j] = Ap [j] ; } if (packed) { nz = Ap [ncol] ; for (p = 0 ; p < nz ; p++) { Ci [p] = Ai [p] ; } switch (xtype) { case CHOLMOD_REAL: for (p = 0 ; p < nz ; p++) { Cx [p] = Ax [p] ; } break ; case CHOLMOD_COMPLEX: for (p = 0 ; p < 2*nz ; p++) { Cx [p] = Ax [p] ; } break ; case CHOLMOD_ZOMPLEX: for (p = 0 ; p < nz ; p++) { Cx [p] = Ax [p] ; Cz [p] = Az [p] ; } break ; } } else { for (j = 0 ; j < ncol ; j++) { Cnz [j] = Anz [j] ; } switch (xtype) { case CHOLMOD_PATTERN: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; } } break ; case CHOLMOD_REAL: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; Cx [p] = Ax [p] ; } } break ; case CHOLMOD_COMPLEX: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; Cx [2*p ] = Ax [2*p ] ; Cx [2*p+1] = Ax [2*p+1] ; } } break ; case CHOLMOD_ZOMPLEX: for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = p + Anz [j] ; for ( ; p < pend ; p++) { Ci [p] = Ai [p] ; Cx [p] = Ax [p] ; Cz [p] = Az [p] ; } } break ; } } /* ---------------------------------------------------------------------- */ /* return the result */ /* ---------------------------------------------------------------------- */ ASSERT (CHOLMOD(dump_sparse) (C, "C copy", Common) >= 0) ; return (C) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/cholmod_factor.c0000644000175000017500000006536211674452555022444 0ustar sonnesonne/* ========================================================================== */ /* === Core/cholmod_factor ================================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Core utility routines for the cholmod_factor object: * * The data structure for an LL' or LDL' factorization is too complex to * describe in one sentence. This object can hold the symbolic analysis alone, * or in combination with a "simplicial" (similar to a sparse matrix) or * "supernodal" form of the numerical factorization. Only the routine to free * a factor is primary, since a factor object is created by the factorization * routine (cholmod_factorize). It must be freed with cholmod_free_factor. * * Primary routine: * ---------------- * cholmod_free_factor free a factor * * Secondary routines: * ------------------- * cholmod_allocate_factor allocate a symbolic factor (LL' or LDL') * cholmod_reallocate_factor change the # entries in a factor * cholmod_change_factor change the type of factor (e.g., LDL' to LL') * cholmod_pack_factor pack the columns of a factor * cholmod_reallocate_column resize a single column of a factor * cholmod_factor_to_sparse create a sparse matrix copy of a factor * cholmod_copy_factor create a copy of a factor * * Note that there is no cholmod_sparse_to_factor routine to create a factor * as a copy of a sparse matrix. It could be done, after a fashion, but a * lower triangular sparse matrix would not necessarily have a chordal graph, * which would break the many CHOLMOD routines that rely on this property. * * The cholmod_factor_to_sparse routine is provided so that matrix operations * in the MatrixOps module may be applied to L. Those operations operate on * cholmod_sparse objects, and they are not guaranteed to maintain the chordal * property of L. Such a modified L cannot be safely converted back to a * cholmod_factor object. */ #include "cholmod_internal.h" #include "cholmod_core.h" /* ========================================================================== */ /* === cholmod_allocate_factor ============================================== */ /* ========================================================================== */ /* Allocate a simplicial symbolic factor, with L->Perm and L->ColCount allocated * and initialized to "empty" values (Perm [k] = k, and ColCount[k] = 1). * The integer and numerical parts of L are not allocated. L->xtype is returned * as CHOLMOD_PATTERN and L->is_super are returned as FALSE. L->is_ll is also * returned FALSE, but this may be modified when the matrix is factorized. * * This is sufficient (but far from ideal) for input to cholmod_factorize, * since the simplicial LL' or LDL' factorization (cholmod_rowfac) can * reallocate the columns of L as needed. The primary purpose of this routine * is to allocate space for a symbolic factorization, for the "expert" user to * do his or her own symbolic analysis. The typical user should use * cholmod_analyze instead of this routine. * * workspace: none */ cholmod_factor *CHOLMOD(allocate_factor) ( /* ---- input ---- */ size_t n, /* L is n-by-n */ /* --------------- */ cholmod_common *Common ) { Int j ; Int *Perm, *ColCount ; cholmod_factor *L ; int ok = TRUE ; RETURN_IF_NULL_COMMON (FALSE) ; Common->status = CHOLMOD_OK ; /* ensure the dimension does not cause integer overflow */ (void) CHOLMOD(add_size_t) (n, 2, &ok) ; if (!ok || n > Int_max) { ERROR (CHOLMOD_TOO_LARGE, "problem too large") ; return (NULL) ; } L = CHOLMOD(malloc) (sizeof (cholmod_factor), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } L->n = n ; L->is_ll = FALSE ; L->is_super = FALSE ; L->is_monotonic = TRUE ; L->itype = ITYPE ; L->xtype = CHOLMOD_PATTERN ; L->dtype = DTYPE ; /* allocate the purely symbolic part of L */ L->ordering = CHOLMOD_NATURAL ; L->Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ; L->ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ; /* simplicial part of L is empty */ L->nzmax = 0 ; L->p = NULL ; L->i = NULL ; L->x = NULL ; L->z = NULL ; L->nz = NULL ; L->next = NULL ; L->prev = NULL ; /* supernodal part of L is also empty */ L->nsuper = 0 ; L->ssize = 0 ; L->xsize = 0 ; L->maxesize = 0 ; L->maxcsize = 0 ; L->super = NULL ; L->pi = NULL ; L->px = NULL ; L->s = NULL ; /* L has not been factorized */ L->minor = n ; if (Common->status < CHOLMOD_OK) { CHOLMOD(free_factor) (&L, Common) ; return (NULL) ; /* out of memory */ } /* initialize Perm and ColCount */ Perm = L->Perm ; for (j = 0 ; j < ((Int) n) ; j++) { Perm [j] = j ; } ColCount = L->ColCount ; for (j = 0 ; j < ((Int) n) ; j++) { ColCount [j] = 1 ; } return (L) ; } /* ========================================================================== */ /* === cholmod_free_factor ================================================== */ /* ========================================================================== */ /* Free a factor object. * * workspace: none */ int CHOLMOD(free_factor) ( /* ---- in/out --- */ cholmod_factor **LHandle, /* factor to free, NULL on output */ /* --------------- */ cholmod_common *Common ) { Int n, lnz, xs, ss, s ; cholmod_factor *L ; RETURN_IF_NULL_COMMON (FALSE) ; if (LHandle == NULL) { /* nothing to do */ return (TRUE) ; } L = *LHandle ; if (L == NULL) { /* nothing to do */ return (TRUE) ; } n = L->n ; lnz = L->nzmax ; s = L->nsuper + 1 ; xs = (L->is_super) ? ((Int) (L->xsize)) : (lnz) ; ss = L->ssize ; /* symbolic part of L */ CHOLMOD(free) (n, sizeof (Int), L->Perm, Common) ; CHOLMOD(free) (n, sizeof (Int), L->ColCount, Common) ; /* simplicial form of L */ CHOLMOD(free) (n+1, sizeof (Int), L->p, Common) ; CHOLMOD(free) (lnz, sizeof (Int), L->i, Common) ; CHOLMOD(free) (n, sizeof (Int), L->nz, Common) ; CHOLMOD(free) (n+2, sizeof (Int), L->next, Common) ; CHOLMOD(free) (n+2, sizeof (Int), L->prev, Common) ; /* supernodal form of L */ CHOLMOD(free) (s, sizeof (Int), L->pi, Common) ; CHOLMOD(free) (s, sizeof (Int), L->px, Common) ; CHOLMOD(free) (s, sizeof (Int), L->super, Common) ; CHOLMOD(free) (ss, sizeof (Int), L->s, Common) ; /* numerical values for both simplicial and supernodal L */ if (L->xtype == CHOLMOD_REAL) { CHOLMOD(free) (xs, sizeof (double), L->x, Common) ; } else if (L->xtype == CHOLMOD_COMPLEX) { CHOLMOD(free) (xs, 2*sizeof (double), L->x, Common) ; } else if (L->xtype == CHOLMOD_ZOMPLEX) { CHOLMOD(free) (xs, sizeof (double), L->x, Common) ; CHOLMOD(free) (xs, sizeof (double), L->z, Common) ; } *LHandle = CHOLMOD(free) (1, sizeof (cholmod_factor), (*LHandle), Common) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_reallocate_factor ============================================ */ /* ========================================================================== */ /* Change the size of L->i and L->x, or allocate them if their current size * is zero. L must be simplicial. * * workspace: none */ int CHOLMOD(reallocate_factor) ( /* ---- input ---- */ size_t nznew, /* new # of entries in L */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) { /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; PRINT1 (("realloc factor: xtype %d\n", L->xtype)) ; if (L->is_super) { /* L must be simplicial, and not symbolic */ ERROR (CHOLMOD_INVALID, "L invalid") ; return (FALSE) ; } Common->status = CHOLMOD_OK ; PRINT1 (("realloc factor %g to %g\n", (double) L->nzmax, (double) nznew)) ; /* ---------------------------------------------------------------------- */ /* resize (or allocate) the L->i and L->x components of the factor */ /* ---------------------------------------------------------------------- */ CHOLMOD(realloc_multiple) (nznew, 1, L->xtype, &(L->i), NULL, &(L->x), &(L->z), &(L->nzmax), Common) ; return (Common->status == CHOLMOD_OK) ; } /* ========================================================================== */ /* === cholmod_reallocate_column =========================================== */ /* ========================================================================== */ /* Column j needs more space, reallocate it at the end of L->i and L->x. * If the reallocation fails, the factor is converted to a simplicial * symbolic factor (no pattern, just L->Perm and L->ColCount). * * workspace: none */ int CHOLMOD(reallocate_column) ( /* ---- input ---- */ size_t j, /* the column to reallocate */ size_t need, /* required size of column j */ /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) { double xneed ; double *Lx, *Lz ; Int *Lp, *Lprev, *Lnext, *Li, *Lnz ; Int n, pold, pnew, len, k, tail ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ; if (L->is_super) { ERROR (CHOLMOD_INVALID, "L must be simplicial") ; return (FALSE) ; } n = L->n ; if (j >= L->n || need == 0) { ERROR (CHOLMOD_INVALID, "j invalid") ; return (FALSE) ; /* j out of range */ } Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start colrealloc", Common)) ; /* ---------------------------------------------------------------------- */ /* increase the size of L if needed */ /* ---------------------------------------------------------------------- */ /* head = n+1 ; */ tail = n ; Lp = L->p ; Lnz = L->nz ; Lprev = L->prev ; Lnext = L->next ; ASSERT (Lnz != NULL) ; ASSERT (Lnext != NULL && Lprev != NULL) ; PRINT1 (("col %g need %g\n", (double) j, (double) need)) ; /* column j cannot have more than n-j entries if all entries are present */ need = MIN (need, n-j) ; /* compute need in double to avoid integer overflow */ if (Common->grow1 >= 1.0) { xneed = (double) need ; xneed = Common->grow1 * xneed + Common->grow2 ; xneed = MIN (xneed, n-j) ; need = (Int) xneed ; } PRINT1 (("really new need %g current %g\n", (double) need, (double) (Lp [Lnext [j]] - Lp [j]))) ; ASSERT (need >= 1 && need <= n-j) ; if (Lp [Lnext [j]] - Lp [j] >= (Int) need) { /* no need to reallocate the column, it's already big enough */ PRINT1 (("colrealloc: quick return %g %g\n", (double) (Lp [Lnext [j]] - Lp [j]), (double) need)) ; return (TRUE) ; } if (Lp [tail] + need > L->nzmax) { /* use double to avoid integer overflow */ xneed = (double) need ; if (Common->grow0 < 1.2) /* fl. pt. compare, false if NaN */ { /* if grow0 is less than 1.2 or NaN, don't use it */ xneed = 1.2 * (((double) L->nzmax) + xneed + 1) ; } else { xneed = Common->grow0 * (((double) L->nzmax) + xneed + 1) ; } if (xneed > Size_max || !CHOLMOD(reallocate_factor) ((Int) xneed, L, Common)) { /* out of memory, convert to simplicial symbolic */ CHOLMOD(change_factor) (CHOLMOD_PATTERN, L->is_ll, FALSE, TRUE, TRUE, L, Common) ; ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory; L now symbolic") ; return (FALSE) ; /* out of memory */ } PRINT1 (("\n=== GROW L from %g to %g\n", (double) L->nzmax, (double) xneed)) ; /* pack all columns so that each column has at most grow2 free space */ CHOLMOD(pack_factor) (L, Common) ; ASSERT (Common->status == CHOLMOD_OK) ; Common->nrealloc_factor++ ; } /* ---------------------------------------------------------------------- */ /* reallocate the column */ /* ---------------------------------------------------------------------- */ Common->nrealloc_col++ ; Li = L->i ; Lx = L->x ; Lz = L->z ; /* remove j from its current position in the list */ Lnext [Lprev [j]] = Lnext [j] ; Lprev [Lnext [j]] = Lprev [j] ; /* place j at the end of the list */ Lnext [Lprev [tail]] = j ; Lprev [j] = Lprev [tail] ; Lnext [j] = n ; Lprev [tail] = j ; /* L is no longer monotonic; columns are out-of-order */ L->is_monotonic = FALSE ; /* allocate space for column j */ pold = Lp [j] ; pnew = Lp [tail] ; Lp [j] = pnew ; Lp [tail] += need ; /* copy column j to the new space */ len = Lnz [j] ; for (k = 0 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; } if (L->xtype == CHOLMOD_REAL) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for (k = 0 ; k < len ; k++) { Lx [2*(pnew + k) ] = Lx [2*(pold + k) ] ; Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ; } } else if (L->xtype == CHOLMOD_ZOMPLEX) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; Lz [pnew + k] = Lz [pold + k] ; } } DEBUG (CHOLMOD(dump_factor) (L, "colrealloc done", Common)) ; /* successful reallocation of column j of L */ return (TRUE) ; } /* ========================================================================== */ /* === cholmod_pack_factor ================================================== */ /* ========================================================================== */ /* Pack the columns of a simplicial LDL' or LL' factor. This can be followed * by a call to cholmod_reallocate_factor to reduce the size of L to the exact * size required by the factor, if desired. Alternatively, you can leave the * size of L->i and L->x the same, to allow space for future updates/rowadds. * * Each column is reduced in size so that it has at most Common->grow2 free * space at the end of the column. * * Does nothing and returns silently if given any other type of factor. * * Does NOT force the columns of L to be monotonic. It thus differs from * cholmod_change_factor (xtype, -, FALSE, TRUE, TRUE, L, Common), which * packs the columns and ensures that they appear in monotonic order. */ int CHOLMOD(pack_factor) ( /* ---- in/out --- */ cholmod_factor *L, /* factor to modify */ /* --------------- */ cholmod_common *Common ) { double *Lx, *Lz ; Int *Lp, *Li, *Lnz, *Lnext ; Int pnew, j, k, pold, len, n, head, tail, grow2 ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (FALSE) ; RETURN_IF_NULL (L, FALSE) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ; Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start pack", Common)) ; PRINT1 (("PACK factor %d\n", L->is_super)) ; if (L->xtype == CHOLMOD_PATTERN || L->is_super) { /* nothing to do unless L is simplicial numeric */ return (TRUE) ; } /* ---------------------------------------------------------------------- */ /* pack */ /* ---------------------------------------------------------------------- */ grow2 = Common->grow2 ; PRINT1 (("\nPACK grow2 "ID"\n", grow2)) ; pnew = 0 ; n = L->n ; Lp = L->p ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lnz = L->nz ; Lnext = L->next ; head = n+1 ; tail = n ; for (j = Lnext [head] ; j != tail ; j = Lnext [j]) { /* pack column j */ pold = Lp [j] ; len = Lnz [j] ; ASSERT (len > 0) ; PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ; if (pnew < pold) { PRINT2 ((" pack this column\n")) ; for (k = 0 ; k < len ; k++) { Li [pnew + k] = Li [pold + k] ; } if (L->xtype == CHOLMOD_REAL) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for (k = 0 ; k < len ; k++) { Lx [2*(pnew + k) ] = Lx [2*(pold + k) ] ; Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ; } } else if (L->xtype == CHOLMOD_ZOMPLEX) { for (k = 0 ; k < len ; k++) { Lx [pnew + k] = Lx [pold + k] ; Lz [pnew + k] = Lz [pold + k] ; } } Lp [j] = pnew ; } len = MIN (len + grow2, n - j) ; pnew = MIN (Lp [j] + len, Lp [Lnext [j]]) ; } PRINT2 (("final pnew = "ID"\n", pnew)) ; return (TRUE) ; } /* ========================================================================== */ /* === cholmod_factor_to_sparse ============================================= */ /* ========================================================================== */ /* Constructs a column-oriented sparse matrix containing the pattern and values * of a simplicial or supernodal numerical factor, and then converts the factor * into a simplicial symbolic factor. If L is already packed, monotonic, * and simplicial (which is the case when cholmod_factorize uses the simplicial * Cholesky factorization algorithm) then this routine requires only O(1) * memory and takes O(1) time. * * Only operates on numeric factors (real, complex, or zomplex). Does not * change the numeric L->xtype (the resulting sparse matrix has the same xtype * as L). If this routine fails, L is left unmodified. */ cholmod_sparse *CHOLMOD(factor_to_sparse) ( /* ---- in/out --- */ cholmod_factor *L, /* factor to copy, converted to symbolic on output */ /* --------------- */ cholmod_common *Common ) { cholmod_sparse *Lsparse ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (L, NULL) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ; Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start convert to matrix", Common)) ; /* ---------------------------------------------------------------------- */ /* convert to packed, monotonic, simplicial, numeric */ /* ---------------------------------------------------------------------- */ /* leave as LL or LDL' */ if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, TRUE, TRUE, L, Common)) { ERROR (CHOLMOD_INVALID, "cannot convert L") ; return (NULL) ; } /* ---------------------------------------------------------------------- */ /* create Lsparse */ /* ---------------------------------------------------------------------- */ /* allocate the header for Lsparse, the sparse matrix version of L */ Lsparse = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } /* transfer the contents from L to Lsparse */ Lsparse->nrow = L->n ; Lsparse->ncol = L->n ; Lsparse->p = L->p ; Lsparse->i = L->i ; Lsparse->x = L->x ; Lsparse->z = L->z ; Lsparse->nz = NULL ; Lsparse->stype = 0 ; Lsparse->itype = L->itype ; Lsparse->xtype = L->xtype ; Lsparse->dtype = L->dtype ; Lsparse->sorted = TRUE ; Lsparse->packed = TRUE ; Lsparse->nzmax = L->nzmax ; ASSERT (CHOLMOD(dump_sparse) (Lsparse, "Lsparse", Common) >= 0) ; /* ---------------------------------------------------------------------- */ /* convert L to symbolic, but do not free contents transfered to Lsparse */ /* ---------------------------------------------------------------------- */ L->p = NULL ; L->i = NULL ; L->x = NULL ; L->z = NULL ; L->xtype = CHOLMOD_PATTERN ; CHOLMOD(change_factor) (CHOLMOD_PATTERN, FALSE, FALSE, TRUE, TRUE, L, Common) ; return (Lsparse) ; } /* ========================================================================== */ /* === cholmod_copy_factor ================================================== */ /* ========================================================================== */ /* Create an exact copy of a factor, with one exception: * * Entries in unused space are not copied (they might not be initialized, * and copying them would cause program checkers such as purify and * valgrind to complain). * * Note that a supernodal L cannot be zomplex. */ cholmod_factor *CHOLMOD(copy_factor) ( /* ---- input ---- */ cholmod_factor *L, /* factor to copy */ /* --------------- */ cholmod_common *Common ) { cholmod_factor *L2 ; double *Lx, *L2x, *Lz, *L2z ; Int *Perm, *ColCount, *Lp, *Li, *Lnz, *Lnext, *Lprev, *Lsuper, *Lpi, *Lpx, *Ls, *Perm2, *ColCount2, *L2p, *L2i, *L2nz, *L2next, *L2prev, *L2super, *L2pi, *L2px, *L2s ; Int n, j, p, pend, s, xsize, ssize, nsuper ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ RETURN_IF_NULL_COMMON (NULL) ; RETURN_IF_NULL (L, NULL) ; RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ; Common->status = CHOLMOD_OK ; DEBUG (CHOLMOD(dump_factor) (L, "start copy", Common)) ; n = L->n ; /* ---------------------------------------------------------------------- */ /* allocate a simplicial symbolic factor */ /* ---------------------------------------------------------------------- */ /* allocates L2->Perm and L2->ColCount */ L2 = CHOLMOD(allocate_factor) (n, Common) ; if (Common->status < CHOLMOD_OK) { return (NULL) ; /* out of memory */ } ASSERT (L2->xtype == CHOLMOD_PATTERN && !(L2->is_super)) ; Perm = L->Perm ; ColCount = L->ColCount ; Perm2 = L2->Perm ; ColCount2 = L2->ColCount ; L2->ordering = L->ordering ; for (j = 0 ; j < n ; j++) { Perm2 [j] = Perm [j] ; } for (j = 0 ; j < n ; j++) { ColCount2 [j] = ColCount [j] ; } L2->is_ll = L->is_ll ; /* ---------------------------------------------------------------------- */ /* copy the rest of the factor */ /* ---------------------------------------------------------------------- */ if (L->xtype != CHOLMOD_PATTERN && !(L->super)) { /* ------------------------------------------------------------------ */ /* allocate a simplicial numeric factor */ /* ------------------------------------------------------------------ */ /* allocate L2->p, L2->nz, L2->prev, L2->next, L2->i, and L2->x. * packed = -1 so that cholmod_change_factor allocates space of * size L2->nzmax */ L2->nzmax = L->nzmax ; if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, -1, TRUE, L2, Common)) { CHOLMOD(free_factor) (&L2, Common) ; return (NULL) ; /* out of memory */ } ASSERT (MAX (1, L->nzmax) == L2->nzmax) ; /* ------------------------------------------------------------------ */ /* copy the contents of a simplicial numeric factor */ /* ------------------------------------------------------------------ */ Lp = L->p ; Li = L->i ; Lx = L->x ; Lz = L->z ; Lnz = L->nz ; Lnext = L->next ; Lprev = L->prev ; L2p = L2->p ; L2i = L2->i ; L2x = L2->x ; L2z = L2->z ; L2nz = L2->nz ; L2next = L2->next ; L2prev = L2->prev ; L2->xtype = L->xtype ; L2->dtype = L->dtype ; for (j = 0 ; j <= n ; j++) { L2p [j] = Lp [j] ; } for (j = 0 ; j < n+2 ; j++) { L2prev [j] = Lprev [j] ; } for (j = 0 ; j < n+2 ; j++) { L2next [j] = Lnext [j] ; } for (j = 0 ; j < n ; j++) { L2nz [j] = Lnz [j] ; } for (j = 0 ; j < n ; j++) { p = Lp [j] ; pend = p + Lnz [j] ; for ( ; p < pend ; p++) { L2i [p] = Li [p] ; } p = Lp [j] ; if (L->xtype == CHOLMOD_REAL) { for ( ; p < pend ; p++) { L2x [p] = Lx [p] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for ( ; p < pend ; p++) { L2x [2*p ] = Lx [2*p ] ; L2x [2*p+1] = Lx [2*p+1] ; } } else if (L->xtype == CHOLMOD_ZOMPLEX) { for ( ; p < pend ; p++) { L2x [p] = Lx [p] ; L2z [p] = Lz [p] ; } } } } else if (L->is_super) { /* ------------------------------------------------------------------ */ /* copy a supernodal factor */ /* ------------------------------------------------------------------ */ xsize = L->xsize ; ssize = L->ssize ; nsuper = L->nsuper ; L2->xsize = xsize ; L2->ssize = ssize ; L2->nsuper = nsuper ; /* allocate L2->super, L2->pi, L2->px, and L2->s. Allocate L2->x if * L is numeric */ if (!CHOLMOD(change_factor) (L->xtype, TRUE, TRUE, TRUE, TRUE, L2, Common)) { CHOLMOD(free_factor) (&L2, Common) ; return (NULL) ; /* out of memory */ } ASSERT (L2->s != NULL) ; /* ------------------------------------------------------------------ */ /* copy the contents of a supernodal factor */ /* ------------------------------------------------------------------ */ Lsuper = L->super ; Lpi = L->pi ; Lpx = L->px ; Ls = L->s ; Lx = L->x ; L2super = L2->super ; L2pi = L2->pi ; L2px = L2->px ; L2s = L2->s ; L2x = L2->x ; L2->maxcsize = L->maxcsize ; L2->maxesize = L->maxesize ; for (s = 0 ; s <= nsuper ; s++) { L2super [s] = Lsuper [s] ; } for (s = 0 ; s <= nsuper ; s++) { L2pi [s] = Lpi [s] ; } for (s = 0 ; s <= nsuper ; s++) { L2px [s] = Lpx [s] ; } L2s [0] = 0 ; for (p = 0 ; p < ssize ; p++) { L2s [p] = Ls [p] ; } if (L->xtype == CHOLMOD_REAL) { for (p = 0 ; p < xsize ; p++) { L2x [p] = Lx [p] ; } } else if (L->xtype == CHOLMOD_COMPLEX) { for (p = 0 ; p < 2*xsize ; p++) { L2x [p] = Lx [p] ; } } } L2->minor = L->minor ; L2->is_monotonic = L->is_monotonic ; DEBUG (CHOLMOD(dump_factor) (L2, "L2 got copied", Common)) ; ASSERT (L2->xtype == L->xtype && L2->is_super == L->is_super) ; return (L2) ; } cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/lesser.txt0000644000175000017500000006350011674452555021343 0ustar sonnesonne GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! cvxopt-1.1.4/src/C/SuiteSparse/CHOLMOD/Core/t_cholmod_triplet.c0000644000175000017500000001115611674452555023164 0ustar sonnesonne/* ========================================================================== */ /* === Core/t_cholmod_triplet =============================================== */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * CHOLMOD/Core Module. Copyright (C) 2005-2006, * Univ. of Florida. Author: Timothy A. Davis * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU * Lesser General Public License. See lesser.txt for a text of the license. * CHOLMOD is also available under other licenses; contact authors for details. * http://www.cise.ufl.edu/research/sparse * -------------------------------------------------------------------------- */ /* Template routine for cholmod_triplet. All xtypes supported */ #include "cholmod_template.h" /* ========================================================================== */ /* === t_cholmod_triplet_to_sparse ========================================== */ /* ========================================================================== */ static size_t TEMPLATE (cholmod_triplet_to_sparse) ( /* ---- input ---- */ cholmod_triplet *T, /* matrix to copy */ /* ---- in/out --- */ cholmod_sparse *R, /* output matrix */ /* --------------- */ cholmod_common *Common ) { double *Rx, *Rz, *Tx, *Tz ; Int *Wj, *Rp, *Ri, *Rnz, *Ti, *Tj ; Int i, j, p, p1, p2, pdest, pj, k, stype, nrow, ncol, nz ; size_t anz ; /* ---------------------------------------------------------------------- */ /* get inputs */ /* ---------------------------------------------------------------------- */ /* Wj contains a copy of Rp on input [ */ Wj = Common->Iwork ; /* size MAX (nrow,ncol). (i/l/l) */ Rp = R->p ; Ri = R->i ; Rnz = R->nz ; Rx = R->x ; Rz = R->z ; Ti = T->i ; Tj = T->j ; Tx = T->x ; Tz = T->z ; nz = T->nnz ; nrow = T->nrow ; ncol = T->ncol ; stype = SIGN (T->stype) ; /* ---------------------------------------------------------------------- */ /* construct the row form */ /* ---------------------------------------------------------------------- */ /* if Ti is jumbled, this part dominates the run time */ if (stype > 0) { for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i < j) { /* place triplet (j,i,x) in column i of R */ p = Wj [i]++ ; Ri [p] = j ; } else { /* place triplet (i,j,x) in column j of R */ p = Wj [j]++ ; Ri [p] = i ; } ASSIGN (Rx, Rz, p, Tx, Tz, k) ; } } else if (stype < 0) { for (k = 0 ; k < nz ; k++) { i = Ti [k] ; j = Tj [k] ; if (i > j) { /* place triplet (j,i,x) in column i of R */ p = Wj [i]++ ; Ri [p] = j ; } else { /* place triplet (i,j,x) in column j of R */ p = Wj [j]++ ; Ri [p] = i ; } ASSIGN (Rx, Rz, p, Tx, Tz, k) ; } } else { for (k = 0 ; k < nz ; k++) { /* place triplet (i,j,x) in column i of R */ p = Wj [Ti [k]]++ ; Ri [p] = Tj [k] ; ASSIGN (Rx, Rz, p, Tx, Tz, k) ; } } /* done using Wj (i/l/l) as temporary row pointers ] */ /* ---------------------------------------------------------------------- */ /* sum up duplicates */ /* ---------------------------------------------------------------------- */ /* use Wj (i/l/l) of size ncol to keep track of duplicates in each row [ */ for (j = 0 ; j < ncol ; j++) { Wj [j] = EMPTY ; } anz = 0 ; for (i = 0 ; i < nrow ; i++) { p1 = Rp [i] ; p2 = Rp [i+1] ; pdest = p1 ; /* at this point Wj [j] < p1 holds true for all columns j, because * Ri/Rx is stored in row oriented manner */ for (p = p1 ; p < p2 ; p++) { j = Ri [p] ; pj = Wj [j] ; if (pj >= p1) { /* this column index j is already in row i at position pj; * sum up the duplicate entry */ /* Rx [pj] += Rx [p] ; */ ASSEMBLE (Rx, Rz, pj, Rx, Rz, p) ; } else { /* keep the entry and keep track in Wj [j] for case above */ Wj [j] = pdest ; if (pdest != p) { Ri [pdest] = j ; ASSIGN (Rx, Rz, pdest, Rx, Rz, p) ; } pdest++ ; } } Rnz [i] = pdest - p1 ; anz += (pdest - p1) ; } /* done using Wj to keep track of duplicate entries in each row ] */ /* ---------------------------------------------------------------------- */ /* return number of entries after summing up duplicates */ /* ---------------------------------------------------------------------- */ return (anz) ; } #undef PATTERN #undef REAL #undef COMPLEX #undef ZOMPLEX cvxopt-1.1.4/src/C/SuiteSparse/Contents.m0000644000175000017500000001656011674452555017307 0ustar sonnesonne% Welcome to SuiteSparse : a Suite of Sparse matrix packages, containing a % collection of sparse matrix packages authored or co-authored by Tim Davis. % Only the primary MATLAB functions are listed below. % % Example: % SuiteSparse_install % compiles and installs all of SuiteSparse, and runs several demos and tests. % %------------------------------------------------------------------------------- % Ordering methods: %------------------------------------------------------------------------------- % % amd2 - approximate minimum degree ordering. % colamd2 - column approximate minimum degree ordering. % symamd2 - symmetrix approximate min degree ordering based on colamd. % camd - constrained amd. % ccolamd - constrained colamd. % csymamd - constrained symamd. % meshnd - nested dissection of regular 2D and 3D meshes % %------------------------------------------------------------------------------- % CHOLMOD: a sparse supernodal Cholesky update/downdate package: %------------------------------------------------------------------------------- % % cholmod2 - computes x=A\b when A is symmetric and positive definite. % chol2 - same as MATLAB chol(sparse(A)), just faster. % lchol - computes an LL' factorization. % ldlchol - computes an LDL' factorization. % ldlupdate - updates an LDL' factorization. % resymbol - recomputes symbolic LL or LDL' factorization. % ldlsolve - solves Ax=b using an LDL' factorization. % ldlsplit - splits LD into L and D. % metis - interface to METIS node-nested-dissection. % nesdis - interface to CHOLMOD's nested-dissection (based on METIS). % septree - prune a separator tree. % bisect - interface to METIS' node bisector. % analyze - order and analyze using CHOLMOD. % etree2 - same as MATLAB "etree", just faster and more reliable. % sparse2 - same as MATLAB "sparse", just faster. % symbfact2 - same as MATLAB "symbfact", just faster and more reliable. % sdmult - same as MATLAB S*F or S'*F (S sparse, F full), just faster. % ldl_normest - compute error in LDL' factorization. % lu_normest - compute error in LU factorization. % mread - read a sparse matrix in Matrix Market format % mwrite - write a sparse matrix in Matrix Market format % spsym - determine the symmetry of a sparse matrix % %------------------------------------------------------------------------------- % CSPARSE / CXSPARSE: a Concise Sparse matrix package: %------------------------------------------------------------------------------- % % Matrices used in CSparse must in general be either sparse and real, or % dense vectors. Ordering methods can accept any sparse matrix. CXSparse % supports complex matrices and 64-bit MATLAB; it is installed by default. % % cs_add - sparse matrix addition. % cs_amd - approximate minimum degree ordering. % cs_chol - sparse Cholesky factorization. % cs_cholsol - solve A*x=b using a sparse Cholesky factorization. % cs_counts - column counts for sparse Cholesky factor L. % cs_dmperm - maximum matching or Dulmage-Mendelsohn permutation. % cs_dmsol - x=A\b using the coarse Dulmage-Mendelsohn decomposition. % cs_dmspy - plot the Dulmage-Mendelsohn decomposition of a matrix. % cs_droptol - remove small entries from a sparse matrix. % cs_esep - find an edge separator of a symmetric matrix A % cs_etree - elimination tree of A or A'*A. % cs_gaxpy - sparse matrix times vector. % cs_lsolve - solve a sparse lower triangular system L*x=b. % cs_ltsolve - solve a sparse upper triangular system L'*x=b. % cs_lu - sparse LU factorization, with fill-reducing ordering. % cs_lusol - solve Ax=b using LU factorization. % cs_make - compiles CSparse for use in MATLAB. % cs_multiply - sparse matrix multiply. % cs_nd - generalized nested dissection ordering. % cs_nsep - find a node separator of a symmetric matrix A. % cs_permute - permute a sparse matrix. % cs_print - print the contents of a sparse matrix. % cs_qr - sparse QR factorization. % cs_qleft - apply Householder vectors on the left. % cs_qright - apply Householder vectors on the right. % cs_qrsol - solve a sparse least-squares problem. % cs_randperm - random permutation. % cs_sep - convert an edge separator into a node separator. % cs_scc - strongly-connected components of a square sparse matrix. % cs_scc2 - cs_scc, or connected components of a bipartite graph. % cs_sparse - convert a triplet form into a sparse matrix. % cs_sqr - symbolic sparse QR factorization. % cs_symperm - symmetric permutation of a symmetric matrix. % cs_transpose - transpose a sparse matrix. % cs_updown - rank-1 update/downdate of a sparse Cholesky factorization. % cs_usolve - solve a sparse upper triangular system U*x=b. % cs_utsolve - solve a sparse lower triangular system U'*x=b. % cspy - plot a sparse matrix in color. % ccspy - plot the connected components of a matrix. % %------------------------------------------------------------------------------- % LDL: Sparse LDL factorization: %------------------------------------------------------------------------------- % % ldlsparse - LDL' factorization of a real, sparse, symmetric matrix. % ldlrow - an m-file description of the algorithm used by LDL. % %------------------------------------------------------------------------------- % UMFPACK: the Unsymmetric MultiFrontal Package: %------------------------------------------------------------------------------- % % umfpack2 - computes x=A\b, x=A/b, or lu (A) for a sparse matrix A % umfpack_details - details on all the options for using umfpack in MATLAB % umfpack_report - prints optional control settings and statistics % umfpack_btf - factorize A using a block triangular form % umfpack_solve - x = A\b or x = b/A % lu_normest - estimates norm (L*U-A,1) without forming L*U-A % (duplicate of CHOLMOD/lu_normest, for completeness) % luflop - given L and U, computes # of flops required % %------------------------------------------------------------------------------- % SuiteSparseQR: multifrontal rank-revealing sparse QR %------------------------------------------------------------------------------- % % spqr - sparse QR % spqr_solve - x=A\b using SuiteSparseQR % spqr_qmult - y=Q*x, Q'*x, x*Q, or x*Q' using Q in Householder form % %------------------------------------------------------------------------------- % Other packages: %------------------------------------------------------------------------------- % % UFGET MATLAB interface to the UF Sparse Matrix Collection % MATLAB_Tools various simple m-files % SSMULT sparse matrix times sparse matrix % LINFACTOR solve Ax=b using LU or CHOL % %------------------------------------------------------------------------------- % % For help on compiling SuiteSparse or the demos, testing functions, etc., % please see the help for each individual package. UFcollection and RBio % are two additional toolboxes, for managing the UF Sparse Matrix Collection. % % Copyright 2008, Timothy A. Davis % http://www.cise.ufl.edu/research/sparse help SuiteSparse cvxopt-1.1.4/src/C/cholmod.c0000644000175000017500000011526611674452555014661 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define NO_ANSI99_COMPLEX #include "cvxopt.h" #include "misc.h" #include "cholmod.h" #include "complex.h" const int E_SIZE[] = { sizeof(int_t), sizeof(double), sizeof(complex) }; /* defined in pyconfig.h */ #if (SIZEOF_INT < SIZEOF_LONG) #define CHOL(name) cholmod_l_ ## name #else #define CHOL(name) cholmod_ ## name #endif PyDoc_STRVAR(cholmod__doc__, "Interface to the CHOLMOD library.\n\n" "Routines for sparse Cholesky factorization.\n\n" "The default values of the control parameters in the CHOLMOD 'Common'\n" "object are used, except Common->print, which is set to 0, and \n" "Common->supernodal, which is set to 2.\n" "The parameters Common->supernodal, Common->print, Common->nmethods, \n" "Common->postorder and Common->dbound can be modified by making an\n" "entry in the dictionary cholmod.options, with key value 'supernodal', " "\n'print', 'nmethods', 'postorder', or 'dbound', respectively.\n \n" "These parameters have the following meaning.\n\n" "options['supernodal']: If equal to 0, an LDL^T or LDL^H factorization" "\n is computed using a simplicial algorithm. If equal to 2, an\n" " LL^T or LL^H factorization is computed using a supernodal\n" " algorithm. If equal to 1, the most efficient of the two\n" " factorizations is selected, based on the sparsity pattern.\n\n" "options['print']: A nonnegative integer that controls the amount of\n" " output printed to the screen.\n\n" "options['nmethods']: A nonnegative integer that specifies how many\n" " orderings are attempted prior to factorization. If equal to 0,\n" " the AMD ordering and the user-provided permutation (if any) are\n" " compared, and the best one is used. If equal to 1, the AMD\n" " ordering is used when no permutation is provided by the user,\n" " and the user-provided permutation is used otherwise. Default: 0." "\n\noptions['postorder']: True or False. If True the symbolic\n" " analysis is followed by a postordering. Default: True.\n\n" "options['dbound']: Smallest absolute value for the diagonal\n" " elements of D in an LDL^T factorization, or the diagonal\n" " elements of L in a Cholesky factorization. Default: 0.0.\n\n" "CHOLMOD is available from http://www.cise.ufl.edu/research/sparse."); static PyObject *cholmod_module; static cholmod_common Common; static int set_options(void) { int_t pos=0; PyObject *param, *key, *value; char err_str[100]; #if PY_MAJOR_VERSION < 3 char *keystr; #endif CHOL(defaults)(&Common); Common.print = 0; Common.supernodal = 2; if (!(param = PyObject_GetAttrString(cholmod_module, "options")) || ! PyDict_Check(param)) { PyErr_SetString(PyExc_AttributeError, "missing cholmod.options" "dictionary"); return 0; } while (PyDict_Next(param, &pos, &key, &value)) #if PY_MAJOR_VERSION >= 3 if (PyUnicode_Check(key)) { const char *keystr = _PyUnicode_AsString(key); if (!strcmp("supernodal", keystr) && PyLong_Check(value)) Common.supernodal = (int) PyLong_AsLong(value); else if (!strcmp("print", keystr) && PyLong_Check(value)) Common.print = (int) PyLong_AsLong(value); else if (!strcmp("nmethods", keystr) && PyLong_Check(value)) Common.nmethods = (int) PyLong_AsLong(value); else if (!strcmp("postorder", keystr) && PyBool_Check(value)) Common.postorder = (int) PyLong_AsLong(value); else if (!strcmp("dbound", keystr) && PyFloat_Check(value)) Common.dbound = (double) PyFloat_AsDouble(value); else { sprintf(err_str, "invalid value for CHOLMOD parameter:" \ " %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); Py_DECREF(param); return 0; } } #else if ((keystr = PyString_AsString(key))) { if (!strcmp("supernodal", keystr) && PyInt_Check(value)) Common.supernodal = (int) PyInt_AsLong(value); else if (!strcmp("print", keystr) && PyInt_Check(value)) Common.print = (int) PyInt_AsLong(value); else if (!strcmp("nmethods", keystr) && PyInt_Check(value)) Common.nmethods = (int) PyInt_AsLong(value); else if (!strcmp("postorder", keystr) && PyBool_Check(value)) Common.postorder = (int) PyInt_AsLong(value); else if (!strcmp("dbound", keystr) && PyFloat_Check(value)) Common.dbound = (double) PyFloat_AsDouble(value); else { sprintf(err_str, "invalid value for CHOLMOD parameter:" \ " %-.20s", keystr); PyErr_SetString(PyExc_ValueError, err_str); Py_DECREF(param); return 0; } } #endif Py_DECREF(param); return 1; } static cholmod_sparse *pack(spmatrix *A, char uplo) { int j, k, n = SP_NROWS(A), nnz = 0, cnt = 0; cholmod_sparse *B; if (uplo == 'L'){ for (j=0; jx)[cnt] = SP_VALD(A)[k]; else ((complex *)B->x)[cnt] = SP_VALZ(A)[k]; ((int_t *)B->p)[j+1]++; ((int_t *)B->i)[cnt++] = SP_ROW(A)[k]; } } } else { for (j=0; jx)[cnt] = SP_VALD(A)[k]; else ((complex *)B->x)[cnt] = SP_VALZ(A)[k]; ((int_t *)B->p)[j+1]++; ((int_t *)B->i)[cnt++] = SP_ROW(A)[k]; } } for (j=0; jp)[j+1] += ((int_t *)B->p)[j]; return B; } static cholmod_sparse * create_matrix(spmatrix *A) { cholmod_sparse *B; if (!(B = CHOL(allocate_sparse)(SP_NROWS(A), SP_NCOLS(A), 0, 1, 0, 0, (SP_ID(A) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), &Common))) return NULL; int i; for (i=0; inz)[i] = SP_COL(A)[i+1] - SP_COL(A)[i]; B->x = SP_VAL(A); B->i = SP_ROW(A); B->nzmax = SP_NNZ(A); memcpy(B->p, SP_COL(A), (SP_NCOLS(A)+1)*sizeof(int_t)); return B; } static void free_matrix(cholmod_sparse *A) { A->x = NULL; A->i = NULL; CHOL(free_sparse)(&A, &Common); } #if PY_MAJOR_VERSION >= 3 static void cvxopt_free_cholmod_factor(void *L) { void *Lptr = PyCapsule_GetPointer(L, PyCapsule_GetName(L)); CHOL(free_factor) ((cholmod_factor **) &Lptr, &Common); } #else static void cvxopt_free_cholmod_factor(void *L, void *descr) { CHOL(free_factor) ((cholmod_factor **) &L, &Common) ; } #endif static char doc_symbolic[] = "Symbolic Cholesky factorization of a real symmetric or Hermitian\n" "sparse matrix.\n\n" "F = symbolic(A, p=None, uplo='L')\n\n" "PURPOSE\n" "If cholmod.options['supernodal'] = 2, factors A as\n" "P*A*P^T = L*L^T or P*A*P^T = L*L^H. This is the default value.\n" "If cholmod.options['supernodal'] = 0, factors A as\n" "P*A*P^T = L*D*L^T or P*A*P^T = L*D*L^H with D diagonal and \n" "possibly nonpositive.\n" "If cholmod.options['supernodal'] = 1, the most efficient of the\n" "two factorizations is used.\n\n" "ARGUMENTS\n" "A square sparse matrix of order n.\n\n" "p None, or an 'i' matrix of length n that contains a \n" " permutation vector. If p is not provided, CHOLMOD\n" " uses a permutation from the AMD library.\n\n" "uplo 'L' or 'U'. If uplo is 'L', only the lower triangular\n" " part of A is used and the upper triangular part is\n" " ignored. If uplo is 'U', only the upper triangular\n" " part of A is used and the lower triangular part is\n" " ignored.\n\n" "F the symbolic factorization, including the permutation,\n" " as an opaque C object that can be passed to\n" " cholmod.numeric\n\n"; static PyObject* symbolic(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A; cholmod_sparse *Ac = NULL; cholmod_factor *L; matrix *P=NULL; #if PY_MAJOR_VERSION >= 3 int uplo_='L'; #endif char uplo='L'; int n; char *kwlist[] = {"A", "p", "uplo", NULL}; if (!set_options()) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OC", kwlist, &A, &P, &uplo_)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|Oc", kwlist, &A, &P, &uplo)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a square sparse matrix"); n = SP_NROWS(A); if (P) { if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p"); if (MAT_LGT(P) != n) err_buf_len("p"); if (!CHOL(check_perm)(P->buffer, n, n, &Common)) PY_ERR(PyExc_ValueError, "p is not a valid permutation"); } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); L = CHOL(analyze_p)(Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status != CHOLMOD_OK){ if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); else{ PyErr_SetString(PyExc_ValueError, "symbolic factorization " "failed"); return NULL; } } #if PY_MAJOR_VERSION >= 3 return (PyObject *) PyCapsule_New((void *) L, SP_ID(A)==DOUBLE ? (uplo == 'L' ? "CHOLMOD FACTOR D L" : "CHOLMOD FACTOR D U") : (uplo == 'L' ? "CHOLMOD FACTOR Z L" : "CHOLMOD FACTOR Z U"), (PyCapsule_Destructor) &cvxopt_free_cholmod_factor); #else return (PyObject *) PyCObject_FromVoidPtrAndDesc((void *) L, SP_ID(A)==DOUBLE ? (uplo == 'L' ? "CHOLMOD FACTOR D L" : "CHOLMOD FACTOR D U") : (uplo == 'L' ? "CHOLMOD FACTOR Z L" : "CHOLMOD FACTOR Z U"), cvxopt_free_cholmod_factor); #endif } static char doc_numeric[] = "Numeric Cholesky factorization of a real symmetric or Hermitian\n" "sparse matrix.\n\n" "numeric(A, F)\n\n" "PURPOSE\n" "If cholmod.options['supernodal'] = 2, factors A as\n" "P*A*P^T = L*L^T or P*A*P^T = L*L^H. This is the default value.\n" "If cholmod.options['supernodal'] = 0, factors A as\n" "P*A*P^T = L*D*L^T or P*A*P^T = L*D*L^H with D diagonal and \n" "possibly nonpositive.\n" "If cholmod.options['supernodal'] = 1, the most efficient of the\n" "two factorizations is used. \n" "On entry, F is the symbolic factorization computed by \n" "cholmod.symbolic. On exit, F contains the numeric\n" "factorization. If the matrix is singular, an ArithmeticError\n" "exception is raised, with as its first argument the index of the\n" "column at which the factorization failed.\n\n" "ARGUMENTS\n" "A square sparse matrix. If F was created by calling\n" " cholmod.symbolic with uplo='L', then only the lower\n" " triangular part of A is used. If F was created with\n" " uplo='U', then only the upper triangular part is used.\n" "\n" "F symbolic factorization computed by cholmod.symbolic\n" " applied to a matrix with the same sparsity patter and\n" " type as A. After a successful call, F contains the\n" " numeric factorization."; static PyObject* numeric(PyObject *self, PyObject *args) { spmatrix *A; PyObject *F; cholmod_factor *Lc; cholmod_sparse *Ac = NULL; char uplo; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif if (!set_options()) return NULL; if (!PyArg_ParseTuple(args, "OO", &A, &F)) return NULL; if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a sparse matrix"); #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr) PY_ERR_TYPE("F is not a CHOLMOD factor"); #endif if (SP_ID(A) == DOUBLE){ if (!strcmp(descr, "CHOLMOD FACTOR D L")) uplo = 'L'; else if (!strcmp(descr, "CHOLMOD FACTOR D U")) uplo = 'U'; else PY_ERR_TYPE("F is not the CHOLMOD factor of a 'd' matrix"); } else { if (!strcmp(descr, "CHOLMOD FACTOR Z L")) uplo = 'L'; else if (!strcmp(descr, "CHOLMOD FACTOR Z U")) uplo = 'U'; else PY_ERR_TYPE("F is not the CHOLMOD factor of a 'z' matrix"); } #if PY_MAJOR_VERSION >= 3 Lc = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else Lc = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); CHOL(factorize) (Ac, Lc, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status < 0) switch (Common.status) { case CHOLMOD_OUT_OF_MEMORY: return PyErr_NoMemory(); default: PyErr_SetString(PyExc_ValueError, "factorization failed"); return NULL; } if (Common.status > 0) switch (Common.status) { case CHOLMOD_NOT_POSDEF: PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", Lc->minor)); return NULL; break; case CHOLMOD_DSMALL: /* This never happens unless we change the default value * of Common.dbound (0.0). */ if (Lc->is_ll) PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "\ "elements in L"); else PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal "\ "elements in D"); break; default: PyErr_Warn(PyExc_UserWarning, ""); } return Py_BuildValue(""); } static char doc_solve[] = "Solves a sparse set of linear equations with a factored\n" "coefficient matrix and an dense matrix as right-hand side.\n\n" "solve(F, B, sys=0, nrhs=B.size[1], ldB=max(1,B.size[0], " "offsetB=0)\n\n" "PURPOSE\n" "Solves one of the following systems using the factorization\n" "computed by cholmod.numeric:\n\n" " sys System sys System\n" " 0 A*X = B 5 L'*X = B\n" " 1 L*D*L'*X = B 6 D*X = B\n" " 2 L*D*X = B 7 P'*X = B\n" " 3 D*L'*X = B 8 P*X = B\n" " 4 L*X = B\n\n" "If A was factored as P*A*P' = L*L', then D = I in this table.\n" "B is stored using the LAPACK and BLAS conventions. On exit it\n" "is overwritten with the solution.\n\n" "ARGUMENTS\n" "F the factorization object of A computed by\n" " cholmod.numeric\n\n" "B dense 'd' or 'z' matrix. Must have the same type\n" " as A.\n\n" "sys integer (0 <= sys <= 8)\n\n" "nrhs integer. If negative, the default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetB nonnegative integer"; static PyObject* solve(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *B; PyObject *F; int i, n, oB=0, ldB=0, nrhs=-1, sys=0; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif char *kwlist[] = {"F", "B", "sys", "nrhs", "ldB", "offsetB", NULL}; int sysvalues[] = { CHOLMOD_A, CHOLMOD_LDLt, CHOLMOD_LD, CHOLMOD_DLt, CHOLMOD_L, CHOLMOD_Lt, CHOLMOD_D, CHOLMOD_P, CHOLMOD_Pt }; if (!set_options()) return NULL; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|iiii", kwlist, &F, &B, &sys, &nrhs, &ldB, &oB)) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); if (strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); cholmod_factor *L = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); cholmod_factor *L = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif if (L->xtype == CHOLMOD_PATTERN) PY_ERR(PyExc_ValueError, "called with symbolic factor"); n = L->n; if (L->minor 8) PY_ERR(PyExc_ValueError, "invalid value for sys"); if (!Matrix_Check(B) || MAT_ID(B) == INT || (MAT_ID(B) == DOUBLE && L->xtype == CHOLMOD_COMPLEX) || (MAT_ID(B) == COMPLEX && L->xtype == CHOLMOD_REAL)) PY_ERR_TYPE("B must a dense matrix of the same numerical " "type as F"); if (nrhs < 0) nrhs = MAT_NCOLS(B); if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldB == 0) ldB = MAX(1,MAT_NROWS(B)); if (ldB < MAX(1,n)) err_ld("ldB"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B"); cholmod_dense *x; cholmod_dense *b = CHOL(allocate_dense)(n, 1, n, (MAT_ID(B) == DOUBLE ? CHOLMOD_REAL : CHOLMOD_COMPLEX), &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); void *b_old = b->x; for (i=0; ix = MAT_BUF(B) + (i*ldB + oB)*E_SIZE[MAT_ID(B)]; x = CHOL(solve) (sysvalues[sys], L, b, &Common); if (Common.status != CHOLMOD_OK){ PyErr_SetString(PyExc_ValueError, "solve step failed"); CHOL(free_dense)(&x, &Common); CHOL(free_dense)(&b, &Common); return NULL; } memcpy(b->x, x->x, n*E_SIZE[MAT_ID(B)]); CHOL(free_dense)(&x, &Common); } b->x = b_old; CHOL(free_dense)(&b, &Common); return Py_BuildValue(""); } static char doc_spsolve[] = "Solves a sparse set of linear equations with a factored\n" "coefficient matrix and sparse righthand side.\n\n" "X = spsolve(F, B, sys=0)\n\n" "PURPOSE\n" "Solves one of the following systems using the factorization F\n" "computed by cholmod.numeric:\n\n" " sys System sys System\n" " 0 A*X = B 5 L'*X = B\n" " 1 L*D*L'*X = B 6 D*X = B\n" " 2 L*D*X = B 7 P'*X = B\n" " 3 D*L'*X = B 8 P*X = B\n" " 4 L*X = B\n\n" "If A was factored as P*A*P^T = L*L^T, then D = I in this table.\n" "On exit B is overwritten with the solution.\n\n" "ARGUMENTS\n" "F the factorization object of A computed by\n" " cholmod.numeric\n\n" "B sparse unsymmetric matrix\n\n" "sys integer (0 <= sys <= 8)\n\n" "X sparse unsymmetric matrix"; static PyObject* spsolve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *B, *X=NULL; cholmod_sparse *Bc=NULL, *Xc=NULL; PyObject *F; cholmod_factor *L; int n, sys=0; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif char *kwlist[] = {"F", "B", "sys", NULL}; int sysvalues[] = {CHOLMOD_A, CHOLMOD_LDLt, CHOLMOD_LD, CHOLMOD_DLt, CHOLMOD_L, CHOLMOD_Lt, CHOLMOD_D, CHOLMOD_P, CHOLMOD_Pt }; if (!set_options()) return NULL; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|i", kwlist, &F, &B, &sys)) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); if (strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); L = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); L = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif if (L->xtype == CHOLMOD_PATTERN) PY_ERR(PyExc_ValueError, "called with symbolic factor"); n = L->n; if (L->minor 8) PY_ERR(PyExc_ValueError, "invalid value for sys"); if (!SpMatrix_Check(B) || (SP_ID(B) == DOUBLE && L->xtype == CHOLMOD_COMPLEX) || (SP_ID(B) == COMPLEX && L->xtype == CHOLMOD_REAL)) PY_ERR_TYPE("B must a sparse matrix of the same " "numerical type as F"); if (SP_NROWS(B) != n) PY_ERR(PyExc_ValueError, "incompatible dimensions for B"); if (!(Bc = create_matrix(B))) return PyErr_NoMemory(); Xc = CHOL(spsolve)(sysvalues[sys], L, Bc, &Common); free_matrix(Bc); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); if (Common.status != CHOLMOD_OK) PY_ERR(PyExc_ValueError, "solve step failed"); if (!(X = SpMatrix_New(Xc->nrow, Xc->ncol, ((int_t*)Xc->p)[Xc->ncol], (L->xtype == CHOLMOD_REAL ? DOUBLE : COMPLEX)))) { CHOL(free_sparse)(&Xc, &Common); return PyErr_NoMemory(); } memcpy(SP_COL(X), Xc->p, (Xc->ncol+1)*sizeof(int_t)); memcpy(SP_ROW(X), Xc->i, ((int_t *)Xc->p)[Xc->ncol]*sizeof(int_t)); memcpy(SP_VAL(X), Xc->x, ((int_t *) Xc->p)[Xc->ncol]*E_SIZE[SP_ID(X)]); CHOL(free_sparse)(&Xc, &Common); return (PyObject *) X; } static char doc_linsolve[] = "Solves a sparse positive definite set of linear equations.\n\n" "linsolve(A, B, p=None, uplo='L', nrhs=B.size[1], \n" " ldB=max(1,B.size[0]), offsetB=0)\n\n" "PURPOSE\n" "Solves A*X = B using a sparse Cholesky factorization. On exit\n" "B is overwritten with the solution. The argument p specifies\n" "an optional permutation matrix. If it is not provided, CHOLMOD\n" "uses a permutation from the AMD library. An ArithmeticError\n" "exception is raised if the matrix is singular, with as its first\n" "argument the index of the column at which the factorization\n" "failed.\n\n" "ARGUMENTS\n" "A square sparse matrix\n\n" "B dense 'd' or 'z' matrix. Must have the same type\n" " as A.\n\n" "p None, or an 'i' matrix of length n that contains\n" " a permutation vector\n\n" "uplo 'L' or 'U'. If uplo is 'L', only the lower triangular\n" " part of A is used and the upper triangular part is\n" " ignored. If uplo is 'U', only the upper triangular\n" " part is used, and the lower triangular part is ignored." "\n\n" "nrhs integer. If negative, the default value is used.\n\n" "ldB nonnegative integer. ldB >= max(1,n). If zero, the\n" " default value is used.\n\n" "offsetB nonnegative integer"; static PyObject* linsolve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A; matrix *B, *P=NULL; int i, n, nnz, oB=0, ldB=0, nrhs=-1; cholmod_sparse *Ac=NULL; cholmod_factor *L=NULL; cholmod_dense *x=NULL, *b=NULL; void *b_old; #if PY_MAJOR_VERSION >= 3 int uplo_ = 'L'; #endif char uplo='L'; char *kwlist[] = {"A", "B", "p", "uplo", "nrhs", "ldB", "offsetB", NULL}; if (!set_options()) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OCiii", kwlist, &A, &B, &P, &uplo_, &nrhs, &ldB, &oB)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Ociii", kwlist, &A, &B, &P, &uplo, &nrhs, &ldB, &oB)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a sparse matrix"); n = SP_NROWS(A); nnz = SP_NNZ(A); if (!Matrix_Check(B) || MAT_ID(B) != SP_ID(A)) PY_ERR_TYPE("B must be a dense matrix of the same numerical " "type as A"); if (nrhs < 0) nrhs = MAT_NCOLS(B); if (n == 0 || nrhs == 0) return Py_BuildValue(""); if (ldB == 0) ldB = MAX(1,MAT_NROWS(B)); if (ldB < MAX(1,n)) err_ld("ldB"); if (oB < 0) err_nn_int("offsetB"); if (oB + (nrhs-1)*ldB + n > MAT_LGT(B)) err_buf_len("B"); if (P) { if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p"); if (MAT_LGT(P) != n) err_buf_len("p"); if (!CHOL(check_perm)(P->buffer, n, n, &Common)) PY_ERR(PyExc_ValueError, "not a valid permutation"); } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); L = CHOL(analyze_p)(Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common); if (Common.status != CHOLMOD_OK){ free_matrix(Ac); CHOL(free_sparse)(&Ac, &Common); CHOL(free_factor)(&L, &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); else { PyErr_SetString(PyExc_ValueError, "symbolic factorization " "failed"); return NULL; } } CHOL(factorize) (Ac, L, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status < 0) { CHOL(free_factor)(&L, &Common); switch (Common.status) { case CHOLMOD_OUT_OF_MEMORY: return PyErr_NoMemory(); default: PyErr_SetString(PyExc_ValueError, "factorization " "failed"); return NULL; } } if (Common.status > 0) switch (Common.status) { case CHOLMOD_NOT_POSDEF: PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", L->minor)); CHOL(free_factor)(&L, &Common); return NULL; break; case CHOLMOD_DSMALL: /* This never happens unless we change the default value * of Common.dbound (0.0). */ if (L->is_ll) PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in L"); else PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in D"); break; default: PyErr_Warn(PyExc_UserWarning, ""); } if (L->minorx; for (i=0; ix = MAT_BUF(B) + (i*ldB + oB)*E_SIZE[MAT_ID(B)]; x = CHOL(solve) (CHOLMOD_A, L, b, &Common); if (Common.status != CHOLMOD_OK){ PyErr_SetString(PyExc_ValueError, "solve step failed"); CHOL(free_factor)(&L, &Common); b->x = b_old; CHOL(free_dense)(&b, &Common); CHOL(free_dense)(&x, &Common); return NULL; } memcpy(b->x, x->x, SP_NROWS(A)*E_SIZE[MAT_ID(B)]); CHOL(free_dense)(&x, &Common); } b->x = b_old; CHOL(free_dense)(&b, &Common); CHOL(free_factor)(&L, &Common); return Py_BuildValue(""); } static char doc_splinsolve[] = "Solves a sparse positive definite set of linear equations with\n" "sparse righthand side.\n\n" "X = splinsolve(A, B, p=None, uplo='L')\n\n" "PURPOSE\n" "Solves A*X = B using a sparse Cholesky factorization.\n" "The argument p specifies an optional permutation matrix. If it\n" "is not provided, CHOLMOD uses a permutation from the AMD\n" "library. An ArithmeticError exception is raised if the\n" "factorization does not exist.\n\n" "ARGUMENTS\n" "A square sparse matrix. Only the lower triangular part\n" " of A is used; the upper triangular part is ignored.\n\n" "B sparse matrix of the same type as A\n\n" "p None, or an 'i' matrix of length n that contains\n" " a permutation vector"; static PyObject* splinsolve(PyObject *self, PyObject *args, PyObject *kwrds) { spmatrix *A, *B, *X; matrix *P=NULL; int n, nnz; cholmod_sparse *Ac=NULL, *Bc=NULL, *Xc=NULL; cholmod_factor *L=NULL; #if PY_MAJOR_VERSION >= 3 int uplo_='L'; #endif char uplo='L'; char *kwlist[] = {"A", "B", "p", "uplo", NULL}; if (!set_options()) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|OC", kwlist, &A, &B, &P, &uplo_)) return NULL; uplo = (char) uplo_; #else if (!PyArg_ParseTupleAndKeywords(args, kwrds, "OO|Oc", kwlist, &A, &B, &P, &uplo)) return NULL; #endif if (!SpMatrix_Check(A) || SP_NROWS(A) != SP_NCOLS(A)) PY_ERR_TYPE("A is not a square sparse matrix"); n = SP_NROWS(A); nnz = SP_NNZ(A); if (!SpMatrix_Check(B) || SP_ID(A) != SP_ID(B)) PY_ERR_TYPE("B must be a sparse matrix of the same type as A"); if (SP_NROWS(B) != n) PY_ERR(PyExc_ValueError, "incompatible dimensions for B"); if (P) { if (!Matrix_Check(P) || MAT_ID(P) != INT) err_int_mtrx("p"); if (MAT_LGT(P) != n) err_buf_len("p"); if (!CHOL(check_perm)(P->buffer, n, n, &Common)) PY_ERR(PyExc_ValueError, "not a valid permutation"); } if (uplo != 'U' && uplo != 'L') err_char("uplo", "'L', 'U'"); if (!(Ac = pack(A, uplo))) return PyErr_NoMemory(); L = CHOL(analyze_p) (Ac, P ? MAT_BUFI(P): NULL, NULL, 0, &Common); if (Common.status != CHOLMOD_OK){ CHOL(free_factor)(&L, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status == CHOLMOD_OUT_OF_MEMORY) return PyErr_NoMemory(); else { PyErr_SetString(PyExc_ValueError, "symbolic factorization " "failed"); return NULL; } } CHOL(factorize) (Ac, L, &Common); CHOL(free_sparse)(&Ac, &Common); if (Common.status > 0) switch (Common.status) { case CHOLMOD_NOT_POSDEF: PyErr_SetObject(PyExc_ArithmeticError, Py_BuildValue("i", L->minor)); CHOL(free_factor)(&L, &Common); return NULL; break; case CHOLMOD_DSMALL: /* This never happens unless we change the default value * of Common.dbound (0.0). */ if (L->is_ll) PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in L"); else PyErr_Warn(PyExc_RuntimeWarning, "tiny diagonal " "elements in D"); break; default: PyErr_Warn(PyExc_UserWarning, ""); } if (L->minornrow, Xc->ncol, ((int_t*)Xc->p)[Xc->ncol], SP_ID(A)))) { CHOL(free_sparse)(&Xc, &Common); return PyErr_NoMemory(); } memcpy(SP_COL(X), (int_t *) Xc->p, (Xc->ncol+1)*sizeof(int_t)); memcpy(SP_ROW(X), (int_t *) Xc->i, ((int_t *) Xc->p)[Xc->ncol]*sizeof(int_t)); memcpy(SP_VAL(X), (double *) Xc->x, ((int_t *) Xc->p)[Xc->ncol]*E_SIZE[SP_ID(X)]); CHOL(free_sparse)(&Xc, &Common); return (PyObject *) X; } static char doc_diag[] = "Returns the diagonal of a Cholesky factor.\n\n" "D = diag(F)\n\n" "PURPOSE\n" "Returns the diagonal of the Cholesky factor L in a \n" "factorization P*A*P^T = L*L^T or P*A*P^T = L*L^H.\n\n" "ARGUMENTS\n" "D an nx1 'd' matrix with the diagonal elements of L.\n" " Note that the permutation P is not returned, so the\n" " order of the diagonal elements is unknown.\n\n" "F a numeric Cholesky factor obtained by a call to\n" " cholmod.numeric computed with options['supernodal'] = 2"; extern void dcopy_(int *n, double *x, int *incx, double *y, int *incy); extern void zcopy_(int *n, complex *x, int *incx, complex *y, int *incy); static PyObject* diag(PyObject *self, PyObject *args) { PyObject *F; matrix *d=NULL; cholmod_factor *L; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif int k, strt, incx=1, incy, nrows, ncols; if (!set_options()) return NULL; if (!PyArg_ParseTuple(args, "O", &F)) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); if (strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); L = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); L = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif /* Check factorization */ if (L->xtype == CHOLMOD_PATTERN || L->minorn || !L->is_ll || !L->is_super) PY_ERR(PyExc_ValueError, "F must be a nonsingular supernodal " "Cholesky factor"); if (!(d = Matrix_New(L->n,1,L->xtype == CHOLMOD_REAL ? DOUBLE : COMPLEX))) return PyErr_NoMemory(); strt = 0; for (k=0; knsuper; k++){ /* x[L->px[k], .... ,L->px[k+1]-1] is a dense lower-triangular * nrowx times ncols matrix. We copy its diagonal to * d[strt, ..., strt+ncols-1] */ ncols = (int)((int_t *) L->super)[k+1] - ((int_t *) L->super)[k]; nrows = (int)((int_t *) L->pi)[k+1] - ((int_t *) L->pi)[k]; incy = nrows+1; if (MAT_ID(d) == DOUBLE) dcopy_(&ncols, ((double *) L->x) + ((int_t *) L->px)[k], &incy, MAT_BUFD(d)+strt, &incx); else zcopy_(&ncols, ((complex *) L->x) + ((int_t *) L->px)[k], &incy, MAT_BUFZ(d)+strt, &incx); strt += ncols; } return (PyObject *)d; } static PyObject* getfactor(PyObject *self, PyObject *args) { PyObject *F; cholmod_factor *Lf; cholmod_sparse *Ls; #if PY_MAJOR_VERSION >= 3 const char *descr; #else char *descr; #endif if (!set_options()) return NULL; if (!PyArg_ParseTuple(args, "O", &F)) return NULL; #if PY_MAJOR_VERSION >= 3 if (!PyCapsule_CheckExact(F) || !(descr = PyCapsule_GetName(F))) err_CO("F"); if (strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); Lf = (cholmod_factor *) PyCapsule_GetPointer(F, descr); #else if (!PyCObject_Check(F)) err_CO("F"); descr = PyCObject_GetDesc(F); if (!descr || strncmp(descr, "CHOLMOD FACTOR", 14)) PY_ERR_TYPE("F is not a CHOLMOD factor"); Lf = (cholmod_factor *) PyCObject_AsVoidPtr(F); #endif /* Check factorization */ if (Lf->xtype == CHOLMOD_PATTERN) PY_ERR(PyExc_ValueError, "F must be a numeric Cholesky factor"); if (!(Ls = CHOL(factor_to_sparse)(Lf, &Common))) return PyErr_NoMemory(); spmatrix *ret = SpMatrix_New(Ls->nrow, Ls->ncol, Ls->nzmax, (Ls->xtype == CHOLMOD_REAL ? DOUBLE : COMPLEX)); if (!ret) { CHOL(free_sparse)(&Ls, &Common); return PyErr_NoMemory(); } memcpy(SP_COL(ret), Ls->p, (Ls->ncol+1)*sizeof(int_t)); memcpy(SP_ROW(ret), Ls->i, (Ls->nzmax)*sizeof(int_t)); memcpy(SP_VAL(ret), Ls->x, (Ls->nzmax)*E_SIZE[SP_ID(ret)]); CHOL(free_sparse)(&Ls, &Common); return (PyObject *)ret; } static PyMethodDef cholmod_functions[] = { {"symbolic", (PyCFunction) symbolic, METH_VARARGS|METH_KEYWORDS, doc_symbolic}, {"numeric", (PyCFunction) numeric, METH_VARARGS|METH_KEYWORDS, doc_numeric}, {"solve", (PyCFunction) solve, METH_VARARGS|METH_KEYWORDS, doc_solve}, {"spsolve", (PyCFunction) spsolve, METH_VARARGS|METH_KEYWORDS, doc_spsolve}, {"linsolve", (PyCFunction) linsolve, METH_VARARGS|METH_KEYWORDS, doc_linsolve}, {"splinsolve", (PyCFunction) splinsolve, METH_VARARGS|METH_KEYWORDS, doc_splinsolve}, {"diag", (PyCFunction) diag, METH_VARARGS|METH_KEYWORDS, doc_diag}, {"getfactor", (PyCFunction) getfactor, METH_VARARGS|METH_KEYWORDS, ""}, {NULL} /* Sentinel */ }; #if PY_MAJOR_VERSION >= 3 static PyModuleDef cholmod_module_def = { PyModuleDef_HEAD_INIT, "cholmod", cholmod__doc__, -1, cholmod_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_cholmod(void) { CHOL(start) (&Common); if (!(cholmod_module = PyModule_Create(&cholmod_module_def))) return NULL; PyModule_AddObject(cholmod_module, "options", PyDict_New()); if (import_cvxopt() < 0) return NULL; return cholmod_module; } #else PyMODINIT_FUNC initcholmod(void) { CHOL(start) (&Common); cholmod_module = Py_InitModule3("cvxopt.cholmod", cholmod_functions, cholmod__doc__); PyModule_AddObject(cholmod_module, "options", PyDict_New()); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/C/cvxopt.h0000644000175000017500000001055111674452555014553 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Python.h" #include "structmember.h" #include "blas_redefines.h" #include "assert.h" /* ANSI99 complex is disabled during build of CHOLMOD */ #ifndef NO_ANSI99_COMPLEX #include "complex.h" #define MAT_BUFZ(O) ((complex *)((matrix *)O)->buffer) #endif #ifndef __CVXOPT__ #define __CVXOPT__ #define INT 0 #define DOUBLE 1 #define COMPLEX 2 #define int_t Py_ssize_t typedef struct { PyObject_HEAD void *buffer; /* in column-major-mode array of type 'id' */ #if PY_MAJOR_VERSION >= 3 int nrows, ncols; /* number of rows and columns */ int_t shape[2]; int_t strides[2]; int_t ob_exports; #else int_t nrows, ncols; /* number of rows and columns */ #endif int id; /* DOUBLE, INT, COMPLEX */ } matrix; typedef struct { void *values; /* value list */ int_t *colptr; /* column pointer list */ int_t *rowind; /* row index list */ int_t nrows, ncols; /* number of rows and columns */ int id; /* DOUBLE, COMPLEX */ } ccs; typedef struct { PyObject_HEAD ccs *obj; } spmatrix; #ifdef BASE_MODULE #define Matrix_Check(self) PyObject_TypeCheck(self, &matrix_tp) #define SpMatrix_Check(self) PyObject_TypeCheck(self, &spmatrix_tp) #else static void **cvxopt_API; #define Matrix_New (*(matrix * (*)(int_t, int_t, int)) cvxopt_API[0]) #define Matrix_NewFromMatrix (*(matrix * (*)(matrix *, int)) cvxopt_API[1]) #define Matrix_NewFromList (*(matrix * (*)(PyObject *, int)) cvxopt_API[2]) #define Matrix_Check (*(int * (*)(void *)) cvxopt_API[3]) #define SpMatrix_New (*(spmatrix * (*)(int_t, int_t, int_t, int)) cvxopt_API[4]) #define SpMatrix_NewFromSpMatrix \ (*(spmatrix * (*)(spmatrix *, int)) cvxopt_API[5]) #define SpMatrix_NewFromIJV \ (*(spmatrix * (*)(matrix *, matrix *, matrix *, int_t, int_t, int)) \ cvxopt_API[6]) #define SpMatrix_Check (*(int * (*)(void *)) cvxopt_API[7]) /* Return -1 and set exception on error, 0 on success. */ static int import_cvxopt(void) { PyObject *module = PyImport_ImportModule("cvxopt.base"); if (module != NULL) { PyObject *c_api_object = PyObject_GetAttrString(module, "_C_API"); #if PY_MAJOR_VERSION >= 3 if (!c_api_object || !PyCapsule_IsValid(c_api_object, "base_API")) return -1; cvxopt_API = (void **) PyCapsule_GetPointer(c_api_object, "base_API"); #else if (!c_api_object || !(PyCObject_Check(c_api_object))) return -1; cvxopt_API = (void **) PyCObject_AsVoidPtr(c_api_object); #endif Py_DECREF(c_api_object); } return 0; } #endif /* * Below this line are non-essential convenience macros */ #define MAT_BUF(O) ((matrix *)O)->buffer #define MAT_BUFI(O) ((int_t *)((matrix *)O)->buffer) #define MAT_BUFD(O) ((double *)((matrix *)O)->buffer) #define MAT_BUFZ(O) ((complex *)((matrix *)O)->buffer) #define MAT_NROWS(O) ((matrix *)O)->nrows #define MAT_NCOLS(O) ((matrix *)O)->ncols #define MAT_LGT(O) (MAT_NROWS(O)*MAT_NCOLS(O)) #define MAT_ID(O) ((matrix *)O)->id #define SP_NCOLS(O) ((spmatrix *)O)->obj->ncols #define SP_NROWS(O) ((spmatrix *)O)->obj->nrows #define SP_LGT(O) (SP_NROWS(O)*SP_NCOLS(O)) #define SP_NNZ(O) ((spmatrix *)O)->obj->colptr[SP_NCOLS(O)] #define SP_ID(O) ((spmatrix *)O)->obj->id #define SP_COL(O) ((spmatrix *)O)->obj->colptr #define SP_ROW(O) ((spmatrix *)O)->obj->rowind #define SP_VAL(O) ((spmatrix *)O)->obj->values #define SP_VALD(O) ((double *)((spmatrix *)O)->obj->values) #define SP_VALZ(O) ((complex *)((spmatrix *)O)->obj->values) #define CCS_NROWS(O) ((ccs *)O)->nrows #define CCS_NCOLS(O) ((ccs *)O)->ncols #define CCS_NNZ(O) ((ccs *)O)->colptr[CCS_NCOLS(O)] #endif cvxopt-1.1.4/src/C/dsdp.c0000644000175000017500000004560111674452555014161 0ustar sonnesonne/* * Copyright 2010-2011 L. Vandenberghe. * Copyright 2004-2009 J. Dahl and L. Vandenberghe. * * This file is part of CVXOPT version 1.1.4. * * CVXOPT is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * CVXOPT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "cvxopt.h" #include "misc.h" #include "dsdp5.h" #include "math.h" PyDoc_STRVAR(dsdp__doc__,"Interface to DSDP version 5.8.\n\n" "Software for Semidefinite Programming.\n\n" "Three control parameters can be modified by making an entry in \n" "dictionary dsdp.options:\n" " options['DSDP_Monitor']: set to k in order to show \n" " progress after every kth iteration (default: 0). \n" " options['DSDP_MaxIts']: maximum number of iterations\n" " options['DSDP_GapTolerance']: the relative tolerance used\n" " in the exit condition (default: 1e-5).\n\n" "DSDSP is available from www-unix.mcs.anl.gov/DSDP."); static PyObject *dsdp_module; static char doc_dsdp[] = "Solves a semidefinite program using DSDP.\n\n" "(status, x, r, zl, zs) = sdp(c, Gl=None, hl=None, Gs=None, hs=None" ",\n" " gamma=1e8, beta=1e7)" "\n\n" "PURPOSE\n" "Solves the SDP\n\n" " minimize c'*x + gamma*r\n" " subject to Gl*x <= hl + r\n" " mat(Gs[k]*x) <= hs[k] + r*I, k=1,...,L\n" " -beta <= x <= beta, r >= 0\n\n" "and its dual\n\n" " maximize -hl'*zl - sum_k tr(hs[k]*zs[k]) - beta*||zb||_1\n" " subject to Gl'*zl + sum_k Gs[k]'*vec(zs[k]) + zb + c = 0\n" " sum(zl) + sum_k tr(zs[k]) <= gamma \n" " zl >= 0, zs[k] >=0, k=1,...,L. \n\n" "For an mxm matrix y, vec(y) denotes the m^2-vector with the\n" "entries of y stored columnwise. mat(y) is the inverse\n" "operation.\n\n" "ARGUMENTS\n" "c n by 1 dense 'd' matrix\n\n" "Gl ml by n dense or sparse 'd' matrixi. The default\n" " value is a matrix with zero rows.\n\n" "hl ml by 1 dense 'd' matrix. The default value is a\n" " vector of length zero.\n\n" "Gs list of L dense or sparse 'd' matrices. If the kth\n" " linear matrix inequality has size mk, then Gs[k] is a\n" " matrix of size mk**2 by n, and mat(Gs[k][:,i]) is the\n" " coefficient of the ith variable i in inequality k.\n" " Only the lower triangular entries in mat(Gs[k][:,i])\n" " are accessed. The default value of Gs is an empty list." "\n\n" "hs list of L square dense 'd' matrices. hs[k] is the\n" " righthand side in the kth linear matrix inequality.\n" " Only the lower triangular entries of hs[k] are\n" " accessed. The default value of hs is an empty list.\n\n" "beta positive double\n\n" "gamma positive double\n\n" "status the DSDP solution status: 'DSDP_PDFEASIBLE', \n" " 'DSDP_UNBOUNDED', 'DSDP_INFEASIBLE', or\n" " 'DSDP_UNKNOWN'.\n\n" "x the primal solution, as a dense 'd' matrix of size\n" " n by 1\n\n" "r the optimal value of the variable r\n\n" "zl the dual solution as a dense 'd' matrix of size\n" " ml by 1\n\n" "zs the dual solution as a list of L square dense 'd'\n" " matrices. Each matrix represents a symmetric matrix\n" " in unpacked lower triangular format."; typedef struct { /* symmetric matrix X in DSDP packed storage */ int n; /* order of X */ char issparse; double *val; /* lower triangular nonzeros of X. Stored in row * major order as an n*(n+1)/2-array if X is dense, * and in arbitrary order if X is sparse.*/ int *ind; /* NULL if X is dense; otherwise, the indices of * the elements of val in the n*(n+1)/2 array of * the lower triangular entries of X stored * rowwise. */ int nnz; /* length of val */ } dsdp_matrix; extern void dcopy_(int *n, double *x, int *incx, double *y, int *incy); static PyObject* solvesdp(PyObject *self, PyObject *args, PyObject *kwrds) { matrix *c, *hl=NULL, *hk, *x=NULL, *zl=NULL, *zsk=NULL; PyObject *Gl=NULL, *Gs=NULL, *hs=NULL, *Gk, *t=NULL, *zs=NULL, *param, *key, *value; int i, j, k, n, ml, l, mk, nnz, *lp_colptr=NULL, *lp_rowind=NULL, incx, incy, lngth, maxm; int_t pos=0; double *lp_values=NULL, *zlvals=NULL, *zk=NULL, r, beta=-1.0, gamma=-1.0, tol; dsdp_matrix **lmis=NULL; div_t qr; DSDP sdp; LPCone lpcone; SDPCone sdpcone; DSDPTerminationReason info; DSDPSolutionType status; char err_str[100]; #if PY_MAJOR_VERSION >= 3 const char *keystr; #else char *keystr; #endif char *kwlist[] = {"c", "Gl", "hl", "Gs", "hs", "gamma", "beta", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwrds, "O|OOOOdd", kwlist, &c, &Gl, &hl, &Gs, &hs, &gamma, &beta)) return NULL; if (!Matrix_Check(c) || MAT_NCOLS(c) != 1 || MAT_ID(c) != DOUBLE) PY_ERR_TYPE("c must be a dense 'd' matrix with one column"); n = MAT_NROWS(c); if (Gl && ((!Matrix_Check(Gl) && !SpMatrix_Check(Gl)) || X_NCOLS(Gl) != n || X_ID(Gl) != DOUBLE)) PY_ERR_TYPE("invalid type or dimensions for Gl"); ml = Gl ? X_NROWS(Gl) : 0; if ((!hl && ml) || (hl && (!Matrix_Check(hl) || MAT_NCOLS(hl) != 1 || MAT_NROWS(hl) != ml || MAT_ID(hl) != DOUBLE))) PY_ERR_TYPE("invalid type or dimensions for hl"); if (Gs && !PyList_Check(Gs)) PY_ERR_TYPE("Gs must be a list"); l = Gs ? PyList_Size(Gs) : 0; if (hs && !PyList_Check(hs)) PY_ERR_TYPE("hs must be a list"); if ((!hs && l) || (hs && PyList_Size(hs) != l)) PY_ERR_TYPE("Gs and hs must be lists of equal length"); for (maxm=0, k=0; k= 3 if (PyUnicode_Check(key)) { keystr = _PyUnicode_AsString(key); #else if ((keystr = PyString_AsString(key))){ #endif if (!strcmp(keystr, "DSDP_Monitor")){ #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value)) { #else if (!PyInt_Check(value)) { #endif sprintf(err_str, "invalid value for integer " "DSDP parameter: DSDP_Monitor"); PyErr_SetString(PyExc_ValueError, err_str); t = NULL; Py_DECREF(param); goto done; } #if PY_MAJOR_VERSION >= 3 else DSDPSetStandardMonitor(sdp, PyLong_AsLong(value)); #else else DSDPSetStandardMonitor(sdp, PyInt_AsLong(value)); #endif } if (!strcmp(keystr, "DSDP_MaxIts")){ #if PY_MAJOR_VERSION >= 3 if (!PyLong_Check(value) || (k = PyLong_AsLong(value)) < 0){ #else if (!PyInt_Check(value) || (k = PyInt_AsLong(value)) < 0){ #endif sprintf(err_str, "invalid value for nonnegative " "integer DSDP parameter: DSDP_MaxIts"); PyErr_SetString(PyExc_ValueError, err_str); t = NULL; Py_DECREF(param); goto done; } else DSDPSetMaxIts(sdp, k); } if (!strcmp(keystr, "DSDP_GapTolerance")){ #if PY_MAJOR_VERSION >= 3 if ((!PyFloat_Check(value) && !PyLong_Check(value)) || #else if ((!PyFloat_Check(value) && !PyInt_Check(value)) || #endif (tol = PyFloat_AsDouble(value)) <= 0.0) { sprintf(err_str, "invalid value for float " "DSDP parameter: DSDP_GapTolerance"); PyErr_SetString(PyExc_ValueError, err_str); t = NULL; Py_DECREF(param); goto done; } else DSDPSetGapTolerance(sdp, tol); } } Py_DECREF(param); if (gamma > 0) DSDPSetPenaltyParameter(sdp, gamma); if (beta > 0) DSDPSetYBounds(sdp, -beta, beta); /* cost function */ for (k=0; k= 3 PyUnicode_FromString("DSDP_PDFEASIBLE")); #else PyString_FromString("DSDP_PDFEASIBLE")); #endif break; case DSDP_UNBOUNDED: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("DSDP_UNBOUNDED")); #else PyString_FromString("DSDP_UNBOUNDED")); #endif break; case DSDP_INFEASIBLE: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("DSDP_INFEASIBLE")); #else PyString_FromString("DSDP_INFEASIBLE")); #endif break; case DSDP_PDUNKNOWN: PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("DSDP_UNKNOWN")); #else PyString_FromString("DSDP_UNKNOWN")); #endif break; } } else { PyTuple_SET_ITEM(t, 0, (PyObject *) #if PY_MAJOR_VERSION >= 3 PyUnicode_FromString("DSDP_UNKNOWN")); #else PyString_FromString("DSDP_UNKNOWN")); #endif } DSDPGetY(sdp, MAT_BUFD(x), n); PyTuple_SET_ITEM(t, 1, (PyObject *) x); DSDPGetR(sdp, &r); PyTuple_SET_ITEM(t, 2, Py_BuildValue("d", r)); DSDPComputeX(sdp); LPConeGetXArray(lpcone, &zlvals, &k); memcpy(MAT_BUFD(zl), zlvals, ml*sizeof(double)); PyTuple_SET_ITEM(t, 3, (PyObject *) zl); for (k=0; k= 3 static PyModuleDef dsdp_module_def = { PyModuleDef_HEAD_INIT, "dsdp", dsdp__doc__, -1, dsdp_functions, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_dsdp(void) { if (!(dsdp_module = PyModule_Create(&dsdp_module_def))) return NULL; PyModule_AddObject(dsdp_module, "options", PyDict_New()); if (import_cvxopt() < 0) return NULL; return dsdp_module; } #else PyMODINIT_FUNC initdsdp(void) { dsdp_module = Py_InitModule3("cvxopt.dsdp", dsdp_functions, dsdp__doc__); PyModule_AddObject(dsdp_module, "options", PyDict_New()); if (import_cvxopt() < 0) return; } #endif cvxopt-1.1.4/src/setup.py0000644000175000017500000001310611674452555014406 0ustar sonnesonnefrom distutils.core import setup, Extension from glob import glob # directory containing libblas and liblapack ATLAS_LIB_DIR = '/usr/lib' # Set to 1 if you are using the random number generators in the GNU # Scientific Library. BUILD_GSL = 0 # Directory containing libgsl (used only when BUILD_GSL = 1). GSL_LIB_DIR = '/usr/lib' # Directory containing the GSL header files (used only when BUILD_GSL = 1). GSL_INC_DIR = '/usr/include/gsl' # Set to 1 if you are installing the fftw module. BUILD_FFTW = 0 # Directory containing libfftw3 (used only when BUILD_FFTW = 1). FFTW_LIB_DIR = '/usr/lib' # Directory containing fftw.h (used only when BUILD_FFTW = 1). FFTW_INC_DIR = '/usr/include' # Set to 1 if you are installing the glpk module. BUILD_GLPK = 0 # Directory containing libglpk (used only when BUILD_GLPK = 1). GLPK_LIB_DIR = '/usr/lib' # Directory containing glpk.h (used only when BUILD_GLPK = 1). GLPK_INC_DIR = '/usr/include' # Set to 1 if you are installing the DSDP module. BUILD_DSDP = 0 # Directory containing libdsdp (used only when BUILD_DSDP = 1). DSDP_LIB_DIR = '/usr/lib' # Directory containing dsdp5.h (used only when BUILD_DSDP = 1). DSDP_INC_DIR = '/usr/include' extmods = [] # optional modules if BUILD_GSL: gsl = Extension('gsl', libraries = ['m', 'gsl', 'blas'], include_dirs = [ GSL_INC_DIR ], library_dirs = [ GSL_LIB_DIR ], sources = ['C/gsl.c'] ) extmods += [gsl]; if BUILD_FFTW: fftw = Extension('fftw', libraries = ['fftw3', 'blas'], include_dirs = [ FFTW_INC_DIR ], library_dirs = [ FFTW_LIB_DIR, ATLAS_LIB_DIR ], sources = ['C/fftw.c'] ) extmods += [fftw]; if BUILD_GLPK: glpk = Extension('glpk', libraries = ['glpk'], include_dirs = [ GLPK_INC_DIR ], library_dirs = [ GLPK_LIB_DIR ], sources = ['C/glpk.c'] ) extmods += [glpk]; if BUILD_DSDP: dsdp = Extension('dsdp', libraries = ['dsdp', 'blas', 'lapack'], include_dirs = [ DSDP_INC_DIR ], library_dirs = [ DSDP_LIB_DIR, ATLAS_LIB_DIR ], sources = ['C/dsdp.c'] ) extmods += [dsdp]; # required modules # Modify this for compilation on Windows. # Set to True if your BLAS/LAPACK do not use trailing underscores # (eg, on Windows). BLAS_NOUNDERSCORES = False if BLAS_NOUNDERSCORES: MACROS = [('BLAS_NO_UNDERSCORE','')] else: MACROS = [] base = Extension('base', libraries = ['m','lapack','blas'], library_dirs = [ ATLAS_LIB_DIR ], define_macros = MACROS, sources = ['C/base.c','C/dense.c','C/sparse.c']) blas = Extension('blas', libraries = ['blas'], library_dirs = [ ATLAS_LIB_DIR ], define_macros = MACROS, sources = ['C/blas.c'] ) lapack = Extension('lapack', libraries = ['lapack','blas'], library_dirs = [ ATLAS_LIB_DIR ], define_macros = MACROS, sources = ['C/lapack.c'] ) umfpack = Extension('umfpack', include_dirs = [ 'C/SuiteSparse/UMFPACK/Include', 'C/SuiteSparse/AMD/Include', 'C/SuiteSparse/AMD/Source', 'C/SuiteSparse/UFconfig' ], library_dirs = [ ATLAS_LIB_DIR ], define_macros = MACROS, libraries = [ 'blas', 'lapack'], sources = [ 'C/umfpack.c', 'C/SuiteSparse/UMFPACK/Source/umfpack_global.c', 'C/SuiteSparse/UMFPACK/Source/umfpack_tictoc.c' ] + glob('C/SuiteSparse_cvxopt_extra/umfpack/*')) # Build for int or long? import sys if sys.maxsize > 2**31: MACROS += [('DLONG','')] cholmod = Extension('cholmod', library_dirs = [ ATLAS_LIB_DIR ], libraries = ['lapack', 'blas'], include_dirs = [ 'C/SuiteSparse/CHOLMOD/Include', 'C/SuiteSparse/COLAMD', 'C/SuiteSparse/AMD/Include', 'C/SuiteSparse/UFconfig', 'C/SuiteSparse/COLAMD/Include' ], define_macros = MACROS + [('NPARTITION', '1')], sources = [ 'C/cholmod.c' ] + ['C/SuiteSparse/AMD/Source/' + s for s in ['amd_global.c', 'amd_postorder.c', 'amd_post_tree.c', 'amd_2.c']] + ['C/SuiteSparse/COLAMD/Source/' + s for s in ['colamd.c', 'colamd_global.c']] + glob('C/SuiteSparse/CHOLMOD/Core/c*.c') + glob('C/SuiteSparse/CHOLMOD/Cholesky/c*.c') + ['C/SuiteSparse/CHOLMOD/Check/cholmod_check.c'] + glob('C/SuiteSparse/CHOLMOD/Supernodal/c*.c') ) amd = Extension('amd', include_dirs = [ 'C/SuiteSparse/AMD/Include', 'C/SuiteSparse/UFconfig' ], define_macros = MACROS, sources = [ 'C/amd.c' ] + glob('C/SuiteSparse/AMD/Source/*.c') ) misc_solvers = Extension('misc_solvers', libraries = ['lapack', 'blas'], library_dirs = [ ATLAS_LIB_DIR ], define_macros = MACROS, sources = ['C/misc_solvers.c'] ) extmods += [base, blas, lapack, umfpack, cholmod, amd, misc_solvers] setup (name = 'cvxopt', description = 'Convex optimization package', version = '1.1.4', long_description = ''' CVXOPT is a free software package for convex optimization based on the Python programming language. It can be used with the interactive Python interpreter, on the command line by executing Python scripts, or integrated in other software via Python extension modules. Its main purpose is to make the development of software for convex optimization applications straightforward by building on Python's extensive standard library and on the strengths of Python as a high-level programming language.''', author = 'J. Dahl and L. Vandenberghe', author_email = 'dahl.joachim@gmail.com, vandenbe@ee.ucla.edu', url = 'http://abel.ee.ucla.edu/cvxopt', license = 'GNU GPL version 3', ext_package = "cvxopt", ext_modules = extmods, package_dir = {"cvxopt": "python"}, packages = ["cvxopt"]) cvxopt-1.1.4/LICENSE0000644000175000017500000011005511674452555013113 0ustar sonnesonneCVXOPT version 1.1.4. Copyright (c) 2010-2011 L. Vandenberghe. Copyright (c) 2004-2009 J. Dahl and L. Vandenberghe. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. A copy of the GNU General Public License is included below. For further information, see . --------------------------------------------------------------------------- The CVXOPT distribution includes source code for a subset of the SuiteSparse suite of sparse matrix algorithms, including: - AMD Version 2.2. Copyright (c) 2007 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. - CHOLMOD Version 1.7.1 Copyright (c) 2005-2009 by University of Florida, Timothy A. Davis and W. Hager. - COLAMD version 2.7. Copyright (c) 1998-2007 by Timothy A. Davis. - UMFPACK Version 5.4.0. Copyright (c) 1994-2009 by Timothy A. Davis. These packages are licensed under the terms of the GNU General Public License, version 2 or higher (UMFPACK, the Supernodal module of CHOLMOD) and the GNU Lesser General Public License, version 2.1 or higher (the other CHOLMOD modules, AMD, COLAMD). For copyright and license details, consult the README files in the source directories or the website listed below. Availability: www.cise.ufl.edu/research/sparse. ---------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . cvxopt-1.1.4/examples/0000755000175000017500000000000011674452555013722 5ustar sonnesonnecvxopt-1.1.4/examples/doc/0000755000175000017500000000000011674452555014467 5ustar sonnesonnecvxopt-1.1.4/examples/doc/README0000644000175000017500000000040311674452555015344 0ustar sonnesonneThis directory contains some examples from the following chapters of the CVXOPT documentation. Chapter 4. The LAPACK interface. Chapter 7. Sparse linear equations. Chapter 8. Cone programming. Chapter 9. Nonlinear convex optimization. Chapter 10. Modeling. cvxopt-1.1.4/examples/doc/chap7/0000755000175000017500000000000011674452555015471 5ustar sonnesonnecvxopt-1.1.4/examples/doc/chap7/covsel.bin0000644000175000017500000015776511674452555017503 0ustar sonnesonneccvxopt.base spmatrix p0 (ccvxopt.base matrix p1 ((lp2 F996.97909104636949 aF-23.899785763250076 aF26.492011082544277 aF6.3509700389619157 aF27.477696307918759 aF-20.10640486870755 aF-14.851814216051114 aF-39.697185237027547 aF947.38157898332565 aF-4.2503539341531873 aF-28.731726153288296 aF25.951573115917355 aF912.79246253755866 aF-13.786277258261793 aF-3.3396074735661352 aF22.900426085981067 aF978.76440922035999 aF29.399302044217663 aF29.493675458377876 aF-9.8056680822397801 aF38.431393241910094 aF6.6172107423274227 aF7.0193511209072703 aF922.22675939152157 aF-8.8777874529557934 aF4.9296560159837606 aF-30.101427193113 aF-42.311444619096605 aF-32.096792771239414 aF18.08157424957227 aF12.193794230496929 aF-28.008728552794793 aF-23.317097036200213 aF913.96913055908465 aF-24.845831724585306 aF10.001968526688348 aF-15.928081845683554 aF32.134996939691057 aF953.23023703606907 aF-31.408813001264047 aF-21.955758549991032 aF-2.6022523785110319 aF-24.409891669365642 aF-46.51328294593565 aF-44.116017388700271 aF1047.0946975616821 aF-57.51406393738516 aF22.728277462104138 aF7.9737432521521878 aF-33.082296788521418 aF949.77361988281746 aF8.4350733450998465 aF32.682251604762506 aF-29.480929352123582 aF15.844238681521945 aF19.775029611324165 aF-5.0947662446639193 aF-0.010269200096147485 aF25.839862079998419 aF-0.53768144547513474 aF13.728102825219038 aF936.80804613048372 aF-9.2282887491194838 aF930.34719524342438 aF4.5440998141051496 aF-9.6553236811682304 aF14.957827712488848 aF-17.772161782765689 aF60.971088332972244 aF-7.2789998145743278 aF1.4970964152603377 aF1018.8447349499803 aF10.983621609183592 aF49.840242715255179 aF-14.10310178560856 aF-30.919625902218471 aF-5.7599582459395755 aF19.647643056574967 aF1134.6711873207071 aF-29.786221437844866 aF46.925579827039364 aF0.26189711511288483 aF19.875802071318404 aF1079.0353644586974 aF23.864347083036272 aF-25.868571048536605 aF1026.8823934566585 aF-7.2148710028710292 aF-2.6049232502276154 aF-0.48592393316242866 aF28.012666242657978 aF1.1148049429081099 aF-29.37521222391932 aF-14.572743019440765 aF20.13160412481874 aF-9.2583971209111322 aF-33.345663083499836 aF34.695361038279906 aF888.60799648751174 aF-4.4075247942034945 aF2.5932154444147235 aF1080.670303921205 aF-16.282864156980011 aF31.309379807682205 aF-21.954211030193544 aF-2.8603119891005853 aF18.247977543227993 aF991.71279680172734 aF-4.8485196053621094 aF-5.0414818836610902 aF-34.90572009172373 aF975.70285310346287 aF-27.599258403475741 aF-19.554081005222098 aF-8.4018748398906382 aF23.194823652370179 aF933.75953922039957 aF-6.2430607181068556 aF-5.9586117210145542 aF-43.032268527051862 aF-1.3812138155781659 aF32.113618418246595 aF1018.2708462985455 aF-8.5235052900855326 aF-35.664545920199821 aF6.9328650233786639 aF31.856762014760918 aF-40.504040625099428 aF938.17126479725312 aF-5.7229700303609707 aF22.891261221872782 aF-11.645128742304806 aF12.999683036644514 aF-19.628499827095307 aF986.78052223527141 aF-23.573385777900366 aF7.4680279152300253 aF5.1275578653598348 aF-1.042737735489033 aF-4.2674437851554483 aF7.3323248320460674 aF25.626888311650887 aF22.80125702608931 aF-7.0929101723473753 aF1006.3374409062694 aF-33.532331109901136 aF33.655649116864673 aF20.598909487118235 aF6.4286632720213177 aF-12.60913185908931 aF1090.9574377004108 aF-33.926302763271558 aF21.256562156107488 aF3.7370158811410956 aF1053.3609691435686 aF30.744153525385499 aF29.109422450014989 aF21.014174788884503 aF1007.0584482857449 aF-1.5984603405285771 aF-14.656323249191676 aF-14.431719681436043 aF-18.271260473117763 aF-24.38795987203671 aF-56.856177163127157 aF1052.7732207215265 aF16.404203703933042 aF25.114131414464595 aF43.133027375829762 aF-14.703733280794587 aF12.381973661705503 aF-8.9376590885897382 aF-16.582927679703612 aF901.18993301223213 aF-7.5820865223780309 aF-22.465964144743388 aF961.23344219977866 aF4.3139958368775391 aF4.719391490830203 aF14.133862869025142 aF-7.0983741979460708 aF1087.2808790903955 aF-14.135427208865305 aF1054.4748258881555 aF13.737369734368269 aF-15.347220908753725 aF-6.4321258683569837 aF36.216082201781745 aF-26.965083293110879 aF960.10855261010522 aF-21.914454026182778 aF-21.827743043101556 aF1008.5701804044542 aF-25.993860159652677 aF85.778194350390905 aF-6.6487449866476691 aF-7.0668184483549874 aF46.461350622533871 aF17.297997152422933 aF22.805276284461865 aF1032.0095447438723 aF-28.641108711765913 aF5.9399886197386076 aF22.255065673589328 aF-3.5282149200877768 aF26.949329521067011 aF1041.6709435362741 aF-5.8457038568418431 aF-19.394448816940876 aF-9.2550734558361949 aF-31.611246970898662 aF-25.985863560140764 aF-0.57462882128036252 aF18.864377008466146 aF1013.3491173265605 aF-66.863711615746723 aF949.11778431555842 aF19.063907832744778 aF7.3797451308862891 aF-49.391427131873691 aF1041.6901639915379 aF23.119632520877254 aF-26.314137094746943 aF-14.435128309283789 aF1103.8106946503312 aF8.0832360649960648 aF14.197651570310311 aF-27.496153186411568 aF39.459897343147475 aF22.124776203268652 aF-23.53779700269606 aF990.02001217446423 aF8.0394128461011025 aF-4.580004486298054 aF-11.701232366733938 aF-15.517650888909165 aF11.260868174999487 aF1125.5105685637313 aF4.2307417866318442 aF-18.811122017069376 aF-49.166763753463947 aF-26.514217249254244 aF1013.0784977065847 aF23.740469837673491 aF-6.9238624602975936 aF-18.843063615748449 aF-11.123058027239367 aF13.709049567101383 aF4.8061662338869713 aF911.39063888213821 aF30.639006236842935 aF-0.021747565629815252 aF17.198727471641135 aF921.03696800405214 aF8.9522118988766852 aF24.559371916829303 aF12.932954764470599 aF-17.862368579528425 aF3.2581867346836741 aF24.263041799814406 aF0.34139103729579945 aF-1.520341874100088 aF-54.577702864673071 aF959.12473603431908 aF33.549573383678258 aF26.330997861825583 aF1020.9158970042796 aF38.420919342586295 aF-30.575114960947744 aF-38.522949644282029 aF-6.4801590504904771 aF45.165711036976923 aF-32.513122824771081 aF981.28052425351871 aF15.793285693426757 aF21.574299701890954 aF-30.343103155018674 aF28.371611701865337 aF-7.0184647466242422 aF849.66955580056037 aF-23.979181842500758 aF2.2871064797447076 aF-9.1828674356218212 aF3.2444600514822808 aF0.88520801809984306 aF-8.0220996082277569 aF-9.8464906550347102 aF1.0072931682897124 aF1113.6735624030134 aF10.804331377034174 aF-22.097135878587959 aF9.0655932227405636 aF1076.1844627846301 aF-31.100256263310126 aF-0.78639288985198375 aF53.059431630329676 aF19.477550749954521 aF-0.3826662495765199 aF9.6945653910461882 aF9.8505431522987958 aF971.94270834392728 aF-4.0344149756277154 aF-4.9201586782246132 aF6.7313325590936808 aF-14.495111443520264 aF1014.0009690725504 aF-6.619427100713871 aF-1.8259780647314727 aF31.650817134456236 aF977.30778603252725 aF11.959060583725442 aF13.668415163062924 aF-14.272952682797696 aF0.82816229449399392 aF892.67161757111035 aF-15.388540215810602 aF-19.852898468643751 aF-37.932623711393028 aF7.3614409924374371 aF-23.143487814306138 aF-20.806535758751799 aF925.26375242625215 aF13.344536737030985 aF4.2522225932815099 aF26.885612171187148 aF1077.2879274467157 aF52.15050215627641 aF-30.226756669657068 aF-6.4380544094973979 aF-28.982072345780633 aF-48.120758203276559 aF-30.281662458765187 aF999.84673918724889 aF-23.518683701514437 aF-9.2419948216726358 aF-27.438359166235458 aF936.47768527933579 aF-20.582899958385791 aF-23.537182437014597 aF988.23103074703317 aF-28.998617923082069 aF-12.078155195404895 aF19.25665241106865 aF-4.1099889849555238 aF-14.936505807695358 aF-39.598183889818408 aF972.94890387750684 aF-24.196169328949043 aF5.7677076851447193 aF1012.5648842676636 aF12.957654862031266 aF-15.472932456386102 aF13.842590808859299 aF26.678461221430695 aF9.6047202281871211 aF-14.16174880616726 aF19.040103169315316 aF30.591039143354898 aF-11.361246706625865 aF11.864708678940017 aF8.0503791145424515 aF32.596981761299347 aF900.79255703062927 aF-15.354325213770883 aF-26.270810710786609 aF-3.8707954077725923 aF-22.438403031173699 aF-18.011636544558115 aF-6.6582438290461647 aF1094.8219953058203 aF7.398624298056065 aF-44.582754735006624 aF4.2281391277265081 aF1134.6529637723695 aF39.24556319852524 aF-2.977945087145295 aF17.008299420676956 aF7.8496400060045977 aF-31.201097633100112 aF-6.1170257923647799 aF-2.3387994558943466 aF13.132685477001628 aF6.3718428136022842 aF39.049743685277633 aF969.37520985338426 aF10.546857547725025 aF-0.57545883560222955 aF0.86008774637314589 aF0.30067153225729298 aF-4.4472034653756438 aF975.41455974105622 aF-38.195275733532654 aF-12.02436581887414 aF23.58432513783886 aF-5.3242633833109938 aF-20.825119054173413 aF918.75128197974425 aF-29.722700733593467 aF8.6243893591408174 aF929.95202309010733 aF-11.295440035213476 aF-1.1179207192235838 aF-10.354913806751139 aF-6.6253088069908292 aF973.38113123859966 aF-38.267940654994547 aF16.750357165266838 aF-9.8139331127157341 aF950.45077464160636 aF26.441691642553554 aF2.2956260079994126 aF14.512140450419707 aF-27.171992256251436 aF1062.4893287119701 aF-1.217693535488708 aF9.7779485751468496 aF7.3963156251352249 aF48.050547699593373 aF-29.845428287043386 aF2.5228808932107616 aF976.82200012005626 aF-38.67074388666515 aF18.763585988988229 aF985.16522410123071 aF-6.3203686815117974 aF19.920540122599444 aF9.211874436274794 aF-25.488973067721716 aF-1.5394340988510185 aF-19.736036540870781 aF-29.482083648037243 aF-31.600174660431303 aF997.47509814723696 aF44.767248594881814 aF21.380693018896356 aF915.72994752936518 aF29.524207112551998 aF-7.1189585506651047 aF10.129794131677576 aF-13.755517278622316 aF36.546611617912895 aF1082.9853923512619 aF-14.639195139804945 aF91.215090903308365 aF10.802159371636852 aF45.870551534479745 aF3.4166552312576117 aF-28.897224258101772 aF47.088508956929481 aF929.00054452676727 aF23.791661469381662 aF-2.868962217178268 aF-42.75056506451557 aF965.20234904468873 aF15.616555773420478 aF996.77078853869205 aF8.985429539837785 aF-44.283100598935007 aF15.271861194244881 aF38.926856224741563 aF-2.8823526596194515 aF1062.5887993753693 aF-36.035798686900542 aF45.851311182426933 aF20.94683708207695 aF29.854527434845895 aF968.61499685452327 aF-4.6751894657062341 aF-17.515650154579198 aF3.8148691793079674 aF949.74187830913331 aF43.516266277561122 aF-3.7364772531718558 aF58.879958188684917 aF990.52088554920647 aF49.44521495647534 aF0.85799963670139845 aF-13.781671082551123 aF29.834743853696214 aF988.21958032416353 aF11.894845749015804 aF-26.84587645106037 aF1038.5621852545107 aF-22.387152764567098 aF21.923875285433486 aF35.005604407147011 aF1007.9812225895364 aF9.0973077722126057 aF24.093345355166914 aF-0.67057040703503723 aF39.611893715767785 aF-14.46663769098736 aF-0.20062715808099191 aF-4.2744627422786481 aF1005.5851962727806 aF1.8504674828965959 aF-41.25983683691846 aF-13.710216406501571 aF-16.303794457336465 aF-54.03312808273779 aF1004.8065453788909 aF6.9983168162326583 aF-40.057710409860363 aF42.779489697955128 aF1.7332844880624727 aF1038.0797697191394 aF-33.168165561438087 aF-6.9327933949906893 aF1.430662134835005 aF1094.8945947785323 aF-37.243987292832131 aF-11.197691834606399 aF27.381174573947252 aF-28.252922210902209 aF18.737618837615397 aF-5.7831802021351457 aF16.964448208683656 aF16.275657558233878 aF-18.719750404254576 aF1068.4179631910599 aF-9.8198917335797642 aF36.710032425130073 aF1031.2836526872818 aF24.264059442944379 aF-11.727968212515853 aF-18.151293655059753 aF-24.976172833095269 aF8.3667909344237614 aF-4.4027812298738107 aF1054.3948452057666 aF-50.233686556757249 aF4.6638860661300994 aF19.98484850322081 aF11.212676332857964 aF-7.2815878645996515 aF10.565828529712272 aF987.13682955214369 aF2.4302981844950278 aF936.96450077602799 aF-27.114012164333719 aF-2.8138847985580897 aF-9.1287015698329466 aF57.29093169564895 aF-29.53431342140323 aF-33.278679663689758 aF939.29199645795825 aF-12.419627542773917 aF887.07987341233002 aF29.756103704007913 aF2.4618525611882416 aF957.25992971071935 aF-20.489353133724816 aF11.515863543184533 aF-0.80449734677080986 aF-2.7284743869198489 aF22.229240705888756 aF17.90116513975228 aF21.72211693735008 aF959.94709648027799 aF34.995273758518863 aF27.134387200012014 aF-13.540189765604676 aF1008.3249906000322 aF-27.527424161063873 aF35.384114149189564 aF29.830611110003879 aF1140.27562979709 aF4.5363497360224887 aF937.30782908739877 aF-21.019776840796247 aF23.718961413043186 aF1081.3801927663999 aF-10.874492381232081 aF-16.78244226343773 aF3.9580343961792464 aF1017.2558843909964 aF-5.2974886623784085 aF19.717334827021709 aF12.725210028812757 aF10.573580776229626 aF7.0077864958226712 aF981.26394725566024 aF2.3980900683046502 aF-11.083431325927501 aF994.49342592893572 aF-25.482713356790338 aF1055.5519883462389 aF15.692942677531224 aF-1.0735847177568509 aF9.5716744111900738 aF38.044645125443772 aF1014.2620152503325 aF5.272922152362578 aF-31.121812465026423 aF11.475405850078996 aF6.4940372367327832 aF1034.8872819188484 aF-6.2508460631289662 aF0.26188270833388227 aF26.519785811843121 aF43.57089398457493 aF1004.116273921304 aF28.704065287909565 aF30.427557981129272 aF-11.326465061106145 aF14.069455348079217 aF933.60658849461709 aF15.676874577427034 aF3.4084531694784346 aF18.173465882323715 aF45.013906240699093 aF4.5319108153049346 aF11.885075058291193 aF992.64788528761187 aF14.18959996401418 aF3.7769693527975239 aF-25.980421919719532 aF10.938509729705492 aF994.513735429446 aF6.1197875649908644 aF919.76287575430251 aF18.742518559670419 aF6.5867800823202103 aF6.4771363562967323 aF-62.45016616494982 aF1110.7757959588073 aF7.725509489390177 aF-17.893776294187496 aF-11.069031616989474 aF-12.00684811208982 aF1049.0632719788891 aF-47.582662848842126 aF-20.238606857455949 aF14.129689818693368 aF1049.3586290282979 aF39.554447989074859 aF-13.516310850214932 aF921.11145940005633 aF6.8214590647956586 aF34.078692056032722 aF-18.90239181389882 aF6.5658112888807789 aF-18.53692030669146 aF988.12241478553949 aF-18.044846992594707 aF16.370358177846555 aF5.6769283570573323 aF4.0252910266531039 aF-20.071459215447749 aF1092.6347297868579 aF-23.334143249427662 aF2.1597939530351002 aF-27.987812677839283 aF942.5282200812286 aF13.857525561174864 aF-23.994012273363303 aF882.17315406181706 aF24.583870087304529 aF1.026884690639823 aF17.834431109537359 aF1032.9956875586195 aF39.018910399607357 aF-28.497374264658632 aF31.22736612426257 aF-12.171225572720768 aF10.164992053560601 aF1076.6470432120457 aF-5.2672822581787608 aF1057.1455550686983 aF13.179716530232717 aF-5.3428894527137469 aF7.2874129869206765 aF22.842223576470332 aF-14.710067883564854 aF42.289407851641968 aF975.84247946784501 aF-14.023467851648695 aF24.229909789557059 aF11.047698002925632 aF-8.398349859307098 aF-47.737302476602771 aF-12.222399410493942 aF29.924836183159623 aF-27.569583619433335 aF12.770587324899454 aF1011.0679190716759 aF1032.3413399546473 aF1.0387597682992924 aF-0.91377003635400444 aF11.457770746909334 aF928.27273798487136 aF-3.8668667143785065 aF-26.800143894417431 aF980.56202340494872 aF-3.9512316927659463 aF-3.1617150619105154 aF998.88354816553306 aF38.517681536164325 aF2.9203953964333933 aF9.5761883172002502 aF-16.175462931073753 aF-4.3248265065054357 aF1116.3448423596058 aF11.774687341176623 aF5.3199036328884404 aF-9.9795719318183238 aF7.8566636930425036 aF30.3367700810978 aF954.44449445688542 aF8.0265790854975343 aF30.754542408670797 aF-28.164624762465621 aF1000.0628032213147 aF-27.494312468544834 aF-2.6021471753383776 aF8.7581693881982901 aF22.431023844326432 aF962.1463604946772 aF-23.551611772685607 aF7.3746320850423022 aF1013.3465262998698 aF12.493368987203331 aF36.509309951825344 aF-23.711073590863279 aF52.730079549213912 aF46.100384322751111 aF-4.9065936527229486 aF962.36936009293674 aF20.215352623151198 aF29.848570313773834 aF5.4755866112082101 aF3.8220384611879292 aF1006.0068763722406 aF-20.367203213511527 aF-0.42045513517412436 aF993.82372076550655 aF-8.6880764634740562 aF44.203842622387775 aF-14.241290998893584 aF-26.225894835652635 aF-10.269201095552537 aF19.633669806612005 aF1043.8579294866754 aF15.007029627523357 aF17.186354706126608 aF25.659546891593109 aF31.860361951425794 aF992.07992771387035 aF-13.027965586523621 aF-3.7261819344015157 aF-2.8846061326574799 aF1014.4091678600224 aF13.760142036001628 aF9.1624223284910133 aF-10.337483218210073 aF1032.7995635309576 aF-28.817042577007591 aF6.226865529298812 aF-21.9417763910762 aF-24.24139759003009 aF53.842854869350795 aF8.1280170174491602 aF978.52914499772362 aF8.3241149896082334 aF-7.4669602996361393 aF997.04558743852147 aF-2.4859489080113 aF-21.847666936301977 aF-0.52144893192605135 aF949.8994980544112 aF-16.909903785338692 aF18.539701926532178 aF944.41326783890531 aF8.1659096876066677 aF16.310477734763122 aF1113.8988696385118 aF-33.958016089052528 aF35.272948568283248 aF-13.534255517263681 aF0.70271285423549901 aF1002.7457241696035 aF-16.480026534436487 aF-19.229461976581153 aF25.828947433523179 aF907.83851651473435 aF-6.5226624352274056 aF966.31430559772741 aF-31.261644297897224 aF-15.763682697269594 aF7.4337743999308259 aF1054.7064765026309 aF28.073531561104041 aF8.2529009925065235 aF-24.401260507710667 aF990.31828208353966 aF-16.941317689731754 aF1002.9542840643745 aF-0.20877765764089851 aF-28.685492670197856 aF28.051702686275132 aF10.279726273699406 aF-21.097934707750436 aF1112.6168482264152 aF17.92809104975856 aF16.895332074163214 aF998.83210342895165 aF33.72095713353616 aF-16.419105890554142 aF-2.0926743729112021 aF-9.9857304056984031 aF1010.3628621834437 aF0.23621362811159408 aF-8.4231733795926189 aF8.7295690899221849 aF25.892471008496319 aF-23.431441779738066 aF24.833173156257082 aF1020.6533198616248 aF26.164357763872164 aF958.78939823174119 aF-7.6422366645427982 aF-13.11394145360636 aF-2.6753300179342001 aF25.247458461348916 aF1039.2055829452127 aF-7.2872759774750611 aF7.0528882516125604 aF3.7080961723917261 aF973.79589640868289 aF-16.86881908205179 aF10.659872977309448 aF4.430660601918734 aF1037.1729140350162 aF29.89355938656152 aF-50.189857566834895 aF-5.9636923789074094 aF17.826068259796294 aF953.92372527061502 aF-2.0454784830086687 aF6.4625250006392605 aF989.64607184204749 aF-9.182833176252025 aF17.644501542694162 aF20.222933139883466 aF11.696837507359968 aF-6.0295871163723538 aF903.51849980515908 aF-0.8349072738825507 aF13.081763637251349 aF5.5823785824615308 aF2.7279389271868797 aF-4.2057616210887945 aF965.10829682890244 aF-14.716828140390311 aF-3.4227041275294057 aF19.081184392250034 aF31.602308063382814 aF-7.5721483503993117 aF954.06001071077765 aF17.958634708939744 aF-7.9726690157125155 aF4.264877245808858 aF-10.351933782805398 aF-22.447819727267706 aF-6.3797954849566114 aF8.5297158949405976 aF1109.990294416541 aF-42.898936696936097 aF3.0954216394606271 aF-11.300425546825728 aF919.10549497839702 aF33.591358147857235 aF935.56184410429842 aF2.4792243365005695 aF47.290613566030274 aF-24.723451850020865 aF18.189449295176459 aF-9.354433646338757 aF1009.176919166517 aF26.265855914888188 aF12.241139956354482 aF1007.5162553425275 aF-35.083016459819333 aF2.8223796343765208 aF24.30865232386504 aF940.49192387351047 aF26.765120022454042 aF-29.991980589880797 aF-6.5726652531282781 aF-35.138197763678562 aF898.02294601185963 aF-11.80030385171745 aF6.3959385613508735 aF5.2095056251171412 aF-11.267639136207618 aF8.9834269096049191 aF-15.601450911359493 aF12.002934352490424 aF1061.9088314574196 aF1021.5286307963414 aF974.27096227826451 aF29.231106974629462 aF-12.372457679181895 aF16.839782914040239 aF-10.784906960159148 aF1110.9133558869853 aF-5.2464051847499347 aF30.421024568712987 aF929.45612487422636 aF0.15988306104624417 aF-23.588118640476875 aF-16.733021339712685 aF1.2551095486065418 aF978.84550675877881 aF2.0201676799620762 aF-6.2871676715210647 aF13.741736823981698 aF-11.700604477132963 aF912.73065437846151 aF-34.706466001545323 aF30.381298303545133 aF1009.3731061378852 aF1008.3238318628544 aF-5.188124346961434 aF0.9410066436597293 aF13.664028186614686 aF31.955663189822026 aF36.298825292433868 aF35.176273581571088 aF-2.8977416727142895 aF963.93010211866283 aF-29.79958993383384 aF994.77502674420896 aF15.935386715699183 aF923.05426690660636 aF10.813258829419137 aF-5.0352645809704404 aF-33.739262545004195 aF9.2116967596217449 aF946.32432870467312 aF-8.5126420806973595 aF1081.0704440762224 aF-37.94791662819712 aF37.652164163556137 aF12.207073541807159 aF921.1930928641782 aF9.6812477407748254 aF-14.504560064472656 aF-4.4435393555856164 aF1079.7871664885888 aF-4.2068315640642764 aF-8.6579170353384622 aF987.87888532003547 aF-18.620256480458224 aF22.673599291714876 aF0.7976252139129526 aF19.045514512488833 aF-6.7236942771881969 aF1020.8978670132979 aF-15.665420619434165 aF945.76290267502304 aF1.5002038650554304 aF-12.140751228062987 aF-8.1605631695879008 aF36.38551674207541 aF954.2048524912725 aF18.096363537958595 aF6.0562064745208684 aF1068.2886355623439 aF3.7385075441161346 aF1043.5461446148433 aF27.167655521117048 aF-1.7205580132454539 aF1021.3718384285742 aF1.4106247755596306 aF-13.751870029269391 aF994.82426288387512 aF-12.597355438002541 aF-1.8773847569154434 aF-7.5209177992746694 aF-1.6775361606032031 aF3.5860267753881669 aF993.30830163951464 aF1023.7684322108034 aF7.3827281845142592 aF-6.2365289844226357 aF-19.581305627993292 aF21.894835215302475 aF982.303314742054 aF42.020832311455976 aF-14.223923349187423 aF15.473580458743308 aF0.89564973651898327 aF1012.4385069146476 aF-7.2487238491036035 aF1026.5110056674478 aF62.970107595120894 aF-32.575454655734426 aF-5.7355057597276309 aF13.588454572583924 aF7.8487505645684745 aF982.13309030362689 aF63.488587900901173 aF-37.193347878489483 aF979.96862484579469 aF990.17460576284623 aF6.3290285485479219 aF-31.241455279740322 aF14.860911033605705 aF1124.0924276728445 aF18.350218398281889 aF-28.656127294058741 aF968.25647178214444 aF49.613549770982445 aF-3.3406091757118856 aF1064.8492682682361 aF-5.8492167950322704 aF0.29639565205010271 aF-35.755746541632156 aF935.43814194014988 aF-30.387506374733036 aF5.6872214491917221 aF991.88747302311162 aF12.259443441354779 aF0.181752200689414 aF16.774813957070222 aF-71.796419982668723 aF41.56387470064346 aF-16.257927337035415 aF986.15091307304851 aF1115.3974609551856 aF1051.793615857719 aF25.486172028493307 aF-1.6049595921194972 aF1059.8939545017458 aF22.26305700865467 aF-0.73933252451773435 aF33.678645064785698 aF12.144505068647897 aF1014.2947204119002 aF-14.265739115479134 aF19.337207481655788 aF-8.6131796268442606 aF940.39212528740211 aF-29.596684220709747 aF1122.0343586091929 aF-14.356302062808773 aF21.163932957048655 aF1038.3909029991755 aF39.044908091569226 aF-11.630458257577232 aF-17.138505408734574 aF1040.082081491717 aF986.20675504822998 aF1073.0478251789652 aF-25.571873318266967 aF-25.733135530201718 aF1.1874720864945678 aF-20.316559061832148 aF-1.0994577450697369 aF-1.5295198320725041 aF1035.9342679890772 aF35.422212819916567 aF3.7260719482504827 aF22.090112190960102 aF29.924784730321939 aF1042.7415438674823 aF1117.4125977172403 aF27.991226802966825 aF53.299664091488509 aF-16.868980357007661 aF5.6904830265721369 aF25.065404373823458 aF-19.684108774384359 aF1038.6668477350022 aF27.74060789188448 aF11.729918308461404 aF1008.0403256317013 aF-7.198024472953171 aF11.550463076420227 aF904.53619512376258 aF31.259542543394222 aF19.522792433471572 aF-1.7081953140500363 aF26.361472695929937 aF42.169357609930557 aF36.954953151121451 aF1004.3887145255586 aF-3.0567176590418392 aF-28.932663385700138 aF2.8463172759176762 aF-41.480817393903472 aF-0.68495314097315418 aF21.208653848364019 aF19.876255515102429 aF998.12874980374295 aF1.3961086816912429 aF23.821668920901342 aF21.441174552653806 aF-44.665288201485076 aF12.633140606795406 aF988.38432905112916 aF18.71811669630037 aF24.913145241742193 aF4.8273734459764572 aF-21.359128252832029 aF1065.3762097654769 aF24.918183253589213 aF-27.897058417766164 aF12.561904979061016 aF1089.7539174243775 aF14.699878990740451 aF5.0699757690162865 aF-55.839834801834542 aF984.98626773133446 aF892.9497079083751 aF-22.650241838469928 aF-12.441283303937622 aF881.06274521697583 aF-9.399730594999296 aF31.227087359930721 aF2.4612959698168853 aF1053.8605901273861 aF-6.0066185359336677 aF11.865775216869102 aF40.152389574564538 aF869.1604587083126 aF959.64234290126842 aF44.706151674854247 aF3.4962543700800031 aF986.8188443638802 aF-10.502807678052365 aF-6.1711187034702828 aF-20.63589248183213 aF7.8996595892496178 aF1036.4526079439877 aF-37.585419309157089 aF1.8542119127221615 aF11.17639906818914 aF-13.310845893051535 aF49.80080106133682 aF22.217313576784736 aF-5.1966403433892667 aF1029.3305958673775 aF26.108870350830433 aF-2.2237912026804105 aF22.044642806617869 aF996.90680772704093 aF-0.61622767913287646 aF-14.016484663587772 aF954.02738078624384 aF28.518877124687648 aF-0.52675077970567385 aF989.09821783581117 aF-9.6785742503752914 aF-15.566186467510502 aF-4.1923485158047118 aF0.47988670677906098 aF20.338575090204959 aF995.46484752607512 aF3.2491500593837461 aF-14.090077037761237 aF890.6364469937937 aF20.468092222026829 aF26.222243827677108 aF952.93565485434056 aF-14.247537927605798 aF12.031538779218243 aF1075.0278864196378 aF-9.0683180187256625 aF-1.3173814606159042 aF20.351359463761465 aF-5.7249534947634393 aF20.95643328024418 aF1078.3569908140601 aF29.153198423325712 aF44.631955652940036 aF17.672876412345737 aF7.9498981094329411 aF-37.993369063165886 aF973.76818102942673 aF24.093330458313645 aF-21.383690393991195 aF942.32575201335362 aF43.917484208170215 aF1041.4431633288777 aF17.528531982715048 aF1097.1674463245085 aF6.1199204015642081 aF-39.180665949999771 aF38.463774914761672 aF-9.2703971202383144 aF985.15913015727836 aF2.9683966801746893 aF5.2893991353821059 aF-2.5889710667866952 aF31.124961594345585 aF930.66965419763653 aF-9.7478464098365709 aF17.546913210897511 aF880.63523601875465 aF-1.3146259309146979 aF12.689126566426291 aF994.38622297713937 aF-7.8134192093558745 aF-9.3952889452393329 aF26.651688979252885 aF13.453806672476007 aF928.41139317250713 aF-31.988649613129311 aF991.57609530813193 aF2.5393815526079515 aF-16.972908002764807 aF1.4846009214004348 aF-26.042299178951076 aF945.54557673218176 aF19.488128200930728 aF-1.849008087892962 aF5.51190192752148 aF-11.515577789711328 aF-9.5639555992494927 aF1094.9177538581603 aF8.1024844191992873 aF-25.855057493164132 aF-3.229587151702018 aF-1.0377722247306955 aF1033.8433841240162 aF2.890273219319742 aF-39.000392988349212 aF58.316975034515771 aF1027.122258371923 aF17.752403838655663 aF9.8199946666143685 aF1053.4288870389064 aF-5.40502329884493 aF21.007796646011563 aF2.150905627670832 aF969.2460169792904 aF56.045494254328204 aF1037.746950512076 aF0.24332250043871628 aF8.4542032980737787 aF-15.852582989449385 aF-31.093548106104357 aF845.25214591528243 aF18.822705535329607 aF1037.6688377619087 aF14.099455252562741 aF-11.92605334630179 aF-10.56113567926128 aF874.50805199618765 aF1.196678136954834 aF0.70470221711887693 aF-0.20806098944469181 aF1095.2559846523645 aF860.78536001686632 aF-12.797069836169143 aF-6.2274215684928294 aF985.36032569452755 aF1018.5176809725897 aF14.258103397746838 aF1142.8546968002693 aF24.576361342147866 aF1027.9333668285065 aF23.37255889290406 aF36.716482522820854 aF914.07006274048194 aF1069.982698286032 aF-24.58754150894681 aF-35.167338791626172 aF4.8587288213400228 aF1074.8431308260019 aF20.751120169182563 aF1056.7832693106482 aF-9.8124652020303191 aF1036.0045977289219 aF17.905178428610338 aF-13.048210549286546 aF884.72968635915527 aF15.399121995606359 aF35.895017097770577 aF-23.341495476676403 aF963.65890337824419 aF22.484448482758129 aF10.904932456284781 aF1001.8703297958077 aF-43.221184817162396 aF3.8710014167748614 aF34.457107600168627 aF1020.9619479343471 aF-23.129131179532354 aF1058.5907629595138 aF-13.3685670710124 aF-16.845929132808557 aF-12.161931765514332 aF1031.6664400398736 aF7.220741488892048 aF-17.933143005178746 aF941.05724984507799 aF-14.874306018602075 aF-14.591792091451611 aF1045.2438710868398 aF0.27301241405562382 aF26.333662896490534 aF5.7101051104655438 aF7.9745010847051745 aF973.48560626466599 aF-7.2155368654098302 aF980.93130564350122 aF3.3226128119453353 aF-26.134141028751909 aF-6.88979382182242 aF-21.570137984224818 aF949.18843783724299 aF2.9123065753508346 aF946.2190659424208 aF5.0246998616493821 aF1060.2297489473428 aF2.2579504344955397 aF36.431019185289209 aF39.163261277266919 aF0.29119685754385904 aF1130.4653674161852 aF41.263367726066292 aF961.92303817120467 aF4.2441858477579597 aF-21.721232874125565 aF962.81486162665954 aF33.090755972740929 aF-9.419895650959198 aF1072.3701007222294 aF-7.5446176173667325 aF24.367840463798203 aF-7.9482872551822537 aF-30.078032175900017 aF1058.590797698771 aF22.219462604678778 aF-3.1221810681913449 aF1030.2954465560813 aF973.44287898903872 aF19.070422894893159 aF-20.602423395747593 aF1052.6446075369067 aF-24.972376245461938 aF15.86630462956346 aF8.4119910789460643 aF-5.8166121590676125 aF992.34080681946023 aF-48.026914381512078 aF1102.50042272269 aF-40.974133403946382 aF-24.778237077313729 aF1119.3619835852157 aF1001.8715736102101 aF-22.424055041406888 aF1100.3127279430839 aF9.8551286851660649 aF1.5542250669072661 aF-1.6387055046079277 aF0.058188311049613639 aF-5.7970879163450055 aF926.53484785132218 aF10.937116140506209 aF961.80175491873672 aF4.0987684089706811 aF943.83622286389163 aF18.72811324906888 aF-23.334282235668393 aF919.90348509748162 aF-11.824265890167711 aF-16.024023045230184 aF-6.8172077271259317 aF42.581953551651942 aF868.04659905310757 aF8.8222034549754849 aF-14.802741048883513 aF1048.8008769723617 aF11.866490457418777 aF962.30668386268746 aF-10.798600875780245 aF0.049648873582764486 aF1164.6723608986147 aF948.08224712533661 aF-21.861378589742827 aF1022.5393005597326 aF27.391385725380363 aF34.987962527246275 aF947.60052859086602 aF12.20367669050575 aF10.134490427507579 aF1080.3929607252189 aF30.369547551456343 aF-31.042478397057547 aF890.06171429438177 aF-8.528837594248964 aF0.49299278460067036 aF-15.025645146000203 aF-5.2267993584695596 aF894.26347001313684 aF20.892000568179263 aF992.57451357195839 aF-4.6347168639342042 aF1078.3450181206704 aF1012.5901973092599 aF-23.794667180651647 aF-7.6153326612137331 aF8.4029780733473416 aF-17.396674871072385 aF34.063227713663309 aF1040.6216780137013 aF12.92394217124675 aF1.1176512938483714 aF997.57531107561965 aF10.956467531790262 aF1012.6047576585988 aF-14.115861508554012 aF1079.2460363014945 aF1.8388919522855594 aF984.25058468817645 aF35.284751721373318 aF1154.2438296290475 aF32.292059665412793 aF-12.51204320110017 aF1048.4143436956451 aF41.525824654444548 aF15.816075416153463 aF1038.3599067838497 aF-37.189056192851531 aF7.9524081361040162 aF1005.8286010408865 aF-24.021984764595079 aF3.0284471123144368 aF982.31115518576803 aF-20.223385367054817 aF986.62025061368115 aF-35.363607813007349 aF1043.4879215084611 aF-11.001392841554651 aF937.99393396710968 aF13.102924948310127 aF23.996638111433885 aF-11.453656280105179 aF9.612866110733675 aF1053.8512892805804 aF-38.569530052983552 aF-2.8506035976923503 aF51.167696065134137 aF-15.262377715627675 aF1024.0504723597667 aF-9.7126020168417355 aF7.5396868035090678 aF19.757287237002707 aF969.10047352986612 aF-22.519440649244434 aF1008.639534783092 aF-13.656048137721186 aF17.52161899914616 aF1012.6602643199868 aF14.170828278223663 aF1067.6727006394742 aF-55.08763015568703 aF5.7816666740873996 aF7.7956599752965126 aF1028.116423646366 aF1016.6730692943916 aF1035.5641382640888 aF1031.5770300131906 aF902.9755036007233 aF-1.6266503890861388 aF34.828424513659414 aF-5.1322544201335329 aF22.298025788808712 aF944.90613724033199 aF1083.066953429895 aF-37.145935482450305 aF914.83968021758108 aF13.450714635283198 aF1085.150628757217 aF1064.6913348870519 aF1.4845313668293347 aF28.699482151607306 aF962.77695606781299 aF21.606881063496761 aF31.900194025609075 aF968.3873931216566 aF-14.581533717781955 aF990.63754331208384 aF949.32033881652762 aF-10.164453921095163 aF927.78881334431424 aF-34.879023681702066 aF-42.411340964874896 aF1015.0254286716503 aF-17.51391259196031 aF-1.192211149272236 aF910.60996636908112 aF-41.119147920753122 aF997.94539888372083 aF5.2030150807425128 aF-12.364252341458542 aF1057.8320736368826 aF-11.385501356635903 aF-3.4371146477551435 aF-26.183440640331504 aF-11.207579747827953 aF964.85387844413162 aF-15.750916769393649 aF12.86135575095007 aF987.99364283168984 aF-9.1887750696343726 aF-68.361901712757955 aF1000.5306627855193 aF961.16810507729178 aF1015.8794408458266 aF-48.165554189084503 aF1004.5613771108118 aF30.245288304632414 aF-11.848015635387574 aF1131.7841986312073 aF950.6151615140991 aF-39.187096352484502 aF919.85797568755595 aF-16.370606082533385 aF-11.023760543202551 aF930.31457724392965 aF-20.223865960920197 aF998.72932245736808 aF-23.643069651849167 aF-52.032647345224525 aF-18.621798467787276 aF864.24780043477608 aF40.648586362092338 aF12.485635719738591 aF952.23439650522516 aF-7.371859311419855 aF995.18363948349895 aF-13.254059968734097 aF14.337265201938701 aF-3.3261839967506139 aF16.211839828317693 aF1074.139174661495 aF-10.087982425771164 aF904.48930096073479 aF9.0842068994247516 aF-0.4220891199209208 aF946.92140709184116 aF-27.378548896563728 aF3.814940602605347 aF5.3956601271397435 aF940.23063254604722 aF-15.922400477895781 aF6.274879494548907 aF974.41202259981242 aF14.363341858558419 aF-23.51470777818486 aF-22.367266066999168 aF951.53245999452179 aF1056.8821961344183 aF974.2797783339729 aF5.0956087710680453 aF973.1342393195049 aF-0.48487549782106809 aF5.3911196018824006 aF35.40333353489487 aF1011.7838219109634 aF-21.303413004827721 aF939.32748124646128 aF9.5240512336702583 aF0.36220236398636069 aF1050.4081052988722 aF42.507341543793771 aF1055.8226636867626 aF-15.315517028556171 aF-16.967342302016135 aF-6.5409236400023083 aF-28.404566524894278 aF41.336057845888099 aF909.51985771002228 aF-20.464344284853819 aF7.5154546862177085 aF929.47379834671563 aF966.89872590184143 aF1043.8363313205539 aF967.74388162008802 aF943.55151897067867 aF1013.35891218988 aF-48.289777667663273 aF1013.4766696460173 aF-8.3019251704998034 aF933.02130189564059 aF979.82454256921528 aF10.826500158875172 aF22.23609977106408 aF-9.9065238589767102 aF895.42629386976046 aF1033.7650085054131 aF-26.419340364393445 aF-2.8419668453944009 aF1045.3304269590642 aF1037.5565575658654 aF26.958064399787073 aF917.55386570862493 aF-1.9728745470291336 aF1069.0994429015495 aF-28.893692649280052 aF-22.473997814268785 aF1026.9972040539328 aF6.2716951855902057 aF1013.7031728491301 aF-19.135459133406375 aF-13.405773291252935 aF1024.747144283941 aF31.239715856179213 aF-2.2878756503907827 aF1063.5916560044479 aF994.00118061524631 aF1085.0476371930081 aF1018.9346955919999 aF981.02630476923832 aF-12.315961623885986 aF1033.3195592051256 aF-19.884832176672305 aF1086.3422997247997 aF1089.948013267651 aF-13.820654131725412 aF1010.0176711914314 aF1134.0133980707567 aF-48.292789736819884 aF1039.5433667005323 aF-6.0658259213090426 aF35.599445050683187 aF893.95788310940941 aF912.97805803559447 aF27.184908324890884 aF1024.9079250586999 aF1.472525225721192 aF1005.4274975899647 aF17.484545693171139 aF925.78394689545382 aF-34.416632014764573 aF965.53055305106489 aF914.19651933299031 aF28.735865458125126 aF1031.8596967361379 aF25.813138890047036 aF24.563692965820579 aF1055.1906070264945 aF1086.5947819427661 aF13.468114187807418 aF-12.813392736986273 aF1056.1012294652878 aF-26.752094420026225 aF1027.9653495103669 aF7.5200870390244505 aF1022.887871087179 aF984.73350227425601 aF3.2119742965560669 aF978.67299769512749 aF-33.196767950035316 aF1014.1868246033498 aF1057.2764997292174 aF-15.216392866795037 aF998.6369174062296 aF954.90106260473101 aF1078.9809922782297 aF991.60916989484087 aF980.139645841723 aF1020.2784569576114 aF-5.7754331748898489 aF2.0404211376002506 aF-8.2752009625003176 aF934.21201651093918 aF1019.147716604636 aF1034.7989964933827 aF1.1638870936243366 aF-23.449642607352398 aF1092.635886078124 aF1005.0625569318283 aF1083.803931047164 aF984.36707052852069 aF1057.3355470860913 aF929.76356924498668 aF21.396148357435539 aF1052.943770437791 aF1043.3610400096018 aF1019.5749436920019 aF959.5331478112048 aF930.41539085051556 aF1032.6286330130063 aF4.9165441773389817 aF1024.1518881303691 aF1107.6072629997207 aF971.39933430058716 aF1007.6514067614387 aF22.692355989800468 aF1097.1836298545143 aF1008.1598110487311 aF1005.1692930610582 aF1038.5089238765574 aF949.68407053315957 aF1043.2951673187827 aF1004.8650127406853 aF24.578040280957357 aF977.34335829467489 aF5.1942821518718931 aF936.90665990233072 aF-32.9237508225727 aF951.24434240502751 aF12.976620825879872 aF1019.9827337001312 aF1.2256141352438643 aF1001.6049118767753 aF971.0729403287537 aF957.72738871108663 aF975.52626578186107 aF998.89766790206545 aF973.56130719300143 aF952.69278806347302 aF949.7715416137188 aF974.28989659037643 aF898.4280248875865 aF949.09480919694738 aF1022.6988429363347 aF948.35892041370619 aF973.04990543830502 aF-0.28996713733898249 aF977.07780990786443 aF5.1628957467225183 aF-16.201618129462801 aF1011.9107287308251 aF1026.9203268242227 aF918.24347258308478 aF1217.0982332180433 aF1011.7445525360112 aF961.72715842890295 aF925.73220480416978 aF1001.7653601153918 aF950.75346555742806 aF1039.0521363974576 aF960.7958892640188 aF1084.7239842867043 a(I1741 I1 tp3 S'd' p4 tp5 Rp6 g1 ((lp7 I0 aI22 aI47 aI120 aI255 aI348 aI357 aI485 aI1 aI34 aI39 aI83 aI2 aI329 aI360 aI395 aI3 aI8 aI23 aI59 aI257 aI338 aI412 aI4 aI88 aI227 aI244 aI310 aI341 aI365 aI432 aI463 aI469 aI5 aI389 aI398 aI399 aI491 aI6 aI7 aI126 aI346 aI347 aI363 aI439 aI7 aI107 aI257 aI296 aI322 aI8 aI11 aI20 aI23 aI158 aI187 aI215 aI317 aI352 aI464 aI489 aI9 aI488 aI10 aI48 aI119 aI145 aI343 aI347 aI357 aI422 aI11 aI97 aI196 aI314 aI380 aI458 aI465 aI12 aI40 aI239 aI261 aI274 aI13 aI100 aI191 aI14 aI78 aI92 aI124 aI143 aI197 aI226 aI234 aI241 aI282 aI479 aI492 aI15 aI217 aI436 aI16 aI55 aI87 aI344 aI428 aI479 aI17 aI266 aI355 aI429 aI18 aI289 aI294 aI296 aI424 aI19 aI28 aI110 aI256 aI381 aI396 aI20 aI103 aI166 aI349 aI425 aI445 aI21 aI24 aI77 aI321 aI395 aI399 aI22 aI42 aI181 aI193 aI245 aI311 aI369 aI415 aI468 aI489 aI23 aI32 aI134 aI333 aI350 aI465 aI24 aI190 aI343 aI399 aI25 aI240 aI298 aI336 aI26 aI87 aI199 aI202 aI236 aI246 aI316 aI27 aI47 aI122 aI174 aI235 aI262 aI344 aI440 aI28 aI137 aI476 aI29 aI45 aI387 aI477 aI487 aI30 aI44 aI31 aI124 aI190 aI274 aI299 aI399 aI32 aI451 aI494 aI33 aI108 aI224 aI346 aI366 aI415 aI460 aI486 aI34 aI43 aI121 aI122 aI336 aI427 aI35 aI143 aI160 aI165 aI207 aI225 aI296 aI488 aI36 aI202 aI37 aI202 aI388 aI414 aI38 aI49 aI276 aI399 aI39 aI57 aI110 aI142 aI162 aI182 aI442 aI40 aI50 aI94 aI201 aI399 aI407 aI41 aI68 aI122 aI188 aI215 aI42 aI61 aI152 aI171 aI386 aI466 aI499 aI43 aI59 aI72 aI302 aI44 aI116 aI121 aI131 aI132 aI169 aI307 aI366 aI478 aI484 aI45 aI327 aI390 aI46 aI66 aI259 aI296 aI344 aI370 aI413 aI47 aI282 aI296 aI339 aI374 aI440 aI48 aI78 aI113 aI186 aI216 aI400 aI407 aI489 aI492 aI49 aI395 aI470 aI492 aI50 aI75 aI144 aI196 aI217 aI239 aI276 aI496 aI51 aI174 aI252 aI258 aI411 aI52 aI53 aI151 aI154 aI53 aI102 aI177 aI274 aI423 aI54 aI66 aI107 aI155 aI250 aI314 aI335 aI55 aI344 aI421 aI461 aI56 aI65 aI271 aI279 aI362 aI406 aI478 aI57 aI125 aI403 aI406 aI58 aI274 aI375 aI59 aI183 aI316 aI415 aI442 aI459 aI463 aI60 aI315 aI450 aI61 aI160 aI176 aI193 aI196 aI303 aI378 aI385 aI400 aI430 aI435 aI465 aI495 aI62 aI142 aI196 aI228 aI264 aI274 aI471 aI63 aI276 aI319 aI378 aI64 aI92 aI108 aI152 aI159 aI254 aI267 aI277 aI308 aI439 aI446 aI65 aI212 aI313 aI344 aI389 aI432 aI66 aI153 aI372 aI399 aI420 aI440 aI67 aI130 aI355 aI68 aI250 aI282 aI306 aI414 aI69 aI132 aI301 aI340 aI70 aI73 aI151 aI434 aI497 aI71 aI156 aI269 aI319 aI352 aI443 aI494 aI72 aI221 aI295 aI73 aI226 aI299 aI302 aI307 aI376 aI396 aI427 aI477 aI74 aI119 aI476 aI75 aI261 aI285 aI338 aI346 aI456 aI76 aI123 aI154 aI239 aI276 aI281 aI487 aI494 aI77 aI114 aI147 aI407 aI78 aI390 aI79 aI287 aI346 aI378 aI447 aI495 aI80 aI85 aI216 aI218 aI256 aI81 aI247 aI445 aI474 aI82 aI370 aI430 aI453 aI83 aI289 aI331 aI361 aI378 aI84 aI288 aI352 aI85 aI282 aI367 aI450 aI86 aI110 aI135 aI160 aI376 aI383 aI489 aI493 aI87 aI212 aI313 aI416 aI425 aI481 aI88 aI154 aI207 aI352 aI485 aI89 aI180 aI339 aI457 aI90 aI152 aI173 aI182 aI273 aI295 aI364 aI373 aI387 aI474 aI91 aI134 aI164 aI92 aI129 aI220 aI221 aI242 aI287 aI431 aI93 aI155 aI306 aI310 aI350 aI376 aI498 aI94 aI475 aI95 aI118 aI133 aI165 aI203 aI360 aI414 aI96 aI181 aI97 aI205 aI290 aI98 aI112 aI139 aI188 aI294 aI301 aI379 aI486 aI99 aI149 aI376 aI397 aI100 aI298 aI389 aI402 aI101 aI420 aI102 aI164 aI360 aI103 aI156 aI368 aI473 aI104 aI107 aI116 aI263 aI326 aI477 aI105 aI270 aI493 aI106 aI174 aI107 aI110 aI124 aI304 aI369 aI108 aI210 aI283 aI314 aI322 aI109 aI163 aI288 aI405 aI480 aI110 aI139 aI176 aI212 aI369 aI111 aI134 aI230 aI239 aI305 aI309 aI459 aI112 aI155 aI309 aI383 aI443 aI113 aI160 aI114 aI176 aI189 aI393 aI423 aI115 aI204 aI205 aI208 aI336 aI116 aI298 aI357 aI395 aI117 aI137 aI484 aI118 aI122 aI141 aI161 aI280 aI433 aI119 aI177 aI230 aI315 aI343 aI498 aI120 aI136 aI242 aI484 aI121 aI151 aI290 aI122 aI151 aI397 aI482 aI123 aI127 aI318 aI353 aI379 aI458 aI124 aI458 aI125 aI281 aI301 aI314 aI386 aI434 aI479 aI126 aI216 aI238 aI284 aI298 aI301 aI326 aI372 aI381 aI496 aI127 aI128 aI219 aI231 aI464 aI129 aI274 aI349 aI130 aI327 aI466 aI131 aI141 aI162 aI215 aI341 aI462 aI132 aI202 aI243 aI256 aI326 aI339 aI133 aI327 aI419 aI425 aI134 aI280 aI296 aI358 aI477 aI135 aI147 aI324 aI136 aI172 aI197 aI262 aI289 aI352 aI433 aI137 aI176 aI245 aI412 aI413 aI138 aI286 aI490 aI139 aI274 aI301 aI312 aI370 aI380 aI416 aI140 aI285 aI395 aI420 aI467 aI141 aI253 aI271 aI374 aI142 aI177 aI199 aI338 aI143 aI144 aI215 aI268 aI314 aI352 aI491 aI144 aI240 aI259 aI145 aI187 aI354 aI439 aI146 aI262 aI409 aI147 aI188 aI434 aI148 aI375 aI404 aI411 aI443 aI149 aI198 aI284 aI494 aI150 aI274 aI151 aI227 aI322 aI354 aI152 aI329 aI470 aI473 aI153 aI491 aI154 aI173 aI263 aI276 aI396 aI455 aI155 aI295 aI371 aI156 aI255 aI310 aI448 aI477 aI157 aI274 aI301 aI413 aI423 aI444 aI457 aI158 aI370 aI159 aI188 aI228 aI277 aI339 aI160 aI220 aI283 aI310 aI161 aI276 aI299 aI444 aI162 aI213 aI244 aI305 aI347 aI163 aI355 aI464 aI164 aI165 aI210 aI218 aI357 aI456 aI165 aI228 aI324 aI326 aI328 aI414 aI166 aI188 aI216 aI265 aI409 aI422 aI167 aI210 aI211 aI253 aI349 aI352 aI368 aI444 aI168 aI172 aI439 aI479 aI169 aI491 aI170 aI283 aI329 aI394 aI417 aI465 aI171 aI228 aI376 aI172 aI255 aI277 aI302 aI173 aI203 aI243 aI290 aI472 aI174 aI236 aI319 aI324 aI367 aI423 aI435 aI496 aI175 aI176 aI177 aI268 aI318 aI329 aI337 aI178 aI319 aI386 aI179 aI200 aI241 aI481 aI485 aI180 aI244 aI291 aI315 aI448 aI181 aI212 aI375 aI182 aI183 aI204 aI288 aI303 aI386 aI416 aI464 aI469 aI184 aI478 aI185 aI321 aI186 aI271 aI368 aI386 aI396 aI187 aI429 aI188 aI231 aI292 aI416 aI189 aI281 aI454 aI486 aI190 aI202 aI343 aI191 aI205 aI446 aI471 aI474 aI484 aI192 aI469 aI193 aI239 aI284 aI334 aI387 aI194 aI265 aI438 aI195 aI435 aI196 aI337 aI442 aI197 aI381 aI450 aI198 aI210 aI407 aI421 aI427 aI443 aI199 aI200 aI201 aI211 aI220 aI230 aI201 aI244 aI310 aI361 aI478 aI202 aI220 aI203 aI244 aI370 aI441 aI468 aI471 aI204 aI207 aI383 aI205 aI206 aI304 aI453 aI486 aI207 aI228 aI269 aI208 aI296 aI421 aI209 aI228 aI286 aI380 aI210 aI317 aI370 aI211 aI243 aI251 aI289 aI339 aI361 aI415 aI212 aI213 aI214 aI348 aI498 aI215 aI328 aI352 aI357 aI421 aI216 aI232 aI240 aI488 aI217 aI381 aI218 aI228 aI274 aI219 aI345 aI372 aI490 aI220 aI221 aI222 aI249 aI266 aI331 aI364 aI474 aI479 aI223 aI239 aI312 aI315 aI369 aI224 aI225 aI308 aI313 aI347 aI403 aI421 aI469 aI226 aI267 aI294 aI227 aI341 aI379 aI228 aI235 aI237 aI360 aI413 aI475 aI494 aI229 aI257 aI277 aI291 aI361 aI389 aI455 aI477 aI230 aI311 aI355 aI376 aI380 aI471 aI231 aI358 aI453 aI471 aI478 aI232 aI261 aI467 aI496 aI233 aI308 aI392 aI428 aI234 aI235 aI388 aI463 aI236 aI331 aI468 aI471 aI237 aI257 aI271 aI317 aI238 aI239 aI300 aI374 aI240 aI328 aI330 aI395 aI423 aI241 aI256 aI264 aI266 aI353 aI358 aI393 aI488 aI242 aI244 aI251 aI423 aI243 aI351 aI459 aI244 aI264 aI468 aI245 aI327 aI341 aI372 aI376 aI379 aI246 aI276 aI287 aI247 aI329 aI493 aI248 aI313 aI442 aI249 aI269 aI294 aI325 aI326 aI370 aI250 aI258 aI264 aI320 aI403 aI460 aI251 aI390 aI486 aI252 aI451 aI253 aI390 aI254 aI293 aI339 aI357 aI491 aI255 aI402 aI423 aI466 aI489 aI256 aI330 aI392 aI257 aI304 aI324 aI258 aI320 aI438 aI464 aI488 aI259 aI409 aI260 aI302 aI388 aI407 aI421 aI261 aI394 aI400 aI424 aI455 aI479 aI262 aI285 aI330 aI402 aI452 aI263 aI347 aI441 aI498 aI264 aI443 aI458 aI265 aI342 aI488 aI490 aI266 aI280 aI267 aI274 aI321 aI357 aI460 aI268 aI372 aI269 aI320 aI356 aI378 aI270 aI421 aI453 aI492 aI271 aI272 aI314 aI397 aI273 aI274 aI317 aI275 aI356 aI276 aI400 aI469 aI277 aI278 aI287 aI409 aI483 aI279 aI409 aI280 aI405 aI281 aI390 aI447 aI282 aI303 aI379 aI484 aI283 aI303 aI427 aI284 aI335 aI372 aI444 aI285 aI455 aI286 aI322 aI400 aI450 aI287 aI361 aI391 aI288 aI292 aI373 aI289 aI349 aI357 aI368 aI450 aI290 aI374 aI291 aI351 aI388 aI479 aI480 aI292 aI382 aI293 aI353 aI294 aI295 aI420 aI469 aI493 aI295 aI359 aI296 aI313 aI490 aI297 aI315 aI397 aI298 aI410 aI426 aI429 aI437 aI299 aI424 aI439 aI300 aI301 aI321 aI385 aI302 aI363 aI373 aI471 aI496 aI303 aI388 aI304 aI336 aI443 aI305 aI306 aI405 aI307 aI309 aI381 aI407 aI446 aI494 aI308 aI441 aI309 aI498 aI310 aI322 aI379 aI311 aI330 aI333 aI398 aI496 aI312 aI469 aI474 aI313 aI349 aI314 aI349 aI410 aI315 aI316 aI492 aI317 aI344 aI476 aI318 aI467 aI481 aI319 aI377 aI448 aI320 aI382 aI447 aI449 aI480 aI321 aI465 aI322 aI405 aI323 aI324 aI336 aI345 aI404 aI405 aI428 aI325 aI332 aI417 aI326 aI334 aI327 aI434 aI328 aI399 aI329 aI330 aI330 aI368 aI409 aI331 aI458 aI467 aI332 aI364 aI478 aI333 aI369 aI489 aI334 aI494 aI335 aI464 aI336 aI393 aI337 aI368 aI441 aI461 aI481 aI338 aI398 aI406 aI459 aI465 aI339 aI355 aI385 aI434 aI340 aI457 aI341 aI361 aI478 aI342 aI453 aI343 aI407 aI449 aI495 aI344 aI345 aI346 aI347 aI348 aI351 aI364 aI471 aI485 aI349 aI350 aI359 aI351 aI449 aI352 aI353 aI358 aI370 aI354 aI395 aI489 aI355 aI382 aI356 aI357 aI360 aI358 aI424 aI472 aI359 aI375 aI399 aI360 aI412 aI361 aI384 aI439 aI362 aI434 aI441 aI458 aI469 aI363 aI374 aI421 aI364 aI432 aI462 aI365 aI366 aI367 aI487 aI368 aI415 aI434 aI369 aI370 aI422 aI371 aI399 aI475 aI372 aI487 aI373 aI432 aI444 aI493 aI374 aI383 aI413 aI375 aI396 aI376 aI418 aI432 aI449 aI451 aI377 aI381 aI378 aI380 aI478 aI379 aI402 aI417 aI418 aI380 aI441 aI458 aI381 aI384 aI410 aI464 aI382 aI383 aI384 aI445 aI385 aI388 aI406 aI430 aI386 aI460 aI387 aI463 aI496 aI388 aI392 aI389 aI414 aI415 aI421 aI448 aI496 aI390 aI413 aI438 aI391 aI392 aI393 aI394 aI395 aI396 aI461 aI397 aI417 aI398 aI399 aI442 aI467 aI485 aI400 aI401 aI417 aI479 aI402 aI403 aI444 aI404 aI468 aI405 aI430 aI471 aI406 aI414 aI407 aI469 aI483 aI408 aI423 aI496 aI409 aI410 aI411 aI412 aI413 aI442 aI414 aI424 aI415 aI416 aI424 aI417 aI418 aI430 aI419 aI464 aI478 aI420 aI421 aI480 aI422 aI472 aI423 aI437 aI424 aI492 aI425 aI426 aI457 aI427 aI476 aI484 aI428 aI429 aI446 aI488 aI430 aI474 aI431 aI496 aI432 aI433 aI466 aI434 aI460 aI435 aI436 aI461 aI437 aI438 aI439 aI440 aI441 aI442 aI465 aI466 aI491 aI443 aI444 aI445 aI449 aI451 aI446 aI447 aI448 aI449 aI450 aI451 aI497 aI452 aI453 aI454 aI455 aI456 aI457 aI470 aI458 aI459 aI460 aI461 aI486 aI462 aI463 aI464 aI465 aI466 aI467 aI468 aI489 aI469 aI475 aI470 aI486 aI471 aI478 aI472 aI477 aI473 aI474 aI475 aI476 aI477 aI478 aI479 aI480 aI481 aI482 aI483 aI484 aI485 aI486 aI493 aI487 aI488 aI497 aI488 aI489 aI490 aI491 aI492 aI493 aI494 aI495 aI496 aI497 aI498 aI499 a(I1741 I1 tp8 S'i' p9 tp10 Rp11 g1 ((lp12 I0 aI0 aI0 aI0 aI0 aI0 aI0 aI0 aI1 aI1 aI1 aI1 aI2 aI2 aI2 aI2 aI3 aI3 aI3 aI3 aI3 aI3 aI3 aI4 aI4 aI4 aI4 aI4 aI4 aI4 aI4 aI4 aI4 aI5 aI5 aI5 aI5 aI5 aI6 aI6 aI6 aI6 aI6 aI6 aI6 aI7 aI7 aI7 aI7 aI7 aI8 aI8 aI8 aI8 aI8 aI8 aI8 aI8 aI8 aI8 aI8 aI9 aI9 aI10 aI10 aI10 aI10 aI10 aI10 aI10 aI10 aI11 aI11 aI11 aI11 aI11 aI11 aI11 aI12 aI12 aI12 aI12 aI12 aI13 aI13 aI13 aI14 aI14 aI14 aI14 aI14 aI14 aI14 aI14 aI14 aI14 aI14 aI14 aI15 aI15 aI15 aI16 aI16 aI16 aI16 aI16 aI16 aI17 aI17 aI17 aI17 aI18 aI18 aI18 aI18 aI18 aI19 aI19 aI19 aI19 aI19 aI19 aI20 aI20 aI20 aI20 aI20 aI20 aI21 aI21 aI21 aI21 aI21 aI21 aI22 aI22 aI22 aI22 aI22 aI22 aI22 aI22 aI22 aI22 aI23 aI23 aI23 aI23 aI23 aI23 aI24 aI24 aI24 aI24 aI25 aI25 aI25 aI25 aI26 aI26 aI26 aI26 aI26 aI26 aI26 aI27 aI27 aI27 aI27 aI27 aI27 aI27 aI27 aI28 aI28 aI28 aI29 aI29 aI29 aI29 aI29 aI30 aI30 aI31 aI31 aI31 aI31 aI31 aI31 aI32 aI32 aI32 aI33 aI33 aI33 aI33 aI33 aI33 aI33 aI33 aI34 aI34 aI34 aI34 aI34 aI34 aI35 aI35 aI35 aI35 aI35 aI35 aI35 aI35 aI36 aI36 aI37 aI37 aI37 aI37 aI38 aI38 aI38 aI38 aI39 aI39 aI39 aI39 aI39 aI39 aI39 aI40 aI40 aI40 aI40 aI40 aI40 aI41 aI41 aI41 aI41 aI41 aI42 aI42 aI42 aI42 aI42 aI42 aI42 aI43 aI43 aI43 aI43 aI44 aI44 aI44 aI44 aI44 aI44 aI44 aI44 aI44 aI44 aI45 aI45 aI45 aI46 aI46 aI46 aI46 aI46 aI46 aI46 aI47 aI47 aI47 aI47 aI47 aI47 aI48 aI48 aI48 aI48 aI48 aI48 aI48 aI48 aI48 aI49 aI49 aI49 aI49 aI50 aI50 aI50 aI50 aI50 aI50 aI50 aI50 aI51 aI51 aI51 aI51 aI51 aI52 aI52 aI52 aI52 aI53 aI53 aI53 aI53 aI53 aI54 aI54 aI54 aI54 aI54 aI54 aI54 aI55 aI55 aI55 aI55 aI56 aI56 aI56 aI56 aI56 aI56 aI56 aI57 aI57 aI57 aI57 aI58 aI58 aI58 aI59 aI59 aI59 aI59 aI59 aI59 aI59 aI60 aI60 aI60 aI61 aI61 aI61 aI61 aI61 aI61 aI61 aI61 aI61 aI61 aI61 aI61 aI61 aI62 aI62 aI62 aI62 aI62 aI62 aI62 aI63 aI63 aI63 aI63 aI64 aI64 aI64 aI64 aI64 aI64 aI64 aI64 aI64 aI64 aI64 aI65 aI65 aI65 aI65 aI65 aI65 aI66 aI66 aI66 aI66 aI66 aI66 aI67 aI67 aI67 aI68 aI68 aI68 aI68 aI68 aI69 aI69 aI69 aI69 aI70 aI70 aI70 aI70 aI70 aI71 aI71 aI71 aI71 aI71 aI71 aI71 aI72 aI72 aI72 aI73 aI73 aI73 aI73 aI73 aI73 aI73 aI73 aI73 aI74 aI74 aI74 aI75 aI75 aI75 aI75 aI75 aI75 aI76 aI76 aI76 aI76 aI76 aI76 aI76 aI76 aI77 aI77 aI77 aI77 aI78 aI78 aI79 aI79 aI79 aI79 aI79 aI79 aI80 aI80 aI80 aI80 aI80 aI81 aI81 aI81 aI81 aI82 aI82 aI82 aI82 aI83 aI83 aI83 aI83 aI83 aI84 aI84 aI84 aI85 aI85 aI85 aI85 aI86 aI86 aI86 aI86 aI86 aI86 aI86 aI86 aI87 aI87 aI87 aI87 aI87 aI87 aI88 aI88 aI88 aI88 aI88 aI89 aI89 aI89 aI89 aI90 aI90 aI90 aI90 aI90 aI90 aI90 aI90 aI90 aI90 aI91 aI91 aI91 aI92 aI92 aI92 aI92 aI92 aI92 aI92 aI93 aI93 aI93 aI93 aI93 aI93 aI93 aI94 aI94 aI95 aI95 aI95 aI95 aI95 aI95 aI95 aI96 aI96 aI97 aI97 aI97 aI98 aI98 aI98 aI98 aI98 aI98 aI98 aI98 aI99 aI99 aI99 aI99 aI100 aI100 aI100 aI100 aI101 aI101 aI102 aI102 aI102 aI103 aI103 aI103 aI103 aI104 aI104 aI104 aI104 aI104 aI104 aI105 aI105 aI105 aI106 aI106 aI107 aI107 aI107 aI107 aI107 aI108 aI108 aI108 aI108 aI108 aI109 aI109 aI109 aI109 aI109 aI110 aI110 aI110 aI110 aI110 aI111 aI111 aI111 aI111 aI111 aI111 aI111 aI112 aI112 aI112 aI112 aI112 aI113 aI113 aI114 aI114 aI114 aI114 aI114 aI115 aI115 aI115 aI115 aI115 aI116 aI116 aI116 aI116 aI117 aI117 aI117 aI118 aI118 aI118 aI118 aI118 aI118 aI119 aI119 aI119 aI119 aI119 aI119 aI120 aI120 aI120 aI120 aI121 aI121 aI121 aI122 aI122 aI122 aI122 aI123 aI123 aI123 aI123 aI123 aI123 aI124 aI124 aI125 aI125 aI125 aI125 aI125 aI125 aI125 aI126 aI126 aI126 aI126 aI126 aI126 aI126 aI126 aI126 aI126 aI127 aI128 aI128 aI128 aI128 aI129 aI129 aI129 aI130 aI130 aI130 aI131 aI131 aI131 aI131 aI131 aI131 aI132 aI132 aI132 aI132 aI132 aI132 aI133 aI133 aI133 aI133 aI134 aI134 aI134 aI134 aI134 aI135 aI135 aI135 aI136 aI136 aI136 aI136 aI136 aI136 aI136 aI137 aI137 aI137 aI137 aI137 aI138 aI138 aI138 aI139 aI139 aI139 aI139 aI139 aI139 aI139 aI140 aI140 aI140 aI140 aI140 aI141 aI141 aI141 aI141 aI142 aI142 aI142 aI142 aI143 aI143 aI143 aI143 aI143 aI143 aI143 aI144 aI144 aI144 aI145 aI145 aI145 aI145 aI146 aI146 aI146 aI147 aI147 aI147 aI148 aI148 aI148 aI148 aI148 aI149 aI149 aI149 aI149 aI150 aI150 aI151 aI151 aI151 aI151 aI152 aI152 aI152 aI152 aI153 aI153 aI154 aI154 aI154 aI154 aI154 aI154 aI155 aI155 aI155 aI156 aI156 aI156 aI156 aI156 aI157 aI157 aI157 aI157 aI157 aI157 aI157 aI158 aI158 aI159 aI159 aI159 aI159 aI159 aI160 aI160 aI160 aI160 aI161 aI161 aI161 aI161 aI162 aI162 aI162 aI162 aI162 aI163 aI163 aI163 aI164 aI164 aI164 aI164 aI164 aI164 aI165 aI165 aI165 aI165 aI165 aI165 aI166 aI166 aI166 aI166 aI166 aI166 aI167 aI167 aI167 aI167 aI167 aI167 aI167 aI167 aI168 aI168 aI168 aI168 aI169 aI169 aI170 aI170 aI170 aI170 aI170 aI170 aI171 aI171 aI171 aI172 aI172 aI172 aI172 aI173 aI173 aI173 aI173 aI173 aI174 aI174 aI174 aI174 aI174 aI174 aI174 aI174 aI175 aI176 aI177 aI177 aI177 aI177 aI177 aI178 aI178 aI178 aI179 aI179 aI179 aI179 aI179 aI180 aI180 aI180 aI180 aI180 aI181 aI181 aI181 aI182 aI183 aI183 aI183 aI183 aI183 aI183 aI183 aI183 aI184 aI184 aI185 aI185 aI186 aI186 aI186 aI186 aI186 aI187 aI187 aI188 aI188 aI188 aI188 aI189 aI189 aI189 aI189 aI190 aI190 aI190 aI191 aI191 aI191 aI191 aI191 aI191 aI192 aI192 aI193 aI193 aI193 aI193 aI193 aI194 aI194 aI194 aI195 aI195 aI196 aI196 aI196 aI197 aI197 aI197 aI198 aI198 aI198 aI198 aI198 aI198 aI199 aI200 aI200 aI200 aI200 aI200 aI201 aI201 aI201 aI201 aI201 aI202 aI202 aI203 aI203 aI203 aI203 aI203 aI203 aI204 aI204 aI204 aI205 aI206 aI206 aI206 aI206 aI207 aI207 aI207 aI208 aI208 aI208 aI209 aI209 aI209 aI209 aI210 aI210 aI210 aI211 aI211 aI211 aI211 aI211 aI211 aI211 aI212 aI213 aI214 aI214 aI214 aI215 aI215 aI215 aI215 aI215 aI216 aI216 aI216 aI216 aI217 aI217 aI218 aI218 aI218 aI219 aI219 aI219 aI219 aI220 aI221 aI222 aI222 aI222 aI222 aI222 aI222 aI222 aI223 aI223 aI223 aI223 aI223 aI224 aI225 aI225 aI225 aI225 aI225 aI225 aI225 aI226 aI226 aI226 aI227 aI227 aI227 aI228 aI228 aI228 aI228 aI228 aI228 aI228 aI229 aI229 aI229 aI229 aI229 aI229 aI229 aI229 aI230 aI230 aI230 aI230 aI230 aI230 aI231 aI231 aI231 aI231 aI231 aI232 aI232 aI232 aI232 aI233 aI233 aI233 aI233 aI234 aI235 aI235 aI235 aI236 aI236 aI236 aI236 aI237 aI237 aI237 aI237 aI238 aI239 aI239 aI239 aI240 aI240 aI240 aI240 aI240 aI241 aI241 aI241 aI241 aI241 aI241 aI241 aI241 aI242 aI242 aI242 aI242 aI243 aI243 aI243 aI244 aI244 aI244 aI245 aI245 aI245 aI245 aI245 aI245 aI246 aI246 aI246 aI247 aI247 aI247 aI248 aI248 aI248 aI249 aI249 aI249 aI249 aI249 aI249 aI250 aI250 aI250 aI250 aI250 aI250 aI251 aI251 aI251 aI252 aI252 aI253 aI253 aI254 aI254 aI254 aI254 aI254 aI255 aI255 aI255 aI255 aI255 aI256 aI256 aI256 aI257 aI257 aI257 aI258 aI258 aI258 aI258 aI258 aI259 aI259 aI260 aI260 aI260 aI260 aI260 aI261 aI261 aI261 aI261 aI261 aI261 aI262 aI262 aI262 aI262 aI262 aI263 aI263 aI263 aI263 aI264 aI264 aI264 aI265 aI265 aI265 aI265 aI266 aI266 aI267 aI267 aI267 aI267 aI267 aI268 aI268 aI269 aI269 aI269 aI269 aI270 aI270 aI270 aI270 aI271 aI272 aI272 aI272 aI273 aI274 aI274 aI275 aI275 aI276 aI276 aI276 aI277 aI278 aI278 aI278 aI278 aI279 aI279 aI280 aI280 aI281 aI281 aI281 aI282 aI282 aI282 aI282 aI283 aI283 aI283 aI284 aI284 aI284 aI284 aI285 aI285 aI286 aI286 aI286 aI286 aI287 aI287 aI287 aI288 aI288 aI288 aI289 aI289 aI289 aI289 aI289 aI290 aI290 aI291 aI291 aI291 aI291 aI291 aI292 aI292 aI293 aI293 aI294 aI294 aI294 aI294 aI294 aI295 aI295 aI296 aI296 aI296 aI297 aI297 aI297 aI298 aI298 aI298 aI298 aI298 aI299 aI299 aI299 aI300 aI301 aI301 aI301 aI302 aI302 aI302 aI302 aI302 aI303 aI303 aI304 aI304 aI304 aI305 aI306 aI306 aI307 aI307 aI307 aI307 aI307 aI307 aI308 aI308 aI309 aI309 aI310 aI310 aI310 aI311 aI311 aI311 aI311 aI311 aI312 aI312 aI312 aI313 aI313 aI314 aI314 aI314 aI315 aI316 aI316 aI317 aI317 aI317 aI318 aI318 aI318 aI319 aI319 aI319 aI320 aI320 aI320 aI320 aI320 aI321 aI321 aI322 aI322 aI323 aI324 aI324 aI324 aI324 aI324 aI324 aI325 aI325 aI325 aI326 aI326 aI327 aI327 aI328 aI328 aI329 aI329 aI330 aI330 aI330 aI331 aI331 aI331 aI332 aI332 aI332 aI333 aI333 aI333 aI334 aI334 aI335 aI335 aI336 aI336 aI337 aI337 aI337 aI337 aI337 aI338 aI338 aI338 aI338 aI338 aI339 aI339 aI339 aI339 aI340 aI340 aI341 aI341 aI341 aI342 aI342 aI343 aI343 aI343 aI343 aI344 aI345 aI346 aI347 aI348 aI348 aI348 aI348 aI348 aI349 aI350 aI350 aI351 aI351 aI352 aI353 aI353 aI353 aI354 aI354 aI354 aI355 aI355 aI356 aI357 aI357 aI358 aI358 aI358 aI359 aI359 aI359 aI360 aI360 aI361 aI361 aI361 aI362 aI362 aI362 aI362 aI362 aI363 aI363 aI363 aI364 aI364 aI364 aI365 aI366 aI367 aI367 aI368 aI368 aI368 aI369 aI370 aI370 aI371 aI371 aI371 aI372 aI372 aI373 aI373 aI373 aI373 aI374 aI374 aI374 aI375 aI375 aI376 aI376 aI376 aI376 aI376 aI377 aI377 aI378 aI378 aI378 aI379 aI379 aI379 aI379 aI380 aI380 aI380 aI381 aI381 aI381 aI381 aI382 aI383 aI384 aI384 aI385 aI385 aI385 aI385 aI386 aI386 aI387 aI387 aI387 aI388 aI388 aI389 aI389 aI389 aI389 aI389 aI389 aI390 aI390 aI390 aI391 aI392 aI393 aI394 aI395 aI396 aI396 aI397 aI397 aI398 aI399 aI399 aI399 aI399 aI400 aI401 aI401 aI401 aI402 aI403 aI403 aI404 aI404 aI405 aI405 aI405 aI406 aI406 aI407 aI407 aI407 aI408 aI408 aI408 aI409 aI410 aI411 aI412 aI413 aI413 aI414 aI414 aI415 aI416 aI416 aI417 aI418 aI418 aI419 aI419 aI419 aI420 aI421 aI421 aI422 aI422 aI423 aI423 aI424 aI424 aI425 aI426 aI426 aI427 aI427 aI427 aI428 aI429 aI429 aI429 aI430 aI430 aI431 aI431 aI432 aI433 aI433 aI434 aI434 aI435 aI436 aI436 aI437 aI438 aI439 aI440 aI441 aI442 aI442 aI442 aI442 aI443 aI444 aI445 aI445 aI445 aI446 aI447 aI448 aI449 aI450 aI451 aI451 aI452 aI453 aI454 aI455 aI456 aI457 aI457 aI458 aI459 aI460 aI461 aI461 aI462 aI463 aI464 aI465 aI466 aI467 aI468 aI468 aI469 aI469 aI470 aI470 aI471 aI471 aI472 aI472 aI473 aI474 aI475 aI476 aI477 aI478 aI479 aI480 aI481 aI482 aI483 aI484 aI485 aI486 aI486 aI487 aI487 aI487 aI488 aI489 aI490 aI491 aI492 aI493 aI494 aI495 aI496 aI497 aI498 aI499 a(I1741 I1 tp13 g9 tp14 Rp15 (I500 I500 tp16 g4 tp17 Rp18 .cvxopt-1.1.4/examples/doc/chap7/covsel.py0000644000175000017500000000453611674452555017346 0ustar sonnesonne# The covariance selection example at the end of chapter 7 (Sparse linear # equations). from cvxopt import matrix, spmatrix, log, mul, blas, lapack, amd, cholmod from pickle import load def covsel(Y): """ Returns the solution of minimize -log det K + tr(KY) subject to K_ij = 0 if (i,j) not in zip(I, J). Y is a symmetric sparse matrix with nonzero diagonal elements. I = Y.I, J = Y.J. """ cholmod.options['supernodal'] = 2 I, J = Y.I, Y.J n, m = Y.size[0], len(I) # non-zero positions for one-argument indexing N = I + J*n # position of diagonal elements D = [ k for k in range(m) if I[k]==J[k] ] # starting point: symmetric identity with nonzero pattern I,J K = spmatrix(0.0, I, J) K[::n+1] = 1.0 # Kn is used in the line search Kn = spmatrix(0.0, I, J) # symbolic factorization of K F = cholmod.symbolic(K) # Kinv will be the inverse of K Kinv = matrix(0.0, (n,n)) for iters in range(100): # numeric factorization of K cholmod.numeric(K, F) d = cholmod.diag(F) # compute Kinv by solving K*X = I Kinv[:] = 0.0 Kinv[::n+1] = 1.0 cholmod.solve(F, Kinv) # solve Newton system grad = 2 * (Y.V - Kinv[N]) hess = 2 * ( mul(Kinv[I,J], Kinv[J,I]) + mul(Kinv[I,I], Kinv[J,J]) ) v = -grad lapack.posv(hess,v) # stopping criterion sqntdecr = -blas.dot(grad,v) print("Newton decrement squared:%- 7.5e" %sqntdecr) if (sqntdecr < 1e-12): print("number of iterations: %d" %(iters+1)) break # line search dx = +v dx[D] *= 2 f = -2.0*sum(log(d)) # f = -log det K s = 1 for lsiter in range(50): Kn.V = K.V + s*dx try: cholmod.numeric(Kn, F) except ArithmeticError: s *= 0.5 else: d = cholmod.diag(F) fn = -2.0 * sum(log(d)) + 2*s*blas.dot(v,Y.V) if (fn < f - 0.01*s*sqntdecr): break else: s *= 0.5 K.V = Kn.V return K Y = load(open("covsel.bin","rb")) print("%d rows/columns, %d nonzeros\n" %(Y.size[0], len(Y))) covsel(Y) cvxopt-1.1.4/examples/doc/chap8/0000755000175000017500000000000011674452555015472 5ustar sonnesonnecvxopt-1.1.4/examples/doc/chap8/qcl1.py0000644000175000017500000001003011674452555016676 0ustar sonnesonne# The quadratically constrained 1-norm minimization example of section 8.7 # (Exploiting structure). from cvxopt import blas, lapack, solvers, matrix, mul, div, setseed, normal from math import sqrt def qcl1(A, b): """ Returns the solution u, z of (primal) minimize || u ||_1 subject to || A * u - b ||_2 <= 1 (dual) maximize b^T z - ||z||_2 subject to || A'*z ||_inf <= 1. Exploits structure, assuming A is m by n with m >= n. """ m, n = A.size # Solve equivalent cone LP with variables x = [u; v]: # # minimize [0; 1]' * x # subject to [ I -I ] * x <= [ 0 ] (componentwise) # [-I -I ] * x <= [ 0 ] (componentwise) # [ 0 0 ] * x <= [ 1 ] (SOC) # [-A 0 ] [ -b ]. # # maximize -t + b' * w # subject to z1 - z2 = A'*w # z1 + z2 = 1 # z1 >= 0, z2 >=0, ||w||_2 <= t. c = matrix(n*[0.0] + n*[1.0]) h = matrix( 0.0, (2*n + m + 1, 1)) h[2*n] = 1.0 h[2*n+1:] = -b def G(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): y *= beta if trans=='N': # y += alpha * G * x y[:n] += alpha * (x[:n] - x[n:2*n]) y[n:2*n] += alpha * (-x[:n] - x[n:2*n]) y[2*n+1:] -= alpha * A*x[:n] else: # y += alpha * G'*x y[:n] += alpha * (x[:n] - x[n:2*n] - A.T * x[-m:]) y[n:] -= alpha * (x[:n] + x[n:2*n]) def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 G' ] [ x ] = [ bx ] # [ G -W'*W ] [ z ] [ bz ]. # First factor # # S = G' * W**-1 * W**-T * G # = [0; -A]' * W3^-2 * [0; -A] + 4 * (W1**2 + W2**2)**-1 # # where # # W1 = diag(d1) with d1 = W['d'][:n] = 1 ./ W['di'][:n] # W2 = diag(d2) with d2 = W['d'][n:] = 1 ./ W['di'][n:] # W3 = beta * (2*v*v' - J), W3^-1 = 1/beta * (2*J*v*v'*J - J) # with beta = W['beta'][0], v = W['v'][0], J = [1, 0; 0, -I]. # As = W3^-1 * [ 0 ; -A ] = 1/beta * ( 2*J*v * v' - I ) * [0; A] beta, v = W['beta'][0], W['v'][0] As = 2 * v * (v[1:].T * A) As[1:,:] *= -1.0 As[1:,:] -= A As /= beta # S = As'*As + 4 * (W1**2 + W2**2)**-1 S = As.T * As d1, d2 = W['d'][:n], W['d'][n:] d = 4.0 * (d1**2 + d2**2)**-1 S[::n+1] += d lapack.potrf(S) def f(x, y, z): # z := - W**-T * z z[:n] = -div( z[:n], d1 ) z[n:2*n] = -div( z[n:2*n], d2 ) z[2*n:] -= 2.0*v*( v[0]*z[2*n] - blas.dot(v[1:], z[2*n+1:]) ) z[2*n+1:] *= -1.0 z[2*n:] /= beta # x := x - G' * W**-1 * z x[:n] -= div(z[:n], d1) - div(z[n:2*n], d2) + As.T * z[-(m+1):] x[n:] += div(z[:n], d1) + div(z[n:2*n], d2) # Solve for x[:n]: # # S*x[:n] = x[:n] - (W1**2 - W2**2)(W1**2 + W2**2)^-1 * x[n:] x[:n] -= mul( div(d1**2 - d2**2, d1**2 + d2**2), x[n:]) lapack.potrs(S, x) # Solve for x[n:]: # # (d1**-2 + d2**-2) * x[n:] = x[n:] + (d1**-2 - d2**-2)*x[:n] x[n:] += mul( d1**-2 - d2**-2, x[:n]) x[n:] = div( x[n:], d1**-2 + d2**-2) # z := z + W^-T * G*x z[:n] += div( x[:n] - x[n:2*n], d1) z[n:2*n] += div( -x[:n] - x[n:2*n], d2) z[2*n:] += As*x[:n] return f dims = {'l': 2*n, 'q': [m+1], 's': []} sol = solvers.conelp(c, G, h, dims, kktsolver = Fkkt) if sol['status'] == 'optimal': return sol['x'][:n], sol['z'][-m:] else: return None, None setseed() m, n = 100, 100 A, b = normal(m,n), normal(m,1) x, z = qcl1(A, b) if x is None: print("infeasible") cvxopt-1.1.4/examples/doc/chap8/l1regls.py0000644000175000017500000001020611674452555017414 0ustar sonnesonne# The 1-norm regularized least-squares example of section 8.7 (Exploiting # structure). from cvxopt import matrix, spdiag, mul, div, sqrt, normal, setseed from cvxopt import blas, lapack, solvers import math def l1regls(A, y): """ Returns the solution of l1-norm regularized least-squares problem minimize || A*x - y ||_2^2 + || x ||_1. """ m, n = A.size q = matrix(1.0, (2*n,1)) q[:n] = -2.0 * A.T * y def P(u, v, alpha = 1.0, beta = 0.0 ): """ v := alpha * 2.0 * [ A'*A, 0; 0, 0 ] * u + beta * v """ v *= beta v[:n] += alpha * 2.0 * A.T * (A * u[:n]) def G(u, v, alpha=1.0, beta=0.0, trans='N'): """ v := alpha*[I, -I; -I, -I] * u + beta * v (trans = 'N' or 'T') """ v *= beta v[:n] += alpha*(u[:n] - u[n:]) v[n:] += alpha*(-u[:n] - u[n:]) h = matrix(0.0, (2*n,1)) # Customized solver for the KKT system # # [ 2.0*A'*A 0 I -I ] [x[:n] ] [bx[:n] ] # [ 0 0 -I -I ] [x[n:] ] = [bx[n:] ]. # [ I -I -D1^-1 0 ] [zl[:n]] [bzl[:n]] # [ -I -I 0 -D2^-1 ] [zl[n:]] [bzl[n:]] # # where D1 = W['di'][:n]**2, D2 = W['di'][n:]**2. # # We first eliminate zl and x[n:]: # # ( 2*A'*A + 4*D1*D2*(D1+D2)^-1 ) * x[:n] = # bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] + # D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - # D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] # # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n] - D2*bzl[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] # # zl[:n] = D1 * ( x[:n] - x[n:] - bzl[:n] ) # zl[n:] = D2 * (-x[:n] - x[n:] - bzl[n:] ). # # The first equation has the form # # (A'*A + D)*x[:n] = rhs # # and is equivalent to # # [ D A' ] [ x:n] ] = [ rhs ] # [ A -I ] [ v ] [ 0 ]. # # It can be solved as # # ( A*D^-1*A' + I ) * v = A * D^-1 * rhs # x[:n] = D^-1 * ( rhs - A'*v ). S = matrix(0.0, (m,m)) Asc = matrix(0.0, (m,n)) v = matrix(0.0, (m,1)) def Fkkt(W): # Factor # # S = A*D^-1*A' + I # # where D = 2*D1*D2*(D1+D2)^-1, D1 = d[:n]**-2, D2 = d[n:]**-2. d1, d2 = W['di'][:n]**2, W['di'][n:]**2 # ds is square root of diagonal of D ds = math.sqrt(2.0) * div( mul( W['di'][:n], W['di'][n:]), sqrt(d1+d2) ) d3 = div(d2 - d1, d1 + d2) # Asc = A*diag(d)^-1/2 Asc = A * spdiag(ds**-1) # S = I + A * D^-1 * A' blas.syrk(Asc, S) S[::m+1] += 1.0 lapack.potrf(S) def g(x, y, z): x[:n] = 0.5 * ( x[:n] - mul(d3, x[n:]) + mul(d1, z[:n] + mul(d3, z[:n])) - mul(d2, z[n:] - mul(d3, z[n:])) ) x[:n] = div( x[:n], ds) # Solve # # S * v = 0.5 * A * D^-1 * ( bx[:n] - # (D2-D1)*(D1+D2)^-1 * bx[n:] + # D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bzl[:n] - # D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bzl[n:] ) blas.gemv(Asc, x, v) lapack.potrs(S, v) # x[:n] = D^-1 * ( rhs - A'*v ). blas.gemv(Asc, v, x, alpha=-1.0, beta=1.0, trans='T') x[:n] = div(x[:n], ds) # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bzl[:n] - D2*bzl[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] x[n:] = div( x[n:] - mul(d1, z[:n]) - mul(d2, z[n:]), d1+d2 )\ - mul( d3, x[:n] ) # zl[:n] = D1^1/2 * ( x[:n] - x[n:] - bzl[:n] ) # zl[n:] = D2^1/2 * ( -x[:n] - x[n:] - bzl[n:] ). z[:n] = mul( W['di'][:n], x[:n] - x[n:] - z[:n] ) z[n:] = mul( W['di'][n:], -x[:n] - x[n:] - z[n:] ) return g return solvers.coneqp(P, q, G, h, kktsolver = Fkkt)['x'][:n] m, n = 100, 1000 setseed() A = normal(m,n) b = normal(m) x = l1regls(A, b) cvxopt-1.1.4/examples/doc/chap8/l1.py0000644000175000017500000000744111674452555016366 0ustar sonnesonne# The 1-norm approximation example of section 8.7 (Exploiting structure). from cvxopt import blas, lapack, solvers from cvxopt import matrix, spdiag, mul, div, setseed, normal from math import sqrt def l1(P, q): """ Returns the solution u, w of the ell-1 approximation problem (primal) minimize ||P*u - q||_1 (dual) maximize q'*w subject to P'*w = 0 ||w||_infty <= 1. """ m, n = P.size # Solve equivalent LP # # minimize [0; 1]' * [u; v] # subject to [P, -I; -P, -I] * [u; v] <= [q; -q] # # maximize -[q; -q]' * z # subject to [P', -P']*z = 0 # [-I, -I]*z + 1 = 0 # z >= 0 c = matrix(n*[0.0] + m*[1.0]) h = matrix([q, -q]) def Fi(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): if trans == 'N': # y := alpha * [P, -I; -P, -I] * x + beta*y u = P*x[:n] y[:m] = alpha * ( u - x[n:]) + beta*y[:m] y[m:] = alpha * (-u - x[n:]) + beta*y[m:] else: # y := alpha * [P', -P'; -I, -I] * x + beta*y y[:n] = alpha * P.T * (x[:m] - x[m:]) + beta*y[:n] y[n:] = -alpha * (x[:m] + x[m:]) + beta*y[n:] def Fkkt(W): # Returns a function f(x, y, z) that solves # # [ 0 0 P' -P' ] [ x[:n] ] [ bx[:n] ] # [ 0 0 -I -I ] [ x[n:] ] [ bx[n:] ] # [ P -I -D1^{-1} 0 ] [ z[:m] ] = [ bz[:m] ] # [-P -I 0 -D2^{-1} ] [ z[m:] ] [ bz[m:] ] # # where D1 = diag(di[:m])^2, D2 = diag(di[m:])^2 and di = W['di']. # # On entry bx, bz are stored in x, z. # On exit x, z contain the solution, with z scaled (di .* z is # returned instead of z). # Factor A = 4*P'*D*P where D = d1.*d2 ./(d1+d2) and # d1 = d[:m].^2, d2 = d[m:].^2. di = W['di'] d1, d2 = di[:m]**2, di[m:]**2 D = div( mul(d1,d2), d1+d2 ) A = P.T * spdiag(4*D) * P lapack.potrf(A) def f(x, y, z): # Solve for x[:n]: # # A*x[:n] = bx[:n] + P' * ( ((D1-D2)*(D1+D2)^{-1})*bx[n:] # + (2*D1*D2*(D1+D2)^{-1}) * (bz[:m] - bz[m:]) ). x[:n] += P.T * ( mul( div(d1-d2, d1+d2), x[n:]) + mul( 2*D, z[:m]-z[m:] ) ) lapack.potrs(A, x) # x[n:] := (D1+D2)^{-1} * (bx[n:] - D1*bz[:m] - D2*bz[m:] # + (D1-D2)*P*x[:n]) u = P*x[:n] x[n:] = div( x[n:] - mul(d1, z[:m]) - mul(d2, z[m:]) + mul(d1-d2, u), d1+d2 ) # z[:m] := d1[:m] .* ( P*x[:n] - x[n:] - bz[:m]) # z[m:] := d2[m:] .* (-P*x[:n] - x[n:] - bz[m:]) z[:m] = mul(di[:m], u-x[n:]-z[:m]) z[m:] = mul(di[m:], -u-x[n:]-z[m:]) return f # Initial primal and dual points from least-squares solution. # uls minimizes ||P*u-q||_2; rls is the LS residual. uls = +q lapack.gels(+P, uls) rls = P*uls[:n] - q # x0 = [ uls; 1.1*abs(rls) ]; s0 = [q;-q] - [P,-I; -P,-I] * x0 x0 = matrix( [uls[:n], 1.1*abs(rls)] ) s0 = +h Fi(x0, s0, alpha=-1, beta=1) # z0 = [ (1+w)/2; (1-w)/2 ] where w = (.9/||rls||_inf) * rls # if rls is nonzero and w = 0 otherwise. if max(abs(rls)) > 1e-10: w = .9/max(abs(rls)) * rls else: w = matrix(0.0, (m,1)) z0 = matrix([.5*(1+w), .5*(1-w)]) dims = {'l': 2*m, 'q': [], 's': []} sol = solvers.conelp(c, Fi, h, dims, kktsolver = Fkkt, primalstart={'x': x0, 's': s0}, dualstart={'z': z0}) return sol['x'][:n], sol['z'][m:] - sol['z'][:m] setseed() m, n = 1000, 100 P, q = normal(m,n), normal(m,1) x, y = l1(P,q) cvxopt-1.1.4/examples/doc/chap8/lp.py0000644000175000017500000000040611674452555016457 0ustar sonnesonne# The small LP of section 8.3 (Linear programming). from cvxopt import matrix, solvers c = matrix([-4., -5.]) G = matrix([[2., 1., -1., 0.], [1., 2., 0., -1.]]) h = matrix([3., 3., 0., 0.]) sol = solvers.lp(c, G, h) print("\nx = \n") print(sol['x']) cvxopt-1.1.4/examples/doc/chap8/mcsdp.py0000644000175000017500000000621411674452555017155 0ustar sonnesonne# The SDP example of section 8.7 (Exploiting structure). from cvxopt import blas, lapack, solvers, matrix, normal def mcsdp(w): """ Returns solution x, z to (primal) minimize sum(x) subject to w + diag(x) >= 0 (dual) maximize -tr(w*z) subject to diag(z) = 1 z >= 0. """ n = w.size[0] def Fs(x, y, alpha = 1.0, beta = 0.0, trans = 'N'): """ y := alpha*(-diag(x)) + beta*y. """ if trans=='N': # x is a vector; y is a matrix. blas.scal(beta, y) blas.axpy(x, y, alpha = -alpha, incy = n+1) else: # x is a matrix; y is a vector. blas.scal(beta, y) blas.axpy(x, y, alpha = -alpha, incx = n+1) def cngrnc(r, x, alpha = 1.0): """ Congruence transformation x := alpha * r'*x*r. r and x are square matrices. """ # Scale diagonal of x by 1/2. x[::n+1] *= 0.5 # a := tril(x)*r a = +r tx = matrix(x, (n,n)) blas.trmm(tx, a, side='L') # x := alpha*(a*r' + r*a') blas.syr2k(r, a, tx, trans = 'T', alpha = alpha) x[:] = tx[:] def Fkkt(W): rti = W['rti'][0] # t = rti*rti' as a nonsymmetric matrix. t = matrix(0.0, (n,n)) blas.gemm(rti, rti, t, transB = 'T') # Cholesky factorization of tsq = t.*t. tsq = t**2 lapack.potrf(tsq) def f(x, y, z): """ Solve -diag(z) = bx -diag(x) - inv(rti*rti') * z * inv(rti*rti') = bs On entry, x and z contain bx and bs. On exit, they contain the solution, with z scaled (inv(rti)'*z*inv(rti) is returned instead of z). We first solve ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bs*t) and take z = -rti' * (diag(x) + bs) * rti. """ # tbst := t * zs * t = t * bs * t tbst = matrix(z, (n,n)) cngrnc(t, tbst) # x := x - diag(tbst) = bx - diag(rti*rti' * bs * rti*rti') x -= tbst[::n+1] # x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t)) lapack.potrs(tsq, x) # z := z + diag(x) = bs + diag(x) z[::n+1] += x # z := -rti' * z * rti = -rti' * (diag(x) + bs) * rti cngrnc(rti, z, alpha = -1.0) return f c = matrix(1.0, (n,1)) # Initial feasible x: x = 1.0 - min(lambda(w)). lmbda = matrix(0.0, (n,1)) lapack.syevx(+w, lmbda, range='I', il=1, iu=1) x0 = matrix(-lmbda[0]+1.0, (n,1)) s0 = +w s0[::n+1] += x0 # Initial feasible z is identity. z0 = matrix(0.0, (n,n)) z0[::n+1] = 1.0 dims = {'l': 0, 'q': [], 's': [n]} sol = solvers.conelp(c, Fs, w[:], dims, kktsolver = Fkkt, primalstart = {'x': x0, 's': s0[:]}, dualstart = {'z': z0[:]}) return sol['x'], matrix(sol['z'], (n,n)) n = 100 w = normal(n,n) x, z = mcsdp(w) cvxopt-1.1.4/examples/doc/chap8/socp.py0000644000175000017500000000100111674452555017000 0ustar sonnesonne# The small SOCP of section 8.5 (Second-order cone programming). from cvxopt import matrix, solvers c = matrix([-2., 1., 5.]) G = [ matrix( [[12., 13., 12.], [6., -3., -12.], [-5., -5., 6.]] ) ] G += [ matrix( [[3., 3., -1., 1.], [-6., -6., -9., 19.], [10., -2., -2., -3.]] ) ] h = [ matrix( [-12., -3., -2.] ), matrix( [27., 0., 3., -42.] ) ] sol = solvers.socp(c, Gq = G, hq = h) print("\nx = \n") print(sol['x']) print("zq[0] = \n") print(sol['zq'][0]) print("zq[1] = \n") print(sol['zq'][1]) cvxopt-1.1.4/examples/doc/chap8/conelp.py0000644000175000017500000000147711674452555017335 0ustar sonnesonne# The small linear cone program of section 8.1 (Linear cone programs). from cvxopt import matrix, solvers c = matrix([-6., -4., -5.]) G = matrix([[ 16., 7., 24., -8., 8., -1., 0., -1., 0., 0., 7., -5., 1., -5., 1., -7., 1., -7., -4.], [-14., 2., 7., -13., -18., 3., 0., 0., -1., 0., 3., 13., -6., 13., 12., -10., -6., -10., -28.], [ 5., 0., -15., 12., -6., 17., 0., 0., 0., -1., 9., 6., -6., 6., -7., -7., -6., -7., -11.]]) h = matrix( [ -3., 5., 12., -2., -14., -13., 10., 0., 0., 0., 68., -30., -19., -30., 99., 23., -19., 23., 10.] ) dims = {'l': 2, 'q': [4, 4], 's': [3]} sol = solvers.conelp(c, G, h, dims) print("\nStatus: " + sol['status']) print("\nx = \n") print(sol['x']) print("\nz = \n") print(sol['z']) cvxopt-1.1.4/examples/doc/chap8/portfolio.py0000644000175000017500000000350111674452555020060 0ustar sonnesonne# The risk-return trade-off of section 8.4 (Quadratic programming). from math import sqrt from cvxopt import matrix from cvxopt.blas import dot from cvxopt.solvers import qp, options n = 4 S = matrix( [[ 4e-2, 6e-3, -4e-3, 0.0 ], [ 6e-3, 1e-2, 0.0, 0.0 ], [-4e-3, 0.0, 2.5e-3, 0.0 ], [ 0.0, 0.0, 0.0, 0.0 ]] ) pbar = matrix([.12, .10, .07, .03]) G = matrix(0.0, (n,n)) G[::n+1] = -1.0 h = matrix(0.0, (n,1)) A = matrix(1.0, (1,n)) b = matrix(1.0) N = 100 mus = [ 10**(5.0*t/N-1.0) for t in range(N) ] options['show_progress'] = False xs = [ qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus ] returns = [ dot(pbar,x) for x in xs ] risks = [ sqrt(dot(x, S*x)) for x in xs ] try: import pylab except ImportError: pass else: pylab.figure(1, facecolor='w') pylab.plot(risks, returns) pylab.xlabel('standard deviation') pylab.ylabel('expected return') pylab.axis([0, 0.2, 0, 0.15]) pylab.title('Risk-return trade-off curve (fig 4.12)') pylab.yticks([0.00, 0.05, 0.10, 0.15]) pylab.figure(2, facecolor='w') c1 = [ x[0] for x in xs ] c2 = [ x[0] + x[1] for x in xs ] c3 = [ x[0] + x[1] + x[2] for x in xs ] c4 = [ x[0] + x[1] + x[2] + x[3] for x in xs ] pylab.fill(risks + [.20], c1 + [0.0], facecolor = '#F0F0F0') pylab.fill(risks[-1::-1] + risks, c2[-1::-1] + c1, facecolor='#D0D0D0') pylab.fill(risks[-1::-1] + risks, c3[-1::-1] + c2, facecolor='#F0F0F0') pylab.fill(risks[-1::-1] + risks, c4[-1::-1] + c3, facecolor='#D0D0D0') pylab.axis([0.0, 0.2, 0.0, 1.0]) pylab.xlabel('standard deviation') pylab.ylabel('allocation') pylab.text(.15,.5,'x1') pylab.text(.10,.7,'x2') pylab.text(.05,.7,'x3') pylab.text(.01,.7,'x4') pylab.title('Optimal allocations (fig 4.12)') pylab.show() cvxopt-1.1.4/examples/doc/chap8/sdp.py0000644000175000017500000000132211674452555016630 0ustar sonnesonne# The small SDP of section 8.6 (Semidefinite programming). from cvxopt import matrix, solvers c = matrix([1.,-1.,1.]) G = [ matrix([[-7., -11., -11., 3.], [ 7., -18., -18., 8.], [-2., -8., -8., 1.]]) ] G += [ matrix([[-21., -11., 0., -11., 10., 8., 0., 8., 5.], [ 0., 10., 16., 10., -10., -10., 16., -10., 3.], [ -5., 2., -17., 2., -6., 8., -17., -7., 6.]]) ] h = [ matrix([[33., -9.], [-9., 26.]]) ] h += [ matrix([[14., 9., 40.], [9., 91., 10.], [40., 10., 15.]]) ] sol = solvers.sdp(c, Gs=G, hs=h) print("\nx = \n") print(sol['x']) print("zs[0] = \n") print(sol['zs'][0]) print("zs[1] =\n") print(sol['zs'][1]) cvxopt-1.1.4/examples/doc/chap8/coneqp.py0000644000175000017500000000115311674452555017331 0ustar sonnesonne# The quadratic cone program of section 8.2 (Quadratic cone programs). # minimize (1/2)*x'*A'*A*x - b'*A*x # subject to x >= 0 # ||x||_2 <= 1 from cvxopt import matrix, base, solvers A = matrix([ [ .3, -.4, -.2, -.4, 1.3 ], [ .6, 1.2, -1.7, .3, -.3 ], [-.3, .0, .6, -1.2, -2.0 ] ]) b = matrix([ 1.5, .0, -1.2, -.7, .0]) m, n = A.size I = matrix(0.0, (n,n)) I[::n+1] = 1.0 G = matrix([-I, matrix(0.0, (1,n)), I]) h = matrix(n*[0.0] + [1.0] + n*[0.0]) dims = {'l': n, 'q': [n+1], 's': []} x = solvers.coneqp(A.T*A, -A.T*b, G, h, dims)['x'] print("\nx = \n") print(x) cvxopt-1.1.4/examples/doc/chap9/0000755000175000017500000000000011674452555015473 5ustar sonnesonnecvxopt-1.1.4/examples/doc/chap9/l2ac.py0000644000175000017500000000404711674452555016673 0ustar sonnesonne# The example of section 9.4 (Exploiting structure).. from cvxopt import matrix, spdiag, mul, div, log, setseed, uniform, normal from cvxopt import blas, lapack, solvers def l2ac(A, b): """ Solves minimize (1/2) * ||A*x-b||_2^2 - sum log (1-xi^2) assuming A is m x n with m << n. """ m, n = A.size def F(x = None, z = None): if x is None: return 0, matrix(0.0, (n,1)) if max(abs(x)) >= 1.0: return None r = - b blas.gemv(A, x, r, beta = -1.0) w = x**2 f = 0.5 * blas.nrm2(r)**2 - sum(log(1-w)) gradf = div(x, 1.0 - w) blas.gemv(A, r, gradf, trans = 'T', beta = 2.0) if z is None: return f, gradf.T else: def Hf(u, v, alpha = 1.0, beta = 0.0): """ v := alpha * (A'*A*u + 2*((1+w)./(1-w)).*u + beta *v """ v *= beta v += 2.0 * alpha * mul(div(1.0+w, (1.0-w)**2), u) blas.gemv(A, u, r) blas.gemv(A, r, v, alpha = alpha, beta = 1.0, trans = 'T') return f, gradf.T, Hf # Custom solver for the Newton system # # z[0]*(A'*A + D)*x = bx # # where D = 2 * (1+x.^2) ./ (1-x.^2).^2. We apply the matrix inversion # lemma and solve this as # # (A * D^-1 *A' + I) * v = A * D^-1 * bx / z[0] # D * x = bx / z[0] - A'*v. S = matrix(0.0, (m,m)) v = matrix(0.0, (m,1)) def Fkkt(x, z, W): ds = (2.0 * div(1 + x**2, (1 - x**2)**2))**-0.5 Asc = A * spdiag(ds) blas.syrk(Asc, S) S[::m+1] += 1.0 lapack.potrf(S) a = z[0] def g(x, y, z): x[:] = mul(x, ds) / a blas.gemv(Asc, x, v) lapack.potrs(S, v) blas.gemv(Asc, v, x, alpha = -1.0, beta = 1.0, trans = 'T') x[:] = mul(x, ds) return g return solvers.cp(F, kktsolver = Fkkt)['x'] m, n = 200, 2000 setseed() A = normal(m,n) x = uniform(n,1) b = A*x x = l2ac(A, b) cvxopt-1.1.4/examples/doc/chap9/acent2.py0000644000175000017500000000165711674452555017232 0ustar sonnesonne# The analytic centering with cone constraints example of section 9.1 # (Problems with nonlinear objectives). from cvxopt import matrix, log, div, spdiag from cvxopt import solvers def F(x = None, z = None): if x is None: return 0, matrix(0.0, (3,1)) if max(abs(x)) >= 1.0: return None u = 1 - x**2 val = -sum(log(u)) Df = div(2*x, u).T if z is None: return val, Df H = spdiag(2 * z[0] * div(1 + u**2, u**2)) return val, Df, H G = matrix([ [0., -1., 0., 0., -21., -11., 0., -11., 10., 8., 0., 8., 5.], [0., 0., -1., 0., 0., 10., 16., 10., -10., -10., 16., -10., 3.], [0., 0., 0., -1., -5., 2., -17., 2., -6., 8., -17., -7., 6.] ]) h = matrix( [1.0, 0.0, 0.0, 0.0, 20., 10., 40., 10., 80., 10., 40., 10., 15.]) dims = {'l': 0, 'q': [4], 's': [3]} sol = solvers.cp(F, G, h, dims) print("\nx = \n") print(sol['x']) cvxopt-1.1.4/examples/doc/chap9/acent.py0000644000175000017500000000167511674452555017150 0ustar sonnesonne# The equality constrained analytical centering example of section 9.1 # (Problems with nonlinear objectives). from cvxopt import matrix, spmatrix, spdiag, log, normal, uniform from cvxopt import blas, solvers def acent(A, b): # Returns the solution of # # minimize -sum log(x) # subject to A*x = b m, n = A.size def F(x=None, z=None): if x is None: return 0, matrix(1.0, (n,1)) if min(x) <= 0.0: return None f = -sum(log(x)) Df = -(x**-1).T if z is None: return matrix(f), Df H = spdiag(z[0] * x**-2) return f, Df, H return solvers.cp(F, A=A, b=b)['x'] # Randomly generate a feasible problem m, n = 50, 500 y = normal(m,1) # Random A with A'*y > 0. s = uniform(n,1) A = normal(m,n) r = s - A.T * y # A = A - (1/y'*y) * y*r' blas.ger(y, r, A, alpha = 1.0/blas.dot(y,y)) # Random feasible x > 0. x = uniform(n,1) b = A*x x = acent(A,b) cvxopt-1.1.4/examples/doc/chap9/floorplan.py0000644000175000017500000001404411674452555020044 0ustar sonnesonne# The floor planning example section 9.2 (Problems with linear objectives). from cvxopt import solvers, matrix, spmatrix, mul, div solvers.options['show_progress'] = False def floorplan(Amin): # minimize W+H # subject to Amink / hk <= wk, k = 1,..., 5 # x1 >= 0, x2 >= 0, x4 >= 0 # x1 + w1 + rho <= x3 # x2 + w2 + rho <= x3 # x3 + w3 + rho <= x5 # x4 + w4 + rho <= x5 # x5 + w5 <= W # y2 >= 0, y3 >= 0, y5 >= 0 # y2 + h2 + rho <= y1 # y1 + h1 + rho <= y4 # y3 + h3 + rho <= y4 # y4 + h4 <= H # y5 + h5 <= H # hk/gamma <= wk <= gamma*hk, k = 1, ..., 5 # # 22 Variables W, H, x (5), y (5), w (5), h (5). # # W, H: scalars; bounding box width and height # x, y: 5-vectors; coordinates of bottom left corners of blocks # w, h: 5-vectors; widths and heigths of the 5 blocks rho, gamma = 1.0, 5.0 # min spacing, min aspect ratio # The objective is to minimize W + H. There are five nonlinear # constraints # # -wk + Amink / hk <= 0, k = 1, ..., 5 c = matrix(2*[1.0] + 20*[0.0]) def F(x=None, z=None): if x is None: return 5, matrix(17*[0.0] + 5*[1.0]) if min(x[17:]) <= 0.0: return None f = -x[12:17] + div(Amin, x[17:]) Df = matrix(0.0, (5,22)) Df[:,12:17] = spmatrix(-1.0, range(5), range(5)) Df[:,17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5)) if z is None: return f, Df H = spmatrix( 2.0* mul(z, div(Amin, x[17::]**3)), range(17,22), range(17,22) ) return f, Df, H G = matrix(0.0, (26,22)) h = matrix(0.0, (26,1)) # -x1 <= 0 G[0,2] = -1.0 # -x2 <= 0 G[1,3] = -1.0 # -x4 <= 0 G[2,5] = -1.0 # x1 - x3 + w1 <= -rho G[3, [2, 4, 12]], h[3] = [1.0, -1.0, 1.0], -rho # x2 - x3 + w2 <= -rho G[4, [3, 4, 13]], h[4] = [1.0, -1.0, 1.0], -rho # x3 - x5 + w3 <= -rho G[5, [4, 6, 14]], h[5] = [1.0, -1.0, 1.0], -rho # x4 - x5 + w4 <= -rho G[6, [5, 6, 15]], h[6] = [1.0, -1.0, 1.0], -rho # -W + x5 + w5 <= 0 G[7, [0, 6, 16]] = -1.0, 1.0, 1.0 # -y2 <= 0 G[8,8] = -1.0 # -y3 <= 0 G[9,9] = -1.0 # -y5 <= 0 G[10,11] = -1.0 # -y1 + y2 + h2 <= -rho G[11, [7, 8, 18]], h[11] = [-1.0, 1.0, 1.0], -rho # y1 - y4 + h1 <= -rho G[12, [7, 10, 17]], h[12] = [1.0, -1.0, 1.0], -rho # y3 - y4 + h3 <= -rho G[13, [9, 10, 19]], h[13] = [1.0, -1.0, 1.0], -rho # -H + y4 + h4 <= 0 G[14, [1, 10, 20]] = -1.0, 1.0, 1.0 # -H + y5 + h5 <= 0 G[15, [1, 11, 21]] = -1.0, 1.0, 1.0 # -w1 + h1/gamma <= 0 G[16, [12, 17]] = -1.0, 1.0/gamma # w1 - gamma * h1 <= 0 G[17, [12, 17]] = 1.0, -gamma # -w2 + h2/gamma <= 0 G[18, [13, 18]] = -1.0, 1.0/gamma # w2 - gamma * h2 <= 0 G[19, [13, 18]] = 1.0, -gamma # -w3 + h3/gamma <= 0 G[20, [14, 18]] = -1.0, 1.0/gamma # w3 - gamma * h3 <= 0 G[21, [14, 19]] = 1.0, -gamma # -w4 + h4/gamma <= 0 G[22, [15, 19]] = -1.0, 1.0/gamma # w4 - gamma * h4 <= 0 G[23, [15, 20]] = 1.0, -gamma # -w5 + h5/gamma <= 0 G[24, [16, 21]] = -1.0, 1.0/gamma # w5 - gamma * h5 <= 0.0 G[25, [16, 21]] = 1.0, -gamma # solve and return W, H, x, y, w, h sol = solvers.cpl(c, F, G, h) return sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], \ sol['x'][12:17], sol['x'][17:] try: import pylab except ImportError: pass else: pylab.figure(facecolor='w') pylab.subplot(221) Amin = matrix([100., 100., 100., 100., 100.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.subplot(222) Amin = matrix([20., 50., 80., 150., 200.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.subplot(223) Amin = matrix([180., 80., 80., 80., 80.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.subplot(224) Amin = matrix([20., 150., 20., 200., 110.]) W, H, x, y, w, h = floorplan(Amin) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.show() cvxopt-1.1.4/examples/doc/chap9/gp.py0000644000175000017500000000107211674452555016453 0ustar sonnesonne# The small GP of section 9.3 (Geometric programming). from cvxopt import matrix, log, exp, solvers Aflr = 1000.0 Awall = 100.0 alpha = 0.5 beta = 2.0 gamma = 0.5 delta = 2.0 F = matrix( [[-1., 1., 1., 0., -1., 1., 0., 0.], [-1., 1., 0., 1., 1., -1., 1., -1.], [-1., 0., 1., 1., 0., 0., -1., 1.]]) g = log( matrix( [1.0, 2/Awall, 2/Awall, 1/Aflr, alpha, 1/beta, gamma, 1/delta]) ) K = [1, 2, 1, 1, 1, 1, 1] h, w, d = exp( solvers.gp(K, F, g)['x'] ) print("\n h = %f, w = %f, d = %f.\n" %(h,w,d)) cvxopt-1.1.4/examples/doc/chap9/robls.py0000644000175000017500000000245111674452555017170 0ustar sonnesonne# The robust least-squares example of section 9.1 (Problems with nonlinear # objectives). from math import sqrt, ceil, floor from cvxopt import solvers, blas, lapack from cvxopt import matrix, spmatrix, spdiag, sqrt, mul, div, setseed, normal def robls(A, b, rho): # Minimize sum_k sqrt(rho + (A*x-b)_k^2). m, n = A.size def F(x=None, z=None): if x is None: return 0, matrix(0.0, (n,1)) y = A*x-b w = sqrt(rho + y**2) f = sum(w) Df = div(y, w).T * A if z is None: return f, Df H = A.T * spdiag(z[0]*rho*(w**-3)) * A return f, Df, H return solvers.cp(F)['x'] setseed() m, n = 500, 100 A = normal(m,n) b = normal(m,1) xh = robls(A,b,0.1) try: import pylab except ImportError: pass else: # Least-squares solution. pylab.subplot(211) xls = +b lapack.gels(+A,xls) rls = A*xls[:n] - b pylab.hist(rls, m/5) pylab.title('Least-squares solution') pylab.xlabel('Residual') mr = ceil(max(rls)) pylab.axis([-mr, mr, 0, 25]) # Robust least-squares solution with rho = 0.01. pylab.subplot(212) rh = A*xh - b pylab.hist(rh, m/5) mr = ceil(max(rh)) pylab.title('Robust least-squares solution') pylab.xlabel('Residual') pylab.axis([-mr, mr, 0, 50]) pylab.show() cvxopt-1.1.4/examples/doc/chap10/0000755000175000017500000000000011674452555015543 5ustar sonnesonnecvxopt-1.1.4/examples/doc/chap10/lp.py0000644000175000017500000000215511674452555016533 0ustar sonnesonne# The small LP of section 10.4 (Optimization problems). from cvxopt import matrix from cvxopt.modeling import variable, op, dot x = variable() y = variable() c1 = ( 2*x+y <= 3 ) c2 = ( x+2*y <= 3 ) c3 = ( x >= 0 ) c4 = ( y >= 0 ) lp1 = op(-4*x-5*y, [c1,c2,c3,c4]) lp1.solve() print("\nstatus: %s" %lp1.status) print("optimal value: %f" %lp1.objective.value()[0]) print("optimal x: %f" %x.value[0]) print("optimal y: %f" %y.value[0]) print("optimal multiplier for 1st constraint: %f" %c1.multiplier.value[0]) print("optimal multiplier for 2nd constraint: %f" %c2.multiplier.value[0]) print("optimal multiplier for 3rd constraint: %f" %c3.multiplier.value[0]) print("optimal multiplier for 4th constraint: %f\n" %c4.multiplier.value[0]) x = variable(2) A = matrix([[2.,1.,-1.,0.], [1.,2.,0.,-1.]]) b = matrix([3.,3.,0.,0.]) c = matrix([-4.,-5.]) ineq = ( A*x <= b ) lp2 = op(dot(c,x), ineq) lp2.solve() print("\nstatus: %s" %lp2.status) print("optimal value: %f" %lp2.objective.value()[0]) print("optimal x: \n") print(x.value) print("optimal multiplier: \n") print(ineq.multiplier.value) cvxopt-1.1.4/examples/doc/chap10/l1svc.py0000644000175000017500000000075211674452555017151 0ustar sonnesonne# The 1-norm support vector classifier of section 10.5 (Examples). from cvxopt import normal, setseed from cvxopt.modeling import variable, op, max, sum from cvxopt.blas import nrm2 m, n = 500, 100 A = normal(m,n) x = variable(A.size[1],'x') u = variable(A.size[0],'u') op(sum(abs(x)) + sum(u), [A*x >= 1-u, u >= 0]).solve() x2 = variable(A.size[1],'x') op(sum(abs(x2)) + sum(max(0, 1 - A*x2))).solve() print("\nDifference between two solutions: %e" %nrm2(x.value - x2.value)) cvxopt-1.1.4/examples/doc/chap10/roblp.py0000644000175000017500000000076011674452555017236 0ustar sonnesonne# The robust LP example of section 10.5 (Examples). from cvxopt import normal, uniform from cvxopt.modeling import variable, dot, op, sum from cvxopt.blas import nrm2 m, n = 500, 100 A = normal(m,n) b = uniform(m) c = normal(n) x = variable(n) op(dot(c,x), A*x+sum(abs(x)) <= b).solve() x2 = variable(n) y = variable(n) op(dot(c,x2), [A*x2+sum(y) <= b, -y <= x2, x2 <= y]).solve() print("\nDifference between two solutions %e" %nrm2(x.value - x2.value)) cvxopt-1.1.4/examples/doc/chap10/normappr.py0000644000175000017500000000124111674452555017751 0ustar sonnesonne# The norm and penalty approximation problems of section 10.5 (Examples). from cvxopt import normal, setseed from cvxopt.modeling import variable, op, max, sum setseed(0) m, n = 500, 100 A = normal(m,n) b = normal(m) x1 = variable(n) prob1=op(max(abs(A*x1+b))) prob1.solve() x2 = variable(n) prob2=op(sum(abs(A*x2+b))) prob2.solve() x3 = variable(n) prob3=op(sum(max(0, abs(A*x3+b)-0.75, 2*abs(A*x3+b)-2.25))) prob3.solve() try: import pylab except ImportError: pass else: pylab.subplot(311) pylab.hist(A*x1.value + b, m/5) pylab.subplot(312) pylab.hist(A*x2.value + b, m/5) pylab.subplot(313) pylab.hist(A*x3.value + b, m/5) pylab.show() cvxopt-1.1.4/examples/doc/chap4/0000755000175000017500000000000011674452555015466 5ustar sonnesonnecvxopt-1.1.4/examples/doc/chap4/acent.py0000644000175000017500000000337611674452555017143 0ustar sonnesonne# The analytic centering example at the end of chapter 4 (The LAPACK # interface). from cvxopt import matrix, log, mul, div, blas, lapack, base from math import sqrt def acent(A,b): """ Computes analytic center of A*x <= b with A m by n of rank n. We assume that b > 0 and the feasible set is bounded. """ MAXITERS = 100 ALPHA = 0.01 BETA = 0.5 TOL = 1e-8 ntdecrs = [] m, n = A.size x = matrix(0.0, (n,1)) H = matrix(0.0, (n,n)) for iter in range(MAXITERS): # Gradient is g = A^T * (1./(b-A*x)). d = (b-A*x)**-1 g = A.T * d # Hessian is H = A^T * diag(1./(b-A*x))^2 * A. Asc = mul( d[:,n*[0]], A) blas.syrk(Asc, H, trans='T') # Newton step is v = H^-1 * g. v = -g lapack.posv(H, v) # Directional derivative and Newton decrement. lam = blas.dot(g, v) ntdecrs += [ sqrt(-lam) ] print("%2d. Newton decr. = %3.3e" %(iter,ntdecrs[-1])) if ntdecrs[-1] < TOL: return x, ntdecrs # Backtracking line search. y = mul(A*v, d) step = 1.0 while 1-step*max(y) < 0: step *= BETA while True: if -sum(log(1-step*y)) < ALPHA*step*lam: break step *= BETA x += step*v # Generate an analytic centering problem # # -b1 <= Ar*x <= b2 # # with random mxn Ar and random b1, b2. m, n = 500, 500 Ar = base.normal(m,n); A = matrix([Ar, -Ar]) b = base.uniform(2*m,1) x, ntdecrs = acent(A, b) try: import pylab except ImportError: pass else: pylab.semilogy(range(len(ntdecrs)), ntdecrs, 'o', range(len(ntdecrs)), ntdecrs, '-') pylab.xlabel('Iteration number') pylab.ylabel('Newton decrement') pylab.show() cvxopt-1.1.4/examples/filterdemo/0000755000175000017500000000000011674452555016054 5ustar sonnesonnecvxopt-1.1.4/examples/filterdemo/README0000644000175000017500000000067511674452555016744 0ustar sonnesonneThe filterdemo computes a FIR lowpass filter by solving a linear program. It solves a discretization of the problem minimize d2 subject to -1/d1 <= H(wk) <= d1, 0 <= w <= wc max(abs(H(wk))) <= d2, ws <= w <= pi where H(w) = h_0 + sum_{i=1}^{n-1} h_i*cos(2*pi/n*i*w). The variables are h and d2. 'filterdemo_cli' uses a simple a simple command-line interface. 'filterdemo_gui' uses a graphical user interface based on GTK. cvxopt-1.1.4/examples/filterdemo/filterdemo_gui0000755000175000017500000001631611674452555021007 0ustar sonnesonne#!/usr/bin/python from cvxopt import matrix, cos from cvxopt.solvers import options from cvxopt.modeling import op, variable, max from math import log10, pi, floor import gtk import matplotlib matplotlib.use('GTK') # or 'GTK' from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas import pylab def frange(a,b,N): return [ a+k*float((b-a))/N for k in range(N) ] def design_lowpass(N, d1, wc, ws, solver=None, Q=50): h = variable(N+1) d1 = 10**(d1/20.0) # convert from dB n = matrix(range(N+1), (1,N+1), 'd') n1 = int(round(N*Q*wc/pi)); G1 = cos(matrix(frange(0,wc,n1))*n) n2 = int(round(N*Q*(pi-ws)/pi)); G2 = cos(matrix(frange(ws,pi,n2))*n) op(max(abs(G2*h)), [G1*h <= d1, G1*h >= 1.0/d1]).solve(solver=solver) return (h.value, max(abs(G2*h.value))) class MainGUI: def check_values(self, param=None): page = self.nb.get_current_page() if page>=0: N = self.fo_spinner.get_value_as_int() co = self.co_spinner.get_value() sb = self.sb_spinner.get_value() pr = self.pr_spinner.get_value() if (co == self.tabs[page][1] and sb == self.tabs[page][2] and pr == self.tabs[page][3] and N == self.tabs[page][4]): self.compute_filter.set_sensitive(False) else: self.compute_filter.set_sensitive(True) def change_co(self, param1): self.sb_spinner.set_range(param1.get_value()+0.01, self.sb_spinner.get_range()[1]); self.check_values() def change_sb(self, param1): self.co_spinner.set_range(0.1, param1.get_value()-0.01); self.check_values() def switch_page(self, page, page_num, page_int, notebook): if len(self.tabs)>page_int: self.tabs[page_int][0].draw() self.co_spinner.set_value(self.tabs[page_int][1]) self.sb_spinner.set_value(self.tabs[page_int][2]) self.pr_spinner.set_value(self.tabs[page_int][3]) self.fo_spinner.set_value(self.tabs[page_int][4]) self.compute_filter.set_sensitive(False) def new_tab(self, button, notebook): N = self.fo_spinner.get_value_as_int() co = self.co_spinner.get_value() sb = self.sb_spinner.get_value() pr = self.pr_spinner.get_value() try: h, d2 = design_lowpass(N, pr, pi*co, pi*sb) except: x = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, \ type=gtk.MESSAGE_WARNING, message_format= \ "Please tighten the filter specifications."); x.run() return w = matrix(frange(0,pi,N*50)); C = cos(w*matrix(range(N+1),(1,N+1))); fig = pylab.figure() canvas = FigureCanvas(fig) # a gtk.DrawingArea ax = fig.add_subplot(111) ylim = [floor((20*log10(d2)-30)/100)*100,10] ax.plot(list(w/pi),[20*log10(abs(x)) for x in C*h]) ax.plot(2*[co],[-pr,ylim[0]],'g--') ax.plot(2*[co],[10,pr],'g--') ax.plot(2*[sb],[10,20*log10(d2)],'g--') ax.plot([sb, 1],2*[20*log10(d2)],'g--') ax.plot([0, co],2*[-pr],'g--') ax.plot([0, co],2*[pr],'g--') pylab.setp(ax,ylim=ylim) pylab.setp(ax,xlabel="Normalized frequency") pylab.setp(ax,ylabel="Attenuation [dB]") ax.grid() canvas.show() notebook.append_page(canvas) notebook.set_current_page(notebook.get_n_pages()-1) self.tabs.append([canvas,co,sb,pr,N]) self.compute_filter.set_sensitive(False) def close_tab(self, button, notebook): page = notebook.get_current_page() notebook.remove_page(page) if page>=0: del(self.tabs[page]) # Need to refresh the widget -- # This forces the widget to redraw itself. notebook.queue_draw_area(0,0,-1,-1) if notebook.get_n_pages() == 0: self.compute_filter.set_sensitive(True) def delete(self, widget, event=None): gtk.main_quit() return gtk.FALSE def __init__(self): window = gtk.Window (gtk.WINDOW_TOPLEVEL) window.connect("delete_event", self.delete) window.set_default_size(600, 400) window.set_border_width(10) table = gtk.Table(4,6,False) window.add(table) # Create a new notebook, place the position of the tabs notebook = gtk.Notebook() notebook.connect("switch-page", self.switch_page, notebook) notebook.set_tab_pos(gtk.POS_BOTTOM) table.attach(notebook, 0,6,0,1) notebook.show() self.nb = notebook self.tabs = [] # Stopband frequency co_label = gtk.Label("Cutoff") co_label.show() table.attach(co_label, 0,1,1,2, gtk.SHRINK, gtk.SHRINK) co_adj = gtk.Adjustment(0.25, 0.1, 0.34, 0.01, 0, 0) self.co_spinner = gtk.SpinButton(co_adj, 0.0, 2) self.co_spinner.set_numeric(True) self.co_spinner.connect("value-changed", self.change_co); self.co_spinner.show() table.attach(self.co_spinner, 0,1,2,3, gtk.SHRINK, gtk.SHRINK) # Stopband frequency sb_label = gtk.Label("Stopband") sb_label.show() table.attach(sb_label, 1,2,1,2, gtk.SHRINK, gtk.SHRINK) sb_adj = gtk.Adjustment(0.35, 0.26, 0.5, 0.01, 0, 0) self.sb_spinner = gtk.SpinButton(sb_adj, 0.0, 2) self.sb_spinner.set_numeric(True) self.sb_spinner.connect("value-changed", self.change_sb); self.sb_spinner.show() table.attach(self.sb_spinner, 1,2,2,3, gtk.SHRINK, gtk.SHRINK) # Passband ripple pr_label = gtk.Label("Passband ripple") pr_label.show() table.attach(pr_label, 2,3,1,2, gtk.SHRINK, gtk.SHRINK) pr_adj = gtk.Adjustment(1, 0.3, 3, 0.01, 0, 0) self.pr_spinner = gtk.SpinButton(pr_adj, 0.0, 2) self.pr_spinner.connect("value-changed", self.check_values); self.pr_spinner.set_numeric(True) self.pr_spinner.show() table.attach(self.pr_spinner, 2,3,2,3, gtk.SHRINK, gtk.SHRINK) # Filter order fo_label = gtk.Label("Filter order") fo_label.show() table.attach(fo_label, 3,4,1,2, gtk.SHRINK, gtk.SHRINK) fo_adj = gtk.Adjustment(10, 5, 50, 1, 0, 0) self.fo_spinner = gtk.SpinButton(fo_adj, 0.0, 0) self.fo_spinner.connect("value-changed", self.check_values); self.fo_spinner.set_numeric(True) self.fo_spinner.show() table.attach(self.fo_spinner, 3,4,2,3, gtk.SHRINK, gtk.SHRINK) # Buttons button = gtk.Button("compute filter") button.connect("clicked", self.new_tab, notebook) table.attach(button, 4,5,2,3, gtk.FILL, gtk.SHRINK) button.show() self.compute_filter = button button = gtk.Button("close tab") button.connect("clicked", self.close_tab, notebook) table.attach(button, 5,6,2,3, gtk.FILL, gtk.SHRINK) button.show() table.show() window.show() options['show_progress']=False gui = MainGUI() gtk.main() cvxopt-1.1.4/examples/filterdemo/filterdemo_cli0000755000175000017500000000712511674452555020770 0ustar sonnesonne#!/usr/bin/python import getopt, sys from cvxopt import matrix from cvxopt.solvers import options from cvxopt.modeling import op, variable, max from math import cos, log10, pi import pygtk pygtk.require('2.0') import gtk import matplotlib matplotlib.use('GTKAgg') # or 'GTK' from matplotlib.backends.backend_gtk import FigureCanvasGTK as FigureCanvas import pylab def frange(a,b,N): return [ a+k*float((b-a))/N for k in range(N) ] def design_lowpass(N, d1, wc, ws, solver=None, Q=50): h = variable(N+1) d1 = 10**(d1/20.0) # convert from dB n1 = int(round(N*Q*wc/pi)); w1 = matrix(frange(0,wc,n1)) G1 = matrix([cos(wi*j) for j in range(N+1) for wi in w1], (n1,N+1)) n2 = int(round(N*Q*(pi-ws)/pi)); w2 = matrix(frange(ws,pi,n2)) G2 = matrix([cos(wi*j) for j in range(N+1) for wi in w2], (n2,N+1)) options['show_progress'] = 0 options['LPX_K_MSGLEV'] = 0 options['MSK_IPAR_LOG']= 0 op(max(abs(G2*h)), [G1*h <= d1, G1*h >= 1.0/d1]).solve(solver=solver) return (h.value, max(abs(G2*h.value))) def make_plot(h, d2, co, sb, pr, N, output=None): w = matrix(frange(0,pi,N*50)); C = w*matrix(range(N+1), (1,N+1), 'd'); for i in range(len(C)): C[i] = cos(C[i]) fig = pylab.figure() ax = fig.add_subplot(111) ylim = [round((20*log10(d2)-40)/10)*10,10] ax.plot(list(w/pi),[20*log10(abs(x)) for x in C*h]) ax.plot(2*[co],[-pr,ylim[0]],'g--') ax.plot(2*[co],[10,pr],'g--') ax.plot(2*[sb],[10,20*log10(d2)],'g--') ax.plot([sb, 1],2*[20*log10(d2)],'g--') ax.plot([0, co],2*[-pr],'g--') ax.plot([0, co],2*[pr],'g--') pylab.setp(ax,ylim=ylim) pylab.setp(ax,xlabel="Normalized frequency") pylab.setp(ax,ylabel="Attenuation [dB]") ax.grid() def usage(): print(""" Usage: filterdemo_cli --cutoff=CO --stopband=SB --ripple=RP --order=N [options] Arguments: CO: normalized cutoff frequency SB: normalized stopband frequency, 0.1 <= co < sb-0.1 <= 0.5, RP: maximum passband ripple in dB, 0.01 <= rp <= 3, N : filterorder, 5 <= or <= 50. Options: --solver = SOLVER One of default, mosek, glpk --output = FILENAME Output filename. """) sys.exit(2) def main(): try: opts, args = getopt.getopt(sys.argv[1:], "", ['cutoff=', 'stopband=', 'ripple=', 'order=', 'solver=', 'output=']) except getopt.GetoptError: usage() if opts==[]: usage() co, sb, pr, N, output = [None]*5 solver = "default" try: for o, a in opts: if o == "--cutoff": co = float(a); if o == "--stopband": sb = float(a); if o == "--ripple": pr = float(a); if o == "--order": N = int(a); if o == "--solver": solver = a; if o == "--output": output = a; except: usage() if None in [co, sb, pr, N]: usage() if not (0.1 <= co < sb-0.01+1E-8 <= 0.5): print("invalid cutoff and stopband frequencies") usage() if not (0.01 <= pr <= 3): print("invalid value of passband ripple") usage() if not (5 <= N <= 50): print("invalid filterorder") usage() if not solver in ['default','mosek','glpk']: print("invalid solver") usage() try: [h, d2] = design_lowpass(N, pr, co*pi, sb*pi, solver) except: print("Please tighten filter specifications.") sys.exit(2) make_plot(h, d2, co, sb, pr, N, output); if (output != None): savefig(output) pylab.show() if __name__ == "__main__": main() cvxopt-1.1.4/examples/book/0000755000175000017500000000000011674452555014654 5ustar sonnesonnecvxopt-1.1.4/examples/book/README0000644000175000017500000000041111674452555015530 0ustar sonnesonneThis directory contains examples from the book "Convex Optimization" by Boyd and Vandenberghe (Cambridge University Press, 2004, and www.stanford.edu/~boyd/cvxbook). The scripts require the plotting library Matplotlib, available at matplotlib.sourceforge.net. cvxopt-1.1.4/examples/book/chap7/0000755000175000017500000000000011674452555015656 5ustar sonnesonnecvxopt-1.1.4/examples/book/chap7/logreg.py0000644000175000017500000000225211674452555017510 0ustar sonnesonne# Figures 7.1, page 355. # Logistic regression. import pickle from cvxopt import solvers, matrix, spdiag, log, exp, div #solvers.options['show_progress'] = False data = pickle.load(open("logreg.bin", 'rb')) u, y = data['u'], data['y'] # minimize sum_{y_k = 1} (a*uk + b) + sum log (1 + exp(a*u + b)) # # two variables a, b. m = u.size[0] A = matrix(1.0, (m,2)) A[:,0] = u c = -matrix([sum( uk for uk, yk in zip(u,y) if yk ), sum(y) ]) # minimize c'*x + sum log (1 + exp(A*x)) # # variable x (2). def F(x=None, z=None): if x is None: return 0, matrix(0.0, (2,1)) w = exp(A*x) f = c.T*x + sum(log(1+w)) grad = c + A.T * div(w, 1+w) if z is None: return f, grad.T H = A.T * spdiag(div(w,(1+w)**2)) * A return f, grad.T, z[0]*H sol = solvers.cp(F) a, b = sol['x'][0], sol['x'][1] try: import pylab except ImportError: pass else: pylab.figure(facecolor='w') nopts = 200 pts = -1.0 + 12.0/nopts * matrix(list(range(nopts))) w = exp(a*pts + b) pylab.plot(u, y, 'o', pts, div(w, 1+w), '-') pylab.title('Logistic regression (fig. 7.1)') pylab.axis([-1, 11, -0.1, 1.1]) pylab.xlabel('u') pylab.ylabel('Prob(y=1)') pylab.show() cvxopt-1.1.4/examples/book/chap7/expdesign.py0000644000175000017500000001166611674452555020230 0ustar sonnesonne# Figures 7.9-12, pages 389-390. # Experiment design. from math import pi, log, sqrt from cvxopt import blas, lapack, solvers from cvxopt import matrix, spmatrix, spdiag, mul, cos, sin #solvers.options['show_progress'] = False try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True V = matrix([-2.1213, 2.1213, -2.2981, 1.9284, -2.4575, 1.7207, -2.5981, 1.5000, -2.7189, 1.2679, -2.8191, 1.0261, -2.8978, 0.7765, -2.9544, 0.5209, -2.9886, 0.2615, -3.0000, 0.0000, 1.5000, 0.0000, 1.4772, -0.2605, 1.4095, -0.5130, 1.2990, -0.7500, 1.1491, -0.9642, 0.9642, -1.1491, 0.7500, -1.2990, 0.5130, -1.4095, 0.2605, -1.4772, 0.0000, -1.5000 ], (2,20)) n = V.size[1] G = spmatrix(-1.0, range(n), range(n)) h = matrix(0.0, (n,1)) A = matrix(1.0, (1,n)) b = matrix(1.0) # D-design # # minimize f(x) = -log det V*diag(x)*V' # subject to x >= 0 # sum(x) = 1 # # The gradient and Hessian of f are # # gradf = -diag(V' * X^-1 * V) # H = (V' * X^-1 * V)**2. # # where X = V * diag(x) * V'. def F(x=None, z=None): if x is None: return 0, matrix(1.0, (n,1)) X = V * spdiag(x) * V.T L = +X try: lapack.potrf(L) except ArithmeticError: return None f = - 2.0 * (log(L[0,0]) + log(L[1,1])) W = +V blas.trsm(L, W) gradf = matrix(-1.0, (1,2)) * W**2 if z is None: return f, gradf H = matrix(0.0, (n,n)) blas.syrk(W, H, trans='T') return f, gradf, z[0] * H**2 xd = solvers.cp(F, G, h, A = A, b = b)['x'] if pylab_installed: pylab.figure(1, facecolor='w', figsize=(6,6)) pylab.plot(V[0,:], V[1,:],'ow', [0], [0], 'k+') I = [ k for k in range(n) if xd[k] > 1e-5 ] pylab.plot(V[0,I], V[1,I],'or') # Enclosing ellipse is {x | x' * (V*diag(xe)*V')^-1 * x = sqrt(2)} nopts = 1000 angles = matrix( [ a*2.0*pi/nopts for a in range(nopts) ], (1,nopts) ) circle = matrix(0.0, (2,nopts)) circle[0,:], circle[1,:] = cos(angles), sin(angles) W = V * spdiag(xd) * V.T lapack.potrf(W) ellipse = sqrt(2.0) * circle blas.trmm(W, ellipse) if pylab_installed: pylab.plot(ellipse[0,:].T, ellipse[1,:].T, 'k--') pylab.axis([-5, 5, -5, 5]) pylab.title('D-optimal design (fig. 7.9)') pylab.axis('off') # E-design. # # maximize w # subject to w*I <= V*diag(x)*V' # x >= 0 # sum(x) = 1 novars = n+1 c = matrix(0.0, (novars,1)) c[-1] = -1.0 Gs = [matrix(0.0, (4,novars))] for k in range(n): Gs[0][:,k] = -(V[:,k]*V[:,k].T)[:] Gs[0][[0,3],-1] = 1.0 hs = [matrix(0.0, (2,2))] Ge = matrix(0.0, (n, novars)) Ge[:,:n] = G Ae = matrix(n*[1.0] + [0.0], (1,novars)) sol = solvers.sdp(c, Ge, h, Gs, hs, Ae, b) xe = sol['x'][:n] Z = sol['zs'][0] mu = sol['y'][0] if pylab_installed: pylab.figure(2, facecolor='w', figsize=(6,6)) pylab.plot(V[0,:], V[1,:],'ow', [0], [0], 'k+') I = [ k for k in range(n) if xe[k] > 1e-5 ] pylab.plot(V[0,I], V[1,I],'or') # Enclosing ellipse follows from the solution of the dual problem: # # minimize mu # subject to diag(V'*Z*V) <= mu*1 # Z >= 0 lapack.potrf(Z) ellipse = sqrt(mu) * circle blas.trsm(Z, ellipse, transA='T') if pylab_installed: pylab.plot(ellipse[0,:].T, ellipse[1,:].T, 'k--') pylab.axis([-5, 5, -5, 5]) pylab.title('E-optimal design (fig. 7.10)') pylab.axis('off') # A-design. # # minimize tr (V*diag(x)*V')^{-1} # subject to x >= 0 # sum(x) = 1 # # minimize tr Y # subject to [ V*diag(x)*V', I ] # [ I, Y ] >= 0 # x >= 0 # sum(x) = 1 novars = 3 + n c = matrix(0.0, (novars,1)) c[[-3, -1]] = 1.0 Gs = [matrix(0.0, (16, novars))] for k in range(n): Gk = matrix(0.0, (4,4)) Gk[:2,:2] = -V[:,k] * V[:,k].T Gs[0][:,k] = Gk[:] Gs[0][10,-3] = -1.0 Gs[0][11,-2] = -1.0 Gs[0][15,-1] = -1.0 hs = [matrix(0.0, (4,4))] hs[0][2,0] = 1.0 hs[0][3,1] = 1.0 Ga = matrix(0.0, (n, novars)) Ga[:,:n] = G Aa = matrix(n*[1.0] + 3*[0.0], (1,novars)) sol = solvers.sdp(c, Ga, h, Gs, hs, Aa, b) xa = sol['x'][:n] Z = sol['zs'][0][:2,:2] mu = sol['y'][0] if pylab_installed: pylab.figure(3, facecolor='w', figsize = (6,6)) pylab.plot(V[0,:], V[1,:],'ow', [0], [0], 'k+') I = [ k for k in range(n) if xa[k] > 1e-5 ] pylab.plot(V[0,I], V[1,I],'or') # Enclosing ellipse follows from the solution of the dual problem: # # maximize -mu - 2 * tr Z12 # subject to diag(V'*Z11*V) <= mu*1 # [ Z11, Z12 ] # [ Z21, I ] >= 0 lapack.potrf(Z) ellipse = sqrt(mu) * circle blas.trsm(Z, ellipse, transA='T') if pylab_installed: pylab.plot(ellipse[0,:].T, ellipse[1,:].T, 'k--') pylab.axis([-5, 5, -5, 5]) pylab.title('A-optimal design (fig. 7.11)') pylab.axis('off') pylab.show() cvxopt-1.1.4/examples/book/chap7/chernoff.py0000644000175000017500000000611611674452555020026 0ustar sonnesonne# Figure 7.8, page 384. # Chernoff lower bound. from cvxopt import matrix, mul, exp, normal, solvers, blas #solvers.options['show_progress'] = False # Extreme points and inequality description of Voronoi region around # first symbol (at the origin). m = 6 V = matrix([ 1.0, 1.0, -1.0, 2.0, -2.0, 1.0, -2.0, -1.0, 0.0, -2.0, 1.5, -1.0, 1.0, 1.0 ], (2,m+1)) # A and b are lists with the inequality descriptions of the regions. A = [ matrix( [-(V[1,:m] - V[1,1:]), V[0,:m] - V[0,1:]] ).T ] b = [ mul(A[0], V[:,:m].T) * matrix(1.0, (2,1)) ] # List of symbols. C = [ matrix(0.0, (2,1)) ] + \ [ 2.0 * b[0][k] / blas.nrm2(A[0][k,:])**2 * A[0][k,:].T for k in range(m) ] # Voronoi set around C[1] A += [ matrix(0.0, (3,2)) ] b += [ matrix(0.0, (3,1)) ] A[1][0,:] = -A[0][0,:] b[1][0] = -b[0][0] A[1][1,:] = (C[m] - C[1]).T b[1][1] = 0.5 * A[1][1,:] * ( C[m] + C[1] ) A[1][2,:] = (C[2] - C[1]).T b[1][2] = 0.5 * A[1][2,:] * ( C[2] + C[1] ) # Voronoi set around C[2], ..., C[5] for k in range(2, 6): A += [ matrix(0.0, (3,2)) ] b += [ matrix(0.0, (3,1)) ] A[k][0,:] = -A[0][k-1,:] b[k][0] = -b[0][k-1] A[k][1,:] = (C[k-1] - C[k]).T b[k][1] = 0.5 * A[k][1,:] * ( C[k-1] + C[k] ) A[k][2,:] = (C[k+1] - C[k]).T b[k][2] = 0.5 * A[k][2,:] * ( C[k+1] + C[k] ) # Voronoi set around C[6] A += [ matrix(0.0, (3,2)) ] b += [ matrix(0.0, (3,1)) ] A[6][0,:] = -A[0][5,:] b[6][0] = -b[0][5] A[6][1,:] = (C[1] - C[6]).T b[6][1] = 0.5 * A[6][1,:] * ( C[1] + C[6] ) A[6][2,:] = (C[5] - C[6]).T b[6][2] = 0.5 * A[6][2,:] * ( C[5] + C[6] ) # For regions k=1, ..., 6, let pk be the optimal value of # # minimize x'*x # subject to A*x <= b. # # The Chernoff upper bound is 1.0 - sum exp( - pk / (2 sigma^2)). P = matrix([1.0, 0.0, 0.0, 1.0], (2,2)) q = matrix(0.0, (2,1)) optvals = matrix([ blas.nrm2( solvers.qp(P, q, A[k], b[k] )['x'] )**2 for k in range(1,7) ]) nopts = 200 sigmas = 0.2 + (0.5 - 0.2)/nopts * matrix(list(range(nopts)), tc='d') bnds = [ 1.0 - sum( exp( - optvals / (2*sigma**2) )) for sigma in sigmas] try: import pylab except ImportError: pass else: pylab.figure(facecolor='w') pylab.plot(sigmas, bnds, '-') pylab.axis([0.2, 0.5, 0.9, 1.0]) pylab.title('Chernoff lower bound (fig. 7.8)') pylab.xlabel('sigma') pylab.ylabel('Probability of correct detection') pylab.show() if 0: # uncomment out for the Monte Carlo estimation. N = 100000 mcest = [] ones = matrix(1.0, (1,m)) for sigma in sigmas: X = sigma * normal(2, N) S = b[0][:,N*[0]] - A[0]*X S = ones * (S - abs(S)) mcest += [ N - len(filter(lambda x: x < 0.0, S)) ] pylab.figure(facecolor='w') pylab.plot(sigmas, bnds, '-', sigmas, (1.0/N)*matrix(mcest), '--') pylab.plot(sigmas, bnds, '-') pylab.axis([0.2, 0.5, 0.9, 1.0]) pylab.title('Chernoff lower bound (fig. 7.8)') pylab.xlabel('sigma') pylab.ylabel('Probability of correct detection') pylab.show() cvxopt-1.1.4/examples/book/chap7/probbounds.py0000644000175000017500000001501511674452555020407 0ustar sonnesonne# Figures 7.6 and 7.7, page 383. # Chebyshev bounds. from math import pi, sqrt from cvxopt import matrix, spmatrix, mul, cos, sin, solvers, blas, lapack #solvers.options['show_progress'] = False try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True # Extreme points and inequality description of Voronoi region around # first symbol (0,0). m = 6 V = matrix([ 1.0, 1.0, -1.0, 2.0, -2.0, 1.0, -2.0, -1.0, 0.0, -2.0, 1.5, -1.0, 1.0, 1.0 ], (2,m+1)) A0 = matrix([-(V[1,:m] - V[1,1:]), V[0,:m] - V[0,1:]]).T b0 = mul(A0, V[:,:m].T) * matrix(1.0, (2,1)) # List of symbols. C = [ matrix(0.0, (2,1)) ] + \ [ 2.0 * b0[k] / blas.nrm2(A0[k,:])**2 * A0[k,:].T for k in range(m) ] # Voronoi set around C[1] A1, b1 = matrix(0.0, (3,2)), matrix(0.0, (3,1)) A1[0,:] = -A0[0,:] b1[0] = -b0[0] A1[1,:] = (C[m] - C[1]).T b1[1] = 0.5 * A1[1,:] * ( C[m] + C[1] ) A1[2,:] = (C[2] - C[1]).T b1[2] = 0.5 * A1[2,:] * ( C[2] + C[1] ) # Voronoi set around C[2] A2, b2 = matrix(0.0, (3,2)), matrix(0.0, (3,1)) A2[0,:] = -A0[1,:] b2[0] = -b0[1] A2[1,:] = (C[1] - C[2]).T b2[1] = 0.5 * A2[1,:] * ( C[1] + C[2] ) A2[2,:] = (C[3] - C[2]).T b2[2] = 0.5 * A2[2,:] * ( C[3] + C[2] ) def cheb(A, b, Sigma): # Calculates Chebyshev lower bound on Prob(A*x <= b) where # x in R^2 has mean zero and covariance Sigma. # # maximize 1 - tr(Sigma*P) - r # subject to [ P, q - (tauk/2)*ak ] # [ (q - (tauk/2)*ak)', r - 1 + tauk*bk ] >= 0, # k = 0,...,m-1 # [ P, q ] # [ q', r ] >= 0 # tauk >= 0, k=0,...,m-1. # # variables P[0,0], P[1,0], P[1,1], q[0], q[1], r, tau[0], ..., # tau[m-1]. m = A.size[0] novars = 3 + 2 + 1 + m # Cost function. c = matrix(0.0, (novars,1)) c[0], c[1], c[2] = Sigma[0,0], 2*Sigma[1,0], Sigma[1,1] c[5] = 1.0 Gs = [ spmatrix([],[],[], (9,novars)) for k in range(m+1) ] # Coefficients of P, q, r in LMI constraints. for k in range(m+1): Gs[k][0,0] = -1.0 # P[0,0] Gs[k][1,1] = -1.0 # P[1,0] Gs[k][4,2] = -1.0 # P[1,1] Gs[k][2,3] = -1.0 # q[0] Gs[k][5,4] = -1.0 # q[1] Gs[k][8,5] = -1.0 # r # Coefficients of tau. for k in range(m): Gs[k][2, 6+k] = 0.5 * A[k,0] Gs[k][5, 6+k] = 0.5 * A[k,1] Gs[k][8, 6+k] = -b[k] hs = [ matrix(8*[0.0] + [-1.0], (3,3)) for k in range(m) ] + \ [ matrix(0.0, (3,3)) ] # Constraints tau >= 0. Gl, hl = spmatrix(-1.0, range(m), range(6,6+m)), matrix(0.0, (m,1)) sol = solvers.sdp(c, Gl, hl, Gs, hs) P = matrix(sol['x'][[0,1,1,2]], (2,2)) q = matrix(sol['x'][[3,4]], (2,1)) r = sol['x'][5] bound = 1.0 - Sigma[0]*P[0] - 2*Sigma[1]*P[1] - Sigma[3]*P[3] - r # Worst-case distribution from dual solution. X = [ Z[2,:2].T / Z[2,2] for Z in sol['zs'] if Z[2,2] > 1e-5 ] return bound, P, q, r, X # Compute bound for s0 with sigma = 1.0. # Write ellipse {x | x'*P*x + 2*q'*x + r = 1} in the form # {xc + L^{-T}*u | ||u||_2 = 1} Sigma = matrix([1.0, 0.0, 0.0, 1.0], (2,2)) bnd, P, q, r, X = cheb(A0, b0, Sigma) xc = -q L = +P lapack.posv(L, xc) L /= sqrt(1 - r - blas.dot(q, xc)) if pylab_installed: def makefig1(): pylab.figure(1, facecolor='w', figsize=(6,6)) pylab.plot(V[0,:].T, V[1,:].T, 'b-') nopts = 1000 angles = matrix( [a*2.0*pi/nopts for a in range(nopts) ], (1,nopts) ) circle = matrix(0.0, (2,nopts)) circle[0,:], circle[1,:] = cos(angles), sin(angles) for k in range(len(C)): c = C[k] pylab.plot([c[0]], [c[1]], 'ow') pylab.text(c[0], c[1], "s%d" %k) pylab.plot(c[0] + circle[0,:].T, c[1]+circle[1,:].T, 'g:') if k >= 1: v = V[:,k-1] if k==1: dir = 0.5 * (C[k] + C[-1]) - v else: dir = 0.5 * (C[k] + C[k-1]) - v pylab.plot([v[0], v[0] + 5*dir[0]], [v[1], v[1] + 5*dir[1]], 'b-') ellipse = +circle blas.trsm(L, ellipse, transA='T') pylab.plot(xc[0] + ellipse[0,:].T, xc[1]+ellipse[1,:].T, 'r-') for Xk in X: pylab.plot([Xk[0]], [Xk[1]], 'ro') pylab.axis([-5, 5, -5, 5]) pylab.title('Geometrical interpretation of Chebyshev bound (fig. 7.7)') pylab.axis('off') makefig1() #print("Close figure to continue.") #pylab.show() # Compute bounds for s0 with sigma in [0,2.5] nosigmas = 150 sigmas = 0.001 + (2.5 - 0.001) / nosigmas * matrix(list(range(nosigmas)), tc='d') I = matrix([1.0, 0.0, 0.0, 1.0], (2,2)) print("Computing lower bounds for symbol 0 ...") bnds0 = [ cheb(A0, b0, sigma**2*I)[0] for sigma in sigmas ] if pylab_installed: pylab.figure(2,facecolor='w') pylab.plot(sigmas, bnds0) pylab.axis([0, 2.5, 0.0, 1.0]) pylab.title('Chebyshev lower bounds (fig 7.6)') pylab.text(sigmas[nosigmas/2], bnds0[nosigmas/2], 's0') pylab.xlabel('sigma') pylab.ylabel('Probability of correct detection') #print("Close figure to continue.") #pylab.show() # Bounds for s1. b1 -= A1*C[1] # put s1 at the origin print("Computing lower bounds for symbol 1 ...") bnds1 = [ cheb(A1, b1, sigma**2*I)[0] for sigma in sigmas ] if pylab_installed: pylab.figure(2,facecolor='w') pylab.plot(sigmas,bnds0, '-b', sigmas, bnds1, 'r') pylab.axis([0, 2.5, 0.0, 1.0]) pylab.title('Chebyshev lower bounds (fig 7.6)') pylab.text(sigmas[nosigmas/2], bnds0[nosigmas/2], 's0') pylab.text(sigmas[nosigmas/2], bnds1[nosigmas/2], 's1') pylab.xlabel('sigma') pylab.ylabel('Probability of correct detection') #print("Close figure to continue.") #pylab.show() # Bounds for s2. b2 -= A2*C[2] # put s2 at the origin print("Computing lower bounds for symbol 2 ...") bnds2 = [ cheb(A2, b2, sigma**2*I)[0] for sigma in sigmas ] if pylab_installed: makefig1() pylab.figure(2,facecolor='w') pylab.plot(sigmas,bnds0, '-b', sigmas, bnds1, 'r', sigmas, bnds2, 'g') pylab.axis([0, 2.5, 0.0, 1.0]) pylab.title('Chebyshev lower bounds (fig 7.6)') pylab.text(sigmas[nosigmas/2], bnds0[nosigmas/2], 's0') pylab.text(sigmas[nosigmas/2], bnds1[nosigmas/2], 's1') pylab.text(sigmas[nosigmas/2], bnds2[nosigmas/2], 's2') pylab.xlabel('sigma') pylab.ylabel('Probability of correct detection') pylab.show() cvxopt-1.1.4/examples/book/chap7/logreg.bin0000644000175000017500000000507111674452555017632 0ustar sonnesonne(dp0 S'y' p1 ccvxopt.base matrix p2 ((lp3 I1 aI0 aI1 aI1 aI1 aI1 aI0 aI0 aI1 aI0 aI1 aI1 aI1 aI1 aI0 aI0 aI1 aI1 aI0 aI1 aI0 aI0 aI1 aI0 aI0 aI0 aI0 aI0 aI0 aI0 aI0 aI1 aI1 aI1 aI0 aI0 aI1 aI1 aI0 aI0 aI1 aI0 aI1 aI0 aI1 aI1 aI1 aI0 aI0 aI0 aI0 aI1 aI1 aI1 aI1 aI1 aI0 aI1 aI1 aI1 aI0 aI1 aI1 aI1 aI1 aI1 aI0 aI0 aI0 aI0 aI1 aI0 aI1 aI1 aI1 aI1 aI0 aI0 aI1 aI1 aI1 aI1 aI0 aI1 aI0 aI1 aI0 aI0 aI1 aI1 aI0 aI0 aI1 aI0 aI0 aI1 aI0 aI1 aI0 aI0 a(I100 I1 tp4 S'i' p5 tp6 Rp7 sS'u' p8 g2 ((lp9 F9.5012928514717547 aF2.3113851357428783 aF6.068425835417866 aF4.8598246870929973 aF8.9129896614890161 aF7.6209683302739473 aF4.5646766516834134 aF0.185036432482244 aF8.2140716429525327 aF4.4470336435319417 aF6.1543234810009473 aF7.9193703742703541 aF9.2181297074480248 aF7.382072458106653 aF1.7626614449461799 aF4.0570621306209551 aF9.3546969910760538 aF9.1690443991340764 aF4.1027020699094532 aF8.9364953091353367 aF0.5789130478426856 aF3.5286813221700037 aF8.1316649730375783 aF0.098613006609235609 aF1.3889088195694987 aF2.0276521856027316 aF1.9872174266148965 aF6.0379247919381926 aF2.7218792496996036 aF1.9881426776106215 aF0.15273927029036269 aF7.4678567656442931 aF4.450964322879468 aF9.3181457846166467 aF4.6599434167542402 aF4.1864946772750624 aF8.4622141782432454 aF5.2515249630517236 aF2.0264735765038728 aF6.7213746847428846 aF8.3811844505238682 aF0.19639513864817498 aF6.8127716128213534 aF3.7948101802799803 aF8.3179601760960651 aF5.028128839962509 aF7.0947139270338679 aF4.2889236534099675 aF3.0461736686939433 aF1.8965374754717499 aF1.9343115640521509 aF6.8222322359138357 aF3.02764400776609 aF5.4167385389808764 aF1.5087297614976465 aF6.9789848185986338 aF3.7837300051267109 aF8.6001160488681965 aF8.5365513066276772 aF5.9356291253968161 aF4.9655244970310282 aF8.9976917516960988 aF8.216291607353428 aF6.4491038419384434 aF8.1797434083924507 aF6.6022755644160238 aF3.4197061827021575 aF2.8972589585623814 aF3.411935694148835 aF5.3407901762660046 aF7.2711321692967692 aF3.0929015979095773 aF8.3849604493808059 aF5.6807246100777578 aF3.704135566321165 aF7.0273991324037688 aF5.4657115182910623 aF4.4488020467291216 aF6.9456724042554754 aF6.2131013079541342 aF7.9482108020092648 aF9.5684344844487708 aF5.2259034908070774 aF8.8014220741132725 aF1.729561412752366 aF9.7974689678884097 aF2.7144725864179984 aF2.5232934687399036 aF8.7574189981807429 aF7.373059884652557 aF1.3651874225970972 aF0.11756687353117969 aF8.9389796644525337 aF1.991380672057383 aF2.9872301210221446 aF6.6144257638232498 aF2.8440858974994461 aF4.6922428521100104 aF0.64781122963272486 aF9.8833493827763075 a(I100 I1 tp10 S'd' p11 tp12 Rp13 s.cvxopt-1.1.4/examples/book/chap7/maxent.py0000644000175000017500000000517111674452555017530 0ustar sonnesonne# Figures 7.2 and 7.3, pages 363 and 364. # Maximum entropy distribution. from cvxopt import solvers, blas, matrix, spmatrix, spdiag, log, div #solvers.options['show_progress'] = False # minimize p'*log p # subject to -0.1 <= a'*p <= 0.1 # 0.5 <= (a**2)'*p <= 0.6 # -0.3 <= (3*a**3 - 2*a)'*p <= -0.2 # 0.3 <= sum_{k:ak < 0} pk <= 0.4 # sum(p) = 1 # # a in R^100 is made of 100 equidistant points in [-1,1]. # The variable is p (100). n = 100 a = -1.0 + (2.0/(n-1)) * matrix(list(range(n)), (1,n)) I = [k for k in range(n) if a[k] < 0] G = matrix([-a, a, -a**2, a**2, -(3 * a**3 - 2*a), (3 * a**3 - 2*a), matrix(0.0, (2,n))]) G[6,I] = -1.0 G[7,I] = 1.0 h = matrix([0.1, 0.1, -0.5, 0.6, 0.3, -0.2, -0.3, 0.4 ]) A, b = matrix(1.0, (1,n)), matrix(1.0) # minimize x'*log x # subject to G*x <= h # A*x = b # # variable x (n). def F(x=None, z=None): if x is None: return 0, matrix(1.0, (n,1)) if min(x) <= 0: return None f = x.T*log(x) grad = 1.0 + log(x) if z is None: return f, grad.T H = spdiag(z[0] * x**-1) return f, grad.T, H sol = solvers.cp(F, G, h, A=A, b=b) p = sol['x'] # Upper/lower bounds on cumulative distribution. # # minimize/maximize ck'*p = sum_{i<=alphak} pi # subject to G*x <= h # A*x = b # x >= 0 # # Solve via dual: # # maximize -h'*z - b'*w # subject to +/- c + G'*z + A'*w >= 0 # z >= 0 # # with variables z (8), w (1). cc = matrix(0.0, (9,1)) cc[:8], cc[8] = h, b GG = spmatrix([], [], [], (n+8, 9)) GG[:n,:8] = -G.T GG[:n,8] = -A.T GG[n::n+9] = -1.0 hh = matrix(0.0, (n+8,n)) hh[:n,:] = matrix([i>=j for i in range(n) for j in range(n)], (n,n), 'd') # upper triangular matrix of ones l = [-blas.dot(cc, solvers.lp(cc, GG, hh[:,k])['x']) for k in range(n)] u = [blas.dot(cc, solvers.lp(cc, GG, -hh[:,k])['x']) for k in range(n)] def f(x,y): return x+2*[y] def stepl(x): return reduce(f, x[1:], [x[0]]) def stepr(x): return reduce(f, x[:-1], []) + [x[-1]] try: import pylab except ImportError: pass else: pylab.figure(1, facecolor='w') pylab.plot(stepl(a), stepr(p), '-') pylab.title('Maximum entropy distribution (fig. 7.2)') pylab.xlabel('a') pylab.ylabel('p = Prob(X = a)') pylab.figure(2, facecolor='w') pylab.plot([-1.0] + stepl(a), [0.0] + stepr(hh[:n,:].T*p), '-', [-1.0] + stepl(a), [0.0] + stepr(l), 'r-', [-1.0] + stepl(a), [0.0] + stepr(u), 'r-') pylab.title('Cumulative distribution (fig. 7.3)') pylab.xlabel('a') pylab.ylabel('Prob(X <= a)') pylab.axis([-1.1, 1.1, -0.1, 1.1]) pylab.show() cvxopt-1.1.4/examples/book/chap8/0000755000175000017500000000000011674452555015657 5ustar sonnesonnecvxopt-1.1.4/examples/book/chap8/linsep.py0000644000175000017500000000720611674452555017530 0ustar sonnesonne# Figures 8.10-12, page 426-429. # Approximate linear discrimination. import pickle from cvxopt import solvers, matrix, spmatrix, spdiag, log, exp, div from cvxopt.blas import dot from cvxopt.modeling import variable, op #solvers.options['show_progress'] = False try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True data = pickle.load(open("linsep.bin", 'rb')) X, Y = data['X'], data['Y'] n, N, M = X.size[0], X.size[1], Y.size[1] # Via linear programming. # # minimize sum(u) + sum(v) # subject to a'*X - b >= 1 - u # a'*Y - b <= -1 + v # u >= 0, v >= 0 a, b = variable(2), variable() u, v = variable(N), variable(M) op( sum(u)+sum(v), [X.T*a-b >= 1-u, Y.T*a-b <= -1+v, u>=0, v>=0] ).solve() a = a.value b = b.value if pylab_installed: pylab.figure(1, facecolor='w', figsize=(5,5)) pts = matrix([-10.0, 10.0], (2,1)) pylab.plot(X[0,:], X[1,:], 'ow', Y[0,:], Y[1,:], 'ok', pts, (b - a[0]*pts)/a[1], '-r', pts, (b+1.0 - a[0]*pts)/a[1], '--r', pts, (b-1.0 - a[0]*pts)/a[1], '--r' ) pylab.title('Separation via linear programming (fig. 8.10)') pylab.axis([-10, 10, -10, 10]) pylab.axis('off') pylab.xticks([]) pylab.yticks([]) # Support vector classifier. # # minimize t + gamma*(1'*u + 1'*v) # subject to a'*X - b >= 1 - u # a'*Y - b <= -1 + v # u >= 0, v >= 0 # [t*I a; a' t] >= 0 gamma = 0.1 nv = n + 2 + N + M # variables (a, b, t, u, v) ni = 2 * (N + M) c = matrix(0.0, (nv,1)) c[3], c[4:] = 1.0, gamma IN = spmatrix(1.0, range(N), range(N)) IM = spmatrix(1.0, range(M), range(M)) Gl = matrix(0.0, (ni, nv)) hl = matrix(0.0, (ni, 1)) Gl[:N, :n] = -X.T Gl[:N, n] = 1.0 Gl[:N, n+2:n+2+N] = -IN hl[:N] = -1.0 Gl[N:N+M, :n] = Y.T Gl[N:N+M, n] = -1.0 Gl[N:N+M, -M:] = -IM hl[N:N+M] = -1.0 Gl[N+M:N+M+N, n+2:n+2+N] = -IN Gl[N+M+N:, -M:] = -IM Gs = [spmatrix(0.0, [], [], (9, nv))] Gs[0][2,0] = -1.0 Gs[0][6,0] = -1.0 Gs[0][5,1] = -1.0 Gs[0][7,1] = -1.0 Gs[0][0,3] = -1.0 Gs[0][4,3] = -1.0 Gs[0][8,3] = -1.0 hs = [matrix(0.0, (3,3))] sol = solvers.sdp(c, Gl, hl, Gs, hs) a = sol['x'][:2] b = sol['x'][2] if pylab_installed: pylab.figure(2, facecolor='w', figsize=(5,5)) pts = matrix([-10.0, 10.0], (2,1)) pylab.plot(X[0,:], X[1,:], 'ow', Y[0,:], Y[1,:], 'ok', pts, (b - a[0]*pts)/a[1], '-r', pts, (b+1.0 - a[0]*pts)/a[1], '--r', pts, (b-1.0 - a[0]*pts)/a[1], '--r' ) pylab.title('Support vector classifier (fig. 8.11)') pylab.axis([-10, 10, -10, 10]) pylab.xticks([]) pylab.yticks([]) pylab.axis('off') # Via logistic modeling. # # minimize -sum(X'*a - b) + sum log (1 + exp([X';Y']*a - b)) A = matrix(0.0, (N+M,n+1)) A[:N,:n], A[N:,:n], A[:,n] = X.T, Y.T, -1.0 c = -(matrix(1.0, (1,N)) * A[:N,:]).T # minimize c'*x + sum log (1 + exp(A*x)) def F(x=None, z=None): if x is None: return 0, matrix(0.0, (n+1,1)) w = exp(A*x) f = dot(c,x) + sum(log(1+w)) grad = c + A.T * div(w, 1+w) if z is None: return matrix(f), grad.T H = A.T * spdiag(div(w,(1+w)**2)) * A return matrix(f), grad.T, z[0]*H sol = solvers.cp(F) a, b = sol['x'][:2], sol['x'][2] if pylab_installed: pylab.figure(3, facecolor='w', figsize=(5,5)) pts = matrix([-10.0, 10.0], (2,1)) pylab.plot(X[0,:], X[1,:], 'ow', Y[0,:], Y[1,:], 'ok', pts, (b - a[0]*pts)/a[1], '-r', pts, (b+1.0 - a[0]*pts)/a[1], '--r', pts, (b-1.0 - a[0]*pts)/a[1], '--r' ) pylab.title('Separation via logistic modeling (fig. 8.12)') pylab.axis([-10, 10, -10, 10]) pylab.xticks([]) pylab.yticks([]) pylab.axis('off') pylab.show() cvxopt-1.1.4/examples/book/chap8/floorplan.py0000644000175000017500000001412611674452555020231 0ustar sonnesonne# Figure 8.20, page 444. # Floor planning example. from cvxopt import solvers, matrix, spmatrix, mul, div try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True def floorplan(Amin): # minimize W+H # subject to Amin1 / h1 <= w1 # Amin2 / h2 <= w2 # Amin3 / h3 <= w3 # Amin4 / h4 <= w4 # Amin5 / h5 <= w5 # x1 >= 0 # x2 >= 0 # x4 >= 0 # x1 + w1 + rho <= x3 # x2 + w2 + rho <= x3 # x3 + w3 + rho <= x5 # x4 + w4 + rho <= x5 # x5 + w5 <= W # y2 >= 0 # y3 >= 0 # y5 >= 0 # y2 + h2 + rho <= y1 # y1 + h1 + rho <= y4 # y3 + h3 + rho <= y4 # y4 + h4 <= H # y5 + h5 <= H # h1/gamma <= w1 <= gamma*h1 # h2/gamma <= w2 <= gamma*h2 # h3/gamma <= w3 <= gamma*h3 # h4/gamma <= w4 <= gamma*h4 # h5/gamma <= w5 <= gamma*h5 # # 22 Variables W, H, x (5), y (5), w (5), h (5). # # W, H: scalars; bounding box width and height # x, y: 5-vectors; coordinates of bottom left corners of blocks # w, h: 5-vectors; widths and heigths of the 5 blocks rho, gamma = 1.0, 5.0 # min spacing, min aspect ratio # The objective is to minimize W + H. There are five nonlinear # constraints # # -w1 + Amin1 / h1 <= 0 # -w2 + Amin2 / h2 <= 0 # -w3 + Amin3 / h3 <= 0 # -w4 + Amin4 / h4 <= 0 # -w5 + Amin5 / h5 <= 0. c = matrix(2*[1.0] + 20*[0.0]) def F(x=None, z=None): if x is None: return 5, matrix(17*[0.0] + 5*[1.0]) if min(x[17:]) <= 0.0: return None f = -x[12:17] + div(Amin, x[17:]) Df = matrix(0.0, (5,22)) Df[:,12:17] = spmatrix(-1.0, range(5), range(5)) Df[:,17:] = spmatrix(-div(Amin, x[17:]**2), range(5), range(5)) if z is None: return f, Df H = spmatrix( 2.0* mul(z, div(Amin, x[17::]**3)), range(17,22), range(17,22) ) return f, Df, H # linear inequalities G = matrix(0.0, (26,22)) h = matrix(0.0, (26,1)) # -x1 <= 0 G[0,2] = -1.0 # -x2 <= 0 G[1,3] = -1.0 # -x4 <= 0 G[2,5] = -1.0 # x1 - x3 + w1 <= -rho G[3, [2, 4, 12]], h[3] = [1.0, -1.0, 1.0], -rho # x2 - x3 + w2 <= -rho G[4, [3, 4, 13]], h[4] = [1.0, -1.0, 1.0], -rho # x3 - x5 + w3 <= -rho G[5, [4, 6, 14]], h[5] = [1.0, -1.0, 1.0], -rho # x4 - x5 + w4 <= -rho G[6, [5, 6, 15]], h[6] = [1.0, -1.0, 1.0], -rho # -W + x5 + w5 <= 0 G[7, [0, 6, 16]] = -1.0, 1.0, 1.0 # -y2 <= 0 G[8,8] = -1.0 # -y3 <= 0 G[9,9] = -1.0 # -y5 <= 0 G[10,11] = -1.0 # -y1 + y2 + h2 <= -rho G[11, [7, 8, 18]], h[11] = [-1.0, 1.0, 1.0], -rho # y1 - y4 + h1 <= -rho G[12, [7, 10, 17]], h[12] = [1.0, -1.0, 1.0], -rho # y3 - y4 + h3 <= -rho G[13, [9, 10, 19]], h[13] = [1.0, -1.0, 1.0], -rho # -H + y4 + h4 <= 0 G[14, [1, 10, 20]] = -1.0, 1.0, 1.0 # -H + y5 + h5 <= 0 G[15, [1, 11, 21]] = -1.0, 1.0, 1.0 # -w1 + h1/gamma <= 0 G[16, [12, 17]] = -1.0, 1.0/gamma # w1 - gamma * h1 <= 0 G[17, [12, 17]] = 1.0, -gamma # -w2 + h2/gamma <= 0 G[18, [13, 18]] = -1.0, 1.0/gamma # w2 - gamma * h2 <= 0 G[19, [13, 18]] = 1.0, -gamma # -w3 + h3/gamma <= 0 G[20, [14, 18]] = -1.0, 1.0/gamma # w3 - gamma * h3 <= 0 G[21, [14, 19]] = 1.0, -gamma # -w4 + h4/gamma <= 0 G[22, [15, 19]] = -1.0, 1.0/gamma # w4 - gamma * h4 <= 0 G[23, [15, 20]] = 1.0, -gamma # -w5 + h5/gamma <= 0 G[24, [16, 21]] = -1.0, 1.0/gamma # w5 - gamma * h5 <= 0.0 G[25, [16, 21]] = 1.0, -gamma # solve and return W, H, x, y, w, h sol = solvers.cpl(c, F, G, h) return sol['x'][0], sol['x'][1], sol['x'][2:7], sol['x'][7:12], \ sol['x'][12:17], sol['x'][17:] #solvers.options['show_progress'] = False if pylab_installed: pylab.figure(facecolor='w') Amin = matrix([100., 100., 100., 100., 100.]) W, H, x, y, w, h = floorplan(Amin) if pylab_installed: if pylab_installed: pylab.subplot(221) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) Amin = matrix([20., 50., 80., 150., 200.]) W, H, x, y, w, h = floorplan(Amin) if pylab_installed: pylab.subplot(222) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) Amin = matrix([180., 80., 80., 80., 80.]) W, H, x, y, w, h = floorplan(Amin) if pylab_installed: pylab.subplot(223) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) Amin = matrix([20., 150., 20., 200., 110.]) W, H, x, y, w, h = floorplan(Amin) if pylab_installed: pylab.subplot(224) for k in range(5): pylab.fill([x[k], x[k], x[k]+w[k], x[k]+w[k]], [y[k], y[k]+h[k], y[k]+h[k], y[k]], facecolor = '#D0D0D0') pylab.text(x[k]+.5*w[k], y[k]+.5*h[k], "%d" %(k+1)) pylab.axis([-1.0, 26, -1.0, 26]) pylab.xticks([]) pylab.yticks([]) pylab.show() cvxopt-1.1.4/examples/book/chap8/linsep.bin0000644000175000017500000001052111674452555017642 0ustar sonnesonne(dp0 S'Y' p1 ccvxopt.base matrix p2 ((lp3 F-3.3259124319899862 aF2.8225398072811516 aF-0.085583482542882061 aF3.1530933114417081 aF-1.3247761851520539 aF2.2606345410061248 aF4.1832161373082064 aF5.7543596834452719 aF0.75502644379389472 aF4.3218889499026991 aF1.5867204004149711 aF3.6376335205696551 aF-3.7537950975207721 aF0.92428488418482946 aF-4.1800929390295156 aF0.91630289899980921 aF4.2629206573744911 aF3.5807156730501672 aF2.573748910847383 aF4.4138777646398388 aF0.13453652761961798 aF6.2684549569682044 aF3.4378865234397504 aF7.3140696878676845 aF-1.7591406875563949 aF3.12875120530243 aF2.6282388968157653 aF8.3076743912936379 aF1.1486751015240078 aF6.4355777960311435 aF3.0470243371220431 aF2.7060007913042123 aF-0.5171185991922278 aF6.3246590293256251 aF-3.1507825952040975 aF2.4337415612517659 aF2.3579117888673511 aF3.7067675889497793 aF-1.4175554889396924 aF-0.40849422934491386 aF-1.7717823012505192 aF2.6872451500321142 aF0.931122926878857 aF5.1885004522252878 aF-1.6371106533789872 aF0.64004041011870338 aF1.2351587354330928 aF6.5189109009536264 aF0.39904790672760693 aF1.98855295706613 aF-0.92488907487814354 aF2.4589906199856588 aF-1.9759356663570427 aF2.4422815951389691 aF-1.6901883178447037 aF2.9238391663761094 aF1.6863365498640297 aF4.3498854200260988 aF-0.054069207143000675 aF4.7696578032384611 aF-3.763470227580636 aF-0.41566113012203587 aF-4.6912529063267048 aF-1.6078012334153884 aF-3.6342230231157275 aF1.2930152609673407 aF-3.3015329081859432 aF-1.817701136997784 aF-6.0700828799319808 aF-1.6205068273178593 aF-6.0922564178915257 aF-0.87265141093362164 aF-3.046827042693721 aF1.235109483262729 aF-4.6075121063136342 aF-2.3866354834632082 aF-3.2776708818532097 aF0.044761524054909962 aF-1.3836061813809617 aF2.2811212122200692 aF0.89365751897667056 aF2.1812349207644646 aF-1.9504864207015848 aF3.3866795568055132 aF2.5555324747844974 aF4.629692916135788 aF-6.9008879666136647 aF-4.0252986202193295 aF-3.7027690950618588 aF-0.26702581794135005 aF-4.9641892055436436 aF-3.1956203424905927 aF-5.4535810893929106 aF-1.7786517352517941 aF-5.7927828700513126 aF-0.66709383907920383 aF-4.9928597973428914 aF-2.104980529891062 aF-2.6695985995034452 aF-0.30423711825838984 a(I2 I50 tp4 S'd' p5 tp6 Rp7 sS'X' p8 g2 ((lp9 F-2.2988730425412962 aF-6.8886127538282613 aF0.11206447589345725 aF-3.3240576614930459 aF-0.74372051739217349 aF-2.1470371556379169 aF-1.0829466884697956 aF-5.2923651188100989 aF0.12976840441848125 aF-4.2049779282934852 aF-4.0222415940723328 aF-5.044396125337884 aF3.4598318341371579 aF-0.92970676505898897 aF1.3952691136349913 aF-2.559228827847134 aF1.8011678836395115 aF-1.7619157225981017 aF-0.98362919545773275 aF-3.6273804334157735 aF-2.3656826672527456 aF-4.5278749522154893 aF-5.7199620621032308 aF-3.749201369226534 aF1.572658516501757 aF-2.1537197033803914 aF0.23314811759215015 aF-4.7095822287706097 aF4.4922671955365825 aF2.7367666036134843 aF-1.1776750048123226 aF-3.3663465468972991 aF-2.3038884777014044 aF-6.5438609147713596 aF0.52318914850250631 aF-0.56843868120988461 aF-2.6652661202159162 aF-4.560160151307489 aF0.025142514973025221 aF-1.2938685960527376 aF-5.5306699466330507 aF-2.9482496744854205 aF-0.24365598231452346 aF-6.433884777987851 aF-1.2587526414888468 aF-5.8634676835104891 aF2.9082964700370413 aF-2.04119192292415 aF1.3692304592723086 aF-5.0646827172416486 aF0.38444927208825685 aF-3.8547764797604556 aF-1.5000663120577835 aF-4.3107025534659931 aF4.3069464239149244 aF1.6142135661793393 aF1.0320292288276742 aF-1.6989736371650852 aF-3.5977156960777501 aF-4.6287278188825374 aF7.8452137354493381 aF4.3299787523984534 aF3.9147900464905931 aF0.27707044522956314 aF2.5487116241206644 aF-1.1377492790435122 aF0.83364231666949484 aF-0.82955309110512321 aF2.5364592833901565 aF-0.56945672762463717 aF-0.46843548774939214 aF-0.42212397750498121 aF3.1121398420558943 aF0.11136088696540258 aF5.9088501740048818 aF2.5339351757838608 aF7.920056421946466 aF3.5443936333542574 aF7.5875426443774714 aF0.67263456075981409 aF2.8803338222063486 aF-1.0726633535600105 aF2.3493280656232298 aF1.8713377957720971 aF6.3375235850156715 aF2.4011775105257085 aF0.72189465458660751 aF-1.1792894527679461 aF5.64036424092766 aF3.5213766242958182 aF8.738328157638346 aF3.1098075267940533 aF2.5791206203432999 aF0.52790175355367319 aF3.611168317023135 aF-0.21097517368754937 aF6.1573596252569232 aF2.4297655543463108 aF2.5780511922520906 aF-2.0378512504695636 a(I2 I50 tp10 g5 tp11 Rp12 s.cvxopt-1.1.4/examples/book/chap8/ellipsoids.py0000644000175000017500000001570211674452555020405 0ustar sonnesonne# Figures 8.3 and 8.4, pages 412 and 416. # Ellipsoidal approximations. from math import log, pi from cvxopt import blas, lapack, solvers, matrix, sqrt, mul, cos, sin #solvers.options['show_progress'] = False try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True # Extreme points (with first one appended at the end) X = matrix([ 0.55, 0.25, -0.20, -0.25, 0.00, 0.40, 0.55, 0.00, 0.35, 0.20, -0.10, -0.30, -0.20, 0.00 ], (7,2)) m = X.size[0] - 1 # Inequality description G*x <= h with h = 1 G, h = matrix(0.0, (m,2)), matrix(0.0, (m,1)) G = (X[:m,:] - X[1:,:]) * matrix([0., -1., 1., 0.], (2,2)) h = (G * X.T)[::m+1] G = mul(h[:,[0,0]]**-1, G) h = matrix(1.0, (m,1)) # Loewner-John ellipsoid # # minimize log det A^-1 # subject to xk'*A*xk - 2*xk'*b + b'*A^1*b <= 1, k=1,...,m # # 5 variables x = (A[0,0], A[1,0], A[1,1], b[0], b[1]) def F(x=None, z=None): if x is None: return m, matrix([ 1.0, 0.0, 1.0, 0.0, 0.0 ]) # Factor A as A = L*L'. Compute inverse B = A^-1. A = matrix( [x[0], x[1], x[1], x[2]], (2,2)) L = +A try: lapack.potrf(L) except: return None B = +L lapack.potri(B) B[0,1] = B[1,0] # f0 = -log det A f = matrix(0.0, (m+1,1)) f[0] = -2.0 * (log(L[0,0]) + log(L[1,1])) # fk = xk'*A*xk - 2*xk'*b + b*A^-1*b - 1 # = (xk - c)' * A * (xk - c) - 1 where c = A^-1*b c = x[3:] lapack.potrs(L, c) for k in range(m): f[k+1] = (X[k,:].T - c).T * A * (X[k,:].T - c) - 1.0 # gradf0 = (-A^-1, 0) = (-B, 0) Df = matrix(0.0, (m+1,5)) Df[0,0], Df[0,1], Df[0,2] = -B[0,0], -2.0*B[1,0], -B[1,1] # gradfk = (xk*xk' - A^-1*b*b'*A^-1, 2*(-xk + A^-1*b)) # = (xk*xk' - c*c', 2*(-xk+c)) Df[1:,0] = X[:m,0]**2 - c[0]**2 Df[1:,1] = 2.0 * (mul(X[:m,0], X[:m,1]) - c[0]*c[1]) Df[1:,2] = X[:m,1]**2 - c[1]**2 Df[1:,3] = 2.0 * (-X[:m,0] + c[0]) Df[1:,4] = 2.0 * (-X[:m,1] + c[1]) if z is None: return f, Df # hessf0(Y, y) = (A^-1*Y*A^-1, 0) = (B*YB, 0) H0 = matrix(0.0, (5,5)) H0[0,0] = B[0,0]**2 H0[1,0] = 2.0 * B[0,0] * B[1,0] H0[2,0] = B[1,0]**2 H0[1,1] = 2.0 * ( B[0,0] * B[1,1] + B[1,0]**2 ) H0[2,1] = 2.0 * B[1,0] * B[1,1] H0[2,2] = B[1,1]**2 # hessfi(Y, y) # = ( A^-1*Y*A^-1*b*b'*A^-1 + A^-1*b*b'*A^-1*Y*A^-1 # - A^-1*y*b'*A^-1 - A^-1*b*y'*A^-1, # -2*A^-1*Y*A^-1*b + 2*A^-1*y ) # = ( B*Y*c*c' + c*c'*Y*B - B*y*c' - c*y'*B, -2*B*Y*c + 2*B*y ) # = ( B*(Y*c-y)*c' + c*(Y*c-y)'*B, -2*B*(Y*c - y) ) H1 = matrix(0.0, (5,5)) H1[0,0] = 2.0 * c[0]**2 * B[0,0] H1[1,0] = 2.0 * ( c[0] * c[1] * B[0,0] + c[0]**2 * B[1,0] ) H1[2,0] = 2.0 * c[0] * c[1] * B[1,0] H1[3:,0] = -2.0 * c[0] * B[:,0] H1[1,1] = 2.0 * c[0]**2 * B[1,1] + 4.0 * c[0]*c[1]*B[1,0] + \ 2.0 * c[1]**2 + B[0,0] H1[2,1] = 2.0 * (c[1]**2 * B[1,0] + c[0]*c[1]*B[1,1]) H1[3:,1] = -2.0 * B * c[[1,0]] H1[2,2] = 2.0 * c[1]**2 * B[1,1] H1[3:,2] = -2.0 * c[1] * B[:,1] H1[3:,3:] = 2*B return f, Df, z[0]*H0 + sum(z[1:])*H1 sol = solvers.cp(F) A = matrix( sol['x'][[0, 1, 1, 2]], (2,2)) b = sol['x'][3:] if pylab_installed: pylab.figure(1, facecolor='w') pylab.plot(X[:,0], X[:,1], 'ko', X[:,0], X[:,1], '-k') # Ellipsoid in the form { x | || L' * (x-c) ||_2 <= 1 } L = +A lapack.potrf(L) c = +b lapack.potrs(L, c) # 1000 points on the unit circle nopts = 1000 angles = matrix( [ a*2.0*pi/nopts for a in range(nopts) ], (1,nopts) ) circle = matrix(0.0, (2,nopts)) circle[0,:], circle[1,:] = cos(angles), sin(angles) # ellipse = L^-T * circle + c blas.trsm(L, circle, transA='T') ellipse = circle + c[:, nopts*[0]] ellipse2 = 0.5 * circle + c[:, nopts*[0]] pylab.plot(ellipse[0,:].T, ellipse[1,:].T, 'k-') pylab.fill(ellipse2[0,:].T, ellipse2[1,:].T, facecolor = '#F0F0F0') pylab.title('Loewner-John ellipsoid (fig 8.3)') pylab.axis('equal') pylab.axis('off') # Maximum volume enclosed ellipsoid # # minimize -log det B # subject to ||B * gk||_2 + gk'*c <= hk, k=1,...,m # # with variables B and c. # # minimize -log det L # subject to ||L' * gk||_2^2 / (hk - gk'*c) <= hk - gk'*c, k=1,...,m # # L lower triangular with positive diagonal and B*B = L*L'. # # minimize -log x[0] - log x[2] # subject to g( Dk*x + dk ) <= 0, k=1,...,m # # g(u,t) = u'*u/t - t # Dk = [ G[k,0] G[k,1] 0 0 0 # 0 0 G[k,1] 0 0 # 0 0 0 -G[k,0] -G[k,1] ] # dk = [0; 0; h[k]] # # 5 variables x = (L[0,0], L[1,0], L[1,1], c[0], c[1]) D = [ matrix(0.0, (3,5)) for k in range(m) ] for k in range(m): D[k][ [0, 3, 7, 11, 14] ] = matrix( [G[k,0], G[k,1], G[k,1], -G[k,0], -G[k,1]] ) d = [matrix([0.0, 0.0, hk]) for hk in h] def F(x=None, z=None): if x is None: return m, matrix([ 1.0, 0.0, 1.0, 0.0, 0.0 ]) if min(x[0], x[2], min(h-G*x[3:])) <= 0.0: return None y = [ Dk*x + dk for Dk, dk in zip(D, d) ] f = matrix(0.0, (m+1,1)) f[0] = -log(x[0]) - log(x[2]) for k in range(m): f[k+1] = y[k][:2].T * y[k][:2] / y[k][2] - y[k][2] Df = matrix(0.0, (m+1,5)) Df[0,0], Df[0,2] = -1.0/x[0], -1.0/x[2] # gradient of g is ( 2.0*(u/t); -(u/t)'*(u/t) -1) for k in range(m): a = y[k][:2] / y[k][2] gradg = matrix(0.0, (3,1)) gradg[:2], gradg[2] = 2.0 * a, -a.T*a - 1 Df[k+1,:] = gradg.T * D[k] if z is None: return f, Df H = matrix(0.0, (5,5)) H[0,0] = z[0] / x[0]**2 H[2,2] = z[0] / x[2]**2 # Hessian of g is (2.0/t) * [ I, -u/t; -(u/t)', (u/t)*(u/t)' ] for k in range(m): a = y[k][:2] / y[k][2] hessg = matrix(0.0, (3,3)) hessg[0,0], hessg[1,1] = 1.0, 1.0 hessg[:2,2], hessg[2,:2] = -a, -a.T hessg[2, 2] = a.T*a H += (z[k] * 2.0 / y[k][2]) * D[k].T * hessg * D[k] return f, Df, H sol = solvers.cp(F) L = matrix([sol['x'][0], sol['x'][1], 0.0, sol['x'][2]], (2,2)) c = matrix([sol['x'][3], sol['x'][4]]) if pylab_installed: pylab.figure(2, facecolor='w') # polyhedron for k in range(m): edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \ (X[2*[k],:] - X[2*[k+1],:]) pylab.plot(edge[:,0], edge[:,1], 'k') # 1000 points on the unit circle nopts = 1000 angles = matrix( [ a*2.0*pi/nopts for a in range(nopts) ], (1,nopts) ) circle = matrix(0.0, (2,nopts)) circle[0,:], circle[1,:] = cos(angles), sin(angles) # ellipse = L * circle + c ellipse = L * circle + c[:, nopts*[0]] ellipse2 = 2.0 * L * circle + c[:, nopts*[0]] pylab.plot(ellipse2[0,:].T, ellipse2[1,:].T, 'k-') pylab.fill(ellipse[0,:].T, ellipse[1,:].T, facecolor = '#F0F0F0') pylab.title('Maximum volume inscribed ellipsoid (fig 8.4)') pylab.axis('equal') pylab.axis('off') pylab.show() cvxopt-1.1.4/examples/book/chap8/placement.py0000644000175000017500000001176011674452555020206 0ustar sonnesonne# Figures 8.15-17, pages 435 and 436. # Linear, quadratic and fourth-order placement. # # The problem data are different from the example in the book. import pickle from cvxopt import lapack, solvers, matrix, spmatrix, sqrt, mul from cvxopt.modeling import variable, op #solvers.options['show_progress'] = False try: import pylab, numpy except ImportError: pylab_installed = False else: pylab_installed = True data = pickle.load(open("placement.bin", "rb")) Xf = data['X'] # M by n matrix with coordinates of M fixed nodes M = Xf.size[0] E = data['E'] # list of edges L = len(E) # number of edges N = max(max(e) for e in E) + 1 - M # number of free nodes; fixed nodes # have the highest M indices. # arc-node incidence matrix A = matrix(0.0, (L,M+N)) for k in range(L): A[k, E[k]] = matrix([1.0, -1.0], (1,2)) # minimize sum h( sqrt( (A1*X[:,0] + B[:,0])**2 + # (A1*X[:,1] + B[:,1])**2 ) for different h A1 = A[:,:N] B = A[:,N:]*Xf # Linear placement: h(u) = u. # # minimize 1'*t # subject to [ ti*I (A[i,:]*[x,y] + B)' ] # [ A[i,:]*[x,y] + B ti ] >= 0, # i = 1, ..., L # # variables t (L), x (N), y (N). novars = L + 2*N c = matrix(0.0, (novars,1)) c[:L] = 1.0 G = [ spmatrix([], [], [], (9, novars)) for k in range(L) ] h = [ matrix(0.0, (3,3)) for k in range(L) ] for k in range(L): # coefficient of tk C = spmatrix(-1.0, [0,1,2], [0,1,2]) G[k][C.I + 3*C.J, k] = C.V for j in range(N): # coefficient of x[j] C = spmatrix(-A[k,j], [2, 0], [0, 2]) G[k][C.I + 3*C.J, L+j] = C.V # coefficient of y[j] C = spmatrix(-A[k,j], [2, 1], [1, 2]) G[k][C.I + 3*C.J, L+N+j] = C.V # constant h[k][2,:2] = B[k,:] h[k][:2,2] = B[k,:].T sol = solvers.sdp(c, Gs=G, hs=h) X1 = matrix(sol['x'][L:], (N,2)) # Quadratic placement: h(u) = u^2. # # minimize sum (A*X[:,0] + B[:,0])**2 + (A*X[:,1] + B[:,1])**2 # # with variable X (Nx2). Bc = -B lapack.gels(+A1, Bc) X2 = Bc[:N,:] # Fourth order placement: h(u) = u^4 # # minimize g(AA*x + BB) # # where AA = [A1, 0; 0, A1] # BB = [B[:,0]; B[:,1]] # x = [X[:,0]; X[:,1]] # g(u,v) = sum((uk.^2 + vk.^2).^2) # # with variables x (2*N). AA = matrix(0.0, (2*L, 2*N)) AA[:L, :N], AA[L:,N:] = A1, A1 BB = matrix(B, (2*L,1)) def F(x=None, z=None): if x is None: return 0, matrix(0.0, (2*N,1)) y = AA*x + BB d = y[:L]**2 + y[L:]**2 f = sum(d**2) gradg = matrix(0.0, (2*L,1)) gradg[:L], gradg[L:] = 4*mul(d,y[:L]), 4*mul(d,y[L:]) g = gradg.T * AA if z is None: return f, g H = matrix(0.0, (2*L, 2*L)) for k in range(L): H[k,k], H[k+L,k+L] = 4*d[k], 4*d[k] H[[k,k+L], [k,k+L]] += 8 * y[[k,k+L]] * y[[k,k+L]].T return f, g, AA.T*H*AA sol = solvers.cp(F) X4 = matrix(sol['x'], (N,2)) if pylab_installed: # Figures for linear placement. pylab.figure(1, figsize=(10,4), facecolor='w') pylab.subplot(121) X = matrix(0.0, (N+M,2)) X[:N,:], X[N:,:] = X1, Xf pylab.plot(Xf[:,0], Xf[:,1], 'sw', X1[:,0], X1[:,1], 'or', ms=10) for s, t in E: pylab.plot([X[s,0], X[t,0]], [X[s,1],X[t,1]], 'b:') pylab.axis([-1.1, 1.1, -1.1, 1.1]) pylab.axis('equal') pylab.title('Linear placement') pylab.subplot(122) lngths = sqrt((A1*X1 + B)**2 * matrix(1.0, (2,1))) pylab.hist(lngths, numpy.array([.1*k for k in range(15)])) x = pylab.arange(0, 1.6, 1.6/500) pylab.plot( x, 5.0/1.6*x, '--k') pylab.axis([0, 1.6, 0, 5.5]) pylab.title('Length distribution') # Figures for quadratic placement. pylab.figure(2, figsize=(10,4), facecolor='w') pylab.subplot(121) X[:N,:], X[N:,:] = X2, Xf pylab.plot(Xf[:,0], Xf[:,1], 'sw', X2[:,0], X2[:,1], 'or', ms=10) for s, t in E: pylab.plot([X[s,0], X[t,0]], [X[s,1],X[t,1]], 'b:') pylab.axis([-1.1, 1.1, -1.1, 1.1]) pylab.axis('equal') pylab.title('Quadratic placement') pylab.subplot(122) lngths = sqrt((A1*X2 + B)**2 * matrix(1.0, (2,1))) pylab.hist(lngths, numpy.array([.1*k for k in range(15)])) x = pylab.arange(0, 1.5, 1.5/500) pylab.plot( x, 5.0/1.5**2 * x**2, '--k') pylab.axis([0, 1.5, 0, 5.5]) pylab.title('Length distribution') # Figures for fourth order placement. pylab.figure(3, figsize=(10,4), facecolor='w') pylab.subplot(121) X[:N,:], X[N:,:] = X4, Xf pylab.plot(Xf[:,0], Xf[:,1], 'sw', X4[:,0], X4[:,1], 'or', ms=10) for s, t in E: pylab.plot([X[s,0], X[t,0]], [X[s,1],X[t,1]], 'b:') pylab.axis([-1.1, 1.1, -1.1, 1.1]) pylab.axis('equal') pylab.title('Fourth order placement') pylab.subplot(122) lngths = sqrt((A1*X4 + B)**2 * matrix(1.0, (2,1))) pylab.hist(lngths, numpy.array([.1*k for k in range(15)])) x = pylab.arange(0, 1.5, 1.5/500) pylab.plot( x, 6.0/1.4**4 * x**4, '--k') pylab.axis([0, 1.4, 0, 6.5]) pylab.title('Length distribution') pylab.show() cvxopt-1.1.4/examples/book/chap8/centers.py0000644000175000017500000001357711674452555017711 0ustar sonnesonne# Figures 8.5-7, pages 417-421. # Centers of polyhedra. from math import log, pi from cvxopt import blas, lapack, solvers from cvxopt import matrix, spdiag, sqrt, mul, cos, sin, log from cvxopt.modeling import variable, op #solvers.options['show_progress'] = False try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True # Extreme points (with first one appended at the end) X = matrix([ 0.55, 0.25, -0.20, -0.25, 0.00, 0.40, 0.55, 0.00, 0.35, 0.20, -0.10, -0.30, -0.20, 0.00 ], (7,2)) m = X.size[0] - 1 # Inequality description G*x <= h with h = 1 G, h = matrix(0.0, (m,2)), matrix(0.0, (m,1)) G = (X[:m,:] - X[1:,:]) * matrix([0., -1., 1., 0.], (2,2)) h = (G * X.T)[::m+1] G = mul(h[:,[0,0]]**-1, G) h = matrix(1.0, (m,1)) # Chebyshev center # # maximizse R # subject to gk'*xc + R*||gk||_2 <= hk, k=1,...,m # R >= 0 R = variable() xc = variable(2) op(-R, [ G[k,:]*xc + R*blas.nrm2(G[k,:]) <= h[k] for k in range(m) ] + [ R >= 0] ).solve() R = R.value xc = xc.value if pylab_installed: pylab.figure(1, facecolor='w') # polyhedron for k in range(m): edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \ (X[2*[k],:] - X[2*[k+1],:]) pylab.plot(edge[:,0], edge[:,1], 'k') # 1000 points on the unit circle nopts = 1000 angles = matrix( [ a*2.0*pi/nopts for a in range(nopts) ], (1,nopts) ) circle = matrix(0.0, (2,nopts)) circle[0,:], circle[1,:] = R*cos(angles), R*sin(angles) circle += xc[:,nopts*[0]] # plot maximum inscribed disk pylab.fill(circle[0,:].T, circle[1,:].T, facecolor = '#F0F0F0') pylab.plot([xc[0]], [xc[1]], 'ko') pylab.title('Chebyshev center (fig 8.5)') pylab.axis('equal') pylab.axis('off') # Maximum volume enclosed ellipsoid center # # minimize -log det B # subject to ||B * gk||_2 + gk'*c <= hk, k=1,...,m # # with variables B and c. # # minimize -log det L # subject to ||L' * gk||_2^2 / (hk - gk'*c) <= hk - gk'*c, k=1,...,m # # L lower triangular with positive diagonal and B*B = L*L'. # # minimize -log x[0] - log x[2] # subject to g( Dk*x + dk ) <= 0, k=1,...,m # # g(u,t) = u'*u/t - t # Dk = [ G[k,0] G[k,1] 0 0 0 # 0 0 G[k,1] 0 0 # 0 0 0 -G[k,0] -G[k,1] ] # dk = [0; 0; h[k]] # # 5 variables x = (L[0,0], L[1,0], L[1,1], c[0], c[1]) D = [ matrix(0.0, (3,5)) for k in range(m) ] for k in range(m): D[k][ [0, 3, 7, 11, 14] ] = matrix( [G[k,0], G[k,1], G[k,1], -G[k,0], -G[k,1]] ) d = [matrix([0.0, 0.0, hk]) for hk in h] def F(x=None, z=None): if x is None: return m, matrix([ 1.0, 0.0, 1.0, 0.0, 0.0 ]) if min(x[0], x[2], min(h-G*x[3:])) <= 0.0: return None y = [ Dk*x + dk for Dk, dk in zip(D, d) ] f = matrix(0.0, (m+1,1)) f[0] = -log(x[0]) - log(x[2]) for k in range(m): f[k+1] = y[k][:2].T * y[k][:2] / y[k][2] - y[k][2] Df = matrix(0.0, (m+1,5)) Df[0,0], Df[0,2] = -1.0/x[0], -1.0/x[2] # gradient of g is ( 2.0*(u/t); -(u/t)'*(u/t) -1) for k in range(m): a = y[k][:2] / y[k][2] gradg = matrix(0.0, (3,1)) gradg[:2], gradg[2] = 2.0 * a, -a.T*a - 1 Df[k+1,:] = gradg.T * D[k] if z is None: return f, Df H = matrix(0.0, (5,5)) H[0,0] = z[0] / x[0]**2 H[2,2] = z[0] / x[2]**2 # Hessian of g is (2.0/t) * [ I, -u/t; -(u/t)', (u/t)*(u/t)' ] for k in range(m): a = y[k][:2] / y[k][2] hessg = matrix(0.0, (3,3)) hessg[0,0], hessg[1,1] = 1.0, 1.0 hessg[:2,2], hessg[2,:2] = -a, -a.T hessg[2, 2] = a.T*a H += (z[k] * 2.0 / y[k][2]) * D[k].T * hessg * D[k] return f, Df, H sol = solvers.cp(F) L = matrix([sol['x'][0], sol['x'][1], 0.0, sol['x'][2]], (2,2)) c = matrix([sol['x'][3], sol['x'][4]]) if pylab_installed: pylab.figure(2, facecolor='w') # polyhedron for k in range(m): edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \ (X[2*[k],:] - X[2*[k+1],:]) pylab.plot(edge[:,0], edge[:,1], 'k') # 1000 points on the unit circle nopts = 1000 angles = matrix( [ a*2.0*pi/nopts for a in range(nopts) ], (1,nopts) ) circle = matrix(0.0, (2,nopts)) circle[0,:], circle[1,:] = cos(angles), sin(angles) # ellipse = L * circle + c ellipse = L * circle + c[:, nopts*[0]] pylab.fill(ellipse[0,:].T, ellipse[1,:].T, facecolor = '#F0F0F0') pylab.plot([c[0]], [c[1]], 'ko') pylab.title('Maximum volume inscribed ellipsoid center (fig 8.6)') pylab.axis('equal') pylab.axis('off') # Analytic center. # # minimize -sum log (h-G*x) # def F(x=None, z=None): if x is None: return 0, matrix(0.0, (2,1)) y = h-G*x if min(y) <= 0: return None f = -sum(log(y)) Df = (y**-1).T * G if z is None: return matrix(f), Df H = G.T * spdiag(y**-1) * G return matrix(f), Df, z[0]*H sol = solvers.cp(F) xac = sol['x'] Hac = G.T * spdiag((h-G*xac)**-1) * G if pylab_installed: pylab.figure(3, facecolor='w') # polyhedron for k in range(m): edge = X[[k,k+1],:] + 0.1 * matrix([1., 0., 0., -1.], (2,2)) * \ (X[2*[k],:] - X[2*[k+1],:]) pylab.plot(edge[:,0], edge[:,1], 'k') # 1000 points on the unit circle nopts = 1000 angles = matrix( [ a*2.0*pi/nopts for a in range(nopts) ], (1,nopts) ) circle = matrix(0.0, (2,nopts)) circle[0,:], circle[1,:] = cos(angles), sin(angles) # ellipse = L^-T * circle + xc where Hac = L*L' lapack.potrf(Hac) ellipse = +circle blas.trsm(Hac, ellipse, transA='T') ellipse += xac[:, nopts*[0]] pylab.fill(ellipse[0,:].T, ellipse[1,:].T, facecolor = '#F0F0F0') pylab.plot([xac[0]], [xac[1]], 'ko') pylab.title('Analytic center (fig 8.7)') pylab.axis('equal') pylab.axis('off') pylab.show() cvxopt-1.1.4/examples/book/chap8/placement.bin0000644000175000017500000000123211674452555020317 0ustar sonnesonne(dp0 S'X' p1 ccvxopt.base matrix p2 ((lp3 F1.0 aF1.0 aF-1.0 aF-1.0 aF1.0 aF-1.0 aF-0.20000000000000001 aF0.10000000000000001 aF1.0 aF-1.0 aF-1.0 aF1.0 aF-0.5 aF-0.20000000000000001 aF-1.0 aF1.0 a(I8 I2 tp4 S'd' p5 tp6 Rp7 sS'E' p8 (lp9 (lp10 I0 aI3 aa(lp11 I0 aI2 aa(lp12 I0 aI4 aa(lp13 I0 aI6 aa(lp14 I0 aI7 aa(lp15 I0 aI10 aa(lp16 I0 aI13 aa(lp17 I1 aI2 aa(lp18 I1 aI3 aa(lp19 I1 aI5 aa(lp20 I1 aI7 aa(lp21 I1 aI8 aa(lp22 I1 aI12 aa(lp23 I2 aI3 aa(lp24 I2 aI7 aa(lp25 I2 aI10 aa(lp26 I3 aI4 aa(lp27 I3 aI8 aa(lp28 I3 aI9 aa(lp29 I3 aI11 aa(lp30 I3 aI5 aa(lp31 I4 aI5 aa(lp32 I4 aI6 aa(lp33 I4 aI9 aa(lp34 I4 aI13 aa(lp35 I5 aI8 aa(lp36 I5 aI10 aa(lp37 I1 aI11 aas.cvxopt-1.1.4/examples/book/chap4/0000755000175000017500000000000011674452555015653 5ustar sonnesonnecvxopt-1.1.4/examples/book/chap4/portfolio.py0000644000175000017500000000350711674452555020247 0ustar sonnesonne# Figure 4.12, page 187. # Risk-return trade-off. from math import sqrt from cvxopt import matrix from cvxopt.blas import dot from cvxopt.solvers import qp, options n = 4 S = matrix( [[ 4e-2, 6e-3, -4e-3, 0.0 ], [ 6e-3, 1e-2, 0.0, 0.0 ], [-4e-3, 0.0, 2.5e-3, 0.0 ], [ 0.0, 0.0, 0.0, 0.0 ]] ) pbar = matrix([.12, .10, .07, .03]) G = matrix(0.0, (n,n)) G[::n+1] = -1.0 h = matrix(0.0, (n,1)) A = matrix(1.0, (1,n)) b = matrix(1.0) N = 100 mus = [ 10**(5.0*t/N-1.0) for t in range(N) ] #options['show_progress'] = False xs = [ qp(mu*S, -pbar, G, h, A, b)['x'] for mu in mus ] returns = [ dot(pbar,x) for x in xs ] risks = [ sqrt(dot(x, S*x)) for x in xs ] try: import pylab except ImportError: pass else: pylab.figure(1, facecolor='w') pylab.plot(risks, returns) pylab.xlabel('standard deviation') pylab.ylabel('expected return') pylab.axis([0, 0.2, 0, 0.15]) pylab.title('Risk-return trade-off curve (fig 4.12)') pylab.yticks([0.00, 0.05, 0.10, 0.15]) pylab.figure(2, facecolor='w') c1 = [ x[0] for x in xs ] c2 = [ x[0] + x[1] for x in xs ] c3 = [ x[0] + x[1] + x[2] for x in xs ] c4 = [ x[0] + x[1] + x[2] + x[3] for x in xs ] pylab.fill(risks + [.20], c1 + [0.0], facecolor = '#F0F0F0') pylab.fill(risks[-1::-1] + risks, c2[-1::-1] + c1, facecolor = '#D0D0D0') pylab.fill(risks[-1::-1] + risks, c3[-1::-1] + c2, facecolor = '#F0F0F0') pylab.fill(risks[-1::-1] + risks, c4[-1::-1] + c3, facecolor = '#D0D0D0') pylab.axis([0.0, 0.2, 0.0, 1.0]) pylab.xlabel('standard deviation') pylab.ylabel('allocation') pylab.text(.15,.5,'x1') pylab.text(.10,.7,'x2') pylab.text(.05,.7,'x3') pylab.text(.01,.7,'x4') pylab.title('Optimal allocations (fig 4.12)') pylab.show() cvxopt-1.1.4/examples/book/chap4/rls.py0000644000175000017500000000427711674452555017037 0ustar sonnesonne# Figure 4.11, page 185. # Regularized least-squares. from pickle import load from cvxopt import blas, lapack, matrix from cvxopt import solvers #solvers.options['show_progress'] = 0 data = load(open("rls.bin",'rb')) A, b = data['A'], data['b'] m, n = A.size # LS solution xls = +b lapack.gels(+A, xls) xls = xls[:n] # We compute the optimal values of # # minimize/maximize || A*x - b ||_2^2 # subject to x'*x = alpha # # via the duals. # # Lower bound: # # maximize -t - u*alpha # subject to [u*I, 0; 0, t] + [A, b]'*[A, b] >= 0 # # Upper bound: # # minimize t + u*alpha # subject to [u*I, 0; 0, t] - [A, b]'*[A, b] >= 0. # # Two variables (t, u). G = matrix(0.0, ((n+1)**2, 2)) G[-1, 0] = -1.0 # coefficient of t G[: (n+1)**2-1 : n+2, 1] = -1.0 # coefficient of u h = matrix( [ [ A.T * A, b.T * A ], [ A.T * b, b.T * b ] ] ) c = matrix(1.0, (2,1)) nopts = 40 alpha1 = [2.0/(nopts//2-1) * alpha for alpha in range(nopts//2) ] + \ [ 2.0 + (15.0 - 2.0)/(nopts//2) * alpha for alpha in range(1,nopts//2+1) ] lbnds = [ blas.nrm2(b)**2 ] for alpha in alpha1[1:]: c[1:] = alpha lbnds += [ -blas.dot(c, solvers.sdp(c, Gs=[G], hs=[h])['x']) ] nopts = 10 alpha2 = [ 1.0/(nopts-1) * alpha for alpha in range(nopts) ] ubnds = [ blas.nrm2(b)**2 ] for alpha in alpha2[1:]: c[1:] = alpha ubnds += [ blas.dot(c, solvers.sdp(c, Gs=[G], hs=[-h])['x']) ] try: import pylab except ImportError: pass else: pylab.figure(1, facecolor='w') pylab.plot(lbnds, alpha1, 'b-', ubnds, alpha2, 'b-') kmax = max([ k for k in range(len(alpha1)) if alpha1[k] < blas.nrm2(xls)**2 ]) pylab.plot( [ blas.nrm2(b)**2 ] + lbnds[:kmax] + [ blas.nrm2(A*xls-b)**2 ], [0.0] + alpha1[:kmax] + [ blas.nrm2(xls)**2 ], '-', linewidth=2) pylab.plot([ blas.nrm2(b)**2, blas.nrm2(A*xls-b)**2 ], [0.0, blas.nrm2(xls)**2], 'bo') pylab.fill(lbnds[-1::-1] + ubnds + [ubnds[-1]], alpha1[-1::-1] + alpha2+ [alpha1[-1]], facecolor = '#D0D0D0') pylab.axis([0, 15, -1.0, 15]) pylab.xlabel('||A*x-b||_2^2') pylab.ylabel('||x||_2^2') pylab.grid() pylab.title('Regularized least-squares (fig. 4.11)') pylab.show() cvxopt-1.1.4/examples/book/chap4/rls.bin0000644000175000017500000006170011674452555017151 0ustar sonnesonne(dp0 S'A' p1 ccvxopt.base matrix p2 ((lp3 F-0.047121492889140526 aF-0.18144060807472698 aF0.013653087886340971 aF0.031338060875565184 aF-0.12489097623978924 aF0.12973250054160473 aF0.12954172641598308 aF-0.0040995849133497603 aF0.035653627548439031 aF0.019024333249689017 aF-0.020339118395864945 aF0.079064069126614622 aF-0.064088324013841361 aF0.23782557495695772 aF-0.014858299759211343 aF0.012411119529011944 aF0.11620850643937246 aF0.006457832089142761 aF-0.010419469033861289 aF-0.090672075692189394 aF0.032071673010384889 aF-0.14555711014719719 aF0.07781501960401431 aF0.17686290293608883 aF-0.075358658263208797 aF0.093465957100732716 aF0.13660477573812255 aF-0.17361309774242523 aF-0.15697161077767993 aF0.062218025991932782 aF-0.043561577143116731 aF0.075164936108880781 aF0.088849899162438697 aF0.077551807520013061 aF0.14055349171253498 aF0.072834065866027101 aF0.129724069901409 aF-0.13098979129424682 aF-0.0021557775409096467 aF-0.017072015304311697 aF-0.17474122810953441 aF0.028029463658557609 aF-0.11508698868103193 aF0.15415858545699271 aF-0.087702607205726243 aF0.057598675082274363 aF0.023891720366797896 aF-0.10042744966489837 aF-0.23646265258303609 aF-0.0064476318414473039 aF-0.1100934882911646 aF0.066936596360841566 aF0.055310795442402944 aF0.18436502454233675 aF0.064411430316731702 aF-0.070110110574056847 aF0.041432078209956348 aF-0.10992810496200837 aF-0.0021253968215440878 aF-0.0052529366981838637 aF4.7051077752639194e-06 aF-0.034626052495573517 aF0.1192843465666204 aF-0.20414332429808865 aF0.046644189537202396 aF0.097566470336184194 aF0.07962691394933645 aF0.062948950331545558 aF0.0043916132417927533 aF0.073758781316401206 aF0.061973203227714539 aF-0.027848760032708052 aF-0.04111962006497568 aF-0.032232493208965825 aF-0.16069393135009905 aF-0.025491255353614174 aF0.012902800686174306 aF0.034293755997786383 aF0.15724872125227904 aF-0.038233469749768739 aF0.067892044618562922 aF0.087044444611906774 aF0.10249594389065429 aF-0.10807361675269353 aF0.023098071430485846 aF0.025913708435641641 aF-0.10978081024929962 aF-0.080834722518353636 aF0.11789991367740858 aF-0.014324933864518793 aF0.042471671834554331 aF0.0095848846381839225 aF-0.069224470658927173 aF-0.060957176075504237 aF0.048329439181683309 aF-0.10347786943300687 aF0.085098101072843255 aF0.061979787322346581 aF-0.089513532125449186 aF-0.028933910070392262 aF-0.12939061325337353 aF-0.23991003719032941 aF0.10744676662947422 aF-0.056497565080437621 aF0.035661819759381631 aF0.025497025122240103 aF0.0023384160791418435 aF-0.10936479526342273 aF-0.10317745541269685 aF-0.040788483438399976 aF-0.12918463846813083 aF-0.11502489517503948 aF0.16040475533374124 aF0.0060724601390490197 aF-0.13260860386657536 aF-0.0044910821108667892 aF-0.1229162566211242 aF-0.14698368997736475 aF-0.028443132558503413 aF0.10386585781600347 aF0.014013894413311603 aF0.071512357138380681 aF-0.1272165243778198 aF-0.050176073301293853 aF-0.028588923652406405 aF-0.13215484719392676 aF-0.143733007094201 aF0.10144227718402329 aF0.0012249639611970841 aF-0.070279026763985675 aF0.087772150168862265 aF0.025232203658383471 aF-0.10781957313251977 aF0.14592790810398251 aF0.031536934346781835 aF0.16110598402803841 aF0.12397120035282824 aF-0.07452670817303754 aF-0.14073718789332237 aF-0.0079442315158470417 aF-0.036013823484595628 aF-0.091900664917866998 aF0.054224590318273258 aF0.16214886479654383 aF-0.059530408630335957 aF-0.092241688955862169 aF-0.026834695396231682 aF0.072226604526381688 aF-0.09305208013744444 aF-0.13086535478608774 aF-0.013057988655794779 aF-0.0071128103212818256 aF0.052865722032410432 aF-0.064869863626206767 aF-0.016304071293831084 aF-0.047359746993677239 aF-0.0086418461244810851 aF0.16723197232862141 aF-0.066067273571916107 aF-0.14677509349552206 aF0.051132299150553714 aF-0.098430159196267006 aF0.0039085521896310704 aF-0.068360178940379573 aF0.058323632023784482 aF0.060228423673130756 aF-0.022189043650150651 aF-0.22378807347929303 aF0.014440517111852723 aF0.17352716181453826 aF0.11094079448199717 aF-0.17216131120280773 aF-0.0085690443950981032 aF-0.074256361186558609 aF-0.11160979424013918 aF-0.13446442494947738 aF0.031461222727192907 aF-0.046766167605753001 aF0.006078708475653909 aF-0.040074345386600665 aF-0.05065192228046999 aF0.040410629917476265 aF0.079335577156967305 aF0.23008838853301072 aF-0.14785737130078022 aF-0.11139814279937914 aF0.11305657675264319 aF-0.04246285449537273 aF-0.15046831491058235 aF0.034373669633165738 aF0.16920264130784787 aF0.077114494202908709 aF0.21322791258756341 aF0.054962373945926908 aF0.20311266344110002 aF-0.037017431437695113 aF-0.12416198814588042 aF-0.022998758696266174 aF0.12965945635232845 aF-0.12159431752427582 aF0.069203654170072057 aF-0.065514892742524575 aF0.06004336410791386 aF-0.11981123472051891 aF0.0093673942549961069 aF-0.21836731464692877 aF-0.053714583772163024 aF0.050333248387719944 aF-0.034968679644933755 aF0.13470431896234991 aF-0.068768515289858168 aF-0.25329711699930729 aF-0.13416845429946414 aF0.11499716731057563 aF-0.012334067098716265 aF0.041310764915469943 aF0.10285649577612264 aF-0.23098890258340468 aF-0.070228164947500171 aF-0.076723182292484052 aF-0.11091088392794095 aF-0.019835107338657735 aF0.16569173593403685 aF-0.0041873307557215873 aF0.13371217478733299 aF-0.075841142552102808 aF0.00081968072468956946 aF-0.085284535497225145 aF0.063938213204799282 aF-0.0273653015663179 aF0.052303645971496691 aF0.072785538409090356 aF-0.0085319276901602136 aF0.096862111986689495 aF0.25156247329468068 aF0.057151569335613946 aF-0.0012840533648383926 aF0.099473090284227142 aF0.0060939036930459014 aF-0.12059877453397955 aF0.052887743415860555 aF-0.00054522823192128592 aF-0.030089821336726406 aF0.13905048343871038 aF0.20298974027402311 aF-0.056925052061492877 aF0.01126655292117313 aF-0.087981342365869075 aF0.074123648135745263 aF-0.25758684186969244 aF0.10785826692162294 aF0.023845798578945508 aF0.028504227406500666 aF0.13218670270320201 aF-0.029920876835725915 aF-0.014503015294160303 aF-0.13840207228874429 aF-0.18122514256394176 aF-0.076641756908064698 aF0.030597745331824355 aF-0.058956694838592179 aF-0.1452683092198872 aF0.11685319054521937 aF-0.077571103085402243 aF-0.0012293937905002597 aF-8.9003160703675995e-05 aF-0.027172367706111301 aF0.043200973733066972 aF-0.028760322372627802 aF-0.18126919854557264 aF-0.11209150985942504 aF0.026481546539927601 aF-0.13688677454289985 aF-0.037820437007946864 aF-0.10254847813891957 aF-0.12795084682853158 aF-0.11123817623942317 aF-0.04375560765388805 aF0.018918287729728357 aF-0.012649380192028931 aF0.11591993055331405 aF-0.026731181846773856 aF-0.1653132836256232 aF0.0010603916403064677 aF0.0077750104820258651 aF0.034481861908635551 aF0.054448561286509302 aF0.13922822991158412 aF-0.059676409138558852 aF0.028411190151574905 aF-0.0014354021257452765 aF-0.063211119633508089 aF0.23271898099751898 aF-0.028063547380331507 aF-0.15354713309711385 aF0.19282612550218259 aF0.035463385826031861 aF-0.12190269293450637 aF0.067577907184326144 aF0.13832381804641797 aF-0.097610483953971053 aF0.014725351182560374 aF-0.015146338004887164 aF-0.12673458775376073 aF0.12894861162379193 aF-0.0016808318167076777 aF0.058413039472488555 aF-0.078044226896787625 aF-0.071413430514105217 aF0.034245140430225592 aF0.011635802509755055 aF0.20133562660191837 aF-0.029968665465767808 aF0.2410248095114626 aF0.164331410680021 aF-0.2118873402834307 aF-0.18307010286194636 aF-0.062478000756624734 aF-0.020241942801833085 aF0.00097323882365007953 aF0.091173223707965781 aF-0.078680631082447258 aF-0.07859564042940495 aF-0.021915673178974578 aF-0.0022292655246742323 aF0.030380911247260761 aF0.11528545606273045 aF0.067722043900426313 aF-0.19070345915690118 aF0.0759656283006334 aF0.088399297212447978 aF0.069320303280407711 aF0.14271373872014315 aF0.035632402034600837 aF-0.073312580542513731 aF-0.016267006740299402 aF-0.26678400460112717 aF0.051557417564956375 aF0.012739487327996155 aF-0.064391958352890494 aF-0.071320648914749735 aF-0.11772201154673698 aF-0.00519956679273489 aF0.041323936760450208 aF-0.035987915002732372 aF-0.05445646816548369 aF-0.0039193334123252621 aF-0.019037534918053985 aF-0.10427977126792852 aF0.1408038403997238 aF0.048030537959775722 aF0.13953943528531315 aF-0.054220248277118056 aF-0.12186751367406615 aF0.08798139558526144 aF0.0044880803988166882 aF-0.082377663368142451 aF-0.0097092930183985734 aF-0.21883431946095702 aF0.11807672458987292 aF-0.10688609639962256 aF-0.075000581577427367 aF0.1459163371476368 aF-0.099048498563631557 aF-0.044974699755641584 aF-0.055138939455148785 aF0.17644739554527483 aF0.0088129274186113399 aF-0.11776500158360284 aF-0.12249946516810253 aF0.189076083528436 aF0.21105725441858653 aF0.17811632703103841 aF-0.13681597314575153 aF-0.023261730525026118 aF-0.021670683441533216 aF0.033497454991407542 aF-0.062346333333855579 aF-0.10650022689755148 aF-0.048673229346148268 aF0.11787779415825507 aF0.25846465199197088 aF0.024977548823577698 aF-0.02904461916020331 aF0.076436731823846332 aF-0.053115721056811678 aF0.20288942325829168 aF0.12057494122875574 aF-0.13372500006643015 aF-0.072974004377627202 aF0.14607428983794427 aF0.042275896557660717 aF0.042817915428542047 aF-0.18598856149033577 aF0.024821805241696551 aF0.074689486917569617 aF-0.069368797409821409 aF-0.10921894068898159 aF-0.020220607376157947 aF-0.11482116372717897 aF-0.007793161691459943 aF0.030414508987519139 aF0.14959789275756513 aF0.019591001610441611 aF-0.059044630151178341 aF0.1780207214689784 aF0.089894898655458591 aF0.025137989117187506 aF0.073164513996255509 aF-0.055347516929667565 aF0.093286750630726833 aF0.029249451733341019 aF0.068081736044857913 aF-0.11409186755203307 aF0.16728841327795888 aF0.047324213097212589 aF-0.20884339422840931 aF0.051192911141795451 aF0.13882157365397593 aF0.069559688550145576 aF0.15041568317065221 aF0.14377721924748746 aF-0.099068768787591702 aF-0.25116132699664229 aF0.19485551588175759 aF0.042571600028842756 aF0.0022139618067442235 aF-0.044225147227447005 aF-0.16720389786495465 aF0.02411530200928385 aF-0.14972897564654417 aF-0.091427656893414269 aF-0.022728499012089131 aF0.08234546141490133 aF0.040930671806609718 aF-0.14656270183041825 aF0.16142834351606136 aF0.0035661145637065753 aF0.20375797374688584 aF-0.13170150892157881 aF-0.085256084203139335 aF-0.083585744805455955 aF-0.011677854602788697 aF-0.10643577053217325 aF-0.10501214608766023 aF-0.25917538854437566 aF-0.091308087961901305 aF0.028033973606397342 aF-0.020025975991481974 aF-0.018259189784959537 aF-0.012744198980566546 aF0.018354276792395773 aF-0.054598960199194871 aF-0.076807573784959879 aF0.055356972886135496 aF-0.045853131429437137 aF0.024960667800576597 aF-0.10452290870943119 aF-0.015909164589905343 aF0.081106327692884408 aF-0.097006278322856201 aF0.01514871808610499 aF-0.025724403656486667 aF-0.0082201480966062387 aF-0.039061068740104107 aF-0.22632736979755652 aF-0.015637166926041612 aF0.15178379898882005 aF0.07100434675126939 aF-0.041083083472510461 aF-0.072054368716034142 aF0.027120263119125541 aF-0.041778372612671755 aF-0.05757000259232347 aF0.0060337372424810456 aF0.13657941014069577 aF-0.27451685946657306 aF0.063711362510221234 aF-0.10981360250779883 aF0.10286576591665671 aF-0.26405402335554562 aF-0.024383100024041291 aF0.0063258487363441309 aF-0.046255372045695138 aF-0.022104887553545578 aF-0.16482719862185519 aF-0.12269925753297119 aF-0.088782345111137737 aF0.039937163732216334 aF-0.063847600902896387 aF0.16747781270608153 aF0.01525870657873942 aF-0.20292068115794726 aF-0.049477572422454284 aF-0.071033760708656801 aF0.011254943705492577 aF-0.024034528767243057 aF-0.030397618260174054 aF-0.079921547960864217 aF-0.0070299722908437317 aF-0.15730273362219824 aF0.066705353642745754 aF-0.14417593327352196 aF-0.072068924309443019 aF-0.015916998855392411 aF0.027025160816212056 aF-0.008347975635986004 aF0.18934772710557662 aF0.17668967818305148 aF0.06824085979940521 aF0.010001723033531109 aF-0.087976757898622901 aF-0.050255804506895166 aF-0.15315940091384242 aF-0.040799424630402037 aF-0.051298764678507455 aF0.19077757184164942 aF0.082052602319217419 aF0.0070796206965107328 aF-0.031892305071236172 aF0.0090223155036073463 aF0.083465148875494208 aF0.24367147492332181 aF0.035609439521581 aF0.09404410509610385 aF0.074009050366022316 aF0.060432579873736771 aF0.10911271513564805 aF0.13718907384598433 aF0.0048096008945879816 aF-0.03422062038389511 aF0.024696420519342288 aF0.10857473973271953 aF0.13245547001126098 aF-0.059119344311806966 aF0.099373689674528462 aF-0.018752212216090598 aF-0.036597253474640323 aF0.058986918507246473 aF0.10153963232292151 aF-0.062120531673706021 aF-0.16325073330027248 aF-0.0054844079856175018 aF0.06024381144998503 aF0.0090958510001425911 aF0.17184768846501866 aF-0.036032922346402055 aF0.086620274611331857 aF-0.085492286299660727 aF-0.13759827102485228 aF0.072622130481076311 aF-0.15170653459972169 aF-0.14167690782769218 aF-0.065908152043950979 aF-0.16215692964682762 aF0.060844935422510842 aF-0.030213618687332022 aF-0.14092768433196676 aF-0.096781779206510751 aF-0.10746666746651859 aF-0.0078016755711929715 aF-0.26303371546111293 aF-0.075638981993101567 aF-0.15157110718952155 aF0.035910217419041844 aF0.065202505395937485 aF0.016032567345209772 aF-0.011050267039152576 aF-0.28704191305119819 aF0.0030560015917348747 aF-0.095460935057567309 aF-0.028919813495361529 aF-0.035684733847812442 aF-0.12617381081517315 aF0.06318815704056259 aF0.026117815167530572 aF-0.038223685204595535 aF0.097180841418793421 aF0.17193214840177426 aF-0.12071904300093587 aF-0.00282480130863415 aF-0.12098634611228755 aF0.081792199509522989 aF0.054485747848417435 aF-0.056347868466662218 aF-0.060917544136144149 aF-0.08206850721072427 aF0.10085350234227369 aF-0.027072586888005842 aF-0.016322238773978457 aF-0.13708561051422924 aF0.034055278801554907 aF0.29306559879887312 aF0.031558095816077221 aF-0.15499319401696574 aF0.026883627672430774 aF-0.15640606864830528 aF0.016184829110890087 aF-0.18443503698625646 aF0.078344872239879043 aF0.12437914246514728 aF0.16906034015175589 aF0.15072589090650571 aF-0.082582858851427673 aF0.048221511951321405 aF0.099250544970391236 aF-0.11700562881270533 aF0.021978954654336528 aF0.083102584830475612 aF-0.14032880679491039 aF-0.10381099582364391 aF0.084770520429373691 aF-0.00068967572326516569 aF0.057135025339246769 aF0.14861709041888826 aF0.052511004775865427 aF-0.085739099970632227 aF0.081919118538924598 aF-0.018179951896739256 aF-0.088915894410867849 aF0.22811720996929766 aF0.008731424476144202 aF-0.10210433619592615 aF0.069254270332745421 aF0.18323189512109797 aF0.064667600514845033 aF0.086075386003257939 aF0.011465838775142515 aF-0.017274772159821834 aF0.094872394093905785 aF-0.021216084178903347 aF0.0082218209454432371 aF-0.057369021790076642 aF-0.074673312534012187 aF-0.029236836531086646 aF-0.12945259166809472 aF0.027078977095147207 aF0.011160577614654736 aF-0.004467088424104604 aF-0.24484061389055975 aF-0.055641488757311945 aF0.027151273139604592 aF0.04021848262191545 aF0.019520802558325334 aF-0.0040614724075353735 aF-0.17465672758504019 aF0.036969528476953034 aF-0.014285184711580721 aF0.052854200678004122 aF0.065224969749770476 aF-0.0093717836003376891 aF0.03543572304234175 aF-0.03650886269521731 aF-0.03512603766345572 aF-0.04165396523517316 aF-0.10385556206650205 aF0.025444582246111947 aF0.13456150491767382 aF-0.063022400198104289 aF-0.054635025640397558 aF0.078745212584835772 aF0.004302771621922408 aF0.16789936321638935 aF-0.1853043687096679 aF-0.11261071723849231 aF-0.083194571109282078 aF0.2370891893945862 aF0.047017709151465102 aF-0.04834160633984682 aF0.003267603037140058 aF-0.034387639133045184 aF0.10652172390375617 aF0.0019929539991309139 aF0.089104866662205948 aF0.076509601069335187 aF-0.025193483058833576 aF-0.01238478627198507 aF0.013937213747456701 aF-0.087083779066319394 aF-0.025993218355501287 aF-0.0097456871140634751 aF-0.11146938927188198 aF0.10213079153096691 aF-0.12328395822386423 aF-0.077420405915042137 aF-0.1273996984528642 aF0.11606350652495633 aF-0.074118763497391382 aF-0.18799722449492529 aF0.088585983261250945 aF0.15706989054637469 aF0.073234042505101585 aF0.015105481392371061 aF-0.09363341801796965 aF-0.08194649306358677 aF0.13394824748765219 aF0.12535754555504958 aF-0.066235268060271815 aF0.087818896732836729 aF0.023653389946325647 aF-0.040683020672773434 aF-0.090637322238969392 aF0.031249810436904411 aF-0.1981411488444646 aF-0.17136051864498461 aF0.21957675131751392 aF-0.007841369294604543 aF0.28638052178590517 aF-0.026505757237590941 aF0.018875892987523662 aF0.10056965927981314 aF-0.019450689550622312 aF-0.056831978473320478 aF0.15599092702035544 aF-0.094786334837419176 aF0.087969649391793997 aF-0.055626038278359935 aF0.080994789724214603 aF0.092365890345922824 aF-0.090405321274879213 aF0.058061804263721102 aF0.11251344969759916 aF-0.11460234047431879 aF0.039446897887691255 aF-0.0040073539490906064 aF-0.13373260957475469 aF-0.029967924537691308 aF-0.017477029773429138 aF-0.11803933598894803 aF-0.21288236983954736 aF-0.099075089325871932 aF-0.00060771927913954899 aF-0.18774855079991873 aF0.13759345245432611 aF-0.065408272257620442 aF-0.22483386511406242 aF0.012082094842997404 aF0.16205341435466533 aF0.0057737938332414196 aF0.017645389232648179 aF-0.0029279488857894358 aF0.018908540531605893 aF0.096099036437980942 aF0.019858261505830404 aF0.082278185661047012 aF0.05534279702140401 aF0.014366377125894229 aF0.030513169913774653 aF-0.10706660103823593 aF-0.10284426286600654 aF-0.0014224218474195866 aF0.038600639614610167 aF-0.097465199369841007 aF0.088467398894731819 aF0.011932462914636116 aF0.29757192091411333 aF0.044780950612495159 aF-0.14236314497595079 aF0.041810000501406826 aF0.054413485350940212 aF-0.055642481230219518 aF0.025591257844392486 aF-0.065124141234068358 aF0.0022626712863536478 aF0.045692040637950036 aF0.12975301114626756 aF0.08401230427747082 aF-0.28804859100671387 aF0.031093335721601369 aF0.089990485664747127 aF-0.00088482457201784605 aF0.093514050802549806 aF0.084401637789930123 aF0.14226329038712243 aF0.13415385696408311 aF0.10442123304903894 aF-0.18023832538139095 aF-0.10788889283528291 aF0.074646257621031137 aF-0.1061975667014108 aF-0.066093720530668296 aF0.074815947893808299 aF0.0021840242439781594 aF0.11588522422991687 aF-0.14608740639825177 aF0.052235519677218498 aF-0.17799712748374791 aF-0.15715686453250796 aF0.032003109827795924 aF-0.015290576115307311 aF-0.12313378708968675 aF-0.031867663311352976 aF-0.063458606261120945 aF-0.09764379306223156 aF0.027081384859451677 aF-0.16227663700789621 aF0.034152098847243434 aF-0.22060278072985975 aF0.057625548703312407 aF0.037416038262748898 aF0.082593791066940689 aF-0.075376576199407574 aF0.074095321559523336 aF-0.11683736900745113 aF0.098016766072835285 aF-0.23127929226245159 aF0.031015161333826851 aF-0.079884609929352771 aF-0.084247754874148192 aF0.016540893941334234 aF-0.036694041244855015 aF0.10574992010134951 aF-0.011681803786322513 aF0.11040484364061344 aF-0.051781948715113942 aF0.0075108733765325382 aF0.043420668516944733 aF0.1216071149484908 aF0.067588908146396121 aF-0.031337849919446673 aF-0.14943427090853711 aF-0.074715149074777568 aF0.036132111294399409 aF-0.10868693012735398 aF0.031745660829168645 aF0.12059970080144922 aF0.026684591378337098 aF0.017971653563712095 aF0.044252853113847315 aF0.13246303973315673 aF0.15778425671071256 aF-0.11167345813968702 aF0.022377232847357344 aF0.064149942323049713 aF-0.028761441031593438 aF0.27182770513610582 aF0.093242748409891343 aF-0.092698722904248618 aF0.0884421064747095 aF0.076280904353520515 aF0.082783960858972813 aF-0.18659594209756156 aF0.16743556929369902 aF-0.17536882991248864 aF0.1208663294991984 aF-0.12088572408209365 aF0.04199114858719967 aF0.10514751722115181 aF0.089141293760822415 aF0.0040359125975843197 aF-0.10087525746777923 aF-0.012191871410870258 aF-0.08747812321495145 aF-0.18137759635861819 aF-0.098194168883553548 aF0.064091932843957547 aF0.060367398507673149 aF-0.045226871133904056 aF0.0067316294046476498 aF0.049830355875853154 aF0.021679601060003162 aF0.02805708827761523 aF0.22666451320399861 aF-0.24807099638694616 aF0.036931443851006322 aF0.031579621227516771 aF0.072143454900635132 aF-0.06327607031837619 aF0.096707346505539651 aF0.018722789931641753 aF0.092466452429488505 aF0.10498828036095313 aF0.14400327494914161 aF-0.0070094187551511533 aF0.14347331532442872 aF0.024839091586394583 aF-0.15573767433949129 aF-0.016307693677312111 aF-0.055008693850193489 aF-0.18836420747296501 aF-0.045477380151625252 aF-0.066991660350122981 aF0.078517882628457034 aF0.036968630226676728 aF0.096172821362334002 aF0.03096428173460071 aF-0.015854561720605394 aF-0.0097655854800728237 aF0.03149976947477498 aF0.12689096969094771 aF0.087772210782490659 aF-0.14767716163243502 aF0.013169480327563 aF-0.024202974260102598 aF0.06228172216203063 aF-0.032695829164779429 aF0.12356256463592434 aF-0.019538209050082016 aF-0.15981506431457013 aF0.15200213438740301 aF0.048022479997309978 aF0.061590170091398132 aF-0.075559849635879653 aF0.090837633315973457 aF-0.24372904871434006 aF0.11957197391032559 aF-0.00017613890291797655 aF-0.17588371118407306 aF-0.13385148185046231 aF0.022593639626333196 aF0.024068339945346 aF-0.1095966739401696 aF-0.049354910650388516 aF0.15244958751340484 aF-0.050324094602053074 aF0.0035639104883209423 aF0.087015531333936844 aF0.097694721319296643 aF0.015021249497558165 aF-0.17638188646122324 aF-0.17937316676669177 aF0.046701228497931131 aF-0.080310317967462699 aF0.061540288116242736 aF-0.15078434188818388 aF0.050139341325869051 aF0.068561973420778036 aF0.041378706770063077 aF-0.11038719362728393 aF-0.037826928719204171 aF0.048139762705270837 aF-0.17323299225540204 aF-0.07640890212034912 aF-0.1173885387007613 aF0.10917690534684521 aF0.18840114013527673 aF0.077238497404089029 aF-0.081472222807072517 aF0.024931147936774797 aF-0.024346627056021936 aF-0.092951629686625431 aF0.037650891797097068 aF0.01195720516792574 aF-0.12342771664204136 aF-0.074416134441641676 aF-0.030268297223749529 aF0.071329601029644571 aF-0.13599393575199947 aF-0.065092976687179921 aF-0.052486300166637155 aF0.10712374986977127 aF0.19195679963661544 aF0.15549414879972454 aF0.099323001153812235 aF0.035602459829127055 aF0.0075839028778393837 aF-0.16337680091885587 aF-0.04555918692992033 aF-0.0022916457452067125 aF0.024883450017052007 aF-0.10982791358719954 aF-0.07240068492889018 aF0.060805023761267278 aF-0.12947395321345848 aF-0.084477157965542365 aF0.029525996633624037 aF0.16721273307434836 aF-0.11463052433105551 aF0.068145288251539038 aF-0.086889479441911055 aF-0.034153550859299407 aF-0.065601782333039163 aF0.13715586768769539 aF0.0935190718890163 aF-0.22934019038356929 aF-0.03931872946836952 aF0.060301759526809898 aF-0.16954483645838328 aF-0.022513152030377195 aF-0.04635924501556437 aF0.053789784671182859 aF-0.094872411493646253 aF0.0086960342054503703 aF-0.056822635373481714 aF-0.15401908223176772 aF-0.041863017871182261 aF-0.049883804319587707 aF-0.031751389755047807 aF-0.032813869340476386 aF-0.17305363128762391 aF0.1192062316993875 aF0.14424825493758009 aF-0.013778071229778749 aF-0.080303017172008759 aF0.023281483842316576 aF-0.043631683044651148 aF0.0070740001985779575 aF-0.19150743327754091 aF0.18374607203251675 aF0.035665375877475605 a(I100 I10 tp4 S'd' p5 tp6 Rp7 sS'b' p8 g2 ((lp9 F-0.16143195583510889 aF-0.67768343369526307 aF0.16084359462457573 aF0.10428881011413052 aF-0.2655660443561319 aF0.35919523061889325 aF0.16074025143663787 aF-0.11421264589574148 aF0.098575589230285338 aF-0.021461162957776336 aF1.2870291537691783 aF0.22335913212959874 aF-0.18518011941716028 aF0.72719403274095085 aF-0.054520392271940908 aF0.055706624603291927 aF0.37152784451573234 aF-0.0026790126321343567 aF-0.065305446670940251 aF-0.28319748376470066 aF0.12179419200875374 aF-0.46190759357216132 aF0.24532948045493169 aF0.57741574009209129 aF-0.20038800518743327 aF0.28434957039940145 aF0.41205424755274606 aF-0.52413630165258562 aF-0.43005085334118509 aF0.21446375085140315 aF-0.10612113952760373 aF0.25388213127924197 aF0.25844013670185351 aF0.2311036000053617 aF0.4426226427094434 aF0.25002892502222307 aF0.41806883402445871 aF-0.41824718377434011 aF-0.049830631694555358 aF-0.090913971598374915 aF-0.52843704660670243 aF0.091982740793313131 aF-0.34299336373036504 aF0.51841960641550788 aF-0.24989594994933934 aF0.15668483679512873 aF0.086065466792963577 aF-0.30200799730645128 aF-0.69916629701899902 aF-0.035171689140503309 aF-0.34615218824469418 aF0.18552621575276762 aF0.1765564681877021 aF0.56172664224590207 aF0.16514178827701431 aF-0.26105954348224142 aF0.13476505078644202 aF-0.27374501099003851 aF-0.017102093695764001 aF-0.068996860348989178 aF0.051640117356078631 aF-0.12095289663013524 aF0.40856213778679173 aF-0.67228595777644418 aF0.1363984331429296 aF0.31097275492788917 aF0.26695864898146232 aF0.18710267994878738 aF-0.0029622200880384877 aF0.25177200926602317 aF0.18701557903892782 aF-0.10280763300825679 aF-0.15555116047213355 aF-0.089792732233990868 aF-0.48911861854845107 aF-0.12748333832274483 aF0.071923350466736591 aF0.11594797486324034 aF0.48429640311993932 aF-0.13201718008527658 aF0.23117313315298862 aF0.2262593150867224 aF0.33708782380681585 aF-0.32833055771415132 aF0.054518808290491542 aF0.063110698981614963 aF-0.28119470239217825 aF-0.24684768490375322 aF0.30522250706068588 aF0.008667421388934643 aF0.15682379142847355 aF0.037458202825196588 aF-0.14092181857921926 aF-0.17069068456403164 aF0.14970644989506304 aF-0.2752575961425312 aF0.28359094471774626 aF0.20607585138147697 aF-0.24478992166892741 aF-0.081555771076436148 a(I100 I1 tp10 g5 tp11 Rp12 s.cvxopt-1.1.4/examples/book/chap6/0000755000175000017500000000000011674452555015655 5ustar sonnesonnecvxopt-1.1.4/examples/book/chap6/cvxfit.bin0000644000175000017500000000402011674452555017646 0ustar sonnesonne(dp0 S'y' p1 ccvxopt.base matrix p2 ((lp3 F5.2057354002832819 aF5.168529540303874 aF4.4693174707257226 aF3.1676414922996394 aF3.2186726818679299 aF2.7558774192658637 aF1.6360627918193327 aF0.72527756034765778 aF0.24583926693470126 aF-0.58044829477967541 aF-0.87676552269878805 aF-0.82548372091436673 aF-0.79731422846855127 aF-0.059483960079878162 aF-0.049755248937001624 aF0.70500263843069 aF0.82600210585526379 aF0.14030590460768733 aF0.51054544095596399 aF0.38582234301290158 aF0.83860085513607274 aF0.41632982151136116 aF0.81154681718230726 aF0.23060126778692916 aF0.84177419098779471 aF0.34454158681673575 aF0.37408513903614865 aF0.86597228912388624 aF0.21207009757657225 aF0.71788999284982635 aF0.80995602827825564 aF1.0691093387601871 aF0.64850168698870958 aF1.0924843876810013 aF0.76143044835863438 aF1.2122857008556023 aF1.177289163343745 aF0.84659501315421903 aF0.95866894737433894 aF1.82113177659879 aF1.801593575785722 aF1.6354388665511546 aF1.7742952550818938 aF2.5264766809146635 aF2.6522776387129992 aF3.750115148675202 aF4.0564222166126189 aF4.6247681095994553 aF4.9123027288568162 aF5.8068945924150048 aF7.0260934631317404 a(I51 I1 tp4 S'd' p5 tp6 Rp7 sS'u' p8 g2 ((lp9 F0.0 aF0.040000000000000001 aF0.080000000000000002 aF0.12 aF0.16 aF0.20000000000000001 aF0.23999999999999999 aF0.28000000000000003 aF0.32000000000000001 aF0.35999999999999999 aF0.40000000000000002 aF0.44 aF0.47999999999999998 aF0.52000000000000002 aF0.56000000000000005 aF0.59999999999999998 aF0.64000000000000001 aF0.68000000000000005 aF0.71999999999999997 aF0.76000000000000001 aF0.80000000000000004 aF0.83999999999999997 aF0.88 aF0.92000000000000004 aF0.95999999999999996 aF1.0 aF1.04 aF1.0800000000000001 aF1.1200000000000001 aF1.1600000000000001 aF1.2 aF1.24 aF1.28 aF1.3199999999999998 aF1.3599999999999999 aF1.3999999999999999 aF1.4399999999999999 aF1.48 aF1.52 aF1.5600000000000001 aF1.6000000000000001 aF1.6400000000000001 aF1.6799999999999999 aF1.72 aF1.76 aF1.8 aF1.8400000000000001 aF1.8799999999999999 aF1.9199999999999999 aF1.96 aF2.0 a(I51 I1 tp10 g5 tp11 Rp12 s.cvxopt-1.1.4/examples/book/chap6/inputdesign.py0000644000175000017500000000406211674452555020562 0ustar sonnesonne# Figure 6.6, page 309. # Input design. from math import cos, sqrt from cvxopt import lapack, matrix try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True m, n = 201, 201 # Jtrack = 1/n * ||H*u-ydes||_2^2. H = matrix(0.0, (m,m)) for t in range(m): H[t::m+1] = (1.0/9.0) * .9**t * (1.0 - 0.4 * cos(2*t)) ydes = matrix( 40*[0.0] + 50*[1.0] + 50*[-1.0] + 61*[0.0] ) # Jmag = 1/n * ||I*u||_2^2 I = matrix(0.0, (n,n)) I[::n+1] = 1.0 # Jder = 1/(n-1) * ||D*u||_2^2 D = matrix(0.0, (n-1,n)) D[::n] = -1.0 D[n-1::n] = 1.0 AA = matrix(0.0, (m + 2*n - 1, n)) bb = matrix(0.0, (m + 2*n - 1, 1)) AA[:n,:] = H bb[:n] = ydes delta, eta = 0.0, 0.005 AA[n:2*n,:] = sqrt(eta)*I AA[2*n:,:] = sqrt(delta)*D x = +bb lapack.gels(+AA, x) u1 = x[:n] if pylab_installed: pylab.figure(1, facecolor='w', figsize=(10,10)) ts = matrix(range(n), tc='d') pylab.subplot(321) pylab.plot(ts, u1, '-') pylab.xlabel('t') pylab.ylabel('u(t)') pylab.axis([0, 200, -10, 5]) pylab.title('Optimal input (fig. 6.6.)') pylab.subplot(322) pylab.plot(ts, H*u1, '-', ts, ydes, 'g--') pylab.xlabel('t') pylab.ylabel('y(t)') pylab.axis([0, 200, -1.1, 1.1]) pylab.title('Output') delta, eta = 0.0, 0.05 AA[n:2*n,:] = sqrt(eta)*I AA[2*n:,:] = sqrt(delta)*D x = +bb lapack.gels(+AA, x) u2 = x[:n] if pylab_installed: pylab.subplot(323) pylab.plot(ts, u2, '-') pylab.xlabel('t') pylab.ylabel('u(t)') pylab.axis([0, 200, -4, 4]) pylab.subplot(324) pylab.plot(ts, H*u2, '-', ts, ydes, 'g--') pylab.ylabel('y(t)') pylab.xlabel('t') pylab.axis([0, 200, -1.1, 1.1]) delta, eta = 0.3, 0.05 AA[n:2*n,:] = sqrt(eta)*I AA[2*n:,:] = sqrt(delta)*D x = +bb lapack.gels(+AA, x) u3 = x[:n] if pylab_installed: pylab.subplot(325) pylab.plot(ts, u3, '-') pylab.xlabel('t') pylab.ylabel('u(t)') pylab.axis([0, 200, -4, 4]) pylab.subplot(326) pylab.plot(ts, H*u3, '-', ts, ydes, 'g--') pylab.ylabel('y(t)') pylab.xlabel('t') pylab.axis([0, 200, -1.1, 1.1]) pylab.show() cvxopt-1.1.4/examples/book/chap6/polapprox.bin0000644000175000017500000000354411674452555020401 0ustar sonnesonne(dp0 S'y' p1 ccvxopt.base matrix p2 ((lp3 F-0.082103425893059981 aF-0.077658017081031816 aF-0.044154955666689109 aF-0.027978495767535284 aF-0.028653493677588893 aF0.0076713634401920257 aF0.020080899761448615 aF0.019932321303742423 aF0.035638548853098133 aF0.046383747342975547 aF0.055565245592635898 aF0.078338990521136007 aF0.080026173863524147 aF0.12401050741944375 aF0.11860999883627903 aF0.14015932722458307 aF0.16910670293333385 aF0.17713978855464221 aF0.18995845130900052 aF0.19062838398418774 aF0.20189935838561909 aF0.17764415001158707 aF0.18411166959318781 aF0.17583110060882948 aF0.13456015420480544 aF0.13304152533273264 aF0.1221260708609055 aF0.081351196920178989 aF0.073236116455466155 aF0.086269618897523839 aF0.071862897042482929 aF0.08028786841829133 aF0.081146142657454193 aF0.081671563556176829 aF0.090894683237619942 aF0.089940590418169097 aF0.10221834607855008 aF0.087124543198926277 aF0.10958163681660973 aF0.12065504923390243 a(I40 I1 tp4 S'd' p5 tp6 Rp7 sS't' p8 g2 ((lp9 F-1.0 aF-0.94871794871794868 aF-0.89743589743589747 aF-0.84615384615384615 aF-0.79487179487179493 aF-0.74358974358974361 aF-0.69230769230769229 aF-0.64102564102564097 aF-0.58974358974358976 aF-0.53846153846153844 aF-0.48717948717948723 aF-0.4358974358974359 aF-0.38461538461538458 aF-0.33333333333333337 aF-0.28205128205128205 aF-0.23076923076923073 aF-0.17948717948717952 aF-0.12820512820512819 aF-0.076923076923076872 aF-0.025641025641025661 aF0.02564102564102555 aF0.076923076923076872 aF0.12820512820512819 aF0.17948717948717952 aF0.23076923076923084 aF0.28205128205128216 aF0.33333333333333326 aF0.38461538461538458 aF0.4358974358974359 aF0.48717948717948723 aF0.53846153846153855 aF0.58974358974358965 aF0.64102564102564097 aF0.69230769230769229 aF0.74358974358974361 aF0.79487179487179493 aF0.84615384615384626 aF0.89743589743589736 aF0.94871794871794868 aF1.0 a(I40 I1 tp10 g5 tp11 Rp12 s.cvxopt-1.1.4/examples/book/chap6/penalties.py0000644000175000017500000000474411674452555020224 0ustar sonnesonne# Figure 6.2, page 297. # Penalty approximation. # # The problem data are not the same as in the book figure. from cvxopt import lapack, solvers, matrix, spdiag, log, div, normal from cvxopt.modeling import variable, op, max, sum #solvers.options['show_progress'] = 0 try: import numpy, pylab except ImportError: pylab_installed = False else: pylab_installed = True m, n = 100, 30 A = normal(m,n) b = normal(m,1) b /= (1.1 * max(abs(b))) # Make x = 0 feasible for log barrier. # l1 approximation # # minimize || A*x + b ||_1 x = variable(n) op(sum(abs(A*x+b))).solve() x1 = x.value if pylab_installed: pylab.figure(1, facecolor='w', figsize=(10,10)) pylab.subplot(411) nbins = 100 bins = [-1.5 + 3.0/(nbins-1)*k for k in range(nbins)] pylab.hist( A*x1+b , numpy.array(bins)) nopts = 200 xs = -1.5 + 3.0/(nopts-1) * matrix(list(range(nopts))) pylab.plot(xs, (35.0/1.5) * abs(xs), 'g-') pylab.axis([-1.5, 1.5, 0, 40]) pylab.ylabel('l1') pylab.title('Penalty function approximation (fig. 6.2)') # l2 approximation # # minimize || A*x + b ||_2 x = matrix(0.0, (m,1)) lapack.gels(+A, x) x2 = x[:n] if pylab_installed: pylab.subplot(412) pylab.hist(A*x2+b, numpy.array(bins)) pylab.plot(xs, (8.0/1.5**2) * xs**2 , 'g-') pylab.ylabel('l2') pylab.axis([-1.5, 1.5, 0, 10]) # Deadzone approximation # # minimize sum(max(abs(A*x+b)-0.5, 0.0)) x = variable(n) op(sum(max(abs(A*x+b)-0.5, 0.0))).solve() xdz = x.value if pylab_installed: pylab.subplot(413) pylab.hist(A*xdz+b, numpy.array(bins)) pylab.plot(xs, 15.0/1.0 * matrix([ max(abs(xk)-0.5, 0.0) for xk in xs ]), 'g-') pylab.ylabel('Deadzone') pylab.axis([-1.5, 1.5, 0, 20]) # Log barrier # # minimize -sum (log ( 1.0 - A*x+b)**2) def F(x=None, z=None): if x is None: return 0, matrix(0.0, (n,1)) y = A*x+b if max(abs(y)) >= 1.0: return None f = -sum(log(1.0 - y**2)) gradf = 2.0 * A.T * div(y, 1-y**2) if z is None: return f, gradf.T H = A.T * spdiag(2.0 * z[0] * div( 1.0+y**2, (1.0 - y**2)**2 )) * A return f, gradf.T, H xlb = solvers.cp(F)['x'] if pylab_installed: pylab.subplot(414) pylab.hist(A*xlb+b, numpy.array(bins)) nopts = 200 pylab.plot(xs, (8.0/1.5**2) * xs**2, 'g--') xs2 = -0.99999 + (2*0.99999 /(nopts-1)) * matrix(list(range(nopts))) pylab.plot(xs2, -3.0 * log(1.0 - abs(xs2)**2), 'g-') pylab.ylabel('Log barrier') pylab.xlabel('residual') pylab.axis([-1.5, 1.5, 0, 10]) pylab.show() cvxopt-1.1.4/examples/book/chap6/smoothrec.py0000644000175000017500000000524211674452555020235 0ustar sonnesonne# Figures 6.8-10, pages 313-314 # Quadratic smoothing. from math import pi from cvxopt import blas, lapack, matrix, sin, mul, normal try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True n = 4000 t = matrix(list(range(n)), tc='d') ex = 0.5 * mul( sin(2*pi/n * t), sin(0.01 * t)) corr = ex + 0.05 * normal(n,1) if pylab_installed: pylab.figure(1, facecolor='w', figsize=(8,5)) pylab.subplot(211) pylab.plot(t, ex) pylab.ylabel('x[i]') pylab.xlabel('i') pylab.title('Original and corrupted signal (fig. 6.8)') pylab.subplot(212) pylab.plot(t, corr) pylab.ylabel('xcor[i]') pylab.xlabel('i') # A = D'*D is an n by n tridiagonal matrix with -1.0 on the # upper/lower diagonal and 1, 2, 2, ..., 2, 2, 1 on the diagonal. Ad = matrix([1.0] + (n-2)*[2.0] + [1.0]) As = matrix(-1.0, (n-1,1)) nopts = 50 deltas = -10.0 + 20.0/(nopts-1) * matrix(list(range(nopts))) cost1, cost2 = [], [] for delta in deltas: xr = +corr lapack.ptsv(1.0 + 10**delta * Ad, 10**delta *As, xr) cost1 += [blas.nrm2(xr - corr)] cost2 += [blas.nrm2(xr[1:] - xr[:-1])] # Find solutions with ||xhat - xcorr || roughly equal to 8.0, 3.1, 1.0. mv1, k1 = min(zip([abs(c - 8.0) for c in cost1], range(nopts))) xr1 = +corr lapack.ptsv(1.0 + 10**deltas[k1] * Ad, 10**deltas[k1] *As, xr1) mv2, k2 = min(zip([abs(c - 3.1) for c in cost1], range(nopts))) xr2 = +corr lapack.ptsv(1.0 + 10**deltas[k2] * Ad, 10**deltas[k2] *As, xr2) mv3, k3 = min(zip([abs(c - 1.0) for c in cost1], range(nopts))) xr3 = +corr lapack.ptsv(1.0 + 10**deltas[k3] * Ad, 10**deltas[k3] *As, xr3) if pylab_installed: pylab.figure(2, facecolor='w') pylab.plot(cost1, cost2, [blas.nrm2(corr)], [0], 'bo', [0], [blas.nrm2(corr[1:] - corr[:-1])], 'bo') pylab.plot([cost1[k1]], [cost2[k1]], 'bo', [cost1[k2]], [cost2[k2]], 'bo', [cost1[k3]], [cost2[k3]], 'bo') pylab.text(cost1[k1], cost2[k1],'1') pylab.text(cost1[k2], cost2[k2],'2') pylab.text(cost1[k3], cost2[k3],'3') pylab.title('Optimal trade-off curve (fig. 6.9)') pylab.xlabel('|| xhat - xcor ||_2') pylab.ylabel('|| D*xhat ||_2') pylab.axis([-0.4, 20, -0.1, 5]) pylab.grid() pylab.figure(3, facecolor='w', figsize=(8,7.5)) pylab.subplot(311) pylab.plot(t, xr1) pylab.axis([0, 4000, -0.6, 0.6]) pylab.ylabel('xhat1[i]') pylab.title('Three smoothed sigals (fig. 6.10).') pylab.subplot(312) pylab.plot(t, xr2) pylab.ylabel('xhat2[i]') pylab.axis([0, 4000, -0.6, 0.6]) pylab.subplot(313) pylab.plot(t, xr3) pylab.axis([0, 4000, -0.6, 0.6]) pylab.ylabel('xhat3[i]') pylab.xlabel('i') pylab.show() cvxopt-1.1.4/examples/book/chap6/robls.bin0000644000175000017500000023412211674452555017474 0ustar sonnesonne(dp0 S'6.16' p1 (dp2 S'A1' p3 ccvxopt.base matrix p4 ((lp5 F0.060692158613671936 aF0.13551661590847716 aF-0.17502709536245181 aF-0.063037297302464115 aF0.014935075566241917 aF0.044744644349989232 aF-0.046890482800718794 aF0.025285039094763633 aF-0.1039788695383739 aF-0.016078750634654217 aF-0.025576092297782037 aF0.081120696754861332 aF-0.045213169012554906 aF-0.076384272870508335 aF-0.075661165259473848 aF0.023626665153808794 aF-0.063221676766965704 aF0.13592483232601332 aF0.048680559916581323 aF0.027181736676694369 aF-0.012832661620716198 aF0.026767008849993876 aF0.11390502495296238 aF-0.18969994093555062 aF0.10959905874785433 aF-0.032081778936551592 aF0.00021374045196674831 aF0.074990571848910018 aF0.049374041941245235 aF-0.13683868137153848 aF-0.12746500526414692 aF0.048622601864251325 aF-0.077185782423571589 aF-0.13828259828092537 aF-0.030443977256897424 aF-0.033705728816664809 aF-0.098443443885964016 aF-0.094080449920338385 aF0.024640157809006739 aF-0.16193001279321245 aF0.11145227630200073 aF0.056398796214405474 aF-0.023321328463359759 aF-0.001951527057240684 aF-0.07696872925322433 aF-0.088470297688072422 aF0.031662744440395622 aF0.076422466932287825 aF0.10838115056771372 aF-0.010889181409712081 aF0.051948575428524997 aF0.16585309976092452 aF0.19211540785366352 aF-0.031700294366078068 aF0.18971747616051238 aF-0.013527531015241514 aF-0.059616817272019874 aF0.047765677876500615 aF-0.0042636019623572396 aF0.098637192455550443 aF0.055846875878276254 aF-0.13140027274671209 aF-0.25677689245733221 aF0.045824553840161798 aF-0.085532309934380421 aF0.076974724513215104 aF0.13413109105577808 aF-0.082996837801254067 aF0.085439373818847059 aF0.013435238914139938 aF-0.049753534949874161 aF0.13343415275593765 aF-0.043796099641046443 aF0.10408000507115905 aF0.13426438776907818 aF-0.17707932111697597 aF0.2500315404872393 aF0.11495805331632575 aF0.089013755970966973 aF-0.065032640077874043 aF-0.021841107501475165 aF-0.11629065823389129 aF-0.10745856696286438 aF-0.075864337491572009 aF0.049936785629542943 aF0.15619879824295907 aF0.11426654118739148 aF-0.04164325703106133 aF-0.18459138854021614 aF0.020090335181653159 aF-0.062340457839723744 aF-0.1508405333228898 aF0.03797931323112097 aF0.049269236947181307 aF0.072614197542196154 aF-0.022571006591697411 aF-0.035388742616540347 aF-0.017446086387622423 aF-0.01477727630010401 aF0.018443903308696562 aF0.14277685169221338 aF0.010132355635830433 aF0.055156767481759419 aF0.17632575933817657 aF-0.028755929312239546 aF0.061891308203607415 aF0.024919614987087068 aF-0.07197855066111282 aF-0.21479395921623348 aF-0.20166172670890611 aF-0.029353635875443873 aF-0.051788865031392364 aF-0.034602211597310556 aF-0.12000067646251812 aF0.019253060882884386 aF0.01762985486311416 aF-0.061010172885885589 aF0.064235100964646616 aF-0.13928780038109934 aF-0.089585533042703711 aF-0.021333249194368877 aF-0.11006818900338923 aF0.10454243372279894 aF0.12669861409093036 aF0.02000037342338052 aF-0.11904683573813117 aF0.055845399300637588 aF-0.21672289826114211 aF-0.045347068774837809 aF0.27147646941216608 aF0.037230572727025985 aF-0.09747658729717773 aF0.075170619973478417 aF-0.024022535453497394 aF0.087764952014292158 aF-0.030930520861569145 aF0.11375963160646478 aF0.085521570403032765 aF0.018130027836889797 aF-0.025368461123362121 aF0.021688212561136601 aF-0.01617619935056885 aF-0.0067019179196910915 aF0.059326050868915167 aF-0.067522324374755791 aF-0.067924418740172507 aF-0.00064412956066938257 aF-0.061611372824163436 aF-0.1263830152585404 aF0.073777841453974174 aF-0.022521142763372703 aF-0.13280802157396349 aF-0.033453145248487519 aF-0.012194502695457419 aF-0.19787301290362988 aF-0.11507795614984975 aF-0.15391504435278744 aF0.093960387529016295 aF-0.01204700081950502 aF0.094327849538079517 aF0.047408542121791915 aF0.040551172818206485 aF-0.057591105037616191 aF0.024156488566328512 aF-0.11299227187336165 aF-0.061371453859505952 aF-0.056253085411093952 aF0.016821930589098213 aF-0.15215012858565732 aF-0.11763233364319792 aF0.0167647322849835 aF0.12455420633608466 aF0.031067453957930355 aF-0.037533861826113617 aF-0.0041166258993559704 aF0.0065873155431801934 aF0.16597110521193559 aF-0.0061752823495857959 aF0.079582468631965678 aF-0.0067483505282747271 aF-0.067896919902647151 aF0.026229731090776417 aF0.089162821628087502 aF-0.14107438740291717 aF-0.092465915558588435 aF-0.016252923778101194 aF0.039282305898183552 aF-0.078339494298245424 aF-0.055071133638965729 aF0.052802359151763539 aF-0.11317641516369061 aF0.088812079377038763 aF0.073183840654319876 aF-0.054456897445780306 aF0.055948759910867632 aF0.10970157219852074 aF0.02666671550528291 aF0.072865588765081479 aF0.010907297298841184 aF0.0014044499857141974 aF-0.0061712957107568894 aF-0.084287168492835171 aF-0.063353205133051829 aF-0.0026120779459830067 aF0.083782347160056017 aF-0.050778352243772279 aF0.12517436549185965 aF-0.06898553106884743 aF0.054679696229415556 aF-0.11104123634084602 aF-0.073531210307305556 aF-0.04020052775877081 aF0.018854215384806482 aF0.15863113613205468 aF0.0093247724511201276 aF-0.034869168382521167 aF0.043337715501156129 aF-0.10164853147782818 aF-0.0081684404914932531 aF0.037791720028581291 aF-0.025076923445044277 aF-0.014240965623745452 aF0.015219800926800453 aF0.035697991390809099 aF0.14221599010312022 aF0.16928040275981268 aF0.059081324507438492 aF-0.11582756348756638 aF0.030775160923186145 aF-0.048068088028103167 aF-0.088512426450381695 aF0.059096152770960982 aF0.041030641285688584 aF-0.016424175460360287 aF-0.032050972790676771 aF-0.075137488792913126 aF-0.15599262562488683 aF-0.13802132182510918 aF-0.099501497967098285 aF-0.035214181262297632 aF0.014842112970621482 aF0.019448950691346882 aF-0.10518953102545445 aF0.059338999496764647 aF0.036186145660405275 aF0.12332299046287609 aF-0.043248238133030061 aF-0.0005642822946495406 aF-0.044546057470140982 aF0.060838920823669394 aF0.092260909855835224 aF0.042431576946535023 aF0.23496328203278374 aF-0.013589332447866096 aF0.036407536815402645 aF-0.16672617172773294 aF-0.046285735240573792 aF-0.1600783144894091 aF-0.0091510809565981208 aF-0.11156888978703662 aF-0.057018677036310417 aF-0.076493032996174382 aF-0.013122181183092014 aF0.080297278085604024 aF0.1314245564979406 aF0.03636951046889924 aF-0.047538286773007768 aF0.015199535954623649 aF-0.065400438015545931 aF-0.079970704911075122 aF-0.11931898196846778 aF-0.1615817963885863 aF-0.005534858663651188 aF0.056977732775431437 aF0.017474977279779532 aF-0.00068868222871107192 aF0.0016989316921270619 aF-0.047339250648454304 aF0.15988202102080365 aF-0.018647179945124447 aF-0.11989761188078994 aF-0.025669169045998391 aF-0.048282504424823743 aF-0.010299055676033406 aF-0.033074578629890321 aF-0.071569812093500051 aF-0.14730880773943511 aF-0.038105614814423323 aF-0.1312175345165445 aF-0.0081189057377445105 aF0.076946516022511166 aF0.20087002053953171 aF0.044060486457657456 aF0.034800014000183524 aF0.089227130284174797 aF0.036347794728549647 aF0.10978396557052823 aF-0.015771596018490274 aF0.011082209841973709 aF-0.055746720517846057 aF-0.064362738519264856 aF-0.050452262238833562 aF0.068866724979258803 aF0.0058949427060753911 aF-0.15544077153240565 aF0.15490467065651253 aF0.055445632098017242 aF-0.13094935474729463 aF-0.031797805759427381 aF0.017605638141093297 aF-0.064900776847605063 aF-0.009015677165866624 aF0.028717317152062324 aF0.087606027843657813 aF-0.11908612593464568 aF-0.087360934912493152 aF-0.054538338525216105 aF0.01447750047908085 aF0.11400136999906689 aF0.16413693797851017 aF0.062842675285585875 aF0.068831119131529825 aF-0.012105797792438082 aF-0.0084649560684905267 aF-0.067826762758254874 aF0.041812483258397322 aF0.1049085352394634 aF0.10985716627638997 aF-0.023582551006749528 aF0.01840576963004684 aF0.053466506527030978 aF-0.046500201772243219 aF0.01946576330331445 aF0.030119560406525168 aF0.044189006351908935 aF-0.052215529565619423 aF0.11408310561316637 aF0.082643702327128157 aF-0.20157631115866284 aF-0.092595351902511808 aF-0.027610245429438171 aF-0.17057558124234506 aF0.13288982394623117 aF0.019779878343450984 aF0.054796690564769455 aF-0.095739710563202005 aF0.016702843720022439 aF0.14384282514836819 aF0.061545521533579083 aF0.067182032792939259 aF0.051146245585978842 aF-0.0049509980245584706 aF-0.093981100021881578 aF0.18176529540679567 aF-0.11467802504827994 aF0.038741480310467098 aF0.033159702531841535 aF0.17572834558673328 aF-0.027407543224982053 aF0.12445287677037718 aF-0.04258809764732701 aF0.017767126023250038 aF0.063984034675111892 aF-0.080377531624257231 aF0.051977000055399118 aF0.14923698282993034 aF0.0075243367679389593 aF0.22002518272417992 aF-0.057259250211893417 aF0.23623605306560647 aF-0.0014264026110324694 aF0.023027715813956264 aF-0.077488012866453404 aF-0.16541677198780949 aF-0.026907384444613741 aF0.049872742131173473 aF0.070273627960712959 aF-0.14197627789973763 aF-0.16295189306895741 aF-0.037015639475495868 aF0.0038124358270698461 aF0.20485479422683522 aF-0.026269376282158308 aF0.015901324159782088 aF0.080335984198454696 aF-0.044563570878859503 aF-0.094569326893292185 aF-0.13498018926257177 aF0.099590973780942754 aF0.041125415974894136 aF0.13948658844022743 aF-0.038505130999862941 aF0.085512794223961741 aF0.1737269429074654 aF0.051032957749205222 aF0.0015139496359284235 aF-0.13651501956920184 aF0.10500840893836204 aF0.057947331655385445 aF-0.066180907119033502 aF0.045010850610702813 aF0.18094034628185204 aF0.030038984011222229 aF0.019641078955178828 aF0.10918148455445278 aF-0.0011434005921222093 aF-0.1130270069027238 aF-0.047160923345076301 aF0.064051559528141983 aF-0.077297412493438217 aF0.11627696374053907 aF0.02081770747911247 aF0.010074394717554423 aF0.032609988457247364 aF-0.0059467833918880218 aF-0.04902301833458788 aF0.039783000153971501 aF0.11017388303339844 aF0.13858104496919635 aF-0.059576749305072271 aF0.068430444944692442 aF-0.087096543685438982 aF0.1097338119460885 aF0.0012656390174823624 aF0.018539524695327485 aF0.14522616337109251 aF-0.17621929892560381 aF0.009571906524898274 aF-0.092101354526515633 aF-0.13209724016473276 aF0.054032563996613797 aF-0.034295728850524392 aF-0.03418969314570483 aF0.0071271181249787747 aF-0.036904333551751656 aF-0.047693246342666973 aF0.074432919613793863 aF-0.069057479358073326 aF-0.021901298186428612 aF0.041816744006189413 aF-0.068043967778948569 aF-0.00070601544350480975 aF0.053198891727609054 aF0.013086859960303046 aF0.21876763635724522 aF-0.11072986921392884 aF0.086763820858365634 aF0.065933350316867895 aF-0.070687981106195424 aF-0.049731168043798686 aF0.0055662897508956359 aF-0.0010461992090408613 aF-0.0065261120634650715 aF-0.13212068435617647 aF0.14432914600174751 aF-0.039755589177722407 aF0.0080207946951718449 aF0.024334901684386595 aF0.077933161671949414 aF0.043243990209341679 aF0.020805801038295768 aF-0.11872131591312268 aF0.08219003289222708 aF0.135096991028858 aF-0.12189155281176342 aF-0.13005597046444525 aF-0.0063330915812549529 aF0.006905278181827304 aF-0.0714810410386503 aF-0.047864275914533939 aF-0.00239105326424011 aF-0.10542802641028878 aF0.062139401910918816 aF0.0050505554731195678 aF0.012642853338764004 aF0.1352800372696647 aF-0.065887136994321055 aF0.13141626671591206 aF0.089431975573895678 aF-0.014127194362040683 aF0.026658640521277664 aF0.12033634216681247 aF0.02774911739971328 aF0.040320877381008757 aF0.033802174546835533 aF-0.0061686830346991883 aF0.11145358925513027 aF0.082928277135227532 aF0.14598279002799822 aF-0.034950625110999202 aF0.047906058063113259 aF0.062716802520371595 aF0.018661015068952951 aF0.11128602042569592 aF0.053332880702688094 aF-0.093923550981758461 aF-0.037892091252976899 aF-0.061542055138776496 aF0.030012260878746581 aF-0.042958816995269468 aF-0.17833363035550301 aF-0.056344976082441836 aF0.1229251049586929 aF-0.027957453549059132 aF0.22903643297871723 aF-0.13859298409387094 aF-0.045464025601946789 aF0.046387802920688379 aF0.12652724660815373 aF-0.0385907525643161 aF-0.042080916901400048 aF0.10471242190426343 aF0.003469302835174042 aF0.063447214089157516 aF0.10433123595673768 aF0.025846465598982474 aF0.091362138885425034 aF0.064861480791600298 aF-0.11186017406424642 aF-0.043163908298280235 aF0.047056901027637855 aF-0.16594696212785112 aF-0.064463252809937824 aF-0.20716707643514506 aF-0.055894112420909893 aF-0.0097297858442645605 aF0.025437591301385478 aF-0.049505024461236245 aF-0.26055985662010733 aF0.13148105375735658 aF-0.034532453567345939 aF0.12105895118270313 aF-0.11471369210731686 aF0.076629102383882583 aF0.045917175333841473 aF-0.039419541082836206 aF0.20602515351017334 aF0.17127505692769077 aF0.067585651184054685 aF0.0026275473385181697 aF0.045838129559369646 aF0.05797569433864299 aF-0.050018399706294472 aF-0.022131990528191613 aF0.12860116343836114 aF0.085384834173546975 aF0.02572085732839572 aF-0.069263522763915633 aF-0.041638117881924681 aF0.073534730420493674 aF0.030583973692698923 aF-0.0068129954400385087 aF0.063517878779181219 aF-0.15190428264301695 aF0.10284454596076188 aF-0.0051305898168892087 aF-0.033273756202930958 aF0.051671000918714939 aF0.054555943048633315 aF0.086424317595873462 aF0.079211749472967719 aF0.1041463369780436 aF-0.021148839298916557 aF-0.059981436811466178 aF-0.050338213531734954 aF-0.022235928378233065 aF0.105355573835343 aF-0.13129969459845792 aF-0.032785484923501099 aF0.023319947437186638 aF0.070032697899465174 aF-0.083012983071170429 aF-0.0088411902079527181 aF0.010837701391339166 aF0.0053017946396145517 aF0.031502397310720839 aF-0.0088128550245095329 aF-0.059065312256890379 aF-0.03279077617109448 aF0.0013676494536718306 aF0.11606742390581588 aF0.035338491274413963 aF0.0058271317069686626 aF0.024938120088625674 aF0.040064849918990585 aF0.15112156086572828 aF0.022088989203976773 aF0.12806366693813345 aF0.026869260022235233 aF0.068109999036359489 aF0.049240376024558601 aF0.15076975100167508 aF-0.07952015812810817 aF-0.077705878533295109 aF0.031873835966120437 aF0.077121596893619609 aF0.01307569117065293 aF-0.017145828619142961 aF0.12619702803381153 aF-0.052696015667808155 aF0.068624071164436001 aF0.16350287609613956 aF0.03357356241578742 aF-0.073020389591259172 aF0.20615402846532951 aF-0.071250276948019484 aF0.023773684764816422 aF0.069546273414915039 aF0.10408237903911166 aF-0.0053883717544810769 aF0.054698791965274399 aF-0.15015373410417304 aF0.0050532490881743837 aF-0.064439867077920446 aF-0.14333690180899283 aF0.093557754857865008 aF0.12397540095471088 aF0.020023656408213419 aF-0.093050700129020322 aF0.20473809953064015 aF-0.034086873092778865 aF0.077490439682654483 aF-0.011525195546458956 aF0.1114035021156886 aF0.027326398021174318 aF-0.040392342550446034 aF0.0064561740610256475 aF-0.0089132482634759255 aF0.12011954388473595 aF0.060009237660788958 aF0.031188204161903394 aF-0.05110283625319012 aF-0.072232936090469962 aF0.055534406101622143 aF0.12462679490013441 aF-0.068697513168427635 aF-0.10817924270969785 aF0.14599583892746293 aF0.0086361139002748225 aF-0.06798491050082546 aF-0.10603289371503688 aF0.10492069434700382 aF0.12954178229736174 aF0.15062888897443322 aF0.053503768130484068 aF0.0070577871139420089 aF0.18141045129124281 aF0.10710369020056738 aF-0.14840134920816336 aF-0.0012234276184989858 aF0.20921981231497672 aF-0.056724236834710035 aF0.022033851747340617 aF-0.031562049592165881 aF0.11177314854268434 aF-0.055361372480918582 aF0.0052709246188267396 aF-0.062379633056702778 aF-0.015201200563663499 aF0.091947365115619795 aF0.011606182181487682 aF-0.0013231007994532857 aF-0.079555439479323115 aF-0.12529658729593857 aF0.030680709734648849 aF0.040502148867473095 aF0.027273879010424051 aF-0.15916108841124027 aF0.057687843234500352 aF0.01978503757339773 aF0.10507111102868678 aF0.010652219857997457 aF0.01523482924419089 aF-0.051290720230629999 aF-0.087893316070213223 aF-0.025030591448970643 aF0.12343412464934823 aF0.15279918211996585 aF-0.11304978302523035 aF0.032827605250904404 aF-0.0019334715866813482 aF0.0093751815168604518 aF0.068901570323773614 aF-0.085540806021560431 aF-0.085157087639798693 aF0.023986230055884412 aF0.024561990867361789 aF-0.020963215828865334 aF-0.018553022531374221 aF0.076181277180358553 aF-0.054440111868013084 aF-0.015296220441686827 aF0.060857134485161682 aF0.025548362900100666 aF0.13129908668318563 aF-0.0037504068788064482 aF-0.0025134766896098997 aF-0.03239125800742329 aF-0.046956311689330496 aF0.079035562956049285 aF-0.11154311272018648 aF-0.025559660131229671 aF-0.22036586336413011 aF0.066126813923529718 aF0.051111015471417796 aF0.07992061052461355 aF-0.086796627787950817 aF-0.0057499013539242493 aF0.0069307848478209174 aF-0.14979001463013944 aF-0.15099689282693654 aF-0.055977870275147674 aF0.11455894108654448 aF0.18109902091080474 aF0.014138147946993125 aF-0.1445513119248315 aF0.023441160629532477 aF0.033442612957205332 aF-0.0083544644568920995 aF0.014957571688001596 aF-0.15579403723262819 aF-0.12734849773147863 aF0.069442950814919788 aF-0.019884196979826078 aF-0.13830976965717573 aF-0.026951512593014825 aF-0.067501009967269834 aF0.058558799242612272 aF-0.003561177310472076 aF0.027468818776133278 aF0.042932063105236798 aF-0.087193042560570908 aF0.0084283238865058077 aF-0.0098629819518493284 aF0.058426447603696363 aF0.15964565289906194 aF0.027586937001231524 aF-0.008071135692638268 aF0.0026424057269274544 aF-0.052031494457894109 aF-0.1467579509858736 aF0.040585532577076783 aF-0.037962790099218227 aF0.032790088153848748 aF0.0044892888412030813 aF-0.041205205556582747 aF0.020723864026545798 aF0.06089071498620479 aF0.013010867267699896 aF0.011340709518262054 aF-0.085294573423006032 aF0.11074878848297351 aF0.10165027322656721 aF-0.21847949931713775 aF-0.17685212469530345 aF0.032732214086609548 aF-0.072989207595781661 aF-0.10433497308751709 aF0.22392329538825023 aF-0.07666585730473402 aF-0.1037018070012635 aF0.025702533631265817 aF-0.061890003476203694 aF-0.096939905067002827 aF-0.11979568314013399 aF-0.050168116461114076 aF0.043985854792137097 aF-0.12654488764821717 aF-0.0073481759028209345 aF-0.0010698147751529716 aF-0.029318209092495943 aF0.083609107235781979 aF0.054528516234050729 aF0.24752226384892523 aF-0.10584194668854276 aF0.013318545224811365 aF0.066860556332338769 aF-0.048919044573621499 aF0.044727309528119236 aF0.14170870524600412 aF0.067822353998618301 aF0.074918197506626399 aF-0.01900406112389046 aF0.02517579830066639 aF-0.044165556833188478 aF-0.013169740429092119 aF-0.008349657545852247 aF0.084529644284431035 aF0.036829790728294544 aF-0.0021803457011865149 aF-0.032206832948435682 aF-0.020547752050636751 aF-0.098766167303695307 aF0.064137047337687311 aF0.098685481144529963 aF-0.086757753035005991 aF0.14424292491166893 aF-0.041890762728008853 aF0.014640844305994865 aF0.030013611500232285 aF-0.020875178524990653 aF-0.012354381080988136 aF-0.099096228629806812 aF-0.0018658699693476994 aF0.052411106114578693 aF0.15816847796746139 aF0.0069404872125397093 aF0.13630892422983251 aF-0.032268896002916825 aF-0.11016546141649186 aF-0.061369593772120208 aF-0.047893383181420127 aF0.05269816843546915 aF-0.11320725059711546 aF-0.010435809748659271 aF-0.093485087889862775 aF-0.23338540370957814 aF0.021363348505271076 aF-0.072744807404919801 aF0.096244213579992438 aF-0.025253487129159018 aF0.097852060372186758 aF0.088675326558720596 aF0.1802941041014951 aF-0.055589610542498953 aF-0.096837996665419548 aF0.080449566688499494 aF-0.034298449700141218 aF-0.032579397436736227 aF0.040860627772090118 aF0.037618535462645257 aF0.032305679219851745 aF0.093445545185463857 aF0.072600589611254332 aF-0.099901627027582415 aF0.034074770002985429 aF-0.049524697653087514 aF-0.083030571194750685 aF0.0097574984683246289 aF0.0058042471478626755 aF-0.044919403247434965 aF0.045869785890580571 aF0.057789075488800107 aF0.045653854164185582 aF-0.043235459536005591 aF-0.11207469264354167 aF-0.051765266931553006 aF-0.047920979079519761 aF0.0073050121396616447 aF0.058618239283889761 aF0.18087703540260719 aF-0.00024277330449130619 aF-0.0075888325188455136 aF-0.021614692373470995 aF-0.074106542937693171 aF0.035851398417501824 aF-0.011308193087751193 aF0.045739809095341144 aF0.074187823198431285 aF-0.10602765519924898 aF0.073606266935643871 aF-0.068223030611107988 aF-0.063805443512156571 aF-0.063222156271455721 aF-0.026249196698221126 aF-0.12900997595108368 aF0.070064636476703093 aF-0.051962637578769823 aF0.081355708214592204 aF0.16724920400391877 aF0.025003435815136695 aF-0.033284875521517092 aF0.048821019534575634 aF-0.09675756436619258 aF0.0051767789035272295 aF0.0010441644342627772 aF-0.014251271665160117 aF-0.058266231031919684 aF-0.08397692859375247 aF-0.0042182773610753019 aF0.060974764946906644 aF-0.023995149336591234 aF-0.12079369782583743 aF0.039125269686408046 aF0.092524567598659055 aF-0.088524382440316809 aF-0.24098144167566674 aF0.084500304590187814 aF0.0064877652913161738 aF-0.15824238114092493 aF-0.052015763385524154 aF0.099125536328423622 aF-0.048743579670089666 aF-0.022446537663845936 aF0.00040030022701921709 aF-0.003340782146976101 aF-0.042841880749831182 aF-0.098148873011380644 aF0.060222582577696804 aF0.061726792948278368 aF0.073485332860663541 aF0.2061229651066685 aF0.0093419098741053409 aF0.0022420735089034379 aF0.082253885074872718 aF-0.00044586489111074598 aF0.11948618144546506 aF0.14901215061100626 aF0.07502199973148721 aF0.096710322732612194 aF0.0341804393843761 aF0.016191707688190254 aF-0.058798395035022238 aF0.00093553367325094751 aF-0.093720026108900165 aF0.16173798904759176 aF-0.014021860102841876 aF-0.062087714371976639 aF-0.083984612791904709 aF0.075809828925531481 aF0.037995961591287028 aF0.075378643803652903 aF0.090986245948041278 aF-0.0088782885791222291 aF0.13116548519145665 aF0.014396750559270389 aF0.068158784086680205 aF-0.14614514359624745 aF0.014761171691388363 aF-0.04103563090057933 aF-0.062019690562370722 aF-0.18072053126198323 aF-0.15346384472942995 aF-0.0044366935815059001 aF-0.0073081830393441497 aF-0.10085348117103896 aF-0.063928187780511167 aF0.080300300538176772 aF-0.015481283065111057 aF-0.0056174830040653049 aF0.076717922511472816 aF0.12361226748358731 aF-0.094770970196496468 aF0.15371214535455696 aF0.012779271665564576 aF-0.023989243181445418 aF0.13988007271292791 aF0.056488567225205948 aF-0.02936091032031115 aF-0.022382700446627182 aF-0.054621114865954265 aF-0.076762216602686395 aF0.060752567690271542 aF-0.00062190250508732268 aF-0.23860918715606941 aF-0.012676912121993336 aF0.048953937377515584 aF0.063841331519094491 aF-0.014155231533196191 aF-0.049320261772552318 aF0.031005105960339958 aF-0.046531637028968287 aF0.049059234557044265 aF-0.16579214906114037 aF0.044250214739530933 aF0.13572748530086495 aF0.062098697183810551 aF0.047110425167358826 aF-0.068946952604527545 aF-0.045688612099235186 aF0.11086805951540255 aF-0.040907951030653526 aF-0.14855408953374455 aF-0.078544872902469462 aF0.078194755348481096 aF0.0034756649143118335 aF0.035064686292288927 aF0.050628091170084294 aF0.1631194483389837 aF0.060535514409109432 aF-0.19601570981990263 aF0.11704258583096482 aF0.11788922308353303 aF-0.038477214405094683 aF-0.053261089617826662 aF0.086738278574960526 aF-0.041461676690827592 aF-0.034111668919723941 aF0.11865042585090992 aF0.023783031761255121 aF0.15944064278459366 aF-0.06778792339688168 aF-0.047530165596747574 aF0.14486047209232189 aF-0.054660237353212099 aF-0.12058427072223894 aF-0.064080402183069457 aF0.013352882943200379 aF0.032072225656970446 aF0.01514533050804205 a(I50 I20 tp6 S'd' p7 tp8 Rp9 sS'A0' p10 g4 ((lp11 F-0.33236911219158921 aF-0.79703227835827628 aF-0.20372554728732137 aF0.13939855560831993 aF-0.51156643333612128 aF0.64767061820678473 aF0.65758757746604812 aF-0.15527744911247962 aF0.30308544785884917 aF0.27002323797135236 aF0.038517847134462421 aF0.55272726536563654 aF-0.82934482432193379 aF1.7435364698118763 aF-0.0077497294047206089 aF-0.08283571514259129 aF0.038254910583614812 aF0.025482190508746776 aF0.076922791161107368 aF-0.3438441796976946 aF-0.26185210648914187 aF-0.55417742336063314 aF0.12367191470607991 aF0.9014197180792719 aF-0.14178699136287565 aF0.5544777553122171 aF0.57652246717331357 aF-0.32403228003045664 aF-0.55620594794914757 aF0.33417609901187567 aF-0.14508493328295438 aF0.1716793424135884 aF0.14889172624180408 aF0.22505790202557141 aF0.66759323308899599 aF0.74250775431593419 aF-0.097937946253113806 aF-0.53758308552072842 aF0.32973208718932079 aF0.0010831611631716112 aF-1.1644800496295651 aF-0.11533738887763249 aF-0.83512811756253802 aF0.74788561065515469 aF-0.28076547598512774 aF0.043413561690396944 aF0.18959436584054407 aF-0.21499665426398107 aF-1.0103534185971659 aF-0.089113147278169422 aF-0.09427527453627188 aF0.50742093717453596 aF0.034650396059268333 aF0.65268282155369794 aF0.38008459263530014 aF-0.39060727007059659 aF-0.018032009876167286 aF-0.53006021531497227 aF0.03973776649467009 aF0.054784097596902434 aF-0.1128922443884332 aF0.067204252822741561 aF0.44359821402253452 aF-0.82127367505096505 aF0.040950228242117845 aF0.057873686823909379 aF0.41387279131804572 aF0.14810036925648801 aF0.074232786229760567 aF0.17671964609189639 aF-0.036517192343637171 aF-0.039107211338940455 aF0.16920569487366222 aF-0.031184549829823438 aF-0.41795459720529515 aF0.13721199927014835 aF-0.051173192628256516 aF0.041083079721396069 aF0.4349356885221386 aF0.10532637448906325 aF0.24913674330355334 aF0.03257709314654416 aF0.35373662130497124 aF-0.55776584189625467 aF-0.0972613325715318 aF0.27394034863535321 aF-0.28557064925287023 aF-0.37094006465511498 aF0.21752359933381146 aF0.043417192733970301 aF0.31922217039518669 aF0.042378854073401723 aF-0.30415560800416624 aF-0.44962354425221784 aF0.016934220927334563 aF-0.16445278057120388 aF0.26963349345225474 aF0.0039037226921592484 aF0.18518209527942095 aF0.21397927331888059 aF-0.36058038972230411 aF-1.3006537733927654 aF0.12984648950636676 aF-0.49158787775340385 aF-0.29379094719974275 aF0.047481297613304815 aF0.08465235749369962 aF-0.12256259240842024 aF-0.52040063853966168 aF-0.18949095232434524 aF-0.13953944911831717 aF-0.85614988845089413 aF0.25887420679427242 aF0.10276393358034562 aF-0.32607282558736456 aF0.30789107634008073 aF-0.56822996927208391 aF-0.69868020289789257 aF-0.36588294487821721 aF0.39864464758339924 aF-0.10042868795281731 aF0.12247725593204037 aF-0.44818525539859139 aF-0.50950728487152719 aF0.083526634653080314 aF-0.7102268232672907 aF-0.47377296180734962 aF0.32895397297381707 aF0.22709844620795272 aF-0.57115336944030581 aF0.32542683409763173 aF0.098132152834769226 aF-0.42842319948411195 aF0.99364559164172483 aF0.33401289528467643 aF0.50116534561251502 aF0.58030646018812915 aF0.21604654133247833 aF-0.46193736375129918 aF0.28749659011065881 aF-0.26485105421461541 aF-0.41398278510122394 aF0.8784805001159427 aF0.75033617721995582 aF0.029438819564361098 aF-0.11335754810649193 aF-0.35336185854175028 aF0.3915389324579383 aF-0.52008447403615188 aF-0.59868410455989318 aF-0.065739733792704716 aF-0.21974521501180577 aF0.45261507947490276 aF-0.75701707668470986 aF0.07959334045679882 aF-0.33435977837840752 aF-0.33261985831639218 aF1.4696731206490903 aF-0.2530789212785059 aF-0.54139304668069088 aF0.18903407388928226 aF-0.90212406124586186 aF0.21608670457548546 aF-0.76701420283161847 aF-0.060114940895396859 aF0.603112193368465 aF-0.013306650995067833 aF-1.3459322723376863 aF-0.16977954985635116 aF0.86408421606832941 aF0.78080376397629536 aF-0.22325393493764617 aF0.27826154387223684 aF-0.50640646636939302 aF-0.0015880688968439565 aF-1.1494870828850889 aF0.058584598233548953 aF-0.25414046801918611 aF0.35953712890414996 aF-0.70759790678082091 aF-0.03400113407400171 aF0.48137185093683826 aF0.063442188601197644 aF1.2582555051256989 aF-0.54798395627051477 aF-0.87608778139220767 aF0.73783062037277158 aF0.46578323019754903 aF-0.89994319638532572 aF0.081834123567553888 aF0.91980845386355614 aF0.38734690431425911 aF1.1566215904462682 aF0.50117636787657316 aF1.1912295516829514 aF-0.046726333991985419 aF-0.66765920059408868 aF0.16008344053842999 aF0.7568539239800085 aF-1.0018743257567908 aF0.2099962485773878 aF-0.51469114815714634 aF0.093090543532692374 aF-0.60269265541804473 aF0.10246950753249626 aF-1.0644419942065799 aF-0.38733829737687753 aF0.53033794389028677 aF-0.4024739117730568 aF0.52868078477237801 aF-0.41215984968676683 aF-1.3284052908096988 aF-0.51949841142170483 aF0.42088678124005624 aF-0.54668645947595595 aF0.35721059453774384 aF0.88282118691419498 aF-1.2966457276723009 aF-0.52612197297586993 aF-0.18229981152823777 aF-0.47623279958278686 aF-0.27586996854346407 aF1.1274941252453545 aF0.09211966564578962 aF-0.00090258407439790418 aF-0.62018800054550804 aF0.19671529195554746 aF-0.41950256499885785 aF0.6176333278441567 aF-0.31637044065822134 aF0.63788552247247565 aF0.64983096857787526 aF-0.014477027731550216 aF0.82405985454360919 aF0.77995729889745347 aF0.66723442596292026 aF0.44675925299386393 aF0.38388942955731969 aF-0.5463495607861778 aF-0.080718603962890337 aF0.42716286921418445 aF0.10772688298432206 aF0.35659366458239511 aF0.71210587744927245 aF1.2039087132404789 aF0.25195282612031489 aF-0.19689831913854355 aF-0.27886058708414607 aF0.45070638897847515 aF-1.4589162365756372 aF0.74143709542244096 aF0.12262151901826422 aF-0.049584651529000871 aF0.62368797580448043 aF-0.38887684116765348 aF-0.3103632649830228 aF-0.79389272724360327 aF-1.083922811820194 aF-0.89644009480218623 aF0.010675695976383324 aF-0.35235871589270873 aF-1.1317446004117653 aF0.58824840323505723 aF-0.63223869302764368 aF-0.50564294228589235 aF0.098825499086337809 aF0.40018549544001769 aF0.27501961539957837 aF-0.60279111152047871 aF-0.84947094700656389 aF-0.89623336246436802 aF0.22282761719322269 aF-0.50141919512356359 aF-0.21727423639331969 aF-0.88222568550417457 aF-0.58384227311424985 aF-0.35473320904263145 aF0.0068181322635614333 aF0.3008811969557813 aF-0.3295478739129486 aF0.82433579333628415 aF-0.48040855938749344 aF-0.67262194791019914 aF-0.53632879812737533 aF0.051622265913358154 aF0.35561880020807046 aF0.4599468764410008 aF0.54871601951288884 aF-0.61056807509935584 aF0.06697994849776201 aF0.22087457235136618 aF0.26388567718428096 aF1.1843446118511902 aF-0.48161645234123934 aF-0.72867519671826997 aF0.81302511631138441 aF0.088134050129641511 aF-0.5636515009024472 aF0.34686619296313215 aF0.40947395161422223 aF-0.3558287680895772 aF-0.16702390415818791 aF0.11234231894431576 aF-0.26548844159025631 aF0.54905850778637622 aF0.36153697523141798 aF0.57641196100935399 aF-0.38272963285610873 aF0.28880207304816147 aF-0.037399069930135108 aF0.071470306572823161 aF1.465500078772592 aF-0.53672096285299031 aF1.5107984906253049 aF0.90727119476890739 aF-0.6905553651072841 aF-1.3648646383703178 aF0.21464625994636058 aF0.26073179718601652 aF0.20847671626183706 aF0.50726185388241696 aF-0.49134753246606799 aF-0.65945872077830781 aF-0.0048850353557923195 aF0.36270844858561541 aF0.63084630348459103 aF0.37001958974693977 aF0.26999301400534853 aF-0.77639042463703933 aF0.78182782607893975 aF-0.20123224512179194 aF0.24990160288827518 aF0.33183700536438587 aF0.033303136344004572 aF-0.085792399439643952 aF-0.064942911986190011 aF-1.0458834518960205 aF-0.1415245789467475 aF0.620156014370708 aF-0.39134911488662899 aF-0.77435343586755245 aF-0.5036471512355597 aF-0.67085461489604736 aF0.33172606361283269 aF-0.28629772705247675 aF-0.71350964912660153 aF-0.048028266764070154 aF0.31468361533204775 aF-0.62784781700531744 aF0.70337283664003647 aF0.39281124652648536 aF0.85899657499118076 aF-0.056042760232306033 aF-0.48736177317759166 aF0.26589901716098041 aF-0.52503247906918615 aF-0.78232709263502653 aF0.30703003160446757 aF-0.92859484822656246 aF0.44386580935286807 aF-0.464699288299458 aF-0.99427346407075512 aF0.99084447027223244 aF-1.3185395906417607 aF-0.54668080329375079 aF-0.063871980647011328 aF1.3492475675898334 aF-0.29654147616475707 aF-0.46895457764635928 aF-0.5618291334286768 aF0.49708541834596709 aF0.90902975046680434 aF1.0135070622106896 aF-0.42238884810540483 aF-0.24398978640135668 aF-0.58694051258307289 aF-0.099386636059589833 aF-0.4058614147846607 aF-0.1098244905104958 aF-0.56380016969485436 aF0.55538015610477187 aF0.71991604038545565 aF0.041312123560049145 aF-0.19087917046566558 aF0.15809868753944228 aF-0.46304038179823648 aF1.0046439578442692 aF0.62900263452272953 aF-0.97062108609687392 aF-0.20514239491422365 aF1.3301380754312131 aF0.44874835028212134 aF0.51490820725005515 aF-0.76863554213560681 aF0.40192522564003408 aF0.65921746666073078 aF-0.083214685157649862 aF-0.69038434825838446 aF0.57748145707426246 aF-0.63015543316830069 aF-0.26130864398261994 aF0.13318180108952546 aF0.67420308657842021 aF-0.42290229393798368 aF-0.19115430675965789 aF1.5617240034958892 aF0.53886128355696161 aF0.43526210610579191 aF0.61475581335039542 aF-0.6227917587503482 aF0.52176372701567364 aF0.91493795716749182 aF0.29984478194923925 aF-0.21590171724947502 aF1.159303041585988 aF0.23254638970550606 aF-1.8019793177778705 aF0.41486856596376037 aF0.84517765164167591 aF0.63477683350091996 aF1.5081884998767379 aF0.74130023682203361 aF-1.0616786862675232 aF-0.98582549991022195 aF1.3595009978625159 aF0.277646308588546 aF-0.25875640485683105 aF0.093429869076259692 aF-0.98572952768109146 aF-0.026140292298743564 aF-1.207110673762644 aF-0.23347907530843007 aF-0.30078849427711973 aF0.43932411795991527 aF-0.22379972307898041 aF-1.4105159138356456 aF0.2416586248988338 aF0.11267852308998139 aF0.96502917834863511 aF-0.67488263312405117 aF-0.55431257497597275 aF-0.42795131427997835 aF-0.17177115223556511 aF-0.26538340091211032 aF-0.42324465765920338 aF-1.5280058697398644 aF-0.38076375407118646 aF0.48787398495758733 aF-0.46571938357781445 aF0.38860004955997501 aF-0.10266314714548819 aF0.43865109396575597 aF-0.20102214660419518 aF0.018339150310398161 aF0.29666659141616825 aF0.11487735278896487 aF0.23771462984846237 aF-0.45047587998114125 aF0.1839924676431125 aF0.25897436977195704 aF-0.11046444973288277 aF0.72812255317798347 aF0.084613134721782279 aF-0.033087320488508168 aF0.15632344382835081 aF-0.77858300766824573 aF-0.18652922874830691 aF0.77144168398563273 aF0.40930734088154364 aF-0.13266727525274122 aF0.016808652256509439 aF0.27238812059872708 aF-0.19293425454716925 aF-0.043335869700804636 aF0.20654690754199453 aF0.70116298840277524 aF-0.57732320720285046 aF0.20729314060106288 aF-0.56810386765861021 aF0.47858889944502292 aF-0.73291004383064207 aF-0.14456064732576696 aF0.14839592965777187 aF-0.61545773832772888 aF-0.1053514890287463 aF-0.48146092022151804 aF-0.58870419938960716 aF-0.34858553556488753 aF0.41534337752233774 aF-0.19658413091515811 aF0.25208032379831602 aF-0.067154357915307536 aF-0.99607425646604986 aF-0.46219734336884138 aF-0.48919026554337069 aF-0.12225344102247154 aF0.18856934256870422 aF-0.06749209194312232 aF-0.25625565526454025 aF0.50277622247763976 aF-0.64433525275847026 aF-0.20177441574164595 aF-0.76060550922668635 aF-0.52134284866502489 aF-0.15421989311502865 aF-0.15906084650024677 aF0.21584817610729373 aF0.85673621058676608 aF0.43691378574919681 aF0.3328456471106282 aF0.18600394904312822 aF-0.39415135673213064 aF-0.12255916544625428 aF-0.66939576526948441 aF-0.32886498596357805 aF-0.010188972176272982 aF0.93284659621930288 aF-0.067498126210697687 aF-0.13644973678811628 aF0.18111934163024626 aF-0.032180576383043891 aF0.28458249277238357 aF1.1405285085570729 aF0.15220507416858223 aF0.48808540446994847 aF0.14414485950691175 aF-0.024731592735728065 aF0.25976109255702329 aF0.59996225692226823 aF-0.3245954727017813 aF-0.17906532838763536 aF0.25772733880535476 aF0.55608281760816691 aF0.54056889515282225 aF0.070458108817025383 aF0.2917848930926798 aF-0.0074846001493192784 aF-0.089234166035346368 aF0.0097579208229841598 aF0.73550810636016462 aF0.049002472199705716 aF-0.43357105682508773 aF-0.094255900555691968 aF0.3193510841957764 aF0.38067583462067139 aF0.70533924388869695 aF-0.052393432962281494 aF0.36505681457317607 aF-0.44206553716320218 aF-0.59905919474311853 aF0.11337864420001242 aF-0.98329889964088046 aF-0.68441867809080914 aF-0.25676799768707725 aF-0.99396635548732815 aF0.37922476678294736 aF-0.20476193482851432 aF-0.48274104112571553 aF-0.57096945980747649 aF-0.40315993063483713 aF0.078835537029294037 aF-1.5473551711451718 aF-0.050808102248647791 aF-0.72215441715526596 aF-0.12436862193703513 aF0.42333237558442816 aF-0.1034866561550655 aF-0.17567804168499049 aF-1.1627129840612267 aF-0.02252359939772124 aF-0.56652898623071379 aF0.18036939349713302 aF-0.42969835748825713 aF-0.60774017859406548 aF0.14226621977845164 aF-0.44057323314868846 aF-0.46526751277379813 aF0.5565775462138054 aF0.78695501145391045 aF-0.89815700574207158 aF0.1598199079448874 aF-0.48799974257136808 aF-0.17192804389833377 aF0.54058935760962445 aF-0.031356942657323139 aF-0.0045221640554677679 aF0.065190056374489685 aF0.68742738034345385 aF-0.38632043117353165 aF0.36755650934489842 aF-0.6183073335775644 aF-0.071752367593108837 aF1.6401259808034112 aF0.36996802826669301 aF-0.68877338278383615 aF0.53698266582077803 aF-0.61233405111800665 aF0.15290292475309594 aF-0.82767731844141068 aF0.095714970450050063 aF0.36169348207787555 aF0.78084570939325948 aF0.74564181446614319 aF-0.074283929240185606 aF0.33649647764102703 aF0.746573869848841 aF-0.13064634514836129 aF0.16415065700384612 aF0.42641408416003607 aF-0.47292383514956154 aF-0.035854291556667188 aF0.90224185648281308 aF-0.027148583131637868 aF0.34148346346791242 aF0.89381995310918394 aF0.038256097479064562 aF-1.0073527989287874 aF0.29883633405273285 aF0.39253158011855893 aF-0.0014667357240155897 aF1.1274248401774249 aF0.11581116067164082 aF-0.67941847856207305 aF-0.11721189657491841 aF0.64493225884308536 aF0.27906613502435773 aF0.30738418403850026 aF-0.16078634446093829 aF-0.64294845563625869 aF0.44925476968453198 aF-0.4670833454082931 aF0.058800389459325607 aF-0.22606510392236415 aF-0.2782771739956299 aF-0.31961432185003286 aF-1.0381536340650956 aF-0.10502456747033624 aF0.11749503806061042 aF0.38930377219317391 aF-1.0352099662793435 aF-0.23688462459142418 aF0.16457413136032079 aF-0.27854367825890647 aF-0.22447778322567979 aF-0.15804961089987821 aF-1.0143074342478575 aF-0.065678701536332082 aF-0.051087132702834666 aF0.30049776847157822 aF0.48506187578506621 aF0.15091605070238101 aF0.68149489101167937 aF-0.25901012082188252 aF-0.0070398093909925762 aF-0.064934546726028594 aF-0.52700209267283604 aF-0.3784822616367704 aF0.42788723569632431 aF-0.35733296262179354 aF0.039899402793572021 aF0.05129362381116849 aF-0.4385819706433669 aF0.93559516434539602 aF-1.5179186572322856 aF-0.65311158177948536 aF-0.17866150724755786 aF1.3305146431707415 aF0.25712431431861549 aF-0.14138625635245899 aF-0.2178529992614428 aF-0.070039099926381576 aF0.57115584524923335 aF0.52939730268009544 aF0.1150695832427017 aF-0.24950758694770306 aF-0.28547162946513277 aF-0.24534465542791323 aF-0.090306252533540021 aF0.017142998228557037 aF-0.37231025471602858 aF0.077662589149465291 aF-0.20718560105016312 aF0.2335341808233509 aF-0.60004323642253932 aF-0.33719617168316784 aF-0.50619099572809101 aF0.58342081060918205 aF0.01190473844588898 aF-0.78381118229243885 aF0.39365018930731527 aF1.1620793651540575 aF0.46570783141279282 aF0.21935633056684967 aF-0.70728180579503419 aF-0.047847719359155681 aF0.88548497965396622 aF0.32932792503793468 aF-0.3697766794342644 aF0.57381178077563266 aF0.017068869178503601 aF-0.33371431579756405 aF-0.7155864913463571 aF0.093004124564737972 aF-1.1084997530191099 aF-0.94077794963106598 aF1.2543471983333037 aF0.11640086356854168 aF1.5421716913486754 aF0.033101326112751885 aF-0.3085679768144805 aF0.58535495527584713 aF-0.36327262486744483 aF-0.1616553011742817 aF0.32702795835250087 aF-0.028889549238767239 aF0.4556070165679193 aF-0.75234378262379786 aF-0.14080076077686754 aF0.16541919355411958 aF0.11556403136932027 aF0.78836661240301087 aF0.57879313390853016 aF-0.55248899708714982 aF-0.24803613837491487 aF0.60657229593967543 aF-0.74598227273584305 aF-0.168153443505138 aF0.012577547863989756 aF-0.59029275911223655 aF-1.0041151200996099 aF-0.78650690250448407 aF0.10057056243882588 aF-0.69538788822697717 aF1.1121133329654893 aF-0.10979617926171287 aF-1.3169252388058466 aF0.54683957924370175 aF0.82431427430085658 aF-0.19859124534687933 aF0.051855149964200827 aF-0.26322444462427641 aF0.041561648653942622 aF0.66491431066059192 aF0.59428152170360726 aF0.20388483259342471 aF0.093905395425005075 aF-0.42924399612922809 aF0.29741657406860256 aF-0.63758333481670837 aF-0.60542276309998877 aF-0.15253100992351057 aF0.22994173534287105 aF-0.24766035699607539 aF0.32488495281360091 aF-0.035318642958775494 aF1.14027231904655 aF0.25150682381438594 aF-0.45740263428169126 aF0.42338624139241637 aF0.18770521128901252 aF-0.15311476595971732 aF0.26727232583816757 aF-0.21018645169645367 aF-0.037219653043604299 aF0.32604697108638137 aF0.37915857222745758 aF0.17830637789262038 aF-0.87233606010802967 aF0.2855585223916467 aF0.30986395179708154 aF0.19950022302573714 aF0.20977316605503707 aF0.39347993492613126 aF0.55936525210970101 aF0.45324956995834798 aF0.49571149529857761 aF-0.45902296531177844 aF-0.40973714522267579 aF0.08335767728394361 aF-0.30838970278930061 aF-0.44496253243138445 aF0.17472548344635536 aF0.16382406151862589 aF0.26432546960952613 aF-0.3168489613385867 aF0.071383954536087479 aF-0.74284020330484024 aF-0.60517933652970368 aF0.36578751334893589 aF-0.21574581463511106 aF-0.53022406859106375 aF-0.083944553217584164 aF-0.61717212738912786 aF-0.14723961308071165 aF0.034323575064721237 aF-0.7006284128521556 aF0.15105507254890177 aF-0.68667917485012853 aF-0.069348116159817855 aF0.24659651600105117 aF0.23898332019634855 aF-0.21373051428761064 aF0.17541689767236798 aF0.040655498279898172 aF0.49418471381325091 aF-1.274199988348832 aF0.060454019929226083 aF-0.63897967651788101 aF-0.29515801667715225 aF0.21001702082302978 aF-0.22246592416901659 aF0.24433465760387502 aF-0.09696132269136154 aF0.50706339180358784 aF-0.23789064401154067 aF-0.18814654718140569 aF0.19387817663814752 aF0.3565442982615224 aF0.081996598614815563 aF-0.15887170046691879 aF-0.85764352618065232 aF-0.47595809150944224 aF0.16854807139492187 aF-0.22958405150103986 aF-0.2422774519040676 aF0.35203993159102642 aF0.24360194147341563 aF0.17737058646736692 aF0.32142846847899031 aF0.7040801620548417 aF0.8376586515070964 aF-0.31555519457073677 aF0.13705342006036869 aF-0.15481872511565686 aF0.2786277693711432 aF1.4084429335707278 aF0.17467716549095261 aF-0.37288575466330126 aF0.2516709461683645 aF0.30049924978968595 aF0.22868024093693626 aF-0.55735162471439326 aF0.21905214815689839 aF-0.36240103818329006 aF0.32283722512690549 aF-0.19380424590864026 aF0.24840845781774204 aF0.35826344962676221 aF0.38744709040406994 aF-0.033471695201945817 aF-0.54719435744363321 aF-0.034281572602260293 aF-0.47654407985891761 aF-0.62124839015946232 aF-0.29335504303006066 aF0.48842295797219215 aF0.29267155811343376 aF0.20300246152105339 aF0.080829811890162417 aF0.14354092747452143 aF0.18439998497042789 aF-0.087964761316127127 aF0.81047013974474347 aF-1.2835820691826927 aF0.02133021752634974 aF0.10004122934667385 aF0.34938747248512392 aF-0.14482254952823478 aF0.21871785639978314 aF0.31597599312056923 aF0.5012831334154989 aF0.83208899855256935 aF0.51333626398630383 aF-0.27189144711109836 aF0.76702567947531464 aF0.070740941023683057 aF-0.72921137895230315 aF0.11463588078127726 aF-0.063760903448682002 aF-0.75603754713528537 aF-0.42481926072894921 aF-0.029615390859620012 aF0.2990897819359748 aF0.31628437807413462 aF0.039469137483556162 aF-0.2641054368983401 aF0.097258056387688058 aF-0.046811827424160742 aF0.057348188242144139 aF0.51195823457791434 aF0.29522117642710483 aF-0.49890384117478831 aF0.034516861222317528 aF-0.24805164530345514 aF0.0466490248130162 aF-0.010963727177418016 aF0.16828056011281478 aF0.060284480864023202 aF-0.57080955413416934 aF0.16547387948909573 aF0.48666780756607952 aF-0.036416597785222514 aF-0.31095180476139489 aF0.86604903725371218 aF-0.81808556833660218 aF0.23988766066334352 aF-0.10511792537630726 aF-1.3694718758963416 aF-0.54122426965118309 aF0.30043433286894794 aF-0.19375261004082192 aF-0.36195872573487825 aF-0.20636860246675404 aF0.75122843007065376 aF-0.46625170056814341 aF-0.031967569647998073 aF0.54949699481459657 aF0.68264460796376947 aF-0.18511277414083174 aF-1.0908199733571788 aF-1.2809727464384733 aF-0.028681000152945252 aF-0.34390528231595574 aF0.5069649322795684 aF-0.90112286791464602 aF0.34543790384362055 aF0.1383988002398677 aF-0.056974462161271305 aF-0.2073877803799046 aF0.095020302163884185 aF0.51518964250695254 aF-0.72515335957861016 aF-0.44609680401934027 aF-0.83029901913376769 aF0.55364396558153905 aF1.1285491473169702 aF0.154960495547007 aF-0.28945785005176183 aF0.12359596060556791 aF-0.014314729538650423 aF-0.62367171759306461 aF0.16878857609727538 aF-0.0081326714940393539 aF-0.46994429160415829 aF-0.83492398505076315 aF0.33627278369331876 aF0.4504192589729914 aF-0.67927004718033746 aF-0.32596541494218145 aF0.3167661335133255 aF0.84908670050638402 aF1.4154114077048638 aF0.4327909436677056 aF0.87125687606519686 aF0.4085374238778261 aF-0.53634842164709451 aF-0.93524765699934975 aF-0.37129124250952855 aF-0.35708686707859127 aF0.2151526338855079 aF-0.54446917252514559 aF-0.46981568502545706 aF0.49668410339162888 aF-0.9115172564963594 aF-0.45720497803599569 aF0.15331644862724242 aF1.3613943109695048 aF-0.42262090884793196 aF0.029031997139354261 aF-0.54661373220639109 aF-0.26087722621355502 aF-0.084738873821703767 aF0.70638807530975711 aF0.50664236123045814 aF-1.1223602095977336 aF-0.25601684786380674 aF0.17673289576195003 aF-0.83194925576556145 aF0.16865008004502596 aF-0.037118928104466847 aF0.55046585479450594 aF-0.029685216765527031 aF0.0060398490390555183 aF-0.87514056493361325 aF-0.46881250292758292 aF-0.11862144632996857 aF0.12666688435887946 aF-0.13819894994841736 aF-0.55926919891967797 aF-0.57231305592277093 aF1.08074732868838 aF0.98114584777808045 aF-0.073755456591349577 aF-0.89177199804686402 aF0.28342023583197268 aF0.20746860305283493 aF0.31764586853424565 aF-1.1708725107784643 aF1.459638128348888 aF0.067484776411970607 a(I50 I20 tp12 g7 tp13 Rp14 sS'A2' p15 g4 ((lp16 F-0.055177143862990309 aF-0.090934983718903642 aF0.1088346509003635 aF0.21859497110484641 aF0.2073827397972903 aF0.21063695520785472 aF-0.024722400297423574 aF0.046028958244294108 aF-0.010910564736127788 aF-0.00017292450566805674 aF-0.039604072069558974 aF-0.017833746610335537 aF0.090197620671043102 aF0.042894655823724606 aF-0.12494111241956032 aF0.025053094003101243 aF0.24227360935358752 aF-0.004920542969672136 aF0.043253018251401869 aF-0.19040336002985572 aF-0.073459159371673979 aF-0.041814199423833992 aF0.017745390654343485 aF0.081425892862078811 aF-0.14569914710592888 aF-0.029473234727100107 aF-0.064424627663900905 aF-0.068130928005078237 aF0.033987103823118862 aF0.1315661712516851 aF0.042099807780963824 aF0.060483032589267502 aF0.10292303300433443 aF0.089653961556869929 aF-0.12050421932662413 aF-0.0021247386459149224 aF0.012316214541374115 aF0.22043635368439249 aF0.082540753051030841 aF0.0069738800353631985 aF0.033113408603218777 aF-0.18844764138149481 aF-0.21347093755475399 aF-0.033952095579280667 aF0.11768966887688906 aF0.050991169240989502 aF-0.016497898435255641 aF-0.00326569938335072 aF0.17707318291438839 aF0.11951038726361075 aF-0.032568247070107768 aF-0.02999559172835399 aF0.0076055465350238147 aF0.039671416813289777 aF-0.11195301194112302 aF-0.25044385117247736 aF-0.048975710309696711 aF0.20220914060071504 aF-0.055448024371275113 aF0.13137208542838394 aF0.10936972845920152 aF0.068026414468520133 aF-0.011112761158783305 aF-0.0028523400837438067 aF-0.091815782400712032 aF-0.095021943298575884 aF0.057539681708335712 aF0.079437925802282372 aF0.18964517211746931 aF-0.054411404639847033 aF0.053667646650171208 aF0.13965085878563877 aF0.1961813466627286 aF-0.068291621253356527 aF-0.14019032668391324 aF-0.019518166912356871 aF0.045084993136515081 aF-0.029592437461493627 aF0.07526574838688288 aF-0.12946242509858352 aF0.10469317206722956 aF0.0896182838137667 aF0.045089130958460788 aF0.11514204590153726 aF0.054382952021918278 aF0.041604243513167716 aF-0.12978789887691822 aF-0.084206705765249398 aF-0.13256099013871966 aF-0.13559176063294912 aF0.0089064097135981048 aF-0.020711413425595425 aF-0.029037857714492171 aF0.058038078263427842 aF0.0035656343037088114 aF-0.0015038298180660946 aF0.041148293756015988 aF-0.047811974225024458 aF-0.096582124164248301 aF-0.0043782848064951385 aF-0.045680484707591118 aF0.14897702535524496 aF-0.021877487035356896 aF-0.088030182538105961 aF-0.013979620351963597 aF0.1540624866980071 aF0.14235608542881514 aF-0.096136149045765784 aF0.0088556295711976311 aF0.023033583727620627 aF0.20570683532114142 aF0.028419071885841952 aF0.1823066357459609 aF-0.010917106396017345 aF-0.024965168361472521 aF0.13222334530162014 aF-0.0068116866107957421 aF-0.033183966120908015 aF-0.071128382014544314 aF-0.022894947917562657 aF-0.038325610799607231 aF0.12951611120504944 aF-0.077568952880594205 aF0.01520733912303863 aF-0.0044112589446748439 aF-0.27253086286362266 aF0.09217925774366699 aF0.080953922574883125 aF-0.037152078716310495 aF-0.23975519773914405 aF-0.08866329465909116 aF0.05083351747855034 aF0.069519362858686415 aF-0.052364446789599214 aF0.10600616977521761 aF-0.02819391818331984 aF0.00029025834479629861 aF-0.1287088493144905 aF0.14866728928187239 aF0.012780651577132906 aF-0.16629295780313147 aF-0.25531491161016767 aF0.024021060302080694 aF0.010913420283174668 aF0.030418910122732224 aF-0.040876244170439884 aF0.00047977934854221208 aF-0.018863263612910148 aF0.0045352427438410522 aF0.08476077123035769 aF0.032108636515289536 aF-0.072842676709623549 aF-0.056959111288764311 aF0.13088936711105964 aF-0.19084927933178644 aF0.003084430138521286 aF-0.0014345953286697354 aF-0.050739652007454658 aF-0.10651407286607693 aF0.0091567860711938391 aF0.04377918968239515 aF0.16245070738046274 aF-0.04307340844096301 aF-0.08469840047142177 aF0.0001415740693069276 aF0.058337469598007154 aF-0.1436192928164296 aF0.064093591930071386 aF0.08913611375164017 aF-0.0064513381888034417 aF-0.0030830642731675588 aF0.027687507517900056 aF-0.060106504775543114 aF-0.0047790728773195899 aF0.070775058155850959 aF-0.029278813853367114 aF-0.10257715405244926 aF0.13370339305999124 aF0.037444987382623703 aF0.10367524479590345 aF0.052179466433580381 aF-0.084006575526882302 aF0.15570347362292775 aF-0.0022701315539581193 aF-0.070463249384634455 aF-0.076665974880955681 aF-0.0083995697792459863 aF0.057681397272742851 aF0.035200361909121645 aF-0.055830440382640824 aF-0.037867375942746209 aF0.10234827161583543 aF-0.06410735247966208 aF-0.032044796103514045 aF0.16630570838571404 aF-0.1501328029736875 aF0.025361899575715927 aF-0.061744336891093266 aF0.018664353285423155 aF0.11967573437192655 aF0.042299399284519819 aF0.11794446268823212 aF-0.087520298342840766 aF0.10945564437222896 aF-0.03712553951424246 aF-0.055232394004153501 aF0.16784634643019819 aF-0.088359188106674202 aF-0.036337061024538667 aF0.0082230616675087256 aF0.024162555225182618 aF0.026744575183451375 aF0.0715606323037416 aF0.036982611675445205 aF-0.029789238320601499 aF-0.034222708035081678 aF-0.026937392163425229 aF-0.15725362483797686 aF-0.0049370095995950889 aF0.019942633126320681 aF0.19893457326664765 aF0.052398216069204667 aF0.074605295930732507 aF-0.098756527489276283 aF-0.053082944870072146 aF-0.17170035163118111 aF0.083985741035467201 aF-0.050065985076010899 aF-0.055390480252292887 aF0.0023128263850746367 aF0.023936472969809809 aF0.06805784972859423 aF-0.014829699289401935 aF0.039883932802202968 aF0.07883920311198106 aF0.0058653689446590655 aF-0.15811083286471841 aF0.065545433730221841 aF0.003353204435138298 aF-0.016923097062455667 aF-0.074580464755409928 aF0.090620459888375346 aF-0.16309354432095163 aF-0.004030481450426145 aF0.081488174739785355 aF-0.041753971603488503 aF-0.17426237098117373 aF-0.035892902291920922 aF-0.10133350515793345 aF0.16087743443398983 aF-0.065835071049081512 aF-0.020132144005941911 aF0.052635829713815821 aF0.0155749335405393 aF-0.045382783887803931 aF0.11009222832394563 aF-0.010257645185249766 aF0.051519457523845617 aF-0.0028063982339499691 aF-0.12109180008477191 aF-0.099135598486534582 aF0.014418712221900099 aF-0.13423179001981422 aF0.061656008926874339 aF0.033185457581472629 aF0.05552139698037848 aF0.0067915813013809294 aF0.098908927262848972 aF-0.060636863738624404 aF0.043517296821579565 aF0.1138997204417688 aF0.0027134074709325631 aF0.063317195771388043 aF-0.062758947028787121 aF-0.0039482511609774049 aF-0.14166970713897126 aF-0.098112035039407894 aF-0.020238649114106593 aF-0.15339724769355365 aF-0.15544519588330058 aF-0.0099339971906280758 aF-0.027532046203550636 aF-0.12525375333502839 aF0.067531675305338601 aF-0.03701097461612872 aF0.078428466566513783 aF0.3060784739241097 aF0.057344423823142386 aF0.11713318574685919 aF-0.067851776034082475 aF0.094661244111924212 aF-0.056591347130605416 aF0.038790639159273096 aF0.081917344989270766 aF-0.021738164019051018 aF-0.011711076888398755 aF0.093321336138313282 aF0.16004901707093555 aF0.0903906214294313 aF-0.038453329501291579 aF-0.030543615843782283 aF-0.078518294734387553 aF-0.070629802249183277 aF0.13404367156682456 aF0.099945520370653337 aF-0.01984602646748131 aF0.129978162520516 aF0.057381111380959832 aF0.20335451438791494 aF-0.11830406718083865 aF0.10712955457337386 aF-0.10791114684777595 aF-0.051984303323715536 aF0.10776844452836695 aF0.020661246329662375 aF0.069350308964136576 aF-0.077658650741859042 aF0.17021774995146344 aF-0.0032914387918880038 aF0.23722341718300341 aF-0.063277314679489272 aF-0.1443136368317515 aF-0.05585036617481047 aF0.034482158004221414 aF0.11651195354702278 aF-0.054169167126587751 aF0.20592520763403246 aF-0.0014943039150752987 aF0.067349918473157064 aF-0.05866290450849071 aF0.13221306517740955 aF-0.10609422163227407 aF0.062823908593857267 aF0.066860057733128989 aF0.047097140555271526 aF0.15523311731637512 aF-0.061910263063460542 aF0.31239876299135561 aF-0.03613436768359822 aF0.11038376403460366 aF0.028175808072849088 aF-0.044527181578319877 aF-0.030301989507218779 aF0.071096951457306989 aF-0.030453449711826334 aF0.1918964498563116 aF0.035588994224299231 aF-0.059730440013489823 aF-0.0051960152853210845 aF0.038678238649738343 aF-0.0068541595576828854 aF0.072012818193856631 aF-0.012546847555840127 aF0.058261314415236881 aF0.14445363238058834 aF-0.0028280262673769977 aF0.028955891792536485 aF0.18168291147144178 aF-0.059045822038194605 aF0.028676890756101837 aF0.14576325978206323 aF-0.089083774895590814 aF-0.105062560892169 aF-0.13588900044923549 aF-0.088434310940037536 aF-0.003630082808377337 aF-0.19424024928677733 aF-0.16810337150732782 aF-0.14115372685309346 aF-0.021547786054055981 aF0.10979328046207114 aF-0.0030365148048419285 aF-0.049555828036475937 aF-0.0061710361916060734 aF0.20651195434172903 aF0.019439612506736797 aF0.017246604888145563 aF0.026064620428664306 aF-0.14001485134787167 aF-0.21696813709120338 aF-0.18601289527858506 aF0.11169989941485885 aF-0.033391918476632698 aF-0.057922140860280788 aF-0.020372283888836662 aF0.016530051685272391 aF0.082120300370432553 aF-0.1126371589784901 aF0.011476431743121334 aF0.073907027921322352 aF-0.097520247116770639 aF-0.18391154716846431 aF0.022258995677168825 aF0.013681766429927904 aF0.23871319687933606 aF-0.0048718260420158015 aF-0.0013456076727166753 aF-0.047300610699094206 aF0.11051610572849201 aF0.01014140842819997 aF0.15501804088894575 aF0.04186086567213871 aF0.097682442518753243 aF-0.011677973819592305 aF0.017213390587544685 aF-0.041490874960699996 aF-0.056762219388886447 aF-0.17624407412633217 aF-0.13048519736495875 aF0.024531712645389833 aF-0.033193321839847273 aF-0.090080994909792697 aF0.12494999843526937 aF0.079359542740060934 aF-0.03926509411950084 aF0.088955591050133606 aF-0.10466999274549041 aF0.18743920904347805 aF0.00071445274375956617 aF0.068357333641444945 aF0.049393815791289583 aF-0.063326018357685643 aF0.099233644705276874 aF0.057612000173089949 aF-0.069208550361688187 aF0.021861975887379023 aF-0.11014606958110534 aF-0.028214485506583238 aF-0.14077839229594691 aF-0.056777847893192353 aF-0.019666088170494162 aF0.099042745655239794 aF-0.015653647030877463 aF-0.074172796647291817 aF-0.00052293636900737771 aF-0.10645346780937884 aF-0.059230640150881239 aF0.14392480396039037 aF0.011918719638223909 aF-0.073619906766106774 aF-0.009376744675956358 aF-0.061109880292916176 aF-0.064595907275467504 aF-0.020147819057824038 aF-0.041251455158585713 aF0.01289309011288358 aF0.14475463399850988 aF-0.027192563652361133 aF-0.03215319259019267 aF0.079871502012213075 aF0.075173094233468421 aF0.054673989542494007 aF0.003628844549442658 aF-0.10311844402707779 aF0.062468022075953131 aF-0.024888498523310456 aF0.015015986547292569 aF-0.043327708268808315 aF0.041354694774414634 aF-0.024813967244999895 aF-0.052283351581727207 aF-0.129674567742256 aF-0.096751046699620216 aF0.16171686780953431 aF0.19294306057647123 aF-0.093600374388917551 aF-0.010261160848028044 aF0.0057577819534901133 aF-0.040213860167795615 aF0.16797498801837432 aF0.051255753225112055 aF-0.056748876004360169 aF-0.11414104626191252 aF0.008710122124355877 aF0.0060788452056667868 aF-0.12561079461859961 aF0.061792806544561762 aF0.0051863321977621245 aF0.12112336335368296 aF-0.021281716088328368 aF0.047146483982639688 aF-0.059682342863964205 aF0.0012858686314625328 aF0.11103124290739934 aF0.12915125571491284 aF0.0079206558070611423 aF0.23299766048779957 aF-0.0078506266706653526 aF0.11779450364331617 aF0.022670513795018051 aF-0.030393093512299817 aF0.16881372691880644 aF0.026279443194090969 aF-0.024645841248289974 aF-0.016680036435908308 aF0.029951537033328746 aF-0.00058006512683570096 aF0.0058925426624881786 aF-0.01541017869261063 aF-0.088034882565110245 aF-0.0025600514430933162 aF-0.14115099942825041 aF-0.014500104517212235 aF0.0083428674551949758 aF0.030812994374712993 aF0.084126789159434293 aF-0.10723477213499225 aF-0.11103786465423179 aF0.18455193651853941 aF0.24753822354466984 aF0.083804846179395764 aF-0.051998163969302978 aF0.053983445734529484 aF0.017656892049984402 aF-0.18927515957483063 aF0.006311039824280773 aF-0.011189587489128964 aF0.041555733540402144 aF0.0084194771753996599 aF-0.32062907708065164 aF-0.10358318766062508 aF-0.13435805984141694 aF-0.072539670511620719 aF-0.17000685533299728 aF-0.024311161217735418 aF-0.084530917003306547 aF0.053814232222157928 aF-0.063939265848471663 aF0.053628907299544393 aF-0.1271343027239423 aF-0.17497690674163796 aF-0.090999956688566627 aF0.056022733031139846 aF0.10515395716141297 aF-0.05600696117229155 aF0.14263349713728926 aF-0.011168363810599635 aF0.011199974868446969 aF-0.026598679079103186 aF-0.050877799036847221 aF0.023960478467587757 aF0.052494320700415167 aF-0.018973635403467057 aF-0.24629790447570662 aF0.19734100671280788 aF-0.087641658119766694 aF0.175998042185665 aF0.093030428491602118 aF-0.24494865231982749 aF-0.00047850548219137087 aF0.022977706341240512 aF0.072500002257234547 aF0.054213581483611592 aF0.052860599932991414 aF0.026610531484314432 aF0.037439681825428971 aF0.15333867599869866 aF0.047103951026739269 aF-0.016197989928733541 aF0.000887566612119359 aF0.057826391183464249 aF-0.0034323735239749414 aF-0.07256557276528397 aF-0.095328068095131779 aF0.027311900323211038 aF0.089474974533514634 aF0.11957053004191145 aF0.082513534507027017 aF-0.066955737401765664 aF0.075039511692776076 aF-0.091870361047227705 aF-0.011436088854156033 aF-0.12387820281903922 aF0.12179285292682285 aF0.04124951773942271 aF0.084899417416483519 aF-0.011615876511216441 aF0.027813413828436002 aF-0.098774666881408693 aF-0.11946120379929558 aF-0.094481027192023379 aF0.16510134130548301 aF0.03355565375248111 aF-0.029167960923471334 aF-0.046095379991226697 aF-0.097030526480389595 aF0.1190763062342894 aF0.089723829062585428 aF0.041429984511248713 aF0.04081011694448098 aF0.11869561692746541 aF0.10376635033268418 aF0.13380899284205736 aF-0.091576421747627784 aF-0.058445875412080413 aF0.11022760303341736 aF0.10005754671764959 aF0.10009279294828914 aF0.012395680527387086 aF0.02340539261028873 aF-0.029957013710068873 aF-0.0034659213637663663 aF0.1257486954128435 aF0.028179340357867223 aF0.022285311892012261 aF0.037262075708562006 aF-0.1521700003874745 aF0.18697639636442398 aF-0.048991377513423862 aF0.19539263086094619 aF-0.0023600970492098526 aF0.058590947949117504 aF-0.044773196244701163 aF0.1478079445747382 aF0.010261345510060046 aF0.0017325564724354708 aF0.051837239023821688 aF0.10191233482160775 aF-0.094138312631391871 aF-0.12374078165417321 aF0.065648947529419688 aF0.026830402697505511 aF-0.15994232298648936 aF0.087695547497904994 aF-0.054937986394894625 aF0.04446814405009946 aF0.10696613973706449 aF0.085818833961108398 aF-0.060413079703052604 aF-0.0032115816633468729 aF0.08460176771732654 aF0.11305612191264475 aF0.054220186574038876 aF0.14074012367025315 aF0.08543260876045293 aF0.048359943835055028 aF-0.065633638232130226 aF0.027030767118143444 aF0.06924993773478251 aF0.096726699709739461 aF-0.00087547557342555207 aF-0.0091848975891697261 aF0.10242903854621793 aF0.1195092110506676 aF0.0052871406290618426 aF-0.063473657396276847 aF0.0023317739197133988 aF0.01902440536987764 aF0.057856224662994192 aF-0.30073752026478406 aF0.13599636090340364 aF-0.16216298961604714 aF-0.079928384281358178 aF-0.14412634398462026 aF-0.072791083991654917 aF-0.12177892972983285 aF0.036862481859833193 aF0.13174584370746006 aF-0.081610183998520172 aF-0.062117220607096325 aF-0.11271114689035737 aF0.063574701966689309 aF-0.10932323126823337 aF-0.0088927102260218643 aF-0.079747647638977917 aF-0.03550158481073943 aF0.028243513065858417 aF0.062359511007092035 aF-0.1233097397950056 aF-0.099342798002378746 aF-0.071200194091729771 aF-0.069633913320042803 aF0.051661010490128022 aF-0.055238623724216937 aF-0.079874144305878664 aF-0.21917630657339188 aF-0.035799316878732682 aF0.040232694075709688 aF0.080978422593848368 aF0.06510479448900991 aF-0.059900216580945263 aF-0.073524620206891031 aF0.1215218442731168 aF-0.24008788944347689 aF0.11011887265232777 aF0.01223121304774352 aF-0.089306221120852292 aF0.048795512493457108 aF-0.074047411304813779 aF0.10809436292091638 aF0.16134931004364916 aF0.15533788239422233 aF-0.013830870051591202 aF-0.07985662368756194 aF-0.078791705788612401 aF-0.096329533766666156 aF-0.059158529230751621 aF-0.20222684765650431 aF0.037430191805560856 aF0.054763129125730399 aF-0.018620844957434483 aF-0.077987529415600901 aF0.0019992596411459677 aF-0.05529912366532759 aF-0.029129341704762411 aF0.052871303728301872 aF0.056265586293919367 aF-0.11854910623057796 aF0.087162520936002463 aF-0.056621519772420068 aF-0.11081584503649952 aF-0.24049193003515856 aF-0.12583845106754871 aF0.0023451342816078356 aF-0.064812191213504733 aF-0.16890956781738725 aF0.092515147088095967 aF0.14921596030355722 aF-0.014742319818963142 aF0.033682604483814084 aF0.12425160121451437 aF-0.046185238920130371 aF-0.064377741379582215 aF0.056806202580856495 aF-0.0091753928729996978 aF-0.036943039398477616 aF-0.035027065000936324 aF0.01172725962279699 aF0.10008614178984791 aF0.043179312134217308 aF0.11591003597298011 aF0.10772505440764008 aF0.019552296126425783 aF-0.042744687104091489 aF-0.063979800732527556 aF0.042270474206796665 aF0.086276894988110975 aF0.038228292228884977 aF0.051598418572029264 aF-0.069975502367457226 aF-0.078651998882348653 aF-0.20765909943503544 aF0.15157440176342074 aF-0.091012133198523359 aF0.03147085770447243 aF0.11236183211433474 aF0.0063486845668841276 aF-0.14379668636598095 aF-0.16496019959373359 aF0.11772687969936144 aF-0.086118941253464823 aF0.026720733533377734 aF0.085471747551329233 aF0.12050779341873413 aF0.030453195829649268 aF0.046875154950436274 aF0.0046587597737350311 aF0.015443534139250195 aF-0.040719502167033725 aF-0.048652227065329366 aF-0.014226920842525565 aF-0.039533677503780673 aF0.0088099468664679121 aF0.051156333701157408 aF0.0018645389882668906 aF0.081208113666952797 aF-0.023146825116148032 aF0.11617443194952629 aF-0.094090320134152791 aF0.010684461111130585 aF-0.1235586826793115 aF-0.073432318081182668 aF-0.088295145596297323 aF0.042581756099878611 aF-0.029788989389739961 aF-0.071782509330200556 aF0.0085472991432579692 aF-0.0044144868911086431 aF-0.036103901230470706 aF-0.11150689459097783 aF0.063386941535653427 aF0.014017931749509408 aF0.058170381331469151 aF0.12211767786227606 aF-0.11354097088743476 aF0.024472115890565926 aF-0.11180637414500229 aF-0.026289395615343283 aF0.0096431378808807672 aF-0.12827700489590682 aF-0.11993098892062856 aF0.021410766662417414 aF0.0080384617328952551 aF0.083156770586368292 aF-0.17064167670284544 aF0.051547595657153465 aF0.043914312895561324 aF0.13310479969656669 aF-0.0036998534149256168 aF0.016395538372920047 aF0.0011467704759317602 aF-0.085352843039020965 aF0.042479436140357853 aF-0.13491053140260531 aF-0.079253982699096059 aF0.0065538594803589249 aF0.05769840820742974 aF0.064997719607653867 aF0.019503860418133991 aF0.17676206960240576 aF0.1346850229343102 aF-0.072160378166972267 aF0.12257425820771946 aF0.050233339138728378 aF0.1761840863714334 aF0.056146602432152387 aF0.0042914391883953421 aF0.040125503911374642 aF0.19176283646512979 aF0.0032538725206520407 aF-0.21240349624260044 aF-0.16756070125515354 aF-0.091835353963488506 aF-0.12500510063194875 aF-0.069358084610301574 aF-0.034786612564470493 aF-0.063695763168122602 aF-0.15094364807696381 aF-0.033286174687399459 aF0.077396125269460977 aF-0.030244053445085836 aF-0.10154325773246933 aF0.012443758777270759 aF-0.02685728148948913 aF0.015202581616044764 aF0.033811352422597959 aF-0.20742738562223223 aF0.059611919386579844 aF0.029314793620553042 aF-0.053042562221212307 aF0.055360563432240287 aF0.034445690355433031 aF0.052925977560950653 aF-0.12699388857431659 aF-0.057788060160968935 aF-0.058488746877789551 aF-0.088835266516803582 aF-0.010194685978115427 aF0.061379126930147701 aF0.10628921727689004 aF0.0799499126816616 aF0.0071407208307813358 aF-0.10450485262403755 aF-0.018717876024268582 aF0.036290012997277521 aF0.0026508606817946174 aF0.0085048509956422141 aF-0.077603908515031586 aF-0.15701955443394924 aF-0.017496364061716767 aF0.068004411659852618 aF0.0010938806266890552 aF0.046252269845260402 aF-0.005385596777490842 aF0.054849019963044955 aF0.11709782636063537 aF-0.1043525292628899 aF-0.10986654424012431 aF-0.10136901884315185 aF0.095983118768833309 aF0.069890029991237015 aF-0.068522458322577959 aF0.032805239817532326 aF-0.11879007648617979 aF-0.014480764793735799 aF0.19507489345612583 aF-0.018018409975172251 aF0.059850802815706913 aF0.033454527254848355 aF-0.021362709766800637 aF-0.099361977511118443 aF-0.17404795127674799 aF-0.034681964502361363 aF-0.072973346723094204 aF-0.10891475677147996 aF0.063046558718000509 aF-0.070884820987525993 aF0.019597000772303357 aF0.038043501261174256 aF-0.027365588653200604 aF0.035294900908687261 aF0.15027749823781078 aF-0.13373718134667167 aF-0.056185354136965758 aF-0.049512171310170841 aF-0.1369444557703017 aF-0.0023723288375381924 aF0.072089759275013293 aF0.20160165746954786 aF0.12695709886025536 aF0.10434114176479499 aF-0.097721782903832238 aF0.070403216173654137 aF0.10907763224810438 aF-0.015406029028988003 aF0.064594896436268881 aF-0.14029873124724718 aF0.079894346718532017 aF-0.16463733676156195 aF-0.14485942349207542 aF-0.05885129854919343 aF-0.0092074740632008909 aF0.19156233637432854 aF0.076023243615986016 aF-0.014004328469303702 aF0.084182008023716906 aF0.010185320757573741 aF-0.056793101767079836 aF-0.035175096833726383 aF-0.015142087371648813 aF0.051404733282198689 aF0.026177927705903201 aF0.046522232676116902 aF0.060840554247612935 aF-0.19491388432482804 aF0.092163938242887364 aF-0.0074705865930164029 aF0.03393784129401306 aF0.10641811745639287 aF0.047104046492291315 aF-0.003466640874568507 aF0.17419701778544236 aF0.080292129236603338 aF-0.041658588401389987 aF0.043071865359607067 aF-0.014600170016479707 aF0.25767278129496635 aF-0.071340820996881771 aF0.1522728991685649 aF-0.060750304629792792 aF-0.062847231777321821 aF-0.0470595236344774 aF-0.091672523032918507 aF0.032847694492830433 aF-0.039580234965704349 aF0.029537233543764363 aF0.0750993948476993 aF-0.17135631302778428 aF-0.1499336206996055 aF0.11848430853427927 aF-0.049386713333446824 aF-0.086627133187029207 aF-0.036044210165912888 aF0.015524993228403087 aF-0.11084586091403006 aF0.0052337011841395624 aF0.040367561058598622 aF-0.0027402794492594343 aF-0.0048802757640931628 aF-0.13314784335585331 aF-0.065092817685368523 aF-0.10533487385104119 aF0.0097306019106171097 aF-0.030242134029479995 aF-0.043836532336292304 aF-0.056997007768730873 aF-0.028142797293627567 aF-0.084407619677833154 aF-0.033961894521222169 aF-0.13410619572506033 aF0.016711858272088265 aF-0.088760956500893634 aF-0.12040560080957897 aF0.083990730559999061 aF-0.090370052154332359 aF0.040825177481693481 aF-0.0040608988006757465 aF0.19532525716272187 aF-0.18573291087434221 aF0.050286492977160188 aF0.05417242691142634 aF0.067479227233466901 aF0.0039202440906208596 aF-0.0088662660033878484 aF0.10356758858610658 aF-0.089891072987312443 aF-0.06759663772839386 aF0.0038027819206750083 aF0.034066951953398331 aF-0.16964413648618737 aF0.016812764001769641 aF0.01269202611335889 aF-0.0056337056792934749 aF-0.016084473719576123 aF-0.046546559449240341 aF0.14519627035611532 aF0.15190980499116222 aF-0.07777342973983295 aF0.034866032603455617 aF0.018363011662855363 a(I50 I20 tp17 g7 tp18 Rp19 sS'b' p20 g4 ((lp21 F-0.17494482323471078 aF0.010130086837419693 aF1.3907158254129897 aF0.37464418421812318 aF0.23718600597427367 aF0.34016090872354826 aF-0.55201056728697639 aF0.0098429496749409054 aF0.75292121325671646 aF-0.51870628663700846 aF-0.65736287593121612 aF-0.37620337387404923 aF-0.24838703758738293 aF-0.026058490448326192 aF-0.53581320087497364 aF-0.013763428549170446 aF-0.64386495906274166 aF-0.63616003623358797 aF0.48130362205467414 aF0.50392445528638474 aF-0.50757353001414185 aF-0.37687414611842035 aF-1.0252370937233803 aF0.70861811021923793 aF-0.50244984236478107 aF-0.27862255650801299 aF-0.63395458332606547 aF0.49636111640380809 aF0.59720961963333297 aF-0.24271422651405122 aF-0.35107467913367585 aF-1.2693851997695071 aF-0.7021056349631144 aF-0.24984839210936544 aF-1.4665448318244334 aF-0.30600624812549704 aF-1.3920359660059674 aF-0.67759063840720701 aF0.041754150431754018 aF-1.2792723419519247 aF-0.072005469411446477 aF0.34970320199098109 aF-0.5568863827471715 aF0.94591956778302877 aF-0.13506237517641967 aF-1.1810864887056822 aF-0.094365674428022822 aF0.073998408524320824 aF0.42898056846646548 aF-0.29027578779908775 a(I50 I1 tp22 g7 tp23 Rp24 ssS'6.15' p25 (dp26 S'A' p27 g4 ((lp28 F0.25003786892612351 aF-0.059178809368941487 aF-0.23893546269585741 aF0.8040982384692108 aF0.72834087768969935 aF2.259480041314939 aF0.87784937292095555 aF-1.1781235875351923 aF1.1710997389319298 aF0.28661532004049511 aF-1.4218299880529588 aF-0.21927421285446527 aF-0.15292762220225695 aF0.71754808267764503 aF0.10592678760041113 aF-0.23814046412136802 aF-1.1080236744514922 aF0.3968374365453794 aF-1.1725308971226422 aF0.28749556684309852 aF-0.50788540647101621 aF-0.20682368621171882 aF-0.70924466217796689 aF1.0676194771667535 aF0.6061780816583493 aF1.6657625388586141 aF0.53493822500285182 aF-1.1761399714418026 aF-0.0073116050361567986 aF-0.81914582091229393 aF0.9671726592132065 aF0.45028478327067722 aF-0.50514111734975509 aF-0.78287996597012754 aF-0.45783088442576902 aF0.25610096521534903 aF-0.055630973574346765 aF0.064597886078462841 aF-1.18546001926358 aF0.50803565677923179 aF0.63414537417766026 aF0.14602884511059472 aF0.13729739931455973 aF-0.44577386903833183 aF-1.2222043565421912 aF-0.56834380363492487 aF-1.0983773329343263 aF1.6653566688636419 aF0.73258043398945261 aF-0.87169609885764143 aF-0.1984768527922223 aF0.2834991082277834 aF-0.77011755849317387 aF0.4852839022277608 aF0.58750812526043239 aF-0.36741047292678397 aF-0.61215769716140112 aF0.1968585721871858 aF0.46718984199461056 aF-0.9085570245213993 aF0.01242276114682081 aF-0.11043147006685544 aF0.24304333547244455 aF-1.3283319269971927 aF-1.36752640140215 aF-2.2598206713738187 aF-1.2640377985028335 aF2.283052815269464 aF-1.0557862202057837 aF0.079432182176553123 aF1.0562408793635381 aF0.6333966102538291 aF0.14171268191814351 aF-0.27125339381618702 aF0.31954097806615628 aF0.47400091612796624 aF0.49104886341471743 aF-0.97220236579446462 aF1.1647582542226096 aF-0.35766948146152477 aF-0.14129038813643882 aF0.34629777676935619 aF0.2728380774782162 aF0.19385462511317461 aF0.74489924106931782 aF-0.80643974520986705 aF0.46229319252446149 aF-0.72185528204607852 aF-0.60700378551548728 aF0.39633882772925744 aF-0.17306267930447911 aF-0.85630984070369109 aF1.0528134657514998 aF-0.20078964091426316 aF-0.027624055334616128 aF-0.21735590066143673 aF0.55858142828074853 aF0.45636177042259124 aF0.59690439001968731 aF0.44997981230070444 aF-0.32914405620430975 aF0.63877354673037445 aF-0.5497895663657002 aF1.2772230925541375 aF2.3263264245959441 aF1.8695478346490835 aF1.4368926766296901 aF-3.0353406845280073 aF-0.11956323005386738 aF0.57975361681607707 aF-0.69181718147751226 aF-0.84664291566905225 aF1.2030788383857915 aF0.17007323610646807 aF-0.49364611846537132 aF-0.064552797091005809 aF-0.22527474566659766 aF0.68055920970193839 aF-0.8221157921078055 aF1.1839675057756698 aF-0.015542966211810907 aF-0.36476277266424911 aF0.22764150044329121 aF-0.33453182607716475 aF-0.43262068989118102 aF-0.42015688055241684 aF0.095687891188762392 aF0.46282388164921529 aF0.0012939188673551649 aF0.052697744521397943 aF-0.054349221743711679 aF0.14637680393589755 aF-0.19314828759177663 aF-0.043098093601348489 aF0.18005659861412335 aF0.075801297944294882 aF0.078637553327431275 aF-0.29762304957670394 aF0.10745122983225297 aF-0.059909109492088886 aF-0.16819981839908613 aF-0.87664730332226048 aF0.45053146573490332 aF-0.55942490969674263 aF-0.24564446891847397 aF-1.347678346984984 aF0.0025483544526788693 aF1.0895861546022101 aF-0.41981826178634635 aF1.2114864571427428 aF-0.47824834776036768 aF0.19427198975720733 aF0.92158533631803974 aF-0.030614869655718482 aF0.092893881414845059 aF0.17924769984076383 aF0.14016240160280791 aF-0.25336078119949618 aF1.2268030036203061 aF0.29405587003838152 aF-0.30898884644941987 aF-1.128976901562095 aF0.59589299679666929 aF0.18832573509477502 aF0.60058916286136077 aF0.16113351033858725 aF1.648542205360084 aF-0.94061950991812737 aF0.76110120970872552 aF1.1418429796637746 aF-1.5985935916679974 aF-0.34385834145024674 aF0.47790224628531475 aF0.062383787224935247 aF0.26433977498802291 aF-0.24273399707910578 aF-0.35225750718632526 aF0.54663129357503393 aF-0.17146329731512616 aF0.710021533328133 aF0.34016765225765688 aF1.0905802833841407 aF-1.1163511782899787 aF1.7083740772773495 aF0.61271253928299041 aF3.679149076624626 aF0.06244669701249439 aF-1.8808226976540339 aF1.3903547169318622 aF-2.1718223133725196 aF0.36928192990289305 aF-0.012675364423275159 aF-1.7675282839522111 aF0.33134577440020696 aF-0.13910060537803384 aF-0.36533787708139259 aF-1.1716298369989993 aF0.84284939693097127 aF-2.4535530177841922 aF-0.4231636179078207 a(I20 I10 tp29 g7 tp30 Rp31 sS'B' p32 g4 ((lp33 F-0.093938931711387313 aF0.047650608737320022 aF0.087250063886046808 aF0.028832813514696722 aF-0.035279958109078753 aF0.24096602913672696 aF-0.085959767026266412 aF0.014646280558452431 aF-0.09612726965853495 aF0.056233185489577731 aF-0.2581708991108852 aF0.088274670093458754 aF-0.14739315874547268 aF-0.013766019455205326 aF-0.14168357045466881 aF-0.16558236423992856 aF-0.25256965636892853 aF-0.13015732756336501 aF0.028357506876190701 aF0.065967655870973405 aF0.2068401448938435 aF0.086220269830623003 aF-0.2872114847970883 aF-0.1375449654712638 aF-0.018927939751101793 aF-0.33779224929697216 aF-0.041842112730442409 aF-0.079360012932377308 aF0.044427743093070467 aF0.074712066583139863 aF0.12030433363980031 aF-0.026857922136630887 aF-0.031247742712063424 aF0.19383623915751369 aF0.24547024343911816 aF-0.051191873439064617 aF0.020732822319118504 aF-0.12896264384766068 aF0.0051812998677210134 aF0.10233319497439021 aF-0.079481187009714765 aF0.017412425023895249 aF0.0046809126504802796 aF-0.083511921102900274 aF-0.072161891340576545 aF0.25132916562484875 aF-0.13420340497169353 aF-0.066502930595451606 aF-0.20112101420637343 aF-0.012760499960766095 aF0.053037954284978983 aF-0.070469346934467658 aF0.04606528272383318 aF-0.096695825289419557 aF0.16954321866785454 aF-0.0041767927517590312 aF0.10403817474036575 aF0.29150617764628844 aF0.058530775273754554 aF0.17825112004322385 aF0.033566329139915779 aF-0.041506475749662694 aF-0.12339523823319276 aF-0.05144019724694613 aF0.15483574310236209 aF0.11530659463253326 aF-0.13832852868924445 aF-0.025758201968683746 aF-0.17375834779733651 aF0.040988432791573506 aF0.12954337814549641 aF-0.099907912084635064 aF-0.3737970832399844 aF0.093145188715757637 aF0.42872754479190567 aF0.071658125829274735 aF0.039899486866684299 aF0.037973382571938948 aF0.12829635533627493 aF0.27908776828996129 aF0.20383267432903876 aF-0.026104176052743806 aF0.0023075104956709154 aF0.032932951757010887 aF-0.11423501661555235 aF0.15478255246577705 aF0.021645245373229743 aF0.20816194788420123 aF-0.025874641130714547 aF0.22076043309473167 aF-0.25384533121579078 aF0.24365110512152224 aF-0.20299506100340059 aF-0.14051634335505611 aF0.0066751492342585683 aF-0.19448359599694048 aF0.062371943679208328 aF0.072918783810003551 aF0.17651184103014611 aF-0.054076351660124054 aF0.0559445428423406 aF0.033067751624565968 aF0.094131646353192364 aF0.084483131915361359 aF-0.13266767636353727 aF0.23618907966749306 aF-0.051082967341706725 aF-0.12184734897111189 aF-0.13316605092856204 aF0.15977715556848729 aF-0.021316378897339026 aF0.36149793311295858 aF-0.026537210834598337 aF-0.01890420979350084 aF0.054981905778027418 aF-0.15762704252767767 aF-0.037135467442436933 aF-0.21136909594524519 aF0.14024251411408523 aF0.040466126804798518 aF-0.16396959694154201 aF0.0093047515346948908 aF-0.05300976688431705 aF0.18566787627956607 aF0.18240794619002834 aF0.087987620610470371 aF0.065683123112646166 aF0.10704910853367605 aF-0.10257525315626044 aF0.04871879750717404 aF-0.05319661626353285 aF0.11554447883599699 aF-0.023745543509868891 aF0.25058363785205195 aF0.023047976386687919 aF0.17001783136201642 aF-0.0047251453017347787 aF-0.20071081476484645 aF0.048846324186016393 aF-0.02655859302220747 aF-0.18579019372064606 aF0.030658554557631289 aF0.036255090888476657 aF-0.048978249485660652 aF0.18408414957892838 aF-0.10662117817764771 aF-0.12523170597448163 aF-0.00032532702304840605 aF0.052952274725589277 aF-0.068006567645814017 aF-0.035866797423479826 aF-0.1446700328849464 aF0.26926707210159284 aF0.25989514200800623 aF-0.20341140557302756 aF0.25926510700881922 aF-0.11976380145691037 aF-0.040662454998708748 aF0.074231110500328365 aF-0.043348164646155235 aF0.17898445425805082 aF0.16340759237636424 aF-0.21336436737100381 aF-0.14274355981617665 aF-0.10159266947780948 aF0.056281478049249649 aF-0.057937113791074073 aF0.094417964240449445 aF0.030461911080015641 aF-0.13596039596590107 aF0.018697762042241526 aF-0.10001108124764241 aF-0.084086889050591557 aF0.18647320311578539 aF-0.22027781201374391 aF-0.2693809914594773 aF0.065737028012767873 aF-0.2078827414961984 aF-0.018797855914423962 aF0.032746219310993682 aF-0.035756199536202765 aF-0.076235420322406891 aF-0.025035467555755597 aF0.1615704591946841 aF-0.085407697696901319 aF0.080953941428165893 aF-0.083486039679039115 aF0.076500477282197998 aF-0.096845552646085534 aF0.15938315808573472 aF0.024965942731801929 aF0.2132254272303416 aF0.042955147049117182 aF0.11588687675041494 aF0.17270498668787082 aF0.058062727113721561 aF-0.051631531729916122 aF-0.015048511289939285 aF-0.12892050918179207 aF-0.27503139425554307 a(I20 I10 tp34 g7 tp35 Rp36 sS'b' p37 g4 ((lp38 F0.14999606832610834 aF0.54203757081097381 aF0.25440881648061237 aF-0.30724069381998481 aF-0.41711182958174531 aF1.1368048328938969 aF0.39131380909323454 aF1.6051478186749 aF0.82589230735685759 aF1.4703903557201077 aF-1.3789068923398957 aF-0.26017206900968748 aF0.99476817276398244 aF1.8340336818640284 aF-1.7159103187349525 aF0.086931705874662257 aF1.9556743528105947 aF0.1614537696153415 aF-0.6286883591253638 aF-1.4388244653384346 a(I20 I1 tp39 g7 tp40 Rp41 ss.cvxopt-1.1.4/examples/book/chap6/polapprox.py0000644000175000017500000001024011674452555020250 0ustar sonnesonne# Figures 6.19 and 6.20, page 332. # Polynomial and spline fitting. from cvxopt import lapack, solvers, matrix, mul from cvxopt.modeling import op, variable, max try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True from pickle import load #solvers.options['show_progress'] = 0 data = load(open('polapprox.bin','rb')) t, y = data['t'], data['y'] m = len(t) # LS fit of 5th order polynomial # # minimize ||A*x - y ||_2 n = 6 A = matrix( [[t**k] for k in range(n)] ) xls = +y lapack.gels(+A,xls) xls = xls[:n] # Chebyshev fit of 5th order polynomial # # minimize ||A*x - y ||_inf xinf = variable(n) op( max(abs(A*xinf - y)) ).solve() xinf = xinf.value if pylab_installed: pylab.figure(1, facecolor='w') pylab.plot(t, y, 'bo', mfc='w', mec='b') nopts = 1000 ts = -1.1 + (1.1 - (-1.1))/nopts * matrix(list(range(nopts)), tc='d') yls = sum( xls[k] * ts**k for k in range(n) ) yinf = sum( xinf[k] * ts**k for k in range(n) ) pylab.plot(ts,yls,'g-', ts, yinf, '--r') pylab.axis([-1.1, 1.1, -0.1, 0.25]) pylab.xlabel('u') pylab.ylabel('p(u)') pylab.title('Polynomial fitting (fig. 6.19)') # Fit of cubic spline # # f(t) = p1(t) -1 <= t <= -1/3 # = p2(t) -1/3 <= t <= 1/3 # = p3(t) 1/3 <= t <= 1 # # p1(t) = x0 + x1*t + x2*t^2 + x3*t^3 -1 <= t <= -1/3 # p2(t) = x4 + x5*t + x6*t^2 + x7*t^3 -1/3 <= t <= 1/3 # p3(t) = x8 + x9*t + x10*t^2 + x11*t^3 1/3 <= t <= 1 # # with constraints # # p1(-1/3) = p2(-1/3), # p1'(-1/3) = p2'(-1/3) # p1''(-1/3) = p2''(-1/3) # p2(1/3) = p3(1/3), # p2'(1/3) = p3'(1/3) # p2''(1/3) = p3''(1/3) n = 12 u1, u2 = -1.0/3, 1.0/3 I1 = [ k for k in range(m) if -1.0 <= t[k] < u1 ] I2 = [ k for k in range(m) if u1 <= t[k] < u2 ] I3 = [ k for k in range(m) if u2 <= t[k] <= 1.0 ] m1, m2, m3 = len(I1), len(I2), len(I3) A = matrix(0.0, (m,n)) for k in range(4): A[I1,k] = t[I1]**k A[I2,k+4] = t[I2]**k A[I3,k+8] = t[I3]**k G = matrix(0.0, (6,n)) # p1(u1) = p2(u1), p1(u2) = p2(u2) G[0, list(range(8))] = \ 1.0, u1, u1**2, u1**3, -1.0, -u1, -u1**2, -u1**3 G[1, list(range(4,12))] = \ 1.0, u2, u2**2, u2**3, -1.0, -u2, -u2**2, -u2**3 # p1'(u1) = p2'(u1), p1'(u2) = p2'(u2) G[2, [1,2,3,5,6,7]] = 1.0, 2*u1, 3*u1**2, -1.0, -2*u1, -3*u1**2 G[3, [5,6,7,9,10,11]] = 1.0, 2*u2, 3*u2**2, -1.0, -2*u2, -3*u2**2 # p1''(u1) = p2''(u1), p1''(u2) = p2''(u2) G[4, [2,3,6,7]] = 2, 6*u1, -2, -6*u1 G[5, [6,7,10,11]] = 2, 6*u2, -2, -6*u2 # LS fit # # minimize (1/2) * || A*x - y ||_2^2 # subject to G*x = h # # Solve as a linear equation # # [ A'*A G' ] [ x ] [ A'*y ] # [ G 0 ] [ y ] = [ 0 ]. K = matrix(0.0, (n+6,n+6)) K[:n,:n] = A.T * A K[n:,:n] = G xls = matrix(0.0, (n+6,1)) xls[:n] = A.T * y lapack.sysv(K, xls) xls = xls[:n] # Chebyshev fit # # minimize || A*x - y ||_inf # subject to G*x = h xcheb = variable(12) op( max(abs(A*xcheb - y)), [G*xcheb == 0]).solve() xcheb = xcheb.value if pylab_installed: pylab.figure(2, facecolor='w') nopts = 100 ts = -1.0 + (1.0 - (-1.0))/nopts * matrix(list(range(nopts)), tc='d') I1 = [ k for k in range(nopts) if -1.0 <= ts[k] < u1 ] I2 = [ k for k in range(nopts) if u1 <= ts[k] < u2 ] I3 = [ k for k in range(nopts) if u2 <= ts[k] <= 1.0 ] yls = matrix(0.0, (nopts,1)) yls[I1] = sum( xls[k]*ts[I1]**k for k in range(4) ) yls[I2] = sum( xls[k+4]*ts[I2]**k for k in range(4) ) yls[I3] = sum( xls[k+8]*ts[I3]**k for k in range(4) ) ycheb = matrix(0.0, (nopts,1)) ycheb[I1] = sum( xcheb[k]*ts[I1]**k for k in range(4) ) ycheb[I2] = sum( xcheb[k+4]*ts[I2]**k for k in range(4) ) ycheb[I3] = sum( xcheb[k+8]*ts[I3]**k for k in range(4) ) pylab.plot(t, y, 'bo', mfc='w', mec='b') pylab.plot([-1.0, -1.0], [-0.1, 0.25], 'k--', [-1./3,-1./3], [-0.1, 0.25], 'k--', [1./3,1./3], [-0.1, 0.25], 'k--', [1,1], [-0.1, 0.25], 'k--') pylab.plot(ts, yls, '-g', ts, ycheb, '--r') pylab.axis([-1.1, 1.1, -0.1, 0.25]) pylab.xlabel('u') pylab.ylabel('p(u)') pylab.title('Cubic spline fitting (fig. 6.20)') pylab.show() cvxopt-1.1.4/examples/book/chap6/regsel.bin0000644000175000017500000001124411674452555017632 0ustar sonnesonne(dp0 S'A' p1 ccvxopt.base matrix p2 ((lp3 F0.3792236226850329 aF0.94419972674730834 aF-2.1204266882242115 aF-0.6446789155419369 aF-0.70430172843360894 aF-1.0181372163990707 aF-0.18208186841138524 aF1.521013239005587 aF-0.038438763886711559 aF1.2274479890097165 aF-0.69620480003288876 aF0.0075244865230144464 aF-0.78289304437828722 aF0.58693855921443094 aF-0.25120737456888181 aF0.48013582284260076 aF0.66815503443364055 aF-0.078321196273411942 aF0.88917261841259909 aF2.3092874859523866 aF0.52463867977109835 aF-0.011787323951306753 aF0.91314081776137068 aF0.055940678888401998 aF-1.1070698948260072 aF0.48549770731281022 aF-0.0050050737555313854 aF-0.27621785935475895 aF1.2764524736743927 aF1.8634006131845375 aF-0.52255930163639908 aF0.10342444693731498 aF-0.80764913089718049 aF0.68043858374894572 aF-2.364589847941581 aF0.99011487204949045 aF0.21889912088117661 aF0.26166246016140166 aF1.2134444949753469 aF-0.27466698645678145 aF-0.13313445081352937 aF-1.2705002037083766 aF-1.663606452829772 aF-0.70355426153675493 aF0.28088048852330211 aF-0.54120932991619408 aF-1.3335307297363925 aF1.0726862678901432 aF-0.71208545249435584 aF-0.01128556123068556 aF-0.0008170291956958361 aF-0.24943628469543444 aF0.39657531871165158 aF-0.26401335492224315 aF-1.664010876930589 aF-1.028975099543801 aF0.243094700224565 aF-1.2565901078338166 aF-0.34718318973352613 aF-0.94137219342832856 aF-1.1745602813024438 aF-1.021141686935775 aF-0.40166673459678831 aF0.17366566856230725 aF-0.11611849335051072 aF1.0641191489863535 aF-0.24538629675166962 aF-1.5175391310895556 aF0.0097341591259511185 aF0.071372864855954732 aF0.3165358137685082 aF0.49982566779647836 aF1.2780841467141097 aF-0.54781614692115776 aF0.26080839887907459 aF-0.013176671873511559 aF-0.58026400214195251 aF2.1363084228053086 aF-0.25761711565348083 aF-1.4095284893691984 aF1.7701008928516144 aF0.32554598476071001 aF-1.1190395753813116 aF0.62035013944552475 aF1.2697818471897746 aF-0.89604250642191452 aF0.13517544475843685 aF-0.13904001004044259 aF-1.1633952938372654 aF1.1837195399368565 aF-0.015429661783325022 aF0.53621869471861705 aF-0.71642862372585547 aF-0.65555938950390591 aF0.31436276331074814 aF0.10681407593458775 aF1.8482162180189687 aF-0.27510567543881131 aF2.2125540789896809 aF1.5085257560961467 aF-1.945078599919331 aF-1.6805427775226454 aF-0.57353413410587606 aF-0.18581652736765947 aF0.0089341156765677023 aF0.83694989083729465 aF-0.72227067243329512 aF-0.72149047716441006 aF-0.20118099951714263 aF-0.020464161095144321 aF0.27888999991245078 aF1.05829481445 aF0.6216732824024096 aF-1.7506152884853836 aF0.69734755148343741 aF0.81148586331699257 aF0.63634494760413318 aF1.310080341410262 aF0.32709751591819802 aF-0.67299316385471109 aF-0.14932749947673082 aF-2.4490177537568125 aF0.47328561224355359 aF0.11694565679328851 aF-0.59110383863220495 aF-0.65470767508278371 aF-1.0806618512116946 aF-0.04773086529790517 aF0.37934453728879497 aF-0.33036104579865933 aF-0.49989825118472925 aF-0.035978607953005746 aF-0.17476033119671699 aF-0.95726507882166145 aF1.2925479001322682 aF0.440909642847022 aF1.2809409427445406 aF-0.49772980521188004 aF-1.1187166376043225 aF0.80764961943935132 aF0.041199578638244888 aF-0.75620860554670111 aF-0.08912914780643004 aF-2.0088503217891547 aF1.0839180379588267 aF-0.98119056314417352 aF-0.68848863746469791 aF1.3394794818077986 aF-0.90924316031600994 aF-0.41285772861879833 aF-0.50616318564854024 aF1.6197477991253717 aF0.080900711206500039 aF-1.0810564901769375 aF-1.1245178115942032 aF1.7356763426062964 aF1.9374585965267537 aF1.6350682185206411 aF-1.2559401667743206 aF-0.2135375062087026 aF-0.19893204828268177 aF0.3074991774798489 aF-0.57232545648506006 aF-0.97764836704205615 aF-0.44680940665694829 aF1.0820919008951635 aF2.372647949389985 aF0.2292883361044312 aF-0.26662313612389132 aF0.70167217691939954 aF-0.48759049128980936 aF1.8624797253190992 aF1.1068511103913441 aF-1.2275657222158463 aF-0.66988511005648677 aF1.3409294523313127 aF0.38808331624114234 aF0.39305892877699972 aF-1.7073335778377412 aF0.22785864470433817 aF0.68563285776295124 aF-0.63679011291329279 aF-1.0026055542338093 aF-0.1856206729110158 aF-1.0540327142000288 aF-0.071539488916578894 aF0.27919841968634951 aF1.3732753424840702 aF0.1798410321847575 aF-0.54201655650396363 aF1.634190580750742 aF0.82521515151758584 aF0.23076114227231159 aF0.67163394593208492 aF-0.50807788041779367 aF0.85635159733999011 aF0.26850345353239546 aF0.62497517619067067 aF-1.0473379377146483 aF1.5356703814685793 a(I10 I20 tp4 S'd' p5 tp6 Rp7 sS'b' p8 g2 ((lp9 F1.7681714743362944 aF0.44972610702627669 aF-1.5918328806524971 aF-2.2520492785828985 aF-2.1770837388797588 aF0.00033917950394704577 aF-1.923579585243794 aF1.4722144218103526 aF-0.88923264442387262 aF-3.2515796920953459 a(I10 I1 tp10 g5 tp11 Rp12 s.cvxopt-1.1.4/examples/book/chap6/tv.py0000644000175000017500000002117611674452555016667 0ustar sonnesonne# Figures 6.11-14, pages 315-317. # Total variation reconstruction. from math import pi from cvxopt import blas, lapack, solvers from cvxopt import matrix, spmatrix, sin, mul, div, normal #solvers.options['show_progress'] = 0 try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True n = 2000 t = matrix( list(range(n)), tc='d' ) ex = matrix( n//4*[1.0] + n//4*[-1.0] + n//4*[1.0] + n//4*[-1.0] ) + \ 0.5 * sin( 2.0*pi/n * t ) corr = ex + 0.1 * normal(n,1) if pylab_installed: pylab.figure(1, facecolor='w', figsize=(8,5)) pylab.subplot(211) pylab.plot(t, ex) pylab.ylabel('x[i]') pylab.xlabel('i') pylab.axis([0, 2000, -2, 2]) pylab.title('Original and corrupted signal (fig. 6.11)') pylab.subplot(212) pylab.plot(t, corr) pylab.ylabel('xcor[i]') pylab.xlabel('i') pylab.axis([0, 2000, -2, 2]) # Quadratic smoothing. # A = D'*D is an n by n tridiagonal matrix with -1.0 on the # upper/lower diagonal and 1, 2, 2, ..., 2, 2, 1 on the diagonal. Ad = matrix([1.0] + (n-2)*[2.0] + [1.0]) As = matrix(-1.0, (n-1,1)) nopts = 100 deltas = -10.0 + 20.0/(nopts-1) * matrix(list(range(nopts))) cost1, cost2 = [], [] for delta in deltas: xr = +corr lapack.ptsv(1.0 + 10**delta * Ad, 10**delta * As, xr) cost1 += [blas.nrm2(xr - corr)] cost2 += [blas.nrm2(xr[1:] - xr[:-1])] # Find solutions with ||xhat - xcorr || roughly equal to 4, 7, 10. mv1, k1 = min(zip([abs(c - 10.0) for c in cost1], range(nopts))) xr1 = +corr lapack.ptsv(1.0 + 10**deltas[k1] * Ad, 10**deltas[k1] * As, xr1) mv2, k2 = min(zip([abs(c - 7.0) for c in cost1], range(nopts))) xr2 = +corr lapack.ptsv(1.0 + 10**deltas[k2] * Ad, 10**deltas[k2] * As, xr2) mv3, k3 = min(zip([abs(c - 4.0) for c in cost1], range(nopts))) xr3 = +corr lapack.ptsv(1.0 + 10**deltas[k3] * Ad, 10**deltas[k3] * As, xr3) if pylab_installed: pylab.figure(2, facecolor='w') pylab.plot(cost1, cost2, [blas.nrm2(corr)], [0], 'bo', [0], [blas.nrm2(corr[1:] - corr[:-1])], 'bo') pylab.plot([cost1[k1]], [cost2[k1]], 'bo', [cost1[k2]], [cost2[k2]], 'bo', [cost1[k3]], [cost2[k3]], 'bo') pylab.text(cost1[k1], cost2[k1], '1') pylab.text(cost1[k2], cost2[k2], '2') pylab.text(cost1[k3], cost2[k3], '3') pylab.title('Optimal trade-off curve (quadratic smoothing)') pylab.xlabel('|| xhat - xcor ||_2') pylab.ylabel('|| D*xhat ||_2') pylab.axis([-0.4, 50, -0.1, 8.0]) pylab.grid() pylab.figure(3, facecolor='w', figsize=(8,7.5)) pylab.subplot(311) pylab.plot(t, xr1) pylab.axis([0, 2000, -2.0, 2.0]) pylab.ylabel('xhat1[i]') pylab.title('Three quadratically smoothed sigals (fig. 6.12).') pylab.subplot(312) pylab.plot(t, xr2) pylab.ylabel('xhat2[i]') pylab.axis([0, 2000, -2.0, 2.0]) pylab.subplot(313) pylab.plot(t, xr3) pylab.axis([0, 2000, -2.0, 2.0]) pylab.ylabel('xhat3[i]') pylab.xlabel('i') #print "Close figures to start total variation reconstruction." #pylab.show() # Total variation smoothing. # # minimize (1/2) * ||x-corr||_2^2 + delta * || D*x ||_1 # # minimize (1/2) * ||x-corr||_2^2 + delta * 1'*y # subject to -y <= D*x <= y # # Variables x (n), y (n-1). def tv(delta): """ minimize (1/2) * ||x-corr||_2^2 + delta * sum(y) subject to -y <= D*x <= y Variables x (n), y (n-1). """ q = matrix(0.0, (2*n-1,1)) q[:n] = -corr q[n:] = delta def P(u, v, alpha = 1.0, beta = 0.0): """ v := alpha*u + beta*v """ v *= beta v[:n] += alpha*u[:n] def G(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): """ v := alpha*[D, -I; -D, -I] * u + beta * v (trans = 'N') v := alpha*[D, -I; -D, -I]' * u + beta * v (trans = 'T') For an n-vector z, D*z = z[1:] - z[:-1]. For an (n-1)-vector z, D'*z = [-z;0] + [0; z]. """ v *= beta if trans == 'N': y = u[1:n] - u[:n-1] v[:n-1] += alpha*(y - u[n:]) v[n-1:] += alpha*(-y - u[n:]) else: y = u[:n-1] - u[n-1:] v[:n-1] -= alpha * y v[1:n] += alpha * y v[n:] -= alpha * (u[:n-1] + u[n-1:]) h = matrix(0.0, (2*(n-1),1)) # Customized solver for KKT system with coefficient # # [ I 0 D' -D' ] # [ 0 0 -I -I ] # [ D -I -D1 0 ] # [ -D -I 0 -D2 ]. # Diagonal and subdiagonal. Sd = matrix(0.0, (n,1)) Se = matrix(0.0, (n-1,1)) def Fkkt(W): """ Factor the tridiagonal matrix S = I + 4.0 * D' * diag( d1.*d2./(d1+d2) ) * D with d1 = W['di'][:n-1]**2 = diag(D1^-1) d2 = W['di'][n-1:]**2 = diag(D2^-1). """ d1 = W['di'][:n-1]**2 d2 = W['di'][n-1:]**2 d = 4.0*div( mul(d1,d2), d1+d2) Sd[:] = 1.0 Sd[:n-1] += d Sd[1:] += d Se[:] = -d lapack.pttrf(Sd, Se) def g(x, y, z): """ Solve [ I 0 D' -D' ] [x[:n] ] [bx[:n] ] [ 0 0 -I -I ] [x[n:] ] = [bx[n:] ] [ D -I -D1 0 ] [z[:n-1] ] [bz[:n-1] ] [ -D -I 0 -D2 ] [z[n-1:] ] [bz[n-1:] ]. First solve S*x[:n] = bx[:n] + D' * ( (d1-d2) ./ (d1+d2) .* bx[n:] + 2*d1.*d2./(d1+d2) .* (bz[:n-1] - bz[n-1:]) ). Then take x[n:] = (d1+d2)^-1 .* ( bx[n:] - d1.*bz[:n-1] - d2.*bz[n-1:] + (d1-d2) .* D*x[:n] ) z[:n-1] = d1 .* (D*x[:n] - x[n:] - bz[:n-1]) z[n-1:] = d2 .* (-D*x[:n] - x[n:] - bz[n-1:]). """ # y = (d1-d2) ./ (d1+d2) .* bx[n:] + # 2*d1.*d2./(d1+d2) .* (bz[:n-1] - bz[n-1:]) y = mul( div(d1-d2, d1+d2), x[n:]) + \ mul( 0.5*d, z[:n-1]-z[n-1:] ) # x[:n] += D*y x[:n-1] -= y x[1:n] += y # x[:n] := S^-1 * x[:n] lapack.pttrs(Sd, Se, x) # u = D*x[:n] u = x[1:n] - x[0:n-1] # x[n:] = (d1+d2)^-1 .* ( bx[n:] - d1.*bz[:n-1] # - d2.*bz[n-1:] + (d1-d2) .* u) x[n:] = div( x[n:] - mul(d1, z[:n-1]) - mul(d2, z[n-1:]) + mul(d1-d2, u), d1+d2 ) # z[:n-1] = d1 .* (D*x[:n] - x[n:] - bz[:n-1]) # z[n-1:] = d2 .* (-D*x[:n] - x[n:] - bz[n-1:]) z[:n-1] = mul(W['di'][:n-1], u - x[n:] - z[:n-1]) z[n-1:] = mul(W['di'][n-1:], -u - x[n:] - z[n-1:]) return g return solvers.coneqp(P, q, G, h, kktsolver = Fkkt)['x'][:n] nopts = 15 deltas = -3.0 + (3.0-(-3.0))/(nopts-1) * matrix(list(range(nopts))) cost1, cost2 = [], [] for delta, k in zip(deltas, range(nopts)): xtv = tv(10**delta) cost1 += [blas.nrm2(xtv - corr)] cost2 += [blas.asum(xtv[1:] - xtv[:-1])] mv1, k1 = min(zip([abs(c - 20.0) for c in cost2], range(nopts))) xtv1 = tv(10**deltas[k1]) mv2, k2 = min(zip([abs(c - 8.0) for c in cost2], range(nopts))) xtv2 = tv(10**deltas[k2]) mv3, k3 = min(zip([abs(c - 5.0) for c in cost2], range(nopts))) xtv3 = tv(10**deltas[k3]) if pylab_installed: pylab.figure(4, facecolor='w', figsize=(8,5)) pylab.subplot(211) pylab.plot(t, ex) pylab.ylabel('x[i]') pylab.xlabel('i') pylab.axis([0, 2000, -2, 2]) pylab.title('Original and corrupted signal (fig. 6.11)') pylab.subplot(212) pylab.plot(t, corr) pylab.ylabel('xcor[i]') pylab.xlabel('i') pylab.axis([0, 2000, -2, 2]) pylab.figure(5, facecolor='w') #figsize=(8,7.5)) pylab.plot(cost1, cost2, [blas.nrm2(corr)], [0], 'bo', [0], [blas.asum(corr[1:] - corr[:-1])], 'bo') pylab.plot([cost1[k1]], [cost2[k1]], 'bo', [cost1[k2]], [cost2[k2]], 'bo', [cost1[k3]], [cost2[k3]], 'bo') pylab.text(cost1[k1], cost2[k1],'1') pylab.text(cost1[k2], cost2[k2],'2') pylab.text(cost1[k3], cost2[k3],'3') pylab.grid() pylab.axis([-1, 50, -5, 250]) pylab.xlabel('||xhat-xcor||_2') pylab.ylabel('||D*xhat||_1') pylab.title('Optimal trade-off curve (fig. 6.13)') pylab.figure(6, facecolor='w', figsize=(8,7.5)) pylab.subplot(311) pylab.plot(t, xtv1) pylab.axis([0, 2000, -2.0, 2.0]) pylab.ylabel('xhat1[i]') pylab.title('Three reconstructed signals (fig. 6.14)') pylab.subplot(312) pylab.plot(t, xtv2) pylab.ylabel('xhat2[i]') pylab.axis([0, 2000, -2.0, 2.0]) pylab.subplot(313) pylab.plot(t, xtv3) pylab.axis([0, 2000, -2.0, 2.0]) pylab.ylabel('xhat3[i]') pylab.xlabel('i') pylab.show() cvxopt-1.1.4/examples/book/chap6/consumerpref.py0000644000175000017500000001020511674452555020735 0ustar sonnesonne# Figures 6.25 and 6.26, page 342. # Consumer preference analysis. from cvxopt import solvers, matrix, sqrt from cvxopt.modeling import variable, op #solvers.options['show_progress'] = 0 try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True def utility(x, y): return (1.1 * sqrt(x) + 0.8 * sqrt(y)) / 1.9 B = matrix([ 4.5e-01, 9.6e-01, 2.1e-01, 3.4e-01, 2.8e-01, 8.7e-01, 9.6e-01, 3.0e-02, 8.0e-02, 9.2e-01, 2.0e-02, 2.2e-01, 0.0e+00, 3.9e-01, 2.6e-01, 6.4e-01, 3.5e-01, 9.7e-01, 9.1e-01, 7.8e-01, 1.2e-01, 1.4e-01, 5.8e-01, 8.4e-01, 3.2e-01, 7.3e-01, 4.9e-01, 2.7e-01, 7.0e-02, 8.0e-01, 9.3e-01, 8.7e-01, 4.4e-01, 8.6e-01, 3.3e-01, 4.2e-01, 8.9e-01, 9.0e-01, 4.9e-01, 7.0e-02, 9.5e-01, 3.3e-01, 6.6e-01, 2.6e-01, 9.5e-01, 7.3e-01, 4.2e-01, 9.1e-01, 6.8e-01, 2.0e-01, 8.7e-01, 1.7e-01, 5.2e-01, 6.2e-01, 7.7e-01, 6.3e-01, 2.0e-02, 2.9e-01, 9.8e-01, 2.0e-02, 5.0e-02, 7.9e-01, 7.9e-01, 1.9e-01, 6.2e-01, 6.0e-02, 6.9e-01, 1.0e-01, 6.9e-01, 3.7e-01, 0.0e+00, 7.2e-01, 6.3e-01, 4.0e-02, 4.0e-02, 4.6e-01, 3.6e-01, 9.5e-01, 8.2e-01, 6.7e-01 ], (2, 40)) m = B.size[1] # Plot some contour lines. nopts = 200 a = (1.0/nopts)*matrix(range(nopts), tc='d') X, Y = a[:,nopts*[0]].T, a[:,nopts*[0]] if pylab_installed: pylab.figure(1, facecolor='w') pylab.plot(B[0,:], B[1,:], 'wo', markeredgecolor='b') pylab.contour(pylab.array(X), pylab.array(Y), pylab.array(utility(X,Y)), [.1*(k+1) for k in range(9)], colors='k') pylab.xlabel('x1') pylab.ylabel('x2') pylab.title('Goods baskets and utility function (fig. 6.25)') #print("Close figure to start analysis.") #pylab.show() # P are basket indices in order of increasing preference l = list(zip(utility(B[0,:], B[1,:]), range(m))) l.sort() P = [ e[1] for e in l ] # baskets with known preference relations u = variable(m) gx = variable(m) gy = variable(m) # comparison basket at (.5, .5) has utility 0 gxc = variable(1) gyc = variable(1) monotonicity = [ gx >= 0, gy >= 0, gxc >= 0, gyc >= 0 ] preferences = [ u[P[j+1]] >= u[P[j]] + 1.0 for j in range(m-1) ] concavity = [ u[j] <= u[i] + gx[i] * ( B[0,j] - B[0,i] ) + gy[i] * ( B[1,j] - B[1,i] ) for i in range(m) for j in range(m) ] concavity += [ 0 <= u[i] + gx[i] * ( 0.5 - B[0,i] ) + gy[i] * ( 0.5 - B[1,i] ) for i in range(m) ] concavity += [ u[j] <= gxc * ( B[0,j] - 0.5 ) + gyc * ( B[1,j] - 0.5 ) for j in range(m) ] preferred, rejected, neutral = [], [], [] for k in range(m): p = op(-u[k], monotonicity + preferences + concavity) p.solve() if p.status == 'optimal' and p.objective.value()[0] > 0: rejected += [k] print("Basket (%1.2f, %1.2f) rejected." %(B[0,k],B[1,k])) else: p = op(u[k], monotonicity + preferences + concavity) p.solve() if p.status == 'optimal' and p.objective.value()[0] > 0: print("Basket (%1.2f, %1.2f) preferred." %(B[0,k],B[1,k])) preferred += [k] else: print("No conclusion about basket (%1.2f, %1.2f)." \ %(B[0,k],B[1,k])) neutral += [k] if pylab_installed: pylab.figure(1, facecolor='w') pylab.plot(B[0,:], B[1,:], 'wo', markeredgecolor='b') pylab.contour(pylab.array(X), pylab.array(Y), pylab.array(utility(X,Y)), [.1*(k+1) for k in range(9)], colors='k') pylab.xlabel('x1') pylab.ylabel('x2') pylab.title('Goods baskets and utility function (fig. 6.25)') pylab.figure(2, facecolor='w') pylab.plot(B[0,preferred], B[1,preferred], 'go') pylab.plot(B[0,rejected], B[1,rejected], 'ro') pylab.plot(B[0,neutral], B[1,neutral], 'ys') pylab.plot([0.5], [0.5], '+') pylab.plot([0.5, 0.5], [0,1], ':', [0,1], [0.5,0.5], ':') pylab.axis([0,1,0,1]) pylab.contour(pylab.array(X), pylab.array(Y), pylab.array(utility(X,Y)), [utility(0.5,0.5)], colors='k') pylab.xlabel('x1') pylab.ylabel('x2') pylab.title('Result of preference analysis (fig. 6.26)') pylab.show() cvxopt-1.1.4/examples/book/chap6/huber.bin0000644000175000017500000000350111674452555017453 0ustar sonnesonne(dp0 S'u' p1 ccvxopt.base matrix p2 ((lp3 F0.2581787157143367 aF-0.79032498914297911 aF-2.9920925260484657 aF-8.0990852965503386 aF-1.3265791215591971 aF4.184703954581499 aF-7.6806353487449863 aF-8.4383063569843326 aF-2.6149418356897964 aF-9.3274324384180041 aF-6.1569924914077827 aF-0.57280309059322043 aF-7.1015436002526169 aF4.3567105542666784 aF3.234285560079984 aF-1.3625917357218409 aF-1.0793022769872564 aF0.16663067516248198 aF0.56175745584152459 aF1.457560328514111 aF-2.7835586633456675 aF-3.2704548506394282 aF-6.5346746968732559 aF-8.2776303488191356 aF-2.1332726032162421 aF6.0873577446152254 aF-9.7783862518977305 aF-5.3377356451646127 aF8.677011718357452 aF-5.4640495662875708 aF5.7189394048037663 aF-1.7854234631105435 aF-7.6121444989052343 aF2.6874068997276055 aF7.247763721853385 aF-6.8351268101647156 aF2.0237015616259075 aF-7.6478537533655082 aF2.5219671859042574 aF6.7024934928410183 aF-9.5 aF9.0 a(I42 I1 tp4 S'd' p5 tp6 Rp7 sS'v' p8 g2 ((lp9 F5.4936896400312936 aF5.4274168025687288 aF2.5957278032779536 aF-2.7682391951102887 aF4.4450599912428901 aF8.8287508575062894 aF-2.9443247093129354 aF-3.5593049753212678 aF2.2284579997026248 aF-3.9802154202240274 aF-2.1188068795744126 aF4.9546317086933325 aF-2.300988118339931 aF9.3075747131227526 aF7.7935911147364498 aF3.1937903207238514 aF4.303236510004866 aF4.9477606964246261 aF5.0033964014225072 aF6.0324219885427803 aF2.4207250219709726 aF1.0605990066305857 aF-1.4556289000445948 aF-3.0969998656187521 aF2.6304308708244863 aF11.358429048442082 aF-5.143167335848978 aF0.23615669383315208 aF13.58831462050204 aF0.094486689236513599 aF10.53303094377349 aF3.3789693568024424 aF-1.8187583043782631 aF6.9619442099217848 aF12.761815572041129 aF-2.4380182798326717 aF6.0830273125621552 aF-2.2168483473403287 aF7.387425622245142 aF11.458313858767751 aF20.0 aF-15.0 a(I42 I1 tp10 g5 tp11 Rp12 s.cvxopt-1.1.4/examples/book/chap6/huber.py0000644000175000017500000000352211674452555017336 0ustar sonnesonne# Figure 6.5, page 300. # Robust regression. from cvxopt import solvers, lapack, matrix, spmatrix from pickle import load #solvers.options['show_progress'] = 0 data = load(open('huber.bin','rb')) u, v = data['u'], data['v'] m, n = len(u), 2 A = matrix( [m*[1.0], [u]] ) b = +v # Least squares solution. xls = +b lapack.gels(+A, xls) xls = xls[:2] # Robust least squares. # # minimize sum( h( A*x-b )) # # where h(u) = u^2 if |u| <= 1.0 # = 2*(|u| - 1.0) if |u| > 1.0. # # Solve as a QP (see exercise 4.5): # # minimize (1/2) * u'*u + 1'*v # subject to -u - v <= A*x-b <= u + v # 0 <= u <= 1 # v >= 0 # # Variables x (n), u (m), v(m) novars = n+2*m P = spmatrix([],[],[], (novars, novars)) P[n:n+m,n:n+m] = spmatrix(1.0, range(m), range(m)) q = matrix(0.0, (novars,1)) q[-m:] = 1.0 G = spmatrix([], [], [], (5*m, novars)) h = matrix(0.0, (5*m,1)) # A*x - b <= u+v G[:m,:n] = A G[:m,n:n+m] = spmatrix(-1.0, range(m), range(m)) G[:m,n+m:] = spmatrix(-1.0, range(m), range(m)) h[:m] = b # -u - v <= A*x - b G[m:2*m,:n] = -A G[m:2*m,n:n+m] = spmatrix(-1.0, range(m), range(m)) G[m:2*m,n+m:] = spmatrix(-1.0, range(m), range(m)) h[m:2*m] = -b # u >= 0 G[2*m:3*m,n:n+m] = spmatrix(-1.0, range(m), range(m)) # u <= 1 G[3*m:4*m,n:n+m] = spmatrix(1.0, range(m), range(m)) h[3*m:4*m] = 1.0 # v >= 0 G[4*m:,n+m:] = spmatrix(-1.0, range(m), range(m)) xh = solvers.qp(P, q, G, h)['x'][:n] try: import pylab except ImportError: pass else: pylab.figure(1,facecolor='w') pylab.plot(u, v,'o', [-11,11], [xh[0]-11*xh[1], xh[0]+11*xh[1]], '-g', [-11,11], [xls[0]-11*xls[1], xls[0]+11*xls[1]], '--r', markerfacecolor='w', markeredgecolor='b') pylab.axis([-11, 11, -20, 25]) pylab.xlabel('t') pylab.ylabel('f(t)') pylab.title('Robust regression (fig. 6.5)') pylab.show() cvxopt-1.1.4/examples/book/chap6/regsel.py0000644000175000017500000000647511674452555017524 0ustar sonnesonne# Figure 6.7, page 311. # Sparse regressor selection. # # The problem data are different from the book. from cvxopt import blas, lapack, solvers, matrix, mul from pickle import load solvers.options['show_progress'] = 0 try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True data = load(open('regsel.bin','rb')) A, b = data['A'], data['b'] m, n = A.size # In the heuristic, set x[k] to zero if abs(x[k]) <= tol * max(abs(x)). tol = 1e-1 # Data for QP # # minimize (1/2) ||A*x - b|_2^2 # subject to -y <= x <= y # sum(y) <= alpha P = matrix(0.0, (2*n,2*n)) P[:n,:n] = A.T*A q = matrix(0.0, (2*n,1)) q[:n] = -A.T*b I = matrix(0.0, (n,n)) I[::n+1] = 1.0 G = matrix([[I, -I, matrix(0.0, (1,n))], [-I, -I, matrix(1.0, (1,n))]]) h = matrix(0.0, (2*n+1,1)) # Least-norm solution xln = matrix(0.0, (n,1)) xln[:m] = b lapack.gels(+A, xln) nopts = 100 res = [ blas.nrm2(b) ] card = [ 0 ] alphas = blas.asum(xln)/(nopts-1) * matrix(range(1,nopts), tc='d') for alpha in alphas: # minimize ||A*x-b||_2 # subject to ||x||_1 <= alpha h[-1] = alpha x = solvers.qp(P, q, G, h)['x'][:n] xmax = max(abs(x)) I = [ k for k in range(n) if abs(x[k]) > tol*xmax ] if len(I) <= m: xs = +b lapack.gels(A[:,I], xs) x[:] = 0.0 x[I] = xs[:len(I)] res += [ blas.nrm2(A*x-b) ] card += [ len(I) ] # Eliminate duplicate cardinalities and make staircase plot. res2, card2 = [], [] for c in range(m+1): r = [ res[k] for k in range(len(res)) if card[k] == c ] if r: res2 += [ min(r), min(r) ] card2 += [ c, c+1 ] # if pylab_installed: # pylab.figure(1, facecolor='w') # pylab.plot( res2[::2], card2[::2], 'o') # pylab.plot( res2, card2, '-') # pylab.xlabel('||A*x-b||_2') # pylab.ylabel('card(x)') # pylab.title('Sparse regressor selection (fig 6.7)') # print("Close figure to start exhaustive search.") # pylab.show() # Exhaustive search. def patterns(k,n): """ Generates all 0-1 sequences of length n with exactly k nonzeros. """ if k==0: yield n*[0] else: for x in patterns(k-1,n-1): yield [1] + x if k <= n-1: for x in patterns(k,n-1): yield [0] + x bestx = matrix(0.0, (n, m)) # best solution for each cardinality bestres = matrix(blas.nrm2(b), (1, m+1)) # best residual x = matrix(0.0, (n,1)) for k in range(1,m): for s in patterns(k,n): I = [ i for i in range(n) if s[i] ] st = "" for i in s: st += str(i) print("%d nonzeros: " %k + st) x = +b lapack.gels(A[:,I], x) res = blas.nrm2(b - A[:,I] * x[:k]) if res < bestres[k]: bestres[k] = res bestx[:,k][I] = x[:k] bestres[m] = 0.0 if pylab_installed: pylab.figure(1, facecolor='w') # heuristic result pylab.plot( res2[::2], card2[::2], 'o' ) pylab.plot( res2, card2, '-') # exhaustive result res2, card2 = [ bestres[0] ], [ 0 ] for k in range(1,m+1): res2 += [bestres[k-1], bestres[k]] card2 += [ k, k] pylab.plot( bestres.T, range(m+1), 'go') pylab.plot( res2, card2, 'g-') pylab.xlabel('||A*x-b||_2') pylab.ylabel('card(x)') pylab.title('Sparse regressor selection (fig 6.7)') pylab.show() cvxopt-1.1.4/examples/book/chap6/cvxfit.py0000644000175000017500000000267311674452555017542 0ustar sonnesonne# Figure 6.24, page 339. # Least-squares fit of a convex function. from cvxopt import solvers, matrix, spmatrix, mul from pickle import load #solvers.options['show_progress'] = 0 data = load(open('cvxfit.bin','rb')) u, y = data['u'], data['y'] m = len(u) # minimize (1/2) * || yhat - y ||_2^2 # subject to yhat[j] >= yhat[i] + g[i]' * (u[j] - u[i]), j, i = 0,...,m-1 # # Variables yhat (m), g (m). nvars = 2*m P = spmatrix(1.0, range(m), range(m), (nvars, nvars)) q = matrix(0.0, (nvars,1)) q[:m] = -y # m blocks (i = 0,...,m-1) of linear inequalities # # yhat[i] + g[i]' * (u[j] - u[i]) <= yhat[j], j = 0,...,m-1. G = spmatrix([],[],[], (m**2, nvars)) I = spmatrix(1.0, range(m), range(m)) for i in range(m): # coefficients of yhat[i] G[list(range(i*m, (i+1)*m)), i] = 1.0 # coefficients of g[i] G[list(range(i*m, (i+1)*m)), m+i] = u - u[i] # coefficients of yhat[j] G[list(range(i*m, (i+1)*m)), list(range(m))] -= I h = matrix(0.0, (m**2,1)) sol = solvers.qp(P, q, G, h) yhat = sol['x'][:m] g = sol['x'][m:] nopts = 1000 ts = [ 2.2/nopts * t for t in range(1000) ] f = [ max(yhat + mul(g, t-u)) for t in ts ] try: import pylab except ImportError: pass else: pylab.figure(1, facecolor='w') pylab.plot(u, y, 'wo', markeredgecolor='b') pylab.plot(ts, f, '-g') pylab.axis([-0.1, 2.3, -1.1, 7.2]) pylab.axis('off') pylab.title('Least-squares fit of convex function (fig. 6.24)') pylab.show() cvxopt-1.1.4/examples/book/chap6/basispursuit.py0000644000175000017500000001571411674452555020774 0ustar sonnesonne# Figures 6.21-23, pages 335-337. # Basis pursuit. from cvxopt import matrix, mul, div, cos, sin, exp, sqrt from cvxopt import blas, lapack, solvers try: import pylab except ImportError: pylab_installed = False else: pylab_installed = True # Basis functions are Gabor pulses: for k = 0,...,K-1, # # exp(-(t - k * tau)^2/sigma^2 ) * cos (l*omega0*t), l = 0,...,L # exp(-(t - k * tau)^2/sigma^2 ) * sin (l*omega0*t), l = 1,...,L sigma = 0.05 tau = 0.002 omega0 = 5.0 K = 501 L = 30 N = 501 # number of samples of each signal in [0,1] # Build dictionary matrix ts = (1.0/N) * matrix(range(N), tc='d') B = ts[:, K*[0]] - tau * matrix(range(K), (1,K), 'd')[N*[0],:] B = exp(-(B/sigma)**2) A = matrix(0.0, (N, K*(2*L+1))) # First K columns are DC pulses for k = 0,...,K-1 A[:,:K] = B for l in range(L): # Cosine pulses for omega = (l+1)*omega0 and k = 0,...,K-1. A[:, K+l*(2*K) : K+l*(2*K)+K] = mul(B, cos((l+1)*omega0*ts)[:, K*[0]]) # Sine pulses for omega = (l+1)*omega0 and k = 0,...,K-1. A[:, K+l*(2*K)+K : K+(l+1)*(2*K)] = \ mul(B, sin((l+1)*omega0*ts)[:,K*[0]]) if pylab_installed: pylab.figure(1, facecolor='w') pylab.subplot(311) # DC pulse for k = 250 (tau = 0.5) pylab.plot(ts, A[:,250]) pylab.ylabel('f(0.5, 0, c)') pylab.axis([0, 1, -1, 1]) pylab.title('Three basis elements (fig. 6.21)') # Cosine pulse for k = 250 (tau = 0.5) and l = 15 (omega = 75) pylab.subplot(312) pylab.ylabel('f(0.5, 75, c)') pylab.plot(ts, A[:, K + 14*(2*K) + 250]) pylab.axis([0, 1, -1, 1]) pylab.subplot(313) # Cosine pulse for k = 250 (tau = 0.5) and l = 30 (omega = 150) pylab.plot(ts, A[:, K + 29*(2*K) + 250]) pylab.ylabel('f(0.5, 150, c)') pylab.axis([0, 1, -1, 1]) pylab.xlabel('t') # Signal. y = mul( 1.0 + 0.5 * sin(11*ts), sin(30 * sin(5*ts))) # Basis pursuit problem # # minimize ||A*x - y||_2^2 + ||x||_1 # # minimize x'*A'*A*x - 2.0*y'*A*x + 1'*u # subject to -u <= x <= u # # Variables x (n), u (n). m, n = A.size r = matrix(0.0, (m,1)) q = matrix(1.0, (2*n,1)) blas.gemv(A, y, q, alpha = -2.0, trans = 'T') def P(u, v, alpha = 1.0, beta = 0.0): """ Function and gradient evaluation of v := alpha * 2*A'*A * u + beta * v """ blas.gemv(A, u, r) blas.gemv(A, r, v, alpha = 2.0*alpha, beta = beta, trans = 'T') def G(u, v, alpha = 1.0, beta = 0.0, trans = 'N'): """ v := alpha*[I, -I; -I, -I] * u + beta * v (trans = 'N' or 'T') """ blas.scal(beta, v) blas.axpy(u, v, n = n, alpha = alpha) blas.axpy(u, v, n = n, alpha = -alpha, offsetx = n) blas.axpy(u, v, n = n, alpha = -alpha, offsety = n) blas.axpy(u, v, n = n, alpha = -alpha, offsetx = n, offsety = n) h = matrix(0.0, (2*n,1)) # Customized solver for the KKT system # # [ 2.0*A'*A 0 I -I ] [x[:n] ] [bx[:n] ] # [ 0 0 -I -I ] [x[n:] ] = [bx[n:] ]. # [ I -I -D1^-1 0 ] [z[:n] ] [bz[:n] ] # [ -I -I 0 -D2^-1 ] [z[n:] ] [bz[n:] ] # # where D1 = W['di'][:n]**2, D2 = W['di'][:n]**2. # # We first eliminate z and x[n:]: # # ( 2*A'*A + 4*D1*D2*(D1+D2)^-1 ) * x[:n] = # bx[:n] - (D2-D1)*(D1+D2)^-1 * bx[n:] # + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bz[:n] # - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bz[n:] # # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bz[:n] - D2*bz[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] # # z[:n] = D1 * ( x[:n] - x[n:] - bz[:n] ) # z[n:] = D2 * (-x[:n] - x[n:] - bz[n:] ). # # # The first equation has the form # # (A'*A + D)*x[:n] = rhs # # and is equivalent to # # [ D A' ] [ x:n] ] = [ rhs ] # [ A -I ] [ v ] [ 0 ]. # # It can be solved as # # ( A*D^-1*A' + I ) * v = A * D^-1 * rhs # x[:n] = D^-1 * ( rhs - A'*v ). S = matrix(0.0, (m,m)) Asc = matrix(0.0, (m,n)) v = matrix(0.0, (m,1)) def Fkkt(W): # Factor # # S = A*D^-1*A' + I # # where D = 2*D1*D2*(D1+D2)^-1, D1 = d[:n]**2, D2 = d[n:]**2. d1, d2 = W['di'][:n]**2, W['di'][n:]**2 # ds is square root of diagonal of D ds = sqrt(2.0) * div( mul( W['di'][:n], W['di'][n:]), sqrt(d1+d2) ) d3 = div(d2 - d1, d1 + d2) # Asc = A*diag(d)^-1/2 blas.copy(A, Asc) for k in range(m): blas.tbsv(ds, Asc, n=n, k=0, ldA=1, incx=m, offsetx=k) # S = I + A * D^-1 * A' blas.syrk(Asc, S) S[::m+1] += 1.0 lapack.potrf(S) def g(x, y, z): x[:n] = 0.5 * ( x[:n] - mul(d3, x[n:]) + \ mul(d1, z[:n] + mul(d3, z[:n])) - \ mul(d2, z[n:] - mul(d3, z[n:])) ) x[:n] = div( x[:n], ds) # Solve # # S * v = 0.5 * A * D^-1 * ( bx[:n] # - (D2-D1)*(D1+D2)^-1 * bx[n:] # + D1 * ( I + (D2-D1)*(D1+D2)^-1 ) * bz[:n] # - D2 * ( I - (D2-D1)*(D1+D2)^-1 ) * bz[n:] ) blas.gemv(Asc, x, v) lapack.potrs(S, v) # x[:n] = D^-1 * ( rhs - A'*v ). blas.gemv(Asc, v, x, alpha=-1.0, beta=1.0, trans='T') x[:n] = div(x[:n], ds) # x[n:] = (D1+D2)^-1 * ( bx[n:] - D1*bz[:n] - D2*bz[n:] ) # - (D2-D1)*(D1+D2)^-1 * x[:n] x[n:] = div( x[n:] - mul(d1, z[:n]) - mul(d2, z[n:]), d1+d2 )\ - mul( d3, x[:n] ) # z[:n] = D1^1/2 * ( x[:n] - x[n:] - bz[:n] ) # z[n:] = D2^1/2 * ( -x[:n] - x[n:] - bz[n:] ). z[:n] = mul( W['di'][:n], x[:n] - x[n:] - z[:n] ) z[n:] = mul( W['di'][n:], -x[:n] - x[n:] - z[n:] ) return g x = solvers.coneqp(P, q, G, h, kktsolver = Fkkt)['x'][:n] I = [ k for k in range(n) if abs(x[k]) > 1e-2 ] xls = +y lapack.gels(A[:,I], xls) ybp = A[:,I]*xls[:len(I)] print("Sparse basis contains %d basis functions." %len(I)) print("Relative RMS error = %.1e." %(blas.nrm2(ybp-y) / blas.nrm2(y))) if pylab_installed: pylab.figure(2, facecolor='w') pylab.subplot(211) pylab.plot(ts, y, '-', ts, ybp, 'r--') pylab.xlabel('t') pylab.ylabel('y(t), yhat(t)') pylab.axis([0, 1, -1.5, 1.5]) pylab.title('Signal and basis pursuit approximation (fig. 6.22)') pylab.subplot(212) pylab.plot(ts, y-ybp, '-') pylab.xlabel('t') pylab.ylabel('y(t)-yhat(t)') pylab.axis([0, 1, -0.05, 0.05]) pylab.figure(3, facecolor='w') pylab.subplot(211) pylab.plot(ts, y, '-') pylab.xlabel('t') pylab.ylabel('y(t)') pylab.axis([0, 1, -1.5, 1.5]) pylab.title('Signal and time-frequency plot (fig. 6.23)') pylab.subplot(212) omegas, taus = [], [] for i in I: if i < K: omegas += [0.0] taus += [i*tau] else: l = (i-K)/(2*K)+1 k = ((i-K)%(2*K)) %K omegas += [l*omega0] taus += [k*tau] pylab.plot(ts, 150*abs(cos(5.0*ts)), '-', taus, omegas, 'ro') pylab.xlabel('t') pylab.ylabel('omega(t)') pylab.axis([0, 1, -5, 155]) pylab.show() cvxopt-1.1.4/examples/book/chap6/robls.py0000644000175000017500000001044611674452555017355 0ustar sonnesonne# Figures 6.15 and 6.16, pages 320 and 325. # Stochastic and worst-case robust approximation. from math import pi from cvxopt import blas, lapack, solvers from cvxopt import matrix, spmatrix, mul, cos, sin, sqrt, uniform from pickle import load #solvers.options['show_progress'] = 0 try: import pylab, numpy except ImportError: pylab_installed = False else: pylab_installed = True def wcls(A, Ap, b): """ Solves the robust least squares problem minimize sup_{||u||<= 1} || (A + sum_k u[k]*Ap[k])*x - b ||_2^2. A is mxn. Ap is a list of mxn matrices. b is mx1. """ (m, n), p = A.size, len(Ap) # minimize t + v # subject to [ I * * ] # [ P(x)' v*I -* ] >= 0. # [ (A*x-b)' 0 t ] # # where P(x) = [Ap[0]*x, Ap[1]*x, ..., Ap[p-1]*x]. # # Variables x (n), v (1), t(1). novars = n + 2 M = m + p + 1 c = matrix( n*[0.0] + 2*[1.0]) Fs = [spmatrix([],[],[], (M**2, novars))] for k in range(n): # coefficient of x[k] S = spmatrix([], [], [], (M, M)) for j in range(p): S[m+j, :m] = -Ap[j][:,k].T S[-1, :m ] = -A[:,k].T Fs[0][:,k] = S[:] # coefficient of v Fs[0][(M+1)*m : (M+1)*(m+p) : M+1, -2] = -1.0 # coefficient of t Fs[0][-1, -1] = -1.0 hs = [matrix(0.0, (M, M))] hs[0][:(M+1)*m:M+1] = 1.0 hs[0][-1, :m] = -b.T return solvers.sdp(c, None, None, Fs, hs)['x'][:n] # Figure 6.15 data = load(open('robls.bin','rb'))['6.15'] A, b, B = data['A'], data['b'], data['B'] m, n = A.size # Nominal problem: minimize || A*x - b ||_2 xnom = +b lapack.gels(+A, xnom) xnom = xnom[:n] # Stochastic problem. # # minimize E || (A+u*B) * x - b ||_2^2 # = || A*x - b||_2^2 + x'*P*x # # with P = E(u^2) * B'*B = (1/3) * B'*B S = A.T * A + (1.0/3.0) * B.T * B xstoch = A.T * b lapack.posv(S, xstoch) # Worst case approximation. # # minimize max_{-1 <= u <= 1} ||A*u - b||_2^2. xwc = wcls(A, [B], b) nopts = 500 us = -2.0 + (2.0 - (-2.0))/(nopts-1) * matrix(list(range(nopts)),tc='d') rnom = [ blas.nrm2( (A+u*B)*xnom - b) for u in us ] rstoch = [ blas.nrm2( (A+u*B)*xstoch - b) for u in us ] rwc = [ blas.nrm2( (A+u*B)*xwc - b) for u in us ] if pylab_installed: pylab.figure(1, facecolor='w') pylab.plot(us, rnom, us, rstoch, us, rwc) pylab.plot([-1, -1], [0, 12], '--k', [1, 1], [0, 12], '--k') pylab.axis([-2.0, 2.0, 0.0, 12.0]) pylab.xlabel('u') pylab.ylabel('r(u)') pylab.text(us[9], rnom[9], 'nominal') pylab.text(us[9], rstoch[9], 'stochastic') pylab.text(us[9], rwc[9], 'worst case') pylab.title('Robust least-squares (fig.6.15)') # Figure 6.16 data = load(open('robls.bin','rb'))['6.16'] A, Ap, b = data['A0'], [data['A1'], data['A2']], data['b'] (m, n), p = A.size, len(Ap) # least squares solution: minimize || A*x - b ||_2^2 xls = +b lapack.gels(+A, xls) xls = xls[:n] # Tikhonov solution: minimize || A*x - b ||_2^2 + 0.1*||x||^2_2 xtik = A.T*b S = A.T*A S[::n+1] += 0.1 lapack.posv(S, xtik) # Worst case solution xwc = wcls(A, Ap, b) notrials = 100000 r = sqrt(uniform(1,notrials)) theta = 2.0 * pi * uniform(1,notrials) u = matrix(0.0, (2,notrials)) u[0,:] = mul(r, cos(theta)) u[1,:] = mul(r, sin(theta)) # LS solution q = A*xls - b P = matrix(0.0, (m,2)) P[:,0], P[:,1] = Ap[0]*xls, Ap[1]*xls r = P*u + q[:,notrials*[0]] resls = sqrt( matrix(1.0, (1,m)) * mul(r,r) ) q = A*xtik - b P[:,0], P[:,1] = Ap[0]*xtik, Ap[1]*xtik r = P*u + q[:,notrials*[0]] restik = sqrt( matrix(1.0, (1,m)) * mul(r,r) ) q = A*xwc - b P[:,0], P[:,1] = Ap[0]*xwc, Ap[1]*xwc r = P*u + q[:,notrials*[0]] reswc = sqrt( matrix(1.0, (1,m)) * mul(r,r) ) if pylab_installed: pylab.figure(2, facecolor='w') pylab.hist(list(resls), numpy.array([0.1*k for k in range(50)]), fc='w', normed=True) pylab.text(4.4, 0.4, 'least-squares') pylab.hist(list(restik), numpy.array([0.1*k for k in range(50)]), fc='#D0D0D0', normed=True) pylab.text(2.9, 0.75, 'Tikhonov') pylab.hist(list(reswc), numpy.array([0.1*k for k in range(50)]), fc='#B0B0B0', normed=True) pylab.text(2.5, 2.0, 'robust least-squares') pylab.xlabel('residual') pylab.ylabel('frequency/binwidth') pylab.axis([0, 5, 0, 2.5]) pylab.title('LS, Tikhonov and robust LS solutions (fig. 6.16)') pylab.show()