pysparse-1.1.1/0000755010116400000240000000000011402271053012347 5ustar wd15dialoutpysparse-1.1.1/Doc/0000755010116400000240000000000011402271037013056 5ustar wd15dialoutpysparse-1.1.1/Doc/Pysparse.pdf0000644010116400000240000131530611402270335015370 0ustar wd15dialout%PDF-1.4 % 5 0 obj << /S /GoTo /D (chapter.1) >> endobj 8 0 obj (Introduction to Pysparse) endobj 9 0 obj << /S /GoTo /D (section.1.1) >> endobj 12 0 obj (Module Overview) endobj 13 0 obj << /S /GoTo /D (section.1.2) >> endobj 16 0 obj (Prerequisites) endobj 17 0 obj << /S /GoTo /D (section.1.3) >> endobj 20 0 obj (Installing Pysparse) endobj 21 0 obj << /S /GoTo /D (section.1.4) >> endobj 24 0 obj (Testing Pysparse) endobj 25 0 obj << /S /GoTo /D (section.1.5) >> endobj 28 0 obj (Generating the Documentation) endobj 29 0 obj << /S /GoTo /D (chapter.2) >> endobj 32 0 obj (Sparse Matrix Formats) endobj 33 0 obj << /S /GoTo /D (section.2.1) >> endobj 36 0 obj (Linked-List Format) endobj 37 0 obj << /S /GoTo /D (section.2.2) >> endobj 40 0 obj (Compressed Sparse Row Format) endobj 41 0 obj << /S /GoTo /D (section.2.3) >> endobj 44 0 obj (Sparse Skyline Format) endobj 45 0 obj << /S /GoTo /D (chapter.3) >> endobj 48 0 obj (Low-Level Sparse Matrix Types) endobj 49 0 obj << /S /GoTo /D (section.3.1) >> endobj 52 0 obj (The spmatrix Module) endobj 53 0 obj << /S /GoTo /D (section.3.2) >> endobj 56 0 obj (Example: 2D-Poisson matrix) endobj 57 0 obj << /S /GoTo /D (section.3.3) >> endobj 60 0 obj (Vectorization) endobj 61 0 obj << /S /GoTo /D (section.3.4) >> endobj 64 0 obj (Matlab Implementation) endobj 65 0 obj << /S /GoTo /D (section.3.5) >> endobj 68 0 obj (Comparison with Matlab) endobj 69 0 obj << /S /GoTo /D (chapter.4) >> endobj 72 0 obj (Preconditioners) endobj 73 0 obj << /S /GoTo /D (section.4.1) >> endobj 76 0 obj (The precon Module) endobj 77 0 obj << /S /GoTo /D (chapter.5) >> endobj 80 0 obj (Iterative Solvers) endobj 81 0 obj << /S /GoTo /D (section.5.1) >> endobj 84 0 obj (The itsolvers Module) endobj 85 0 obj << /S /GoTo /D (chapter.6) >> endobj 88 0 obj (Direct Solvers) endobj 89 0 obj << /S /GoTo /D (section.6.1) >> endobj 92 0 obj (The Low-Level C Modules) endobj 93 0 obj << /S /GoTo /D (section.6.2) >> endobj 96 0 obj (Higher-Level Python Interfaces) endobj 97 0 obj << /S /GoTo /D (chapter.7) >> endobj 100 0 obj (Eigenvalue Solver) endobj 101 0 obj << /S /GoTo /D (section.7.1) >> endobj 104 0 obj (The jdsym Module) endobj 105 0 obj << /S /GoTo /D (chapter.8) >> endobj 108 0 obj (Higher-Level Sparse Matrix Classes) endobj 109 0 obj << /S /GoTo /D (section.8.1) >> endobj 112 0 obj (The pysparseMatrix module) endobj 113 0 obj << /S /GoTo /D (chapter.9) >> endobj 116 0 obj (Other Sparse Matrix Packages for Python) endobj 117 0 obj << /S /GoTo /D (chapter.10) >> endobj 120 0 obj (License) endobj 121 0 obj << /S /GoTo /D (chapter.11) >> endobj 124 0 obj (TODO List) endobj 125 0 obj << /S /GoTo /D (chapter.12) >> endobj 128 0 obj (Indices and Tables) endobj 129 0 obj << /S /GoTo /D (chapter*.11) >> endobj 132 0 obj (Bibliography) endobj 133 0 obj << /S /GoTo /D (section*.12) >> endobj 136 0 obj (Module Index) endobj 137 0 obj << /S /GoTo /D (section*.13) >> endobj 140 0 obj (Index) endobj 141 0 obj << /S /GoTo /D [142 0 R /Fit ] >> endobj 145 0 obj << /Length 331 /Filter /FlateDecode >> stream xڽPO0~_q[JkՠD*,M{sEPM}?raP^Zᰬ"׈3mpjCje{"dB5S -> endobj 143 0 obj << /Type /XObject /Subtype /Image /Width 80 /Height 80 /BitsPerComponent 8 /ColorSpace /DeviceRGB /SMask 152 0 R /Length 760 /Filter /FlateDecode >> stream xڿK`;::U?ANԮZЭE( j x A[/@p~|7imWf4MkZTh4Y0 퍍/]R4==ͪRUFo"XVBrXNSed띘xX / / gպn{kkkǃZZttdR3MjYӹ ,..^\\Xfx|-ˮVKKKZUա!FG.5u=ph4*UշWbzY===|B!7{?^x^x^x}Ka:<833c> stream x _pfi endstream endobj 146 0 obj << /D [142 0 R /XYZ 72 744.907 null] >> endobj 147 0 obj << /D [142 0 R /XYZ 72 720 null] >> endobj 144 0 obj << /Font << /F28 148 0 R /F29 149 0 R /F31 150 0 R >> /XObject << /Im1 143 0 R >> /ProcSet [ /PDF /Text /ImageC ] >> endobj 155 0 obj << /Length 19 /Filter /FlateDecode >> stream x3PHW0Pp2Ac( endstream endobj 154 0 obj << /Type /Page /Contents 155 0 R /Resources 153 0 R /MediaBox [0 0 612 792] /Parent 151 0 R >> endobj 156 0 obj << /D [154 0 R /XYZ 72 744.907 null] >> endobj 153 0 obj << /ProcSet [ /PDF ] >> endobj 190 0 obj << /Length 1214 /Filter /FlateDecode >> stream xZ][FϯKG/ukMF&_6@Zn$!8pΜh'?}` )_ @Kp}}_'P/$fflJ<#c{H#|9E҉w,# :Y\ngm,('>4r(һ@6 TP0S c>?NMi+]sv">.fC OJ̅ Uj1[w ,*D+0؂8Ktޅi}NAFퟄ%PDiVatK#.<dH-sW@GٳrƙW@2 䱎t|1m0^ܭuEGoCz $Bڦ Q_=6!Q:/'[i%:ҝ~K ,pat"KoYUuDGux=@2kuozYBIqiQ#:P,&479_a\s-ܩJåO\D/u՝ 3IXC]-;Ʃ4 a^2Nᚙ4LDe]fHV2mQBkp"}n%^FG2AGV=nˊ< &xU~}ldfVڎR&({\fC)$2$< Ff=ɨAF cQд\ʣ4.4mӺy?L55u5։ cv]yeι`EQB1`qKXi8 tR۬]_T"U0ѫ]Lۼ6~UgmRG娕">k MZġhV/GO-J'E=[rs+TPLCțtTgYƝܛ&2,\~L(rhMӇ`yBGMʷl;B Ts̳3;Oߴ$G 2!@@` Kc^8h (78VtU1gmio>d endstream endobj 189 0 obj << /Type /Page /Contents 190 0 R /Resources 188 0 R /MediaBox [0 0 612 792] /Parent 151 0 R /Annots [ 157 0 R 158 0 R 159 0 R 160 0 R 161 0 R 162 0 R 163 0 R 164 0 R 165 0 R 166 0 R 167 0 R 168 0 R 169 0 R 170 0 R 171 0 R 172 0 R 173 0 R 174 0 R 175 0 R 176 0 R 177 0 R 178 0 R 179 0 R 180 0 R 181 0 R 182 0 R 183 0 R 184 0 R 185 0 R 186 0 R ] >> endobj 157 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 525.699 193.473 536.578] /Subtype /Link /A << /S /GoTo /D (chapter.1) >> >> endobj 158 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 515.666 186.211 524.513] /Subtype /Link /A << /S /GoTo /D (section.1.1) >> >> endobj 159 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 501.654 165.309 512.558] /Subtype /Link /A << /S /GoTo /D (section.1.2) >> >> endobj 160 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 489.699 189.389 500.603] /Subtype /Link /A << /S /GoTo /D (section.1.3) >> >> endobj 161 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 477.744 180.941 488.647] /Subtype /Link /A << /S /GoTo /D (section.1.4) >> >> endobj 162 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 465.788 236.691 476.692] /Subtype /Link /A << /S /GoTo /D (section.1.5) >> >> endobj 163 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 444.005 187.297 454.884] /Subtype /Link /A << /S /GoTo /D (chapter.2) >> >> endobj 164 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 433.973 191.91 442.819] /Subtype /Link /A << /S /GoTo /D (section.2.1) >> >> endobj 165 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 419.96 244.333 430.864] /Subtype /Link /A << /S /GoTo /D (section.2.2) >> >> endobj 166 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 408.005 204.313 418.909] /Subtype /Link /A << /S /GoTo /D (section.2.3) >> >> endobj 167 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 386.222 223.829 397.101] /Subtype /Link /A << /S /GoTo /D (chapter.3) >> >> endobj 168 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 374.755 213.13 385.036] /Subtype /Link /A << /S /GoTo /D (section.3.1) >> >> endobj 169 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 362.177 230.116 373.081] /Subtype /Link /A << /S /GoTo /D (section.3.2) >> >> endobj 170 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 352.279 166.963 361.126] /Subtype /Link /A << /S /GoTo /D (section.3.3) >> >> endobj 171 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 338.267 207.65 349.171] /Subtype /Link /A << /S /GoTo /D (section.3.4) >> >> endobj 172 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 326.311 213.468 337.215] /Subtype /Link /A << /S /GoTo /D (section.3.5) >> >> endobj 173 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 306.431 155.277 315.407] /Subtype /Link /A << /S /GoTo /D (chapter.4) >> >> endobj 174 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 293.061 201.175 303.342] /Subtype /Link /A << /S /GoTo /D (section.4.1) >> >> endobj 175 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 272.558 157.638 281.534] /Subtype /Link /A << /S /GoTo /D (chapter.5) >> >> endobj 176 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 260.568 219.108 269.469] /Subtype /Link /A << /S /GoTo /D (section.5.1) >> >> endobj 177 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 238.685 147.695 247.661] /Subtype /Link /A << /S /GoTo /D (chapter.6) >> >> endobj 178 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 226.63 221.937 235.596] /Subtype /Link /A << /S /GoTo /D (section.6.1) >> >> endobj 179 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 212.737 239.302 223.641] /Subtype /Link /A << /S /GoTo /D (section.6.2) >> >> endobj 180 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 190.954 164.004 201.833] /Subtype /Link /A << /S /GoTo /D (chapter.7) >> >> endobj 181 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 179.487 195.198 189.768] /Subtype /Link /A << /S /GoTo /D (section.7.1) >> >> endobj 182 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 157.081 240.895 167.96] /Subtype /Link /A << /S /GoTo /D (chapter.8) >> >> endobj 183 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [85.948 145.614 247.89 155.895] /Subtype /Link /A << /S /GoTo /D (section.8.1) >> >> endobj 184 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 123.208 266.619 134.087] /Subtype /Link /A << /S /GoTo /D (chapter.9) >> >> endobj 185 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 103.193 120.039 112.169] /Subtype /Link /A << /S /GoTo /D (chapter.10) >> >> endobj 186 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 81.275 136.199 90.252] /Subtype /Link /A << /S /GoTo /D (chapter.11) >> >> endobj 191 0 obj << /D [189 0 R /XYZ 72 550.325 null] >> endobj 188 0 obj << /Font << /F28 148 0 R /F44 192 0 R /F31 150 0 R /F46 193 0 R >> /ProcSet [ /PDF /Text ] >> endobj 199 0 obj << /Length 245 /Filter /FlateDecode >> stream xڭOK1s=lkAjnmՊ޴BJA/0/K2K@ <֪*g`_ͻqqx `,B0F#VKݰƪ[Rs͇,;(XL4\&+(͇Ynǚtq&}o~4U =/xKVJLg1';w?er^ܖA`w<%ZJ?iSh endstream endobj 198 0 obj << /Type /Page /Contents 199 0 R /Resources 197 0 R /MediaBox [0 0 612 792] /Parent 151 0 R /Annots [ 187 0 R 194 0 R 195 0 R 196 0 R ] >> endobj 187 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 708.922 166.744 717.898] /Subtype /Link /A << /S /GoTo /D (chapter.12) >> >> endobj 194 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 685.101 128.767 695.98] /Subtype /Link /A << /S /GoTo /D (chapter*.11) >> >> endobj 195 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 665.086 132.502 674.062] /Subtype /Link /A << /S /GoTo /D (section*.12) >> >> endobj 196 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 643.168 97.355 652.144] /Subtype /Link /A << /S /GoTo /D (section*.13) >> >> endobj 197 0 obj << /Font << /F44 192 0 R /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 202 0 obj << /Length 274 /Filter /FlateDecode >> stream xڍQn@ WH`gT`oC҇DTU K*jՓ-kf> endobj 203 0 obj << /D [201 0 R /XYZ 72 744.907 null] >> endobj 200 0 obj << /Font << /F28 148 0 R /F44 192 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 206 0 obj << /Length 198 /Filter /FlateDecode >> stream xڍ;o@SlݹH> endobj 207 0 obj << /D [205 0 R /XYZ 72 744.907 null] >> endobj 204 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 213 0 obj << /Length 2296 /Filter /FlateDecode >> stream xڵv8z/BcIc%$dq ~P E>sP}<^xp'N=ɪxNo%I<?$9~Yp'Lt}&P <rg-$ =A^"휸0}/qgQqcR F1]v% ̡>5$ $eolp` P kZ| ,jGݩʂWMM A~EziI>z&͚F:fs}K#TFSޫ5,MQ }nN02ljw?^ݬ>G c >'|$ȵaW5^2䅆 L-g4<`oea/\shj߯~ݷ \ǎfo>YjTu4z\ UZL;Tن=0#~1-I},5FUe4(ϊfdí_ĮsnnأUwDU7KgzÿKDAV駢i)6ވ_D f!122d֨OnK"JCBJ \΁E$ iX _,*+fXa\WIHs?olƩǸ@P\ҍ eʘ-#8s}u+cTy\?` =ăRH<4 R Al ^,5Tn 3 (K/p>++b)B5N/!횾M, n0+tZ{zz[ekV)~ _֓"v봂TLϸ 3BOzv\;;g|}"Ssb|b?&>9iiYRJ}/t]у|eo6DrTDIZiK&1*ǡ ҋEri8l`HQNWc"W/8lѨ.W!"--KXġe$K8=od7,MΕc&8mpnUk`-LC-*0~4Y8Gk@;<29D-YwXEiO *030Bc%BN<؍jXAB{*rZ(-LG};@ާ{O k ;c@3aJwBڔ|E'CnAKc ¨['DN/=J C(RUiLʒo S bgק:.eW"DXԜΆ㵐KqHI…VYd6toGd^ ``m HgtT8ijwO<k;aI*3hgAv=Q6?P"5,ݛl0Um?W~xb4Ѓp]Cv|dAz0w|;-y>g!7HT4̆bcM!@>ո&]׳ց`%/E}=,WoH3\d n!V׺kl`"Ƚaࢴ#}`/!Pi4[`` ,؝XD*},M& G `dR&FtM)Qg@{*X [t4e&C@`Qh {;|?p=4CV,5vz29Db?;' JI_;'MOv)ؗSȒ;/>R Y}oa\j;-N(Ɋɋ-"^"9b%#ɫ(0oZ3s<$\)jq,(^BdOp񮯳@I3o5[pۄlh*}^X(Mb.όe DM${ I2 h\_E endstream endobj 212 0 obj << /Type /Page /Contents 213 0 R /Resources 211 0 R /MediaBox [0 0 612 792] /Parent 219 0 R /Annots [ 208 0 R 209 0 R 210 0 R ] >> endobj 208 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [132.362 364.034 164.801 374.937] /Subtype/Link/A<> >> endobj 209 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [192.685 233.941 286.551 244.845] /Subtype /Link /A << /S /GoTo /D (formats-page) >> >> endobj 210 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [359.56 186.12 446.232 197.024] /Subtype/Link/A<> >> endobj 214 0 obj << /D [212 0 R /XYZ 72 744.907 null] >> endobj 6 0 obj << /D [212 0 R /XYZ 72 720 null] >> endobj 10 0 obj << /D [212 0 R /XYZ 72 338.179 null] >> endobj 215 0 obj << /D [212 0 R /XYZ 72 301.49 null] >> endobj 218 0 obj << /D [212 0 R /XYZ 72 125.472 null] >> endobj 211 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F57 216 0 R /F46 193 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 226 0 obj << /Length 2526 /Filter /FlateDecode >> stream xڵYKwܶWRsHԻ<\6k;{.4FI__5F9M$>@|ݼxvwH6F"7A+6[/:EX/|dgjKjqw/-Ɲ?V]+jY?pɢ>[V;4CsRBFz,FswhW0yNN9N ]-^?uQ5PjG+_U ]ܣ<ݎ+>yD }j,Ff)=Gp?N$|h[*M֗#' z4Z\0,T `>Su_^G7NCԴr\O[;B?,PR bIj}>@S򬦗onXiIGEgЇIaR}r{g 'ȋs{CmRCjg&M8Qc$ϋ"uU & mVIzTpp)`#Ki&s5?eޛh!H/Ml{e'^v<oF\ffN#6^/uC'LYBQEy+?UCv_#oKR^'̣=%\(iF 0)On Lk}AFC]|9GLmdDEley.}G=>?I=x d$$٬`ŅNJVY1Ρu _|&0#ZsͰ+':{`{P]s졛#ӪgY"G @g$;i"s~%1 Hﯳ٩unoYCu6}N)m?4mwr^y;vYLd/D@gMiȧ{,7lYx=d$=/ot@a/oejf-=UWu2r h N==o w ?G)c+":Z{R?eM3!qKZJz})@×vOxfԥ$9eƢ}5#?xMv p:BnH/om>@` MM2mYuS( J*k@m7Att7+#ȔL r>к[ls)(`#F.C|mfK' ` ]} ;J$Ho0훗TXOyc}$Au1, H}TNw%ҦIDQzN7 4ך:qCD%ֽQ]㍂ Re<-;4ZJiFaSN4h PVgT_P@QEgFNW0ثJ}1}3q#sO '6/}k|-ŏTO> endobj 221 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [220.852 443.147 259.367 454.051] /Subtype/Link/A<> >> endobj 222 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [223.813 361.625 272.649 372.529] /Subtype/Link/A<> >> endobj 223 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [95.91 112.693 128.349 123.328] /Subtype/Link/A<> >> endobj 227 0 obj << /D [225 0 R /XYZ 72 744.907 null] >> endobj 228 0 obj << /D [225 0 R /XYZ 72 654.466 null] >> endobj 229 0 obj << /D [225 0 R /XYZ 72 487.817 null] >> endobj 230 0 obj << /D [225 0 R /XYZ 72 406.295 null] >> endobj 231 0 obj << /D [225 0 R /XYZ 72 247.373 null] >> endobj 14 0 obj << /D [225 0 R /XYZ 72 164.779 null] >> endobj 224 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F46 193 0 R /F57 216 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 234 0 obj << /Length 1312 /Filter /FlateDecode >> stream xYKs6W8 ,-mNwA#QȒTwI"'i)LvDF#~ \qKhhFTJMT~)ljjύMpyznE86e{FFp1%Kj!#S\O%DjRH5EZOi ~xS yn] ha@EAȽJb1_=8[k"BfSi'~k:񓻛; K5@y7<͆au-?BZ:hfs[nCE%"M-\S^nΓpEɓڞu&w{DkKjo^N۱0R4+ AŒf[ s|d^dNiq1q5'h]lۖ[m-n#)8 r*8 V" $UM]3Fmҷ%'( c"PJ&04n'!핼Bb1 -J2\63xCua(A ósO` }$/yLѢ\^{K?ܹb[<НY[laOgT!N[D>3/Uܖ7 2g`Zl` ̎A&KoHبc̒= 'Ky/$m9i@wXgA<;C!VP͜2tS< RG(A)?m&w(]@srU#I 縷h#?ܽhq8eb JQTYԦN÷ KӰt!mFtA:pemsѮFб48FuGb@qϢkqprV7iXJDZ ?>'H2E+Zyac YGaRP$tFƱ&Qi*97K'<.(q߯>z$a̢)-yxFjo* r,3X db01.$~zMJWlĻK׻K"}ᢰ$Wli1zw]oc~Ƕ}4́)xݱ1 ] dǦr#"5#WjQ@ [96j6{Uy^ tkEqjl[Qr!9r?y=ל|r9VF~G\ endstream endobj 233 0 obj << /Type /Page /Contents 234 0 R /Resources 232 0 R /MediaBox [0 0 612 792] /Parent 219 0 R >> endobj 235 0 obj << /D [233 0 R /XYZ 72 744.907 null] >> endobj 18 0 obj << /D [233 0 R /XYZ 72 720 null] >> endobj 22 0 obj << /D [233 0 R /XYZ 72 663.416 null] >> endobj 232 0 obj << /Font << /F28 148 0 R /F46 193 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 240 0 obj << /Length 1230 /Filter /FlateDecode >> stream xXKsFWpVy3ne+8r`d#P=$${m9T4~|>L~Of H*2isx‚y܄&m""VGS:ۮuե]QWJ:7>?N.擿',8dbzr9?Dv:RZד'{IN0@ I‚|9ء`(BD(y vc Գ'}M&dhyPr(4&@A$ 4M8s=%)> endobj 236 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [211.426 538.294 241.652 549.198] /Subtype/Link/A<> >> endobj 237 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [422.481 538.294 452.149 549.198] /Subtype/Link/A<> >> endobj 241 0 obj << /D [239 0 R /XYZ 72 744.907 null] >> endobj 26 0 obj << /D [239 0 R /XYZ 72 593.713 null] >> endobj 220 0 obj << /D [239 0 R /XYZ 72 330.112 null] >> endobj 238 0 obj << /Font << /F28 148 0 R /F46 193 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 244 0 obj << /Length 2372 /Filter /FlateDecode >> stream xY[o6~УȰ$%R߲AڦnHBжJ_<$u>\s!F/Xx%"Q+v0cDI]Rn}۫oY\rGiH&X$sNRDcn^o~.g)IRzhRF[I9.yiY~vΠeDe92r"UG|0J7o7[79o~vC7(F&RoY,ѭP$UXf{]UۘNt_v՝vsãvw}1lXU|{0cáU]GJ6$KwU-vqEˆhTe >I)h\4;l0p, ֲ$M2}HbVWgTwۺ4)˶?QA߿[(3㢩tڦ8AGJ /bOPQ]L'%nTP{ZM8B=97SjЪ1]ۘ" HᮃW]Hf)KFFq^LMǒ)hN<)w8JRa& eLm#o F!-o}A'y`~j;rIxRPreq]V$OQ3͞-</A{oVG ZLe|IeK'sKZWdʌd9 ”\5%9iC$aRl g"ؒG[}Hى AA:5qiTƖM pxbb3&>F޵&5 LIkDz- l@{^辣HnoStm;> l ,P)|$/P4+j-J !O>NwȕP@3 res,lȚAKʦת+;"PmY/:KJ:^/r+ұ~o ,T3wZ-S!R6#Nec8w߈a`>ta5U) X>I 8Zq$dAsɀkBEprć-SWOjLr2Vg^nS0jY L}pƺӏˈ{#׋gtI6sp$vH$\y8 +AY_I!d@nh;,Mާ0U{rAX_],2dm#K?|%0aͺW A(9Њ"S:@ 5_}㓹ҧhJXxjΈTrVWn{o 8J>?ݟ ̂dRLJ&?8VoG>򳆔]2}&m4%t;CzbM]tAqcwl{tɃ<+.E)P+/~DM셿$d"]0T endstream endobj 243 0 obj << /Type /Page /Contents 244 0 R /Resources 242 0 R /MediaBox [0 0 612 792] /Parent 219 0 R >> endobj 245 0 obj << /D [243 0 R /XYZ 72 744.907 null] >> endobj 30 0 obj << /D [243 0 R /XYZ 72 720 null] >> endobj 34 0 obj << /D [243 0 R /XYZ 72 420.588 null] >> endobj 242 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F46 193 0 R /F57 216 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 248 0 obj << /Length 1675 /Filter /FlateDecode >> stream xYIs6WHO#=6t3h pQU~}6iy$b{xg /I({''hhz3K""* YIU+CLD.>X]/,0H :g%/5ͧ&QyŔ~=H+JwMk3&+g% _p#1,vyRPD؆ٓmE^D؝aDȆ ^62<>$Hhƞ u9TF%X` ClV3ʝ!9es&,L2PJٗ?K\j(|$MhyҴփsrwEP}1yC uМ4nC&y'ELqWP"N.j~HD'7+odv % ,͙vf0>X6+INsoQ՛a)fGPw4h#,ΏO6 $s̜I%FvGlcybPjӥ-hozi}n, H{X_ ҵQ_81iZVv.IZgtMrꩈo!6Ump$Z'ڔSJ.p&iR KљLti2N:YNϭ2EezoUZ|f}>H]Ugh.KYk k7rxunP8ƮM=mWyVʧ6tX=EV+3CoWԁZiamօ2eX& m]x6:MhT7tt7Ǣ\2 8Up@֛,U%${!gH|\hB$( obfRom(}g<x ;gĩSyɸfg{/=\]x<>3g:jٰ)fV\7:|`''IcX0@0' BQ^Џ@}tsHron:M5MN##g~th;Q4yΡqw^=+P1" \ GD 9?WT&(}Rd1(k)+j&W~}V1mEZE6P2#0] =6 ) j߶SXF-T),٘i'͚4ʵdwcB)j=kr-t EVE-|kl'U$Z(tnOɱXE!R -mkI߮8Qz G46ʄV>>90O= m endstream endobj 247 0 obj << /Type /Page /Contents 248 0 R /Resources 246 0 R /MediaBox [0 0 612 792] /Parent 219 0 R >> endobj 249 0 obj << /D [247 0 R /XYZ 72 744.907 null] >> endobj 38 0 obj << /D [247 0 R /XYZ 72 720 null] >> endobj 42 0 obj << /D [247 0 R /XYZ 72 517.088 null] >> endobj 250 0 obj << /D [247 0 R /XYZ 72 276.457 null] >> endobj 251 0 obj << /D [247 0 R /XYZ 72 276.457 null] >> endobj 246 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F57 216 0 R /F46 193 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 257 0 obj << /Length 2778 /Filter /FlateDecode >> stream xZKsFWVyHUV7^I-'ȑ5`6gz$HQeFs_?`/."䋐Q^ YPzqmRGpxyw+-bkw 3)1'f!z}f/I"E +.^\_[ދ뻱tZE=W:.In('47|RKI߮.W-(zվ=M& 8_@W+-c#3%}zwۛrYvV`$bdm<YҬԚuTx'F6B e1Dj23uGxA_ xNqAJTq$FA-jP`S3NkH7_6lg^Wxk8%{kq]5ދ[Bziƚ):p!Gv7y4Ujj▦fH4=HCuݺWkdn/jS$6)ن;N)4cm9Nz gbyZ!5Cf%3d.haAOiĮ5u{<ɐZ?&A:)jdap؊6pq {$ܛ6cVhN@7)G Kr1"'PO6$$1]?v28n |*3ۚmQeopi3=;Zi˚ҵj\ qtވ+; G$`K8<#B8+8$8k]6=2gD<6nPPyF%zg$٤s$V &XΩ7tUcZrWE9Sy`aB:ź=YqPMb{r>, Jɮfۻ~ :Zє}#ؕ >;lnA x o<{ӚuX(+]חEMЂ}:@NJ9*O5qDD40\Cf9DLΉbyL\+^!-e x rب/D.E7EB:Ч*9UVߏ;% bQZׁZo4Km!chZF蓠E6.FkԞT}Phg0ѰC+_-n%hRI_#Pcwfm8Vau| j2.k k8R9֡9]SU-nhrm^ڶ폆baM\t8ů j"xmO` G\()PI_AdmCyz÷;Xm}*"i8hmmNA|NHa/w|!3jhؑ@P6HஂE:vgw?cbaCΗҡauM6Ͷ RҼu2[rJh38]׾/!,c;Qz1c%o4.dO\)nàā!ЁϨo}E Τ;2рnc?:ϩ/_wmLcJMWŶaRѺ2x7P(Hcr挈ǟ4srxR?uWfW5ϡ F|28|4B5C!'0]?1'b]6#w!swwUv3@lZ]: rt2D}r^Ztdždg?L? {~0|`*TKn,5Ṁg,s2ߓO|ڍ''> endobj 252 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [172.071 483.498 265.485 494.402] /Subtype /Link /A << /S /GoTo /D (formats-page) >> >> endobj 253 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [403.881 166.407 538.506 177.311] /Subtype/Link/A<> >> endobj 258 0 obj << /D [256 0 R /XYZ 72 744.907 null] >> endobj 46 0 obj << /D [256 0 R /XYZ 72 720 null] >> endobj 50 0 obj << /D [256 0 R /XYZ 72 562.518 null] >> endobj 259 0 obj << /D [256 0 R /XYZ 72 333.998 null] >> endobj 260 0 obj << /D [256 0 R /XYZ 72 305.921 null] >> endobj 263 0 obj << /D [256 0 R /XYZ 72 238.518 null] >> endobj 264 0 obj << /D [256 0 R /XYZ 72 196.983 null] >> endobj 265 0 obj << /D [256 0 R /XYZ 72 155.448 null] >> endobj 268 0 obj << /D [256 0 R /XYZ 72 113.914 null] >> endobj 255 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F46 193 0 R /F58 217 0 R /F11 261 0 R /F14 262 0 R /F65 266 0 R /F8 267 0 R /F66 269 0 R >> /ProcSet [ /PDF /Text ] >> endobj 273 0 obj << /Length 3077 /Filter /FlateDecode >> stream xko{~~\"Hvnq-\Pȶ+K>I\;=q;"93n&gpug|Ϯng&&fW!.ΫdA8K9ȗ}%q3@ )껋^]t`%9Sو@FζL / gn~f쇋^HƲ} HpY.DdnSRH/ <˗/ kxZXB{׸݌+I6u5G B`FH1uHL+Y&li$mG ~?B;'R"4 @A  SbYlES|SzC~⳾G QJ/^h9Dz\1$O8Q+ηR= G* dœCȳmEoRH4a@NhhgB}R' 5UD \U5(@5_%5+ bUDceϯ`ʄp5xSEfT\ÂkQntֈ#}(áM5/1!nqAumőUXԛKla; 8skgCo:Vk|Ez:d>c|hR_ы/ko@ݫdE0ht}IT(cC]mӅ~WZEjЯ2ie-s-˖aw7fGrJժyK"zD48rj 5(ynZS[: cL5cw |:C'OW9%?7\7t:/;(LjyȚ *U1abZB_;RƩEWtk$BO-fkLͿeztP 3F ]B#4IXIY!{`ZPwM=BcgK8 h,ۤLs [4CES 1I|aU2 v"79 )Ohuo\P@36ᮘ`6\W37c\6d;`h`QWq|IN6dIo O-Gq[{c@l. "3rڒ@qM] S/^C1sT Z}l: oAK!M!FR'@]$$t9긬>w&GݗJɨrUA:RCH~: m]:s@2{V/m:ćp[rL ndke%~e,PBn;7$ȏ83 "h Mv 8VDA,HdeԴM;ڲs!8I pHKj#!%ݦȎں9V *kQ߃l=ٳr1O`޶!Ki_S YJ\\J6zDm73F{OfS0Bg^d'`h)ab{['vxNe2^ b@o-MaaK :doU !%&ǘ!ήWGsjĄnykCQ֏k) PFCźV (udipJX mIϭ=h67y0*:qR QXf8kOc`'v?;ϋE%3$*OxBviqXkt])WX}%|3 Ryngt޼XFyhb3קH[c#rut ,H8!Eg;C SrExAMhLM"viow솀\kREѽ=Q˱m}g9ĖPz=ccoyNp7E-X ×Za06Eñ& ڄYb+1^:L) | m c՝y58W*oϸ7m(YiΧ,`@(jW5ѱP^%, >JO #rta o$v(*]g)mm"I}Vl$H?a ;'~ ž %^d񲒪>(-(ca>|=jg3\~ % W!$Ijemyj WWSN뺹v黜z7KaO:+6"We+*ޫ/l]W5CG.B 90{ȽnJJ6z Xףtkz=m柒 ĄeEqxȒqJX;Ie6̺B{?CӃ>{xS_}rdWO]jYjLXLa] endstream endobj 272 0 obj << /Type /Page /Contents 273 0 R /Resources 271 0 R /MediaBox [0 0 612 792] /Parent 270 0 R /Annots [ 254 0 R ] >> endobj 254 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [405.711 682.827 499.544 693.731] /Subtype /Link /A << /S /GoTo /D (formats-page) >> >> endobj 274 0 obj << /D [272 0 R /XYZ 72 744.907 null] >> endobj 275 0 obj << /D [272 0 R /XYZ 72 720 null] >> endobj 277 0 obj << /D [272 0 R /XYZ 72 145.357 null] >> endobj 271 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F31 150 0 R /F58 217 0 R /F8 267 0 R /F14 262 0 R /F72 276 0 R /F44 192 0 R >> /ProcSet [ /PDF /Text ] >> endobj 280 0 obj << /Length 1506 /Filter /FlateDecode >> stream xZ[o6~ X^D*-ذ! flaIr&ے$ےus%>{.{>p-(  .G*t_ҲYP~Hb,T1p ˴!}ce &ZrcwuHD;k ".=~US)^1";+\ &'A=ƈWKK(Ȫ|3U*3bHǎ'  F&tONy 4+'}z Էn_U5 I:$ZE;ԓ2vc)ƜɕC;"q9e͏؃롌bZ2& ?$&X7n'U=&XH.%(\kw\_PdX: ?!Y $< O7ox/"m^^l(Z* 9Bm]^gȈ{UʒwfWk%՝Mg[v,4: qNF\WsuL 244#둿X-;С4ݨndd;g}{,i .ؑF΢γEe9<+)( )a͠0[k^F滾Uk"ݓ|K*bP q;@yn?,|T^6zo@m-D9!^$ %GO\3"W6 TH}ި/M"jo}Tө4Ǧ˃|nQPo&giѶ; ǝ\7 _<_<_<ՙIwG%q#Șz;I =h|vT@vH2 IρySNӖlO7?{ד&9؜B<?Y.9vB{ܾ/RӪbXC~ʏ nуb 1+'S&&B"L33q PtvQpg.}eĽt_ORN˔EĖYgM‘4t_ݻ(1yc֔}U H`?KJum5bRpebׇqTq{XTEĬykW^iw:'#Hw_p$jkLg> endobj 281 0 obj << /D [279 0 R /XYZ 72 744.907 null] >> endobj 278 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F46 193 0 R /F57 216 0 R /F72 276 0 R >> /ProcSet [ /PDF /Text ] >> endobj 284 0 obj << /Length 2091 /Filter /FlateDecode >> stream xn_AP4p{j4xK IBC)%i؀Hg6g,|w٫74H*E 1 .4yWojDDXфFqr]I,vUN #:˳g0XE8 f0}KZ\p̓_~9}*PI0,T.U4봩hfgjn^zt>EsDd-JۼYݎ5۪Ps'$BrK-ƴ鋃sbiGfiP#Z,m֬ϻfUyV7<  ͻ1E"EFLh (F&KCGzh ^4.`r(ơ2%࢒֐7Nq F⫁n>}.<~ßP%#f~?d^,8C$AS(\TVLK^]oFPuMUj?(Ir$MR2k <7ր'Ŝl~% hhW fQr!ϰ`:|dZ}fɞvc_R/s|'+)-cQD$ݑrVyI3|-oxZjVnZxUe,fDE[5m)&()yRI™f'4]bz*;O[~dahhvv7b"Hv/7H>Ǻ g,ƚAk騋jlG?vI Sߗb,s{ȏ?>"yV^Shz|u95%ϖqPJDzf:cJo9e*1Yw+\Fp4Nb%YfҪv(J{MpDczv)%{c2sbיA A^rW4cD)]H1%6[H q?9ICGo=HtSU.gCU4GpH1mچiO>$G[GK'3M0q )xFpAIwIo:1dt%'ZD2"<5YI 03|ތnm z w` m˳L޼]]fk8XtD3k;b\emat5qOU[M8ٷıڎSk~pkA 2Ͱ`s@9#Z,F& p`}؇q 5k sMQڎ j!d"U-j U@Ԡ˧gQ$?Ԥ tRyRLك^m95Ac5f*h,90f 7?(ЖyobB9}8-9h&%O{@nwQ{v͢c^3LB}g\wڝ[D05ϊ?OL|3/>U6[ٹ,mf5H+tmʅ}owGl৮;FpoR8-{Y.#zw~ӝz6V벍C˘SifHPJcKuvRxgk5:iY ΊfbyWo@{$qɼl@%F)5١(vZ^c47v]Ծ,qrI*zAS%P[H~rj !) ߖzo'o_Q}렧βr$qO߃! endstream endobj 283 0 obj << /Type /Page /Contents 284 0 R /Resources 282 0 R /MediaBox [0 0 612 792] /Parent 270 0 R >> endobj 285 0 obj << /D [283 0 R /XYZ 72 744.907 null] >> endobj 286 0 obj << /D [283 0 R /XYZ 72 170.072 null] >> endobj 287 0 obj << /D [283 0 R /XYZ 72 102.324 null] >> endobj 288 0 obj << /D [283 0 R /XYZ 72 74.428 null] >> endobj 282 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F57 216 0 R /F46 193 0 R /F72 276 0 R /F44 192 0 R /F65 266 0 R >> /ProcSet [ /PDF /Text ] >> endobj 292 0 obj << /Length 3325 /Filter /FlateDecode >> stream x[[o6~16fy)hRld"GF#M%Mb9H{yXhH!y\͊~8<]e$S\.W"DJ2%2bv9K}y~ue3C6lۛ.s?J?}y芭4ɒhW_骀W,]}4+RW?=[rH4 mW4x!'$?ySainq^7UڵeVBWꇶ+ Q5mÀ;\/T2_D+ 4  5 #"GNmzbhnKXn`xʙ^M}oQG0+IXBuKU|&35|ZCݞdыysS_hBfSYklK޹qY68]HH&@%PJ}µqV5C6vSvn؈Sa1MIGΞ)$P5SU޺E_ɮ  c0PgxXL2iw$,k"e2A@*80ON{lˠLs}qʅFsB <W.YqQ})/<ڶJ82KxMчrc=grfpvP2{S?54&Hә4v. :=|nw|5[kݳ=hthw][7Cٸ.3$ϿD&yYoˮgs'IySi"_I-8@It"Q2"rQ1 g %h6c9` DcAШS@m{SM`^E:$:Qhp5]3@1&>u$=H{@;8R9U0í+tO^;Ȅ8J'85LjbhmCSsxԮ2Xmel:]oK en~ݴ͹kk`un;'3zӎyF֦:v 5m{?z.QQE"`OnMAwi~kB1dn7"M*GmR!DJGoͭ}=8qݵ[Pf3 )x4F| Jˁ+1p~Ǐ?JmRmw.1 Z i PZ&Eu P9={1JJl~ب8 Tc'{vx mwjN(ԝH=Wpk\rJ 5 Z~&G2!XF4rZodnS#BJHc t BjE F8W8-7=́]4D2Xz7FгkޕjE& Z+vm7wD&Z\B)W9Hv΅^K(M!Jw3eZf'&f>i>2 3LH( o`1NK$pڸi$Bj`HDP $L[MP>)Q"tՁ4lxi;+۶튪XK CܕM1%@&!1@"tC"'?FTU[Vl̕ee,<mk\vq B@#"<<'l֮FQ81UngD4(NQVq]xE\\^{r()@0T>n1<9˃# ߙxӧT />HG[]1Ղfӓ}umEK)i(F$_(^[oaJjuf-Ă#Tҁ :OPI4t|_nsp1#DDzc^,T' f̯UdpEf2CIMq%%O; pg PBCm;g5m,QDL,VhfdlXzbzd!c8g~dðF,_j#AK·1NwOݔq^ h.8I6%ph8 ;gk wa)1JਗyqXI?z]t7<&d pJ,[\i~zԠ֗wł+jtqhiW,owE>򢀴 ywT={:{fm3N|+I,WyXsגLOwL}ۮkt= k$*/}۫VaM^R2Q@]n аgl/KXw x‘(>X$_$ra|ߌ'-pb(P&'̗w~jYؑ*n^E _l{;JvOB}#t#k=x+.A"cKTIhb @mX9f3VjO̸J^4*"eDkHXѝApH]*̦&XYo TO0>@G87[:k#x6 g 7d}ڒPJ)I endstream endobj 291 0 obj << /Type /Page /Contents 292 0 R /Resources 290 0 R /MediaBox [0 0 612 792] /Parent 270 0 R /Annots [ 289 0 R ] >> endobj 289 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [405.095 419.96 538.506 430.945] /Subtype/Link/A<> >> endobj 293 0 obj << /D [291 0 R /XYZ 72 744.907 null] >> endobj 294 0 obj << /D [291 0 R /XYZ 72 683.97 null] >> endobj 295 0 obj << /D [291 0 R /XYZ 72 644.12 null] >> endobj 296 0 obj << /D [291 0 R /XYZ 72 604.269 null] >> endobj 298 0 obj << /D [291 0 R /XYZ 72 554.466 null] >> endobj 299 0 obj << /D [291 0 R /XYZ 72 512.613 null] >> endobj 300 0 obj << /D [291 0 R /XYZ 72 448.852 null] >> endobj 301 0 obj << /D [291 0 R /XYZ 72 385.091 null] >> endobj 302 0 obj << /D [291 0 R /XYZ 72 345.24 null] >> endobj 303 0 obj << /D [291 0 R /XYZ 72 162.744 null] >> endobj 290 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F65 266 0 R /F46 193 0 R /F58 217 0 R /F8 267 0 R /F10 297 0 R /F14 262 0 R /F11 261 0 R >> /ProcSet [ /PDF /Text ] >> endobj 306 0 obj << /Length 2950 /Filter /FlateDecode >> stream x[[s6~[>$ݦNMdh PJRq_7D˒&3NC$q;4#rk%bIIOXt.gov&I_qT [jr +°!̼2yH7J&D!Ey$1CBxM*-,5w(A1=y1edǭ7DxXJk=X&c|4|%bJ/9H%I41$ cNZ>Eʝ%_I|:$i_fˀ by iryn> L wҘ'H |r˕9 g1/~ˮ2{v)" N@0J-EL$/'eKkC}#G$kc%)淳̥ܭ7z;W;w,BP0eEc:SA" X9m'3%6~RI]W^32{782 e 8s'\ ?eaߞ߅siIsg= fU.׷[y(BR_ 0f|R+T=o# `{R{۴7:Ph>u~jf `KVPMh/**ny`[<7-y.@O=G-PRm\px0u7?SjTlǐmzØ#!e~Ѿ0yl9fZ{1# *ޢmQL-")j}Sz:;|ne>9Tq|b7˥UbWu NvVдZ4ӭ8A91Twj 3Ƹ\!ͣ^#p39\v`XZp$fMYIb5c?Aj*a20gOa0nZΈ-&~(\Me'º k&K6[uY_+l{l-B30t}i擡T\RNSmͶ=kjQԃYwc⁉ 6<,[ FGSͥ^<FmEGIc:S'u_+$91XypFo|÷@UUdy]Wȶu^1NV%Fr$(Woݠmf[ 9jk;{h;z"BB3yC`G=Myw8_siVƚ-lqR/{v/ жk5>r.tU[ߧqjȜH[nm'fi#dw: ʴON&Yד2WG$[f\o%e3aOz$3Jv4.ϭ|D$ǒ࢕NGS ]ힵnnrk  ?9w('u]HHXpHt3j#:^aK! @jG"gtΓ.|;w\Eݤ6'I*`PJ:& 4A|CR[pon:3ݜ^&vW8LIGSljuR7f> endobj 307 0 obj << /D [305 0 R /XYZ 72 744.907 null] >> endobj 308 0 obj << /D [305 0 R /XYZ 72 600.1 null] >> endobj 309 0 obj << /D [305 0 R /XYZ 72 452.47 null] >> endobj 310 0 obj << /D [305 0 R /XYZ 72 380.719 null] >> endobj 311 0 obj << /D [305 0 R /XYZ 72 350.667 null] >> endobj 312 0 obj << /D [305 0 R /XYZ 72 312.874 null] >> endobj 313 0 obj << /D [305 0 R /XYZ 72 257.018 null] >> endobj 314 0 obj << /D [305 0 R /XYZ 72 229.123 null] >> endobj 315 0 obj << /D [305 0 R /XYZ 72 203.285 null] >> endobj 316 0 obj << /D [305 0 R /XYZ 72 161.377 null] >> endobj 317 0 obj << /D [305 0 R /XYZ 72 133.482 null] >> endobj 318 0 obj << /D [305 0 R /XYZ 72 84.645 null] >> endobj 304 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F31 150 0 R /F65 266 0 R /F58 217 0 R /F44 192 0 R >> /ProcSet [ /PDF /Text ] >> endobj 323 0 obj << /Length 3502 /Filter /FlateDecode >> stream x[Ys6~УT5BpLUfM6yLhHq~v5ڭJ P7Cw o﮾EF2B(N #-X./-/Y-|w0UhUgMΪbZ6+Ѡ4/yO|pŔ)76IznÓP PzގnAZ`X0m2bT@ۺ ̝ΈԽ3/`>La6"ыVrca7yuW 1EaR$ߗt=Z+Thx~l#86Qc(|5c::/JeN`V~QE%2A4fQ4ūXptE1B:pj_B&GAF]- Ŧ +iֿ4%""rLWawF =^)`59Jk%e,FH?-Q3ck-"[706bPxIۏS%?K66@v~VZ-oe8MiA.KEO]WI26 Mt iCrqEQ9}]VM7fvE0.@Uwіɷ,]X1L_@ʓ˛"qFig%̲<6w! ScT,i>S&`G&ºvvQ(#̅f,m/%3)$+5gHЖgjù[U{^L@)) :!DbZ QlqX џ+p>%ɰ>ZFv\m T>~ 묑1I2>S2OG :j͢ǷEwl\![~pMy%!7SXG¸إ\=W,AFg5 xZ./+w0aA997newad0 3*GQeq 0Tu弃{JܬP*· rbc8}#e&IwTJ!STARgͲ4Sokyf>7wbN/7HhMX|aQT_rpJʦm~Qc>315dՠm^F엛!*nb*XnjBu`eoI.o0vu`&1fx_nD8a[P! :lnԩ#"oa@-sHf"۹%ѡ"D+Lu9&qY*<= A7/<7{BńTNt*Td  Cx:o45Rc~g@_+;Ϙ0y,ne*Z iKg(fy{yOp7+ICi]!r"vn:N,Bd ,c6OjΨM}<ai3߉)i`fF0ӓllr@m  8sjf(`zN&{,&DG0:Tj c`6YT6/@7sPz "Y+7yE _⍥!tHrr}+1ZM&G>'Mx,t|} ۞? 'Ƕm6O=|NUp44osve5KǗBg!R aU? 2v C4 Ϝ< Olán܋Xv0Yx/]o6ݟ6z|Gf=˩)Vw+ղ eHGEQ3FK&%b7Z`mxu;負hWhT_[q*\q ;͊+B=7 ]Mv2RejuM '5lzpQ TR+AmbbvKvS`Wu8OT ؈w0jwmݷvcVQ" e_>pO{L47<\hUn` oyh[YUE崇TL/QDe L5j{9< Je;CSFJF.akd4gt8#\-5)2S"aOI""ӑ){SL! &2zTLN6biX& ?~"e55>Z°b`ԗV?.-P`< '.F'J_)HH>GnVk͹+>Oq$0 w"cݟ~-BhAxc|w]$ endstream endobj 322 0 obj << /Type /Page /Contents 323 0 R /Resources 321 0 R /MediaBox [0 0 612 792] /Parent 337 0 R /Annots [ 319 0 R 320 0 R ] >> endobj 319 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [441.22 434.331 538.506 445.235] /Subtype /Link /A << /S /GoTo /D (formats-page) >> >> endobj 320 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [344.185 422.376 438.654 433.28] /Subtype /Link /A << /S /GoTo /D (formats-page) >> >> endobj 324 0 obj << /D [322 0 R /XYZ 72 744.907 null] >> endobj 325 0 obj << /D [322 0 R /XYZ 72 625 null] >> endobj 326 0 obj << /D [322 0 R /XYZ 72 585.012 null] >> endobj 327 0 obj << /D [322 0 R /XYZ 72 558.041 null] >> endobj 328 0 obj << /D [322 0 R /XYZ 72 532.131 null] >> endobj 329 0 obj << /D [322 0 R /XYZ 72 479.001 null] >> endobj 330 0 obj << /D [322 0 R /XYZ 72 332.83 null] >> endobj 331 0 obj << /D [322 0 R /XYZ 72 307.343 null] >> endobj 332 0 obj << /D [322 0 R /XYZ 72 267.238 null] >> endobj 333 0 obj << /D [322 0 R /XYZ 72 225.703 null] >> endobj 334 0 obj << /D [322 0 R /XYZ 72 198.732 null] >> endobj 335 0 obj << /D [322 0 R /XYZ 72 159.806 null] >> endobj 336 0 obj << /D [322 0 R /XYZ 72 120.879 null] >> endobj 321 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F58 217 0 R /F31 150 0 R /F44 192 0 R /F65 266 0 R /F8 267 0 R /F10 297 0 R >> /ProcSet [ /PDF /Text ] >> endobj 340 0 obj << /Length 1652 /Filter /FlateDecode >> stream x[[sF~ׯ୨6{@F9|{=} [DK5..5wFsb҅kd}F( %SOIbpc.㒖aqhØqI~ٟ΢?`ϱY!S?Oύ^aul 4Nކ<pHYh婟n~<3d|emzlPSr4##?OO=qK t>NTFw'L miA60ѷ&i2-_F "OuYc2CMأ%8Ca3.0re YP30ڼ26 lKhd_HK? 8jXEN> WELT,Qr}RnA*n1M+PJ|R{-o4.#W8D7f5"< [`?㘟%懣^W~)  G!\ `9S"m7]DžqڼRxvjdg {y;6~T:Kw#Oo 񁙿d"-xRpD_TޓSDJƆHŕ ?nY F )uap ҷ?>$=KlY#Ho endstream endobj 339 0 obj << /Type /Page /Contents 340 0 R /Resources 338 0 R /MediaBox [0 0 612 792] /Parent 337 0 R >> endobj 341 0 obj << /D [339 0 R /XYZ 72 744.907 null] >> endobj 54 0 obj << /D [339 0 R /XYZ 72 720 null] >> endobj 338 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F46 193 0 R /F11 261 0 R /F14 262 0 R /F57 216 0 R >> /ProcSet [ /PDF /Text ] >> endobj 344 0 obj << /Length 2128 /Filter /FlateDecode >> stream x[Yo6~۪nOQ2d' -GI=Nק(Rj]c[}`L"Ǫj;vśwxsq9̹]łT%u&**KNmTt #__`H 9X:;`y{%|(7?]`+j["qQq x1j|qiXCp&R`U*+?kȾyHGYRy{y jw"=BT钨CtEټO)GҦ[vViȆM}=wk۫WYNmiUFΒIXu@;LHa2mU=k.mǵ)ԖZvSm\HTd{Te66v`ZV* t Ǐ;XPX8P=5009}[]5TI|.c3ӆ%pkV"-:l h 3O&\rʸ'̊t&Zj-XX6cMyZI7&wvuj3T@oF6 ZGW5G0z9lz %-,h:OĒ6n &FsP p$v 0 q HKOƽ]ԃ]cYb- [An3Rq͌q^9<80WC*Z?alOG`;ce=|H.i~[ R U6g Ε|*ܛlOxm; B@#Y{/@ k|w̲Ts0߸{ HyBt0!+Tϝ>`|428G)$*5H&,~kԮɄ#0M -[:AFÑl:4igyElsh#Be.!@IX@98]G}8_ƭ=vȣR߹| 0:Ncٜ&!=y2,(il˪hs,u0Ym!cQǖE\ |$D /eh ]~s*v(rLo"VFSҁ)$w&-YtPVg_}L̟Jt&Pajb;۲y+!UgW~oK>9}b@.@6g#sPސBQs̺ȒO>$-Z`iR ? $ϊjIa>!ԚS;$&1C g{t59?趼 ȉNޫjMu'k < /G q, 6QGO"s2L6 sC.b"fitΪˁL ~QϙGD 8$!Gt>:!ScQCN VV\o9FS#x@>=ùkm W/WK0i(]Ch;ѬCyC)ڃ>Ng;C'K ?PFs7O :b9ÕQݿd*$3-erqdVq / ֳPնH;?8w@bA4(=]z?fLmxMr|)HK<:t~N6 sƐ sdPM/drA1r$u&">s"BBpA9Dx_5~^T7?>ק WKy}uԢxXB+Uי)ۯcꃩo%ڦlk{ȯ{ m宑pB^u\VlIA6Ww:; ͇裂?M۴j9|[X^d02+z4$$8޳1)"6|@u$"Y endstream endobj 343 0 obj << /Type /Page /Contents 344 0 R /Resources 342 0 R /MediaBox [0 0 612 792] /Parent 337 0 R >> endobj 345 0 obj << /D [343 0 R /XYZ 72 744.907 null] >> endobj 58 0 obj << /D [343 0 R /XYZ 72 720 null] >> endobj 342 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F46 193 0 R /F57 216 0 R >> /ProcSet [ /PDF /Text ] >> endobj 348 0 obj << /Length 1592 /Filter /FlateDecode >> stream x[[o6~yY")*@_.ŊnRAt"TOf~Hٖ$ISGÏ<&_7gDp0] H}L6_3' .bAɉ); 0D/FMGj l)f*t}oŀr|=BOv L*cxAȞjckD5!b @Ե{>Do7˩Bp&NJ;)TU/BTWiafj9}rf9̿' Gȹm%T})=.ʺ,u!#K.]4S ڳ0^YQ-1JzKiibjE5k Q+1H&6_bDCLHt\2?1+&.LTŹI2&ic{& (ۑҕK!/Kz 겁Gim>X[vcs1^6][oQ[؊Gml\!=g=s>Ɛm_b b1C$t.έ>>%P 05{D/v(+ &IJ@]6$0,di2m" g7mYIn&#*rn1 cZTq V; E~(U-"7͞^//jn촳#l??˵Rq(2kw>"@@ۣ7{FC]w^ׅuc>c&֫]6poxX`흃uA3]oњdb vxq^\{͟0m vJyqm0l&:*Lܿc7*^/HhAj^qN_]7g{:pwNJ ex=.7)Xf)g̸z, iw29!T'ewyqx#G6JQ endstream endobj 347 0 obj << /Type /Page /Contents 348 0 R /Resources 346 0 R /MediaBox [0 0 612 792] /Parent 337 0 R >> endobj 349 0 obj << /D [347 0 R /XYZ 72 744.907 null] >> endobj 346 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 352 0 obj << /Length 2347 /Filter /FlateDecode >> stream x[oB@Q<%~(wئ f]Iew(R^ے"g͐νOyuOs|K*; 8=}\͝US"&:RכOgX%EPirf.UAӛ_Ouu v!K2G.vY|r}9`|y*{<#'9VT1/?רJI ]ޠHf.kIt)0!u6 WΔs2 $vw\ f+#,@txw32",܃MPahIM ݅3b l#_窫bYh^^y%n$-@⇟[sܥY~(Aep(O`ÊLҚC5"^ɽbs\)l_\ˤdҎk@sj_'Zaqe.bb̮=t3JgQ6Ư D۱_ܽS)EcTAtPi[ 8%0EmiD(=q;F?ub%:E&eCrF$8C%HyOr6 6Y"2hTir6(@ɦOhV?z|/NtBLj6!X)r{lޙYEara3r+JTIWx-CxBSNA]]G=((sRel|1 ۬h^*#v2=7(bu*.Sa0]f2(Ox)++^ۮ6L`kj僉C.u~0466wq.QP0OctxQz"?/TۆQ+ʼkY m 0n 8"U#q/$Ɣ#jlKxo9D0zYfym\E¢"#f!1;յsb ˨^>7a¢ݤM#cv>vH5o`o&fAC Jk& $kv[P_N5l0,8Hf-\Rv+ 8vD vyLa&bexl:~,հ7m1VbךšDrg*@^h8x$ qiLN,aTgql1|m"CLjT2m/x}3awoi߾ݸL^-o̖ʖ LZǙHU?v\)韾uHMz$KYбܕ ZbvVd[2s~w+7ˣ) lca ZTR.nW$[vԃaZ.N\geX=Ұ<, (kmJ8VEVcpf+ Uyœ }ʞ9ԃE4;Lt9PKQ5ɞR:P(:X/WuTW+;T<50Loꬖqu6}A}/ VÉz=_5zV7AS{A*KڵTٗcnXJ}[5mP5Y?ɞLh+29>z0 gߙﰼGxїój)-UC㷳or>z ~[-EKfyW F-2Tx2,6x))aG+z;Kn1Wv[Yս“K\ ('ȸ˝y qm˥y1yׇ%S^JޢEߛG{0Xߘ`wǤy^u9p*ex B5eemƖ endstream endobj 351 0 obj << /Type /Page /Contents 352 0 R /Resources 350 0 R /MediaBox [0 0 612 792] /Parent 337 0 R >> endobj 353 0 obj << /D [351 0 R /XYZ 72 744.907 null] >> endobj 62 0 obj << /D [351 0 R /XYZ 72 499.394 null] >> endobj 350 0 obj << /Font << /F28 148 0 R /F46 193 0 R /F57 216 0 R /F72 276 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 358 0 obj << /Length 2511 /Filter /FlateDecode >> stream xڵZms۸_T!xxL\rw͸>S%D"U]"(fԻZbIߖ6+6Y #tO #$sVۋp_#XpD_YUwk\II"EDNJVD'=  N59aB(+*nG8" R@ 3++BEYr2I\ȷbeV.Qbhtou?,NRAjF+G+|Wu]tjXD$N,iEV1y6ĺlޝnW^ VJ,"B8ޒ !^ t{1C;Y~zm' ipD"T|3ni%˙=dtϯmSoj^R !8CDa$P"pd$&%SPl~ſ&1mڅ=JoJ~1CVenn|g^Q"U.ҭ)6F6khZ`0?p& 8Mo)FjVy!t|g3]4xn6cKk0 #@0hFc1nz5 8 %iSH$,9nHC+ j~:_A6 )b_k_UXt`g]*hجEw8M הrRyv +]nՍq[2@kUe,5ut_&۸曲ʨkݗQ n:"A[! Y*ݚuE1֩ UۍaXp#3vi;wܖMiVPH N"HA-+K Td:DX¿%3V9AU(izk\kI6_gXhRKBRsۀIBN g@ۈJ0ń ;+b†QlHH9B|aB}'+Jcnʧf/ (J#|~yz,ABgK?6ϲfZ7Um|\f{5{7nsH6j4+H8$$5]Sչ{3/͚cF0G2y\EfmqfAb_g ;=*G.6')MnCeuvߪ%e}ț:C AM$5zvCji)XhÌQC"|6 !ARݥU^[ (޵Q+ns.ր>_Y]:ӨncTq툣I$=d f` QWӬm-1촦:q<8d0e 罌 gQا|ƺ+md>drǷ%j: ÆskW_ɚC;mN Ѧf]~ kj4(64 5,#?uRfGi:\'W3-!B‰+TX6pSqOt$3VIhK=c1D@w' ^/DO98I8=և&7kB pRL9 .%hr:[ Y+<*A1{~L}{B!' Ҋ?S,l 3q8R&O if*N'6,K\pdNm\ yIS9A9awla32Sb%":2K l3vj}\!( %B`  F2 YRt3w%`gr¸i2&ÄlDW&H1'E)fHc8_Lb@z3wf V| H00IU9Me"D}3 OL3TPAc3aDxʼ-fl)dgC5]٠ endstream endobj 357 0 obj << /Type /Page /Contents 358 0 R /Resources 356 0 R /MediaBox [0 0 612 792] /Parent 337 0 R /Annots [ 354 0 R 355 0 R ] >> endobj 354 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [353.144 292.713 408.474 303.617] /Subtype /Link /A << /S /GoTo /D (mpy1) >> >> endobj 355 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [492.068 155.158 538.506 166.062] /Subtype /Link /A << /S /GoTo /D (mpy2) >> >> endobj 359 0 obj << /D [357 0 R /XYZ 72 744.907 null] >> endobj 66 0 obj << /D [357 0 R /XYZ 72 345.975 null] >> endobj 360 0 obj << /D [357 0 R /XYZ 72 271.956 null] >> endobj 361 0 obj << /D [357 0 R /XYZ 169.724 275.542 null] >> endobj 356 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F31 150 0 R /F58 217 0 R /F44 192 0 R /F14 262 0 R >> /ProcSet [ /PDF /Text ] >> endobj 365 0 obj << /Length 697 /Filter /FlateDecode >> stream xڭKo0>&;H T(ݦt}@3Y!QaObxHMH>{NȋJKV,o2Z[]*{u_ɛX~wmծW٧zSW$Pq<-2N xd N:fWRs!A^<zm9q G:{$etYxWBYba?TO(VkW{zPvkU7ПNbnnYqH D( mޯWuȝunZ΅f CShk~e2uc8~;8dԸQF:4[Wh?;ɎsI%o:$|1J2G\W?PfJ(ǿ&Gǘ*È)S #~$~ܬ#~3@f ဉ :2(?Rp{?X޷EHsq4vC50eŤ41se2/x͓AO'0]A]mjiޅ.!.z|N endstream endobj 364 0 obj << /Type /Page /Contents 365 0 R /Resources 363 0 R /MediaBox [0 0 612 792] /Parent 369 0 R >> endobj 366 0 obj << /D [364 0 R /XYZ 72 744.907 null] >> endobj 362 0 obj << /D [364 0 R /XYZ 72 710.037 null] >> endobj 367 0 obj << /D [364 0 R /XYZ 121.104 713.624 null] >> endobj 368 0 obj << /D [364 0 R /XYZ 72 621.768 null] >> endobj 363 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F57 216 0 R /F44 192 0 R >> /ProcSet [ /PDF /Text ] >> endobj 372 0 obj << /Length 231 /Filter /FlateDecode >> stream xڍPAN0{%bc;WhAԷ5P)iB(=nMT=4xΑPR(U>wL,CcYa7an5TGr32uILʊa`]J&g x^Z؟X5(m#V /DV8ꫥ.UȥĔ1/ KYr2Hͱ}6GU:/κyCIcZCScX/"Xf endstream endobj 371 0 obj << /Type /Page /Contents 372 0 R /Resources 370 0 R /MediaBox [0 0 612 792] /Parent 369 0 R >> endobj 373 0 obj << /D [371 0 R /XYZ 72 744.907 null] >> endobj 370 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 376 0 obj << /Length 2240 /Filter /FlateDecode >> stream xY[oF~@4@&@c}X$łhDjI*̍7ђn}I6|Nt?8!" &/8Y#cdfm.5\7?.~ՉAFR?$IܯO7}su{7pĸvBdN^\B#QVjFt.$nn\|ǫ;:#~aD%LG?]S*d P֓| ġSV!!D:m*[T؅@8rdþ{HoYPD9` d5\4a ii[orD̾櫬#V*oK2+/dVdpWկ{6{Z˵L pl_g+?GPVYmyU)Ѫ mf]|d۬h:)d'p!#8+7uUD@&FJsFD3ۻo1+PT lM% Em_Va;z16p|HcqPHڛCK:<=T6tIk㰠!~䔋/ٲ2pN둚r)xCbj,Y7M>LI1" qanן)Yө tzOlnXp[e;*>y"[64mV9d|~F9WHh͉mAːQkLL fr&gO1Ȳ)cAUl`P4 6^#[i"Ä(q,`m6>U.0:kIF}pjɑZo?L0dsN. DzYO qN > ZSjZ-i+/6mUR9ۛSiUzX9;U6AV4 %5:]'Y X;gtY.33 jhnb @0HC >y c?x+>a}tjؠE@u# DSN1q Aֳwbi'-szeJSaL giH`hKu(HplW@&rDf⿩2(QWz/q0#/Jn/&(eUWPC%9Բ&S)`/ڠ0` 4Dz)o~ܱ#_= -G7),,c|;j"<ƶk$~aˮI=(;hg{4%ew tVvOkl fo0o"8q ޠfein{X伷]Ou%E@dcPI9)ecl&u3Χd9rT`UYlw2C?9-Xc~bn4h!CzA@/ PIdi5k [\u gp sO7s8,` NJ!x~Þ1 az0'dOw z {"]QEPaڂyvlPdt3( g[@Ih2aBpXŒls@!Y<*_}ƭ>T&Op 1AB.vN | @ށ `>g4 b떡H_ [h졯cIJc/e}v00ZcJ } >@ ʆ4?; l)sv#b߁h;pFcdg6yE:`49#D=%bRS"Kl:DOMȣ=daw0⮾.uڧN?M|vf&~[nԶSFlGZ@j96> endobj 377 0 obj << /D [375 0 R /XYZ 72 744.907 null] >> endobj 70 0 obj << /D [375 0 R /XYZ 72 720 null] >> endobj 74 0 obj << /D [375 0 R /XYZ 72 562.518 null] >> endobj 378 0 obj << /D [375 0 R /XYZ 72 378.833 null] >> endobj 379 0 obj << /D [375 0 R /XYZ 72 348.698 null] >> endobj 380 0 obj << /D [375 0 R /XYZ 72 285.281 null] >> endobj 381 0 obj << /D [375 0 R /XYZ 72 206.446 null] >> endobj 382 0 obj << /D [375 0 R /XYZ 72 125.472 null] >> endobj 374 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F46 193 0 R /F65 266 0 R /F58 217 0 R /F11 261 0 R >> /ProcSet [ /PDF /Text ] >> endobj 385 0 obj << /Length 1069 /Filter /FlateDecode >> stream xX[:~Wk;$G:+i"9 %-ؤPJUU)ɺ7!hzoԻ|@2F R`(Yо*M, %O뎑>CxؗsOA5 2$ep0Rp$wmr푊Jv8W_"o5Z>h `%'B!L WX1 Wp[X0x(p#CIyO1qYbڳ{Qb8EE!I nuEQ,hp7FIO5TB99thb^= 2.GRpN 78 o ͝&ב;金 s2X҄ȘGɷF[oW^o_bTsih8jnO%zF.5 ,Qα`E%c&K},I%ːI`ɵ2>GGB(.],?]4z Y/x]p}X<}׻86q!tw>foCi*ܩ_RW[aAETܞK-*R\\8Jj/(a14$܆SmwZo?<<鼡7BM]h>.JW#Zav¶Lnvd3t&N¤AW.-a&Y1wI Ed7fù!Zad DpJdeG:bLG(cU_wm:#˶R8_v1%~=m6P5( > %0m|&Gm̈B碴vg,eI5n]鉲"{]ɳ[Ga ``1%x5NQ~c?zd endstream endobj 384 0 obj << /Type /Page /Contents 385 0 R /Resources 383 0 R /MediaBox [0 0 612 792] /Parent 369 0 R >> endobj 386 0 obj << /D [384 0 R /XYZ 72 744.907 null] >> endobj 387 0 obj << /D [384 0 R /XYZ 72 474.617 null] >> endobj 388 0 obj << /D [384 0 R /XYZ 72 474.617 null] >> endobj 383 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F57 216 0 R /F46 193 0 R >> /ProcSet [ /PDF /Text ] >> endobj 392 0 obj << /Length 2555 /Filter /FlateDecode >> stream xڭYYsF~ׯےa2^UڔM]k-m^DB$qҿpT$ fC|E' X fDB4%i/z!*g]W߾ITq?2e$XRN$6x7ޭ?3IT3Ex!DQnW;%^$NbxJ iCf=yf~~Np%P,h`dWsICM;TȪ&"lzÈ7T#zMHMں7)l%nm_޾}-! *, j$M6&<  !k>ۼ53yygy]d]?n_oucVjg^ʢ3vj $\+\%|ddk*존e\оͶټ>?Ʋ %W7ei}aYɑcN3h ce$YdQyko3j"+{o5ʲ/nv@*ks* %*W} \s /*X2nGЯz_rk 8vqi,D4BB4Ả%2p4԰Adpʞi6BO0d4\I%ٙ @R1O(ZY?+ʲo;%g qo&wߏQ̘Ϝk8YQTvo p78nvh>쳫K;:dOE޾Y&$ӑyy,H wzw.b$`c'N\!IIz,X&R?,0Rt{CG-l:ޙˏn ]&`[w81)/0M\)†gJ l B %MF68xOuiǻU?cW3כ?A9Æ.Zn1&ܷOsO(:8\rD=S0K8ؼ1}k'E-02o z#MnPJ;[bj*6;*9N @%b%>;pJO,@LWR*:CM%$xͺfJDŢLJ6=U{\R%kdXR/X>#\jgF&SŘywОCC.9!64M˒b=(&lu|O PPٯ!3g4Z}M"DK" *8,ز aG]V ]W<k˯ ] ԾDAQgyAZ:tZt @X}@VQ6VO#op{'dF*Edu֙_4&Tb}K;.}5w5oJQ"ĮCI 2Xd?W+C_FjO:n@GWrZ:}V^цbeP;n1Ďe:g6$\ARBdz.4]uF5O@W6#<9OI=˅lJ ҙTWB3k7Ppښib YUma/+;/L_t=8fn+a@4'ejؓ=9ÞLm'G /vHZ[:/ysmi%G+" rqʬa`4sgt-0 r}oZn &L*{F$blC(Ԍ]/#zcN'Ah3#:[ &7&xQA;ܠ`:گq^X!29Ovm)7Kqˠ@])`2t4)؛}p6w , BT0~%äkBCe\'2 K0CeWeݹW@W%lLW4tqp̨B&+2|ϠC?MḫkŖ8Wۯ\9 A~ԇc}m IU<Z@ #Ws<“17$v endstream endobj 391 0 obj << /Type /Page /Contents 392 0 R /Resources 390 0 R /MediaBox [0 0 612 792] /Parent 369 0 R /Annots [ 389 0 R ] >> endobj 389 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [189.2 448.25 263.69 459.153] /Subtype /Link /A << /S /GoTo /D (jdsym-page) >> >> endobj 393 0 obj << /D [391 0 R /XYZ 72 744.907 null] >> endobj 78 0 obj << /D [391 0 R /XYZ 72 720 null] >> endobj 82 0 obj << /D [391 0 R /XYZ 72 562.518 null] >> endobj 390 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F46 193 0 R /F58 217 0 R /F44 192 0 R /F65 266 0 R /F10 297 0 R /F13 394 0 R /F7 395 0 R >> /ProcSet [ /PDF /Text ] >> endobj 401 0 obj << /Length 2096 /Filter /FlateDecode >> stream xZ[o6~ϯ۔fIԥC ڥ]C[Zuq%o(E*9x.ߡk{'G\=~Ac/AIHCʋ$.f;l.pu,Eե]^Wع(Dj'=p#Gd"yYyf0(HbF*=p-#lCkXK8A669D#%ި\ͱ_-KPW*Euy!) 8VM PŒUaB_]ncKbrLEnM`g˴sN_Ţo2.rAuVe'fr|tٰ,0lBJx,E7I@\"湁.:0X`L,D53*~lprXl7I( 8;A6Š(F?6ƞ2]Y;20+Jg\hHmԶX韎)!nm GUz=V27u',T骶a"oGBZN Mceuh݀/C V?klGvX}u[H4P?՗Ev-̸4[sܕm޽3}@mq(RU')Φ.ю;Sޥ]^ؼtҤ\;Tw'#$jQX =$ QLa@& {C;lP̣ EG医ashf+!O~q,޻ ĞߦrEO#2Oյzips&r00](wz*_9+#3Nc9W0^B % bVόFfQСpq2\ۖMMx@y\Cֿ *@ښB3kjnTDz2n1(E+J?TAP t"M.C %h 4 $QE,g5sv!( }ZLN" aYY2G8Zn={4 dф>rGm| `/mnnn>"/ܲ , tNw꺴5CQןZù}0%o`) ȅҝCQG,2pA.K0@εM6Gj!xj8Si<]mJtnzg@!3G642bvQIR"U=MIM7> BYi}FP5ˊ2 1٦ T-jfMiLjS r.+)[b#O{KA%Ct6xY|5+H`$ȬHGS"(~Fa㑋(@0 " k]'xC G-6P<^? W#[QSo гyTb5)_;J` ?[ endstream endobj 400 0 obj << /Type /Page /Contents 401 0 R /Resources 399 0 R /MediaBox [0 0 612 792] /Parent 369 0 R /Annots [ 397 0 R 398 0 R 407 0 R ] >> endobj 397 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [339.411 339.156 468.409 350.14] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 398 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [438.134 195.13 540.996 206.034] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 407 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 183.295 95.502 193.74] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 402 0 obj << /D [400 0 R /XYZ 72 744.907 null] >> endobj 403 0 obj << /D [400 0 R /XYZ 72 632.548 null] >> endobj 404 0 obj << /D [400 0 R /XYZ 72 442.606 null] >> endobj 405 0 obj << /D [400 0 R /XYZ 196.113 401.088 null] >> endobj 406 0 obj << /D [400 0 R /XYZ 520.912 394.114 null] >> endobj 399 0 obj << /Font << /F28 148 0 R /F44 192 0 R /F31 150 0 R /F57 216 0 R /F46 193 0 R /F65 266 0 R /F8 267 0 R /F11 261 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 412 0 obj << /Length 2983 /Filter /FlateDecode >> stream xڭ[ms۸_o:w׹mwso5I>2ZmM$%K|X")"gLvGۛ|+]JLk1&zzJ˥0*[d>-սvYt3|ߍ8( Yz=6PCęJ\G:x77a"Ÿ!:RcV(9a'%VzODLIDlr Bta^NJ%kYt?*wVr`7nXB!XUEϙԀr^ E~YX~ㆿ_a%8KLBm^_`Rѫ9v[g Me+joUxZ?x݅f01 PjcJY_(ErϨ`,oF+&?:qgy;f|kZf xƽ}@eޥwTK0_h8TAbt3vEJiEb+,>V_QhO}-t꧑ (uU$;t#YH6|F6 )C',/c^؎į\n,r$>҇[?WBt{ߟŐ.j(!M$`XldܗiӞ TT+"$28b1кo.TYY\1ǙM(̍%b?@ B/  m2Ҡq*X'7L0S0`\e"+<ܧ:,YVc?4P!WAӝ1BjM22b# Ia4zi!MMm]Қ.pF=dtl}bSL:9>$r5@ 82yӞ"|5 +vuؤߖ  u,vj>-?TlR0æSyWt]?R>]?nfL08s5(y@uuVw^ ?DoaJ`Y':=rh'Y^Leli ,`ʱق_'Xxl+A_aSye펓>~@G7AN깪=1.Hc.RVRnX46m}F\+/l< KQ]| @k~aO{5PNLgm2n'=~? iu)_q m9e.+UHw}8XSM~Α%Y,scԅ [IMM려%' ,fְӲfG6=<*rY)\Ƴ Ýbǐ dl>69" M;499MA%əaqs7$_|sva9j3 &9m95yy1/]pE2Z],cbx!tC15I9pźX4`m86u<ɮ HK2YHv Pi㘙$d]Xά -ɺ2I@nXOf\ii-'j,OAShR]X':jK>lb':lC.`r"^:BS3n˘XRb]X ̀R Kncs62<ɮ HK2{l~b$Rd]XG:-fmYŕ'h6pC0${ R,Z\T}|Y, /$As-]IwU1޽AսaYxdkxBîAa\*j d%_f3Blxy@N9U L(<4PQ(\ȁWa2=vD9JՄSx+xa917YٻetTu:t%N/jH/gg j !H++id{P1V@&=.6J/xZ9k endstream endobj 411 0 obj << /Type /Page /Contents 412 0 R /Resources 410 0 R /MediaBox [0 0 612 792] /Parent 420 0 R /Annots [ 408 0 R 409 0 R ] >> endobj 408 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [458.885 460.886 473.33 471.416] /Subtype /Link /A << /S /GoTo /D (equation.5.1) >> >> endobj 409 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [104.965 150.688 119.411 161.218] /Subtype /Link /A << /S /GoTo /D (equation.5.1) >> >> endobj 413 0 obj << /D [411 0 R /XYZ 72 744.907 null] >> endobj 414 0 obj << /D [411 0 R /XYZ 72 589.323 null] >> endobj 415 0 obj << /D [411 0 R /XYZ 72 559.089 null] >> endobj 416 0 obj << /D [411 0 R /XYZ 192.099 398.22 null] >> endobj 417 0 obj << /D [411 0 R /XYZ 240.309 401.807 null] >> endobj 418 0 obj << /D [411 0 R /XYZ 72 129.457 null] >> endobj 419 0 obj << /D [411 0 R /XYZ 72 129.457 null] >> endobj 410 0 obj << /Font << /F28 148 0 R /F46 193 0 R /F31 150 0 R /F44 192 0 R /F58 217 0 R /F57 216 0 R >> /ProcSet [ /PDF /Text ] >> endobj 423 0 obj << /Length 213 /Filter /FlateDecode >> stream xڍKo0{%7\y8DRBxZ*H|+afl۔X2?XP9vBDFq7Uݱ= PIlM<0/IPY [o$?yj@[2Z믮B#W INd9PpM,D q֏FPR endstream endobj 422 0 obj << /Type /Page /Contents 423 0 R /Resources 421 0 R /MediaBox [0 0 612 792] /Parent 420 0 R >> endobj 424 0 obj << /D [422 0 R /XYZ 72 744.907 null] >> endobj 421 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 430 0 obj << /Length 2102 /Filter /FlateDecode >> stream xY[w6~F(q'ӳv:VzzN6LJ`TIʎwp!EPo6( ]? C8$8D ݞ}k9QLDٯg?,ϾDAbAD XQq br|]g33D z>($4XDH7grGaHF(,a9X ^z}/f.^_]Z/ň T0py,1\"?{ょlQVraqt{r}az/im( 34\"84WpM{}#=.`gh aMS'aU HX퇝ALaF=NU{AE<ˊFUsf>B_4k6nZK`{lU%գiJ۹M>w[aɪ]`xlŽZB/vnbmjq@*bU#֚]~NjiTadwI7R֩J;7-}:'¹)Nt#孛i;U*ɭ,v*KxK &ũ5ca8j2-p"pNYdސHwaK8"$ʆ eWVMm;Ԡ|;v_ڝ/4s%0nş.= Fe3@w^x)Q ;'jQ,9δoTs*gw`#XO0+xꠇS`sgfv[\8nvc3Ѓcvqp@V{!3UՓ!P Χ\QD2;m'uu^r6;T]jU2t,m0@Ą/:Gcj<筳r{o47ͦh͔c1Du1ÇlQs` _k+,81Yލ()jŅ-8 E˽ G/p^$~t&H$YE0F@%^ EJ]#BeSwe; sad Nj@ 'NTd:ٮ>o^BGB,@?-ѿ6`-w7MO8 =RJrg}E4N5x<7L!p$''" 8Q#Zw7G~$m*^k\?Rmvʓ/S P5Y*XiyF _*֓}Z{.)T~S;br< Zn[oW!=C2ozXnj7Ťu_9NI^@Agr`S*nq7Э̉DY†&G\#)Fg<}Ntpҷ 4<,".mk2cx Xkop 6\]Z+E_V #q1#(ï dFBFK׍d endstream endobj 429 0 obj << /Type /Page /Contents 430 0 R /Resources 428 0 R /MediaBox [0 0 612 792] /Parent 420 0 R /Annots [ 425 0 R 426 0 R 427 0 R ] >> endobj 425 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [90.168 480.343 134.003 491.247] /Subtype /Link /A << /S /GoTo /D (module-superlu) >> >> endobj 426 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [88.986 438.808 132.822 449.712] /Subtype /Link /A << /S /GoTo /D (module-superlu) >> >> endobj 427 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [243.626 206.288 335.283 217.302] /Subtype /Link /A << /S /GoTo /D (superlu.superlu_context) >> >> endobj 431 0 obj << /D [429 0 R /XYZ 72 744.907 null] >> endobj 86 0 obj << /D [429 0 R /XYZ 72 720 null] >> endobj 90 0 obj << /D [429 0 R /XYZ 72 562.518 null] >> endobj 432 0 obj << /D [429 0 R /XYZ 72 523.982 null] >> endobj 433 0 obj << /D [429 0 R /XYZ 72 439.804 null] >> endobj 434 0 obj << /D [429 0 R /XYZ 72 286.565 null] >> endobj 435 0 obj << /D [429 0 R /XYZ 72 273.1 null] >> endobj 436 0 obj << /D [429 0 R /XYZ 72 259.635 null] >> endobj 437 0 obj << /D [429 0 R /XYZ 72 246.17 null] >> endobj 438 0 obj << /D [429 0 R /XYZ 72 151.515 null] >> endobj 439 0 obj << /D [429 0 R /XYZ 72 125.406 null] >> endobj 440 0 obj << /D [429 0 R /XYZ 72 97.256 null] >> endobj 428 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F46 193 0 R /F58 217 0 R /F44 192 0 R /F8 267 0 R /F11 261 0 R /F65 266 0 R /F10 297 0 R >> /ProcSet [ /PDF /Text ] >> endobj 445 0 obj << /Length 2897 /Filter /FlateDecode >> stream xZs۸͗HAr~Ho4YHb}w)F>A.bE[z?_[DKf }EHx7 B'^:)i[ lIIQBEh%Nx뷂^D,& ܬ4/[3YH"%Gm%>e'1]h,WVfen3ӹΖ: (:OPY:I8UMdq< PG GDYGD)U4vRж)`՜++ͽKc\qZ p kqgNv"ģ y-vksF 5}\oK<;Tlfqe샿6p4 R+yj$S.d Gz;^Ȉ*zyr`1Ŀ(^fDf^XA,<[,(aƄ+;Q<fI8¤5k`Q?^TBc Įaa+@A$r⇟x 0 `Yx]K04}\M0J"K-=s}`Vן) \\q2ԪH}%-`eCɉl0NF(WɃIvͥR_t_ C{6(N|qmmbW$S N@-vVf`-Sf_Ik}nh4xM5W풖#8G.Y,X`@G_^cHuUQ聎N `d)T燐2Pg/̅m!YfUi>!HZ7yzF* V[wە+lr2.kte{ |`)hDFrakY5YiY$hr(^ l[JЏl5 r F8hz!6M)@4;KPZzSc&(ͳ˕6;H?piK b]l +)aiGo4knMl`l/9ĢLL #n(sۀgI8[a502 #hޚECg5Ay9- =ܗK7v^E5I}rW?^53.oJ.ǪRU?"\?>M!+~*xf2>ft^5MOd@: Dh 1H6-Z]G>ZEhnZ[a=vb[yMJ X4`aq'O~ȇ>pU;&[0:mȡQWU5B='bAxyvz:?sm_uBURSru{[]>qc%v&Sà X`u5vNw<ק mK:,4WցI7In<k_Ks endstream endobj 444 0 obj << /Type /Page /Contents 445 0 R /Resources 443 0 R /MediaBox [0 0 612 792] /Parent 420 0 R /Annots [ 441 0 R 442 0 R 450 0 R ] >> endobj 441 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [126.346 575.549 254.364 586.453] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 442 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [466.427 432.915 540.996 443.819] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 450 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 421.079 125.11 431.525] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 446 0 obj << /D [444 0 R /XYZ 72 744.907 null] >> endobj 447 0 obj << /D [444 0 R /XYZ 72 720 null] >> endobj 448 0 obj << /D [444 0 R /XYZ 72 697.983 null] >> endobj 449 0 obj << /D [444 0 R /XYZ 72 630.182 null] >> endobj 451 0 obj << /D [444 0 R /XYZ 72 408.138 null] >> endobj 443 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F46 193 0 R /F58 217 0 R /F65 266 0 R /F8 267 0 R /F10 297 0 R /F44 192 0 R /F72 276 0 R >> /ProcSet [ /PDF /Text ] >> endobj 458 0 obj << /Length 2749 /Filter /FlateDecode >> stream xZmo8_!ؽIl[t.٦mme+Mo(;nf433xoO~zCb/A 'ܛ,< CEa„zrWoj٨cDr]I,^jٕEj` 2}ɟ' W/@4[5jQKHG(F GACf5iU+#"KSI:mN^QVkLߦ\_l:k1aosP1y*˕~e&P?(5Lr[5? LT{כE-&}] 0(\ /AWFMHX!\dIbǭ >c+F& ^bAZxkM;|Ap/31Hwjj-HG ۺV($ cxk8`$IK;t{Dt rWyi}btҌ95K{mZi4Z*=ZeQ0@ IKz)mgf{N* eFBڟw ߝv1H>J n:/u5I!-=$I{2w12\X$ڌ6?ĬLU%6Fś06%) .cO"'vVn* 1 Tf5dG)Mj]gS&ڞB?g$,4_aC* !逬|\1ƣ뷟oNnj'c>pYջqdO ]M@cPtB2'n?>L渥tޟ`xm-LMoV: {03Ių7>~xPj?]_ Z/NTҭ25G!Xy%=pv%w l#dm(^{?[R^k0;9g$ 9t,!;d=Q|и7>؊ogeT`VzRzAf-{F֝ZPhmeCA,Yoq7CWJ4[=m&\]Td T8 der; o%"ѽ$![?Z/F7h4Ddopq!Uy_LE#^A6A}Kp4SSY-;ptqSw|OQV0<:.ΰax`Z-?i[碞f]<[nvPt]&EI&oINkv!= eiWV"$Ctcb^R[\o"3-a$Q> endobj 452 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [228.88 540.875 267.963 551.779] /Subtype/Link/A<> >> endobj 453 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [231.371 442.064 275.207 453.078] /Subtype /Link /A << /S /GoTo /D (module-superlu) >> >> endobj 454 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [243.626 175.547 335.283 186.56] /Subtype /Link /A << /S /GoTo /D (superlu.umfpack_context) >> >> endobj 459 0 obj << /D [457 0 R /XYZ 72 744.907 null] >> endobj 460 0 obj << /D [457 0 R /XYZ 72 528.269 null] >> endobj 461 0 obj << /D [457 0 R /XYZ 72 151.359 null] >> endobj 462 0 obj << /D [457 0 R /XYZ 72 125.499 null] >> endobj 463 0 obj << /D [457 0 R /XYZ 72 97.349 null] >> endobj 456 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F72 276 0 R /F44 192 0 R /F31 150 0 R /F8 267 0 R /F14 262 0 R /F11 261 0 R /F7 395 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 472 0 obj << /Length 2581 /Filter /FlateDecode >> stream xZ[6~_!܍D@fsi&"-٦Ȗ+ɝCRʲ,&)^s?4=tw<D#bWfir+HRK0ُ'7 8, R6]BZ$AJ D"`$CǷ*ڀ5oK.-NG@G%$_~vʋf`jE< kmϩRݩN9$ c E6cJ]"p-uhrųCL0]t\FyS٪CW֩?GvO#&' A$3IFNX:CHy!!ȷ^]GqG1R<󼘠fU=(t\wozm>}| _z ͧM:bʁKVL'cvC7ϋH=h%"ՏrUD[žl2hþ3X>|2N]b4> I$A5䃲ksQ\&]{aP`ѳ b_e_7CH˶ZTN?(_*7\锟5Mw+C֋"XF9YG DUcٳnķ"6"Kq1H..!2ڎEVU+a[ԝyQ4dWuϭ~2 )D ZJ'IŚF̸ W@NCl8$OB(LBqrGDB) 3J4@jC(% e,6nJUgH[\4ɲͮ(aevPM~c.*Ai~pw}P&Cbq'ўY` `|]p XXH!&T5IH5urz̤~|;|ID[mCuA[1 B1DO1P ݂MQ/}ۤ7e h+ۯ?Qs/Mv#. {@B} m-f[,XJ4o vX<q%$%&̼'!' SR^& b 4#{!x=vsx7svV%ޱ99 Mﷵ*>?XZF C#"ہ_o6 aIFN:OLĄvӭma*r G7Motjٲa ] Kmh+s!\F clVxf:uQ U[{†pLޚmUZ*4:ȃmzn9,sjp[X*mta7 H{jw h ?ps ҿI7!ޤvU{ VGHyZmU-L`h>7b͛\Uӕf:!AOPB_>F@5طtW"8jڿ?| endstream endobj 471 0 obj << /Type /Page /Contents 472 0 R /Resources 470 0 R /MediaBox [0 0 612 792] /Parent 420 0 R /Annots [ 455 0 R 464 0 R 465 0 R 479 0 R 466 0 R ] >> endobj 455 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [392.556 683.691 430.414 693.878] /Subtype /Link /A << /S /GoTo /D (superlu.umfpack_context.lunz) >> >> endobj 464 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [126.346 450.02 254.364 460.924] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 465 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [466.427 307.385 540.996 318.289] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 479 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [71.004 295.55 125.11 305.996] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 466 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [180.198 228.155 327.557 239.059] /Subtype /Link /A << /S /GoTo /D (pysparsematrix-page) >> >> endobj 473 0 obj << /D [471 0 R /XYZ 72 744.907 null] >> endobj 474 0 obj << /D [471 0 R /XYZ 72 720 null] >> endobj 475 0 obj << /D [471 0 R /XYZ 72 684.687 null] >> endobj 476 0 obj << /D [471 0 R /XYZ 72 586.336 null] >> endobj 477 0 obj << /D [471 0 R /XYZ 72 547.108 null] >> endobj 478 0 obj << /D [471 0 R /XYZ 72 505.37 null] >> endobj 94 0 obj << /D [471 0 R /XYZ 72 281.537 null] >> endobj 480 0 obj << /D [471 0 R /XYZ 72 203.259 null] >> endobj 481 0 obj << /D [471 0 R /XYZ 72 159.585 null] >> endobj 482 0 obj << /D [471 0 R /XYZ 72 130.005 null] >> endobj 470 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F46 193 0 R /F58 217 0 R /F44 192 0 R /F65 266 0 R /F11 261 0 R /F8 267 0 R >> /ProcSet [ /PDF /Text ] >> endobj 492 0 obj << /Length 2614 /Filter /FlateDecode >> stream xZIs6WHe0 *($'bqpj[Nf."mxˇ;sޜ|}5$qz!#A(I۷9ۊbRT]uucE!Rӏ?x} vCD^dɇIRϭ{.N(pEW"5m'? .iwJ]pGvV(~{uu6ܽ|)jJVKJT:-+45idf7ޥ}z׎v?C/1G*q?\2I>ZgϦpvy@SJ;Fx3tk]P47:98=}RtMအ҈KH@EՇ~%7MluȚW0X*!A0 ދ 4]Q/m3"m!ӌ$mMxg'+T.Bl3 E!$I5gw?Ƚk( ԑpBCnPM5fbP#: B VҊ-h`Ep%C[ R#a8ZF Ĉ^qj*d"mf3ӵK v{WV;>5-r0vqӷyBIgYb[QE!' g11  }cTVнkZ*0m 0Է2cnW5^6)rhgōr'l|Rl!wŔp`mevD-Dv$;$޲o;dۺ |.Jᘥһ]Pw7ݶv!vt"#8r2- f ;#0Ϋ|BHrp,$kҢן<u` ?G $|kwhv}cꆑ찹1[$ŀƋj&9%s8I"?Vhp_Arw t8aax{#+m_PW ԛH,6E[ K,F%#[ih"XԞ|Fv!jȼ,>-a襾tUھHg\[|nZao8km~lb2gjjkGt&k鮆 ~{4ɟ$Q_j8|ۑ(mR|UxI$+-n00^7xhL/ivoOw5+7kdԽ, Q˼zd˙`CPÇ|ɇFtFkbtӯY(vmW/ Ej:3Vdm!FbEYrjYu@ OێD*x3o?ć!^ǼH5Oh2-PTHd`LKkn ~)Wfd| aT_{HP)t;}OǾsyۈw endstream endobj 491 0 obj << /Type /Page /Contents 492 0 R /Resources 490 0 R /MediaBox [0 0 612 792] /Parent 508 0 R /Annots [ 467 0 R 468 0 R 469 0 R 484 0 R 485 0 R 486 0 R 487 0 R 488 0 R ] >> endobj 467 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [244.362 670.872 295.6 681.776] /Subtype /Link /A << /S /GoTo /D (degll99) >> >> endobj 468 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [298.588 670.872 337.652 681.776] /Subtype /Link /A << /S /GoTo /D (dgl99) >> >> endobj 469 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [340.641 670.872 372.511 681.776] /Subtype /Link /A << /S /GoTo /D (ld03) >> >> endobj 484 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [87.88 636.181 115.327 646.527] /Subtype /Link /A << /S /GoTo /D (slu) >> >> endobj 485 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [125.011 589.042 324.263 599.054] /Subtype /Link /A << /S /GoTo /D (directSolver.PysparseDirectSolver) >> >> endobj 486 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [305.98 220.247 349.816 231.151] /Subtype /Link /A << /S /GoTo /D (pysparseSuperLU.PysparseSuperLUSolver.solve) >> >> endobj 487 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [431.469 136.64 505.192 147.544] /Subtype /Link /A << /S /GoTo /D (pysparseSuperLU.PysparseSuperLUSolver.fetch_lunz) >> >> endobj 488 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [515.093 80.902 540.996 91.806] /Subtype /Link /A << /S /GoTo /D (pysparseSuperLU.PysparseSuperLUSolver.lunz) >> >> endobj 493 0 obj << /D [491 0 R /XYZ 72 744.907 null] >> endobj 494 0 obj << /D [491 0 R /XYZ 72 720 null] >> endobj 495 0 obj << /D [491 0 R /XYZ 72 621.032 null] >> endobj 496 0 obj << /D [491 0 R /XYZ 72 348.582 null] >> endobj 497 0 obj << /D [491 0 R /XYZ 72 334.66 null] >> endobj 498 0 obj << /D [491 0 R /XYZ 72 320.739 null] >> endobj 499 0 obj << /D [491 0 R /XYZ 72 306.817 null] >> endobj 500 0 obj << /D [491 0 R /XYZ 72 279.039 null] >> endobj 501 0 obj << /D [491 0 R /XYZ 72 249.113 null] >> endobj 502 0 obj << /D [491 0 R /XYZ 72 221.244 null] >> endobj 503 0 obj << /D [491 0 R /XYZ 72 193.375 null] >> endobj 504 0 obj << /D [491 0 R /XYZ 72 165.505 null] >> endobj 505 0 obj << /D [491 0 R /XYZ 72 137.636 null] >> endobj 506 0 obj << /D [491 0 R /XYZ 72 109.767 null] >> endobj 507 0 obj << /D [491 0 R /XYZ 72 72 null] >> endobj 490 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F44 192 0 R /F46 193 0 R /F58 217 0 R /F65 266 0 R /F10 297 0 R /F8 267 0 R >> /ProcSet [ /PDF /Text ] >> endobj 523 0 obj << /Length 2647 /Filter /FlateDecode >> stream xZ[s۶~[LKf9m6'q -6ǼQY\xd/5ߺb ߘF˶.u]08\ݬ,m*3h"`@ھeik>ӥ\پҢZp cexz5e󍂏#Em}`MYBֆ|ːn,izf6-$B1 PcCjC_ @$5] 15!Dy"Cu2q~ mdt_w0FHU3fB1"0 2t;5:R]X|!!d;3y{%-ֹ| 6zj5MUF}׶[}^@9º@fB <4|=0S5 3@PeLͲvEʑY1tc˫ƶzl^gSMx4 kb^H {C#&$G|Hbil33'ANQ<#r-˝@<c7<Vf (bPHm#e]3k ,Qd 1֡mр++\V 82OÈ8$T|rG `L;c~o( {9c)>^7%n sm0 bWltKhƢW Ooǖdʪ.lg_8.t 8=# %1ƴgH1v@`*vR u1uwbnR3h}((KTޝZ")$#ZbA{7q=4KbfDG.cɞ{Q8Dc^,qorG)>Gs蜊b⃝'8K3PS-M͖Z`Y?9I(pzZz~0D)ߡ2'Ux*/>UL<å vPce pؽy{ܯhrwrN0/EUCZeWuu]l]w!Y XòL@x)~ĘL3MbX02e(A"]p6 7p(L"eN0DD00m AgRfU퐋K1+gZRɉXz NrYM[wfktZ4hLn& Eͺ?- :dV&ŘI`_ΓyEN}]qN7f(Q&2q_MյͻWgAl±ӯ粕5|roPq(츞u  RmUn]󂆊+4Ψu1?t~N54OdjꩋпؘLqc(l GB#T.o˺*۾4A`<{1j$t"VL?<JH]iXEL>hPUBaNw봰j :ӞL }/m}9v٦UCu 2qRS(LUkVBglm宩KKng&m&{1uic|^ߢ ri->~|s gN!B]ޓ Qxzf} x*Q3R,P/ICGwoΨmYyGa,QLLTڗʕikש[MuECAcSn.σ:-o^vs }1)Z[jcdޢeWSlroUgϙ鴶4BъӒP'l^jSKczq7c('rt+Hֵl`bb2BnιPfB,gN"~U—<ͯ6{cF'oaǒ>f1z4RԿU#J>+㫬 e͡ Į6;0 jI7UL|@8ǂ(3泚;;?6ƧkG+O--ObC!'(=F=5&g٫}d*WS T4TaG[Ujѹq~:Zo2 w,;_,ySD=1}Lt;SkHo6{vuYrKƬ endstream endobj 522 0 obj << /Type /Page /Contents 523 0 R /Resources 521 0 R /MediaBox [0 0 612 792] /Parent 508 0 R /Annots [ 489 0 R 513 0 R 514 0 R 515 0 R 516 0 R 517 0 R 518 0 R 519 0 R 520 0 R ] >> endobj 489 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [295.241 682.974 315.166 693.878] /Subtype /Link /A << /S /GoTo /D (pysparseSuperLU.PysparseSuperLUSolver.sol) >> >> endobj 513 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [239.819 611.415 367.341 622.319] /Subtype /Link /A << /S /GoTo /D (pysparseSuperLU.PysparseSuperLUSolver) >> >> endobj 514 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [336.894 329.379 464.912 340.282] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 515 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [304.775 259.812 334.981 270.716] /Subtype /Link /A << /S /GoTo /D (d04a) >> >> endobj 516 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [337.97 259.812 368.734 270.716] /Subtype /Link /A << /S /GoTo /D (d04b) >> >> endobj 517 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [371.723 259.812 404.699 270.716] /Subtype /Link /A << /S /GoTo /D (dd99) >> >> endobj 518 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [407.688 259.812 440.664 270.716] /Subtype /Link /A << /S /GoTo /D (dd97) >> >> endobj 519 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [87.88 225.121 118.097 235.467] /Subtype /Link /A << /S /GoTo /D (umf) >> >> endobj 520 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [125.011 177.982 324.263 187.994] /Subtype /Link /A << /S /GoTo /D (directSolver.PysparseDirectSolver) >> >> endobj 524 0 obj << /D [522 0 R /XYZ 72 744.907 null] >> endobj 525 0 obj << /D [522 0 R /XYZ 72 656.085 null] >> endobj 526 0 obj << /D [522 0 R /XYZ 72 316.437 null] >> endobj 527 0 obj << /D [522 0 R /XYZ 72 209.972 null] >> endobj 521 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F58 217 0 R /F31 150 0 R /F44 192 0 R >> /ProcSet [ /PDF /Text ] >> endobj 542 0 obj << /Length 1780 /Filter /FlateDecode >> stream xYKs6WjƂ &u8Kqh aG]9>5_Zu=>rǚ/\Ŕ0:TdUXyv.D"fAO_aXdq̭(|0rߺSR|x&և 6ʮQ0flvVDǧ̢ ̅/zxU v +vQ c* )Li@퓩WN]Mg.uߧ.)eZ7 YKgő ƴ_:}!gn|Iï/`)`XNIR)hJʙl: Uy[/uB$[;`{mz` QYdF, 8J̰0\!{j[E.8DFHcJAU1݆ #3^ūܤ;C@/a]ۋ83e+ ]fXU"]Wb@UX}0`c&@D.t3ʳ͂w+i`z50yB oR|Q%LHƙQă2If dHz߂;flޏx :PDX;>6, e-"jGU^bѣ#pEk |fy[U[h' 衛Bϸxm`IfJD/ٞ"P;<0G%w[F$(9ų/gkiyZ6k>`/Mu:LBiݡLh6j O8X5NOE]DX?1Vm}7FX*Z]-6.;rP =Sq0~7PIXi΋;zTאN;!ކ-.B|G'ҿ/Q,QL,N w^& $ׄ#qlRG7IM߭h5^C,P4{`a)B$5nkm{cLq]ό1ć `)\Wx^C^\;w+ @gb[NqSNAI3+7ޤA驑:atw4$&woo/?hДW?qh;pO ԡ:>6ymQØ@iIQO #ˑC،3X:{ηpW4fvw@l@·Kp0B#]elE)e .#ӷoxY JޙFhD{ *nY p^q}Ԑ^$tQw.7a/z֧nm] RԹgj$7 uEsINj ޘ1ld/ |\2Q[QmY*"[9 ¥> endobj 533 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [305.98 583.348 349.816 594.251] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver.solve) >> >> endobj 534 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [408.047 443.871 499.703 454.774] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver.fetch_factors) >> >> endobj 535 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [241.294 360.184 332.95 371.088] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver.fetch_factors) >> >> endobj 536 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [478.781 94.899 498.707 105.086] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver.lnz) >> >> endobj 537 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [503.084 94.899 523.009 105.086] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver.unz) >> >> endobj 538 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [117.828 82.849 167.641 93.131] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver.nz_udiag) >> >> endobj 543 0 obj << /D [541 0 R /XYZ 72 744.907 null] >> endobj 544 0 obj << /D [541 0 R /XYZ 72 640.135 null] >> endobj 545 0 obj << /D [541 0 R /XYZ 72 612.239 null] >> endobj 546 0 obj << /D [541 0 R /XYZ 72 584.344 null] >> endobj 547 0 obj << /D [541 0 R /XYZ 72 556.448 null] >> endobj 548 0 obj << /D [541 0 R /XYZ 72 528.553 null] >> endobj 549 0 obj << /D [541 0 R /XYZ 72 500.658 null] >> endobj 550 0 obj << /D [541 0 R /XYZ 72 472.762 null] >> endobj 551 0 obj << /D [541 0 R /XYZ 72 444.867 null] >> endobj 552 0 obj << /D [541 0 R /XYZ 72 416.971 null] >> endobj 553 0 obj << /D [541 0 R /XYZ 72 389.076 null] >> endobj 554 0 obj << /D [541 0 R /XYZ 72 361.181 null] >> endobj 555 0 obj << /D [541 0 R /XYZ 72 335.343 null] >> endobj 556 0 obj << /D [541 0 R /XYZ 72 305.39 null] >> endobj 557 0 obj << /D [541 0 R /XYZ 72 277.494 null] >> endobj 558 0 obj << /D [541 0 R /XYZ 72 123.074 null] >> endobj 559 0 obj << /D [541 0 R /XYZ 72 83.846 null] >> endobj 540 0 obj << /Font << /F28 148 0 R /F44 192 0 R /F31 150 0 R /F57 216 0 R /F46 193 0 R /F65 266 0 R /F8 267 0 R /F11 261 0 R >> /ProcSet [ /PDF /Text ] >> endobj 563 0 obj << /Length 2141 /Filter /FlateDecode >> stream xZo8_!:Ś7}ȵ!iPlb[:I&PlIEK 9C{9ABIep}((Yp=.,O*=$]fǾċ8'=O'=! RHa̖'0b~T vR⦴B5 % "aE;6ߞs٘KC!^ l'Js'͛`F i!a4ԯ~{HcXYiDŽPWX9 ;wHV1p@XbO J Qa j)O? 4r 9w-x1zStPgn;#2Ұ}ɇ( MD"" YLqmiTI#R%UΩ~q~ym(dPCKьБ-g673")i ң[Ϲ$dnƍ'Hlfy|[umY Ўb dIH<1P}Xe{ %놊 IVk\d0n:;@82 ;^Ӌ> bSK if-[ ʂf]xVvL`yP&JGIw`r{!>&]# V HчA5͟iEf;n_;^z0q*7@8 8@@^[1{t<u(PU/ G)#QPQnRˠP M>bG|-<4᯲ ʃ<8%ApMWIop&W{׫H9ky] b[ n(5CQO )66MO2[Fl]Yh E_H;{gb ,Ggf}`L9-<&w.IFj/*8YyOWl%fGON7m޲x9\oZY D7Gava[6 @,s0 J\L갭l/ bnڪ(dlHjjM(mha]Dן<\"lk!' !$.M!U/)=l#<򬛋*QݹRA~3W0#XK[.T?)u<&e~>mW.7/UrUr k2kRR]U{PD`[JG> endobj 539 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [377.392 694.929 397.318 705.833] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver.sol) >> >> endobj 560 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [239.819 473.989 367.341 484.893] /Subtype /Link /A << /S /GoTo /D (pysparseUmfpack.PysparseUmfpackSolver) >> >> endobj 564 0 obj << /D [562 0 R /XYZ 72 744.907 null] >> endobj 565 0 obj << /D [562 0 R /XYZ 72 518.66 null] >> endobj 566 0 obj << /D [562 0 R /XYZ 72 245.607 null] >> endobj 396 0 obj << /D [562 0 R /XYZ 72 245.607 null] >> endobj 561 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F58 217 0 R /F31 150 0 R /F44 192 0 R /F65 266 0 R /F11 261 0 R /F8 267 0 R /F10 297 0 R >> /ProcSet [ /PDF /Text ] >> endobj 574 0 obj << /Length 2316 /Filter /FlateDecode >> stream xڽYrF}WL03Hjk'z#Rvj $!0K~`W`0>}A[xψ~Fq%%~J>F5zC=ԳROHֻ:_Ͼi/Cɤw}㉐: /(~ooT\Hf//0;;3z /U _iES Oj]6폜yA N `86 do.>S* Vp)Y`p+9 f:.͈E}mYUI;ڸKm^$&}gI1'J {#0,}]Emlt)Ԏ6yy8uJ+8)Ofqr;y,v؎jP*UU.J 8hQU$b:\Yn z'\+b:3@/l/v;DX0!/ֺ/1"!tRABI ,tȓUbbj3̙6 &cLf=l" 6'$"F(PhBpU)aY|IӴfG'BXT j3 jKtPgêE*YqU9t$m쳕AF 'N8ZwGC9etן.muo}Ru3If D)o{9WrJU~t' C֠bow}e!3bCgÓoRT*ybgnl.8nbY 3>?k!?԰ ̈9HJTD[\'Wk 1:} gR9ˌqvh j'4n[it .@s nY?.!~vQikXE#ji^;3)4~Ćd)b͆YU lǕZ:VIFnQޅ:eUIuRp].81dR>Y%(ZMԲUgPhZ5PDIo~HFa=[X{T뾻@n`.%l"pTeIt\)8ӗdNHW`7Vk2̈,ZjVE\&}u[>naWo6!ɔ뻯H`zxn5AmMK7g ll92ZλN=h#!mq1lsݻteЧBe⅑R1;3OFRLg8> BtOLNA?6~,wʽ19n UQK2yڜ~tSæXujw<;.we/tHу .Je/}j_q, ;Qsl`> Wc⋐ endstream endobj 573 0 obj << /Type /Page /Contents 574 0 R /Resources 572 0 R /MediaBox [0 0 612 792] /Parent 508 0 R /Annots [ 567 0 R 568 0 R 569 0 R 570 0 R 571 0 R ] >> endobj 567 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [269.633 311.139 284.079 321.669] /Subtype /Link /A << /S /GoTo /D (equation.7.1) >> >> endobj 568 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [302.351 311.139 316.796 321.669] /Subtype /Link /A << /S /GoTo /D (equation.7.2) >> >> endobj 569 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [239.397 285.236 253.842 295.766] /Subtype /Link /A << /S /GoTo /D (equation.7.1) >> >> endobj 570 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [424.076 273.281 438.522 283.811] /Subtype /Link /A << /S /GoTo /D (equation.7.2) >> >> endobj 571 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [218.151 119.527 285.468 128.394] /Subtype /Link /A << /S /GoTo /D (itsolvers-page) >> >> endobj 575 0 obj << /D [573 0 R /XYZ 72 744.907 null] >> endobj 98 0 obj << /D [573 0 R /XYZ 72 720 null] >> endobj 102 0 obj << /D [573 0 R /XYZ 72 562.518 null] >> endobj 576 0 obj << /D [573 0 R /XYZ 512.424 498.607 null] >> endobj 577 0 obj << /D [573 0 R /XYZ 520.912 491.633 null] >> endobj 578 0 obj << /D [573 0 R /XYZ 253.956 439.827 null] >> endobj 579 0 obj << /D [573 0 R /XYZ 520.912 432.853 null] >> endobj 580 0 obj << /D [573 0 R /XYZ 72 361.266 null] >> endobj 572 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F31 150 0 R /F46 193 0 R /F65 266 0 R /F8 267 0 R /F11 261 0 R /F58 217 0 R /F44 192 0 R /F14 262 0 R /F7 395 0 R >> /ProcSet [ /PDF /Text ] >> endobj 583 0 obj << /Length 3113 /Filter /FlateDecode >> stream xZoF*f\>Czi^W"$bC*I573|<~3np[}UҤ[znOl_&eΫ!m㛱n] Nf8P4eݸ?xBE=Ā TsH<:'dAS6"b3Ps}=F*X.~UETنk2XgKYh[݊YҧXR#d,?K-+6OkX_Ԣ$6M9*iܞ'_ _F#UYq,e,Nk"P&=$tO?;Z~߮F?Ed܅G3w0*};֢Y(I҃}lHvFS%O k:) dct~8nÁo}LQ0+k uNI1ozԶ*㺬b"O{Z-Y.9$/n :t"I\AwpUñ }5>fR bdR"bA(tOBΜDP#E?+эRV2u`p9kEYdB{91}]7Ȏ˪퍘 G掆Q!6FӻJ:Bu&"U@fߔ`b";1N1LaGXS1F$leƚx֥t4vxjuy^Z0/;MtCyBtp*8V QMF@&KaZ`&Ĺ ʁDQY=D NܤU}@V8C K36w_b(H/dl(B!h vhp;|wJP$):]RSW26}!&Ks鼜|\ ${ly[%LM$0l-xyJV扄(-ѫ +HZ"p3`PSwRy3OpUA$>e~uI5M2e fuJtJO<␧̘i!4^xoXKkoۗj$^ۑNa-~Ne]h_zzVSx(Ju84p}ondU}tdI&԰a;uV=1NqEe:8\=)o|j":;V{a0E's"f: 'tfwr6{NEO']NsgΝsԊ(R"Ԉ$kJ2zm#Й$r^4ʶud9goiZ:NډKaaTPBI2~]V\FN«X&P^:/5ݢT Е0ht[2m^}/&<;wr߮![e嶜Q!4/-B7YڻN2rR;0+HMKq̖ڇkG֥ 3륧5!f!4COθt A ]= <,7xb&W$'t$]B]yl'V}',l?#i )5-Gޖ8? DC1X^΢(,ϏAX]:A=g pLwŜԢ sF*O VK){5$|DPK3C};Gň.bITi%\WeA}!Ok>K$9 & gCBfO]GGD>.gV̾Y3}:: ?2gCF"pNG7@YtW }m&6Yo(9p]=ص4d4r&ȶ|_&780t&ln6*ٴ 9aQUK-N"Xvӫ  A+Dx=!+j]͌5/CŒ:Je\kNZK;fr8o R:~X~0sEq$w4|GꬭHpy:p:F$A- ~(݇v&Hv90_G$vgM,$8~CpXaRzTPH* R\W@mȴtHD%?J2 /&x [2bz[T+G}pA[ߠ{L]P6EvmLe@T4P d#F M2L@#^Ǣm'\o&Ԣt{~|)`ϧfzd6XEm?~?uNDqiaO=_M_ w;ߔfS2B6oF TQTVS*8Ek|pk}TX' їG{@04L> endobj 584 0 obj << /D [582 0 R /XYZ 72 744.907 null] >> endobj 585 0 obj << /D [582 0 R /XYZ 72 349.301 null] >> endobj 586 0 obj << /D [582 0 R /XYZ 72 319.166 null] >> endobj 581 0 obj << /Font << /F28 148 0 R /F44 192 0 R /F31 150 0 R /F46 193 0 R /F11 261 0 R /F65 266 0 R /F14 262 0 R /F8 267 0 R /F13 394 0 R /F7 395 0 R /F57 216 0 R >> /ProcSet [ /PDF /Text ] >> endobj 589 0 obj << /Length 928 /Filter /FlateDecode >> stream xڽYo8+(1KR$%Co,]"1(ɿ!R ޶!5~sP AkDū;IB`sb`FhU{ͺ@p$xC>˶9sOR٨@1,xZ|[P0GE121Q^/.T"8JZ52B/>.w"׭|z@ 4B18Qr cO eHJec9Jy{J9#!R&7X"ܖ'~P3 0Rp /<!ۯZDEc-YRS|̹\՗~cٟe.}SX w܏y. Dq's'p& f)*x|?A*^խO[}uٜB"<:m1.w`tOJ3*ɃfqļM*CPz^mJ.#I-MHI(1uSB,oDžvǵ?L nMe\fư> endobj 590 0 obj << /D [588 0 R /XYZ 72 744.907 null] >> endobj 483 0 obj << /D [588 0 R /XYZ 72 591.061 null] >> endobj 587 0 obj << /Font << /F28 148 0 R /F46 193 0 R /F31 150 0 R /F57 216 0 R >> /ProcSet [ /PDF /Text ] >> endobj 594 0 obj << /Length 223 /Filter /FlateDecode >> stream xڍn1{?Ŗ[{* AQ>N+"H5hvv>=T84ڄX.tDfl첿²jXxt[9꯮A0j!Uy'oاPY.{UhUU1X_noqj&aQ endstream endobj 593 0 obj << /Type /Page /Contents 594 0 R /Resources 592 0 R /MediaBox [0 0 612 792] /Parent 591 0 R >> endobj 595 0 obj << /D [593 0 R /XYZ 72 744.907 null] >> endobj 592 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 598 0 obj << /Length 2075 /Filter /FlateDecode >> stream xZ[oF~T*IxiqlH긿g8C7)bQh\ss΃wW^"pq|#zy)`eٛ$ɖT,J.b=2˳NRsmŇF̦ʊMߴS :GbIBUll6*eE=?KVDRdw8(y@鑁0,h3d_G#+GIlcN Q@0K.8ع{A` 5 GktR6=iFǮG| aH{#.dP"3 I ɒhuףhDmz6سe Dys>Фf)?a: vk &nm7o3+drަvaqmf8G/@ij.}c=m.@{G]MPwoKig?F cA_X=9 񝆾˷¢wUo6z^[MtmQic# Z/b#N>{鰕bP.s?IP/!YQovx =HR@bϞzyf`hmDth?jsJaGohhIcDXsx/d:xH]K0Y"@C]d->Lx!ϐ}uga/EC buY㸩p f48{wDwʞB/.hEX8(nufd 'PQ[.; ]-}6PuXFtXS^[#8Hmd58Ak40v$NG8|0h|ZN&] B 4t2wm]uݡc>_NuxNs5~ *.ccFy|&켤koG[#/AaߧD- Y =ҤD endstream endobj 597 0 obj << /Type /Page /Contents 598 0 R /Resources 596 0 R /MediaBox [0 0 612 792] /Parent 591 0 R >> endobj 599 0 obj << /D [597 0 R /XYZ 72 744.907 null] >> endobj 106 0 obj << /D [597 0 R /XYZ 72 720 null] >> endobj 110 0 obj << /D [597 0 R /XYZ 72 532.63 null] >> endobj 600 0 obj << /D [597 0 R /XYZ 72 494.094 null] >> endobj 601 0 obj << /D [597 0 R /XYZ 72 325.317 null] >> endobj 602 0 obj << /D [597 0 R /XYZ 72 214.258 null] >> endobj 603 0 obj << /D [597 0 R /XYZ 72 184.206 null] >> endobj 604 0 obj << /D [597 0 R /XYZ 72 156.311 null] >> endobj 605 0 obj << /D [597 0 R /XYZ 72 128.415 null] >> endobj 596 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F44 192 0 R /F46 193 0 R /F58 217 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 608 0 obj << /Length 1969 /Filter /FlateDecode >> stream x[Ys6~#ձ6mzLi+6;TRwA/KM̘a$a^]Jnf#4n4񟫰p:ꨆtatWΧ> %*hW9*84 xݯRL@!A}ܳ4yoԽf6Xޓ@! -վ{kYyCg<ztz0$eiYz$;y-Nhtm]Bw_JF@ͨN2zy`jrW;i|&K{{ `(&i" .K*g8$j؞S}R!*!<2}Lߗ9?􎆩e$sgV)dmYAٕ|p3G7-k3 忆^~E=BTJcҺjߘ,8 ybG$dW]KJ Zo3u305#g$xFȔ2TBB*_ ARfD ?h$clsVI]g!hHB~\ ]2j(to+Oc]`N @Ʃ%W%_qY,po܅-̨of7j` ekЖ,}$ŝwaro6R`lў2]n44@z!(e~jT.zLAvp** ݊za%Å^ݖ T-L5I?iB~c[ꭦQψjmAEHi8REmC{)CQBZ@)v>eU7%hDËqZH "d(f҇oCHAgrO^fIDmtxJG(&?E_QTg/Ka&nJ tE8#{{T©vӶvwH5ca{ v>cw4_M݈W{R 0MY_ endstream endobj 607 0 obj << /Type /Page /Contents 608 0 R /Resources 606 0 R /MediaBox [0 0 612 792] /Parent 591 0 R >> endobj 609 0 obj << /D [607 0 R /XYZ 72 744.907 null] >> endobj 610 0 obj << /D [607 0 R /XYZ 72 611.466 null] >> endobj 611 0 obj << /D [607 0 R /XYZ 72 581.413 null] >> endobj 612 0 obj << /D [607 0 R /XYZ 72 553.637 null] >> endobj 613 0 obj << /D [607 0 R /XYZ 72 525.623 null] >> endobj 614 0 obj << /D [607 0 R /XYZ 72 497.727 null] >> endobj 615 0 obj << /D [607 0 R /XYZ 72 469.832 null] >> endobj 616 0 obj << /D [607 0 R /XYZ 72 441.936 null] >> endobj 617 0 obj << /D [607 0 R /XYZ 72 245.603 null] >> endobj 606 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F31 150 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 623 0 obj << /Length 2239 /Filter /FlateDecode >> stream xZ[o~[ p&EhFAKkD$gR,v#j;3;;ͅuN=;=M"2:s*`v(x1Q9n%eH\~5Q)cnM"~!ȌيE20WFzX{#pB6R. USgE$F$ `g*fCeeqw]ƶ\k6`i,Ra}7n,QJi똟kf ƳEX{ʏ}%ʼq^>qC[Dk,`dS@*\:sl1`ƭ7`|͓斐.}3 n'sPl#Ns)_1Сqgu7KLPyԍ{C|wU~*{6i]f_J4XiffkPZؔ@oI(N&">&CVuǓwzBpw*e:#E]!ϯ] BUV߻O?;Ռˀąr:|d R,qHtôc7= @ )Q;-w6I-,>pjMc-5WjFlh CT2bgc3c>"<S[y Y?TZ%V;;+5*h?md#Q^BW!.ofYVhVpݗt]7#7x­邡Xf KF<3ve䫹#wEFqC;n=qso ']mK.TpVww o(NLB0) &X<%3g&?0XN3 rWli<"3cgmQ͉L\\{>@o-ZA4mBZf0CIfbO6]T{m!HlJjw5#U3;\X# :qඑ_ }֯)yT%JMʘ,wwEv-mNv1XQTCIӮ=j!)L?$dQ$3>Tg'u;!aQ +}EA?/i /Yl'H'PdǤZ90I2F oF"ڧ3QSS* ~xMzϛʩjDUvp$&+D]^ SHXz\6=ԼeWk 3_B[]͒~ѦM^M<_y֌w]iѼ7]4_6_̃ PQӹSZ.Kɚ (G,ӲL|t3pccݗ%xir%pS\jf#qz ejJwWƏc/M=5]c?xGB?> endobj 618 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [125.011 516.274 300.353 526.287] /Subtype /Link /A << /S /GoTo /D (pysparseMatrix.PysparseMatrix) >> >> endobj 619 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [125.011 371.054 300.353 381.066] /Subtype /Link /A << /S /GoTo /D (pysparseMatrix.PysparseMatrix) >> >> endobj 620 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [172.044 109.644 300.062 120.547] /Subtype /Link /A << /S /GoTo /D (spmatrix-page) >> >> endobj 624 0 obj << /D [622 0 R /XYZ 72 744.907 null] >> endobj 625 0 obj << /D [622 0 R /XYZ 72 667.26 null] >> endobj 626 0 obj << /D [622 0 R /XYZ 72 616.267 null] >> endobj 627 0 obj << /D [622 0 R /XYZ 72 572.277 null] >> endobj 628 0 obj << /D [622 0 R /XYZ 72 544.2 null] >> endobj 629 0 obj << /D [622 0 R /XYZ 72 429.213 null] >> endobj 630 0 obj << /D [622 0 R /XYZ 72 398.979 null] >> endobj 631 0 obj << /D [622 0 R /XYZ 72 166.269 null] >> endobj 621 0 obj << /Font << /F28 148 0 R /F57 216 0 R /F46 193 0 R /F58 217 0 R /F31 150 0 R /F44 192 0 R >> /ProcSet [ /PDF /Text ] >> endobj 634 0 obj << /Length 232 /Filter /FlateDecode >> stream xڍPn0+H7\yj8X` R4N__78j4;pGƖn@* 4ɪ%} 'eg9jC[&q/nf+;'3K^8,-Y8l"?ΊYՂT&b Lo/JP]moQLL= Y :ٻSŰ,W#gw$> endobj 635 0 obj << /D [633 0 R /XYZ 72 744.907 null] >> endobj 632 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 640 0 obj << /Length 535 /Filter /FlateDecode >> stream xڭSM0+}L|Vݤ JD(Ii쥕z3߼y3)̣~Z b1DF ⬓5xm#jM{,gz,`isqYW?:ݗ`h֞mQ8pT~]WnPYS]q8#묜˱_OyIAo_Wd_}5! c- y[J endstream endobj 639 0 obj << /Type /Page /Contents 640 0 R /Resources 638 0 R /MediaBox [0 0 612 792] /Parent 643 0 R /Annots [ 636 0 R 637 0 R ] >> endobj 636 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [95.91 513.846 120.498 524.75] /Subtype/Link/A<> >> endobj 637 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [95.91 493.921 137.753 504.825] /Subtype/Link/A<> >> endobj 641 0 obj << /D [639 0 R /XYZ 72 744.907 null] >> endobj 114 0 obj << /D [639 0 R /XYZ 72 720 null] >> endobj 642 0 obj << /D [639 0 R /XYZ 72 472.999 null] >> endobj 638 0 obj << /Font << /F28 148 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 646 0 obj << /Length 245 /Filter /FlateDecode >> stream xڍPN0+hKĬvOW-(mcÂ> endobj 647 0 obj << /D [645 0 R /XYZ 72 744.907 null] >> endobj 644 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 653 0 obj << /Length 1708 /Filter /FlateDecode >> stream xڵXs8~_圛gĦ r\+p<}VHn: +ەXYI]HB$Ȃ,X/A-KVPu^|E7w)X+6jɢɂn)*GDNp}heUBeKT5CVƢ.)T9QpP"+8E ӐtcE UWn8^4.e+*.@P.X[^ ӱa DӴ~fC@9?(2cтȹ ARLaURTȌB*Kv^/.I?$ML$g|ES}/T Ar*")PfQwvQgd\'"_Ȣ%|8IL:-}7U/cZyT~(,<zHMG[۴1+4%9,+iLq')[!fdمiЗ6o@x[C1本HW5Kqb[Ѻxm@u+:e[(΢ϓYnqI F}-io/s: ɞ3c"tkW'E⼎:;oj\QV {q3pTy8=hMwj_ My1dz4PEYq:Xyq{qX޶E?u KUlC{㊾ᘜPKj%9򓣪obX3ݐz2ܩ3'Ds6O;#:7J @;}[j{̣i8!\`lNMP{"n WP!{'CpS/;ymw~0t،w;@dYUC ' ۽w"h{p<u8os.LRRk.cdM6/ ([\ %X8;x::W`tOޞf翩Uܷԇh 3ߟ5tig~+U 0݋p@9qS|vs=hw#'^1h|ੋ)yq4w«)|4Ay@Pi$љ-ܙM ytCHazhVgE%g[럪Wȼ2U{8{>tOϒcMu.&MiKЭܽ:W|r[(奬AL>F?ID5:dvKE8&q2M?Db"/ 4t'f :-POf{x]5XV{ QW=-,hcv3m`,m`vvm\guA ጿTcS!T3-YB(RQUmВh?ZgTsQ$T-V\$x^ԗ Kנ#W 2L+jXf~sWuevMi#ti@nmHԲd g[tpk#q'k|CSs=jYpC /6,v;nt7&hEKQUef}$n endstream endobj 652 0 obj << /Type /Page /Contents 653 0 R /Resources 651 0 R /MediaBox [0 0 612 792] /Parent 643 0 R /Annots [ 648 0 R 649 0 R 650 0 R ] >> endobj 648 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [353.84 219.713 424.176 230.617] /Subtype/Link/A<> >> endobj 649 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [344.199 202.089 373.867 212.993] /Subtype/Link/A<> >> endobj 650 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [71.004 178.178 322.926 189.082] /Subtype/Link/A<> >> endobj 654 0 obj << /D [652 0 R /XYZ 72 744.907 null] >> endobj 118 0 obj << /D [652 0 R /XYZ 72 720 null] >> endobj 651 0 obj << /Font << /F28 148 0 R /F46 193 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 657 0 obj << /Length 211 /Filter /FlateDecode >> stream xڍn@{-m),{܆Hu2G@Qs`\Di4;;|w#vcn؀_eP r>TsH{l]/P7Eo7Pt.X}zuT:~"m% eKU@ ĸ;V3Ey)0j-b,www)M8=ӞaN&2ԑmWM endstream endobj 656 0 obj << /Type /Page /Contents 657 0 R /Resources 655 0 R /MediaBox [0 0 612 792] /Parent 643 0 R >> endobj 658 0 obj << /D [656 0 R /XYZ 72 744.907 null] >> endobj 655 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 663 0 obj << /Length 456 /Filter /FlateDecode >> stream xTMo0W1`|BUQhòIANTۥ"!!yof> endobj 659 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [356.132 506.801 375.459 517.705] /Subtype /Link /A << /S /GoTo /D (todo-0) >> >> endobj 660 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [346.877 453.927 366.204 464.831] /Subtype /Link /A << /S /GoTo /D (todo-1) >> >> endobj 664 0 obj << /D [662 0 R /XYZ 72 744.907 null] >> endobj 122 0 obj << /D [662 0 R /XYZ 72 720 null] >> endobj 661 0 obj << /Font << /F28 148 0 R /F44 192 0 R /F31 150 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 667 0 obj << /Length 217 /Filter /FlateDecode >> stream xڍKo0{%Xv- !LDx%7$PF`"ނCe a &K l`)?~S~Q:eT}v^kU^펇^}}̻FBV0 BKm6@dnMc}{XOAJ })aԚ[Δ!I=ZiT˃K[f!9[{+YS#O endstream endobj 666 0 obj << /Type /Page /Contents 667 0 R /Resources 665 0 R /MediaBox [0 0 612 792] /Parent 643 0 R >> endobj 668 0 obj << /D [666 0 R /XYZ 72 744.907 null] >> endobj 665 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 671 0 obj << /Length 324 /Filter /FlateDecode >> stream xڝ;OAS7̾KB\@ XF?=0J;y}XPp|(IBwbJ1(kƅ$0n^u bt| %pѐ_wgeq'xNq 5:ŭPL$EiLUA<5XcG_e>t>J&3PQ9@n-HmGf{dи -%++ )^@y>u̪ ^KZ-y&+6i$Av|:?~I!`?9x endstream endobj 670 0 obj << /Type /Page /Contents 671 0 R /Resources 669 0 R /MediaBox [0 0 612 792] /Parent 673 0 R >> endobj 672 0 obj << /D [670 0 R /XYZ 72 744.907 null] >> endobj 126 0 obj << /D [670 0 R /XYZ 72 720 null] >> endobj 669 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F58 217 0 R >> /ProcSet [ /PDF /Text ] >> endobj 676 0 obj << /Length 221 /Filter /FlateDecode >> stream xڍ;O0{-m)tI Kc@jW^]v~C V;} 5 Tç$*_ڏ!shOq1(&u`LO$kiB; Pkm\=<ǖhIA5Ip6$}[pd!)*CnۦqCBR6 R endstream endobj 675 0 obj << /Type /Page /Contents 676 0 R /Resources 674 0 R /MediaBox [0 0 612 792] /Parent 673 0 R >> endobj 677 0 obj << /D [675 0 R /XYZ 72 744.907 null] >> endobj 674 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 682 0 obj << /Length 1424 /Filter /FlateDecode >> stream xŘKs6<3' DcW78=_|wiolyqVVaelyqѶ~vEb0[o;Xyz*do>86.|v#}0*۰vXOLQҙ(S%x1,hp>E4z|vijy]d0yf˰*Ϧ>]9mn$ $J3+Y)aH(Y#+nO!( T\D T* *NHpeKKlN@[?֥-fq-qHo84$s4S;IzI1_^C@seV4$YH2@D}1|%K\Z|ڰc6JO#;Җ:h0pA,^PvxAK>|v΋?˕'90 o8O(h8Sɤt hxaPUWiTQz\?0;Spva0bnrsgMIyzL1b%CAcn&3IޔЉXVZ6 YGdV>Ӱ*!2ٔGDf>zЃ{Y> endobj 678 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [101.439 428.547 244.173 439.451] /Subtype/Link/A<> >> endobj 679 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[0 1 1] /Rect [104.209 281.1 300.062 292.004] /Subtype/Link/A<> >> endobj 683 0 obj << /D [681 0 R /XYZ 72 744.907 null] >> endobj 684 0 obj << /D [681 0 R /XYZ 72 720 null] >> endobj 130 0 obj << /D [681 0 R /XYZ 72 544.656 null] >> endobj 685 0 obj << /D [681 0 R /XYZ 72 539.297 null] >> endobj 686 0 obj << /D [681 0 R /XYZ 72 507.416 null] >> endobj 687 0 obj << /D [681 0 R /XYZ 72 475.536 null] >> endobj 688 0 obj << /D [681 0 R /XYZ 72 443.655 null] >> endobj 689 0 obj << /D [681 0 R /XYZ 72 423.73 null] >> endobj 690 0 obj << /D [681 0 R /XYZ 72 391.849 null] >> endobj 691 0 obj << /D [681 0 R /XYZ 72 359.969 null] >> endobj 692 0 obj << /D [681 0 R /XYZ 72 328.089 null] >> endobj 693 0 obj << /D [681 0 R /XYZ 72 296.208 null] >> endobj 680 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F58 217 0 R /F44 192 0 R >> /ProcSet [ /PDF /Text ] >> endobj 696 0 obj << /Length 208 /Filter /FlateDecode >> stream xڍ;O@SIm־sR.Ja,qHP= $ F1`˃=VZBvTw{ĭ%a|f,WM/4+"T c ^̓៕ʔ$w՟*佌^C9npll~yK endstream endobj 695 0 obj << /Type /Page /Contents 696 0 R /Resources 694 0 R /MediaBox [0 0 612 792] /Parent 673 0 R >> endobj 697 0 obj << /D [695 0 R /XYZ 72 744.907 null] >> endobj 694 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 710 0 obj << /Length 460 /Filter /FlateDecode >> stream xڵ]o0{~ŹLqbNIFBIQ/$A~&fUvu O2a/d<# $X!!:@+Bd[XnNӋ]L?^fY3#KRS=/39RǐsLg3hu%?g\游?|ߕXgņ, $f0_Pz.XHP7 I&D]꤮"l%|&nBۆy/z#drhP=MBZwɶ1GFBz{/-Jdܛn@U.]$ Zڱݢ&"T[t>W%aMFx(v2&sy[2e~W7_g@&ڢwWE~K݁U1G+]jZsi|K3`D6ye:?NE9H]zX$Nr@?#Z r endstream endobj 709 0 obj << /Type /Page /Contents 710 0 R /Resources 708 0 R /MediaBox [0 0 612 792] /Parent 673 0 R /Annots [ 698 0 R 699 0 R 700 0 R 701 0 R 702 0 R 703 0 R 704 0 R 705 0 R 706 0 R 707 0 R ] >> endobj 698 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [147.716 544.647 159.671 554.833] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 699 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [129.783 507.939 141.738 518.126] /Subtype /Link /A << /S /GoTo /D (page.24) >> >> endobj 700 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [105.873 471.137 117.828 481.418] /Subtype /Link /A << /S /GoTo /D (page.36) >> >> endobj 701 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [111.851 434.429 123.806 444.711] /Subtype /Link /A << /S /GoTo /D (page.21) >> >> endobj 702 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [123.806 422.474 130.78 432.755] /Subtype /Link /A << /S /GoTo /D (page.1) >> >> endobj 703 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [159.671 410.519 171.626 420.8] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 704 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [165.649 398.564 177.604 408.845] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 705 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [165.649 386.609 177.604 396.89] /Subtype /Link /A << /S /GoTo /D (page.34) >> >> endobj 706 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [123.806 348.774 130.78 359.055] /Subtype /Link /A << /S /GoTo /D (page.8) >> >> endobj 707 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [117.828 336.819 129.783 347.1] /Subtype /Link /A << /S /GoTo /D (page.27) >> >> endobj 711 0 obj << /D [709 0 R /XYZ 72 744.907 null] >> endobj 134 0 obj << /D [709 0 R /XYZ 72 572.094 null] >> endobj 708 0 obj << /Font << /F28 148 0 R /F73 712 0 R /F46 193 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 715 0 obj << /Length 206 /Filter /FlateDecode >> stream xڍKKA+ *>0 [aɎ"CMfO Euu}xF]D65' K{V*v<7Х~__lS٠ɔRWQ+/1,a۩d}e]<[<ŧU ?AŐf1ć7wCshOX}NFBK endstream endobj 714 0 obj << /Type /Page /Contents 715 0 R /Resources 713 0 R /MediaBox [0 0 612 792] /Parent 673 0 R >> endobj 716 0 obj << /D [714 0 R /XYZ 72 744.907 null] >> endobj 713 0 obj << /Font << /F28 148 0 R >> /ProcSet [ /PDF /Text ] >> endobj 766 0 obj << /Length 1068 /Filter /FlateDecode >> stream xYrH}W#Z3<:Kkv#*UNJad`%>EW# Yz sNܸ~N.0MT ΰΉ#i]-f\ q:m@LS71睦sN.!< @3|8wȠ3waA%(7VkP_&N+Gc(ԉA7D _/{.{Ek2pH7[AwZ( !Lv@L]0]#/G(&:6iߵ?dH9A_;?G+d/R '(lϊ֝9.(X`:2OgU' 9ғہqc,EA31e\n$dxi2Zg+\r0VKʂI $쟋Pܯ%iV2ؚ-j ʖrp!w{B>ej0<:MP7dqtIv@Y; \;`$W+qOJ2rfa<0\(ۅ1~-)Jækpl3! ),ۣ6;@lRGy6Ȝ~/)ld5S+kV.aJU ;)1.4cͦ+9hoU҆6BB(-U‡!ShKm>Z~ȱ]r*#+)dr3?4R]RQ\jL}iY5~nʣ1򶺢ϵq_Zݏg+n<|"^iBԾ]MD&?xCϱċ1aZa-}U+'f0v0ZwOZto1mxOgYr(א޵:mBѦN RHr`ժ{=W9u'Q7qP)xWU3Lڈ>w$ nQҔF+P.y=c~=! ձ*lwG=J_h ;W]=0;|1XG endstream endobj 765 0 obj << /Type /Page /Contents 766 0 R /Resources 764 0 R /MediaBox [0 0 612 792] /Parent 768 0 R /Annots [ 717 0 R 718 0 R 719 0 R 720 0 R 721 0 R 722 0 R 723 0 R 724 0 R 725 0 R 726 0 R 727 0 R 728 0 R 729 0 R 730 0 R 731 0 R 732 0 R 733 0 R 734 0 R 735 0 R 736 0 R 737 0 R 738 0 R 739 0 R 740 0 R 741 0 R 742 0 R 743 0 R 744 0 R 745 0 R 746 0 R 747 0 R 748 0 R 749 0 R 750 0 R 751 0 R 752 0 R 753 0 R 754 0 R 755 0 R 756 0 R 757 0 R 758 0 R 759 0 R 760 0 R 761 0 R ] >> endobj 717 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [275.375 544.772 287.33 555.676] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 718 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [149.041 521.235 160.996 531.766] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 719 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [224.576 482.778 236.531 493.682] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 720 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [270.294 470.823 282.249 481.727] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 721 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [206.215 458.868 218.17 469.772] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 722 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [183.62 446.913 195.575 457.817] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 723 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [231.769 408.786 243.724 419.69] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 724 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [247.011 396.83 258.967 407.734] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 725 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [234.837 384.875 246.792 395.779] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 726 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [163.546 373.294 175.501 383.824] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 727 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [144.966 349.383 156.921 359.914] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 728 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [181.966 337.055 188.94 347.959] /Subtype /Link /A << /S /GoTo /D (page.9) >> >> endobj 729 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [232.735 298.927 244.691 309.831] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 730 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 277.174 122.809 285.921] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 731 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 216.457 122.809 225.303] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 732 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 180.591 122.809 189.438] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 733 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [198.444 166.579 210.4 177.482] /Subtype /Link /A << /S /GoTo /D (page.29) >> >> endobj 734 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [213.388 166.579 225.344 177.482] /Subtype /Link /A << /S /GoTo /D (page.31) >> >> endobj 735 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 132.77 122.809 141.617] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 736 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 96.905 122.809 105.751] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 737 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [149.041 71.311 160.996 81.841] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 738 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [388.022 548.239 399.977 558.77] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 739 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [505.51 535.91 517.465 546.814] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 740 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [441.431 523.955 453.386 534.859] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 741 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [466.865 485.498 478.82 496.402] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 742 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [529.041 473.543 540.996 484.447] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 743 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [518.78 461.588 530.735 472.492] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 744 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [388.022 438.051 399.977 448.581] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 745 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [526.531 425.722 538.486 436.626] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 746 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [445.664 387.595 457.619 398.499] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 747 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [349.836 365.842 361.791 374.589] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 748 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [447.517 351.73 459.473 362.634] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 749 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [387.593 340.148 399.548 350.679] /Subtype /Link /A << /S /GoTo /D (page.24) >> >> endobj 750 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [424.803 302.021 436.759 312.925] /Subtype /Link /A << /S /GoTo /D (page.23) >> >> endobj 751 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [378.338 290.066 390.293 300.97] /Subtype /Link /A << /S /GoTo /D (page.36) >> >> endobj 752 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [422.064 278.111 434.019 289.015] /Subtype /Link /A << /S /GoTo /D (page.37) >> >> endobj 753 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [443.941 239.984 455.896 250.888] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 754 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [349.836 191.959 361.791 200.805] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 755 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [416.524 177.946 428.479 188.85] /Subtype /Link /A << /S /GoTo /D (page.12) >> >> endobj 756 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [433.68 165.991 440.653 176.895] /Subtype /Link /A << /S /GoTo /D (page.9) >> >> endobj 757 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [478.511 154.036 485.485 164.94] /Subtype /Link /A << /S /GoTo /D (page.9) >> >> endobj 758 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [455.268 142.081 462.242 152.985] /Subtype /Link /A << /S /GoTo /D (page.9) >> >> endobj 759 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [383.947 118.544 395.902 129.074] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 760 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [383.947 94.634 395.902 105.164] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 761 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [383.947 70.723 395.902 81.254] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 767 0 obj << /D [765 0 R /XYZ 72 744.907 null] >> endobj 138 0 obj << /D [765 0 R /XYZ 72 572.937 null] >> endobj 764 0 obj << /Font << /F28 148 0 R /F73 712 0 R /F31 150 0 R >> /ProcSet [ /PDF /Text ] >> endobj 833 0 obj << /Length 1217 /Filter /FlateDecode >> stream xZ˒8+4U1 ۩NRIM\Љ02|K6 GIpѹWJ@ @aj= 3z&&tjrGN!c=mMk~n%N wo{ҡ/Owٿ3$O M f_ pOĶyPf_5 i ۰hzUf~$QP31I)YP!e R?FKݢs^̰;e"/}St9dHD%35Ēl$@|LDFOD$vv<Sj\g%L)wEN.dz3#FCbt1"z8 G5GJ1fa\#i7_:ߴ$Q0_\fY $0JdQķڂ)a#)P{B#Sbԩ(Mta/=J#" e+k:cP5ڈTiVh99w8e*V/D>&/nW!'RkrRĉڻF'e9!ʀ50S#RCH?j}Oz0M }O~Al.P+ ;ens'2M{' KWZz/ [$K-8!KZ|~0ʁw"50r*zXm!IKU~^>F Xۧd"KV<b8iٜA\/KC H)]o5$v{Vݷ/lh9LpW=P>d6/t\9~FëfsR> endobj 762 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [232.716 706.884 244.671 717.788] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 763 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [144.966 683.348 156.921 693.878] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 769 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [242.121 671.019 254.076 681.923] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 770 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [229.019 632.892 235.993 643.796] /Subtype /Link /A << /S /GoTo /D (page.9) >> >> endobj 771 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [279.649 620.936 291.604 631.84] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 772 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [215.57 608.981 227.525 619.885] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 773 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [221.657 597.026 233.612 607.93] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 774 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [244.9 585.071 256.855 595.975] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 775 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [250.987 573.116 262.942 584.02] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 776 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [197.816 534.989 209.772 545.893] /Subtype /Link /A << /S /GoTo /D (page.12) >> >> endobj 777 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [203.904 523.034 215.859 533.937] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 778 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [230.305 511.078 242.26 521.982] /Subtype /Link /A << /S /GoTo /D (page.30) >> >> endobj 779 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [235.834 499.123 247.789 510.027] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 780 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [207.978 487.168 219.934 498.072] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 781 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [144.966 463.631 156.921 474.162] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 782 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 415.606 122.809 424.453] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 783 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [142.107 401.594 154.062 412.498] /Subtype /Link /A << /S /GoTo /D (page.21) >> >> endobj 784 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [263.759 389.639 275.714 400.543] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 785 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [199.68 377.684 211.635 388.587] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 786 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 355.93 122.809 364.677] /Subtype /Link /A << /S /GoTo /D (page.42) >> >> endobj 787 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [149.758 341.818 156.732 352.722] /Subtype /Link /A << /S /GoTo /D (page.1) >> >> endobj 788 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [251.933 329.863 263.888 340.767] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 789 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [272.615 317.908 284.57 328.812] /Subtype /Link /A << /S /GoTo /D (page.43) >> >> endobj 790 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [241.622 305.953 253.577 316.856] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 791 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [176.876 293.997 188.831 304.901] /Subtype /Link /A << /S /GoTo /D (page.41) >> >> endobj 792 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [275.385 282.042 287.34 292.946] /Subtype /Link /A << /S /GoTo /D (page.43) >> >> endobj 793 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [186.28 270.087 198.236 280.991] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 794 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [286.294 258.132 298.25 269.036] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 795 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [186.828 246.177 198.784 257.081] /Subtype /Link /A << /S /GoTo /D (page.34) >> >> endobj 796 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [287.39 234.222 299.345 245.125] /Subtype /Link /A << /S /GoTo /D (page.34) >> >> endobj 797 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 185.866 122.809 194.713] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 798 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [110.854 137.204 122.809 146.05] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 799 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [206.862 98.439 218.818 109.343] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 800 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [206.115 86.484 218.07 97.388] /Subtype /Link /A << /S /GoTo /D (page.12) >> >> endobj 801 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [212.202 74.528 224.157 85.432] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 802 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [477.585 706.884 489.54 717.788] /Subtype /Link /A << /S /GoTo /D (page.29) >> >> endobj 803 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [483.114 694.929 495.069 705.833] /Subtype /Link /A << /S /GoTo /D (page.31) >> >> endobj 804 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [443.642 682.974 455.597 693.878] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 805 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [383.947 659.437 395.902 669.968] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 806 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [383.947 635.527 395.902 646.057] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 807 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [349.836 601.345 361.791 610.192] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 808 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [349.836 565.48 361.791 574.326] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 809 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [520.653 551.467 532.608 562.371] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 810 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [388.022 527.93 399.977 538.461] /Subtype /Link /A << /S /GoTo /D (page.33) >> >> endobj 811 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [388.022 504.02 399.977 514.55] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 812 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [479.299 491.691 491.254 502.595] /Subtype /Link /A << /S /GoTo /D (page.30) >> >> endobj 813 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [484.828 479.736 496.783 490.64] /Subtype /Link /A << /S /GoTo /D (page.32) >> >> endobj 814 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [388.848 467.781 395.822 478.685] /Subtype /Link /A << /S /GoTo /D (page.8) >> >> endobj 815 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [416.505 455.826 428.46 466.73] /Subtype /Link /A << /S /GoTo /D (page.23) >> >> endobj 816 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [422.611 443.871 434.566 454.774] /Subtype /Link /A << /S /GoTo /D (page.15) >> >> endobj 817 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [383.309 431.915 395.265 442.819] /Subtype /Link /A << /S /GoTo /D (page.27) >> >> endobj 818 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [449.012 419.96 460.967 430.864] /Subtype /Link /A << /S /GoTo /D (page.29) >> >> endobj 819 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [506.506 381.833 518.461 392.737] /Subtype /Link /A << /S /GoTo /D (page.43) >> >> endobj 820 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [442.427 369.878 454.382 380.782] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 821 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [388.022 346.341 399.977 356.872] /Subtype /Link /A << /S /GoTo /D (page.43) >> >> endobj 822 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [450.277 334.012 462.232 344.916] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 823 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [450.287 322.057 462.242 332.961] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 824 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [349.836 274.032 361.791 282.879] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 825 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [454.542 260.02 466.497 270.924] /Subtype /Link /A << /S /GoTo /D (page.31) >> >> endobj 826 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [383.947 236.483 395.902 247.013] /Subtype /Link /A << /S /GoTo /D (page.35) >> >> endobj 827 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [484.03 224.154 495.986 235.058] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 828 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [497.868 212.199 509.824 223.103] /Subtype /Link /A << /S /GoTo /D (page.13) >> >> endobj 829 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [519.457 200.244 531.412 211.148] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 830 0 obj << /Type /Annot /Border[0 0 0]/H/I/C[1 0 0] /Rect [451.134 162.117 463.089 173.021] /Subtype /Link /A << /S /GoTo /D (page.14) >> >> endobj 834 0 obj << /D [832 0 R /XYZ 72 744.907 null] >> endobj 831 0 obj << /Font << /F28 148 0 R /F31 150 0 R /F73 712 0 R >> /ProcSet [ /PDF /Text ] >> endobj 532 0 obj [142 0 R /Fit] endobj 531 0 obj [142 0 R /Fit] endobj 530 0 obj [142 0 R /Fit] endobj 529 0 obj [142 0 R /Fit] endobj 528 0 obj [142 0 R /Fit] endobj 512 0 obj [142 0 R /Fit] endobj 511 0 obj [142 0 R /Fit] endobj 510 0 obj [142 0 R /Fit] endobj 509 0 obj [142 0 R /Fit] endobj 836 0 obj [667 667 722 722 667 611 778 722 278 500 667 556 833 722 778 667 778 722 667 611 722 667] endobj 837 0 obj [569.5 569.5 569.5] endobj 838 0 obj [892.9] endobj 839 0 obj [674.8] endobj 840 0 obj [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600] endobj 841 0 obj [897.2] endobj 842 0 obj [388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 277.8 777.8 472.2 472.2 777.8 750 708.3 722.2 763.9 680.6 652.8 784.7 750 361.1 513.9 777.8 625 916.7 750 777.8 680.6 777.8 736.1 555.6 722.2 750 750 1027.8 750 750 611.1 277.8 500 277.8 500 277.8 277.8 500 555.6 444.4 555.6 444.4 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6 500 555.6 527.8 391.7 394.4] endobj 843 0 obj [575 575 575 575 575 575 575 575 575 319.4 319.4 350 894.4 543.1 543.1 894.4 869.4 818.1 830.6 881.9 755.6 723.6 904.2 900 436.1 594.4 901.4 691.7 1091.7 900 863.9 786.1 863.9 862.5 638.9 800 884.7 869.4 1188.9 869.4 869.4 702.8 319.4 602.8 319.4 575 319.4 319.4 559 638.9 511.1 638.9 527.1 351.4 575 638.9 319.4 351.4 606.9 319.4 958.3 638.9 575 638.9 606.9 473.6 453.6 447.2 638.9 606.9 830.6 606.9 606.9] endobj 844 0 obj [777.8 277.8 777.8 500 777.8 500 777.8 777.8 777.8 777.8 777.8 777.8 777.8 1000 500 500 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 1000 1000 777.8 777.8 1000 1000 500 500 1000 1000 1000 777.8 1000 1000 611.1 611.1 1000 1000 1000 777.8 275 1000 666.7 666.7 888.9 888.9 0 0 555.6 555.6 666.7 500 722.2 722.2 777.8 777.8 611.1 798.5 656.8 526.5 771.4 527.8 718.7 594.9 844.5 544.5 677.8 762 689.7 1200.9 820.5 796.1 695.6 816.7 847.5 605.6 544.6 625.8 612.8 987.8 713.3 668.3 724.7 666.7 666.7 666.7 666.7 666.7 611.1 611.1 444.4 444.4 444.4 444.4 500 500 388.9 388.9 277.8 500] endobj 845 0 obj [583.3 602.6 494 437.5 570 517 571.4 437.2 540.3 595.8 625.7 651.4 622.5 466.3 591.4 828.1 517 362.8 654.2 1000 1000 1000 1000 277.8 277.8 500 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 777.8 500 777.8 500 530.9 750 758.5 714.7 827.9 738.2 643.1 786.3 831.3 439.6 554.5 849.3 680.6 970.1 803.5 762.8 642 790.6 759.3 613.2 584.4 682.8 583.3 944.4 828.5 580.6 682.6 388.9 388.9 388.9 1000 1000 416.7 528.6 429.2 432.8 520.5 465.6 489.6 477 576.2 344.5 411.8 520.6 298.4 878 600.2 484.7 503.1 446.4 451.2 468.8 361.1 572.5 484.7 715.9 571.5] endobj 846 0 obj [500 500 167 333 556 278 333 333 0 333 675 0 556 389 333 278 0 0 0 0 0 0 0 0 0 0 0 0 333 214 250 333 420 500 500 833 778 333 333 333 500 675 250 333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 675 675 675 500 920 611 611 667 722 611 611 722 722 333 444 667 556 833 667 722 611 722 611 500 556 722 611 833 611 556 556 389 278 389 422 500 333 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 400 275] endobj 847 0 obj [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600] endobj 848 0 obj [600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600] endobj 849 0 obj [333 250 278 500 500 500 500 500 500 500 500 500 500 333 333 570 570 570 500 930 722 667 722 722 667 611 778 778 389 500 778 667 944 722 778 611 778 722 556 667 722 722 1000 722 722 667 333 278 333 581 500 333 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444] endobj 850 0 obj [556 556 167 333 611 278 333 333 0 333 564 0 611 444 333 278 0 0 0 0 0 0 0 0 0 0 0 0 333 180 250 333 408 500 500 833 778 333 333 333 500 564 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 278 564 564 564 444 921 722 667 667 722 611 556 722 722 333 389 722 611 889 722 722 556 722 667 556 611 722 722 944 722 722 611 333 278 333 469 500 333 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 480 200 480 541 0 0 0 333 500 444 1000 500 500 333 1000 556 333 889 0 0 0 0 0 0 444 444 350 500 1000] endobj 851 0 obj [278 278 556 556 556 556 556 556 556 556 556 556 333 333 584 584 584 611 975 722 722 722 722 667 611 778 722 278 556 722 611 833 722 778 667 778 722 667 611 722 667 944 667 667 611 333 278 333 584 556 278 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 611 389 556] endobj 852 0 obj [278 333 278 278 556 556 556 556 556 556 556 556 556 556 333 333 584 584 584 611 975 722 722 722 722 667 611 778 722 278 556 722 611 833 722 778 667 778 722 667 611 722 667 944 667 667 611 333 278 333 584 556 278 556 611 556 611 556 333 611 611 278 278 556 278 889 611 611 611 611 389 556 333 611 556 778 556 556 500] endobj 853 0 obj << /Length1 928 /Length2 3863 /Length3 0 /Length 4483 /Filter /FlateDecode >> stream xڭuX[Q)x!!Df!PDB$DB$NMs{ֽu_صtAH%J )@An BBp..gb8Pp XGg-Q)Ph+PGlQV{@kF<y{{@ @rvC!i (4ӓ2 ]F:rv!x~&XDYӀ5PD/\^kံC9X$oosp]Cأ16(@E G!8+[aUGa@ ѽ;pEצy8nS!3ٿ."@X 4C$1@c(<1X@:(T ,MP CX7TCDoZ0CĞMAf0-!/p,HHX* HBz!hQ(<ʊflku;aRUpϝW|g6O46ƞѩ7YfxXzn|1Kxv҆ӓEl۩ ovhLv'elfi(-Q~f'i6qhN * *%®s!)?T48/}>Cj' 9TO,H[QDD\ =?&];U!{E4Uyšr=N,LSS׾ H}s=h mXqiFZˡL~?Gè/Z%J~V \6Yhx˺X2CGחa RIYuyI)>HͯtgE\+ Yu L!KNEN-͠Ձ{iF>*ǔ*ZR#| G 67*~ӯ_zDKT#/^oWx0Or-B8 UO)Fm8)Z*S+F n9|+~2^mޟv\S~7&,EEfjIy[s#yP*#:|)*|3DE-c:wpqgrBEqfƂsJphx#dovY;ݼҀlU lZ/7V4vYG_O3/P!pδx(ud̚'b[%ޔk1;Nώ?jIlz}--TR_vMr$:kKїzJh)f&yI"6߁邙RiJ07^2t?R ,l̟RLI~} fZwC+! #kFǻb޷}<;bNGڙ׃xM(́IKopo*22R@BXW?bkyRq]$zgDv1< n߭N+~~\𰟋%kݯFIA-^)\,򤅮gԧjf}|O2 m aSʓ˙ۇoVJyc^jL\Cܶ ݥغW$mo8Q*96ȧKk;0A9-knk1l* <ȚzôxS}++W}!CBihiykǘ6pJ۫UϲgNUF-?jl\:L؉_©&q (M~٘ֈSڄ[-hP:W|)de_1Hפ]g~kܕfݐa<3eK=$IF[N0^МYk{wPjXh f(gH$)U-r\8T5{߁{^’NpTi;G1ҹݝ4l臟|yP瞮v&nMse'ϮM/>u䧮dq<ٖ1[o+3U7\3m}uKБVf%-0RJ TkUfPTԋ\}zp2Bo79W*,}`_`ۘI^+K dbM8{f5@;yX\7=j+^!fK~$Mq\)Fqqh^``5h9[mdLmÌK&^$+,K8in#sg~'Ehd(l=_eKikDXgX^ h 'ɝv}s0K O4./RFw3^}(l< H IUN,)7yT`G]jK׽^EtvcK_;0g>9 s@ o/)۷EC6"\sم> endobj 855 0 obj << /Length1 734 /Length2 1069 /Length3 0 /Length 1583 /Filter /FlateDecode >> stream xڭR{><"||! ,5c/b$!0AF@(F) K?I,) "途H`D@XR!KrH'32Opq@$ %|悋겂P3&!S @eA ~$Dx/% pr|xC1_x1u׹m4&$\m,vG( 5ljnL&{#5kVw"!*uR Z:cȤ=kM#+e˧U]Qv,`&gՀ޹ e9*_8KDx*nnAsNkP"vH5tWwvP:ݙ_n&ZX]jqq2CSSA}!} 3֣iwSvbq_,kj/n,JXRꄈrKE7a(Bvҹ|!Ewag6~+`O*C^**g$zQ0ʷu8{(CN 7q7y# اm nᖘOX#wй¢[';2;,09EϫX]N+?I2>]ܖrSBPT 6P>Sh kXߨ͏L@8№=0]NtYt?hhSmWzZ{~uj1-w6d~0Y{gG#['ױ:O3ԩ]FJ[;Z=lJ__;!0;(-.mZ4LZ_Xva4mjs}v2?^ka U;#uh }vӊ*G;ƞM`S7]Rg ;& M]jwuDPI>3G?Zf&*2]3]j4j0}e",Fa/ == 3o7YKM Bwx78]ʨ% P=xҔ7)'_$pa˖ .MXɿH,2bXNWBzRx7]p潚U[;~ 6ٙ6dSÚe\_v endstream endobj 856 0 obj << /Type /FontDescriptor /FontName /UDTJWW+CMBX7 /Flags 4 /FontBBox [-55 -250 1289 751] /Ascent 694 /CapHeight 686 /Descent -194 /ItalicAngle 0 /StemV 127 /XHeight 444 /CharSet (/T) /FontFile 855 0 R >> endobj 857 0 obj << /Length1 934 /Length2 2947 /Length3 0 /Length 3576 /Filter /FlateDecode >> stream xڭRy<{T"Cdf0kvBm0 cF#c_EF(;R^d)H%[f'{~oy^}}z6i#HBT]33c`11]"NzpR`JE2WʪPU2K $b^$@BWH!O808zO8"xb@Y@,,Hb!' @1x(7 S @1%zH H% I{s2{ aRpdH"wpfHjLc1x4 `ſyDcH^ GxICT__Y4c$@_$!0}HD p˂srLI@`h@Dx '#(0x )rx~O&@,? S<~P?yp8y <(/*(rK[ҷO@ S_PǠ w!ɿl鶔𿧯C<> ГL$"8}`v$d xEyVuO{<2MMg5RG47!;m[Mm h;%nut+W-'qf}k>[x~3D9w!PjO軏ìwfh,.YLSs7w ygOO%d1i|,IAMcd g.ZWNjk՚-ꖄM Gӌm6s8=ȲF&tEOYoM7\vw7x<x3IdhHHmv{%ϒY/$ujMR{XY>nReԶv֧0^'slLȐw5uw~]RՔw!Z Fd,K 1cCcA/_ vr&HhM#\ ogv_O'J#uY;n -}6qxSa)^9?kԠ{t>m8XSFF¹❟l .R|!|[:ˮ5T jާ9b\(w+=A]0/9zܑ.̆GON\?6ebzCdjŬD=s{H$VH ^ll5)wQ Ek\)=gaW g˕hxo]PV>%PD)# IKWe]9 F.?ښKMtPcr-j+jMTSS+ag=|y~Հ-Pf4Y˝ŻR~#H EBuT5]DEm`֠̍ǽ7c>&hpfѠ[0j&1v=&:=$C >j|?7(|η*uU _+G{sd,l4o}Ptl\<">:np&C]rR6_m l[ 2Bk&9^ѓ3=c"UĔez [0tqŵGL UCu); [6%הwG?JMܾȴAMHJ=u 6$JrUNwu -JݝpZƚۏ9e(*Gq\9]oW28ɤƝl)+~$^ԡT &Gn+8Ob6'N3=M_Tΐ/p@.ïb9hx5rJ)7a`o56VHU> endobj 859 0 obj << /Length1 743 /Length2 1156 /Length3 0 /Length 1687 /Filter /FlateDecode >> stream xڭ{Tgƹ n(Z~++IC6֍LL&@(P*W+@U s(7-{77Vذ1 E0*j\.K `eŖB| FW>*{"@(vKlTAfDv%. ĸ/>0% D"oa d4 T* `@^@ (%FaTCEL"!("R!H {iZj&0a7*1H "Kl\HK/,$H-b`$ E2h!¥$x|dˏ8aUJ @]XS񈤰(*.ğO#KڍP!R)_IV4:F@ LBP `"A *%,[@]h ..BE64:H;:%dT !? H ZTQyJeDG5ow :Io>i\W@zJVϦL̉|ck4ԭ_L]}a5ˮyR.{ۨГ;3G4w[P`{cqW*uJfc J;I8,}޽jWSH!FnN+nt> endobj 861 0 obj << /Length1 984 /Length2 3529 /Length3 0 /Length 4185 /Filter /FlateDecode >> stream xڭSy8ξ/iY3d72h0ƞ( (K}+dRʾ$z~߾繞s|s_GLZV 8,T#P*,&OQD g"TMMU)}O0I$%$ F zS4(,`Gc@b7$@79f(pà+1dsh7C b iSt,oT)^?l)bQ?4(o 6? xo"Hx73 aQX Z_ ,1D'?y J~Z22505ӟ1KG<O SC(R)'?jx7 P(L Ps0bX^'Rx󏁪AyW }$bAw/^7kj<7 < 3*Aן29)wLRM*S eHv)>X@E_(C@/ UAʇG5@ME-_hOACY cohhe$ۃtRTzImÏX.ޠ–JMWTda_[ r|57)bF~/و]^h{Fer,ա+o{R{ICjsUTX+UJHL߲X嘩@dکI^1 ی)NM] :κa%~̘w;^z{$ WnMˏfHn Yg9Xrr8yqRa<-zZYzϺN)r>25(9̝va>UPU_Ӌﰛs,6HemzqpbYm`칪|cn y6Wkv9&+Y$*d =}Je"ίC1J-,5N]>R ms2?ߦjy#S5}!rbl5sΟVZS3*E 6LlY6}]o3nLH>8LAB!F~mwVE'Sζ]th>:vcOc\oouJ!חa,dǞNkϘޙnk=}ᴏ5yps/Hw0iȊQŴ'\"[Kךpz]cs' \~?:ϙwU0FWb! iU; kϵpYP5i jW[yUhHizwϙShٚy/2`!l?qnaL]8ώG?5lr탙4dh+t]>yqRSDW/G R1}nIt(- MM8up9άilʒlV#dl|&њn:)+Y! }CF))[(f ]4oRu:&/ɫm-sc\^At.I;[.awyz [d)%Hooc[i癏j2'HqxRR_]PjsS;|D-U>FzE\:D'ߩd7T-z9dgܶw/FT_M !\ J`uV*G\y孂b)4# U{eSaT jAX%- EzLHfrhȐ4Z$WLYZnʻߍRJ#Ee )q'H/?+4..N 3θ: !SfWW$JSǝNż0T8y)0(̳c{mȒF}G߮ c?v!"2aNb ?pP9ۖѬui5%ԎmRɺm/}Zf}vK˥Ԭ>[T37_ xrj 8)}y%l]@v2h#/m5)fliܠ2rF 걓ۡtbohGWKw= c>qG}ȏfU47ju3SGfΞvHu$RUlfrkEn[k\%w]oQyG{Q07;9}nWlQ+ 7+E,4f5= hW3,9i+`. Gse,utF?cY8Xiu夤Nc`IxQ^5h~^eA<6~bh8/H(BcW%_ldVrT,[pM!~U=cRy'+g,<!_# &-q퇖?X#h5/ 63Wdm]?n1%@qHwJٺ7@j7Xo+2.$VhxpSFS}WהnƠAO* *wv. "_8;]r{ټj 0Jʤ4>%Ä26W_tۘ#-ߦؖ=]1MjoKg)a_f:E5۱GQvgjv#hq`5p>LcQǎA:Ki*n-BŢJ'{ZzҞ"=_-hJ5Xy!0 Sl^|W$O޲y=jX6 ':V^9-vUyR1Vy {E%-PI*Q!CZ,6B7Ѥ1YIC133xN/ϴi(wwlL%ٯkYN Q~Up ?Կԑ \a{#rLYHmܨhݒw`g D7P1\m2oϗ8Vzo/Xt{=|8cDTIi+D%&fX\gl'}XQMyO)^J{&߇Ҥ~թJQCTQ2c(qgw K2ӡ2߮3A]y4YJ#{d7-H_nF3idl\_0sXyb/^{1rDi4o-{3<$|FO]axfKz 0EjpƲ$^>&8Y[:ywlXXr}^tN~cS:EB"z3DŽO;4p#kYbQ1+E8~`*PxśSl9ҙYQ}]y%L]qNʼn=yY-^3/=nWg4fۦz4T~BTA0g./\pб07%ՌzJZ<mճ~4/ɱ4->~6azC"хa[9|ueҘQE5C}޽3ga,O6z7*T.0z]kTĀ>w(v.qRl7>&__0] OXd~|^}Zyn鼨R+ xz Pq_ݵʮ:m|qE*nsK&>u!m3EVk_?eVݼ>upl@LvWalytN/ܷn" k/ĥ_ 8pN̅/Bu>OX/ir;r{7/7/uY=(OY;1r;I4bau>F<+6NqP``w(&Q"t endstream endobj 862 0 obj << /Type /FontDescriptor /FontName /QHDADJ+CMR10 /Flags 4 /FontBBox [-251 -250 1009 969] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 69 /XHeight 431 /CharSet (/bracketleft/bracketright/c/colon/equal/five/o/one/parenleft/parenright/plus/s/two/zero) /FontFile 861 0 R >> endobj 863 0 obj << /Length1 768 /Length2 1353 /Length3 0 /Length 1892 /Filter /FlateDecode >> stream xڭR{8yT]:bs0 *9QNcx_f^QĘP%ǶZlr^$6JCRDƮCJ\ 97y>tF S 1\B|B!0FS" X#!|.Xk"c r!h,br(r8zpy 7d` P` nݏƟivX)Ħؤ F``~qD|(v0y8=9 ^/o*3#!a(6ȅ7كl(,xj29 s@xt(d;B(+crx&ımX9rx ɑ +?䯡_,Ά ExrGHnȸqLH`80W93 yyqEM̪9ZVٕ;~euE\ln)U]V@Ы{-9`@R*[ɵ;,8wwcB|٢QHO];WM3RrH W![_@3#8k)n"-ݘMJvJN_2[XCǣRO뮻W/j0c-hFuE_]|uloG8Kk7ռ2̡W.yV.Jlդ*3r fdX܁EGUzd 'i(L)OޓZnyO*NAfxq/k:ڮ?fLuPqm3d淫D%?I S$zƳcTv Ksi[>4Dux˭7Z/IS޲+5&[lc|ڑ%Hs{fss啵׎cźrdfYtނ5ɐQ\vb㔂)t\a#t_V+9RշDePZww5JNݧY9T^&Lԋbl{ނ>)_~^I/ԨV1=:u)XbQ_lj3sRF(Gj+Fza':c2lN'lo>SӮy},.K&ս_dMIa Ϻ%㞓w#Z>̪IΞ0'Ώ(g"X;׿Ǜ endstream endobj 864 0 obj << /Type /FontDescriptor /FontName /ZEOTZW+CMR7 /Flags 4 /FontBBox [-27 -250 1122 750] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 79 /XHeight 431 /CharSet (/one/two/zero) /FontFile 863 0 R >> endobj 865 0 obj << /Length1 855 /Length2 1387 /Length3 0 /Length 1983 /Filter /FlateDecode >> stream xڭTiXx KY&h@V D+!d&N&@k".p[p-ȅlB *" (()zG\>|~9ց<*GFB(SAxryA$[[O 0G!@`1n,6De* Gွw"6B,#GAR/xp H$@r CX $@0Bs䇈P*d{R(D B"=%΂'S7VH$|3)Ka/*)pϥ渐VH?gpprÉް¸ %rhVf}x\-u Q%'L ~0X |͠1 !$ևBF 1"7X@RpL!(NlhԀHdtLJh ANL0tQ|LIÈF`\dt)(T!ayx8*:RP0g.%Z %$ B+~N/xSy_'/ ޞ[XyOPceYONՓ V1ŊSR"FO+I>'#v%5zhį~{hϻ`OeGm.f {l9U=e`|Ёb}vv|QǢ MC{vm"wQR(1hS )5_+5V{(I# \qf24.(F/aFSr&."NYr@v pN,|.udpE% ͍hc5{ _YC}h8b$:zgGyok^_eEɡYhǮ4ȁl%[Ɛ{z&^R"\V~U`'d4.؉GVː{B@6)ΙRüDq"2g;ڈY?;H>K8`1eԺ_̊ tq;OX5CM}S_/ft*"wչU\j48H _u6UF/֪}H\`Nzɗ۳TھkNޫ }Iʵʉ[L[MZ'=)-yTCWM3:}xVo/hsEƤ']Q}v;zߏ_}@@^t<}օ$ÔCMϗٱt|^.Z; ~k J:3/ۘOQe4mZ4?9ySg]+u:Tkף}Hua]CS]sARY\.5/G/)&8qo%E򭕿z7茞V5uiiPl^155`lvʜ Fm]Ϋ鞻~iP~jΰ +]f >]a~u)i14~]mթm2ᒍTā&IgFI\L~W4sȺ%0rbϠ0gKuWf;ں}#rz]!vqpˊ葨kcu~}7!-,67}NhS3'ng߰\֭rjuy`llQ^7RV7VFiE_Ć"^ţg5o`^9;8-Y&%to I]v4"; lz-F½-fznvYv?0|0]n-x00E59IX endstream endobj 866 0 obj << /Type /FontDescriptor /FontName /PGSMJZ+CMSY10 /Flags 4 /FontBBox [-29 -960 1116 775] /Ascent 750 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 85 /XHeight 431 /CharSet (/approxequal/arrowleft/bardbl/infinity/minus/multiply) /FontFile 865 0 R >> endobj 867 0 obj << /Length1 745 /Length2 581 /Length3 0 /Length 1092 /Filter /FlateDecode >> stream xSU uLOJu+53Rp 4W03RUu.JM,sI,IR04Tp,MW04U002225RUp/,L(Qp)2WpM-LNSM,HZRQZZTeh\ǥrg^Z9D8&UZT tБ @'T*qJB7ܭ4'/1d<(0s3s* s JKR|SRЕB曚Y.Y옗khg`l ,vˬHM ,IPHK)N楠;z`D8{hCb,WRY`P "0*ʬP6300*B+.׼̼t#S3ĢJ.QF Ն y) @(CV!-  y Q.L_89WTSQ-ҢԼp: Ԋd[ok[Y*V}Ο'־~ bG̔`y%K^-|xE dE[${z,^k nW6wMpa،9=թsr y)/~V$-%)+2W}~)Snʞ6-*Аbm?k/H&gB;A[":SZ}qMw~O: 77s7;8?lj9MuLWŭ94͟N>/rW7Uj{E=ۙ^ mWMXZ7_m]ToنU]0RܭboWd☭znڶ *nnd UDU+˸RIѱC&N3.0G߯Н69# 4W쪻t`j7nߎMȑ:/SFE?O.Ut[ڐJg_,]{RP͓nj-._alyyȗVk&' i=81wry_7 endstream endobj 868 0 obj << /Type /FontDescriptor /FontName /PXBGHL+CMSY7 /Flags 4 /FontBBox [-15 -951 1252 782] /Ascent 750 /CapHeight 683 /Descent -194 /ItalicAngle -14 /StemV 93 /XHeight 431 /CharSet (/minus) /FontFile 867 0 R >> endobj 869 0 obj << /Length1 1606 /Length2 15302 /Length3 0 /Length 16128 /Filter /FlateDecode >> stream xڭc%\m۶mtM7=+= '3'ڿ`˖7rq 2F-Qq13XO鯞V.ۛXedgcO2:7gDpW~ԅ24O|y.9|bP |I7):8i35b9w'}@Ow:A]?S=9 7ƣw"5S$kVaη~GxpڦÀm2^B#p I^{SӌVc݃k|%1[ ay:F xT _jyW0np,RjF"v(l n!]z N )06#s_FqR(EPghaK~; HeA$  ALlމyѶa}KbSiͪ֍$՗иܵA^m1wݯM>q:+o䚧(4SڄrH.Mi-jYw<VQ{M7GϡNPhuxDI(2e~Aԧ]?V|׺lLrKG4HW0Cq K_FAIpz6)'18;51"ABinJ2=A;n##k@^ǡ}w ؟;KF&TНX3N0; NADǿ S?w =jNU4ɦr?F7Wc) T7qw{qrL }>*%3o5^/gc%̌a Ttjkv̑dRKbї]wg$Q6!yjRyye'i_e^یg\&QWAt/ gK(Wߗuѿj?Txlr+E{6P~dMwDQi(POi:yd`n8k eg e\:ZȻb~jZxt id1owMw)L#yNZ0NUe\7x= qX)uB8\f?Cys"cp ɯXӉ֨gD9 !b OG~kfMRČ*n.)± TAy2XtW<났T8"3PJUxcȨݷ|N9H^R oYd0U,ŶۢLZwXy |gm&9 [#/9&GYCөwQ&E,眔7ubdZ.G]¤5)FʛTŶ%nk"SfY'J.SaXLx+"M].ri۷V앹۬u^ ǐl{`FulF~'P]ϯEA%‰+NhZ0UK)9OE^ΖhfNj͜~va>tq3Ӑ2Է^aբWGEߩ(YO3MO'# ́am|0פg zhNR$M1JyX*#J55A,C%:XAjm3߮xmޫIʈ }0+UyG<_|_M\{2:cl}O\ֿgۑ9 HmEr>Qqm_qKgvE wPaW/Z~O \s蠋ʀ/Ss6u\Pa-&pM.5l+!q!Rwv4"P$`&8.҄Rf~$}~IO8s2N5qS&cV (6߹^x3zs0?8x2L%sI[|Ə~#=V6:ELBeU֓\9TJ D2tō%ȏL߭Gkc?8ty):\A |8!.V 绾9S,E'zOR;G뼐4o+9f[?rEsl }^l G*sS' C5gU뵄>+QGȩ֭L;e]iP5nܱZX4|kI}7s`)2ʚ0&0+n3K܅GW)rUpHB]+. 52t,"lx|PzXɑkͨ31M$%  .YvAݏ@W*EU5TtDۡnco7wb? 4K""DqrQqBIٔJxq[;jF@h&wR $g Hi3{9~@~@ϽU4%7xBYK켰i*e*ŦځۻR}t As^3_Vw0z\Hi']M$l%u[nG_7u-Z^ɡIj_Lˠb{l%BGS1:16!ksDyEGD1,ca0@#ʧGzWr-5 I-0Ur]=1StHna WqUF$k9/)J`) ֥qOa}6٧2q ao'?$=(cR8O@q*۱poT&4a+(VU)1펙\-|LI '4IP $(bz 3n%G- iѰÓ,0>5?[>1e[D۵ <$ʀG\m祟  jA,aniCqW&L㺋R) ,,`VrD 0u^Q_qo=FTԹ<ڥ|z7۟Q7/Ӥ#c ?'{Ur1~)b#iɑ't cg"6-ԏa狱nj)[kZBpD0ߕo8/*U"Sa_c* L:/fF,%,QIp'_X>9tv>qفԏd;]츴dh>?U״]?TiR q|]o(t{a_^Mub=n[fbuQw0+ӊ٘|w"x>q"I~VVgC2et=H>g6ڸބ{N`*ˢү3T[FkO'm]<4\um&f/x7؜Yဟ{51J=40΅XQCb) fxHDվњX[~yK}n@$mBHCX~A;PE>eLT rӇf dbG3dڟܛ Ԗe<¡ZH뼁ZAi#+'lByjoio2h^~=WjGtrwAP;,fC@S߱㷛e’bI/VцBc(uvF#D/1]o)`l, \CHɇk94$_Q;u@M0^ݖ '2QP>Kew|&EfzaYK&~LJeqKƧƮqzuW{ⶣwmͣ @'Hv M+cYLIBƫi@Pb(iڜXu(` |iQ['k7\-5vT#xMϜq^ਸ਼Jܕ8vк)*ɳ"O>ƏDSC&ofD-W#؏qhUy \Wwొ\yoܱz-ؑyr,Ül2p <:Zl6Hj[pWgLN0bmlz !N$KEL`T5k?-4KmJ^z:T,7&!S-:BLm'B:|T$q9Լ6쫍{IAo5$kOp?@1ۏi[kq7+#緽)0/ K}d +4S~4P Ri.<]Tb5/:?)αc,5.2 dIiݜ=kS 1]?3utI!W+5Y@9<A]9nT?/-7ry *KEEzX> [PYhLz^ԺQ;'>\6hV3^W'B6yU1]^5j":A R€7ջ %qɢh`[#m@nȬdx8\g9 Z'D[Fv!hj-/D\'rgwi3Ysϥ#4$O(BT*pۻ.;Rmbn&xbm}TR^ FHz$Y~Gcm dٜwz'& Y_fP,y]Q"\n$})_2 Jqk/`цaun& GU%d^l;ރ% 9Bx ϠQ4qͅ*pJ8頗㑯΋~SS Q[*٠:Bk]W:Tޯ%nefw/W]nY 9>X&$aa4ȔS߭(;'_8qIckoqxۊVkWM[0՗hӦuuBמ>t|1aH@uAt:8$Ye!-Ќ&|o*dSHeoX #E-:XY)̰MX/0ClkW)jޓ~Z^:q񪟸r5'k_d_c-˃[d_fm=R^Q݃sƌ~Z }b(I޼]!*fg=ڧ/$[O4c뎿2m8RV,g?aj1ZR BR Fh^F9J1吭c>eW>l (S+fFZQ!&PT@*95HA\yȀvF;2ycpDx*iJpWƐ+]7TVN8t"*1#4a T{m-oM(L| _:$?Vva1L>02 onk< GTڃӪc M.r*2a\N ԇͳ9MxdЯԞ!./ e|E]Hvy^U8OaQe(cS*/]&Om>3&ףPSm[wfӳfke3ޚѾF]a_'/Ggq7JڅH&W߹tŴ)2͖Ժx;vtΌt9 &ڀ~EԴ\F8-n=OA|mK%^|H6Iqt,aK(){ۿքnC =+Ksra g憴jbF6-ֶ 7d3V(o1WˇBg('h]^rJ@,T5YO8kW| 5*M.sxeBF|Ti|yDo41霃:'xRj%&E`.}Yx-pjf\ݵR^PL/b:i41+-9El.(~ L~V{NM mrOZ_N{[n Eg*^ܶ$} {lRfQn%k@og$ꣴՔec$af_qh !<zgD[/z9ds4&2c0~]\:ԵLrwˮզymkhM䖚羭7 [58 ܧS)|  `J@^mAǟin <>CLsTKٺy^$6C x@"ԡΚT1C77l;GZ qrmPqdӄOT8KbsPIk%`~ 0."XZB~䪪c2·_%h魶 ##ӮC⼀SȾb2_&_^Fw4RDr@5SXx6kҢ32l(KogY;@:#7Ux~Ϊ;]ʐ5Uouo}]KBm1)XΟytxP\tCk XM7 dkW#0EF+V[?$|f{F\eҜ <8{mM l1(t&<_EU)ă^Hn%b"A^ÖpCbt^eunǏdz8ʃ{?=?葉3oPc^R-k O`:c]x`:{aR\y+`^T8]f)`/'zz, TG>N;WܱBg0O/=?0Ѽf븊_%%ZȑřYv@AMį,٬L6R?A\oMrdT-c{wuy B7ƺJù | 4C DU&\ܧc\ ̂u9\+dIzqy Odanf^Ӥ+BoV%y,+t^}b:H{HθM ?3Á@ٓr~PC?jcם(i4 7X:㔮Xqjӕlق@{'} >]VԐ,roT&jO|EX)Kؖ1$kr-wG>5gp $j</s~\(ۖO׉A ]Yk [Xeԛuxu`||tJ|3%8;#K8*{ CP"ax5Ɵ&vGZc{٭?y=4?4%/έJc //ruk\a"$sc !4@PI07v@ǎߚ(kn#@n!v0_6U] S6 ‡s @.ve>RN 樿Tt8>ytDATU(33! (e+ldF2_ 'X\3{'/nbU.H:dAvHpW7gDyX0aQ_]P T7ĊV.Wّ M?;4i9GI #sk>Kpcb7ġnj%R7*^٠])dIvf&A3`ZЂ&.TXDX0`"H%}UA~BJT:=p= !{BWa857|N]x'm8h%&^+.6Jvy*$C1 /K83xs xw 'lph\'7h\w{ev Dzo'v_N)\J XuDm#1DN1٩u76+-]j[Y4BNjDHٞF8lP5|D\pc+or%Wl[(/f{V|̛o^A۾ќmƆY1 k}8| IL‰T_ou3~[^{Wk<+#}&%PB;u,%X ͧ'2R;-~rZUX>6\7?VZnzSae3ݰCs7Ejd"a;oPjNW1B%r\jcC]1_u4(j.hdz{2YYO!I-8) 8yXߧ&3Ԣܑ6sE[LMsvSQ: mKE?GMMgCy34rW!Sʁ΢g'_6;BjTDhju,>)d҇KjZ5/Lg;*'yq l(p Ø/Fz>Wn*K?i &Ќ|KIJ t jdŋk,D.D}tPʓ#yr}x&`#5F Ͻx ٞX5 l@ V£_IC6iLK.M VdC Y>~,\t4"<9K}şcfF|@ ?`E9 wZ$=Vޞi؊y-f;3ـM]jw 31K0&kB2I)Z„t+X,э]C#0} @x[eSrɺ!7aͮѣFE]Jgd#-~_`UB1!&ҶYx6o`fngr+, |U0m+pk^\0~Av?eS#DS%UXױFO0(ZQOo!ipc8M#)E`)]ZmC z(.EXjW9F^%WRL<4g;ZٜYnvt@IUE;iTd`"JaXi0p^NXm5/x>#oi%f/# ;??"說؏h֝,ߠjuTXII1-iCC0RV_s'(Ai.FlBU'Encc9Y1 u˿ZQ<^~YtrB;$Rhzt*j7 %t;Y(t+Bn[@a}*k eM+_qluȇ$Zfi-eVѭmm/(ؕdž7؈~gk~BJ GVL3=wCRui '^D=6!\FYjx4SO5'#?A#i/Og.;Bglf1Bfss+`sҕǎr4;Az+vqAN:D8 RY3L䟬3@ɾ ~` _gT/͓ܳ.m֩2 ,AI% ש^ ϟf+jRP7#g؁o}'aɯ~U?T{#pHpPTh~PƄy,MR:ki}w,( B#:cn6QvU,{k^nt-*OucKG\=}`]7 e ؔI_9( ęܚʔpxǖ9HyTrϕ맲IT}GqRpYjUk;X>:z^=rvO^lLI~6ZuMs]U}y~F.fQ*OV(~2pbOӾZ:z;ÉuoZ2͟PvFHrךAox&vnƾ:NO1Ix!I^(u|)H4x&Ժ R :|Oi!!4EO~: m=Hִ ~^ځD5QXȲ;;%Q n.1cC6|cƛ1^(]F_gV6 .%TN9 ,oa6@yO [O;fY`Ǐ4*a1=Y\!:Q5XjT8(%:AG^aRJY8עULr lDneODY {Eq++PIejy ΐH*̂#"-}s t)yS-G A2o95nĝ5 7"E&F^gL>ZCt e:ZUUvkV=ʇow 3 /ZkyQ4MVY =.o3Ƃ*M> endobj 871 0 obj << /Length1 1612 /Length2 17812 /Length3 0 /Length 18651 /Filter /FlateDecode >> stream xڬct%'ŶmUl۶]mN*m۩ƭ98gga5ךkoRBy%ZAc;C1;[gZF:.4 ௓TVل fb 1101999Ivf E5Jjj0',ld\MmLlB_T218L-Mr qY5@ madbdB 0sX[Ӛ_,A'1w#B4{G ' '8,l]!oj/Bv3l99;9Z;V7Ogsj;Y LfҿbaF ,l&24[8[x_4\,l /__} =u_Y)4#ߚFkYB(vF]g_gg(00B9- SO[ovs5~`_;47n`ca8j&&#lwfacIX`j`wR8Z[ؚU_220GLѳ;dbk/Қ"*+KVd; ebf-/e -Z[f`W/K?`Dm%g[\ikMLMז팸,2ӝ0r'E{AK kzv9+?j隦ocmFMRd:FQܰn8DLdz4ۭLK4xErަJY]`FZUWʀ^hμDیO97A`*q!uM1MӴ9厏5R &J:ibSc[KER[l/f \KC raZs>ag9SqoEmA\Ĭ-J~Lkߛ; }U4VҦiDxD/ؙݮ허k# [VĴ%6}M!:"YyUFܟHΪ6!< -Ӊ1\#\ )< h$2 ;?eaJlf,S!TEpk1X{S7/$'4a]?'\ˬJ0]PtbfEʥ^}gG[!_!h5#/c,VrU5d?9E҃j7Ed؆>Ԃ+@}J[%;O(?h( |G-:%*\n3AH2VCr`@ &xEl8d1p ahv_!Z1RE.+jƓҨaqaD[8Z-JBs;k|/"ۤZ7/inex_iruȘP^] '㿚Y;+;*kAކaJVJ1Ƶֶ .I#F *n:a^/6EDoH6۰ }$l +^3|PN}ԦpR;'_)J +T˹+"u(!H0 z UH5Aǜ^GukoqzCMhH{n=PWͥ6SD<-fu/n9<X/W5伍bYn7va]j.hAE"ށ:(bz$7sqÕ#: Hy@*{ 4f_Y/~=.eZǸBc73glW* [Hh cd a_-^CoFvg7L]`4([0 = !sA5= ѬyEG%xPt{#]ʭ؄2mDH6ybpDpfIe 09!' E0t/ "pWT[{zyU k5bӲt7S!0c BSm-fꑰ Ybe澮i2TZ$sо#;ĭ4~c$S` \?o 8  $$B8rdKsG{9歾kZxY$T>0R Xwf:i @F])W5t ݏVPD!|A$Wۢ.&~DtYi~/HqU0 pxXq%'|au [!S~˯@U+Rza̗#γ'`OGq=+Rw_w_.2i,ҷbgq[,u˩VYk>2X]wa ;҈l5_/ۄxF7tbeU"Ve< Q}):@q7n4u!Bs[fp2ȄAEtebo|q OR$4~[#,W,I`DSb9QYF|: ")`?EleA6\Ɂxnsj˵W[)#X%13lsFB!‰@ ;x4.kDu)}D瞊&I'#w5DMvթrC\`ïm}pvKQݻA xүUUd+pFYc`|uͣuY:- ;3rX\+Reb6HtM `?¡ތʡwy+R-g_ N HGCZf|lHGS*!`/ȓQEPD\N?62$bn+.]D;'@Eǩɣ@PzXUDAp~]K_9/e;Zh#~v1z@q))SEz̊/4K@5ډA킉MmRKHkcen, 8~qoG7؇Py"+W_P`)H,-fM~R>Wj!AM`49o瑴%ɗb oTJg/wſE8Mbp3p<~Djۿci8W_^Ӎ >p^=@l*9؞&̀XxG/ȲX:P1.>GzykR͆u͇fn 0-ʒ 3F-w'M< ;YjkbOTƜ=с)B*yT"*gͫ @ޞx&UAwͿq mwS? dFp(v 8 TETIgU?CЪD6;SM^)ӯQQV$ y.O'킺?6.L*_dEgfBo6s"$ue(δđV,t޾֘3ڛD4++ISDR s#æ{T}(ٙ:PP;8Y~ԈZ8W~RfwBl;ֳ#3*2^8`jO|Q |WΗ-x}X~_7 3 ,("U7r)V})S>*e}VtVfwPtb9Kg-YDr;/6&/oT(ÛQ )is%f;e_a}9~Ђ j@rlhEm`56"rxH1~6t䡀SCS',vә-]ubo- %QŖe| eЏt?r•}n`2"xOw01"F 'T G޵dLbKkϠsA8^~&b-/:H^]m\L|)Jeݨ`)3q~]Hu6ՄC z &#NS.;\w$1 o? Jq*M"R.ط`LbR WeCDwڊwDh2y)A14 gभ)C5%o/3W-4aAe!f}ֳZ{_kTX%x5΃c"/ުݚ4Umwτ.Mavڙ!7!"HGi؝T7|"O~APa"3B2*TivQD-t=ٸ͒tbyq3a?ZX20лPp 4pGڇ?U{7?ؐ+Dr]dB2}x: -:0yLXj%;L^s$D<{!k⏪~XMyA7͚ ٣[jlW#A+͂Z#KB42]-)Ձj R@װN;ֶz`i}d6pAכ^SR*C1&@۬_|=tZjR/wmqb2TOaH򓸄"ξkC\p}AO߅SIiI쮯d=b^ 8j|PAGcZЂnR=gXk4H`oj 3W #ͼԩ`1৚I҆TUyŧw#=b)Pia2Xƺ` ZO/ e_fX )} wF7Jjw?@ LbD.R)ϨpZ̈́F5; ,#`/)M6iCIr/=`ʘZG1)6UW/PvLQKۦ'' 3zzU_bcԉ;I`H%n1z*5̚CF^mZm#ѽ֭zj(Eyz+̓p].{HK$?1O)zVey O?F]%oyumgF$qS|N^/$^A@tcR$W t6KP+[E^)ی!;( %+OB Ɔy;KuS05“iG1%d7؄}`jJ ,*$N]FF W#ݦ4hP05@_qy{gm BRVܖi )OeŐ6 Xp9OdUc#ٚ)VxyQ}̓^6UNBв\֠V  o(C9QT ] ˎI7D{ N+^ V#N/:Z1Q:PtY c;^(h ͖=%o$S`ן^rCzUX%Zp rs]Ց[a\gU;3vbL(fD=~]ABmxlȷF`3Cp[lhϥNH.\X\@$GbZ(gA5c%с=]:]ꡰa%Qz(NʰG6cO`s-6y{ 8#4ߌ0ӁۛfJSjo]=ƕҥwvg l!OWsC&5݃T)f(0G ?T0N"{ TUly'AٻJD! 굳qO۵K1FqSwo8C7gX"J J_*gͻI)v%| |4bSVیP!l{G5 ~/*iwc]aZi^C:U,l׵iwNV0`/FϗBGtBYW٬WaeM142sQ~>M# |KtP6$i̍rTGܛ0/بQu Yٻt BѝmM;J럾vXiFZU-}'@|kYձ3GwԬ/`68B1c)' k eɗ xH(P ~V, c+09FEta]3\\oa3D qd-T/[Қ d@K[:WYvJgl$1j{wm5<7 @L%z^ F@J,Et! SQ VXLHa|&Tf!ArڶӆvxN+ζP YM?IwY9>j.n3ܰ,U1@OEXd;[u#_txL ;|pAAT.RT_&ȸC(KwK6\r|<2C<ߪ&gZ"fqY=WHXZg,,,[˯0KSC1bl ]RHHrdH%q+. ~ \m}ES\PTP9G^ :%ӟiI%Tu`YAp7r *$]ʶutA ;wN sXk齓 k@{0<5SV=ê1>}!P6uLM~ 2O`V4]FB62AyBQ(~'؎=(3\<T/^;ti)v=1y"8L?}ͱ{9]H]^P_ן,^Zû5fѿH&9VDRE?KPiղ[BhB|8_ձdp׸2F+ۼ: TAn_sV'w@3`8y Vg6lJ m%v;::3|O^OCnruUaܷSo]; )TfO7AǁޔfIA.m2~ho1'iC #..jÂ7`l|x3f)WS#^]jPOU" ^%7K3򽒺` еd͑:, pJeѧ mgKZM?s DQBo߷} 8%m l\LpA" \Z&P `7p/d fj,ڎLbdO ]\߯YV%Fb-,G {i Y*}´US0F\@zQ**f^TOT]Td@Q$әӛXGln՞괏+/Y{}4_c (_(i{TYhdì~.T|f4&I6>Wݿ`A.鉻ޠ^4@ˢnZPK􁴥Bnݺa`&w5y?;g-G"8RWC Һ-y_98QMmglx8?DlI ={*c˸8Ghöq۠O loW7x܈o:-#5PNI5L.Ę*ՈΆ R uOi>x^Z# Ԥ.5m=Wj.\8{%IF \MvLS>q) bG›Mg -o+[>DȸZ=@|/=ӆtX\B3ÎRӺ^%f3z3a 2j-'yh?!Ƣ~AK;VHȨGE疞0P&ej\#mwf+^:}1SŐ$fczuXEee"H@E3^PWlVpiL3-Gđ'lc1#HpKhbsR'J;v43يO'րn~)`?V`4msj ~;i8# o."#M@ .6^8B .6ҤS@*PTUkD|b9~G2+G]qh7<!}hs:qa\$äfL>K/FJNC䘈rǜ ٺ 4QSЭ]XtH+RCSTI Nj qn@δy&!I*m[G 4A{#m$5Evb_+(T%)ݲ/ٺ JiV!o KGWUOV|0돆B/wA"[,7"}(!W2!0^D&.ǦR^v}&z¯*w~5k 3g.i]~5ˎavgw"Ԕ~@K Հq2K#HSBI2`U-/9խìbD$?%xox+- Ad{XVt*pJi4֠.'ٓѡڑO~b`LnTq)mc&یA@dLBڙ m!?x|{$(m`drm c7 DeD㺣GYODКh'LJH²zkeOnDoCr2U [qn(%DJ9H2E?sm 9w(*t7ܔ,f%)*M҂#(лK'VDDoaPJhǂ~]PkP%Q]'&a 7L2S^_L*-mU싞=m@iLEx@ÿCXؤ =%ҌSz1aSRҋ3(8B.8դ1ld|Jf Kyl_ܰZȸf՚sB  =>*7o7 rX, VpJ?h9h(O %'B2FMhdŏ vYDzz]=|poxNzR ef1ګ$.: ɗP4|q_ekZu+[vDAn6}6\TTw~zAh0\xO$(& F>g{3;/U3fWp,fM*g=~S-OcFjk=/qK gx-K ~4q)iܪ@D~9s} G.JJo`AiţK pAh]^ ËFOvZl޷#v+4}odDi -)XJ4oJ#?oODWF-0? л?Y7+')[acǛ[-%4VwubTcPpWNOGlڈR^e-4 1h/7VZR )mL 䰑s2]*zÞW1K CL&Su z!<8[0ND1WNK'` 7.SGDlE Iu0As?1yJYuLҚ=] ׈8KCj?uʒףXŵBAŌ?n ݺGbIrXd d5Kv55.wV8zbup%G<EʼH<} "z5 Mw$u"i  gS0(]noXH*HI’Y/߬{Q.ŨF3 m‚Gf8-+R B%]mX"L ̒$DJUAt%PHqV1}!n/ %*!ec'b7`B]-M'A Rk,,Ke=_o@ì Q`uoR<5\e<1W{`L4uG_S e#!D Q~xEc ,eL04'jň91qNVjy50d^*rXoPa*uCZ|ta@בOz3GHM3d9fxq% ט3dС(sˎߦw?݁vd0[?~7].nY$nMZ%Ere{x5~gm*n?hQIe:Oo. oywL ۛt1&./¸5 DuhV%Zڳ Pg uEߵvnBF}ZWG$5S("I81nk|(\켬.ؒ !W"|?H -|*ay6>ё =8e+/Ue~&uܭ7+9}?LV՚8BoP@b_p3A`qg9B8p%c. -5I[!o^8#'5<T0S-6P!{7g?k`Tu;V|^+Y4@zr7DD <at"8kM3=TCif2跱e ܦ焊7be/GycEj>0_s1b%&$a$]dbh/[ [ YvM/7]rd?ƺ#8c*)" P`R <&ZA;f>u-WhIܦ4p>GR_{\nW uA)>Q`  7W?Ĺ .XQ{qK_^ X\# sHNckt4%Q>t<&T}:Xh8B2ꯔ&m)'+b|&!,dj9]wD\85 ɷznn!m\GF[@GhxaGl4 `nsI- ,࿕y$;%#Lݵ)ίBz6~0)5b%DTuE`-ŋcqI- 2'slvŪTXj-^2My #س~Po/jQza|w ,1rJ^;αǰMՑY.8|1繼 ӍW¯p?7Y}hFh)X/^ kA.;/S =V9(]ZK͆Qy#'Pz|Jc[a~sWjupfn-E|.*4\cu )HOc_άdDi|Fst{ZAK%p 攫^PڐG<$,#yLc޴baS~'vu'O %uH<ؐn%E6o'oHk9I47=p/tc.HvDZ`L]@OJ$̦sG0u YnhMq¨~)L}mE^ߛgyzD , 88"h>D"O0oN_ AdaiDه;scn & B2wMv| ~dԈ&Iq>&hɸTÂi|Ga(ڿ`L.lݬ`T3&kh]a:-.5wgׄP0'(b%UB`͖O}نb PlSYi}nǷ7|[JpN. 5䗤Xk l2J dڅ/D 0#³0wgd+D z_:ma8qujsITw3+C.8+)Vs>%> Y sGIUj7R6(Np2e6vִ3йJoT=ۿ#2 [> endobj 873 0 obj << /Length1 1630 /Length2 11562 /Length3 0 /Length 12405 /Filter /FlateDecode >> stream xڭweT5wN whn5wCkpwwwsܹ7fGzO]onJR%P rd`ad(X99ȃAr _fNFwRhh:y@8 `Am-4߾?wO 3h )ǎ*@ 04e4R R@^1@rL`_90s8 @cw71/` ppxX8 A=p,@N&%n7=;Nvpt0uGUG憎vx`&`cJ{yG -@G_ [kCd`2W{5Noo߷3 G)#" {Lcf DEd 0ndOhwh$ M k7 I@?SNO?'k_^ԒN 6%x2`=cmhk9?7C k/;,hٻ0 ,0[8HZM,= dߵN[[dwL_%wJf Guy<8Y l\..v7 o -\̌,~u7 1Qq45/t#.̂,Rp3kwu@֪V$T|44=|H8<]lMӻ-.{z78ix"Wa=YD \t;/BP^Io7n^^J{[ucċ|p (;rٹt/6)g{W{Hw?wWݪ3B 1~ f%=ķ.Jt5]UTF]ƪZ\fH4S1˙@ߌL^rpԧঽ-BA2F1|{?aho76!ZZu[m#(Q=hy%DVEY,zaTHɻoGA1՝n{K=HӰ[W9us0WXc'(ԟn<u`%YF,l1x*8.]9*eN8Աn׆gcPy*Evn#Y>1qHju@MUML^LCB)].>4f'2nM\ɩ e)_̃1u_\WO͌_;?tY#Ԝװ}FǛF Mxr ZtΣ:b/u?Pˌ;/W?vx3<4I1ѡoh h/lcC<.$6O>~7ez|L~B2 ~ri+%(XxhhI}恢Hte ]wGa:0xEa]1͟T)JWXbb0~ B| CuL":sݻ![! IY?kAW u ePurF9=]RkCmKL@) \X?X]Ĭ}bYh-"8'av&T4|7.l%fȵY]X#+אYnt ȏ#480DO,mR;a38Xw5whXҗ0h9R}S(!),s]u#sQ15X$#âv  m?O rrc:) $ xP.~,Vhu[#Ҡo%D}*$&$2! SVlk ilo+eJZ"T~8Xa[+L _;F74>EK% < \L!6OG(B9 h-6-{ ;ʹ0lex0Ψ9\|z&\ n]0M88iq`dSDL{pzşUe~L8n=[XЋF)3 h~79/+3o-Prxqϣ@%A`WF47`ԔH*oKW_vtcH%%OBgǛ$ܡ$cUxwx3r1aw{DIe&Qc;]}mk OJ.;^WPDԌ"O&̲V'?UWk l|*2& ^̾"n)ypf0,pOoُ=v$oy::"'GDsᕻ+-^ef!)ɣDžJ-V̢a˃kX{,~:w ֋#*IOzCDW7J'qED^~TUmLF w>}g$f[D3~H ^&.j Z_yЄm:)8^.ᲥT}i cף`8a48FqԖsr1z𽞙h>jn!!tHr9ɬJ|/170Ec@pqlϳ ѭ*Oy%Ҷ}P8wߥmËT}sbD?te7OM{dXc٫s#Lq Z{=~5rw`7 `߫48,hh@Wljr hU^+)܂>g+QOaAF|jc(T-;PUd/cαd˜A${(%$E"T$LaJ%ϊ{:]7VpNێ¡Q#*s;3LACbx. KÞ57ȼ?6almdiodR"ף}&&Rt:0CF }[`Y//pxR'qGVܨOqp-)E^~onގZft<49"?#isxR^BvN<|&.mJR GCcZCk"&2h$QpEznwXDv,rxC tV* 1ZUF2˲Q;<*uxhkRbp!uWU&(:n"3ȈXg*3`Oooi=UsB%j.uG %w4{1_UսE2 ؗ+LbY:;'5AAMlu3ˇtc8%/᭦ahY>,Q\E߮%U'4z Gb[O U]kǪ(9ΐ&`RWq8S)KAq/nV_/&(@yx=HڤbVh#ȰcDr72 ONR:Cb-=ǎ)rh./r7^) 8?1OtVn+JV4 QE(0j7?ij" |@%hwӥ߮u@.υЀ尭mmGEo D4iqa4MM8*/.X~wgg?qƳC$=9n FOM#eej,V^:ݢZ~(}>Ǿí^:2JtY[Y+/*K5NK.zhȣKs%ȷrFT\_mTq4Eh#cUYuGSVYo>#_:!)RN'{#e%~ ;ܬҳ EI"̮%}.d_pkйUz8릝3BIxz~&U&&ۖ#FO5B_ռϦ]+C /ZaW8cƐ(ui/>FbPJWM/PbE< TVh_ӡ7)l'-/˧-hx-eiT jHqߦT6;̞ZO {䎻\'"hN<`tcpp#Y[c\ B0h҉_^ct$KdO5u>REV?zc#v4koK.d ^-i*"/n˃1 nKhk{zdvQr wv_2B0&i^L CPx۞te!-҂ S<-H~ h3(R̈́U*cNi)CډT"| 6<P60-qӭMW$*npF.A c kyDK8.]5Wnu8b=ka2gS2-/҃5iXĜ:vKL"9;Ŀ}6 G⨳QEDBy-eG߲&mXsbX)Ě G-zr )?8W:d4҂Qa"❳pRyTo%їItmu_3~.Xׄ5d3dg20 ҩ ]R Ut"iM5cS޹~:xq~Jsf؇Bw {E&-5nXFk)Q,ILc 0oDd/$4˓ts0֯t[C^W :ĦaK$w?n} YD-Ew٢ˣǚIfjƯNKY宅j׫Vt"͓Cuך2>sc\Nt8ב~$f-u*Hq0Mϯ\bV痛nfxz9+ a1ꌄNDc׎?hk+b -P7l/~;5s{mj \D]Ңְay ѹ:}v~(&- 3GG- bDL6tM-3MS2XƝ C*|+j 25W2!/8W fZWCU6=2=lԑD#+#_'Y$"P{iQ~y9 kHSP].y+M!JPYK;@e&?.FžEF(ڒy0 h}EI FԴzҫkі6O)4rIg\B0?:,}y1`ZG}m͝ի8¯r=>ԕ!6җT%Tcė%I$ 펵Qu<[qY|>i?3o,2#(^u`9z7~~on躥ەV,8ƟNZOgT!Q'*4ܳ_pW \=ۦ~@p> `̐s)JGubī5nPggCa{o qO;ItIC2džӅbCh_2n+.(j=wF7[?ѥ`Ulңg%̩&@ A3+5w;էB2rʵC\Oj%O9ج202 y(%#'?~]2Wϻ=Zf>IB[AC?.4opHh%Qat;S+XvјvCL9aн?yϢm=h2c;>!KaCH__u]>14UR~73!ee< ײݴCwx}b:&7}lY-8kρ.ǝYL~iHt!CkNA⫰(N5$ (-Hm:8jL[OOLN{9zԙa/^2M5sz˲X7ݚO8ѿ++&[_ By(Ih?D#uTQ4M/Ɇ(@͖ ؎HT1tYnf/m=3CZ_. 3iזP,DJ84bmBKկ pc E _)U;4 ըK!\o[nS$!t_KvWc; cy 3M1 SwK}>|NӴPckLՄPXVr^6;B@M+0Kf|X Iխ8 fj< u]@'>E&\o qۡcqrq/Nyo5=&h.k? q(1f5wNY&ܗr3sƛ$M[hXɷD_Ѹt.=ar*FC89>TMP$cк7KID{kuՕƊ׉c @vG?oԐ;/37 JNL1"Af BC[pl$qy>r5uuR 6?d'E")A5d\uªlY{E ,5CR6tP.MB%J7D'6c񜹩[9?: Cd6CW\M+Q e%D`W=5q%QA7&bٓVX[tk],D9>W`J甸XȉQW,ibeA k^jE(Q:U4!W/SHF]TDnѥl,;5w {B~HIÞ3n K9RhNUd?BD:J!<}T3љ+.hhw~} IT=Aͽ`vv-p:~Si712=2Z aqe`TJC/BKp(/sm>o9Q&T/UN;0R})?NQcXQCqr{ݥr%}5ʤ(>u^z`,qX򷂲 Ov|Ba~c#Q 6U8r(4MO7M~]<,ϓq:wjQ\n«bnP:md\K~ ,^'(^'Bʩs}F|ucK &*9ci=P{WtH!of5z@ZgpYya$ /Y9,>J>R^;~9>Ux|-(6KhI]2Hl`51k誛5yo,`,FFȬ/q #^y[MwW%!ӀTi,=$zWwT%">E}s? eZ@CXTiCb.IrAty4& 3Yi /s1`~vԄz]8 b= V,غ5TgP3jݧM^sFD e<>>{1yܯ%?ӁzKa2Aiv">@@ &RRqJRY)3pr+&_N3">,lv7N\dEuӑ *xF݂]!7GG3pFSolVd6FҜRK!PU:PAfwGw_CgRB\f+z@%T2rdžEoh18ހxviׅOH3t߅6jCXn!.|LOr<Sǽ41Lm/vcyq3tv+eɾ{&H:Mb V9 l_'+`͠fɼ&6?uBܼ~|x 7Ѝ2Юsjcok*ĩ*TvTe*m#4@*nT̈́%V*hqfh!< >B7 08΋g\f3ʫrXCuPG,Q~[g&;M>{dxua.a8Mi6L{x{HԪK8)ڻ;E}^HuEl==x&jU3 Hs۲XU{*e{. |mdžƷZKvF3-3Ʊ$8+Y=d?fbz*ޢY4O wvXHP{;fLx0ٜP~ +~^$&U# c -8$կz0EݡڦfzYwU05K'o%D" ~`p]m 'hu_g *A9i";<)+}XԲHh`Ǟ}s?f@ή=bL5wAZx\0LD[]q1 4X=0εyo#\zccx=+JUnRV+],&t`эc!-:rgm {̚D0:9.z3$45@% %-60.<˩UoK g=_~x=jFS{ `4㦧 T|RpI.8[~Mg ԗjhkX31ȟNMlY ΠuWrvh1Y ϔbezJΔ'M:KX&״ D[٨42g㆏l 'zB2W\PY8Ou~toU+aGA՜s'Wfoa7~HX`HRC<6qHcC !Uqjc]k.n-&~>V),>-ƒ{Јc'ÌH6gؙ;|Gf 0$z"KR?c4sZa@gC2Y󐗳qqbbXj3=5o~}n4g4 luv6&ABZ0@2;[QĎy"?ڲ <>6w'|wr(+Hqh7!އLuX:bf [td1aq $gn`3MOڢtx3`^ݱlZV^xZvDdp>Nk9 3;Yē7?b{ endstream endobj 874 0 obj << /Type /FontDescriptor /FontName /KLLHEU+NimbusMonL-ReguObli /Flags 4 /FontBBox [-61 -237 774 811] /Ascent 625 /CapHeight 557 /Descent -147 /ItalicAngle -12 /StemV 43 /XHeight 426 /CharSet (/A/C/D/E/I/K/L/O/R/S/U/a/b/c/colon/comma/d/e/f/four/g/h/hyphen/i/k/l/m/n/numbersign/o/one/p/parenleft/parenright/period/quotedbl/r/s/seven/slash/t/three/two/u/v/w/x/y/z/zero) /FontFile 873 0 R >> endobj 875 0 obj << /Length1 1608 /Length2 11132 /Length3 0 /Length 11956 /Filter /FlateDecode >> stream xڭweT]ے5]'wwwww8,5www{_~=׿cZfլDLA. ,̼E+;SW<ȁHA! 2qr7q@fq `A98z:[YX5The+`ON= dhwyoT. - #(RHA&eWS[+ @ h,@{3J3c&#h 98w`lb=/vs 9:;Gؽ.` =?xXl8G9]*o;̻ py0;ښx~st+_  g3[WwU'Tohn dkΈA7w0nOQ534$Lm=f sD&Eʌw"H";q]rߡ%]mmM 1_Z0@d\L bo.3#?V`I+ `nbޣf g[+{лo>uK+_M7w͛IB\\[ToӿUwQt|'u(8/ QQ7 1xy||k`l{/`$f͉h/7]ѿO{\= 0 NHsfq,W/vO _0~09s-Kז+tGg> e;Na JڑVٴ]Nf͝Ug؏clgw4oQ)u18 5G wT}.`~ne P}@p&ը2-fINAͶ2۸C/.zՂ N=}mD[O)IiB~=2+^š7#L5쩇C6<[ٰ5&㌽ͱ)r#⥰5BT P6 ~݊#ɘnP\F(q¿ɚ/ mr+"͡3 xfvrm)*ߪ.#%а$dwLl &;3Xe?j V&Y`zPHhF(Dp`PD6gO t!XRexw op.]s$gp)ñ6lrB:Pb$yюpXmfݿHPV0̍vq#Z{y XjIga@K<&fVH(=M-*DSՔΕb(M\F] Z&C"@z2876lD<m ~WvI) $`Ǽ&!쇩8iڑ2^m*,9eߠ+sZD6!,i#_o`f7E_H! d6ۦV uc65l\pd*k|*HyB#>BYSZ'Nbp5'VHO34-U>W+-j¡;%^ggVw31O(2@|zq(K=L%`BBq0:4F0)3(Л US ܲڭ k= FٲGuȅ\Up\>R(9W.J>A4Lv>nkgZN{Fc~AY, [($nݺ7 &O*w \6r,!(@g1\ty k&^6짞[|F龘+"d"2#.9 jBSn|9gO_he\4 eiuN%LJ)A9m sN KP&2]$_ҠX$C}8J_gYun;}D *Wu: pPKlMQ#eDNNcO+ 4U#fkq"٘P}/R n02\B#,>!p+@. +)y qmsRP?ΐS+Q}i>%+.D'R0 ;v?H@S?M@*e;h>*홬. d, $kX#ٞ 4ʡ$,S`&3j4(ӥ|]+<,(sH.XNx_(2U7Fl 6|C@4!XBB B/Fi8"eaYrShRZ |||E[Z[X.jP+j<$:bt\Z Y2n~'qm>/uNmן)JuMxqWē'vaɻ0PR4)f 6M #iSM[s;h*PM,":ks_r1:HH?9`hI9E&gV뤗aZ!1p424zcMe]HG̻~2 7"bsQ@;b)ʇGXKȩi!(Z!hkQ/J!3y4@%oꋧ%~ćIQUEkCHݥWqZ|Oׂgq ]'j ]C- S&9X?ɲ8ߘ9TfNԜ8`Ϲj>.0=3!B >hd_ntUqn/XGyٽ $@^֥rPGgn1 /0"|yVQIH~?CH}xWPfvm傳%&T v^j[sEH``!-o7dqeU])yQ_s>f8x@64n6riF==xYIA;"½~ wb|`pbR m^8&v~TieEb쬽k#dz,țȄC7mppY"NT-ӛ]gICَ2yK9S`tJ@:Vmirf40ݭ_/R/̊6E9#'1]|ڰ8`d"Qa9=C"F߉; k#> ŐAЀdPOb3d/2sDI^A !Oʦ<VL4\ccUh dʻܓ^!Q'>? f8u{T`w~,^UOyu0LozA;'v5הʰKX`N>-tsC]gyKQps`$OUd.½PYaV̾$Ɓk woSJHtndm1ĖN W3ySgH05kXk@6#&Sa>Wķٮu_%}hߎe2@vw2lIa%.P@3.Ay8_4$&H?rh6pS -a@ϭ ?d0oҧuoW6ݰFj|nFO8 yvRnbl"@qe1`ص~5ѣ>|ُç%Uq!i{j=%4ªjm6ukdp96j2c1t7 h+"*reѓR0aBKW)r ~O =nb'Fb?c[t |>#%tƔleR/EϸʃߕuL} /rԤwDekz 4eF~ q,ퟨ|N36E5UQ"J!'FMq+<_pmϣ1Wz;!l-}a7=l0}Q *UtH/oǀ=G~i|, k.T[jԀdq|^Y1YW Zo ֝FO- AH_2Zm0:t7 58j1ZƷ9F[@ zNs>6"hc^~Z̗2F}9Jg+:mgm*KCSa[Z4`M5=͐~3cB5fr*w T7EdF~H1RrxhMѩimMqӍ;c6?,H##OVG,D}llB737!CdN1SHO6d;z vf_)ʝ|?^ó-b$;uO)\)гg(E\?0=5cZw6ryYч_s)a9F.I\;*}F}q+,C(-_nUO!$gkMF]-#t,≯H[&%ג҇~#V0oI&%Kx1R XiV0>F6}}ߓ($XlrDbS T!6>ŦȣР'WOI;+Ih+X񥶍j4}N, Ǒhc9l}l FӗB96:N|όj卍ds)k#6*P䉲f{ (23觞=8DƖ띲jqd}^u! dFPXISaxrSfwZMmxgB#8D>I9wMϹxW1u@ v`s]:ә~d4.}l},1 v}fn_B`D6Gk?仈Kb|! TtP&)73JAOS+qS (chE{gЫpTt tVmG}F4JӉr<ՔcR+Y\^E1<**2 hPe ݬc(ET-l͇}"a91ۼj$6ÁmUF`)B`II݈TY7S7F7N?^_nCZmv& =fݴnNaŠ#:NWTMe|=# ]v2eHsx㪎qVDҋ%^KJS-2ɃuÞ=d|Z6|oXrxHu%qfhj5_y)x"rF&u{D >/R],93BVyQ`buK !mƮ%-xZۓEi;h!EJV WMo}E[ku.oQYD,)i+nA@NCFzf$y.&;#7x9ig [(vKfXC2rf!*uR=ekqSnÇ#cxZ4e|RLX@M=t0XQQ>'{o +T6fĊ |=_rgHq?ۃ"&D<ϕE*|[]lPأb|1Zgdq1D<)*PYZ/3RiE~s{mQo+*r>Ī"kU K@ٹ2qA Fz葾7b`EWӞ]?C׉_#g!Uh,:5&ϲ&"hz1?y{ Wؚp뱹k!J5;׳\z%MU,W/cO5߷c+.C'MUut|PId{lN;iӢ>6/AXb]`A򄉀q!Ir)e5#Na+=w$ %/\ϊOļ1jAJ7Uvd?~Z|=Oa?R |*PpzfIM{68tJ FGE^ 1%-zGv=~/Su ^t8`mB!Da3ؙOn@^5~l0^R]]O<ڿ$ OްufFnzC*C%,tiqhG^MK:*D~_Z`Q&dlGׁpf5E m\ܜ.W-Z6 9"?ٷiǩ5})SnqK]Td }r1:sjmI,C"Βg]cz HW ׄB@顀 a;~cY/hk& Aev-@[맋lt*Bx7vquZA[ퟑ|uQ-x#Y ?LD˙Q s$yVO7ښbGr0<o872//OdJ,iEBFTײĦ\Bd {ӵdPe=2-:y>|z una5I6/:MqN`gU{,NWJd /Dȷc"L#8pT!Urq3t̫*Nןݶ;zsbO9a(F戾=Ep,D0BQ?e) 1St4"x[/ݑ6-.2Sn8=SHˠ (yk,&FE(O0„leO6\ݠg$kuy} ۿ NfѧV0[nÁxb(pK[1,1!#i#i\>sRjUˌmG:9O W.]l_p=wR~5#vlL;JH u_Ғj ǤLjη+Gǰ]#3KgDM@2vwu-֗35}N5ǛjJ;w"ָBҞe,q0'^jDP?sZK#>2[n1(ϭ\T3 19 endstream endobj 876 0 obj << /Type /FontDescriptor /FontName /EDDXBX+NimbusSanL-Bold /Flags 4 /FontBBox [-173 -307 1003 949] /Ascent 722 /CapHeight 722 /Descent -217 /ItalicAngle 0 /StemV 141 /XHeight 532 /CharSet (/A/B/C/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/V/W/X/Y/a/b/c/colon/comma/d/e/eight/f/five/four/g/h/hyphen/i/j/k/l/m/n/nine/o/one/p/period/q/r/s/seven/six/t/three/two/u/v/w/x/y/z/zero) /FontFile 875 0 R >> endobj 877 0 obj << /Length1 1625 /Length2 5111 /Length3 0 /Length 5932 /Filter /FlateDecode >> stream xڭTg8&zޢ! A轷DB2`3c E'jt& ѢhQIH""D(uczuu{51U ZHF$&!==Q5$< M) 10$BPu$%DaN@ZXD_sOsB/(r"0x: 0P&u!m#K@Exa H48 yibx.U x0|:(( `{A0r.owDB#nx Ofx8a( jN3s#tx2[ kFCP< ; [` ;_`(Q$v!(ϗE@!?1/(wwF/ A">H)nSBݔ!#G7ܿ.>Z7G2p `pwGkBϹApOD$)&BL`g 70?@,aߵ[zZ{WcჂ+ GM deQ) 9䤥CDΆ`  ܑ?lFp@BΗF@{/9F{Po{BK6SŚ3q'U\kQ5/WvyX݈ w_P'zWW^Aq w6ˊdnXmMHX, ==&iBo ?tyE^BWGPUeC0ymJwomK"  ^41ݳ/X6Z4f7:Foqݐqw&F]xrqF\)]:nYޗ[,nC'YS[ x'IBA[9m"7Sኚ w8t|d^MD(Aոia ?gI{ߚtLL֪s-<F|h`<9ir$+hq"'4{ =8!!"kM'浒𗙸*Zw.ڱRpeje$F=vvSd+KDDǖp[i_- Kz*v$Ʌ]R߸nraC8SF{w=}oBQ%bhU",r4qtl~hui'7Sc۔r3:\U p 3SlHR'RZͦ&bEȌfrcØ~%-qgP;{=.E-3Em)̆}ׅ)Deʦ*pS{U]Vtc>By}+{I9*#KTЬ +ׅ:\ZR 0W:1w_;OSYKPt7ϵ(oL%u=Vt ¬wf+ #bBoeż4.5VBӴ;׸=y,1jyrsh~KjD3{1ơc3ڄDݱq Le ׯdk=@v( 1yN#&ЭqPA۵<* } t%Jbuڼ1EL]_kf2J8mqՖ^yL#}'g{*{ObzT 6OB9}T9 j|K.ۺs~'p3)3a\~>3Lt2'QT9ܦpkn8'mVKvH\g@Bڲ 꽒iAR dlCsB?Rn䛋n;n!:*:Һ<+'1(]:]+Fxr٦ ؉UԢ "/ml@O4d9E;^~}g vn&QR'F1RKm 8k14+sbl5Y6"bG#siDZ"KN戈z?nDًSW#iD~J)L|j&UZ@ŇsS> fҒ3ƌWJ)p7VIa=+(wlPȯpݙz bJ!-3`IJ'=P3 o"`f!.K"azϴ){i#}նHIjRXIӒt7C~rQ$te)TX ~i^8j狳;|t6VnfSf7^_Lv3tlvy{Isʇ~L_͈Q4cQzGŋR + mzNݣpRO.KXn>`C~iy?5/B;TϽ""(V60p'+Ӱ^ F w=ٙ2w҄mS8XJǦj"y,1<AnG_?}f c,q-ƒ~EJaBA5o0?W4&u̐ [&kԄ4Z#/;LSfʥK[w%|z-W59эz i0m)mmyP;.pZnu/Cw!zzDh;Qg2;YV MA@Y|~KA,s3$Xv ̓A)MFH:cDyo1qⶫ?T*9/|!jjn4_L՚h=twң9J M. ƃΒ%yjO`k;9/_03*y2.mR ,ٷpYMC52_57]]VaG[txpP_/u} 0LK}N|_DnZǶ&ŊRVcMQAǻ?¢M;vï"wq{>DShK\q*G,BO+Ϟq;Q0w>mf$VQ 4[ UTe&}o3&b{>nE˅}JR:YYU() urPѐ O\ Ro͊[oY8 ܧܖd\F;2Ǝ@܆Eg>EHy8Q| 騳 W7A_TL,բ((OJNK;7N8fHí1YteRW~Di0p9^3iUZrֵ{?"koi*0y9M9oI*0SMn4hQҦ'ܔ񝢬׋ :ID\ltͩ&P[Tf* ,n:!F' U)U̮Z|eV~b5FjKU|7U$1uO{)72%ј6d-.^2+ jFXS!]' 8=3;*킯>bF,1 Xخ!#\yJW{ޙ]}_ӧ7r6nZ2U}}s16W@q.0_ּS/flM0ӎaP*vfzv^10b@NM/+sŢkI=bxQe1E!mM0*_3οXx APT&)?Ʃ& ZOU5F'KQL۱kBڸ?L-=ja8J ۹Y~6-d$VQ #fg _}axꗄTAy}+o"C7tro/vR8Ļs.6d]}{J5p%]A?(e3_R,V@\Ьq +숌Y&6;&f .\ӻw0NI endstream endobj 878 0 obj << /Type /FontDescriptor /FontName /DDGOEI+NimbusSanL-BoldItal /Flags 4 /FontBBox [-177 -309 1107 953] /Ascent 722 /CapHeight 722 /Descent -217 /ItalicAngle -12 /StemV 145 /XHeight 532 /CharSet (/R/a/e/l/one/period/s/two/zero) /FontFile 877 0 R >> endobj 879 0 obj << /Length1 1166 /Length2 3147 /Length3 0 /Length 3895 /Filter /FlateDecode >> stream xuSy}lcɒ<%;3cce7Ṽ̌Y0$KeDv%"[YRDQ"ZN9su_~'WU,$)j0 ]x;U0 0A-4, G A3 3xs4ɣ=#5␞sH N$\!p) )gR 5 S\Db(ĺdz@VD D\<U~"j?d\ c."Pq3I̦;Nh ,3.Dpbdb0r RF-X3BN2f8aE[cnx\81_0@ E`8Fa;%Q4"Tہxll @Сd021dtPHT06qXk h x#`Z2/K~;@lfnE)Ut4UCZL03ji/-~ uB'gJ|>S#E$2ӛ7+@0 :>-5̟ڿZoo(|`AEBѤp9kO :1%lN8 &]~A'U5-_8Td]|@<x +$_HLy]} F' OnԙHFv[ۦJkr 5ct )s oV{]gu"CtM`P$(izK"3U,n~嚧5 /5.qᱢV;G8g=vsDp\ێMy[/ƷBmPݦZ#Vܔ Ir~b/qBHi oH}Ҫ'Ȟsl)c*3s)#LcccBgX=:괶6BX#kv F1ahs4J[G̙I\í؉6dTzI6@(U;wQ'X/,baU;RaT3{4-wTgԇA+Gr)sp.t)fZL)xcY[BpptUK 2ᦿ ed E6PfWtBw9Ǿ"e?#dH}k8l|[UnܰYvh]5:/1M;s?wßx8Ji\jhq,ͣrTSv-I KT#酿P>)=Pl%{UrD\*kk=cUeH]Bo;h?|^6:ٴtCq}'?)?}c\X+HǨ>< ˋSWJ) !ǚ R^}=ithf;.bJY1c E٦VjHWU/SSVzH%8YIy:lȘUaAYܱDk${sf7n_~ctwsCϣoG,MߕnŶ K.p+(qkTUQS kܖMS>L gb+ù?k3a8|R,;R[7]~/qaE5>&2V{[(qt%qXtÐ 5b*E˄j|vR+.APœ"gyFumiXMM-r Zz;&GHi<`S:^z-u=L+QX^FH4hhPJ̚ϖgrw \3X8E~d5~hwl~#{GCǣx&&rq͌ݰ Qs,i ?óIv9y}#Zl_HVX{j W3֚{}NKxz˕)hl$R8W5OG+)e_d mx}tV@֊I9s'䕦63 | GD~ɕsE"9'VM0m|*%u˿̢z#0[y;KkFt٭/S{|#*W6 OIea2IyٗO_A֏=!a۵DY>;(co |.!1-_WNw{vp6[CR#FʂzbF,=v5ԟ;=2 Dhޓͅ%yޒ]Qҟ76Ç@0e%p!E(}DI"W);ASإ$wqp*ᐟbyRwV)*X SWV:&$t8݂gmL|}<|EPNY̪ܰ?i"y 6?D ەZ^R.M[瘎1\k[R\jb.:س7.{6d#,F:ÃZi6Fr;E큩Ʊ7VI V%v>#SiLxSwC˲^s WVJ [(KvEι ;y[vd`^ލfTN^Buh|=}|]&̡ӆQ-Ӎ1s>WV-B!.Unchn~Qf?5w.r|+ }G1 w6lN-gɝr iħCu2F=Xg$203&&e_,3Cv%A+]*#KNm,b2mv}sES+p<5z> }u0캲Xi.d hZ$MRhڡԢ%@Q&: =Ywzwud>'Fߛ 19`d044W4'c̨->~^# "(1oI uFRIy=W6#>2O<~KiZ{׶+Gu&J).tY{|(WyA endstream endobj 880 0 obj << /Type /FontDescriptor /FontName /QBUIVB+NimbusSanL-Regu /Flags 4 /FontBBox [-174 -285 1001 953] /Ascent 712 /CapHeight 712 /Descent -213 /ItalicAngle 0 /StemV 85 /XHeight 523 /CharSet (/A/C/D/E/F/G/I/J/K/L/M/N/P/Q/R/S/T/U/V) /FontFile 879 0 R >> endobj 881 0 obj << /Length1 1626 /Length2 14278 /Length3 0 /Length 15125 /Filter /FlateDecode >> stream xڭctf&۩_K3{(SOWby #c5R!!|"cph~R1Hwh<@KQS(27;I xp(WCtaTnzn8Y rPmRd}>34 YooEwIuGHYIa(c S T $hwv뷆‘bi 2*Na@5ƮĠ]J K,f=ou%xy E}rCEPdb*,yIٕrx?ÓzeyCI Xw-8;."wDu 9돮> /=ƸfN<+S*`^z>ԼVp$m#GgY9ħY|Ud؋DEh`ڳaJ`˼ }]E*hÌfWr}dhi'o$]6bFJ>tɊA)~U_%Y-ԪxĘ 63mvД;PT>ULlpa$s28?kGf~qf*Ѯ3?}TQ3= ?Mg~qQ)G/K:HxKz,?y,yeLب)%pSHĩD4) N tU`O+[ݝλ>m1ry1!N nF_ yrNw}e_cčMG&Fkعfb SFHciy|z),y]5XhL3fuR2qǽ+ËO~Wz*Jrt#`5|Nz;Q7^rrl$8O ec~8QE[7_a9^xt!zb ?Z/H-osw(.g!Ƹ_3,MU]x*4ɜd3;g!<7E'MCu4?YĶ"* LR޴6[/7d?Xuw6@5nMW_r$FVC59"F?dU =7v1J#Y #|'.hdTH,&= eMŹʢ/]7}S=9@S3M?BK^U*GP)t 18#ֻDM:0Ͼe(=mih0R vȵ*GЇBEw6%_$?uCFM$驻^I'3_`L4jSC Kg7Z \;z(0\'#J=Lsę{XͰz Sdru 8b kT2 nVt{3Y;o:c(wꚊb9FX_C("ҜT)T0&! chWbv`Ň!oI.==˻߿]\;Jks6b ب+!mr2] 5`Ax! X~{FF{FZm2MI**B~\/"c<};`l,F(^8`3Hڨ:dYOӂLt!ɠ8y.#`K7\|YUJ7Bbb+NFDA@{te\JdzlLGĠE ~$hcvyF_Rg5mp6dy잱vr㹻)I@T-(ԁ)T|!%es.eyRxRg4tՋ8$tE^ ݺ *t "0{%FKVQBջE: .XHftQL@np#¤ʦEJnߊF_XvND̹֢8IjL+ôV$ŌsVq/4sX}uZ.40K\_.WZLb;IQo<qu C~&%MU 6Wb3m"lI 8[< S0IPk-CpRY3&HCs8&(^^[M;t0Z8-w/,~T\_~3;%vFRETP~PtyЙoEp[)t r"EDD\ yjcz%ʇ/(BtʑS*DkLYJʟ`+B\Y{^'\=3f%dD$=G wK<“ebpgPY_817AkrP#8* X;/A70[=S!q#M6Fy+YWLh^@Ux$ipvzJApSb5;&d~gяbxY+X;^:Osߙ@*Hm[jěD{}'*uƇdre3 pܻ+#ѼKx=EiK c#fkH棒 a\^8 vJ3Zơbp0@`ju5!:Rإj<2l']Do?4҂]vsҟ1zߨ~C{| ԡ9jLWvxey $ߐlHpTT7C/M/հnJlN eTnFv4.]܎Q!e!H~jEc7S+ڐ#hp}X`r>WxEKck 8gD&>%EzBz$|E@ {a#$@H6Х `Ρm;b mCYcKKx _ŵ`e̺-V~n.ܗ~YjY:_*Vwc'?s4նvh_ܕ+)+CL{hE\zY| N6ھe)ц9kP#҉7k_ua6%\K+62caU t}na Ų?C>R6-VCa:O34~LA1OBp\>^ه~v R'=`$ɔ껑﯎{R/(]婉IL6'߃68:ӿZ2~SG&HlҌ[0ud ޠS:> ;Kp<Pʻ0K.Mג} &-{r* kgb5h?eq h樌l¶xϾTFPXdI(Ɖ 5rI&?rJM)VB ʨ8U!׫ @NJR[)q4'u 7@)fy2/u=ByY~Y2adv`,#kPӀ ]MY *#*g֟OtID1Jd~zDpEˆO`}VeZ ? XB+l|{ίOt ҍ #DS➽ $?շ:AIÕ.5}s&GdM;2 uWnn>-I޽٤nEFd|ix S-]nZ:y ՝ :L%L{f7-㴎r`!*lh+!Wd?|jp(= ŮM:M;ipTy<%U`͇}-PG@BbOHUr`KoOy1RvPRu8`]%N^0 ւk^Qo`|<>28b .Ǿ׊"bT6}棍sbR ϓ\17|UH02>s5Wu#+'WoCx\S~ףR<@;%YL/oij~fee>~U<dO78<Fƫ)_W'UZi0eG/sJAJ_(4NLWY8*($`~ba^&oW![:%]G$AJN߫qwWb@4aѣ0v 㾡O}"zSp\*"ӎ|=vj2_AZVS} 5+bJq}}Yeg\(0R\M\J(lWE"wW=/*iGXwKjgx [Y,Eb/xGZhv"fAg{(vP)I腼 _p/ȔA5|0h{a+%&.>UO\ZSDxb0b۪JɁk{p8,ev^NB[2%flڍD `*JDgo|X'o׌12Oajs0](?Aؚ˹zCWv01ݞ.lC9 |m g`} `4T_~Yp~mQj ڽe;&bCFkhLꑄڝ GZݒ +nmZ0߹4! G7yC@ֺqo1ܤ5R^?uz1os͇p Fd{ FX(V@4:ܑX?"=Lkh_bI]%Fg Gc&aL?Ū:*?Lg(zHkN詛Dim˺Kߘ>95!*j};$5>E] \X{u?$q`^Hc~*\s7Sk<8#J E³ DaFxt[2D [J愞m-S"3 Ҥxl` nKZO/*Ojk2|.P//$[‹Dm62yDi4T׉Ac~3ʚs'Mn a ]daMkWO$xT]xt1}P؏њtV+M3__k_Ng_Ƚl6js h  ҈ $Gz \=<ÿ6(wµlk{Ic.XQ'}u-U~rkgѴ &گEs\?'5j`nD x@%3i]aQDʈe݁эb#6rA}19gLiUDN.e#TWcl`++.[䋫jެi)S>oۙAWbGnb2~}%+WBt&U:YXzq\lg^"ήWBtL=4&6J|Vs$]G[ ؎|<$^_%IZɅCpL#[퍛=T/y˘rȗlkͿF :US#.ϻ"qy=::Mp4>RZ<8/9.boMlh!߈_Ѯ{BwU !-C;Re*{ r)4*4VQgM|t<%c<]< S+9)Rbkԭ.ĬB 9J⼑ GųodHNk7HQP99n=$5p_=H&ݓMml^Koa@2M!1+ yg7L5~uSyzwE_T7rY s47ԙ̯̈ⲮyIA$GknAڐ&?*"5|q?a]qgӔ͊6be:qEbi1!=Ȏ6lʀtK:>҄C4>ۋvyd cilWDꂍ;?Ǫ4׵ U4iSWwR\up*Z;^Hl_B <]ݣMl-TY?zR=0S#_6I]@OSH.2V:hmQ>6/Pr+!0; ?#>|q6z-ZN;:8-wҪzC9<|AYӹޫ$-u.H\I| ͮu[nD5z D؞Ћ O n,n7SPe-\D;KfP4)`v污IE\Xz]Tm$}5$rHF,K>8?=o+7(RϽm9'chvۘW)T hL0d?=lz}#8[XF UbOuU_Xq6fSm C fs!wngJ fR1]#Ԍ 3d"}ѱFpvPq[uWuC5N#Ghs|4}S/욿LPaZWV9|&An[IПcE~r~[M:U td__^6plm5 G8woNF(%ݱn/U#LTI7Nfʃj!n玙(̑JVN45su/-5.*Z;+i{/$Z/ӧ|7(;@*0 06n33m>#4k%6D21>%K2%o|ōY]R*miHo/XNʾ-x~#sVN7 /kī₣cM:;顳 wpC&<2M _(VMZDъJzwc})@w, &&PFJG67F럛U>/L,0 ^맧 J?" b-kk^XFH-#Brv +Qsv U2uUMY<mG<Ӭect9?Z[*H4T CAԊlh󖿸@&unF -.8dhJ<zՖ| Ă4ZHt} h5W^&;&ǮcN^TҙUsŔ:jhC{r[-LZ\ Y&EME|߰9bL| FNM||O]%)l0Vo&QecޔAIA0 !v1<) awMFF2/{״.I!sK m 7a]]ċDVAS#=.~|8KyM-=zm ʕk7d&;(_қI!gVdFwS'kjAXJaDz(*H3yeZKik]_D`}D3%,Le"4GR\֒PViT`dIA?\t䪼Ñ4GRVvGRX?\fr ֺka<(1VBz[2+My VZnaC;]^S!fom늼NČL~>1#ĝFk[GN+ElTi1\вS8aaޗ4#рt|eC 9mw;@a'sO(h ⑕P{:s?!ΒC\tybF'h$ILc枢Gkg4/9 |=dz+FG(5Ut)@&yB@m~G x^,>O*=$ HN~׮Ƚ%~av,od# Noe#ɵ琌5GT'#_j H<VPw }-4٩9\$:!f09ά_6N﯅à2qDoP3=V]gcx0mF2|J,F(.l`jv&Yֽ*!ǖ ._\uѡwH2aYE/B{~4]mfa yblv >spJ 䘷́%.4y=,IXYD(Jik-V]znX,7I#0e<OӝkNjkSA! %ưzoɺA%"foņAK'?1 8L ^98{ U(.7o / Ĭ=‚]o U`U~@!;F8D71V>XsQD Srյ` 7 !`:͇JZL<;u-uJD9FⅣ\Bb: )*$w Uʶ(;Y`s7s†+*A\L+P1t*,عKIʃٰ j_AlE :ta,ami|_ogǛ)/-gK7B̛a7]\hBSG烵J%i\nwLA1׿?R(f>d_c.!BZq#}E>K/܁dHq1񷪪"9mV"V} UQ*DPν]~ڍq[bLO##":0^3O! .|i?d#fm7#q` ŊczKUSy&-_= B]\|`w&24wqğ&B8r/G2Q{Jo0nOxg-a:&z ejXzGixViů v֕*qQH2La9!Hᥘ]3gC{`zߞ>Fe$I.pQyI\U}MSu%NGbwpM^P7[mk?h}.*[>qb=uI$uʎ,c%<v{ 7o:QE͍"_ߑ䶶4ص ,|Zyc>^? q?a?X?| Rqc?h0J2DxtQnGn`Gؼp]dq@ogp.t!Rىx>hMwȺYåL4t$r*)`;bb7 ̛8ly+;n'@"!ӘqJ3};aQVAF **Gb.IYJpX~Y]N%$БR3ƄAWԯSc+,O#!1|k&ìkw)Sx{&Dl:η2q(S1\I"_3aNmNY1 LۄlzJ?8 J {%9hDŽIGZzM50<V͹28]Ԉfyx;oT) IpjA f6z&SaϲI[K 5^}bkXӶ¡?Ȏө<һ&GQUkR#UR%}p81֪8>qWP2"q$tlg#(=QF* G@OR ۨ,&P+$_ P} 7U±3'5c-j)*a"(+_1tejf@&t nc^Qy LևvP3v 'Fi HDk쬫e`Yf{!+~3mg p5꓎x6 s}o-v҅wJx!>}'gz@) sCYy9MvDZ9<ԅFP[h4Mpx^Ш3$h#D8^ ypXmL9}Qk!$WfwRR%] jܦ0`/ЃLʷ꽔$/;|Ʉ=QP=~j(cOaPqn߽_YPO6ɩ7*94]#iy91+`S.G ,d M5Ll~,*^ ;N(֑P# >Dv$WWhQܨ Q!YXiHbWRpN\> _1HV}\3o:`W*ujEd5,^:м.Vd=rt1Cz)SAg>MP64EZ](wYm*qa)êjD5؃7!#=D9SQJwZS@>3f³Se)PBɋ-__d.HLy,K&m&rK9b~->YS~tnk@^Z fGZ]%LScI:;H Qp4%j'MWf,m؈2ĉ)g6]ue[W@ I>9 ~al2~$E,ɽ(?ssob?`&¡AՇJhC"q71>gmCBF:tZ֝N4P>6׀7 rNs߿|^I1ѨՕz &0?[+-9?q3J`*$JNR tzN7iKXǜsPWt3Jmk b1W2.m}?2Ap#<2t@JÏ M2`|ݼQZuVǮbHq^ԝY$媚Wl'<)hIŦY2$V[ Dq=GZ~hQj t\6 < [”&Zrh!ߋY6^J@k<tiB7T"΋1rWTc 8fXhU_v%]Z5'O&0Rt{},u|'f$Cc P4)zxoBlIϔ !vZM#쯷ܚ)\]TW4^' s#ԺR{Tyo8K9uװ<8Rg۾@qd[;)0hYxJ76s^`V! 3NuZ>a[dA ӗN.6ۢ: VZ)R,p]m7ڞ Y* +FhlJP(5!Ha֎H\q'rŖ=<~e0n^CЦ,Ή\&U{BYn%#e +MF).QB?-}A!J݁uIєB3gF[#>A`C{epg]ϠRIؼe*U~J4 /ּ7}OTZY6PzMi*eesc}](D~GBıh]bE9xjsq wj8&YTH%ڡVE\(h|HV endstream endobj 882 0 obj << /Type /FontDescriptor /FontName /GAXXVG+NimbusRomNo9L-Medi /Flags 4 /FontBBox [-168 -341 1000 960] /Ascent 690 /CapHeight 690 /Descent -209 /ItalicAngle 0 /StemV 140 /XHeight 461 /CharSet (/A/B/C/D/E/F/H/I/K/L/M/N/O/P/Q/R/S/T/V/W/a/b/c/colon/d/e/eight/f/five/four/g/h/hyphen/i/j/k/l/m/n/nine/o/one/p/r/s/seven/six/slash/t/three/two/u/underscore/v/w/x/y/z/zero) /FontFile 881 0 R >> endobj 883 0 obj << /Length1 1630 /Length2 18263 /Length3 0 /Length 19113 /Filter /FlateDecode >> stream xڬctf]&Tl[wlU*mݱm۶m۶m'VTW|Ϗ=^5{+ 8330dֆΎֲ&f΀rvXr&N@['1@`%sw;TըiiS ?4=f6/.&Vv&6N!LLN&S JLV fbc``w6F&6&S[տ#[c?92rLL܌LQL@G86FV$WnjlZXutr4r9FwNNvUlMZ9Sҿtaj 6'7bvVcs+ gGf@p013p02qt gz;;+ytr42eefol3 ,?"acj `f?t.&j?3C7 c[+w),ߐ;Hoz/>WhQg++Yd l @Ϣ2pXO^Z$ E/5L LEn&@'#sߞKbcl`1 gfb/:es?$[ebc_+K׿gSPД,'ewjdlaa[7'=37 &俀,cth_?O:槍?d`cw_VͽoEZfSVȔ@3H]irQ_moZw{m0C gǑ$Xeou>7)u6E''qn)B/(ϛ%]pM&)EݒwHNVgj?R?t';DԆX.&Ժ‹_gOC#ýwGx90.~9x*14qB  4K)M CDpZ >'2vE. lpŋ (oM:i%X%* M$oY 9:B:j`Zf薢0IAmbIAe@=^ɺcEw@q80Bb7hIWl(D %Р0yE`$Iԓ.In`0i'' 9_3CA iZEg 7(œy VPvCp`sLoit'%rƺ/4<q+ckLBfҍP;ť>@F|<{rp}I"eve\i@(}ڞyb呭\?$x ^X3xJVcV2iKa8T>J^B@(eGZKlvG |4wrneR萔 ӲX.jN_-M!ǚQj2gj?pi:q=[J.{eSI DDt}!}T)>w*\! WL2*7?L2f頟*CE6yh,C|8 oMdƉ׻8V_J`fh|8*TT!9$̷"X~xn]M+<A<R<(H=Fry ]H=z'ZzY5uO:Ы7QagIοJ!29/4_#eȟ a̩Hl2<:%ӊ4;ى&N_5. /_i B<GlmlFŬʳw:S۽k o"Xl‰(%LXiC [} Ι rp]1Oב&{'6?}:I?5f~ $f{W(7ݨFZ LcN8I(! 4Vm)M (w[5g]a's4OhG ș 8Lw HbkWdi_4=+YRg/k+)XTl^iC=ܤҺ n5]B~=K^ܙ'AW;LK {N#jY=aPGU9!ag8k@-g4g_~5F8i4n: /mY/-tlՁOQԸ-6DSj|ƻbVY(#Ii@5/[6@CW<`Aao:x հ 1w <+WxYc*򞶳 ڛ6)J$ 7-H`JD0=k0׷%8Q~$<[6td<ާ˜;vaYf*HpmixR wJDe9wĀkWpp 77l6NҠ_'uvk?+Ԍ +Dq\ xi{%/n{U6>7ͷ=Wa1$\},X'^}pYH_+.;Le_$5I mw" =ʼ5s6*t9r}Oz,=Vb Eʾ}.xv>pg#U1(sD|py% OXf)5p>8tVџk͘ ~d1D)yy*!ˬA(Js!x-1O[dI<=nq|ByLW#m44c#ۂ>Ydͣ6!)1@}hh$)O{^$eꄩ,|PȷOx)Ez"}*d"VSh#TE%\We.vϷp(u?f[&?֔[SxknEbY L7ݍ 5[L$&?ȉdu9pJ戝BN-jBUP}"nr/\A0LK *_Rj;Ly%HDǑw*"COK7p[*^.sI6o&noڃ^O^ 2R `o]KƧYoZ;KBӁ(X =*Xv/[rBp1W5^V]`!ۿ@eU@[ wu—I(UIkX=eL^wƘC(˦sB3#ݛ@lߣ#v"ztKġX#`LϝQd.$݀݊_K [b!;0'{8pWsPiLrUШ)kLƒ͐T_<0(G!6nȺHB:4AK}v/& wb]h9Q=c ɀŧ?<< ͯV`RѿBg@؋/|ɇ%bIASrOvywMl*qzHwq*X[*>^_:S} r[ILyM{^MuwguQ8Kc(;.p|vգأȖ9tG$죩D՟ "&Cå.v .oߋ](g vNO fǧNt&B:#s,⛌)RXyngk,0 ws~Cu0oĸGq_f_"H6~DJnCn \K !p!^ы}ɞq8aʁ*YhIP|`w,l0j:zbJXKFQ $E,R=鿦@~g٢iFC,mzDWYH-妀EJPlij5Ne 蝋\RV aZ4:4IBEdpf,^^H9eV F@SMN6`H=gϑI`1)9͹9I("c/f *]0Pڞ\c4dTkD(=):)MH]sAB:Z*V@}xF_zm+U]r2/L֤Iny:ۼDg]*{G8Bd_jzόO$}bwb P='AQ&Zlj&Vb9 };XnARuR40 SgrK|u z=d2#ud\m颬4jL|op@_X`& ΡG6~4T\5ʪߥ4w,+"PQn,h:`&o#{.5/,T`J[  =Jx|wf~8 zAEI{D&3Ež˴[^-b92wk<݄FWS x?U_ʲb,~W"q9ڭ%o~*@Zm/ =aćvo^>5h`Lab!zѢT86SS~7۬%8zn}6(g< U`%>N4>$C" o Zq^E (鈻A"Swh@/Wᡘj*[4_4!#B:(fۍRRtbnjؔ e+#œƆe-%\dC Gp:=u),sCA "7_ T!1d:%u*Af*MW,6% /3^NarVIp5I59Pa,j SMߝ᝛أ?rEL)mmҴca1=%͝9M:iƠa{R帮SLG|a!_mH2!ܜszWnz띑V:4rIx<HkJO@cB3:W橉IQ0V>Ɯ B&0@'5;uRjF#p\D2\=}>ޗqn4!>a˝~ <(1[]ɀD-i j2WM$p8E.')=~-ڟ@n+ <:wź 6j6F0&Y =V@ԐI4r72QqFe`go]S!zAx>%4a'1љ"B-*: cBCC1ݲ$TWgLzp.8 ͎+yCقfoIҸFH{6szaK @yUOsx{q *YP;S{bnlh^ @9@&wG|fy8 ٬#c8=)]UW&cKzIgxK$QyOQhDů9rw{w5r T.l: bmS/=]]ϦZ^[eCcwc A#^ހ&Vy̽{kNXiN MF\^vv~uWkl7"Cs$xU Znv򂴔%eN(MUL%l%9Ge&.sG[͉ Gayzu<xHOd.OqT1w㔌rk쭙r.U١-NPp}PC1~$vˉ@>d5XhlkX&X798ƛP|(mav16_<svh,$z}+}*!Vl t!(5Z-:ڐIsw.<8O* vwzY)L4XA2+j/1:f]_7xzhpU BrnV=wqԪ6T5)P#QWigYq;qQ#IiaOMT֔#TyFbzuDP]-VDf 9׾W ܩ3X\~.ݗM,9^`fyժަoGkL 萇>_KŰNt0!26gJ6ڎY'0ϣht9Fq0њv1L\V&9#m8cQArMw}3_@Ӽq/$[oGsTwU|1Md>?k;(&@^V$ qn)P1`cB7س1\d''g?!i%{N辖a'nL\\7=J&zH~wb0 Yd xgYݕ}Z6o5.]p T4hq([ԩ{WLT9 o&q&m?޺a@?*LxVpX%WQzR΂If4y(%`>yݗl+46'3v{E~7aF_?b_}05)Xj#SQ3)H TD iBI-#to;A6 uK}EFq_+X٩Qыp"5Z 4.x[AIMIW¶-Ѿ tr0JH |6qHŒ-l!6<4Č'['(cx8ʓ(؊(E8ߐ plQFl^7wYׄu-5BvHqv'A:Ka[c >#? RqGC.+ͷ*-CÂc)6-MRNs}ٗ_3S }|R0:Y%*<&3wnqCTm7u}^rRmsaAN't8P!;ro|&r=vnݤQE,fw,X>!P ,1YԝV 5-k0Pn-3 $#؋B- MFV9J mP`wYhs`g,?n:%( Җ'~-+&ۥ撣?Pǭ2䲉j_➩u"9'3&̑ı_vێg?{͠HԪPׂo& (BaIF q:m熯k?8!hVJY-ѻQ,/V~ Z/#=DFTҪy'|o _e[qp2 UUG,D~`\O+x$£O@G%~~- dU!k%.84Uw jHUۆbh/M%\XbZ;T\M "3(y{/K6髅ӃRg=B:; ?|c@ * =D$VZiT.HNiw2-cKk3Pv^$Jt/ 7"U^eПd^bq_M[߷vc(&"s+DN0QB&u>aZm-RDK瑦"(c&fWBs6ź!2t=˴N"sNJklRuk7:vb_,Fcٚxbn65/rېxKM[xuIw ߐigI_%֝h-}} -T}I޺K?Y>Q5W3FkE}>ֳa1hmT)TIGڧ7 6bȯse*daXÜK:ƻ[3 fhO aIVw[qz89d66Xu`eï44{֗??yAyEy~'ĭ`/B_>AEt)pJ#3'n#xJnW *FDx՟⼗Sn~Ҵ7[_?O̠3n$<;94+{"q x(lԽ&Ѝ[礍Fg,EpWȸtРP :qS8+sm -3-; 1. y"%\Ecw)2=W^l&oCdGK:dUz"sV'Et`^2Ub: C+3ᮬno%shq7DYE;s)$$2`|-_z5ך\Cp,z{,_8"_}UYUDЂj$d5ƱQ4AX y mw1AlfyV-*zp=Ǐ ҙxgR/,`t7%ɵ .a,&78`R$1wOv7}*ıui% kC]?@,WaNZ>RYu@π$|? y;%-FDb S>>(o'ykQ哸ܣP0GG`8d҃;jzCG9(CY&E&4kaP;v Fr]|O`G[Ba~92tq-FNq s4!Ϛ%h} Q+{\Nz\I1]UjS(X0&FΛq1p}ʃ@ fcL,j҆o[ݗ;o9ìK}OIG0mh0Z'+j_@5/yFtS?9aEt &o|ڷ/mU4٨݈I /vSK,2Λ}1hiͩ~8VvM-1wz\y!x>*x)x9H卾si$⬩W&ږn[ʰEuPFUT>u.@Ei(y%[8arD{Q5*C19Go GbiAJĥR&n䄫b EjN@=YX-:HZXPMlvZX*cة^ zUݬ+^,k&f-ƶv(}Ln 5W5Fe_!yh^5Y' nxezq4ӷ{{>CgYoNm`s[]13CaX{x@\xq1N-qq<qlQ_CAH\l6(HUrj\ h'̖xےJH( ==Ik$tY_AW2d.Jx5qRDW]Ǫ,3_liA1H)>W}` t"x|$6dmw{ue*^w HAIF+valOL8P;=|22t ՝_dPh"wvHiFVϗJ }Bd !YV ţlp0 Wz dc(ܶ"Q=~k &JtfG5u6ПK`  u6ՠKLJAIEK4 /oGxAꈌ9_ Bs/w3INy*)cpyuNcaY_ *t"n Znv|^Hb@ oX: be's͋LՊZ_`̑)FǭrXh|40BWh&=zbf1&QxX8פOf"ɲ;d6''J.?ò.2))qAû%>ΓB11 X4BN賗ɸ?dl8~S?:G\qM!c0  $fminq%̽n7:Wgb-Di,ځE /WYȰzoUz{z"ha}CNBThQʒLL,.igUY|AvYj.Ѳ+T:N-U KT_23K$%7cH`yRLyceDܶD{1dZP4 A'Ma gyV^eFm(,lJ(&~Li2W( opB1^i8xM.EW+K*1ΧmY/HV3>,qVg2INʅxgABe8:Άښzx ܎AtV[uݕПGҿ)5ĥQV|(0OdߪTYZܯ0@_ зqz7YN?F@\ꗼL5޶)+xNow@U#X{0Ƽ}IZа.=? Hɰix"ƇeYacǓ}v`|\kH=R6tx)W?ϝ|h׉V+u~>GɾREAaj!|fp'$P HTYf79Fz%,U)*nNqs*bl$S/j}>=ܡvMw}osqBW= ƫk4心yQ=` Q9`|r&;Fڝ͕RLDPJW:>댑V0Qd%)(Ы !D!t\: Y[neT(eMb[`yY/ށ\ V(,s,f&;>I X=|cZ9AN9r gq?v^s9>>dg\w[;HG2h4^9.-xْ75&Uo˖#'5Yx*!8bo']&8T04{UIsSl61|q̻LŢE`| OCcWzC)lVDh\YLo 51l3c~.sdS4SN"OFq[mW雠K[Ek"UQK$xm9C9.E4nT߫sZ:E gV\?zxM! yTHB8}z$p8wA7 s]L Bu *0@2\n+ yOH^lRy+իڱem^<~+lS5_ǝqTg.=xC4 ) ۛ>v, `qpx)`UD7уtvE9c7x[Me5 Z9gr;=mq,<}ayેzQ AVI1 ?r[JA x$ T=OYƑP "dulʲ0~DQ@m)`&M~[yA1ӨJ4%<Hs)6AgX~V2'F lA* +J2CROe_[*9GkjydU v9[ϲ!]Nj ̉7)l -טYndZ{Wxq [{礪U3~1=$Cxї9Mjh0X2HY"K1&,!?}w(> PԇY 6Дw Bew1z+G`3|'[lZ$r~Fygj/hȔu`aw`G|5˷-ɲ1fZo 2 >J-[^) 819Xlؼ,i;." ߁qb 8SLv}z;52mvu7fv)dwOlkY[wVڄJ692l{5^W[)o .DNRU6zI 0 g;b)v b?aVF.LKӆ 6Dzo2 |fs ?vl%0+٥r>L݉g8t#%j*]<3TfB ?|%E#8𭤡:} ) [f6X%@@9.fIU. |3tIDb(~k_=Jo DgkBu{; VZ+H0U?ng[.֪'}MH߯ ' 뀪>KvF{;m: rV[ S,υ+[*,2.1gnQ5T=Lc<m8Nx)w8v0?}=$ŵA? H2pDG"0sgY6| ²tMbB2,`sWo2m4xPa$b馺۹m .]Qw7n(xuR;*><S-"[b^ LAdނ$Gn?%.Dcy;MQ=ݎ6x2J̋iPx(NL{g@ހv!D"GDۛZ>D-f|ȖBHmB@FVVv4_ht vc5BdO`N9銤/saF\~CPV\M[0#;rؿ^=]dyr؀FBXFk*˖  endstream endobj 884 0 obj << /Type /FontDescriptor /FontName /OQQZLL+NimbusRomNo9L-Regu /Flags 4 /FontBBox [-168 -281 1000 924] /Ascent 678 /CapHeight 651 /Descent -216 /ItalicAngle 0 /StemV 85 /XHeight 450 /CharSet (/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/a/asciitilde/b/bracketleft/bracketright/bullet/c/colon/comma/d/e/eight/emdash/equal/exclam/f/fi/five/fl/four/g/h/hyphen/i/j/k/l/m/n/nine/o/one/p/parenleft/parenright/period/plus/q/quotedblleft/quotedblright/quoteleft/quoteright/r/s/semicolon/seven/six/slash/t/three/two/u/underscore/v/w/x/y/z/zero) /FontFile 883 0 R >> endobj 885 0 obj << /Length1 1647 /Length2 14737 /Length3 0 /Length 15596 /Filter /FlateDecode >> stream xڭct]&mɎmvwlgǶm۶dvy޷OOָg]WͺMJ(D+hlgh"fgLH1tqR㔦U41sp6|cФŽ&v"&\5c M p03wP(QRS-C@=,ld&v6&׎J&&gs @XN^CBV@!.75q.B madbdB 0sX{054'o.A'`ohc p9:vJ{7M&odha */"< d LwSҿoo lO,Cwo2{GdakM Mi9Uo`oo/o_9X8;XA32}4rmfa MOHؚm7v_DOP~'a`lgk061s SO[oMv_s5n1|4acmgX\ l,=OuɿwA[ohYXmpp71p62X޿*&&"| lnadeLlk ߺz1qIôfpV7Hj2vk;@}#'"bϵ;@\Q[#;H[McK`bnbdgh\=4!:d_\\[eY^D0@pݚ;271eo&Y;;?n1\ZՂ6&nvfGȫ'J_b<_TG{xo gd'OC78Y1Pܮ`pdY8*^(2ҍSiCk@,)/@%i;`+۹t^P2P@ul%^ُgG EK&:U(Yl7ov~Rl7\ݑ@^3:csz:zЮ߫xLߏWy>]]X [%7zP潄٤XG$04X!4'|BCJ8:Ӱ^9rEiԛV;`lf)~e Y >Jy\4 :+!`!pV%uX %1 fNSp!0-x T`XU| F k ' T//|="ӜK/vM| suL{L+*0F3,ma#ݟJ +Dr7;Xs)'وyːbeJ~.i[uPy9$iM8f“FHƍE3jT _8FmLrBc⁤'~K?65|z<}PPj"l{W# JVgyGE6cv{%7 U]jdm3KIL$lQ8:SU)v'Xӈr8Rt"JgUd==L~FC!@P_Ee&r3gsP0zʿ~.01t|P[Jőu)Bw.g˘W1{ܡv3ʯ<~lyE! !+a/յ~S%I fgXIbiMSףW0} =^`pyRyHVaa醐> '0F C }x_y* ޚa.@E CYXaZGԲ_Y.N'x \gU2!kbGVȚ#]]J7 e-2R$ UAˋ+)@!mU =Ce2c'WǿܴATȭŊ4N%XI8 KMCI9eo3.MU}7!'M=}KoOۘ3_]誄̯u bo FʫR*dZK YҪ@#1{1E aIG[bOd=]DV;YY] 5n05@Qi7œC| (-y\1݀ \Љ.fKF1)l\曊$R Ri=(ȟ)>׼.G& 5L?QTkĴRw]$RXT#@K5ɢ&v$H<73x| >M"uBҮM)/qI:5ߌ"MJݮS =Uy uht_~ۈ1Hc:sYCgRHwG(O8 eú _.0DE}KT%ҸNOr2`o:,t@Ar1Rʻ$bI5L*a&tȖtzF>cRhyM|>_ +!īDSz&:!]$f}>"E/VbsyTy 5ʳ }DJ5#uyW8Ukz`·p¶2"˲ Fu_KV̞}.R>wu}uaeBs_ۄ|T4Iv$3l3lx#O`luL*󠚱ՀFթzkYޏj"8w|x\>Y9}hTQsk~)pC,϶Ȝ@h靥LԿzW)O;oz2-G+[v~9(RQ70$uDoIMjzYplT4,{zW1cO/⭼)\>SS:JTP3ęܫA v>D=znDK4Ej;Dhy7F^ ݮfIaw+)IQix+rCM*jL ;RC)G]?&"OMqjdn>brBVИ8 BAv %fSI2B!iy DIz m6`ׅUwF="CI4"i)RV=i[g婍ӄZkRKrM?iiTLq31O-^X*mu +G1z͊={96ʕBu+ɠf ]ѐϴ+Nfiļ wV)GJ.7l=k[b% ګoR9;{^;@^WizXXz<.T& У-yQ|WSkI&9J =sS70V<jG`哿5BMgPWnyqP\PlE?M%@.;a“MfCf? XgI^CjA&<$nGֿLco-|:tɿf]ÐC1K{s!}0FtP?dj'!dNsy]&Idh  gióg-M +Vd E;(3C>GF =. V~b`bU\ UDk;grx5optG'8%)eঁMҝX0L=7 Ԋ/3+³o-~*Tns%U8]C&@^ /$rIA23DU{:V= g*B|$8}1X,=) ZkzRԜ;)&Xt}/kZnRykN/1KPxgqi#QO<%r뉚uhLY5hMCVh%S 9ՙ r8ƤzesU@e켰$סK|$"w?b˽QrMMXUjۮG -|:_~xe9+E@k]D؍{cM 2JO'iN"`" /U9o"U[w/s^Jt#pkr`īus>nWhW_-.)С~Ru4ZoEpO[$׆$^.G}N?BP٢ ٶrДrsIǔbX_nYӯ3B#2í]T>qYX,6"~uVZxMQyM Ƥŗ&AJdP^NѾn²}ۇ@d!J\x p[`ܫ܀>ɳa =#0OS<@Y5/x6 6&W߶E"ݸ=hͫz:&n7a8'RlR w|'{t}ZQsnL@곡QRe/b޴ޙd u „?tJ]nt8L]SXa<#ڎĀXt)ڥtb6i>QC] cKD '(ž+U*D Za!3rMv.R$xGdNso B9v) T9u<ڬ|buQ}eYIuWF!EhvП4anlO<ĺLŵT[>xn7hYMuܶD^bSW9| ?}s*T?̪hbt A.@DXⓝVsŜc6,p7 pT%wo{rKwiX^&s3D(dPY58g p6VtzRqj G$sOWVmrN5x/TpMpjhÍYV)$]quX];~ 8Yf^<ry_y;p0iF+!#xpc[r5<ʬ?Ca9{9SD㟔;",)ӭ-teq";B߁c2`::ϰlDzL /0ו'>x<^Kv`=X 2F :eLz+Iq>@9 =PL> !늴Up(϶YjqQl2WϚlt-lK޾q哠Rt,C3` E1[LAva7 }E=u8jV!u}b&y3mSj%)xhfE+&!^V]Iz^Z x3}}-6 oJa g< !HK&hX}!5-'k0)+Bk`b8eK x-4MMK ew !vf|+~h/ηV|Osǯi*+J6SJ¬TH,DOև J gc{!׃7NAi{.yU{ϚEAîȠ0WflQc!%0řF(:?̿KKGfGO[>5X,5lͪXLU Խ-l!* b|hmMᾊn_o-V:݊$o@GSy;|WIw6 37@$ԅ+lޣl̋D`^g"Y6mቛ.0Us`>pnk}0dEz^:Xe{%X֠p}eӎ^lp{°֜/5wt=}?x@bZvB nH?I l҂?욂w$$DE8Mmhvb&rLГ#qk ð~'/ GM#R`׼ L~(SQ21:W=o ̇N=!cS&h >VaͪՔD0f4 1p=Q= q"pM'|ȯ$kBnrN|y*N-gS ػ,gj( q]%+@Кɽ*W>sA#hFujܻO8?@HjSLhuP<@X'mApJS[Z' }renb Ś'V4{'<6霃h3svGI uT"dMCh+7 2F6Eڡjj_DiOG^Ɣ??@gzbl17(c$빣 2Dlo,DKbmU-:-N A?lo+C'3 ż:w71_ jb=փmP ^t5lOT_e3f0廨'LJ}$d[NĦe]H)Qu8W M}p O9{g$'N \eU~Q 5gZBo \ig01mԘ+pVFe#%s3gDLj6szoH0ez{S}rl|i WS~mIm `bQ`PjWBvDr}l;Mx>w*%֠ iqn\ϲ$1FwQ]~5O۠rƴBPyWѩ9&tޮqu<tё6ooUkoiKuzFX8b@-vo6^b|dL3:?hj=))8 09l? '5~д;i >ٖJWehet=i'[=p,u +N$Kz)|@^`EOml2cA引MI%,:9wR]ܶ6jHryTZOOs2EskR+ؑ$Q,D_WA}mUnA- q:<`~W[dQ%Eu?K/aEEґQ@ =R/J {SEjPkky-1}8ow7jm@u8%-p{g`ZL#/nMߡZys}*R|?ŶYCFnH<Ȫ۪;Z]ea(# ,~`lѾH/QQfMwhWD($Žt.m82ް0 [TU.VU" y(^Vì@ji˧' _Am eL= Bl'7+A?Sf]^Na+"a/h?~ Os+rl3y\b;pZ}Xo뜲{O㔬j r*Gӂk.>Į0@0MtatR95[/+@; rdlEB.F]d=bQC~D , Gs#3ɣ_ Fl%fj$}v5+%1ۮX 欷= B&bw+䦱O:xNee+'kս.{5ǡ6ܳSnap!0Cyt]Ysub0bmAmLzPAG$4z[mSCTcinrr>d(0-nĜe<Tzc?6B%d叠9)H CWoLz',4 Q:Zxy|t$~vV'pCgm:+]xLNaY 4xokFx/?kk9gRF{[bRdp_58` _YX.#Y̜^ GLD:KUr* O+Xfu_Fm –R-yUQB RpXNtV \'~O КyPx5Jh4;'Em 0Pq^) VLo82L^YӛN+ű?s5 ͗a݂d~wXE}b]ʢ'm*١-C *=fԌ@ v@'%_ƬqXc+9C Np?9=/7 \b?dhєl'dZJ͌V c6iRTq2o|]P*GfC_r1Kn¢6=i/zL숕m\92YBO4ݣ(=ȳ`~w2`ɝכuc7@`9Q0USeJ݌y1R`>o[ӯT Za֌B)xj [.2bc(Yx?-b8;5 VvQA[{zYnM` #}2LKSIғ's}ib(ږ>p <}Xtu Pq:b{JG]rDBrۋ<ca NsD{l o oj!չ0ԖePe[[AtM`ӰT^T&o!Uؿ!+3: 6nҞHg!:p*UtbƂ~kjL(Pw9&}w peԫ>'ޜ;kҍdS3४8OSBB d.J]YoݬxͨZNje^cq][R|~L */'&}~>@,P)0BBEUA mB½K8}`|0&Q0QlWlѠ^}$ʳS`9 xYUiُ8ET\ȷCzY5 #OK6~@mdB ͫQ{MA`o'{tZ 5rݪxzowW"pۯ}/ӣ+/ꀨDGWW p wY7UB*qwq4.D@IJx8]ą XZU&ٵ &}c9>Ƌv廪e3S#GCn6])w3PVi-jI~3t%aLyXUU ,DHq_JtJЦ6e/ ȡe Ky0Az QZQ,[M!N~5Y' } XeR㽃&r[: ?b7NKlTR] Pm;tz/"OQFC&w)5vQ@S O * <]IJ Q-gCH-yb*Idy )&:u6#TcP֘&GVeY%[ E'ĭbA1Ⱦ bm\"\7K#kBDbt'~yzbǯLY?r4cAD`ÆUB:<|ED4|Xz•'#K '3 q"Q͟>8Mz:' ܿ/ppJty]mğVrOWgy{՗|8Wxwqqv{XZ{l|tWkяayk.np?}CRu-#{dS jXқ DX'/jA]1r'eNif:n%;D4cW0LOrګm~Ot2&>Uۊx!LkC(W=P sb(6J$!㲖"D%\fIL'䜚6F:"qs}BKOty,W7³MI_kr`-Jܮ2K+QJ8QSjsۿ.܃Gag[Xl6 pacTu[j;ѦTQ(|V`k6>]e'bK짏n eT/M9\T,cN@V*Q/E f5/s}+D`~zUL_dXt,hs.:x:vQ3Z?4ռ *6pIfrֲgи1d&106Y@t'!M]b(Q=fT غ`NJekrTyY0A"cʢb-@!&TE /u`@-JI1c)h/6tB4W2s yvtaQ"9Jr%ocFB.],jl_!E އbԲ/>ܘiLz'Y_p5\~$ "k+)oN֥& zL4]yiec9k#snYt &U4ɥBo')M]Ֆؓ}X-f߾H}똫ax(̧mj)c" 6$C=x&4C ,)*K@$5VK0u( ˪u[ 7B:$BWBy|w|ݍz,'ÔRշa#Kr ^$PL$ endstream endobj 886 0 obj << /Type /FontDescriptor /FontName /DFUQGJ+NimbusRomNo9L-ReguItal /Flags 4 /FontBBox [-169 -270 1010 924] /Ascent 669 /CapHeight 669 /Descent -193 /ItalicAngle -15 /StemV 78 /XHeight 441 /CharSet (/A/B/C/D/E/F/G/H/I/K/L/M/N/P/S/T/U/a/asterisk/b/bar/bracketleft/bracketright/c/colon/comma/d/e/eight/equal/f/fi/g/h/hyphen/i/j/k/l/m/n/o/one/p/period/r/s/six/slash/t/three/two/u/underscore/v/w/x/y/z/zero) /FontFile 885 0 R >> endobj 835 0 obj << /Type /Encoding /Differences [2/fi/fl 33/exclam/quotedbl/numbersign/dollar/percent 39/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater 65/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft 93/bracketright/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z 124/bar 126/asciitilde 147/quotedblleft/quotedblright/bullet 151/emdash] >> endobj 266 0 obj << /Type /Font /Subtype /Type1 /BaseFont /YHEBDR+CMBX10 /FontDescriptor 854 0 R /FirstChar 49 /LastChar 121 /Widths 843 0 R >> endobj 269 0 obj << /Type /Font /Subtype /Type1 /BaseFont /UDTJWW+CMBX7 /FontDescriptor 856 0 R /FirstChar 84 /LastChar 84 /Widths 841 0 R >> endobj 261 0 obj << /Type /Font /Subtype /Type1 /BaseFont /VFPYLE+CMMI10 /FontDescriptor 858 0 R /FirstChar 21 /LastChar 120 /Widths 845 0 R >> endobj 297 0 obj << /Type /Font /Subtype /Type1 /BaseFont /PMKFGS+CMMI7 /FontDescriptor 860 0 R /FirstChar 84 /LastChar 84 /Widths 839 0 R >> endobj 267 0 obj << /Type /Font /Subtype /Type1 /BaseFont /QHDADJ+CMR10 /FontDescriptor 862 0 R /FirstChar 40 /LastChar 115 /Widths 842 0 R >> endobj 395 0 obj << /Type /Font /Subtype /Type1 /BaseFont /ZEOTZW+CMR7 /FontDescriptor 864 0 R /FirstChar 48 /LastChar 50 /Widths 837 0 R >> endobj 262 0 obj << /Type /Font /Subtype /Type1 /BaseFont /PGSMJZ+CMSY10 /FontDescriptor 866 0 R /FirstChar 0 /LastChar 107 /Widths 844 0 R >> endobj 394 0 obj << /Type /Font /Subtype /Type1 /BaseFont /PXBGHL+CMSY7 /FontDescriptor 868 0 R /FirstChar 0 /LastChar 0 /Widths 838 0 R >> endobj 216 0 obj << /Type /Font /Subtype /Type1 /BaseFont /CDXSUZ+NimbusMonL-Bold /FontDescriptor 870 0 R /FirstChar 40 /LastChar 122 /Widths 847 0 R /Encoding 835 0 R >> endobj 193 0 obj << /Type /Font /Subtype /Type1 /BaseFont /LZHDUP+NimbusMonL-Regu /FontDescriptor 872 0 R /FirstChar 34 /LastChar 122 /Widths 848 0 R /Encoding 835 0 R >> endobj 276 0 obj << /Type /Font /Subtype /Type1 /BaseFont /KLLHEU+NimbusMonL-ReguObli /FontDescriptor 874 0 R /FirstChar 34 /LastChar 122 /Widths 840 0 R /Encoding 835 0 R >> endobj 148 0 obj << /Type /Font /Subtype /Type1 /BaseFont /EDDXBX+NimbusSanL-Bold /FontDescriptor 876 0 R /FirstChar 44 /LastChar 122 /Widths 852 0 R /Encoding 835 0 R >> endobj 149 0 obj << /Type /Font /Subtype /Type1 /BaseFont /DDGOEI+NimbusSanL-BoldItal /FontDescriptor 878 0 R /FirstChar 46 /LastChar 115 /Widths 851 0 R /Encoding 835 0 R >> endobj 712 0 obj << /Type /Font /Subtype /Type1 /BaseFont /QBUIVB+NimbusSanL-Regu /FontDescriptor 880 0 R /FirstChar 65 /LastChar 86 /Widths 836 0 R /Encoding 835 0 R >> endobj 192 0 obj << /Type /Font /Subtype /Type1 /BaseFont /GAXXVG+NimbusRomNo9L-Medi /FontDescriptor 882 0 R /FirstChar 45 /LastChar 122 /Widths 849 0 R /Encoding 835 0 R >> endobj 150 0 obj << /Type /Font /Subtype /Type1 /BaseFont /OQQZLL+NimbusRomNo9L-Regu /FontDescriptor 884 0 R /FirstChar 2 /LastChar 151 /Widths 850 0 R /Encoding 835 0 R >> endobj 217 0 obj << /Type /Font /Subtype /Type1 /BaseFont /DFUQGJ+NimbusRomNo9L-ReguItal /FontDescriptor 886 0 R /FirstChar 2 /LastChar 124 /Widths 846 0 R /Encoding 835 0 R >> endobj 151 0 obj << /Type /Pages /Count 6 /Parent 887 0 R /Kids [142 0 R 154 0 R 189 0 R 198 0 R 201 0 R 205 0 R] >> endobj 219 0 obj << /Type /Pages /Count 6 /Parent 887 0 R /Kids [212 0 R 225 0 R 233 0 R 239 0 R 243 0 R 247 0 R] >> endobj 270 0 obj << /Type /Pages /Count 6 /Parent 887 0 R /Kids [256 0 R 272 0 R 279 0 R 283 0 R 291 0 R 305 0 R] >> endobj 337 0 obj << /Type /Pages /Count 6 /Parent 887 0 R /Kids [322 0 R 339 0 R 343 0 R 347 0 R 351 0 R 357 0 R] >> endobj 369 0 obj << /Type /Pages /Count 6 /Parent 887 0 R /Kids [364 0 R 371 0 R 375 0 R 384 0 R 391 0 R 400 0 R] >> endobj 420 0 obj << /Type /Pages /Count 6 /Parent 887 0 R /Kids [411 0 R 422 0 R 429 0 R 444 0 R 457 0 R 471 0 R] >> endobj 508 0 obj << /Type /Pages /Count 6 /Parent 888 0 R /Kids [491 0 R 522 0 R 541 0 R 562 0 R 573 0 R 582 0 R] >> endobj 591 0 obj << /Type /Pages /Count 6 /Parent 888 0 R /Kids [588 0 R 593 0 R 597 0 R 607 0 R 622 0 R 633 0 R] >> endobj 643 0 obj << /Type /Pages /Count 6 /Parent 888 0 R /Kids [639 0 R 645 0 R 652 0 R 656 0 R 662 0 R 666 0 R] >> endobj 673 0 obj << /Type /Pages /Count 6 /Parent 888 0 R /Kids [670 0 R 675 0 R 681 0 R 695 0 R 709 0 R 714 0 R] >> endobj 768 0 obj << /Type /Pages /Count 2 /Parent 888 0 R /Kids [765 0 R 832 0 R] >> endobj 887 0 obj << /Type /Pages /Count 36 /Parent 889 0 R /Kids [151 0 R 219 0 R 270 0 R 337 0 R 369 0 R 420 0 R] >> endobj 888 0 obj << /Type /Pages /Count 26 /Parent 889 0 R /Kids [508 0 R 591 0 R 643 0 R 673 0 R 768 0 R] >> endobj 889 0 obj << /Type /Pages /Count 62 /Kids [887 0 R 888 0 R] >> endobj 890 0 obj << /Type /Outlines /First 7 0 R /Last 139 0 R /Count 15 >> endobj 139 0 obj << /Title 140 0 R /A 137 0 R /Parent 890 0 R /Prev 135 0 R >> endobj 135 0 obj << /Title 136 0 R /A 133 0 R /Parent 890 0 R /Prev 131 0 R /Next 139 0 R >> endobj 131 0 obj << /Title 132 0 R /A 129 0 R /Parent 890 0 R /Prev 127 0 R /Next 135 0 R >> endobj 127 0 obj << /Title 128 0 R /A 125 0 R /Parent 890 0 R /Prev 123 0 R /Next 131 0 R >> endobj 123 0 obj << /Title 124 0 R /A 121 0 R /Parent 890 0 R /Prev 119 0 R /Next 127 0 R >> endobj 119 0 obj << /Title 120 0 R /A 117 0 R /Parent 890 0 R /Prev 115 0 R /Next 123 0 R >> endobj 115 0 obj << /Title 116 0 R /A 113 0 R /Parent 890 0 R /Prev 107 0 R /Next 119 0 R >> endobj 111 0 obj << /Title 112 0 R /A 109 0 R /Parent 107 0 R >> endobj 107 0 obj << /Title 108 0 R /A 105 0 R /Parent 890 0 R /Prev 99 0 R /Next 115 0 R /First 111 0 R /Last 111 0 R /Count -1 >> endobj 103 0 obj << /Title 104 0 R /A 101 0 R /Parent 99 0 R >> endobj 99 0 obj << /Title 100 0 R /A 97 0 R /Parent 890 0 R /Prev 87 0 R /Next 107 0 R /First 103 0 R /Last 103 0 R /Count -1 >> endobj 95 0 obj << /Title 96 0 R /A 93 0 R /Parent 87 0 R /Prev 91 0 R >> endobj 91 0 obj << /Title 92 0 R /A 89 0 R /Parent 87 0 R /Next 95 0 R >> endobj 87 0 obj << /Title 88 0 R /A 85 0 R /Parent 890 0 R /Prev 79 0 R /Next 99 0 R /First 91 0 R /Last 95 0 R /Count -2 >> endobj 83 0 obj << /Title 84 0 R /A 81 0 R /Parent 79 0 R >> endobj 79 0 obj << /Title 80 0 R /A 77 0 R /Parent 890 0 R /Prev 71 0 R /Next 87 0 R /First 83 0 R /Last 83 0 R /Count -1 >> endobj 75 0 obj << /Title 76 0 R /A 73 0 R /Parent 71 0 R >> endobj 71 0 obj << /Title 72 0 R /A 69 0 R /Parent 890 0 R /Prev 47 0 R /Next 79 0 R /First 75 0 R /Last 75 0 R /Count -1 >> endobj 67 0 obj << /Title 68 0 R /A 65 0 R /Parent 47 0 R /Prev 63 0 R >> endobj 63 0 obj << /Title 64 0 R /A 61 0 R /Parent 47 0 R /Prev 59 0 R /Next 67 0 R >> endobj 59 0 obj << /Title 60 0 R /A 57 0 R /Parent 47 0 R /Prev 55 0 R /Next 63 0 R >> endobj 55 0 obj << /Title 56 0 R /A 53 0 R /Parent 47 0 R /Prev 51 0 R /Next 59 0 R >> endobj 51 0 obj << /Title 52 0 R /A 49 0 R /Parent 47 0 R /Next 55 0 R >> endobj 47 0 obj << /Title 48 0 R /A 45 0 R /Parent 890 0 R /Prev 31 0 R /Next 71 0 R /First 51 0 R /Last 67 0 R /Count -5 >> endobj 43 0 obj << /Title 44 0 R /A 41 0 R /Parent 31 0 R /Prev 39 0 R >> endobj 39 0 obj << /Title 40 0 R /A 37 0 R /Parent 31 0 R /Prev 35 0 R /Next 43 0 R >> endobj 35 0 obj << /Title 36 0 R /A 33 0 R /Parent 31 0 R /Next 39 0 R >> endobj 31 0 obj << /Title 32 0 R /A 29 0 R /Parent 890 0 R /Prev 7 0 R /Next 47 0 R /First 35 0 R /Last 43 0 R /Count -3 >> endobj 27 0 obj << /Title 28 0 R /A 25 0 R /Parent 7 0 R /Prev 23 0 R >> endobj 23 0 obj << /Title 24 0 R /A 21 0 R /Parent 7 0 R /Prev 19 0 R /Next 27 0 R >> endobj 19 0 obj << /Title 20 0 R /A 17 0 R /Parent 7 0 R /Prev 15 0 R /Next 23 0 R >> endobj 15 0 obj << /Title 16 0 R /A 13 0 R /Parent 7 0 R /Prev 11 0 R /Next 19 0 R >> endobj 11 0 obj << /Title 12 0 R /A 9 0 R /Parent 7 0 R /Next 15 0 R >> endobj 7 0 obj << /Title 8 0 R /A 5 0 R /Parent 890 0 R /Next 31 0 R /First 11 0 R /Last 27 0 R /Count -5 >> endobj 891 0 obj << /Names [(Doc-Start) 147 0 R (Item.1) 434 0 R (Item.2) 435 0 R (Item.3) 436 0 R (Item.4) 437 0 R (Item.5) 496 0 R] /Limits [(Doc-Start) (Item.5)] >> endobj 892 0 obj << /Names [(Item.6) 497 0 R (Item.7) 498 0 R (Item.8) 499 0 R (chapter*.1) 191 0 R (chapter*.11) 130 0 R (chapter.1) 6 0 R] /Limits [(Item.6) (chapter.1)] >> endobj 893 0 obj << /Names [(chapter.10) 118 0 R (chapter.11) 122 0 R (chapter.12) 126 0 R (chapter.2) 30 0 R (chapter.3) 46 0 R (chapter.4) 70 0 R] /Limits [(chapter.10) (chapter.4)] >> endobj 894 0 obj << /Names [(chapter.5) 78 0 R (chapter.6) 86 0 R (chapter.7) 98 0 R (chapter.8) 106 0 R (chapter.9) 114 0 R (cite.D04a) 689 0 R] /Limits [(chapter.5) (cite.D04a)] >> endobj 895 0 obj << /Names [(cite.D04b) 690 0 R (cite.DD97) 692 0 R (cite.DD99) 691 0 R (cite.DEGLL99) 685 0 R (cite.DGL99) 686 0 R (cite.LD03) 687 0 R] /Limits [(cite.D04b) (cite.LD03)] >> endobj 896 0 obj << /Names [(cite.SLU) 688 0 R (cite.UMF) 693 0 R (d04a) 528 0 R (d04b) 529 0 R (dd97) 531 0 R (dd99) 530 0 R] /Limits [(cite.SLU) (dd99)] >> endobj 897 0 obj << /Names [(degll99) 509 0 R (dgl99) 510 0 R (directSolver.PysparseDirectSolver) 481 0 R (directSolver.PysparseDirectSolver.solve) 482 0 R (equation-eq:python:1) 405 0 R (equation-eq:python:2) 576 0 R] /Limits [(degll99) (equation-eq:python:2)] >> endobj 898 0 obj << /Names [(equation-eq:python:3) 578 0 R (equation.5.1) 406 0 R (equation.7.1) 577 0 R (equation.7.2) 579 0 R (fact-page) 419 0 R (formats-page) 220 0 R] /Limits [(equation-eq:python:3) (formats-page)] >> endobj 899 0 obj << /Names [(itsolvers-page) 388 0 R (jdsym-page) 396 0 R (jdsym.jdsym) 580 0 R (ld03) 511 0 R (license-page) 642 0 R (module-itsolvers) 387 0 R] /Limits [(itsolvers-page) (module-itsolvers)] >> endobj 900 0 obj << /Names [(module-jdsym) 566 0 R (module-precon) 368 0 R (module-spmatrix) 250 0 R (module-superlu) 418 0 R (mpy1) 360 0 R (mpy2) 362 0 R] /Limits [(module-jdsym) (mpy2)] >> endobj 901 0 obj << /Names [(page.1) 203 0 R (page.10) 274 0 R (page.11) 281 0 R (page.12) 285 0 R (page.13) 293 0 R (page.14) 307 0 R] /Limits [(page.1) (page.14)] >> endobj 902 0 obj << /Names [(page.15) 324 0 R (page.16) 341 0 R (page.17) 345 0 R (page.18) 349 0 R (page.19) 353 0 R (page.2) 207 0 R] /Limits [(page.15) (page.2)] >> endobj 903 0 obj << /Names [(page.20) 359 0 R (page.21) 366 0 R (page.22) 373 0 R (page.23) 377 0 R (page.24) 386 0 R (page.25) 393 0 R] /Limits [(page.20) (page.25)] >> endobj 904 0 obj << /Names [(page.26) 402 0 R (page.27) 413 0 R (page.28) 424 0 R (page.29) 431 0 R (page.3) 214 0 R (page.30) 446 0 R] /Limits [(page.26) (page.30)] >> endobj 905 0 obj << /Names [(page.31) 459 0 R (page.32) 473 0 R (page.33) 493 0 R (page.34) 524 0 R (page.35) 543 0 R (page.36) 564 0 R] /Limits [(page.31) (page.36)] >> endobj 906 0 obj << /Names [(page.37) 575 0 R (page.38) 584 0 R (page.39) 590 0 R (page.4) 227 0 R (page.40) 595 0 R (page.41) 599 0 R] /Limits [(page.37) (page.41)] >> endobj 907 0 obj << /Names [(page.42) 609 0 R (page.43) 624 0 R (page.44) 635 0 R (page.45) 641 0 R (page.46) 647 0 R (page.47) 654 0 R] /Limits [(page.42) (page.47)] >> endobj 908 0 obj << /Names [(page.48) 658 0 R (page.49) 664 0 R (page.5) 235 0 R (page.50) 668 0 R (page.51) 672 0 R (page.52) 677 0 R] /Limits [(page.48) (page.52)] >> endobj 909 0 obj << /Names [(page.53) 683 0 R (page.54) 697 0 R (page.55) 711 0 R (page.56) 716 0 R (page.57) 767 0 R (page.58) 834 0 R] /Limits [(page.53) (page.58)] >> endobj 910 0 obj << /Names [(page.6) 241 0 R (page.7) 245 0 R (page.8) 249 0 R (page.9) 258 0 R (page.i) 146 0 R (page.ii) 156 0 R] /Limits [(page.6) (page.ii)] >> endobj 911 0 obj << /Names [(precon.jacobi) 379 0 R (precon.ssor) 380 0 R (pysparseMatrix.PysparseIdentityMatrix) 628 0 R (pysparseMatrix.PysparseMatrix) 600 0 R (pysparseMatrix.PysparseMatrix.addAt) 601 0 R (pysparseMatrix.PysparseMatrix.addAtDiagonal) 602 0 R] /Limits [(precon.jacobi) (pysparseMatrix.PysparseMatrix.addAtDiagonal)] >> endobj 912 0 obj << /Names [(pysparseMatrix.PysparseMatrix.copy) 603 0 R (pysparseMatrix.PysparseMatrix.exportMmf) 604 0 R (pysparseMatrix.PysparseMatrix.find) 605 0 R (pysparseMatrix.PysparseMatrix.getMatrix) 610 0 R (pysparseMatrix.PysparseMatrix.getNnz) 611 0 R (pysparseMatrix.PysparseMatrix.getNumpyArray) 612 0 R] /Limits [(pysparseMatrix.PysparseMatrix.copy) (pysparseMatrix.PysparseMatrix.getNumpyArray)] >> endobj 913 0 obj << /Names [(pysparseMatrix.PysparseMatrix.getShape) 613 0 R (pysparseMatrix.PysparseMatrix.isSymmetric) 614 0 R (pysparseMatrix.PysparseMatrix.matvec) 615 0 R (pysparseMatrix.PysparseMatrix.put) 616 0 R (pysparseMatrix.PysparseMatrix.putDiagonal) 617 0 R (pysparseMatrix.PysparseMatrix.take) 625 0 R] /Limits [(pysparseMatrix.PysparseMatrix.getShape) (pysparseMatrix.PysparseMatrix.take)] >> endobj 914 0 obj << /Names [(pysparseMatrix.PysparseMatrix.takeDiagonal) 626 0 R (pysparseMatrix.PysparseSpDiagsMatrix) 630 0 R (pysparseSuperLU.PysparseSuperLUSolver) 495 0 R (pysparseSuperLU.PysparseSuperLUSolver.LU) 500 0 R (pysparseSuperLU.PysparseSuperLUSolver.factorizationTime) 502 0 R (pysparseSuperLU.PysparseSuperLUSolver.fetch_factors) 505 0 R] /Limits [(pysparseMatrix.PysparseMatrix.takeDiagonal) (pysparseSuperLU.PysparseSuperLUSolver.fetch_factors)] >> endobj 915 0 obj << /Names [(pysparseSuperLU.PysparseSuperLUSolver.fetch_lunz) 506 0 R (pysparseSuperLU.PysparseSuperLUSolver.lunz) 504 0 R (pysparseSuperLU.PysparseSuperLUSolver.sol) 501 0 R (pysparseSuperLU.PysparseSuperLUSolver.solutionTime) 503 0 R (pysparseSuperLU.PysparseSuperLUSolver.solve) 507 0 R (pysparseUmfpack.PysparseUmfpackSolver) 527 0 R] /Limits [(pysparseSuperLU.PysparseSuperLUSolver.fetch_lunz) (pysparseUmfpack.PysparseUmfpackSolver)] >> endobj 916 0 obj << /Names [(pysparseUmfpack.PysparseUmfpackSolver.L) 546 0 R (pysparseUmfpack.PysparseUmfpackSolver.LU) 544 0 R (pysparseUmfpack.PysparseUmfpackSolver.P) 548 0 R (pysparseUmfpack.PysparseUmfpackSolver.Q) 549 0 R (pysparseUmfpack.PysparseUmfpackSolver.R) 550 0 R (pysparseUmfpack.PysparseUmfpackSolver.U) 547 0 R] /Limits [(pysparseUmfpack.PysparseUmfpackSolver.L) (pysparseUmfpack.PysparseUmfpackSolver.U)] >> endobj 917 0 obj << /Names [(pysparseUmfpack.PysparseUmfpackSolver.do_recip) 553 0 R (pysparseUmfpack.PysparseUmfpackSolver.factorizationTime) 551 0 R (pysparseUmfpack.PysparseUmfpackSolver.fetch_factors) 557 0 R (pysparseUmfpack.PysparseUmfpackSolver.fetch_lunz) 558 0 R (pysparseUmfpack.PysparseUmfpackSolver.lnz) 554 0 R (pysparseUmfpack.PysparseUmfpackSolver.nz_udiag) 556 0 R] /Limits [(pysparseUmfpack.PysparseUmfpackSolver.do_recip) (pysparseUmfpack.PysparseUmfpackSolver.nz_udiag)] >> endobj 918 0 obj << /Names [(pysparseUmfpack.PysparseUmfpackSolver.sol) 545 0 R (pysparseUmfpack.PysparseUmfpackSolver.solutionTime) 552 0 R (pysparseUmfpack.PysparseUmfpackSolver.solve) 559 0 R (pysparseUmfpack.PysparseUmfpackSolver.unz) 555 0 R (pysparsematrix-page) 483 0 R (python-vs-matlab-vs-c) 416 0 R] /Limits [(pysparseUmfpack.PysparseUmfpackSolver.sol) (python-vs-matlab-vs-c)] >> endobj 919 0 obj << /Names [(section*.10) 684 0 R (section*.12) 134 0 R (section*.13) 138 0 R (section.1.1) 10 0 R (section.1.2) 14 0 R (section.1.3) 18 0 R] /Limits [(section*.10) (section.1.3)] >> endobj 920 0 obj << /Names [(section.1.4) 22 0 R (section.1.5) 26 0 R (section.2.1) 34 0 R (section.2.2) 38 0 R (section.2.3) 42 0 R (section.3.1) 50 0 R] /Limits [(section.1.4) (section.3.1)] >> endobj 921 0 obj << /Names [(section.3.2) 54 0 R (section.3.3) 58 0 R (section.3.4) 62 0 R (section.3.5) 66 0 R (section.4.1) 74 0 R (section.5.1) 82 0 R] /Limits [(section.3.2) (section.5.1)] >> endobj 922 0 obj << /Names [(section.6.1) 90 0 R (section.6.2) 94 0 R (section.7.1) 102 0 R (section.8.1) 110 0 R (slu) 512 0 R (spmatrix-page) 251 0 R] /Limits [(section.6.1) (spmatrix-page)] >> endobj 923 0 obj << /Names [(spmatrix.csr_mat) 331 0 R (spmatrix.dot) 268 0 R (spmatrix.ll_mat) 260 0 R (spmatrix.ll_mat.compress) 311 0 R (spmatrix.ll_mat.copy) 302 0 R (spmatrix.ll_mat.delete_cols) 326 0 R] /Limits [(spmatrix.csr_mat) (spmatrix.ll_mat.delete_cols)] >> endobj 924 0 obj << /Names [(spmatrix.ll_mat.delete_rowcols) 327 0 R (spmatrix.ll_mat.delete_rows) 325 0 R (spmatrix.ll_mat.export_mtx) 300 0 R (spmatrix.ll_mat.find) 328 0 R (spmatrix.ll_mat.generalize) 310 0 R (spmatrix.ll_mat.issym) 294 0 R] /Limits [(spmatrix.ll_mat.delete_rowcols) (spmatrix.ll_mat.issym)] >> endobj 925 0 obj << /Names [(spmatrix.ll_mat.items) 315 0 R (spmatrix.ll_mat.keys) 313 0 R (spmatrix.ll_mat.matvec) 295 0 R (spmatrix.ll_mat.matvec_transp) 296 0 R (spmatrix.ll_mat.nnz) 288 0 R (spmatrix.ll_mat.norm) 312 0 R] /Limits [(spmatrix.ll_mat.items) (spmatrix.ll_mat.norm)] >> endobj 926 0 obj << /Names [(spmatrix.ll_mat.put) 318 0 R (spmatrix.ll_mat.scale) 316 0 R (spmatrix.ll_mat.shape) 287 0 R (spmatrix.ll_mat.shift) 301 0 R (spmatrix.ll_mat.take) 317 0 R (spmatrix.ll_mat.to_csr) 298 0 R] /Limits [(spmatrix.ll_mat.put) (spmatrix.ll_mat.to_csr)] >> endobj 927 0 obj << /Names [(spmatrix.ll_mat.to_sss) 299 0 R (spmatrix.ll_mat.update_add_at) 309 0 R (spmatrix.ll_mat.update_add_mask) 303 0 R (spmatrix.ll_mat.update_add_mask_sym) 308 0 R (spmatrix.ll_mat.values) 314 0 R (spmatrix.ll_mat_from_mtx) 264 0 R] /Limits [(spmatrix.ll_mat.to_sss) (spmatrix.ll_mat_from_mtx)] >> endobj 928 0 obj << /Names [(spmatrix.ll_mat_sym) 263 0 R (spmatrix.matrixmultiply) 265 0 R (spmatrix.sss_mat) 332 0 R (spmatrix.sss_mat.matvec) 335 0 R (spmatrix.sss_mat.matvec_transp) 336 0 R (spmatrix.sss_mat.nnz) 334 0 R] /Limits [(spmatrix.ll_mat_sym) (spmatrix.sss_mat.nnz)] >> endobj 929 0 obj << /Names [(spmatrix.sss_mat.shape) 333 0 R (subsection.1.1.1) 215 0 R (subsection.1.1.2) 218 0 R (subsection.1.1.3) 228 0 R (subsection.1.1.4) 229 0 R (subsection.1.1.5) 230 0 R] /Limits [(spmatrix.sss_mat.shape) (subsection.1.1.5)] >> endobj 930 0 obj << /Names [(subsection.1.1.6) 231 0 R (subsection.3.1.1) 259 0 R (subsection.3.1.2) 275 0 R (subsection.3.1.3) 329 0 R (subsection.4.1.1) 378 0 R (subsection.4.1.2) 381 0 R] /Limits [(subsection.1.1.6) (subsection.4.1.2)] >> endobj 931 0 obj << /Names [(subsection.4.1.3) 382 0 R (subsection.5.1.1) 403 0 R (subsection.5.1.2) 404 0 R (subsection.5.1.3) 414 0 R (subsection.6.1.1) 432 0 R (subsection.6.1.2) 460 0 R] /Limits [(subsection.4.1.3) (subsection.6.1.2)] >> endobj 932 0 obj << /Names [(subsection.6.2.1) 480 0 R (subsection.6.2.2) 494 0 R (subsection.6.2.3) 525 0 R (subsection.6.2.4) 526 0 R (subsection.6.2.5) 565 0 R (subsection.7.1.1) 585 0 R] /Limits [(subsection.6.2.1) (subsection.7.1.1)] >> endobj 933 0 obj << /Names [(subsection.8.1.1) 627 0 R (subsection.8.1.2) 629 0 R (subsection.8.1.3) 631 0 R (subsubsection*.2) 277 0 R (subsubsection*.3) 286 0 R (subsubsection*.4) 330 0 R] /Limits [(subsection.8.1.1) (subsubsection*.4)] >> endobj 934 0 obj << /Names [(subsubsection*.5) 438 0 R (subsubsection*.6) 449 0 R (subsubsection*.7) 451 0 R (subsubsection*.8) 461 0 R (subsubsection*.9) 478 0 R (superlu.factorize) 433 0 R] /Limits [(subsubsection*.5) (superlu.factorize)] >> endobj 935 0 obj << /Names [(superlu.superlu_context) 439 0 R (superlu.superlu_context.nnz) 447 0 R (superlu.superlu_context.shape) 440 0 R (superlu.superlu_context.solve) 448 0 R (superlu.umfpack_context) 462 0 R (superlu.umfpack_context.lu) 476 0 R] /Limits [(superlu.superlu_context) (superlu.umfpack_context.lu)] >> endobj 936 0 obj << /Names [(superlu.umfpack_context.lunz) 477 0 R (superlu.umfpack_context.nnz) 474 0 R (superlu.umfpack_context.shape) 463 0 R (superlu.umfpack_context.solve) 475 0 R (table.3.1) 361 0 R (table.3.2) 367 0 R] /Limits [(superlu.umfpack_context.lunz) (table.3.2)] >> endobj 937 0 obj << /Names [(table.5.1) 417 0 R (todo-0) 415 0 R (todo-1) 586 0 R (umf) 532 0 R] /Limits [(table.5.1) (umf)] >> endobj 938 0 obj << /Kids [891 0 R 892 0 R 893 0 R 894 0 R 895 0 R 896 0 R] /Limits [(Doc-Start) (dd99)] >> endobj 939 0 obj << /Kids [897 0 R 898 0 R 899 0 R 900 0 R 901 0 R 902 0 R] /Limits [(degll99) (page.2)] >> endobj 940 0 obj << /Kids [903 0 R 904 0 R 905 0 R 906 0 R 907 0 R 908 0 R] /Limits [(page.20) (page.52)] >> endobj 941 0 obj << /Kids [909 0 R 910 0 R 911 0 R 912 0 R 913 0 R 914 0 R] /Limits [(page.53) (pysparseSuperLU.PysparseSuperLUSolver.fetch_factors)] >> endobj 942 0 obj << /Kids [915 0 R 916 0 R 917 0 R 918 0 R 919 0 R 920 0 R] /Limits [(pysparseSuperLU.PysparseSuperLUSolver.fetch_lunz) (section.3.1)] >> endobj 943 0 obj << /Kids [921 0 R 922 0 R 923 0 R 924 0 R 925 0 R 926 0 R] /Limits [(section.3.2) (spmatrix.ll_mat.to_csr)] >> endobj 944 0 obj << /Kids [927 0 R 928 0 R 929 0 R 930 0 R 931 0 R 932 0 R] /Limits [(spmatrix.ll_mat.to_sss) (subsection.7.1.1)] >> endobj 945 0 obj << /Kids [933 0 R 934 0 R 935 0 R 936 0 R 937 0 R] /Limits [(subsection.8.1.1) (umf)] >> endobj 946 0 obj << /Kids [938 0 R 939 0 R 940 0 R 941 0 R 942 0 R 943 0 R] /Limits [(Doc-Start) (spmatrix.ll_mat.to_csr)] >> endobj 947 0 obj << /Kids [944 0 R 945 0 R] /Limits [(spmatrix.ll_mat.to_sss) (umf)] >> endobj 948 0 obj << /Kids [946 0 R 947 0 R] /Limits [(Doc-Start) (umf)] >> endobj 949 0 obj << /Dests 948 0 R >> endobj 950 0 obj << /Type /Catalog /Pages 889 0 R /Outlines 890 0 R /Names 949 0 R /PageMode/UseOutlines/PageLabels << /Nums [0 << /S /r >> 2 << /S /r >> 4 << /S /D >> ] >> /OpenAction 141 0 R >> endobj 951 0 obj << /Author (Roman Geus, Daniel Wheeler and Dominique Orban) /Title (Pysparse Documentation) /Author()/Title()/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.3)/Keywords() /CreationDate (D:20090325110925-04'00') /ModDate (D:20090325110925-04'00') /Trapped /False /PTEX.Fullbanner (This is pdfTeX, Version 3.141592-1.40.3-2.2 (Web2C 7.5.6) kpathsea version 3.5.6) >> endobj xref 0 952 0000000001 65535 f 0000000002 00000 f 0000000003 00000 f 0000000004 00000 f 0000000000 00000 f 0000000015 00000 n 0000017039 00000 n 0000334283 00000 n 0000000060 00000 n 0000000102 00000 n 0000017090 00000 n 0000334211 00000 n 0000000149 00000 n 0000000183 00000 n 0000020971 00000 n 0000334125 00000 n 0000000231 00000 n 0000000263 00000 n 0000022713 00000 n 0000334039 00000 n 0000000311 00000 n 0000000349 00000 n 0000022765 00000 n 0000333953 00000 n 0000000397 00000 n 0000000432 00000 n 0000024804 00000 n 0000333880 00000 n 0000000480 00000 n 0000000527 00000 n 0000027637 00000 n 0000333756 00000 n 0000000573 00000 n 0000000613 00000 n 0000027689 00000 n 0000333682 00000 n 0000000661 00000 n 0000000698 00000 n 0000029794 00000 n 0000333595 00000 n 0000000746 00000 n 0000000793 00000 n 0000029846 00000 n 0000333521 00000 n 0000000841 00000 n 0000000881 00000 n 0000033545 00000 n 0000333396 00000 n 0000000927 00000 n 0000000975 00000 n 0000033597 00000 n 0000333322 00000 n 0000001023 00000 n 0000001061 00000 n 0000057814 00000 n 0000333235 00000 n 0000001109 00000 n 0000001154 00000 n 0000060381 00000 n 0000333148 00000 n 0000001202 00000 n 0000001234 00000 n 0000065094 00000 n 0000333061 00000 n 0000001282 00000 n 0000001322 00000 n 0000068357 00000 n 0000332987 00000 n 0000001370 00000 n 0000001411 00000 n 0000072959 00000 n 0000332862 00000 n 0000001457 00000 n 0000001491 00000 n 0000073011 00000 n 0000332801 00000 n 0000001539 00000 n 0000001575 00000 n 0000078020 00000 n 0000332676 00000 n 0000001621 00000 n 0000001657 00000 n 0000078072 00000 n 0000332615 00000 n 0000001705 00000 n 0000001744 00000 n 0000089033 00000 n 0000332490 00000 n 0000001790 00000 n 0000001823 00000 n 0000089085 00000 n 0000332416 00000 n 0000001871 00000 n 0000001913 00000 n 0000101838 00000 n 0000332342 00000 n 0000001961 00000 n 0000002010 00000 n 0000123003 00000 n 0000332213 00000 n 0000002056 00000 n 0000002093 00000 n 0000123055 00000 n 0000332149 00000 n 0000002142 00000 n 0000002178 00000 n 0000131510 00000 n 0000332018 00000 n 0000002225 00000 n 0000002279 00000 n 0000131563 00000 n 0000331953 00000 n 0000002328 00000 n 0000002373 00000 n 0000140163 00000 n 0000331860 00000 n 0000002420 00000 n 0000002479 00000 n 0000143495 00000 n 0000331767 00000 n 0000002527 00000 n 0000002554 00000 n 0000145211 00000 n 0000331674 00000 n 0000002602 00000 n 0000002631 00000 n 0000146488 00000 n 0000331581 00000 n 0000002679 00000 n 0000002717 00000 n 0000149314 00000 n 0000331488 00000 n 0000002766 00000 n 0000002798 00000 n 0000152817 00000 n 0000331395 00000 n 0000002847 00000 n 0000002879 00000 n 0000161924 00000 n 0000331316 00000 n 0000002928 00000 n 0000002953 00000 n 0000003417 00000 n 0000003529 00000 n 0000004803 00000 n 0000003005 00000 n 0000004693 00000 n 0000004750 00000 n 0000328647 00000 n 0000328818 00000 n 0000329337 00000 n 0000329687 00000 n 0000004480 00000 n 0000005206 00000 n 0000005037 00000 n 0000004937 00000 n 0000005149 00000 n 0000006906 00000 n 0000007057 00000 n 0000007210 00000 n 0000007363 00000 n 0000007516 00000 n 0000007669 00000 n 0000007822 00000 n 0000007973 00000 n 0000008125 00000 n 0000008277 00000 n 0000008430 00000 n 0000008581 00000 n 0000008733 00000 n 0000008886 00000 n 0000009039 00000 n 0000009191 00000 n 0000009344 00000 n 0000009495 00000 n 0000009648 00000 n 0000009799 00000 n 0000009952 00000 n 0000010103 00000 n 0000010255 00000 n 0000010408 00000 n 0000010559 00000 n 0000010712 00000 n 0000010862 00000 n 0000011014 00000 n 0000011165 00000 n 0000011317 00000 n 0000012117 00000 n 0000011524 00000 n 0000006542 00000 n 0000005247 00000 n 0000011467 00000 n 0000329163 00000 n 0000328301 00000 n 0000012269 00000 n 0000012421 00000 n 0000012574 00000 n 0000012726 00000 n 0000011961 00000 n 0000011635 00000 n 0000013335 00000 n 0000013166 00000 n 0000012811 00000 n 0000013278 00000 n 0000013881 00000 n 0000013712 00000 n 0000013433 00000 n 0000013824 00000 n 0000016478 00000 n 0000016648 00000 n 0000016803 00000 n 0000017259 00000 n 0000016330 00000 n 0000013953 00000 n 0000016982 00000 n 0000017146 00000 n 0000328130 00000 n 0000329510 00000 n 0000017202 00000 n 0000329804 00000 n 0000024860 00000 n 0000020138 00000 n 0000020323 00000 n 0000020518 00000 n 0000021027 00000 n 0000019990 00000 n 0000017383 00000 n 0000020686 00000 n 0000020743 00000 n 0000020800 00000 n 0000020857 00000 n 0000020914 00000 n 0000022821 00000 n 0000022544 00000 n 0000021151 00000 n 0000022656 00000 n 0000024369 00000 n 0000024540 00000 n 0000024917 00000 n 0000024229 00000 n 0000022919 00000 n 0000024747 00000 n 0000027745 00000 n 0000027468 00000 n 0000025015 00000 n 0000027580 00000 n 0000030016 00000 n 0000029625 00000 n 0000027869 00000 n 0000029737 00000 n 0000029902 00000 n 0000029959 00000 n 0000033139 00000 n 0000033294 00000 n 0000037473 00000 n 0000033995 00000 n 0000032999 00000 n 0000030140 00000 n 0000033488 00000 n 0000033653 00000 n 0000033710 00000 n 0000327277 00000 n 0000327847 00000 n 0000033767 00000 n 0000033824 00000 n 0000033881 00000 n 0000326991 00000 n 0000327563 00000 n 0000033938 00000 n 0000327135 00000 n 0000329921 00000 n 0000037795 00000 n 0000037341 00000 n 0000034183 00000 n 0000037628 00000 n 0000037685 00000 n 0000328472 00000 n 0000037738 00000 n 0000039726 00000 n 0000039557 00000 n 0000037970 00000 n 0000039669 00000 n 0000042361 00000 n 0000042022 00000 n 0000039850 00000 n 0000042134 00000 n 0000042191 00000 n 0000042248 00000 n 0000042305 00000 n 0000046049 00000 n 0000046809 00000 n 0000045917 00000 n 0000042511 00000 n 0000046242 00000 n 0000046299 00000 n 0000046355 00000 n 0000046411 00000 n 0000327421 00000 n 0000046468 00000 n 0000046525 00000 n 0000046582 00000 n 0000046639 00000 n 0000046696 00000 n 0000046752 00000 n 0000050820 00000 n 0000050028 00000 n 0000046997 00000 n 0000050140 00000 n 0000050197 00000 n 0000050252 00000 n 0000050308 00000 n 0000050365 00000 n 0000050422 00000 n 0000050479 00000 n 0000050536 00000 n 0000050593 00000 n 0000050650 00000 n 0000050707 00000 n 0000050764 00000 n 0000054693 00000 n 0000054847 00000 n 0000055737 00000 n 0000054553 00000 n 0000050970 00000 n 0000055001 00000 n 0000055058 00000 n 0000055111 00000 n 0000055168 00000 n 0000055225 00000 n 0000055282 00000 n 0000055339 00000 n 0000055395 00000 n 0000055452 00000 n 0000055509 00000 n 0000055566 00000 n 0000055623 00000 n 0000055680 00000 n 0000330038 00000 n 0000057866 00000 n 0000057645 00000 n 0000055912 00000 n 0000057757 00000 n 0000060433 00000 n 0000060212 00000 n 0000058003 00000 n 0000060324 00000 n 0000062386 00000 n 0000062217 00000 n 0000060544 00000 n 0000062329 00000 n 0000065150 00000 n 0000064925 00000 n 0000062497 00000 n 0000065037 00000 n 0000068006 00000 n 0000068153 00000 n 0000068532 00000 n 0000067866 00000 n 0000065274 00000 n 0000068300 00000 n 0000068413 00000 n 0000068470 00000 n 0000069629 00000 n 0000069805 00000 n 0000069460 00000 n 0000068682 00000 n 0000069572 00000 n 0000069686 00000 n 0000069748 00000 n 0000330155 00000 n 0000070397 00000 n 0000070228 00000 n 0000069916 00000 n 0000070340 00000 n 0000073352 00000 n 0000072790 00000 n 0000070469 00000 n 0000072902 00000 n 0000073067 00000 n 0000073124 00000 n 0000073181 00000 n 0000073238 00000 n 0000073295 00000 n 0000074935 00000 n 0000074652 00000 n 0000073502 00000 n 0000074764 00000 n 0000074821 00000 n 0000074878 00000 n 0000077814 00000 n 0000078128 00000 n 0000077682 00000 n 0000075046 00000 n 0000077963 00000 n 0000327990 00000 n 0000327706 00000 n 0000119363 00000 n 0000080641 00000 n 0000080796 00000 n 0000081399 00000 n 0000080493 00000 n 0000078316 00000 n 0000081104 00000 n 0000081161 00000 n 0000081218 00000 n 0000081275 00000 n 0000081337 00000 n 0000080951 00000 n 0000084778 00000 n 0000084932 00000 n 0000085495 00000 n 0000084638 00000 n 0000081574 00000 n 0000085087 00000 n 0000085144 00000 n 0000085201 00000 n 0000085258 00000 n 0000085319 00000 n 0000085381 00000 n 0000085438 00000 n 0000330272 00000 n 0000086095 00000 n 0000085926 00000 n 0000085632 00000 n 0000086038 00000 n 0000088498 00000 n 0000088654 00000 n 0000088810 00000 n 0000089650 00000 n 0000088350 00000 n 0000086167 00000 n 0000088976 00000 n 0000089141 00000 n 0000089198 00000 n 0000089255 00000 n 0000089312 00000 n 0000089367 00000 n 0000089424 00000 n 0000089480 00000 n 0000089537 00000 n 0000089594 00000 n 0000092964 00000 n 0000093120 00000 n 0000093711 00000 n 0000092816 00000 n 0000089838 00000 n 0000093430 00000 n 0000093487 00000 n 0000093540 00000 n 0000093597 00000 n 0000093276 00000 n 0000093654 00000 n 0000096877 00000 n 0000097072 00000 n 0000097229 00000 n 0000100704 00000 n 0000097678 00000 n 0000096729 00000 n 0000093899 00000 n 0000097394 00000 n 0000097451 00000 n 0000097508 00000 n 0000097565 00000 n 0000097622 00000 n 0000100875 00000 n 0000101030 00000 n 0000101339 00000 n 0000105123 00000 n 0000105271 00000 n 0000105419 00000 n 0000102065 00000 n 0000100540 00000 n 0000097878 00000 n 0000101501 00000 n 0000101558 00000 n 0000101611 00000 n 0000101668 00000 n 0000101725 00000 n 0000101782 00000 n 0000101186 00000 n 0000101894 00000 n 0000101951 00000 n 0000102008 00000 n 0000128472 00000 n 0000105566 00000 n 0000105710 00000 n 0000105886 00000 n 0000106071 00000 n 0000106261 00000 n 0000110388 00000 n 0000107289 00000 n 0000104935 00000 n 0000102240 00000 n 0000106444 00000 n 0000106501 00000 n 0000106554 00000 n 0000106611 00000 n 0000106668 00000 n 0000106724 00000 n 0000106781 00000 n 0000106838 00000 n 0000106895 00000 n 0000106952 00000 n 0000107009 00000 n 0000107066 00000 n 0000107123 00000 n 0000107180 00000 n 0000107237 00000 n 0000330389 00000 n 0000173989 00000 n 0000173957 00000 n 0000173925 00000 n 0000173893 00000 n 0000110572 00000 n 0000110752 00000 n 0000110908 00000 n 0000111055 00000 n 0000111201 00000 n 0000111348 00000 n 0000111495 00000 n 0000111639 00000 n 0000112043 00000 n 0000110192 00000 n 0000107464 00000 n 0000111815 00000 n 0000111872 00000 n 0000111929 00000 n 0000111986 00000 n 0000173861 00000 n 0000173829 00000 n 0000173797 00000 n 0000173765 00000 n 0000173733 00000 n 0000114213 00000 n 0000114398 00000 n 0000114592 00000 n 0000114785 00000 n 0000114968 00000 n 0000115151 00000 n 0000118829 00000 n 0000116305 00000 n 0000114041 00000 n 0000112180 00000 n 0000115338 00000 n 0000115395 00000 n 0000115452 00000 n 0000115509 00000 n 0000115566 00000 n 0000115623 00000 n 0000115680 00000 n 0000115737 00000 n 0000115794 00000 n 0000115851 00000 n 0000115908 00000 n 0000115965 00000 n 0000116022 00000 n 0000116079 00000 n 0000116135 00000 n 0000116192 00000 n 0000116249 00000 n 0000119013 00000 n 0000119420 00000 n 0000118689 00000 n 0000116467 00000 n 0000119193 00000 n 0000119250 00000 n 0000119306 00000 n 0000122169 00000 n 0000122324 00000 n 0000122479 00000 n 0000122634 00000 n 0000122789 00000 n 0000123417 00000 n 0000122005 00000 n 0000119608 00000 n 0000122946 00000 n 0000123112 00000 n 0000123174 00000 n 0000123236 00000 n 0000123298 00000 n 0000123360 00000 n 0000127094 00000 n 0000126811 00000 n 0000123617 00000 n 0000126923 00000 n 0000126980 00000 n 0000127037 00000 n 0000128529 00000 n 0000128303 00000 n 0000127294 00000 n 0000128415 00000 n 0000330506 00000 n 0000129113 00000 n 0000128944 00000 n 0000128640 00000 n 0000129056 00000 n 0000131961 00000 n 0000131341 00000 n 0000129185 00000 n 0000131453 00000 n 0000131619 00000 n 0000131676 00000 n 0000131733 00000 n 0000131790 00000 n 0000131847 00000 n 0000131904 00000 n 0000134773 00000 n 0000134148 00000 n 0000132098 00000 n 0000134260 00000 n 0000134317 00000 n 0000134374 00000 n 0000134431 00000 n 0000134488 00000 n 0000134545 00000 n 0000134602 00000 n 0000134659 00000 n 0000134716 00000 n 0000137365 00000 n 0000137537 00000 n 0000137709 00000 n 0000138318 00000 n 0000137217 00000 n 0000134897 00000 n 0000137865 00000 n 0000137922 00000 n 0000137978 00000 n 0000138035 00000 n 0000138092 00000 n 0000138147 00000 n 0000138204 00000 n 0000138261 00000 n 0000138937 00000 n 0000138768 00000 n 0000138455 00000 n 0000138880 00000 n 0000139765 00000 n 0000139930 00000 n 0000140273 00000 n 0000139625 00000 n 0000139009 00000 n 0000140106 00000 n 0000140216 00000 n 0000330623 00000 n 0000140853 00000 n 0000140684 00000 n 0000140358 00000 n 0000140796 00000 n 0000142862 00000 n 0000143031 00000 n 0000143232 00000 n 0000143548 00000 n 0000142714 00000 n 0000140925 00000 n 0000143438 00000 n 0000144107 00000 n 0000143938 00000 n 0000143646 00000 n 0000144050 00000 n 0000144856 00000 n 0000145005 00000 n 0000145264 00000 n 0000144716 00000 n 0000144179 00000 n 0000145154 00000 n 0000145842 00000 n 0000145673 00000 n 0000145375 00000 n 0000145785 00000 n 0000146541 00000 n 0000146319 00000 n 0000145914 00000 n 0000146431 00000 n 0000330740 00000 n 0000147110 00000 n 0000146941 00000 n 0000146639 00000 n 0000147053 00000 n 0000148827 00000 n 0000149011 00000 n 0000149883 00000 n 0000148687 00000 n 0000147182 00000 n 0000149204 00000 n 0000149261 00000 n 0000149371 00000 n 0000149428 00000 n 0000149485 00000 n 0000149542 00000 n 0000149599 00000 n 0000149655 00000 n 0000149712 00000 n 0000149769 00000 n 0000149826 00000 n 0000150452 00000 n 0000150283 00000 n 0000149994 00000 n 0000150395 00000 n 0000151269 00000 n 0000151419 00000 n 0000151569 00000 n 0000151719 00000 n 0000151869 00000 n 0000152017 00000 n 0000152165 00000 n 0000152315 00000 n 0000152464 00000 n 0000152612 00000 n 0000152874 00000 n 0000151065 00000 n 0000150524 00000 n 0000152760 00000 n 0000328993 00000 n 0000153441 00000 n 0000153272 00000 n 0000152985 00000 n 0000153384 00000 n 0000155146 00000 n 0000155295 00000 n 0000155445 00000 n 0000155595 00000 n 0000155745 00000 n 0000155894 00000 n 0000156043 00000 n 0000156192 00000 n 0000156341 00000 n 0000156491 00000 n 0000156641 00000 n 0000156791 00000 n 0000156939 00000 n 0000157089 00000 n 0000157239 00000 n 0000157389 00000 n 0000157539 00000 n 0000157687 00000 n 0000157837 00000 n 0000157986 00000 n 0000158135 00000 n 0000158283 00000 n 0000158432 00000 n 0000158580 00000 n 0000158730 00000 n 0000158879 00000 n 0000159029 00000 n 0000159178 00000 n 0000159328 00000 n 0000159478 00000 n 0000159628 00000 n 0000159778 00000 n 0000159927 00000 n 0000160077 00000 n 0000160227 00000 n 0000160376 00000 n 0000160526 00000 n 0000160676 00000 n 0000160826 00000 n 0000160975 00000 n 0000161123 00000 n 0000161271 00000 n 0000161420 00000 n 0000161570 00000 n 0000161719 00000 n 0000164013 00000 n 0000164163 00000 n 0000161981 00000 n 0000154662 00000 n 0000153513 00000 n 0000161867 00000 n 0000330857 00000 n 0000164313 00000 n 0000164463 00000 n 0000164612 00000 n 0000164761 00000 n 0000164910 00000 n 0000165059 00000 n 0000165207 00000 n 0000165356 00000 n 0000165506 00000 n 0000165656 00000 n 0000165805 00000 n 0000165955 00000 n 0000166105 00000 n 0000166255 00000 n 0000166405 00000 n 0000166555 00000 n 0000166705 00000 n 0000166854 00000 n 0000167003 00000 n 0000167152 00000 n 0000167302 00000 n 0000167451 00000 n 0000167601 00000 n 0000167751 00000 n 0000167900 00000 n 0000168049 00000 n 0000168198 00000 n 0000168348 00000 n 0000168497 00000 n 0000168647 00000 n 0000168796 00000 n 0000168945 00000 n 0000169092 00000 n 0000169240 00000 n 0000169389 00000 n 0000169539 00000 n 0000169689 00000 n 0000169839 00000 n 0000169989 00000 n 0000170139 00000 n 0000170288 00000 n 0000170438 00000 n 0000170587 00000 n 0000170735 00000 n 0000170885 00000 n 0000171034 00000 n 0000171183 00000 n 0000171331 00000 n 0000171481 00000 n 0000171631 00000 n 0000171780 00000 n 0000171930 00000 n 0000172080 00000 n 0000172230 00000 n 0000172380 00000 n 0000172530 00000 n 0000172680 00000 n 0000172829 00000 n 0000172979 00000 n 0000173128 00000 n 0000173278 00000 n 0000173428 00000 n 0000173635 00000 n 0000163377 00000 n 0000162079 00000 n 0000173578 00000 n 0000326484 00000 n 0000174021 00000 n 0000174128 00000 n 0000174165 00000 n 0000174190 00000 n 0000174215 00000 n 0000174590 00000 n 0000174615 00000 n 0000175041 00000 n 0000175466 00000 n 0000176088 00000 n 0000176657 00000 n 0000177140 00000 n 0000177491 00000 n 0000177866 00000 n 0000178198 00000 n 0000178774 00000 n 0000179073 00000 n 0000179408 00000 n 0000184010 00000 n 0000184260 00000 n 0000185962 00000 n 0000186182 00000 n 0000189877 00000 n 0000190150 00000 n 0000191956 00000 n 0000192175 00000 n 0000196479 00000 n 0000196784 00000 n 0000198795 00000 n 0000199024 00000 n 0000201126 00000 n 0000201399 00000 n 0000202609 00000 n 0000202834 00000 n 0000219083 00000 n 0000219528 00000 n 0000238300 00000 n 0000238857 00000 n 0000251383 00000 n 0000251788 00000 n 0000263865 00000 n 0000264268 00000 n 0000270320 00000 n 0000270585 00000 n 0000274600 00000 n 0000274866 00000 n 0000290112 00000 n 0000290514 00000 n 0000309748 00000 n 0000310327 00000 n 0000326044 00000 n 0000330942 00000 n 0000331060 00000 n 0000331170 00000 n 0000331240 00000 n 0000334392 00000 n 0000334560 00000 n 0000334735 00000 n 0000334922 00000 n 0000335105 00000 n 0000335295 00000 n 0000335453 00000 n 0000335718 00000 n 0000335941 00000 n 0000336152 00000 n 0000336344 00000 n 0000336512 00000 n 0000336680 00000 n 0000336850 00000 n 0000337019 00000 n 0000337189 00000 n 0000337358 00000 n 0000337528 00000 n 0000337697 00000 n 0000337867 00000 n 0000338031 00000 n 0000338369 00000 n 0000338785 00000 n 0000339194 00000 n 0000339662 00000 n 0000340122 00000 n 0000340549 00000 n 0000341042 00000 n 0000341433 00000 n 0000341632 00000 n 0000341828 00000 n 0000342024 00000 n 0000342220 00000 n 0000342491 00000 n 0000342806 00000 n 0000343092 00000 n 0000343371 00000 n 0000343694 00000 n 0000343978 00000 n 0000344232 00000 n 0000344474 00000 n 0000344716 00000 n 0000344958 00000 n 0000345200 00000 n 0000345444 00000 n 0000345764 00000 n 0000346046 00000 n 0000346174 00000 n 0000346282 00000 n 0000346390 00000 n 0000346499 00000 n 0000346652 00000 n 0000346806 00000 n 0000346934 00000 n 0000347067 00000 n 0000347173 00000 n 0000347299 00000 n 0000347387 00000 n 0000347462 00000 n 0000347500 00000 n 0000347696 00000 n trailer << /Size 952 /Root 950 0 R /Info 951 0 R /ID [ ] >> startxref 348100 %%EOF pysparse-1.1.1/Doc/spmatrix_manual.pdf0000644010116400000240000045352611402270335016774 0ustar wd15dialout%PDF-1.4 3 0 obj << /Length 2274 /Filter /FlateDecode >> stream xڭYK6W訩2$8&z+x0"dqM2AF$<3'l4~?ܮ{Ș*Y"L2_idmQw\ERMDkzN]5Fw4Gsi+6_{تmhivW޾_O:" '{(aTs#=hf1iQad*G^7ND<*-#x)SA+ q)p0MOql. vwWvzןNu# e0)ͿPW?47iܿ]Z$Hk $޶MKtƶ_hSZtOӷ)-{WwdFj'{wYڟQ]m<+cIwqozTjCwplm%*LFٶꒆw`f74mMQ 4E nqOaIUyq&"9,Y-`%Y 2{Pnkn?̍@ݱ37PݝhCԚ絛ޟƲեkҨjP:ЖC&^pMwD2SʈyX*vŒOw4\V)/v Se@gO7O ,-diMң3e9<_e!:q{sz! 'ݑ^*b~ˍʀ5/oY}5IԆ <8ﺆ" "gQH:".hKϷH :ku49MR,zOUwm]/#-X ^p` |yUw X ː)>E52%x?BeFq HFƓ#<Hg}OB}O|^\W<&yN~֑RPa47y14l\1Nu}[-II> HV] dkCe%S*?\g= LE!ׇdEa^nVF#hW%y :ˌd@_0qofដ%\)O=c8.׻{R2ƟwO5ġ)-^gk$׻hE32>lBCvg%"Sr%ŹXxEaq 04 Kr淈6)&r|>bt Wpŷ;Fd#D1 ]yOe7`,\6Dx!P\wCr 8 Wu¿([teJ*%Yp© Qxb; {Ojiа U,xk:_~WurI(lmחpqm48XO/'M\Y[yz3<%.;ݕ䛡r=w>BDto3?0x!|id r2 l8ڕ5H74}U{چ?4mGCΓp X0zIN⇈ҹ * w*>h)`(%vU^ i*⚃ è[ 1A Sv%BTzz0#Dc]mV^5zK(LJ@E t懑c4gy??G8OhC}H8r  m;d|v"L&2&Pi1pșXC?|'|kt ml( } { WdG$w.pe  !jqH3Nb&rFV0!!a\/GVY. +˘ӹ*Ggi6AKƝ=zSvWantYFñto\a?E $zy|OZ. [JA `_XcarW9%WǐHIrZ-*zB=\B:fRen:r|⦒Co.ڹ-iݰċ_/S=[ >4X;ld8DܝF>jPg  C EW?Pzaχ&\hc4gT1pl:qg2;}(d`ӠV1.%^O#' `}ҧ c]fu&/^! eEVF֍w)B~Bvi~.׺Yp}cUS+KaQŶ;o*Ӥ,K2Kgendstream endobj 2 0 obj << /Type /Page /Contents 3 0 R /Resources 1 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 19 0 R >> endobj 1 0 obj << /Font << /F40 6 0 R /F43 9 0 R /F14 12 0 R /F45 15 0 R /F46 18 0 R >> /ProcSet [ /PDF /Text ] >> endobj 22 0 obj << /Length 3393 /Filter /FlateDecode >> stream xZKFϯm%`7 .2l(q- O~}%RYX]`1*UWWUhy{3KzaƸ$YF5a=)?/\?պ+]y$RΖ\n_(1Rtfl{:wk (akϻ-I_2E`c諸=>|ŏe}(@p1M@N7Eb "@3"( n\/#pMejaTzbu[{S-.}<U;$gtPE8x `(گp}K2XX((J%|G)bC < DF Qƪs~X [t}?MX("bF_XF("27/u;@‰..]U?ZF.3J8ilҔݺma{d U7a*Z['Jdԋur(I{?TBT[D&V_|W*+M\D:(:h6:`U/y:\NxST8JtKo *̸%O.(n/uM`ΆqF(5;Aƨa (w;Pl_#&p" E$7pG"y #D )N#z:g#qnqB%#8#9i#3aςA? :a\szXD娕)}9=z{OhI)~+7"~3(D+tKu7sY!76&V4ZɈeS e0?GNzPT3ffRR(Mհ8.,q| }"|rYcNk4$JCt|2 6;IftZ13z:dG _ȉ4oh]#ohP,gRrs(r$z>SNc#̤fCC ^rr":Hnq+^2FÖ DP>Mݽs얇qs7PЙ&6]BCkfg{=Ly382ud -f$Cǹ Y^D>?37dyADeXXpP_$!ˉjPb+ C/QM,m D w9Nht)' &:)y0ݭc.S FRfUqIUw'iI2,RSŨa'oCe6u铬Lny3 +]>Ra*lhp&]&~]W GJַ(rS WSD%@=@4ӱ CHzpSeSdķ<,xIAyxay7 .o .\ B0Խb׆qɒ}NW% ;Ihr]vIVbezA(b\N7N!Cj] YP]VYs0PCWJR]pjSqz>1 p3e䙠2XHvA_ ^W'8q`PU}3XȄ\{~H0u+F ?~龼)]"goxGᅪ2pY!O4ER6Jdn9$c,E>r٧rS cA;yI%pOI  qX}S6]nGI4pk?[8&q4,'5~7_U-?}(57o.|F^=}ބ9 .1z]&<&7v!l8.q>.'ɀî|v\P ?Ԟ{5LlCig@Ex LJlep&JeGb,K-x6Z¸}XM3)Ǘ65\dUcoZ]ZotYu@EI.1|)f`e`87Ň)O C3eDiS]҂*NZT1ͨvwB"+[ǗcrgW>/ҍb`\_Mw~~xnr ϛxudCַ/9zo8GmYC8bGC pZw "|CIGNpSMk4vd7NUHI1pH%d>> endobj 20 0 obj << /Font << /F43 9 0 R /F40 6 0 R /F45 15 0 R /F11 25 0 R /F14 12 0 R /F46 18 0 R /F58 28 0 R /F8 31 0 R /F10 34 0 R >> /ProcSet [ /PDF /Text ] >> endobj 37 0 obj << /Length 1978 /Filter /FlateDecode >> stream xY[o~0J2@bQt(:J_ÛLڒ33E_b;9T>/˥F|y$,G fpO>ds/S?a_ ]x\<t~0XݒrUsy%O~y)(#vJB&cPDϽ{kr[j'MÃX06pNdVȚD+4Z 3G},,Z _hE<2|Qirb~86ƍ 6~ؗOn4~ x fJݖ}O8n2 t};79|n&%Pl:PFӕf^daW N#tSUMs4 f߉TCJx"gu6n#/8`S\F$4*1Ls Xռ2 "Vbc(JVqYj'PPA M1M"kP++q0uHұjPn.a*Xtd ND%Q)yhߙi-wc "x9"e+y'D0heغ? b93hɀ݉g"hgYx?Ǹ5=8b)3 \8J_V!-l~3׌'\ִ7UJUdp+0=\4ԭ 2v 4_6BߙY=k_{SXl *|NN9(ɯfĩo:P9aוEw.]'ؾiq'L.W3o6O99⊜]`Nuh+sbOw!,~ŽH-`nuX*܄3n>b0)0bbP>&gY}oٓ4AivL﫿'چNaQ- Z?"θ_ 'ZֆT/endstream endobj 36 0 obj << /Type /Page /Contents 37 0 R /Resources 35 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 19 0 R >> endobj 35 0 obj << /Font << /F46 18 0 R /F40 6 0 R /F45 15 0 R /F43 9 0 R /F58 28 0 R >> /ProcSet [ /PDF /Text ] >> endobj 40 0 obj << /Length 2665 /Filter /FlateDecode >> stream xڵYKs8W(X R5wgS7OD[L$RCRI~@h95TF]\UəKfvs?%Ve&"umUu{淋_n.qk:^n/f 6%ҥz,ΉB$.Mys?=EOq1$y}f 1s~i'cbm˅f/y:ϗEST{8lHSĦ_ p>o9M|u-|6M1"~vPF: e|~C :hشU Zw~߻| 6UQfmv_ Yʛe]u6h<:mw\&b,W8fE&՗WU`Iv32wPp||rW%*Mvu Dmͫe!L;=e^ÔVaaova}tjl;q kx`#:mܺhGE?®je)xe5˧v  JIۡԄujvH*AAoq0P֍eQ.feCPѼ]{,0We]7WqoYu.ǃpoowxX$>{8HD bPj}K*y nӃۋ\eQٷbS<RcBL3&&h,p_X6jDJ8чŦx=kVwS<vYw1n\wzB1 D"cwqwO#!'T>΁jerx+l~]M>'yc# 1B*9V;-=~Yg<@'ph8O'kt( I_z!%H310-SHDK:\W1䑓HL"߼ץC[ 2zu*UE&T.]K WAbvC gÿʎ?I%9X7P-фT[\'wRZq)>.Q*k %w4ȍ I>TW}6bQEJ 3: ݛ7o.0u/?@*Qk_ nON)/8k$"\=?SF-PXV.{3!%IrV Z#&k[R̿P0&FX yp:/Qw+#:]U 5H:E9"VBt8{=!n~a4m==ty$4PK˾MoPU٦.|Apl|VD|2q߭:ٙDg, 7ŐT/H yp0qV' "QbgX'Xfg’kL"WO [9}-оoA)Z#\K / NJM{BvЖ\Gp|{z~TwTQҜ6oz2ow c_zҫUfmKglz4Ju.d%=K>||-OPx{K+:{#bt}[\}LC4*s&X(Q %Rhž`߾ {qK_I:Kϱ|JYEEqk͊L)Ni,)L@vC'uX?0_V5j]U"%o6SO?щ1Ʊ3AdYm۲'n!M\T YOűJ!jX*/4:a/u]>(ڧg)Oq CT%LHL"m2.Bd?ub* R`ob~mF_ |#`AyߴaN8EcGt3$SPE_M'R,$ е/bH^S{84Zj܊eQ|EӌY$x?5?@9RxOݘ?ȴi;hb~pFsj{ ^f|5ȳQQowmxm]>6JX.r6e3SP)f _bHrBR$:?`¡C"d :} Q5GM>n2? ƜPiYR,Eu?3endstream endobj 39 0 obj << /Type /Page /Contents 40 0 R /Resources 38 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 19 0 R >> endobj 38 0 obj << /Font << /F43 9 0 R /F40 6 0 R /F58 28 0 R /F45 15 0 R /F46 18 0 R /F14 12 0 R /F8 31 0 R /F11 25 0 R >> /ProcSet [ /PDF /Text ] >> endobj 43 0 obj << /Length 2940 /Filter /FlateDecode >> stream xڵZo6_G[dC-@u̓l+vmɕf>lN/>,")j8Ùqf7Q%Vs=1aI.,0n~q~GU+o Qf,D|yV7t %5J|cb}?=,3i8J)juĠ2axEN9)|#p+x)^STn3.弪W@(Mrau$p\uM{nVN۶-SU<6o\m[Ve[J<b*Ž,Ulrmn>Z7b_!źur]n)#dXzΡ vٻ5~o2BeyF;qbY tsUu} % 1&鸹ѹ^IE/ZEPQzm|AϽ+ޜf5I_zY~{ͪ.TyńCPMa-8l?93ΈbP 9&ԪG5̻@ǧ??V>=$Eq[©U# Y[ݖ-l;Ɔ7~onh [H­ЧRp8^"VqzD7ѭ 9喁iarۖX76.0?Y%)2B [m)ڑ~O˘&nIY~ٷMۖcpmUwvU?w[iXejKsNk3h(ڣ(q0%)əoR"lL2H2F2As&Dqj]V>ULGiŧrx,/*5s"rͮ'SO1!(ɁXn /E։Z nn״T6B.G= Z@?q,l "/7=I1_ݲ>>> `Z!h<߿>c|lQN0RXgAkެОb6&yP)1Zg%8(nH4QG0A4=)eTx6KH|*ãKrf1T;;Vw!Ff3[r> endobj 41 0 obj << /Font << /F43 9 0 R /F40 6 0 R /F58 28 0 R /F45 15 0 R /F46 18 0 R /F55 46 0 R /F14 12 0 R /F11 25 0 R /F10 34 0 R >> /ProcSet [ /PDF /Text ] >> endobj 49 0 obj << /Length 1232 /Filter /FlateDecode >> stream xX[o6~%HJ(PR@OiȖ+ѥi/%Oid@ys!CY~+rgv #Be,(eܣRw=-Ӻ. GM~.!HMZ:Y5i'fsfmTQ&1r1PSːZMY|B_v&ef|#I+2.mfh Se-9eSa*R}`l-*۬I{3\Wenz4<&vI0X" "#QE*} pXr0`%C10 li3\Б10+#i DYv= e (0b<$ZW=Ő/B 8P{ 0D#cseeS>9X:؎f8:q&4]lϷ#u^Ȗ?M #cl~R@_HK; fIzY>FFз *gv-4/ȖQ$ ˬ\m)>  nm)~!\G9:ׯ~5]ޤ 4JѭF9>~h8SD 秕{=2RzwlAѼ ߉ {)J ,qRk^VyT(¢|!?F!jh9Yl$T~2՞@H.*]A1ߚMp2Nl-KUØB>{C[Yf^=Zt[Gmvg6mhwr=;^6>=N ~eZMMj,Qn҉pm\F葉te8u8CC+Si>yWYendstream endobj 48 0 obj << /Type /Page /Contents 49 0 R /Resources 47 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 19 0 R >> endobj 47 0 obj << /Font << /F43 9 0 R /F40 6 0 R /F45 15 0 R /F11 25 0 R /F14 12 0 R /F46 18 0 R >> /ProcSet [ /PDF /Text ] >> endobj 52 0 obj << /Length 2631 /Filter /FlateDecode >> stream xZ[sۺ~PU(rz˙əf&=[N#KX\nŅ$HjLfB-" ȂpHjX.}3^l. VbhM F ^ ^ĈTzZAo3V4e#BZJ]P\dX!LZ\o>%??ؗ׿\JBg'򥢙 G @ 4fO˔*P0J'Faa$YL,cX$_DD1CVkaA^_/ i˜E~\X& b;n {sGRP/z_$3bAN3p2$qy(EBַ8x {Κ ;qH~6HB&,"Ȏ̎$b!HF~*JƧ.Ȏ1rʑք6RQL3`Lwm hKQIі&R8EҜ^ NTZ&"+E4ƬcO0kJ4F0,ȞYCl/9gx {f`>gbXaubO}6M 5ԋ#V2.edbmF$@x+`x*aPś4[n1s?f d { d@? %h{ȩFN4Gt7~8LQ f}0jeU !DOU|SMcD#V1.D!ATz"!ijXFzd3Pl@/ Qf:ЎLsC,xCbc (RT8`28FY/5JNh$ȉ+MDc'PK4%9,ȀfA2(҄ja} 7?Dٓ" fO/Pi^ooHLRz9AJ®ĥVjDj DQc硚(7>oRu d b4y~41<Ȯ A(dh{V_DQ]h9ͬ57!aVx>]/NV7| yLYƓyuvr;*\[*7a$%lMlyyjͽoп]R0Ddj⛏aM62K%7_~?"i]^*w%Y}2:K>FlQ^L$N6_^HP뒀k775ݫvÔx 2D3ITb=~r.Z.?q3e3k: Y2%HHMX,xove *`MVefN60t7Ci ac|IIN@-ь{z?vݟ<+^[v .-l#/7'=|z_5.< Ӄ0{G5!hO; g) 3y4op  8'Z_p[[i([{Ǡ#3P+ʶ,j~UNVգ ltA,%_ hm=i9i M`"M6\+0 %Q*,t|q2p>i7?Q8(|hZCFpp[z:MpqPMUD:7#([w\ľ!n $]}7px2Alwp;됏UҼZD!cBY \<7endstream endobj 51 0 obj << /Type /Page /Contents 52 0 R /Resources 50 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 62 0 R >> endobj 50 0 obj << /Font << /F40 6 0 R /F76 55 0 R /F75 58 0 R /F46 18 0 R /F77 61 0 R >> /ProcSet [ /PDF /Text ] >> endobj 65 0 obj << /Length 2653 /Filter /FlateDecode >> stream xڭYKϯОV~?  ;k &3`JxhKBRO~}dSqV_U۫?AFR[frDj7k>]vW5뻺m=>ukp-z)gGRB;5еto^|{E"+N)bRx}x«wW1^0""$Dq3')e!1!y+Q L o5Q,iɉ2^IQL}fNRn)"Z=gblq(>" UHd8e0XT#~Ȍ)kؤ9bOƈ/ z Cw\)p^ #Frn/}?͇ha{,ӼAJQ~NJ.yB%ӆ2@T}c}۽]_AQB!YI'6z7FUx1w9>Sp6^Iq g '-{rqp>ڡ&aT|x2H/pik?4 Auk ͕tH"\,T.,!׌^gvi=ػ!EA·HD {!"(&lHt:B()lSQpaI l A<-ΌPcI,0-f(˜*B`x_ >Ǻz4 %E%>[AzkƆ5j?mH0 TBj'>`nH}J5!q;Tl_}p) #H cdT!?%zT%$ 13~vݶ) %M2-}݄E`dIi ;̝X4LPq!e^IcAkw dpb#N hc% qOG|6]o`aUMd߾oC/d\KM!ko sK9%4f.Ŗ  aiTum-gWK3p. 5z1#jV]=t,R œnC-$2)!"R'OȤTC)b 6,pr%{jc}15-'."848H$af-2p2NLatD&x4}ch4%. (GET.#YayÍ0Ԓ~nŦɇ]s-7٪TȂ1&9p1a`$!+fs65RI^5bPꥼ$ y*$U§rlsv %@}@#!(1Aqۨ瀇}/[`%ΖCA ՗<O]ɻ 2JMVЖ,ΨY#NhOpFh=b QjXŠӄ~18Y=вQRcP:Jh]wK>i _"Lioj^\>]+ٳDW0 ^]A GJ8\u*Cs҄Q@DR+6 ?^d鲢Kϭ%\8^{ٴݾ]L }Tqc";ī(yxܿPlo14B ) 6sR.'^jK>́#̿vtJiyYnC9A1SCFZqMc{hu^ԺQ|EmC>8mioz-0/*fx/l:Ũu z7My{y[jXI Ly9MZ)}VeݡWeuWVJ\NJmendstream endobj 64 0 obj << /Type /Page /Contents 65 0 R /Resources 63 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 62 0 R >> endobj 63 0 obj << /Font << /F40 6 0 R /F46 18 0 R /F43 9 0 R /F45 15 0 R /F14 12 0 R /F55 46 0 R /F58 28 0 R /F11 25 0 R /F8 31 0 R >> /ProcSet [ /PDF /Text ] >> endobj 68 0 obj << /Length 2221 /Filter /FlateDecode >> stream xڕXݏ6߿oH4@o ZZ>\I_3JfŦp8O7?#1Yc~%e)̤3lu[|Z謁7[(/|J -[YO^=R6潫oi=|~܏?GG?mafAx{l-5뺶G o;)_˛{發(ɧB8 ~T-2D12sEhPc$sBF@|eALj2a2~lڅ%&)8W“{NE,4Bb_]{WdNGdiʛI.dI#OVZޟPM^UO4:'\3<(u=?&2R0+ɬJIُۻn`|{8M4+t& $`)SǪ uiI%Ys'RNՠW5f@JôԤxSzCVΠVTȅ0 d̤By^) 3AǞ=#,/ RF#ClB{/VmӇOXH=Ve.}(` a2.GH/%h~H^Hq,IHVFej&]A#U7 }{"O1@H}Upp;lJKqvLR>JdB }^;:)@`*-3X7(³>QNٷ*LU9pLL\rK.e*MeW/%)/1揻xEF$Dy`J#&PpˋySFcdž* kc)P .D<;E-A+ =L>eYxHKf)_'b!Cݕ.z]Hc H:UT`,)z_21u2*ąQMsIe1UnyjJ;p!0S4Ib&] S}↯~?E=hٮougY6~W7o=1Ns?Vi4s"qۡ%?Zi9M/DŽ{e9t3a4nPX$)1*1إj\^Mo#!#O,`4{u*!1Hײ!pЕa R'㤇s m1C#4\*,&yQ&BPɾGȐeQmu | IHvZòT_ו LLj+^AEUV'j|h" Sun:(R⺮ A$hj`AhkZ5=` ˛)5>>O̯;f 7Zdhr|2eҦri)h@042L$[e7!Mn`8EqC{]"bqh'ק>S}7nIYE žTr qJoPgGJFGz M"\*T$nK\ N/_ i5p=fXN,{[N$ eGd>⥞J!`_Ö6rfs`KBZ3$O8H*`n`"QO5%-qtDg+>_áyFl'{^Nö+b>ECLJ80Bl5 qwendstream endobj 67 0 obj << /Type /Page /Contents 68 0 R /Resources 66 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 62 0 R >> endobj 66 0 obj << /Font << /F46 18 0 R /F40 6 0 R /F43 9 0 R /F45 15 0 R /F58 28 0 R /F55 46 0 R >> /ProcSet [ /PDF /Text ] >> endobj 71 0 obj << /Length 1963 /Filter /FlateDecode >> stream xڭXKQ!x 㲷d.gw|p|$̈2I4ERn'@߿?22(V+3)_TƵY~]ù0n6[nӆuQt$X~wU튡pV˵ }[Ϯwtݹ"cɚ\ZHK}A%#(*ƴV0 cS x22eiYrE8q.چmQ<+nsn3+2lW} n XU+-uT"2΍B94;:VPyB06 @=LbHf_V>ѡVb!Ԁn\gw)5>v/O͖xLRWONk]T(- N<]ٞ}w{~~.|ϟ>.,>]?0z%>6a9]`%##29#NE9rMPPN+ĐY6tI8~ߕ;{HMYVg ݹ"OwU']Çop#\I}~f2+H=DՇo,iSuof3Ar-Ŝ7p1CBYM>"*>? "F"n&B%+*&mƭ WW=6٩pUWڗ?nDSz&B<9{sF(ີd3OfE2?PȒ\TdP| :TrWo~?S^endstream endobj 70 0 obj << /Type /Page /Contents 71 0 R /Resources 69 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 62 0 R >> endobj 69 0 obj << /Font << /F43 9 0 R /F40 6 0 R /F45 15 0 R /F55 46 0 R /F8 31 0 R /F10 34 0 R /F58 28 0 R /F13 74 0 R /F7 77 0 R /F85 80 0 R /F11 25 0 R >> /ProcSet [ /PDF /Text ] >> endobj 83 0 obj << /Length 2189 /Filter /FlateDecode >> stream xX_۶קKR d2f8DE*$;gH]'>u"-?7- H6RP$R/ciI߮{ʎb \mCY߯7:Pqjʮkjt/w`{9a XJU`絊Vd7;J{oa@"˜`hHN'bDJH8pD"I _)"DӔY~TcZn@ FW9wvX5@y=Ǣ?4KjDĩ|N NBnrf0zu|A*mȉ["YϨU M4HR ($F)L"odGN뛖Əe`"˂3odᓔ=]{==aw'WuDUMU5k/\05&$Ou@$iZ)ms\ot SDw'o"Acm(MtcWH9zz@OލZ9 Ȥd?/Zq,/(Kc|̹.fpulDxzx-mQiwR}묄x/dZK)<8\vMna 9=})H5!% Sނnr"]B cd.޾|!R)`# rT/ $n\-f767% `(((83 nO Fi<bmI8F%C;ѼYG̋ RJ+Ri]d* q/F3,%\0:6+ oOCjH)LΩPg;V5y\χk&`QvcxUv7WX$5~.iv]u1!Ϯ|t2 x3Οq,4&"I T ADwI$RD#VIR Akˀ7k ъM{pw ?FX[(G` {9:NbW߮0(ɪs&TSq)!PA\")Ri*K"jp—%@'(&pzpSK_{:ݛc^.|/i?YqݗGحA2ɦaqxaWџ7kGk{H>t;Ü{iBh/RЖ]vd J >Tr iZhCc&d o M; .OUq. 7sFP`TOhu8a.n9kP D(*yZ=*vor@@Qu.ܻk3GM>`6 fT1@JۛѲ`y o HM9@W5=Mugo{[<˜۾=XB.U3ܞkRμYܟN`.<TVġDKh4u4 ݂֕fV?7HSWG1<癩l fkhګs:tY̪+ Z6w|Cza+C:MݕyUOPK m 54`HR6WtZ( jnJ蜯u,9M ?v>>+UcŹ0 ̣vyԿY31H6)fcܵ>˺B^+(MނMqjknsUh-@y^K|b=SBE iۙ" ,*cgh>RHG36 C~ m .ӒիoKC MWPBjB5{MPegnǔe=Xe!i!kXTFG">N@#b^A8?B?u YPJNϿP36$6,jWeǶ0wLEp{ .endstream endobj 82 0 obj << /Type /Page /Contents 83 0 R /Resources 81 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 62 0 R >> endobj 81 0 obj << /Font << /F43 9 0 R /F40 6 0 R /F58 28 0 R /F55 46 0 R /F8 31 0 R /F11 25 0 R /F46 18 0 R /F45 15 0 R >> /ProcSet [ /PDF /Text ] >> endobj 86 0 obj << /Length 3398 /Filter /FlateDecode >> stream x\ے}߯#eN~r9TJ9Ѿl?`Iק̀2U`OOdY-.HXo{x‹W1=`D%iep_W$+Bc0Vh'Vt+RLi;o rqs ![(/n6?.;M]|ۛvX8LE:eCr <Rs <THs!+#QL۞ $zC #h!Ϡa #]hû, "(K.,;Ct(ɜP,9 I E HAX9 OI:\tr"fl) nzE^GHgV(qS(P9d&P)RRpQ&bDSKֳ)r)DBG jF-AMC԰>".D1J\3jK\Crs19!L>`S|: Ab6d @&&BRD(8̆) ΐj9Nh 蟔 $hئ{g@I? $}(d" $' &l0Q@2H͐@ɟ9@v0 RQiT2DK@b2 R%">[{,CP45wD,K/?˒1,z2g>( sYb.cxfpĮ̙L6Ď&!eN 2N6'p *)G+sYga6Hqw80! ]*q2 aScRSl60#bś9ɴqAJڦ+ fØƮI1R/-'@v0 s2s|9D#-:Bgh桸/l6ɘS않9Ga3PSc;Ą vM Q_ QOlImaB46xP?t|}.8 nd Rⷹb .I2.tbc6LAlӘ{۵A¾&\m#lM:\tpe2$` v0 AvhR./nfْ4L G LBFa>(-hW7IIbKaL͵sfI^1?a[z},U?>bunoځk/A/C-wMa?foWl@>B3Psծ,]?Mퟰ#}bx(ݦV4ek7n6Lavდc}tM-k,tV#[n!un0$cY@F)o"c`]{`o Mde-Xp׍UNڛ-dY4?ZOb ړ`z{LJ- '3Apa]ԥ{a{PL"(9L۾F)!M K#^#t}b9 58D U0+j$҆|i/6Ux`A!T1UZjLz"?;"S{o awPzۄB\EOu-\#`(08Kz< 0 ėlꧭp!/_pu[|*` G^ gU`ZԷ툫tH_ߊojפՏ)}"߷YXE6pᘎsC ֩ 칏/ИHX<43[/BF!!J?{PoPj©;9xa$Z}s7";4F]#cQ|ݶ]!km`Mw.ݕ9mXXvc'{iAN|e^ G`"L11ωuoUk70Pu>~`sܝLqv!#5SKg8i֦3~;nsF &=)Ċ )T L9=fp%☜ڭ nm6*n{ 1<Ԗ$kv#aX2Z#sD]6HߖErueUS6VV_s7xa"H&pߓdnOp-]#0 dUJUUC ؝*,ߞAYL+պRɟŽL `9 ,in#(Sx難X$["!&)Ke2|uox\&hX._1yCx }A#17J ֨l4$-XmІ%>Q*<ڤfBt6bRvNU̺h) Y$b6zu eoZQMPn ~MedkЪaϕ?15%a^JLPtAI% }tJ)qh ~V~V0Q/l  eVo @@ }Ur|DnSoK{/ ;(-`=endstream endobj 85 0 obj << /Type /Page /Contents 86 0 R /Resources 84 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 62 0 R >> endobj 84 0 obj << /Font << /F40 6 0 R /F11 25 0 R /F8 31 0 R /F76 55 0 R /F43 9 0 R /F58 28 0 R /F55 46 0 R /F45 15 0 R /F46 18 0 R /F14 12 0 R /F7 77 0 R >> /ProcSet [ /PDF /Text ] >> endobj 89 0 obj << /Length 2920 /Filter /FlateDecode >> stream xڝZݏ۸߿Y~<=m.=ȶ6Ė\I;CeIKg1"p{_Yy歴ǕNU-n[/4g+~#_솺mbox*تCu5_DQUW4YWqX O힖l@]U&.P{du1LrV!7F&G tr]\"w=hOUَGp&@6tO F !;ص* w |Ͷg&'~t!UbL?_j 7/o wwI;a:}/Q}<cg_}-|jJ܃F}rWE͡p#J<o7 A?FJf;eIu^BPpp" [3! 8Ǎ_Tq>7|LǥA#]* _ oICI?W2ROtˆ;  \'TC@DghN߼~ѾwmWOGTt\*"L7š`Ky|<|: DiS#zG.}b|=AWMlסZc R $e 1e^0SCtnKM"s~ǔ,i?= h9ӏ[Z/`9WZQX։YD2$ih\tq@[hա`kbiW!yH.l.Հ1@w>^NZnZ:VH(x>ʑJh镆Zvǻ+_g;dV;MНw? n7%{W;qr3FM#IQWmdùs}5 A#6ra>] YT@5ˀqPfh[`-:>μ)}e6L96eYEZLPjrxYa4-ˉYteL[lb{W/Ґ=CPZ;۫ب;'cjfnxtˮt1X"ܹW@/rފhɍX&7v2PN)Emt ph3w^K-r9}mx+2S)F)eǶJ`*Vc!C.yC[y8הToB5řTŚ~3p1<ذUPpޖY%vgͮ Vi[CQ2s`tbS-@+HvSbo.CEK{*FH+_хJ:f,l `*ՋGS:TO.V}\,M,mDlSDGO/o=P*Q^Qh$hE[@kN\7Ӂ[a|snAZ A*X  HƇ?~"Ohx #0OƬ\0J\$˼TL >\eKtpyՄF誀Us$ i?7fa߰OpίcqOW  9&XGW {r:eΧHl!g-"RLC ," c;9X|2q/sx܈ ^\l/SCJNE_,9afPT 6 W&\+~I7s*gX1o]T^f|\^ Z1"iJ"&kq c;=,=@szGt'rgp !}^o3:v^ %M)] ds&T߼]2 XƩu%XH\Yë&*բQA3endstream endobj 88 0 obj << /Type /Page /Contents 89 0 R /Resources 87 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 90 0 R >> endobj 87 0 obj << /Font << /F45 15 0 R /F40 6 0 R /F11 25 0 R /F8 31 0 R /F43 9 0 R /F13 74 0 R /F7 77 0 R /F58 28 0 R /F46 18 0 R >> /ProcSet [ /PDF /Text ] >> endobj 93 0 obj << /Length 3212 /Filter /FlateDecode >> stream xڵZݏܶbߢ,?Eс4m\PI`vuwFw;!V5=(7OjKe[ Y ǼW뵱Ebhwn~O`Y~ .@Û#ty]9q $>#y)%S&U|Iea]|>yĆ#`IfDt{Xԇ/UڥjJ"ȞVuvߖhIӌ@ՄAEr]dG{E/ppG{ǘ$q:eF  `TDBcþhPY`[3P-TLX9@hhaO%%zKxFOH?MU޶y4tb=]]~7 o cT#0Y岩.^st]Oj g}ͧ{?|5\A!G;%>YC!TҞaCڔq/AB`wAeGFO8KϦqg0>TRj]`byklh 2؇+&0FhY|Ɂʹy? 0h79+<7)di9; kNlŚ&N<HF:lnJKa$PȜXm߯~W|30u7J8,WW?]8\cߝv*nXPsf%`cvxY)5V+fl{dK] 6ퟏH`\d3*0LWcU+Z |/pHԒ)uh͜_aW;P Ō_Eg \r-xjk;pqcq CtRCGwKAh |]n}k@~"$?K oyd#<5kCcTfUYoGC@mA)ŠP0 Q]|PcKmInN:VjԢTc.fMמ}4Xt@q?P\ILXdK,*b=@è-vw(Yl ,bS-*rlŖ-Hpi&ƒB4b8 LtPJ~8#8 d4,44} цCf~>&#KLZՔILb\Pt@DإBOW  }lz/¢ӊY@ym엥 Y=ql\dQyf‘W"q4ՖkL/K~F&#KL1gʄ scx%~JZ/;x kSkLN ^w͗\xHwtnLP]'"|uCؘi(p%sLcIEU]Տ4YI?E.Bԗ㻟匟A@ Ky`xxaVr~+cYiv}TlKbjiߢ5[{NMkޖ0sd,3$Hq=&H Nsm-/v~As=U>}'/OA B5;Է ^7Muw- m4"u3Z6ͻ+ +MZBsaz1%e Xu9vbR6(5vѴf%.vW['%}2AaiTJ^Gt]*}endstream endobj 92 0 obj << /Type /Page /Contents 93 0 R /Resources 91 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 90 0 R >> endobj 91 0 obj << /Font << /F43 9 0 R /F40 6 0 R /F45 15 0 R /F58 28 0 R /F14 12 0 R /F11 25 0 R /F8 31 0 R /F13 74 0 R /F7 77 0 R /F46 18 0 R >> /ProcSet [ /PDF /Text ] >> endobj 96 0 obj << /Length 1929 /Filter /FlateDecode >> stream xڵX[6~AHjMRyIuaC6E"mϯ#$as}to/8P&I$8IKDhEobML^}QUqG1(㘍ʿyͻX=}Qf/\/NNfDYR#")iKu$$Q<sk-$HƼ]t]H0lNxꟁ~l!Ʋti6f?_dzߞ:μjz(7D?oC'&eB@Daa6. }r3xY K["QB^} Sxɡ5*SKc̀sk~osԁ1҄Еq0+HD1HdW[G G?0Ј,Q(KԏW?M ӊ|oƪ$Asr٨o.Hd&!&J]{fw$\S#$-2ۏs(]]@%¡TRq峰,\eNren8I5HPA!D"YlPي6s%Ā J/5]!rֺv&؃ F [iqE.X>="B&fNj)g(:;vPjltalk~Tu([UKՌ!/e'`__8+>}RBoOaq\˄I [bDـB#Dǡre,{-w# %oVb U'"4x_ΐ(l"8 (+p̗|R&g1.-`,lה^6O֧ -~0ц'SƛhàM]j gk_vZف~4jvz=ľ8onBge@(Pj@ur.gZ1){caWu3gl]_MM"dtϕ>6{sdcՔyDJu %tj$IиsM rFb]6ɖ6za>Fd꿯=v}}Z8vnAh:.d偱qΑsRlom c˼Likvdc.M1 uA <.T|^b}iC`^/w50ڶRڜ_,#'ܧmo6B^MbxUM>AH5mGP/G%4DRA9:(,eOR) "yڎQ gx^ ؑf?m14P8݁J_zs2bl˦e`soh9CvXy-Pʱ34]Xg3&TK5}PAyr98As'3@xbK-}֛Xb@VUuھn 8P( F;,`9$`]u6Shq`Q3]}\-z 'pb0 Df6 ,fgMqskP$->2nlZ!֥-vvB͎nznsU~m>:coߡ3zfj8=F1QH%-ٮ?$C~>D} `)gS|v=5@',wӊ|I{bX ɠSa~y$3g~ŗT&]u[plSBl4_y%v%~6G `} DB-$@b4"Sendstream endobj 95 0 obj << /Type /Page /Contents 96 0 R /Resources 94 0 R /MediaBox [0 0 595.2756 841.8898] /Parent 90 0 R >> endobj 94 0 obj << /Font << /F40 6 0 R /F58 28 0 R /F10 34 0 R /F8 31 0 R /F45 15 0 R /F11 25 0 R /F43 9 0 R /F55 46 0 R /F46 18 0 R >> /ProcSet [ /PDF /Text ] >> endobj 79 0 obj << /Length1 795 /Length2 1960 /Length3 532 /Length 2532 /Filter /FlateDecode >> stream xy<V~ Y"Uh6YdAofMQ^ƚTB![ڜɡ t':v|ru[hsp@@4,Ȧ26D6d1#-Dm XfHbVtE% $" tg;Zh ێPB,DFh4Hؠ?@eoL 4&@PuSA ZH(҅): 7~lnFگ8hܶݖm~j*WQ>Tە5H%hĒ0ACғ_(jﵓQgWAu3eS!mרRn|0q gƎ^R 7p및؝2ISA{C B˳ u3>ufWywɅFsg$aܟ:9 tZVNH F5o'~0?^Wt>R`=XI>i,plBA\jĜKVwottUͿ_ou-; @EK|2G^5eKd(Mc*Q.^oQ:7~Q'i\KRk){®ޢxQn1⚑3[ u\,EHH~ JhƟKi$5ɬ*K6:$!{2 G>.E=˅n%o6CMvAO %md%JF%>xFĭ8yiw ә2 "nwl@v rhU>s59^RnSl0TzpbށG6: .+`=~|>}gƼʔ6lx"׵id9b8 @N™_`C^i<:5 n!,~P* h(HLMpEqt!2臝z&?lSw\pWKEv[:+ٞꬨKor}f KȄx1kٵ}pWcl7]ⶑ{{kbTJ9c2^ osr7J{eM{ܺOZCt *i}hī3xXVvʉ:gZ lT@ %[\j+m$F6M@LW(K}2:.dވSa|"hy?>Z pg=Zpo?рD,6Ndg-/endstream endobj 80 0 obj << /Type /Font /Subtype /Type1 /Encoding 97 0 R /FirstChar 102 /LastChar 111 /Widths 98 0 R /BaseFont /QRWMGG+CMTI10 /FontDescriptor 78 0 R >> endobj 78 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /QRWMGG+CMTI10 /ItalicAngle -14.04 /StemV 68 /XHeight 431 /FontBBox [-163 -250 1146 969] /Flags 4 /CharSet (/f/i/n/o) /FontFile 79 0 R >> endobj 98 0 obj [307 0 0 307 0 0 0 0 562 511 ] endobj 97 0 obj << /Type /Encoding /Differences [ 0 /.notdef 102/f 103/.notdef 105/i 106/.notdef 110/n/o 112/.notdef] >> endobj 76 0 obj << /Length1 786 /Length2 1552 /Length3 532 /Length 2126 /Filter /FlateDecode >> stream xRy<Χ6T/e,wL 0ˋafޙ`B*Gtdɒ EljD%#[5?~>~(e> Dm!wVkXV@`̥C,k24X"<a~C vL jV+"} t*`)A%3WJQڀW:" M4: P : ^c eZ8a"SȤ: HX("Ї YmCdxQFcL:#_7",&YMJH^}{vgFܫ*ܼ0`9v>Ze_:w)l4W؋D^f7ETTx`W5dq #BSS6v|UGX&.=x9I;%zݢ )MN;^iI qNj)ze[ΐdjhJ|?0w~o=pl@`_-HQnYMiB|QNTs36Gy{Tz3z[!krnW㔥Yۗ=܀'Řw#ҏv%ʴj WZg5gD|#SYMH7V,RR)]QjDDT1GrR Rv8I-8\~/#5XiDu 񂑥,.RCGQoƔ&zaNyܻAйs]7PK779{ }#0j΋Woӝ,ݹNQyUr| ެ~;Td]O^D!D\]mԘbF#,G'?OoFt1z-.H㔡ɱ yE;^R#S%$>⁅WcQZ7!r!{a-[Ņx ??h(-|C :Ԫ+H]<;̶w(̃Ib8ٱ.Rgks#S\OL)4:$m ]#?.nڶ:fßUP/=A|s(~#@Jhkj֗CAi 6}W\9}  |o258yFhE̓%kī:mNKbkF] C /cc0raaRas_޲%dTv ڼ/rg_7xu={ Jt֑v MPZ~/zE|QpwQ&mp  RTStmMSϛllbMTK^LNJ,:Il0"3Sv.:f*{fPNjyp*syR{m:hIprv*p *Zᳩ_'gVXwv3}8FaURF%BוڙKGOӬq}Ri1}IF[Jxӫzq.:fKW` s!&E9_endstream endobj 77 0 obj << /Type /Font /Subtype /Type1 /Encoding 99 0 R /FirstChar 48 /LastChar 51 /Widths 100 0 R /BaseFont /ZBJVLP+CMR7 /FontDescriptor 75 0 R >> endobj 75 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /ZBJVLP+CMR7 /ItalicAngle 0 /StemV 79 /XHeight 431 /FontBBox [-27 -250 1122 750] /Flags 4 /CharSet (/zero/one/two/three) /FontFile 76 0 R >> endobj 100 0 obj [569 569 569 569 ] endobj 99 0 obj << /Type /Encoding /Differences [ 0 /.notdef 48/zero/one/two/three 52/.notdef] >> endobj 73 0 obj << /Length1 745 /Length2 581 /Length3 532 /Length 1113 /Filter /FlateDecode >> stream xSU uLOJu+53Rp 4W03RUu.JM,sI,IR04Tp,MW04U002225RUp/,L(Qp)2WpM-LNSM,HZRQZZTeh\ǥrg^Z9D8&UZT tБ @'T*qJB7ܭ4'/1d<(0s3s* s JKR|SRЕB曚Y.Y옗khg`l ,vˬHM ,IPHK)N楠;z`GhCb,WRY`P "0*ʬP6300*B+.׼̼t#S3ĢJ.QF Ն y) @(CV!-  y Q.L_89WTSQ-ҢԼp: Ԋd[ok[Y*V}Ο'־~ bG̔`y%K^-|xE dE[${z,^k nW6wMpa،9=թsr y)/~V$-%)+2W}~)Snʞ6-*Аbm?k/H&gB;A[":SZ}qMw~O: 77s7;8?lj9MuLWŭ94͟N>/rW7Uj{E=ۙ^ mWMXZ7_m]ToنU]0RܭboWd☭znڶ *nnd UDU+˸RIѱC&N3.0G߯Н69# 4W쪻t`j7nߎMȑ:/SFE?O.Ut[ڐJg_,]{RP͓nj-._alyyȗVk&' i=81wry_€B5j0 9'5$?7( 8jXendstream endobj 74 0 obj << /Type /Font /Subtype /Type1 /Encoding 101 0 R /FirstChar 0 /LastChar 0 /Widths 102 0 R /BaseFont /OYTTST+CMSY7 /FontDescriptor 72 0 R >> endobj 72 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /OYTTST+CMSY7 /ItalicAngle -14.035 /StemV 93 /XHeight 431 /FontBBox [-15 -951 1252 782] /Flags 4 /CharSet (/minus) /FontFile 73 0 R >> endobj 102 0 obj [893 ] endobj 101 0 obj << /Type /Encoding /Differences [ 0 /minus 1/.notdef] >> endobj 60 0 obj << /Length1 749 /Length2 729 /Length3 532 /Length 1273 /Filter /FlateDecode >> stream xkPW} ZbU h HU0HLy(ݛe &DE|_:hAh-`(U+VcթnSt{Du_h`Cs~ET G2tA9@PbT \"Kdo`R,K‏b$!zȒ8F(Kz>($"BQ ھ P$ ԑ@lRZ c+) SH04e *? $#E0=^2')_Fb @< Ҩ*9"ZGAi@"H$$'-F`:(|{} HܸHaijXs ks}=;bIXxxY4$i X3 >J"44Mx`f8~ - $%i3_ʘ$P4 d2ߌe!+|ZB >=msw;>; I#-xsgWuuɭn.l帵nJ7dJkEb\y[GN[2w{ъZuo+e\i<5zeûju݇U}o<[v5DMn~8Bc~)XMmjr<n~OVu1q"NVۥqs\2۲j&քD$O1IHW_ϚxMˊ8S)eN/KR+nrg3G4囨*k8fʖ5?-w/<bfsɐ5M3/myafʞSG_/Hz> endobj 59 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /TKCVUK+CMSY9 /ItalicAngle -14.035 /StemV 87 /XHeight 431 /FontBBox [-30 -958 1146 777] /Flags 4 /CharSet (/infinity) /FontFile 60 0 R >> endobj 104 0 obj [1028 ] endobj 103 0 obj << /Type /Encoding /Differences [ 0 /.notdef 49/infinity 50/.notdef] >> endobj 57 0 obj << /Length1 889 /Length2 2579 /Length3 532 /Length 3213 /Filter /FlateDecode >> stream xRy<{&9e$g:1ƜlP(40fA2(K,G"ɒmJd)iQT,eyzw]{7T阣)zRp!up @]#bĆ=qذG^΍js[̵U^{+zƣ9TU{YW|ےc̝zk{^>2NWC*9VǞ9 t{o ħY[^RE I7sel1۝=u&y@# xdCu\ĺ}e[$نjnqSڄ{OUEjٌ3K57"Vl,5v= ߴۍ@S_KȰür9iEmq|GPNijZ~]|@¸;q}C]={U"]H^ YDt4J_LFl9Ε\\B.)/*&R6U?賒S{ ~篾%2בϕIVN_6Vv`zc/hw˝8"D g1)m}8>y:a\1fp}<9J/ebo\i0 U4ιvۻ5:9{yVZꮕ@ }֩qb?rV,L.OKI6w} ӛ%_sj \rd|E,AK,OͼKr,fTB *[c]t& (I!Em>Nn/sщT{5+m:|KWksz6&k1ſ-ǯm(.ucqdGu 㵚\)1(ۭɶC2j}|Pϫ&鄣 (8wxe~mW#q45Fz[+J*y N;zoh!-jX UAviհnX+5^-;o+Q4؛@?K7M>9K(Xڧ'+AGK,)icqgmNj> ֑,N Bt bzϢ޵n-]jLٱf&4Sdu&eϰ%Ϡ|4'uyz1ci#{}˰|po>1|dIOrw#g״^zmQ+Fis8Tz"5gv\?g}|2W_M;&Cv{Nu-"?"E]2¼rT0T0,TӷDTx6wE2I ^ͭ-iFE/Zl!;}nFl%Y+9$[{%7nPgFgzS&"H Lc̱[ϠI`6ғ=H3oI$}^}Rۤ׻6) uc` =$,Q300nWi`BiJݼ$(}CQv@ǥ."?TC8;.[ _e_sĭ{;t*/=s-J~Kl{u-eGd/ 3lV~ЀPbg}\4/XmU;E\gRJ캲iv{gw ǫƥޘnZKHqb1+k8P7H{bK*+>NIU(;i)YQBR~vKko—[x}+> endobj 56 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /LMMMCK+CMR9 /ItalicAngle 0 /StemV 74 /XHeight 431 /FontBBox [-39 -250 1036 750] /Flags 4 /CharSet (/zero/one/two/three/four/five/six/eight/nine/equal) /FontFile 57 0 R >> endobj 106 0 obj [514 514 514 514 514 514 514 0 514 514 0 0 0 799 ] endobj 105 0 obj << /Type /Encoding /Differences [ 0 /.notdef 48/zero/one/two/three/four/five/six 55/.notdef 56/eight/nine 58/.notdef 61/equal 62/.notdef] >> endobj 54 0 obj << /Length1 780 /Length2 1381 /Length3 532 /Length 1951 /Filter /FlateDecode >> stream xR{_Pe_yYT7-V_)4n~n9,ݒ1X3CUģdL#f)9ݟSqivnZ`hhE %}Kۇ$3/3PyN'@a_֜róR<^' nv.;Xma?b#ڴoIֲ>z',oz?gUS<֍+̗J;R&sQ;@CG} 5:g*mxEb'uaʟXkǟ.SNo>pRy+0 /ΐv)HU{|5kKzEaw9=kB/eS#k8{>$m]wR>Ij$•g| ?ҚgtW=1" RsacbCT܃/{|F}U#TaP˗~z[XK>>y[2O6Cq~թlwJu4|IreIqrh$P+I^X\!!f Ne$8GC춶٫Z>\}eb4vlDۛ< z*sN~X[FC8,LK5ԋ["RqmxtBZ zա#;7M" w>:u.Uζ~&DP[UB VGmʧ[/hF񴧪8K 귶 R.̦ -ZUendstream endobj 55 0 obj << /Type /Font /Subtype /Type1 /Encoding 107 0 R /FirstChar 58 /LastChar 116 /Widths 108 0 R /BaseFont /QCCSOO+CMMI9 /FontDescriptor 53 0 R >> endobj 53 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /QCCSOO+CMMI9 /ItalicAngle -14.04 /StemV 74 /XHeight 431 /FontBBox [-29 -250 1075 750] /Flags 4 /CharSet (/period/n/t) /FontFile 54 0 R >> endobj 108 0 obj [285 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 620 0 0 0 0 0 371 ] endobj 107 0 obj << /Type /Encoding /Differences [ 0 /.notdef 58/period 59/.notdef 110/n 111/.notdef 116/t 117/.notdef] >> endobj 45 0 obj << /Length1 805 /Length2 2172 /Length3 532 /Length 2757 /Filter /FlateDecode >> stream xy<)#"ѢN?Edj23!cY˘ 1?P9Y ɒRRY({!l% YC{o{{~CR T8O, yJդNrѽp@Bz;!idC hl#i+@%jdP~F ڙqD{Uh\^/o?g?vA(4 X,7zJ8h @.`@y +@,hKJC@rE{ =V3ts=Y,Y}`$T?wdxW;D t- N=*CXE8_\<3J`Tͳό(-;gh4njfypO͗8S!K ۦǴZ{_ީNM&*,ߋt+Tڟ)(nu1(o f%=^R1B=nETyPTWO ̑aaa쭗:8o??_WO ,x GMl!U\_J ~gxQAԯ{df7cPDE oL}]x`\ ܜ*1껅q9wydɫFrwC{6jџb "9/aEs3\}yLw<39Yy ,XvprtxU|Y$H?Ռ -pE34$pr|}f7Kp&]h>iT-%SPa|rI56[%T̖wNRWr%dmN xT_mJNVRJŭܯXxɃ7GEOBOvSء/}Q4'5X[o;nG(d5}ES5}Cq,-JdVHJzs_PgZYLz:ޏ 7wJX%h6e;VEHZ}G)wJl| >1T"MB/ ֔.ᕈEpI{w9{ǵ&n3Ne"W3Y5Ԗw,|=?a ^((YRKȘș_$3~JMqrIXS']A*DIau .Zh =X) ]}#m8dҎr> K=s_}w6&XiUSg?Ǟf*/ԗǟ|tBh663NJG@P$>dKRbl9Ew2AzGsc4BS#&ݾ^7>Z/+ha~ˎ i},fq^kZ t:t؅ҧ02~rp +G+㳞9Dӌ{:3fܸgHRxY'iX'%⶟=Pw >Iw6~1fXߘB\ݓ0ca: VH! ms<8qܩI ؿGVXɊO;|̽AgI:H0'p6) YmArއQ),s:a{ Ng:TĴ`k;j*MCDB' dw8~TKor@ 95S6Mjq':b𰰿 oLp,2wr FH |m\&NR_R$k6V,bzel.,+|~_XUINīoBe`8v&FsJSrg'*B{#RX|uNFDƏ,f=+ 4"5l!v~o!^%"#i{b˞ ' Ǟw/fo+9ma K[1耻N6-yFn;=r`B'L\͙*YYՉj݂Iw6x}D׳@xJԷX)9MT?O4 AXendstream endobj 46 0 obj << /Type /Font /Subtype /Type1 /Encoding 109 0 R /FirstChar 48 /LastChar 121 /Widths 110 0 R /BaseFont /ZVXCZM+CMBX10 /FontDescriptor 44 0 R >> endobj 44 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName /ZVXCZM+CMBX10 /ItalicAngle 0 /StemV 114 /XHeight 444 /FontBBox [-301 -250 1164 946] /Flags 4 /CharSet (/zero/one/b/x/y) /FontFile 45 0 R >> endobj 110 0 obj [575 575 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 639 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 607 607 ] endobj 109 0 obj << /Type /Encoding /Differences [ 0 /.notdef 48/zero/one 50/.notdef 98/b 99/.notdef 120/x/y 122/.notdef] >> endobj 33 0 obj << /Length1 743 /Length2 1156 /Length3 532 /Length 1710 /Filter /FlateDecode >> stream xkXWƹ 6-ZWSJ&  A JXDA $3q2RDmV XAPW,ܞr]qri}vf>=yϱۊ%@$-r96fH,,08p` QLK*h[!-}#X@lT, dE6K0C ."'Q> p9 b Оh,H*|:a@G (d,?B&@A DH)@4, .RЃ'Om%@Eb)0 ,ٸ@KE',$P +5bK\`x8? %`bM| d?NvɃG.œ\ˠB5ѡE{DF!0''P4V4:RP!d`2 AqHLbSf }K?*SP +]HB6tJĿR pG41|>Cb+N]ܙ\(1;䵳v;V#+p'gLT)'1gdJm0=Nv|P_׿4 ^r}jsqo.g^Ga!08C8|{+v6>9bcMm.W=kBQ۞zx qe`{Q6cJ!BO~HQ"{lq]G;wK.-pPgL\3}i܈^[̋279f̍C Jfr>U2F")5fV@-qN9Hy=QZd/ \ϱT0rH s]%22w>xFڦMLRu-M3`M6Kk4,V6WL×/+]*/{>Ϯڜ77@=fJvo1PW YUᩖ{^E SemkM/>15|[UqVubxf+S{k> :F?t?a\X:6L_8[:6Ian8pU군˾%ɱԦ0Om4Ji۔M%,KX[o=ᮊ9Ћ;mZӌZ&]>gs6O9~5ҽ&ğLw˳c֤NF;^s\h r|I\Š=Ф.]r|f߻ΉCG_[f:$#Ey?X7~] "G&~.K`@kC1! erj}oĨd@J7+Q0w$mΝ*gcv.Nٶ)j̰?N+AD5\n^woO[wnV3P|1ݭ.$PіJʰ7wVT\l>`ڽi^;IolH*NLu>;'&q;u`B@TηY%usgЏŔfjȱlm)Qeiۏ#OtkkvUPGipi;?|70 Q !endstream endobj 34 0 obj << /Type /Font /Subtype /Type1 /Encoding 111 0 R /FirstChar 84 /LastChar 84 /Widths 112 0 R /BaseFont /YABHEC+CMMI7 /FontDescriptor 32 0 R >> endobj 32 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /YABHEC+CMMI7 /ItalicAngle -14.04 /StemV 81 /XHeight 431 /FontBBox [0 -250 1171 750] /Flags 4 /CharSet (/T) /FontFile 33 0 R >> endobj 112 0 obj [675 ] endobj 111 0 obj << /Type /Encoding /Differences [ 0 /.notdef 84/T 85/.notdef] >> endobj 30 0 obj << /Length1 1044 /Length2 3757 /Length3 532 /Length 4461 /Filter /FlateDecode >> stream xSgXJqP$Q:H !$^(Eһґ& (WAix?|35k7ڃX ᒸ,EĔ!*8N@a1p( \A{J\ T8TH Prq( N GX $xJh4@<qqB{@J8`?`)'ɼE"7 P],4C?h]OFWB{Nq 0,5Ц"Q.jhB ? ^"QG_8ASѹ_&Ʀ&*WN]bY+K1BgaX$ \8Bb$( @/`(K nXgCPW8ĠA?|iⰿŀDzVq:`q!(U\x1I R )A]Q)$IOD[ ?ܐۏ2e'_22Qpm%g"z!<(@-BT=goiBGInB*KNQ̝<ߩ3R_v2xARxl[δOxlLj;{E6a}ŏwe連!H :^éf۷֭.RSg{$ i`CGb '1S/i'O'rcL.ZP8Y2ds*@ι*$uWLV/CP i[زynj7pPXʱޢeSV0F~#2 F,9"s$n .M,P)_qصRtjtlsUBiOꮗw?[El&%;on/vZجkh|ۙx+W`>a A֟=2 ک:%.Dx1p6n(jPv_eKЉ0v! yNAM=B1l8Հ=$s;^-ᓍKQxGb6`ScG/he!-\ЭM=O5̦oT;.j[RlZy~9.A\,FZ* 3l)v;).<}6'gv2dzN@Du@G3uE$BȭQO"(8ߏ$N=}лJWԻ7NY/IL`;Ӑ]9ApYC4 EG6P~Ysك{w ͪ =YQ=msa!]⃛'+$N X>tߥ8T6ʪq@X^o[L)色5 NaBir4Rx`&cX>17Pj%ɯab`Y/^9|CTs׮bb:`_(مLhol$}H@;WGFcN ZTL99h+p&. ! FȻ!j-c44_ߩmPͧ>EHU%/ t{=Sy-YjK||~vbWʼ;ʆ&۠e{5 O+҃Ðf|9qek'ʖ˼]Y𔮬HU61) HK_ |P9KY((J[p8MWn5<LRD,%S _&ucAё4 =yT+%QZS?)<uhv~R'B2#lY:D12o'2=NDؐI\;/Q+:Z!FcRZS)i dazֆ4dȇ?.\uShg℄/y &V6?q'T#Pv_xF2 /rNDk9yfe_uWXT*QWP9&hyVύZJb(g%d)CSFC74%?y9|G]HT-nҿ#{L! Siw#e;%at.艨F?x\8%w=l{!*م{[}`Vϴ4|k{7ωdcS%S{=g$e><_frV%Atʊ`bLٓ9f5U Q0fJ =n{*_x8ᦥaW{ڀ%JJyٲ[\zvS5gzxOVpڽyt-I m&驈0{K|F]A0WpҾ}lk2ѭT8S.1{.6=ϤMaU_տjM;Eh7@񑧟_KP{a 1z#R35h}KfN ['[[6/tzmNxJ7^ ULIt qɼ;M%*\Msa쬔QP|go1Yݸ헩hFU= jX_W)\ Rr;. [Aף*^T]Q˿.\;WN}}7ⶤUk3Q/]{11lM'jC%mRQS0~[{xm[_թJ?aVK?vI#D8h7m=YwRpvixŃL8tEǗPlG{Rf{hЕ'@aB;WU9{Z?=ʣ0;jˀQqγxo;>ЃVZ6Q̵$ ߪIbc_vKݯn}(|&B5ΤrrD3:g',!nTjJNJީˆ93U:%mWʙ2>M^d'/6]H{.C9C!e8k2*OVYʥ_uܭ6xfؐ4:=7oo.Zns| =+>RO;#m[S@ zdpKy*@}lB, Bqt%K9ڥJmHwێ)t#sOov^gʛc;!Tiny,o@;8(ThR/|̆z婕ԯWy> endobj 29 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /VUWVCI+CMR10 /ItalicAngle 0 /StemV 69 /XHeight 431 /FontBBox [-251 -250 1009 969] /Flags 4 /CharSet (/parenleft/parenright/plus/zero/one/two/three/four/five/six/seven/eight/nine/colon/equal/bracketleft/bracketright) /FontFile 30 0 R >> endobj 114 0 obj [389 389 0 778 0 0 0 0 500 500 500 500 500 500 500 500 500 500 278 0 0 778 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 0 278 ] endobj 113 0 obj << /Type /Encoding /Differences [ 0 /.notdef 40/parenleft/parenright 42/.notdef 43/plus 44/.notdef 48/zero/one/two/three/four/five/six/seven/eight/nine/colon 59/.notdef 61/equal 62/.notdef 91/bracketleft 92/.notdef 93/bracketright 94/.notdef] >> endobj 27 0 obj << /Length1 847 /Length2 2792 /Length3 532 /Length 3395 /Filter /FlateDecode >> stream xy}=:;9SJZAOv $B蚛 p.R d 55$`()p "@@!S2?D(@R8, 0RA"Xqh{yg~dg@!'਀ F A`?L\WוHa)0L$B`dF7ߋzyY`??X"+$d/d N{Wɭ4Gg-5G ._[8пj|# /1qȮ3 ΍%w,sCym[x 69™mdI<1 k69sKۤ;.x]7:3벯n^pSaSG4'BIx' N}*9m鬹,~<2rx37)\:WfN>q.ڱS+Wj~o9rA_;. $q(F<'MY&( 1&$zeEBNf3u!~߮)#zNP{x.ބ4J蒟0&x\yȺLmlʺGڿmis9BhrpFZ>S|_4wh9g fAYj:)yk%Ln,s{㴦Gb$L"-{<䝥oWZ ^Xx VyI7upĮT̋O5MΊNKxE+wLHƑ#OZw ѩ 96'nrxh\"d1>[ 4S6hYTRNeyjdgXM4=Sṇ̌ZvGO]5zɤ9ͭM/0%M%?z,VzZcx^mnd茎'9;VmGܧ]]2<@?mhag]+sGhLSO]SRMsE>ˎk,VR`BN\}hS֥YlE-dbϙR4Mg#^M{^Ȥ:g/p[>@^d8'1DkٯI^WP@'U󌄯C%7BwŢPyѫ;Zu5,߹m̻chL40 yoX[]\S[eX6c:r<ڮ~u.txxtj,bd,({Y(7l|'xZ n#=-ٲQi6zT]6O\- %x֘`W~I0E/jQ*lEnlGE[ڍˉ穗(N;~]{mdU|d "eBŐtڃU=\&B2,&"" _B.‚ݍ ' 31Upۗ [Mw>aMi1J&taIO84G?3¤LVnjezBқz,oV,x_|BKvids^ Y'2] (tRiXMhMի7f&܅jhV\}+?l *V2]X?862bێ7{n+<р2w166w1L2=š6ɣ4>ú vʗ󿛝M/sKWCCA^7,(0{l;YkEZFx:R\fzIz١j ctU_;Ҧ}PsU⾯g9gNwtAykJeWk>l 9P:*r\C`;94xJK|UblxtTˮ\۔HSW9^-g+$rumOO4.\~-R4"4weӢ|Ȱ5ʟϯUٷݙ 7婷p0{ |K-XVQ-5 } g xo`JeJpQT`B)HkWqo8/KX'_!endstream endobj 28 0 obj << /Type /Font /Subtype /Type1 /Encoding 115 0 R /FirstChar 65 /LastChar 85 /Widths 116 0 R /BaseFont /XDVCDF+CMMIB10 /FontDescriptor 26 0 R >> endobj 26 0 obj << /Ascent 694 /CapHeight 686 /Descent -194 /FontName /XDVCDF+CMMIB10 /ItalicAngle -14.04 /StemV 113 /XHeight 444 /FontBBox [-15 -250 1216 750] /Flags 4 /CharSet (/A/B/C/K/L/M/Q/U) /FontFile 27 0 R >> endobj 116 0 obj [869 866 817 0 0 0 0 0 0 0 971 756 1142 0 0 0 869 0 0 0 800 ] endobj 115 0 obj << /Type /Encoding /Differences [ 0 /.notdef 65/A/B/C 68/.notdef 75/K/L/M 78/.notdef 81/Q 82/.notdef 85/U 86/.notdef] >> endobj 24 0 obj << /Length1 990 /Length2 3455 /Length3 532 /Length 4145 /Filter /FlateDecode >> stream xSy A0&h ٲ/Y*i!(!q$4!eIw~{]uWIiFy"Pk3QRF$0@00Cht J-0Ng*?Dz|TK`n |H # GF@zHBHaޠ dKz?C! =k PiS$Ҩ0B`hn ɇN? oFJÂDR0Q[L1A@ k0P@br:a+;W3@ QNa 0wHtR(yG3+HH]@ KE:@ Q`(ràTp's!?`~ LxF EA kq(/6Hdmfr2`>ׅsAA$矜. 0έIQ?fnN BH epw'%q >Ka‰IQVW+Udn$3Ƕ>-hE)Hb|>zXH3G^\*__{߲s'!E@c=kִ4ҭ#7; Ҋ/߶UC}9}죅(!YA<`^BQz;'T lNgu^()!I5nL1qDcX@M?|ZPZT<˷乾>f4s'BaT#MBTgTt*/M1LlFM:(M8 _Q1/oFB>V)9X7=B>qJ?O?a]FXz5:RZy媥xe2gg=sU^64n.`,.k[c ?~ ͘oY[-`}3v|0wCW.2^&tI-Bo]WX~emgמ9DHMǜ[vImY5őMKfE Z.zYMCxwC$a Jw5idRԉՈd:~Y7pe"G/ҖK9A s ³6VEꟹSy#]oIMeGo+3[}5uD:Eɮ<5%bC)RB(1Ԝ–Ċ.IQ;Ӓ0 W]`QCu (*^>Ym_&6zMޔ8~[ K~n㳼$}SHk:``yXV_ŪیV/Z-+tixT(ȋK[+h׶=yRt[*̥t`<5\-|&y+z._Ÿ"ީ7I>}SXǩ="QX1p`~\b@1[>ipGdlv.yb$_AM㠏t %w],ݹh\PBۇ峒͓#njTof]J `ֺ[yINԘiv5ndVtTF Cţ#+x*˿ZCd X_p4r1l.,)1ҕo;_9mvأkV>?-`R ec -m=Y5Sd{y>U3B x{>..*F_1,`—Ƭ[Jkde{gYЉyr-5U_eb /?e>7,P'.}6sIrwf_G >+F9&+[{r{\mR HVא\6{2mlQGŇbaBԃ|2M/yaP(\+!T3sv{CrzEJr)k7LD`k֮'ƎcSl su3aSնOݪL6K8&e-M7k i4UL^/: )vï(Tz҇*-E+<5&)ͻo3 䯎v!Z:,↢8RQuj(aӱF^م)%a[7,]O] 79"};/7{EWy7!,ثsFy߽ .9w*y2RiÌڷi.j )aqb(󳿣YF1u[M!;.]݉ʴĶ6 +$8rV [W#b}TqE`vن|RyDMd98}k`.(+&긅K`@GFEɲ^M-:ktB+>=`o/Ac[%w*li+xWgtasgFCMc[6VlYh ȵO& ++ѵ+odע\"qїTa  w&-myYޠ6^"?7Oi)[MR:Jz&sHT8{ 87Gfum ݆}M= !\s7Hױqk娽Єɺ‚pf]i펴2 ˁIeFjvG-, \M?|}1d1Q5k.dq"FCɨʍPfek8w$C&g='*2\_81z 2?kVvDn3s}sN5@7e/(3'&rːrNXI0`on W{{ RK> endobj 23 0 obj << /Ascent 694 /CapHeight 683 /Descent -194 /FontName /GUOEKS+CMMI10 /ItalicAngle -14.04 /StemV 72 /XHeight 431 /FontBBox [-32 -250 1048 750] /Flags 4 /CharSet (/gamma/lambda/sigma/tau/omega/epsilon/period/comma/less/greater/L/U/m/n/t) /FontFile 24 0 R >> endobj 118 0 obj [518 0 0 0 0 0 0 0 583 0 0 0 0 0 571 437 0 0 0 0 622 466 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 278 278 778 0 778 0 0 0 0 0 0 0 0 0 0 0 0 0 681 0 0 0 0 0 0 0 0 683 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 878 600 0 0 0 0 0 361 ] endobj 117 0 obj << /Type /Encoding /Differences [ 0 /.notdef 13/gamma 14/.notdef 21/lambda 22/.notdef 27/sigma/tau 29/.notdef 33/omega/epsilon 35/.notdef 58/period/comma/less 61/.notdef 62/greater 63/.notdef 76/L 77/.notdef 85/U 86/.notdef 109/m/n 111/.notdef 116/t 117/.notdef] >> endobj 119 0 obj << /Type /Encoding /Differences [ 0 /.notdef 1/dotaccent/fi/fl/fraction/hungarumlaut/Lslash/lslash/ogonek/ring 10/.notdef 11/breve/minus 13/.notdef 14/Zcaron/zcaron/caron/dotlessi/dotlessj/ff/ffi/ffl/notequal/infinity/lessequal/greaterequal/partialdiff/summation/product/pi/grave/quotesingle/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde 127/.notdef 128/Euro/integral/quotesinglbase/florin/quotedblbase/ellipsis/dagger/daggerdbl/circumflex/perthousand/Scaron/guilsinglleft/OE/Omega/radical/approxequal 144/.notdef 147/quotedblleft/quotedblright/bullet/endash/emdash/tilde/trademark/scaron/guilsinglright/oe/Delta/lozenge/Ydieresis 160/.notdef 161/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis] >> endobj 17 0 obj << /Length1 1612 /Length2 14870 /Length3 532 /Length 15733 /Filter /FlateDecode >> stream xePM%kXƭqiơqwwwwwwwwg93s~ݸ;bGMF<9 E |mR*/-DYdxd6/f+-oq-rM{eW3aB\әb8zn~M|YeSAҍ9;8VXGH7\,dH(,cz+J{0k횶<5sJH븞=Xw-;.;J[~T4Tɽ"̥OSbyC]Z[cPG~3J9|@7W`hRdlٴ:')nI~A}$S jl2k!ͼ~VۆGMH#i~|QA/(lt{#YO$>V:#VȐȢfm)#?BÝ-_TM/@28Ԟ~Km|R"Xz5ET7=5@=~\n அiHtͥ$ݞ6~b%\,'F4{FnfbflYlD/;a}S3V ͚l/=h35~kTzIj€_[zg)VQlA2Qn-5ިC5Ui`^$Մ+B4H,y:J|B# {bSNVGl/KZwDigxubZ u͛1o&YmU{ʐ(?;Q!9mboOKlM] Z`z,^/Sl-MuC?zCSm_+9mJxс:&lT5n+ Mdʪ~o-0?w/\}B]N}(Eɮ ZpM -}>fc6yS~!O"`j{\6$t[&!@.=طь9Mv&ԋJ8%9fz~ tăqO4˔FZgLxmA3yHo±[ǹK(#/P\9_L~['oG$#I"{p 3"c6}]3%('(.yט(^K̽ް7t$[ UVh5{LCt--|?gk;$`8?-,D+cfduQ^f~i7uU66/o^$܈d%}prIFPS!`(m'@beo/;{Z9Hpof8ϳG)m0Va{{_RY ҋ54(C/(CIϾ 䛫l#IWN^沸RHU(!{g$VGhD uS0a8M}Y^dڶA;M{n VUA%JV;׀U>{9Uw-tmYfzsc u theayOk'<hk$‰h١ c,(1h0sυY=aqcVrϯf"| " sXV!EB/AYO|7`~W~}w†1bsM! FU@ ::с.x2qԇG8pG .F&qjH8s?0'r/'ǝWf2#fPC(h#PLͺ/ȯ|8g4֜xpVƌ&K'29WGs+o9DJR_|ƁQzo|V_W|Wp(ⅇhnN*;g#ޘ0PW5ZL6\C\JGZ,9D~BD8!RLNd׸ 96z`H6Ai#sʚ|c-#%z"{Is?3%(ah T/kd qY]]!ݥ#(N7RZwQLx;x.\i O>`XnStvF=KN!#*TZx}[ ~f0,G'`7JI"0F:3*C3T{[?oCtUxX!6 $NC\Gz>)z4.1kC噯ݝf9X8ﱡ6+=L0 ' 79by+{s4+$l ߨܫrrh_H qz.NSsD4c&»'!|MRH-=/3 «X"I  G""ʼko\3E)j}԰ӤY]ȫ8B!AG%K.4_۟wc̮ɬG/e z/x} lT:c|IeCP07˙yOF67w^S~p$>0('2`.J(CVҲ0nS.69\/gǭirSB{bX- 2XFh S!JڇV}oW-Ef"`A 1}Iu6\EnG >4T@&N )?;16P^JSzFz̗@X mM@qЪR={9BZav4fPY9VCjbl"CXA:1 rbΟG|4oLNc=ѓ=N βFꀲr4A| Hx3Zv0bkẩb"Zg[R5n6]whg)}qpWpOXtqv˄V]CoȖJ#%8;n8ن (96[7 ~Pf^))0# >:}1SLBYEk$8&iwJu7if6 j;xꑲ۬k09rH'd[ބH:ΊqާnbGy*qd<ZU@῎©lג0xP]8ȄjsdD*A ?5(?BfD[ҽ d,t&Pr\B~A;6vU7Ǥb6[ ^`y*y%u1: pYi 1pln 㔘zV_te>ͦ+4VʒX*8ZSo?1uhdAev9@O54PKOc3ESnfngC ;A^bu*(kQ::[j^2Czv#Cd\ i \Z6VUzZw>5tX`ϟbzB?zfP6V: j6 )d\w)UӲ]p}lSmGUxMG5u;LFH}y'!,ts'kp5)»2kX_c (u%N1՛P4Qc= #jl LKI0Y8SM:YuJ~Pa?+ziFds"t c0{C.,"?\ Kw`zm ]B̬q*c>cx8DžLGK`=$U[$P_S-fjؑwc4J+!J_nOj )s莁w HA&=e IS'"6j2tkb= > dzU=YLs/N[A7r<*7;O@zTm빮|w*]c?H%UeQ0QģXJ@=SX8!Wo>|&' H~itz|=}6V\Vj"kW5(酞+^t A7%dS+:ڽ#{?cӪϒo^*ϊ%f.² KoFZh'?x TV~* jlZLŷuN- dQd<޷smKV$WE'ū)We`OU)t-9Hw҄^w:騅  E#F`&>ۧK/=T)=ӁRS|6U[xOdotDQj tz>rl.N+mZ W MEzvbeeV2(X8E8?yӻ? {+)>ќcИ\{iӻecy@K2oڝwJ _ \Oc4QHPm6UIލzJ=|Z"F׎4J2LeHy>nB)6ujI6I'owx QQyBއiԋh1݅R̴c*rx< g$BǬn ܫthZ}SOvXL(ьahH&ϾpHɮP9C?DXsZ&bkg!Vdz;Z@@+`6'8(u+wlEzzՇ|y˞bT]&:۳ m =?z8nAiLg޻ayc{ƝIeQ HjS4#m>}\{iCX2ibt멸0ݱW`ܱ)Z{ @CLH z.Yg&k|pV/X HOH8~آg(#Tx9 ]Ru97ˆ&>+lL=5Dm/{PG<j1QVӷ;  !"yjx]l3̅/Js[z"IhQ5R'"JHbf?Z8ÊZF{}G9Ѓ&D ;Ԍ2T h.KCC-sҩvంX s,蚞9RO_=THLuUQQS~ZuեWeNrd5]ҭB|s-Rǥ\myiu\+@e{g/SW: Ga/}Il-Cb N&Z@LBcr JӆoqcAb(֞ѐRG責W?ͶbȰ6&ʘd\|CUnrHV4b, 2ZKkpج5',MFW4rKdd$r\U,::Gq< G͎uh*No{9=))i]!)ח_D8d/$0- EPRb n'Xc*ctugDBSKAaQsʹ2R{ťDt&|iۛnXO7UIUؔ40Hp Gv:W a+ dcqDs}f#:* N_ȸEtSy4B%;CGIN͐ |,Q6.*Wgp<0JH1[ADVM;1#B`5̝Q-7yϯqhRYUYә)oȕ&{pႜX~d8֔R` { =g5iF~\¡cnw8Da*bl\/uzU[NP߂wP4-`Y <*ZNKI@$ h(AGspoUVƏbzmCMeϷkxvLtB֬jlfnB FID^ ,eѯfXLB3dxL9 H8cN!BԄ&37bizHZ͚2:f :qލ;yDѽ֒VNi_*gcy_TI(GLGѥKz7z]q_ICc*c[l~s`p!x2?NRB>k@{*hhdgֳ|؟@n180+A{ G*/k$/IV2:>_i뺢f.(pǀSrY]\VӟA}sMawsmO\k|`S !}aIpokPhfFhuZ2"z;嫰 B=FAt< 1 X+>P}nZ%c9!Ai8 ȏ):>((t]"EtB/ ,vD\ݯ5̓'h>^ fŜ l8 ?qDĎ3IZF6w .;E*P?3J ZɬW[#-zZ| )PccUڮ? ˍf vL|1J7~Cl;~Q`FTLMF&.Gl߈:T0(ҍ;)) jG#P2WWzhqA";*9@UQ|5;0 )d $W"bWA c=._G аgq%7P×iּk3v|VL򺒭OCxp)X_,ώ 5CN7ps'q&Fl B->W _.Ф̞PO@?eЛoQ9](֧Rt דߵTsygJtϜ}`@Ё0nack>|8ހVd pnEAZSwRjמyTܑHg߰1'wώ*1v=w {icp`yK`jgDɺ"N&^&\}= svHZFZ^7wo^LGܤo6s`&7v~)qXo݀EuZ1d<ĽBQtѠC%XN@RT XmCf߼37Pi-bgO}W,wzڢbcp+TQfd1_aJrB\_;w&`2Y* 55=ZJVuL+ޤp[}4-g]1CukʡiyU]MÓS0;5%Z;V=T­KA3Oa EWŝ ޣYb,LN_ds-J|] Mwq q&9zK}STBu}rcaBh rp =pwl}GɔhxS,4+P %N8,'Uq9_Ӡjջ$BB}mh+ =HsP?e Q2h9!YЃ6n/E6{/#5[(\}S*3]oǁAeqy:2n*as&%S|F_8Ôm?8_;ۨ-75F+[uKvٵ`؜PcHq/l90>aQn1>pdl5;WUil mmm|v#X+za(2uD1GzJ+[No;*ꦄG>JSkn?30?B&T-khj;lJ?=ͬ:#3emgE ԱFo:9ʊrM[L엸)?ZF.nѨꌁͩN3DLmn%ĻBi9/%.\08+d麜X5eX<}j0I#zׅdHGC}ºd:')co9pwmTHBhB}șF^Ŝ^Tnt Nh$@`!tȃ&+H$ƴz U,#췤UgutqkV|4Mx7ь߬0<-*xՑj涖S%$.U<=$б ReP(ӉV>2xkj…jcXXƽiۡE g s^cHXw*77DbT\UR ԝWzuf p]I6 t{`To1+FB| :Aya,4hXvRg֨Φ9Ⳬ&@4g??~WuU! .sˌvPl /+'bgFM5?@rQ)k6E@*X-ďG?g-uud{Wudls'f4+ּ= m~tFF5EN托HV'-.Bd/A^1s`|oG$Y@y$3Ӵ B|Z\ Tb=/xg]"& _¢*'@Ќ@d/aG,3S̯:'^Hvdz%!%w=ܒ6s3O )|\Z:ɵGdo[qE{e'mhq 5ф9yūR^[o6gW<5ID S!hϦB1"'&&L҅h^S?%ďEgm%-C4(~nZ'BUyi0ZB9 KF~B>=?h(-0[02Idʸ; 1+`/مs}%|$0ƾMz%m*G6m;-nP{$'xc9͸v˅קU0` Hd'LfA% %  .fa\u&ۏac5V]ˬRgf6ktۄK7b4Pn4.ѣ,v. )p`N^;K&sgIyQ zW΅^b9ΠgW}&\n+&ψIz6tqZa ?ϖ\<#Z ۭ7 Կ/g+}{ r1"SOn<AjpLv=@u`A*(V jEw~;|gƆ1zhZP獚i_VS>| fH Bۡ9+:(,0d5V4`"\`5f!9mgAo2;փ$$r&)A`>EXY m~ &}bU-I~\S_}6|k47ى7fwDgmΕO nL@mx#6p8) T+VG1o̅w#wd2%vY%Q"Ns ]kiHUMi,c/}␓[ڰ3<4OsQ&")˞ JoCB*KM_:F*W&-7BDKdRa7+o(ގ6IXo̅7I~pH~qVgp]2:v7y~U'ʬ']37Isd| ;7I⵩A5!-U~ gwP]@&"2Zi{nk{%(xd$GD,ߐw&m^d) B~\|Yxafp_L(Rg5/̋Q}Vk drvLxOKh;ap;+{Ժ $}yjj8ۙQ,QUPc}ͼ9EkO@גPc[1~cq eEQ\!,uRL4֞-C*2ןX z䃾qNJ)86Y'gǽM^KD <@ܯ b[{pbI1+${FXiq`-8= P CjtMlIBtQ E8ɰ*= 1͵ ]cƗ5LrN%8+]AO.KְpD];wiF3Sv6!gŽV$ lR ;#~_NDd>PM|ȌmPJ3O;zZAO4!iA瑦a@ZjV+“Pc6^ %:n+79oŒvN{6/FsT(TT.qzk䇇A.}f˩d&`e~ڹ\^hw#m)ݏXċ+^D } / '')en-[/K xՅ3U>2^'3sѾ dO T5izW"G|("7˄OzMa^_}a'x-G~Yys yXD .iya~e04bWZZN;4St.vQJtoAB[%Ee}5cgoMmH冘G؂tʞ5VԤuF׈ۣ/~0Bh䂍KU]2QT p6wELkx<^ɮW|#Ig:`븨vc&?ry8a M$PhjHQf;ޅc^d+]Ώmb8;$ m%, ajjS^s6I@Xam9Oܮ7TJ?+fqdF u;hC6~:#BbŵU_KmyTDE^bkkGz\ H';~`%E+J?LTDo2Y_w#%W7nݴ;en^>~HruJfNuDcVxLUI&"EI滫9/&|i/o p:ER1^TD梿` )WF#,juOr[6k'jO4G%#Ю\". mAbR5ϕ'CgGl`D8L$ ݱR%x%ţ#K W"'U?a֣0a*g⥙:)rjuxdK'n}{ =rr(27G }qE(&;3̍l}@Jqܳ+R իk35OXT\:nB]x'x6Ж6ݰxC?`l :8իendstream endobj 18 0 obj << /Type /Font /Subtype /Type1 /Encoding 119 0 R /FirstChar 35 /LastChar 122 /Widths 120 0 R /BaseFont /FRHPLK+NimbusMonL-Regu /FontDescriptor 16 0 R >> endobj 16 0 obj << /Ascent 625 /CapHeight 557 /Descent -147 /FontName /FRHPLK+NimbusMonL-Regu /ItalicAngle 0 /StemV 41 /XHeight 426 /FontBBox [-12 -237 650 811] /Flags 4 /CharSet (/numbersign/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/colon/semicolon/less/equal/greater/A/B/D/I/K/L/M/N/P/Q/S/T/U/bracketleft/backslash/bracketright/underscore/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 17 0 R >> endobj 120 0 obj [600 0 0 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 0 0 0 600 600 600 600 600 0 0 600 600 0 600 0 0 0 0 600 0 600 600 600 600 0 600 600 0 600 600 600 0 0 0 0 0 600 600 600 0 600 0 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 600 ] endobj 14 0 obj << /Length1 1647 /Length2 10982 /Length3 532 /Length 11856 /Filter /FlateDecode >> stream xveT]ݒ-n .9;8kA{x|^7cךU֬UcS3Z8L,|%#Mljx8()]`)Z$66+///%@de hi3s/׿# +;~vT`k d+*Ih4@{*nfv s X:;:X*͕K` pu݀@ \Lgv,J}\-߱w2GW x"!<֦ba廥_%Ӽ`S+  :ٙz~'sr+0\V.v@WwwNuSNNv^{;m9@;K&$VV $E} 7܁._=ChĬ~ SNG'j.>+{c} ;S_dڃ+#W!Dbdd6U Pͭv|}wbaLdnZûnW#-G_LۿU޻[$mEGXE%& ad0q_7?׊`'@?WB#`hWM,[?6\\{W/ 4Ghb;4! =TڨQTP[iR4pgOnǎ; xOGN[NMlTqs> Ţ=fTG4p~O@^EqKC5/p;QKD34hK^//謻_zn].t(i]J5d Qr"]:9{F2PjB!Q (f0[zMڽK_Sek?Ganfb$B)j̤鱭Cmp%tC `P%`L; o)[`l&f;D?;y&h07X1ÀzX4HF {lWr|:a.H’Nz[@FbI'%BUލ E&wn+yӐZećSb3ըBh?bD42JXI`M_~1k$9AFPoY>;Y3r73ٵc>iBF~H/Pb~%! B#<Qþ+ZڼS3]WR_ ӛga{Ջ&PU9pBsBhoO=ZY!(Y2(fuɼn)}6Km 0ZO lUP'l<},\ 4w0f[Z-my?5YH,W\3Ցu(–83hG+hYM'cvxSHL*Ȣ2|Ʌ9RJR>V20;=xM[!Ơ閮fxNFZpئM0w%K2 XsuoF)f.8 ,C!F"5: 3%cDcx%C:y$T*SNïƫqn4XNE"% HqKU/}^?=eu?.2 YwdFXaXWoCd,KA!΃7k_ f4o%໥KY0qʆ'e3I*q(h Ji$H&y:*܃],Z@H\{#ÙJ8Hnulwdv#S@(^_9éY,;h!K˹T>7~S M;]F~KьlEZ(~G|]_cYIU;8u$1*ʲ̚ Ŗa d/H=MgzhӢ ;GRTEk;Ue. kگI:xݏ"La|**ا"Ƒk=T/hZFdB%8Gi"e٪ w4/ ''] X pRy1-̌0ɟDz[9<Nqd'1WOʳ)Qh\ILi-{^I!3@Bh|3_a JoUlFĘÚI>É7@-rQTZ FJٟM>y]k4Ic.V~] 7;24s%bkXP:HJڦ,X$;V8GE&3.Q즳lj+*џY샇dz!vc)% %\%MxRS΃?6jPNMKzDeEcjQ/QQזKYW O" Bi#v KvRafχ˃0{OHthFڌW*_(X89"/zNo%Q ; lI bvtKF9e '!!!c:*t!z!?V87e1#$;ƤLCHQ5=MH+Nz<>ZoDE\mwN-5&UFc9 sG'c.a"џbM<ݳ42XH(i-7 hf?,1w"ץ,)vX\^ 4{O=$L<2&R.F]xp ƂzVCcs\&ږ_8v/H8zKrkMDԾ@oI2!?M~hhP܌U4!3"?[ Vfj 1'hĕz5kU_4ȱ<]li7OY ;EYUַ,2tD#>7kdXn }K|*3(\c[B QUhlN զ}u8<hihn+ciڊSp89c ^A;{`u/7_ _>ݹ*#hT?~OL%%fxZs,P]ME %Zg#xԧ`:m/Z)Kя:|jy"I:q6 Vl̇a%;^fc_ĝ^e*DLBcY1),5_CS!\)*K^@iS(lZ:9T xYu0࠮*ӥ>%+?#t5ީٺ_dd7lEI5L67:e4NPBAzĊ0|Ͳ3==v?jRnb`5@RPgvԺڪl@ ftܞG2ʍ,ng|儜xa*0j>{qV!~&B@L9C 6tOQeT--F vG fÞ75+^ΘPv,HjIlO;SF:ՎL·0Yu4t{c?w[LݵKTS11js3+<)1Dl#"ws̝K>.i-;KR"V`oPqu&H1~#1o)%D@PqGbnp$U$bŭqVcyTJwMZ-gPyD4є`?Ph`V=ю 1 ]댊pюapPWo 7V/Zo)l*-yfX׳Ѳ0l3N(X0-lg>8=cG"n1`wMs;Gp~<=M?j4L'c8Nߎ §0Qac+d5}-FJ޹tdWXHy6Z-y}e"1oQ.ghcuz qW3Ox*b8HW]߄OR1b ä*â,?]>Zi([%s}4@۔T?!6t}ӔKb T^ 8}s-g7E"7T1abU%*β@> ߟ i rvEobe^2#41}}}+\qӪ{2>j[E߯F*OГQ4FC*ݔaIi}­;pH3 U43Ec=㬴[igqtb_?JRϭQYM$'$2=Ik藷LRCyvu"0'é佞(\(>k)=ݑJ~DnQBh'!Ë"~:VlU?X`]/:1nbud(8=9:ٽuFngTGڗ@a:$i B 9ZP5A9s7<)=(! t1Kϒ۵=#=қْ@>xk{5սNwUVC> -bGwlQoey.̽_~ϷgD*>`bqyvTzg Ajɱ? 1窟EiV?O%y'J˺5QRPuOJo]8(CIHڦ8> uO޾vކ`+DqZPOr$LJ+{†Sz[nx@PPKqLZe,ey3H~s\&%`?p8GUS+aQfhӜ넁wlCY޲DZwr>V~~ul$s8$G !s[(J^'k`ڑ+U yM2&DPqo7F2~y Uxj#x?hhZX #8ts;勤bϾzu oIJЊ#*wG苃C(p?uGj>ߩggC0^EdgjA &YY⪡$Z7ed$ ҕ-͆IjnGQJ$f89'7xbV1-evEfS28kLgс24rn̍OR6}UM@8"jjb;L-1pz֠u/mŊ2Ytɾ|87Y݅eqBt4ӮI:fMIQ[%A|u Jpn$l|ˊ&՟⤋od?i[~|u/9jx OoH'нVROrtO'eTa̰Dh͆GRi{m*WkUHz6:DZIXL45zQ}"X~ռC[GCG͗51"g>PlܐǟsG58ݻ9:PiT)vJ/u Be?I֎>!氁hp oqAR%kt`i5%4 h U6c$1JW}?+C?UWXKJG74MlKVZQԞWq9Mz1_*ZfʴH eQ_~(8 L&NEcKƙXϻbbEf 2>h% r^e'MNEQk* nnj*+|#/yX|)+eƷ榫eȜ$&-x CjчFXtFlrdfV19]8&.R _ k {Ñl\^ U2oVzA3l4XO$I4ZQ"_ЏXc?bK^0bRz[G5z~t$ G/OA\N_DRvTt|Vn2IEgZscCN{HmufƓ4K_'~^n v 9=xB"3҆XKj$+ =wq. r+*릵Wה#X=AW:WbklYKYꪗׅ(y|Kae+4D1eGtW8\aHm9f"h;'%+(2 2>{V`[Sk~rD2q]8\1͊ޭ~ǖ̙6KE$Mv*3j!LlMd!S{ZyqܜtnZxT6's3z1h ޿y=; ;UŇ'9kȄ;@6#ʪX od_N`ά {TN?P*EH@@.*n&hbc삎mV$R[}4fvb xpkX6z5UxQbf6HpKZty6 s8^y1+0{Q[pĔ{) ī %k%HEV"&n"jes MDSm'[Nx:1)FW3ƺ6bEJ;gF>zrW>+r5JP˒~%g2,FTP&HA)'SL2z=*5 kܬF?(RVxn*Z/ C4W (V0 ~b ?&OW rUi{S ?SA=dxVS1ibnnbjoI/5GWZ>plI9ȼ* ff`ftKk 9`I]]X֕djxsHȺY?7dld$Dž[3gYB  OHt"ߏ:Ub%R7*j{1k4_1 B pI*I% nF;dp>b @U뚹1|9qV2DVZ8l<΄(R&^y`r[9ETr,FMY*oNuId8B-Z燫 $­p0ҏ9-TCAr#,,LQ]Fa8898nH! : c 6Y>|ٶGyj0'#)b*( B"lk1YQԪdR<X<"S\P(˨!]i$&<`ez[„ {ehXGpY(|ּ)%s:WD'MP#@rUme9sQW`ި| <̎4>7̢] y}!?$3(0wFؠԎimcAѱ^h~_)c15!1Mf cJEe'Ǣx ,PCF-o3)1gYY4Q˩|\ Wة+o2,g"WV.on~Wk; abV,J"d4rE'4m+Wol"ִoL ~ qVJZ CbCV94_Cg e# TWvKT{s+$ij^ڏŸGrXFzaLqlvQ]e޸WKʧ #ͷ5f\g,VTnDGHî ߖw[ͩFͰXí`!ŀFaYV"]NGC#VRdjHJOG#H]"ٷL.ޚ0nlʭkkӏEW8p/YWj1zf*Z$LݢC c|6)5fk2B`^8,&yBf$nd$Hc4. (L?,l,$W;DsY#fkz̧ #}y8"ء2|7co?v@S-endstream endobj 15 0 obj << /Type /Font /Subtype /Type1 /Encoding 119 0 R /FirstChar 2 /LastChar 122 /Widths 121 0 R /BaseFont /XGHVTZ+NimbusRomNo9L-ReguItal /FontDescriptor 13 0 R >> endobj 13 0 obj << /Ascent 669 /CapHeight 669 /Descent -193 /FontName /XGHVTZ+NimbusRomNo9L-ReguItal /ItalicAngle -15.5 /StemV 78 /XHeight 441 /FontBBox [-169 -270 1010 924] /Flags 4 /CharSet (/fi/parenleft/parenright/hyphen/zero/one/H/N/Q/V/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 14 0 R >> endobj 121 0 obj [500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 333 333 0 0 0 333 0 0 500 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 722 0 0 0 0 0 667 0 0 722 0 0 0 0 611 0 0 0 0 0 0 0 0 0 0 500 500 444 500 444 278 500 500 278 278 444 278 722 500 500 500 500 389 389 278 500 444 667 444 444 389 ] endobj 11 0 obj << /Length1 829 /Length2 1037 /Length3 532 /Length 1636 /Filter /FlateDecode >> stream xRkTFTk-[DDh@̄-*h0Pk 2 $@lA(g(R/P^ Q W{UPA0T+juWWsnr `MT@"E*Dx|~ 1 ~EA.HĈD@Zc`, 'IA2 cHd B@ rDB-d!.( % ` IxlvkSbp;缈 %jsG}dNrv@Xs[ 3{\L.xkxAz}޿Ҧ{ݝv^{ϑv2e'ÕsOu_9t06$ǣC.nƋU%wtxp|Ol|l\sk{wrHNƋ:+I]=gv]qJ{sQ)uܖ^GsZ#v=Q|kVYOm|vK,<5{I_4[gcYC]g?Pf#jGw'l9]ZkR[;&0/o5&-5>8|cc7W|RE_i}2aP҆kE-0ve㼾^Tc 1<ʸxl3HlyYr]1-yIƂW6n4d42 >$=Fŕy_OPC9_VhZǿ8){hlDF3 r6`G1O,dQ}-] xF=NMYqk҂ CrmA`ЮwBn&V59T(T&EL[R5U[ؔ\󁢌) WdCs|q@km'NZZA(dO_n4i!j^\^mcuR⦍|KPks:'0j=ZLuqDlWsύyn筏}{{Ѵ2zm>ֺʰ:p4ҾzV͊sE;KsLvTEμGzfKIf-OU9UzKP\sNco<]=hDV7 QN~X_c飬EGĽ*7>RRyKT>W?E% 1}endstream endobj 12 0 obj << /Type /Font /Subtype /Type1 /Encoding 122 0 R /FirstChar 0 /LastChar 107 /Widths 123 0 R /BaseFont /HMETPY+CMSY10 /FontDescriptor 10 0 R >> endobj 10 0 obj << /Ascent 750 /CapHeight 683 /Descent -194 /FontName /HMETPY+CMSY10 /ItalicAngle -14.035 /StemV 85 /XHeight 431 /FontBBox [-29 -960 1116 775] /Flags 4 /CharSet (/minus/multiply/bullet/arrowleft/bardbl) /FontFile 11 0 R >> endobj 123 0 obj [778 0 778 0 0 0 0 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 500 ] endobj 122 0 obj << /Type /Encoding /Differences [ 0 /minus 1/.notdef 2/multiply 3/.notdef 15/bullet 16/.notdef 32/arrowleft 33/.notdef 107/bardbl 108/.notdef] >> endobj 8 0 obj << /Length1 1626 /Length2 14405 /Length3 532 /Length 15281 /Filter /FlateDecode >> stream xvePfے%E|KnZptq"ܹre; 3 -='@IF֎CFeg!!r41p6p6M3\EQ =daf p51uT218L-MBrbr1Y5@ madbdB0sXc054'/,'+/5`0s4uꁳ/_vS ;}}99;9Z; _,;ӯvF. l`ap6qw+ +4\,lɀhbfhlmWwY'?Uo`oow߻)- WN#f0t͊vc8 f⋄N+%Ne9$D:Т.ֲ6_;u4ோ 1?n56WWKl;dIX`j`կ*&&_R =-l.[%$Ԕ_CaJ3_0v/Vv 3"J_kgG wW Wo?W:#bkdg(9Mr8:~ ϼ겝WezVs)a>БFB^JڦΏvSIñ>tkT"BMN6@:23hEm0MVz)E7ܙN&GG "B4{_o]HM@(uEgIǏdC#ýTq$\`Q|*^P ۙjpTwRsGY+:[!|8dÃrU @fw7-e3I'adiDo%byLe,(`JBJҫ!LrT(b/Mk<<4.1}!9pT滄)T&(o4ݶ6i28dz(YJj'ajҮr|}]fJWy |AgcPs̝U[:Jsԥ zl]Zh=; ݷmt穖?r9w* @TB'4zOSbƽ n)8v )VNO49e9tś x}/DLC *#;Mb쌌\ ffGvl> jycPc `q>1B1tOgw97y\AQR9;pb{Fw@9 8 q(,4jjqVF 6[d|<y9BQ3mgBLi6kYZRR2$m?ucS4b G QA5<=qQԿc9m8i"5C&&Vzc xB$p`v9}'+&>hgkҕ$HMM4JbB̷1Aȱaa%eO2*4.h&޷0sVP?7.hq2]AabclK '<ލįw^[EҭV=BN)h#AjgCW0B_fȸGd1ejIlgBz}kɐ+Hi#RS(O & ( T|Y‰}:{Mʛ2w7/˙LyށRŞ;稂 zz9X6J/Xv8oO SmQ}cGbdUE4`!NݹHՔ,\0a% /_+XDWꠀ]L`I DdgФ.F'r͔7+d9X@6%J\>r%rl"?=,8Eʱ$Ʃ eGno |z0"gߒ2 T=pH `&v/S44h`IkOtuI@M4PP.\삈s#;D>9&aثq?w!h)l0ܛxc&6 !{ Q'vi`ʔjޯ n(#v-}Xcy= 0n:[n }%Zh"xH3`(ԏ50%@ Y4z;Lqj."0c%8#" Sscf  f؃L2T2 SWzKbewf2d8A3H% Q'f:n$G19bQe)3I~9 @g nl#򖋚SՁ}f/A?kyO{< 3NH/ }ݧ/:q y KNms4i*ьWJ` 5 Cߑ}![@ xF?5NhBw΄$ ʿ4EFM&㕈-xL\Ư;!éX]eYt r-[ ©Zz$0\0c#;g~wU()v Kg`щjՑ*Ml ^*FaH.Ƹ~ yK $ ,sb0x=6(Nu/Iz+C!PP@s&.Q'7бЂu:hڮmqs9HډPԼUJptXj2S6- #Cɮwǡ脑Ba\mfQ4pEO6Һ4$-g( 8Cµ5`bQ5jTRIdYc X-a{0 —{hmޯ0vȰ֬]Ė?z3osђݥ!d@f9~5cU Qr4Ԩ2[)4Y[2##TNu:_0/4S {ŭxI2lm Jhn!~Ev=lΔ-ӎ=8UWmb{_> 4!Xb\4I/bV c&Ś\sMaHr.UH݄wD }hZ̢I[tdqx7NK,lʔQc̸P(aL !*43:`P/$o&kW tܞ1:|.VqB(@ti";ҹkU|ݠ2|JKJ+&V1 &9cIť u2*w %75P%XM75 㣡M d̊E ` )`bPɥ4G۲xPORz|-Td772c6[ikƄgIP=^a_vsčL̳gq <7r>=m;!h`3/mr&ݰ*Jg+mF+Lg}bĚsD֡V>ŋ3%DC@g8 Qw4tiyA-I?8ED5cyXfpJu$ZT]yʅNտo gȳ()y*F\ J!H/.#b)u^ a\ )s3}1Jw~c" ?֖j%eFO@ ls}c.]5z VE}3$&_Wk\ {k`H-ɥ|MLL:VZ/nSU0 s뵼*˱i`唋VXr/;n\nsdRzT@kh4Co-=%7NKoQ@ ӬBUMThšq;Q Q^]j Lf"&ӈSc=3Bu/:7t}kXasMS (YF"^R5!Ч_~@[2`N*֣<Һ_ ;9&;e1k u(V&ߚX \KKTShI4ش'Q4[$r#> Y$>WNԢ N@81 w0Yh6ڐTU0=? Cc@߇.o24jNB<4֌ +c.9<<%a+OvF\1B !浉<f+j\,pS3E[R}_'-7|9HϿ>/W,[_L=5dن ˪T9KI^TmZלp |5 :j-GF"Q)~p3vg5N5ﴨ%zjWS5P"*:Y>.pSP_|.|.؉*$_Q(+^ácޑLsT@YT%f %V^8t ߱a Uf9p+e|0|*Ik.oEw[/.TьC0xkJ#CB,0I >>w)SFlҞ=[<FDtig{Ǣxo8AH׺XfT& 3sPj[F%P}ܐ[M( ,J& D̈A~ŰK&S *u.c;КvKnG^! TeCoC;^5/#0~r(!? X `Zdza^GA f Y-BL+`V"*\cvj_[6^"o3i:ۜHWY>GWB XIlZ@*2+m# I|9P}!V y|?[[$ys tDG5hoE3M<6:J]_6rڱ/ÏI'{uCok1՞hw&c~0Bv셆ȚhZT/9cWwdېN rl1W}ѵF|VC;UJRn{B05&9JB1ϸmlVȽlCNJ &\S^8dgUC&{ƞ^FKˁq1.2R8QtCPqų !pBdv^NEd^Tdۦ*R RaQFM*-hع㠰*?Y+NL^iSIWۮ_1C%lVZ IMqvK2A_ɅwVRd6K=P;^U N!LsKȋ9'Qm}^ QoܰBOT~^e 1;o6;>wONM|M&/+錕 @Y!S&ޖʪ'4qޫ$!.P-Tb \Mα^nX.Pt`cu||'5usa Ȱt b[| k_CO]&TGRW-ޛX,"i # 5Q%WAN)L9nE@ǔ v^%1gۯƈDީB#.ٞ^`]F;-ì{5Ꭺψ[eTQzBH$FYv'YQ/0J\I..]HNBaQmn,ε,Z"ɜ~ȶ^1Lx>5g5%R(pxw܇b}ϑx`4^k볦8XXyG[׉΂fڶoI9공ܮ> [VӘ썒gZ: W5_BBdYHu &D/"T]>.q>xҼsxeIVٕrR7@X-w]CQ-;0㾼tdAHdP _(b"_T^Լ- "BO=ryО\)]-YÔ>Iqzx.|G9Af1]y(\JT !N`!`R2K[SQcwp0y{J!6&bmd?7*gD VO4{$Vru/ r w99xZ<^ND{odPˎ ^e;+11z>vsc6ЃλrGuxB%!]8˒ Ed_Af. ~KZDuO\}nh> (l[=Wڅ0↿Ǽ:yML`JrJ#Ť[IKYr U=UDU˕@A`4)XV[[ l^?d kjAb2FJx- F#\/JmMwkʂCƽ,@n2}hJ-aS,?~oxB}B@!ߪu`_Xkr3ťKxl^ߞ")Traɠ ~p'Zp_1Q )fq?8 *.s.q>)6&ۼOܓi㧣1=YMH gFhF\憤 uIFOaAqZLp6D -2YFDzܪW-@2xSLa|VTanK\z3pk+' u0qvLK63ֆZb7K •`@>i'{?sÝv+.uX>nPso(<1]ݺ;nhc/EuGơ!ہ>X4~訂eRcB8#u w4ŀυs>v9`P/rKkkJ0` ptw\Spg@O'9mozy8eezW(0\ě}^e݌Yd(C<4MlucAe Ync|AKyog:_ 67d!{Q]=;vT}Vx𔿂~7xbʓ>J ͞ ?snTy6?XJb*|k 8juSF%b0%֟ Cȕ|.糴xjT24K%1C%9WMFL~z 0Jq_B g"I# s0`uL9]_}kٰq8ÃrHCuG`!b~ۖCUm;m5c:%NEG4IӣeP)[qz4|W#-! '\fa }d\pt 5"o,U 4Q:ή &݊a1㐢2Y.NgZcò4"xD$w1!QezreD6< *4D})?1ȑMfqq'w.7; 6w5**&0toٵt'v[0u֌SWɮ+e$[ا.D:[%JSFj\?4Hsٹ;AlWfhD=oeHvBz8A*؇H1,K3Ex)GV4➻!:_%@M\AhZ^Bc zQ +fw*nnK/ߘr*{YL2fŦmWAwiO<2rW @A)u/y|C*l,^2hN@5A=Lo%ޅÀnk 8e2 /dCֽ3ٌM/p&^}{˙|=چ'v ;1"M0y\NIT-̅*SGJs23ey}<ġ{ӎ U@&mߑ{+3LF'ƒ2Ţ`4Ki;"eifz*?A݀19<isjǦ+6 f#C<Ғi7Ohq@~(ߗ΋eڜoڰ$؉ͮ7=wbQxmϥ|^biq+[,ˆ(r|O 速^vQٔgS[.T]0L43:Ne]MŭU~u9-8c!@c?Zjdwyv3?M cUe}.{-LI\7fxKܸ Y3>۰0?݃pg 7OS@23$Y1Jv'eVvX*LrI? Q23Ȩ&^:.q10]6LKB))^"P)۴mL߅G_ȒIʔp0%ɰ6Z$I7_Bkn+lP\f$#^|:ݬ1qRBaTg&CyӔD);zV5\I< ;o:N];iq+Q+K+ôa1zo˨) Xt]E,FMsOz=n_xYHtyfcq`۰o΀A#x8Qr sGxz*"v?ȫTg&e~;!6?Pg:XQB~f)$$.K(s 8Ml4UBTژFJE%e2=wAf1 `Ѐ`t7XM%3g vqᰁ DySl&iAhYLIzb}$̯tS@(X6 Wcg?%,eML)fGDLNDWW_ h o \*;o[/WIV@Ӫՠ{j4>׏,dE"d""*MIg*&ku >~4P;Y*&b)ZGܘ#Ypqk/_w3>Ut5˟Bw6AK(=HBa'2mc)&HEZ> ') JTH ȍ(8JϔV}Ll?<ƎɄyo0 C*  \AR_q@UB[iX\ zkMMEFw|0mKςy ?@Yh $gYnNjRZ6#˟HK "vnRмҦHPtRyf?b˗;y{$`|XzK؂8az$X\Fa۰]nEW3ȑVχT~vUǡթD&񅈎L/Yt\Tak0l|D6.'H.tG꣢Y1ld*beeN#湡DtA IM#2t?D"6B Sk/ͺ)Hpg2u }} н cl챾_0K:P|u03 rj-)'xK%bDjg@yלRDe` Abg8^Ry͍y%N7n 9/r,-g =]TKR[",>)4uj%t@q&7@8"2,e@67Ү=\p-I_GnYs>,K KN`z` SJ.Vj:µ߉*>J}Ź=Bf1[^۳}@$hUuιT9QXg8L>? TBR wB/ƶ{94.AdmxLE6ƨFjUTf')0͝f9[@nF@h%+ ZbR=㢕U2]Ec7/NԎGZ t-r#30 ,Ҷ6B}Бj lja%HSjŕ>!Ռ6OK$= Si9eL{b:띅!wzܖ~Ӣl0Bґ-ưݗ=oxa(Y/%l+mZiŪ+hsKr3+VOZUj4ǜl#nI=~J gC:C(B.Mś N$:(\ h uCɯƣp'.6٤ajXj2D򠲠Aaj[N^Ƙ6OĘ7smm[)tʷ|/y'uTKv<&꘾ 8zZa Îܾ>pS<n^Rzs0wX淃!6P֯p(#9SA{$mb6ƂMC #e7DcYbtIZ؊$s]Wjmݳ~+7ڊg@aJj Gݍ>S\TqhB.#ۯG؈ 8IFU'*޷v zTlGJ}ziO'V mAyz] q[71'Њ+LFv-,}h:vwKQn\}Q%d2^hJDTWlVZX!'\Hue~+b@Qh;ůp~2XFT٨)?sa pS㻱H|cA^[kv=~N"=)$E08W,,Cd6ޜk m$ >",!MhSq­.8MLY/<}g]bwr u?`dmblgchЎendstream endobj 9 0 obj << /Type /Font /Subtype /Type1 /Encoding 119 0 R /FirstChar 2 /LastChar 122 /Widths 124 0 R /BaseFont /SJROWT+NimbusRomNo9L-Medi /FontDescriptor 7 0 R >> endobj 7 0 obj << /Ascent 690 /CapHeight 690 /Descent -209 /FontName /SJROWT+NimbusRomNo9L-Medi /ItalicAngle 0 /StemV 140 /XHeight 461 /FontBBox [-168 -341 1000 960] /Flags 4 /CharSet (/fi/parenleft/parenright/asterisk/comma/hyphen/period/zero/one/two/three/four/five/six/colon/equal/question/A/B/C/D/E/H/K/M/N/P/R/S/T/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z) /FontFile 8 0 R >> endobj 124 0 obj [556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 333 333 500 0 250 333 250 0 500 500 500 500 500 500 500 0 0 0 333 0 0 570 0 500 0 722 667 722 722 667 0 0 778 0 0 778 0 944 722 0 611 0 722 556 667 0 0 0 0 0 0 0 0 0 0 0 0 500 556 444 556 444 333 500 556 278 333 556 278 833 556 500 556 556 444 389 333 556 500 722 500 500 444 ] endobj 5 0 obj << /Length1 1630 /Length2 17870 /Length3 532 /Length 18781 /Filter /FlateDecode >> stream xڬctem&vvl۶m۶mRm۬vRT8_ck\c/2"E:!Sc3q{W:&zFn,௜ L^Ռaf 5303`"^VJ5e *c0_O+ {w3[G;3{׿׎*ffWK3@DAQKJ^@)!07s6(ZdL]̨;LM)ͅ/ hfb-3`ld+{[7+7wWB-):8[9FU<]-\bW p0ki`OIu5wy `jhk7_0Ggbeo_,Mm\\;U'_\]la4qY7w01?tfj?3C7 #S{[/9 ߐ;Hz/>whq7[[y#o;w,Eck1?ywk K&j-Bag7%o%W75s7 cbdo:UK+H`7/]ʟA[SZFX`ew\U9aaO;'3&俀,gl [7#ӿ?jdowS/Zf}':=+õ3otJTg t4̱I0֡/ =r.yk4ѯ~ [4HSݼ8Nø$FT\Mew>BFbHkzƍaWup#Cn͜8r} ˂\}`dvf@֨#3ZWUա#TO/b&ϬEb`WTIJ02Z4l!@QyZMw - 4هm FX~.I0SKix?- bƮ7$IeKoC+#ZU\+Kb -2U.sGjٓXԷՂoj. ;,XB0>Vz&ah bFZ SxO$>·~(zACօ1ϒ44Ylpp½a5jte}/GW9wn*.܍Vzϧڐ1$s9S.1Pm7@.HX#knAYe@^DPmN!.ZG'3N(΢ JipD!CuyoH:𛥃2KL}dc2Fg_0XD7}?$u%WB7 ijᢰW \-a&Aa{ #Y0r(I+Ckѕs;_ M ^qUᝯcd!DY0oD/P:%MHhm )u^pCY3PJaTZ"1;`ϛ&kQZ=8#l,o )}bFJO2*YR 44nYeRp'h[6iܧ@,_Jl!0 ֭0U Ӏ[dBu~$Cog:Eg*XN6FOSJɥڷ<ٻ6p9^'?̵M&5 `'2_7qMzևXd6q;dk]Iԫ=d)8bLC@ S3&M7x\aүP.ZZp)`pA{jbf-P+^r*R04E&$xWW{]u a#4?_cpĤaƢV{$] *dʔt0:^BR2ϦϢ~&+Oy j·[7hmXzvvDE:_nVQ4cNqzkyP8LY``EzVϥ|<$K8Zdsp0Bpӹ1zHLS~q̷ m bH`gO9ȱMfӨf4!o ܲ% K29s]>Q'EoHVbP̏譡Z/[J/UpEq;[!I#69m҈ {Ui]Έdo[cؾʩ^ՍH3'J=N˗吤 Ky潬 0 4QVάc–D3|\+Ry$J7HǁkUn1*,!͑i㣈 ):qooNYǧ3#Hi5).Hyڨa*սS_Md]T\2'E{=dbŒ_tٓ;)~TfFaEmc"r9R-MS!wk^s ~@WPU>oqRdFgN0ٕ+;e0б||ͭ r-ZnUA0*[8̒:y 2–n$ -'=}dh{[';n|OYrQ7 iZ%2?..QNW&Z˂g˙8a}VmeLS]믬Qs0/ug퟿(\($+y\4.FNYbv&}J qNxS2(I0|uaWCNJH\O-&x4 A;V;2Z ox9s')4S;9G],f(95HOg'G_kpͰYHe] gW`7J4m}?ke^>7 8*c ) αF(ּD b%# 1P ֶභ e< Zlv Kۍ@ͳjQ\Ui֤@)qĆ*0-H<߰mv<ԗ*A]*m9" -)#KNxuޏZwMR2nザ\6;bwd/ cI_qsQQ1aq0^!Yއdߘ/37J]{jJ6ǣm1H"ot MEYݵQPa`~H6g1\E$Mg-bچi钚NUr@.C\ݖqF" zݸԶ[g Ҳ3[x0$' ;%Bp Ɖ9 d4wkV ]! O5FDzp d ~-rrW\0C נ +ke[)dƸ7;F*Thp h1zf1w%}RGhJab Q }$Df!ҩĊ%3hE.;Y\)..ҧK(@OU& ☘8s땍rdځB`;AdeWYC:?;cO㬹A2k>)@,G4uS/QG5ܻ]ǾhB`쬄7-c E# SAPFFzv-N=A&,(#9mB$J@?V#ndA,8W(/~L_b ZHuxĦɽ 2Lϋu#]V4FXBu-l>0- .4D5s '!DU[͎BTu+Hա!nUJ{ WѢ,"K2'ZB~;I;>k#]>8X0%Ii?+Z)LJHvJM;(2eCZCD"?׷z>y4G ߹K+_1 ;姆26Uяk9?%."w !i/ҩIY@˱q?jluȦng*=?xGm*`O;-JOSh SC*jH?~R̩)iJD  2~V3R6' 6Mf:,NF 9C^١R$E("/p/S$֫tx+eDxc;ZfS:lhNٮ :=ˍ}(Sd*dHFjz"J$҈ "ujQݐ}trfד,_9R$J-?ExoYž,GT4$ߎG`FD0j㧀Ibt;s9M7GkX5~T;>TXq:O!rJ&L7x%#K";JpNi;z*gı*"/[u^ 4BÈo®pLH')J}Y&h货$p38 DV k5f/z2PF>\ۃD39;M\DҵA5[N~ИtÓMˌȏ,TjuƣYHwIB=  {wj >o6O~=3J^4A7+&f8=؄+”.whKeX-|+bWrr0 </=$O==3W}i{R42_&/mqTWkrR6 ]Z8!Ӭwy9ux)rN6O*2"amJׂ0OZS&FTe^2Gbcfc[Ն?)'~VBρy?"o"8 bf%f#l =`,9~\c rsNs|o3UM|Pnfo/P<A/Ł >t?q6AKyKJcaZ"Ew !״JӚ~t\ef ]T]"~GKM5v[^f~N!]Kv .b< t8%P`_}ó 8JSӯBRxO,Mf T{Cgl5M?٬8ScS՘S)CՇ]V NO;j3Ru]ZA0oh56Wՠ2;)@1ZbDCӛ5ֻn ѓhɆ?ITm*4ڄ7cȗKj09K$CI[K ;`agKzUÓT]lǏż^a";a8dj6,-B DՕS~uTyFr2D"OH䦞wۜCihd3y 9 p\Hva9O8+-4N5U]:6Z*GNWM_K#1Ѣ.IVes+nw bWod\z cux C%UTWmVL%҂v 6Zwvqȡij(jDD FUt'܆qꭄ`!͊0L]Zelۖ_-͌^D>0DŽ`Z¾q&s0^"aN.DE#`޷8_ EUfE')W}:zF_tʩsC0w*)xUknvo4?DDuv#f]]0<]}zc59Gg *˃Mֱ, } $`]܌Q Ob q@h9ӣH4+2 4[`\zB;@.m:$ܝu'dIӯG3>.?u9iw{֏g:BK`yS5/(M5{+-; qyyR>M^&Vqraߖmxb |г|NueFhL_l= f%9vӏc`v+M)4l}8wDG}0 t6}ee/s |W|, 4P 2s6h-w s)Ty^g3 rnJtyD_{PuϷ4uON~; *KJk@nEjA>S2U^,)oƽ [Ŧ&;wMqF_{MO^>^pb?6W,l[۳G\Mj?ƱM|z!"1O>E[mJ\g62Ԭߝß=sTtxKrU6[\&]F!T">"Urůs[2g ӁSV790"Yvn gsMRp( QYRK=PJHʼn`y͈=Į't˯p^ u-LiXנ+8p7%sL$`t)N4:i7FRǻ"քEe7 K1ґײy.}% G_\;E6EOXol8B`Nӓ͘=mۡ*.8vw]r<0WgiW%۩A?0 z`=50CUrVk`luawg1ofBg/yp}tp@Fc&B0FkˢBVlV@G.$F#B1-@JlH4t8ޛ]cD,l^Ud\ xpM& o 3kiTA;Nɮu NLQP7wFEN BN>q?A伐_%^sРr է7R5 $;Eē&UCpPZӽp%A[Лayx!taBf(X7'0^TS@ $akEױ%jxޮΪ~4|9POԋR' J[ ݼlRpI%R/ :U zlhgwtqɊMTWλhdžU`e{5?CDD`kNeS79)¯Rv"8=W]QW~Tg8o4/ȇWo mQy7ng-4}BB*4!_X>]6*el~or IJ 6@C})xHgKcz *'ɿ6YG(g_hpUK! rvXh[gn_;J" H P´3[aaeq ]SF݊ yɣ!Q +MҨu'Qા=Ȝ z*ut^EK3djL"#>yG(;|ɛڇm;(B9Psިos=mğA3(h?]?(Aʹ_(.OÄpMx??{qPs[Z+Hy_^Q,%v wnTl,?4w0nȾgKDn밲9cZ rvٌ\oퟂq>G>եmc3TZ ^].xhY%>*bG^I#&W@,k2ݶqavى!cG)va}e҅ \ |qъ[^qE=AYf5w/= Pq^}w;ac2/n#x:^H03_ZNȆvحu@4[pMM@fX^2f4Lzsm #v,iM)g60Sk}{5Vpt5C[b;kVC7;\`fhKR/AZ '^APOηiO>r#ʨ[څҶ7{^3/[_6jשu^˨\`YI@KP>QvӤ.hc.(aZRI1w2F(h.$нs|F,a&R~s%\NJ@А+J *w̏IgK5{ |/KyկjZBJ(p@yQڕMOn@4apsțOO508pf$'eJRa{|Ym\6f=^)-sy/t.Uqk~{q?60cؒt[h |t̶&AwŰu T;j\~S#w,V`Xt9"V_bNQV*8|lgcw*>SIFD )iVWJ k7vy@0+aRl*ai$* Ds<} 8%zj<8jpt:.%z)rꆄqi-o$yD:E(YGwe>NYzS/fA}ANtx<Qhj}+m}Q岺I  Nr#B=Ķ.Z@6#sM8!.ӹ:VZ³y`?D 6(Wɶ$!oETS;ȱV!WR}?NPYlW,3e7g-N;-RM?%{ mT~X[!T V7c!T ۃiSVpp F!AE  yes> oyAmHh&@U$v ;"b?O" 干ŝ.xs)[FGDw,'x)hv Iܺ1eB5j&@ liJ:.=|!NO|lp;A[5+{aZT#@sr*a@})~ SA"S3.,"PA$*bv8?73 tߕ" FyM?{;==B \%Q[WDp @ k>\(uǣd, Mh? vג!fqnɪSu`mpN{|V~CW E{{8`>)8@tkBl6m:-N_Ow2D2$#< `ng{vM:7xyKTXJӎ@d9Ǖ+!j;*5mG i,avZ{G7 7dͭPȏ: R\Tz3Pο֖g4ZM LlKxJ,p\{9 CFqmiL vDAZG}DVx<],&R1(gwl8?+ˡZy+5Gv/$?H,| r[įkWJr_3O@!N}M'OiXzI2|kEu.uř2#n^¦_lEg;㻋bӧ-"ph\QFU^Z#MuDbR;*%sQ-X< ^\ԨӍj4bk6KM1 3R\L m_3uЍsJ{Fʅ3:,5=Ǚy9sRx5l62FL["ixJvk-\4J;1dǤMǪAw2ʨl埯ckytm@m1~}Jg[,^1Q}20E-r1ſE]TDЏ/SKÃF‘2h'3Ε=@#*$t$C;+ >zGgGHj,_20[:WlDq˔(j3fdShJN P wiiƠq^/\08pK; *Su e SgV6R!92rnRw:Cڹ%dw¹?qICo\_|ƟUJf7'Lj]PbF"tHTGiՠt$|PRIڅ=MB7z_(V>A?{y`x60x 1'ChO^(ML 1 /U'`HSc^ub‘4TmCm ֗gaqcAl*{m_Mutf%M Kx#HH5[+ˑ6Ҳ3ϸƶKrR:@*tzךUɎS&uęXA&p*E|iۈ2El;1?a06V=^^"ѥo3(&$Gq"ǔ%V~ώ->rB\kIJH볺:0\.gp6]ѧ2$kuW89[ul52JxjFݾ ^k8"KUo;L'Xʼn_@lnى)ĝϊ ӿ d5:ܙ3K8A<\T=D۵4=%+ :'*'[˕0rhyv`Պ{1MfZ­0tu3kRwNg^kS@,l IJam%EfMx.?'8vƣA0i%q ݯ@ _h* DYbg Tr l1wػ~l S.AVU Neb_%ɵ8l}z^72@c:݁P8%͇ t>w:21 ){'-j~752Ly][yH'FݳdߔY4!m/tfD> 0juZg :e#DG~^A?M&XKVmA\z, HՎ7yM ~hB>&BR,JB j,zh$H-J\eGW 4~3aPuhs,:'~;uOF$3B(FS] 8dQG fc@CWmq5b@c !۵DΈl%[FݯGȯ{A>/|M4D60I N4#K֫_6UZRLD+ޠNRC A!x}Ңh:UňHO@a ^t~M!1A>߄ډ!:_dwjc (8_E3v $H\=޹}GDi.S)!0h+׹3Y!#<;ݮz'!mԂrKWxӛ6nAiю 2_v;v.+#-7{#|WݰA#|pu~Q,Mu=I8%]zԧi<%+S B|ȰrAJQ?*mP34D[0hcPkM+Rf^yIO>B|'8pH$ߏgWs9YMG˿n"c{Q7HVԧSd[Wa}3uyH0s] T㸉? =3Rj\gfcӜ{+,LJw~|~.(K:.e׾1T`od[%r NM?6.œS -jE%u/aL=5tVS)yjDU35nh<+X&{kX$$zόqܖ;M a#\gwtrܲ+U`=^gE}s%evAH,Ό3K\U &ŵOEü?FX^/'FP{uVNm7C *[{]ޠg|S/v;X@sFSaM4@xaQ^{4?D:W0 Eq~ 㢱:XnI*!Lqp{;~6rnVR!oxnѼ?]-Nk~yeap[,FIҸRkӧejDIؐ;O=Ĵ BLlXqPߔH߆@:I4wqu1 g}*dʗŵw5pR `wwmF*$֮KХ}x_O?glUvagQ|"[{qٌo婜+ב7g7r#pi3jf O?i֪?b@;7b1N\2pۚk?>8'qy:^En R/ .:G|T pnm:)F2M3# ֡<1$>wYL2EAY\FCX:B3T-)n!e[Dcz"ثvаc_ҀLluMa3v3O&2=.23(ل2c^-P]xZGj{+$ݗ\CF3xM(#ZZ'5{t~7^`$ٻu30;,tƒ0$ 򀲿"W]^j@UQGهVuuVKyv+eT䯹+"No1DzeFXGͳ; gpi!5sEDY%E-JI:i2oS]` EnFǒ7 -QW_$gj7[[B Hz{X ~j`dM Iқ82T2)e9ZE# 粜X)\yA(7DCIm{1H c:,ͣ6+9.}d4!\"WB!-kw\k{+_!A\YNendstream endobj 6 0 obj << /Type /Font /Subtype /Type1 /Encoding 119 0 R /FirstChar 2 /LastChar 148 /Widths 125 0 R /BaseFont /ZXJKBV+NimbusRomNo9L-Regu /FontDescriptor 4 0 R >> endobj 4 0 obj << /Ascent 678 /CapHeight 651 /Descent -216 /FontName /ZXJKBV+NimbusRomNo9L-Regu /ItalicAngle 0 /StemV 85 /XHeight 450 /FontBBox [-168 -281 1000 924] /Flags 4 /CharSet (/fi/fl/exclam/percent/quoteright/parenleft/parenright/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/equal/A/B/C/D/E/F/G/H/I/J/L/M/N/O/P/Q/R/S/T/U/W/Y/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/quotedblleft/quotedblright) /FontFile 5 0 R >> endobj 125 0 obj [556 556 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 333 0 0 0 833 0 333 333 333 0 0 250 333 250 278 500 500 500 500 500 500 500 500 500 500 278 0 0 564 0 0 0 722 667 667 722 611 556 722 722 333 389 0 611 889 722 722 556 722 667 556 611 722 0 944 0 722 0 0 0 0 0 0 0 444 500 444 500 444 333 500 500 278 278 500 278 778 500 500 500 500 333 389 278 500 500 722 500 500 444 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 444 444 ] endobj 19 0 obj << /Type /Pages /Count 6 /Parent 126 0 R /Kids [2 0 R 21 0 R 36 0 R 39 0 R 42 0 R 48 0 R] >> endobj 62 0 obj << /Type /Pages /Count 6 /Parent 126 0 R /Kids [51 0 R 64 0 R 67 0 R 70 0 R 82 0 R 85 0 R] >> endobj 90 0 obj << /Type /Pages /Count 3 /Parent 126 0 R /Kids [88 0 R 92 0 R 95 0 R] >> endobj 126 0 obj << /Type /Pages /Count 15 /Kids [19 0 R 62 0 R 90 0 R] >> endobj 127 0 obj << /Type /Catalog /Pages 126 0 R >> endobj 128 0 obj << /Producer (pdfeTeX-1.21a) /Creator (TeX) /CreationDate (D:20070104170753-05'00') /PTEX.Fullbanner (This is pdfeTeX, Version 3.141592-1.21a-2.2 (Web2C 7.5.4) kpathsea version 3.5.4) >> endobj xref 0 129 0000000000 65535 f 0000002476 00000 n 0000002361 00000 n 0000000009 00000 n 0000149120 00000 n 0000130050 00000 n 0000148951 00000 n 0000129285 00000 n 0000113715 00000 n 0000129116 00000 n 0000113066 00000 n 0000111152 00000 n 0000112907 00000 n 0000110503 00000 n 0000098351 00000 n 0000110328 00000 n 0000097548 00000 n 0000081525 00000 n 0000097379 00000 n 0000150049 00000 n 0000006181 00000 n 0000006063 00000 n 0000002591 00000 n 0000078824 00000 n 0000074400 00000 n 0000078664 00000 n 0000073966 00000 n 0000070292 00000 n 0000073806 00000 n 0000069560 00000 n 0000064821 00000 n 0000069402 00000 n 0000064517 00000 n 0000062530 00000 n 0000064359 00000 n 0000008519 00000 n 0000008401 00000 n 0000006344 00000 n 0000011497 00000 n 0000011379 00000 n 0000008635 00000 n 0000014785 00000 n 0000014667 00000 n 0000011648 00000 n 0000062016 00000 n 0000058980 00000 n 0000061856 00000 n 0000016378 00000 n 0000016260 00000 n 0000014949 00000 n 0000019334 00000 n 0000019216 00000 n 0000016506 00000 n 0000058504 00000 n 0000056275 00000 n 0000058345 00000 n 0000055807 00000 n 0000052318 00000 n 0000055650 00000 n 0000051996 00000 n 0000050447 00000 n 0000051838 00000 n 0000150158 00000 n 0000022301 00000 n 0000022183 00000 n 0000019451 00000 n 0000024882 00000 n 0000024764 00000 n 0000022464 00000 n 0000027170 00000 n 0000027052 00000 n 0000025010 00000 n 0000050144 00000 n 0000048757 00000 n 0000049988 00000 n 0000048412 00000 n 0000046011 00000 n 0000048256 00000 n 0000045635 00000 n 0000042825 00000 n 0000045476 00000 n 0000029742 00000 n 0000029624 00000 n 0000027356 00000 n 0000033488 00000 n 0000033370 00000 n 0000029893 00000 n 0000036791 00000 n 0000036673 00000 n 0000033674 00000 n 0000150268 00000 n 0000040362 00000 n 0000040244 00000 n 0000036953 00000 n 0000042662 00000 n 0000042544 00000 n 0000040536 00000 n 0000045890 00000 n 0000045843 00000 n 0000048659 00000 n 0000048623 00000 n 0000050373 00000 n 0000050349 00000 n 0000052229 00000 n 0000052204 00000 n 0000056117 00000 n 0000056049 00000 n 0000058857 00000 n 0000058713 00000 n 0000062405 00000 n 0000062227 00000 n 0000064739 00000 n 0000064715 00000 n 0000070029 00000 n 0000069867 00000 n 0000074262 00000 n 0000074183 00000 n 0000079354 00000 n 0000079096 00000 n 0000079637 00000 n 0000098025 00000 n 0000110818 00000 n 0000113552 00000 n 0000113305 00000 n 0000129676 00000 n 0000149589 00000 n 0000150357 00000 n 0000150432 00000 n 0000150485 00000 n trailer << /Size 129 /Root 127 0 R /Info 128 0 R /ID [<24F67CBCCA974BE585286D8F7748A8B3> <24F67CBCCA974BE585286D8F7748A8B3>] >> startxref 150689 %%EOF pysparse-1.1.1/Examples/0000755010116400000240000000000011402271040014121 5ustar wd15dialoutpysparse-1.1.1/Examples/jdsym_debug.py0000644010116400000240000001017611402270400016773 0ustar wd15dialoutimport math import Numeric import pysparse.spmatrix from pysparse import spmatrix, itsolvers, jdsym, precon, superlu test = 1 if test == 1: # Test: compare K=eye with K=None # # results are not the same, ritz-value in 2nd iterations differ path = '/local/home/geus/matrices' A = spmatrix.ll_mat_from_mtx(path + 'edge6x3x5_A.mtx') M = spmatrix.ll_mat_from_mtx(path + 'edge6x3x5_B.mtx') n = A.shape[0] sigma = 25.0 I = spmatrix.ll_mat(n, n) for i in xrange(n): I[i,i] = 1.0 Keye = precon.jacobi(I) k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A.to_sss(), M.to_sss(), None, 5, sigma, 1e-10, 15, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, toldecay=2.0, linitmax=200, clvl=1, strategy=1) k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A.to_sss(), M.to_sss(), Keye, 5, sigma, 1e-10, 15, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, toldecay=2.0, linitmax=200, clvl=1, strategy=1) elif test == 2: # Test 2: K = diag(A - sigma*M), test diagonal prec using Matlab Asigma = A.copy() Asigma.shift(-sigma, M) K = precon.jacobi(Asigma.to_sss()) b = Numeric.ones(n, 'd') x = Numeric.zeros(n, 'd') K.precon(b, x) print 'norm(idiag) = %.16g' % (math.sqrt(Numeric.dot(x, x)), ) k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A.to_sss(), M.to_sss(), K, 5, sigma, 1e-10, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, toldecay=2.0, linitmax=200, clvl=1, strategy=1) elif test == 3: Asigma = A.copy() Asigma.shift(-sigma, M) K = precon.ssor(Asigma.to_sss()) k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A.to_sss(), M.to_sss(), K, 5, sigma, 1e-10, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, toldecay=2.0, linitmax=200, clvl=1, strategy=1) elif test == 4: Asigma = A.copy() Asigma.shift(-sigma, M) K = precon.jacobi(Asigma.to_sss()) k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A.to_sss(), M.to_sss(), K, 5, sigma, 1e-10, 150, itsolvers.cgs, jmin=5, jmax=10, eps_tr=1e-4, toldecay=2.0, linitmax=200, clvl=1, strategy=1, optype=1) elif test == 5: # time jdtest -e1 -k1 -o linsolver=QMRS,optype=SYM,jmin=5,jmax=10,linitmax=1000,jdtol=1e-6,strategy=1 1.4 1 ~/matrices/cop18_el5_A.mtx ~/matrices/cop18_el5_M.mtx path = '/home/geus/matrices/' A = spmatrix.ll_mat_from_mtx(path + 'cop18_el5_A.mtx') M = spmatrix.ll_mat_from_mtx(path + 'cop18_el5_M.mtx') n = A.shape[0] sigma = 1.4 Asigma = A.copy() Asigma.shift(-sigma, M) K = precon.jacobi(Asigma.to_sss()) k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A.to_sss(), M.to_sss(), K, 1, sigma, 1e-6, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, toldecay=2.0, linitmax=1000, clvl=1, strategy=1) print k_conv, lmbd, it, it_inner elif test == 6: class prec2lev: def __init__(self, A, n11): n = A.shape[0] self.n11 = n11 self.lu11 = superlu.factorize(A[:n11,:n11].to_csr(), diag_pivot_thresh=0) self.K22 = precon.ssor(A[n11:,n11:].to_sss()) self.shape = (n, n) def precon(self, x, y): self.lu11.solve(x[:n11], y[:n11]) self.K22.precon(x[n11:], y[n11:]) print 'Loading matrices...' path = '/home/geus/matrices/' A = spmatrix.ll_mat_from_mtx(path + 'cop18_el5_A.mtx') M = spmatrix.ll_mat_from_mtx(path + 'cop18_el5_M.mtx') n = A.shape[0] sigma = 1.4 n11 = 4688 print 'Constructing preconditioner...' Asigma = A.copy() Asigma.shift(-sigma, M) K = prec2lev(Asigma, n11) k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A.to_sss(), M.to_sss(), K, 2, sigma, 1e-8, 300, itsolvers.qmrs, jmin=10, jmax=25, eps_tr=1e-3, toldecay=1.5, linitmax=3000, clvl=1, strategy=1) print k_conv, lmbd, it, it_inner pysparse-1.1.1/Examples/jdsym_demo.py0000644010116400000240000000337511402270400016634 0ustar wd15dialoutimport os from pysparse import spmatrix, itsolvers, jdsym, precon path = os.path.join(os.environ['HOME'], 'matrices') A = spmatrix.ll_mat_from_mtx(os.path.join(path, 'edge6x3x5_A.mtx')) M = spmatrix.ll_mat_from_mtx(os.path.join(path, 'edge6x3x5_B.mtx')) sigma = 25.0 Asigma = A.copy() Asigma.shift(-sigma, M) K = precon.jacobi(Asigma.to_sss()) del Asigma ##n = A.shape[0] ##I = spmatrix.ll_mat(n, n) ##for i in xrange(n): ## I[i,i] = 1.0 ##K = precon.jacobi(I) k_conv, lmbd, Q, it, it_inner = \ jdsym.jdsym(A.to_sss(), M.to_sss(), K, 5, sigma, 1e-10, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, toldecay=2.0, linitmax=200, clvl=1, strategy=1) print k_conv, lmbd, it, it_inner ##path = '/homes/geus/jdbsym/test/' ##A = spmatrix.ll_mat_from_mtx(path + 'sameh_10000.mtx').to_sss() ##K = precon.ssor(A) ##k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A, None, K, 4, 0.0, 1e-10, 50, itsolvers.qmrs, ## jmax=20, eps_tr=1e-4, toldecay=2.0, linitmax=60, clvl=1) ##path = '../spmatrix/' ##A_ll = spmatrix.ll_mat_from_mtx(path + 'cop18_el5_A.mtx') ##M_ll = spmatrix.ll_mat_from_mtx(path + 'cop18_el5_M.mtx') ##A = A_ll.to_sss() ##M = M_ll.to_sss() ##k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A, M, None, 5, 5.0, 1e-4, 50, itsolvers.minres, ## linitmax=3000, strategy=1, clvl=1) ##path = '/homes/geus/jdbsym/test/' ##A = spmatrix.ll_mat_from_mtx(path + 'node4x3x1_A.mtx').to_sss() ##M = spmatrix.ll_mat_from_mtx(path + 'node4x3x1_M.mtx').to_sss() ##K = precon.jacobi(A) ##k_conv, lmbd, Q, it, it_inner = jdsym.jdsym(A, M, K, 15, 0.0, 1e-10, 150, itsolvers.qmrs, ## jmin=15, jmax=30, eps_tr=1e-4, toldecay=2.0, linitmax=60, clvl=1) ##print lmbd pysparse-1.1.1/Examples/jdsym_test.py0000644010116400000240000000666711402270402016700 0ustar wd15dialoutfrom pysparse import spmatrix, jdsym, itsolvers from numpy import zeros, dot, allclose, multiply from math import sqrt import RandomArray class diagPrecShifted: def __init__(self, A, M, sigma): self.shape = A.shape n = self.shape[0] self.dinv = zeros(n, 'd') for i in xrange(n): self.dinv[i] = 1.0 / (A[i,i] - sigma*M[i,i]) def precon(self, x, y): multiply(x, self.dinv, y) def computeResiduals(A, M, lmbd, Q): kconv = lmbd.shape[0] residuals = zeros((kconv, ), 'd') r = zeros((n, ), 'd') u = zeros((n, ), 'd') t = zeros((n, ), 'd') for k in xrange(kconv): u = Q[:,k].copy() A.matvec(u, r) if M <> None: M.matvec(u, t) else: t = u r = r - lmbd[k]*t residuals[k] = sqrt(dot(r,r)) return residuals n = 1000; ncv = 5; tol = 1e-6 A = spmatrix.ll_mat_sym(n) for i in xrange(n): A[i,i] = i+1.0 As = A.to_sss() M = spmatrix.ll_mat_sym(n) for i in xrange(n): M[i,i] = float(n/2) + i Ms = M.to_sss() normM = M[n-1,n-1] K = diagPrecShifted(A, M, 0.006) #------------------------------------------------------------------------------- # Test 1: M = K = None print 'Test 1' lmbd_exact = zeros(ncv, 'd') for k in xrange(ncv): lmbd_exact[k] = A[k,k] kconv, lmbd, Q, it, it_inner = jdsym.jdsym(As, None, None, ncv, 0.0, tol, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, clvl=1) assert ncv == kconv assert allclose(computeResiduals(As, None, lmbd, Q), zeros(kconv), 0.0, tol) assert allclose(lmbd, lmbd_exact, tol*tol, 0.0) print 'OK' #------------------------------------------------------------------------------- # Test 2: K = None print 'Test 2', lmbd_exact = zeros(ncv, 'd') for k in xrange(ncv): lmbd_exact[k] = A[k,k]/M[k,k] X0 = RandomArray.random((n,ncv)) kconv, lmbd, Q, it, it_inner = jdsym.jdsym(As, Ms, None, ncv, 0.0, tol, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, clvl=1) assert ncv == kconv assert allclose(computeResiduals(As, Ms, lmbd, Q), zeros(kconv), 0.0, normM*tol) assert allclose(lmbd, lmbd_exact, normM*tol*tol, 0.0) print 'OK' #------------------------------------------------------------------------------- # Test 3: general case print 'Test 3', lmbd_exact = zeros(ncv, 'd') for k in xrange(ncv): lmbd_exact[k] = A[k,k]/M[k,k] kconv, lmbd, Q, it, it_inner = jdsym.jdsym(As, Ms, K, ncv, 0.0, tol, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, clvl=1) assert ncv == kconv assert allclose(computeResiduals(As, Ms, lmbd, Q), zeros(kconv), 0.0, normM*tol) assert allclose(lmbd, lmbd_exact, normM*tol*tol, 0.0) print 'OK' #------------------------------------------------------------------------------- # Test 4: K = None, with X0 print 'Test 4', lmbd_exact = zeros(ncv, 'd') for k in xrange(ncv): lmbd_exact[k] = A[k,k]/M[k,k] # Fixme: RandomArray.random is broken AMD64 # X0 = RandomArray.random((n,ncv)) X0 = zeros((n,ncv), 'd') for k in xrange(ncv): X0[k,k] = 10000 kconv, lmbd, Q, it, it_inner = jdsym.jdsym(As, Ms, None, ncv, 0.0, tol, 150, itsolvers.qmrs, jmin=5, jmax=10, eps_tr=1e-4, clvl=1, V0=X0) assert ncv == kconv assert allclose(computeResiduals(As, Ms, lmbd, Q), zeros(kconv), 0.0, normM*tol) assert allclose(lmbd, lmbd_exact, normM*tol*tol, 0.0) print 'OK' pysparse-1.1.1/Examples/matmul_perftest.py0000644010116400000240000000073311402270402017712 0ustar wd15dialoutimport time from pysparse import spmatrix n = 1000000 # create 2 nxn tridiag matrices A = spmatrix.ll_mat(n, n) B = spmatrix.ll_mat(n, n) for i in xrange(n): A[i,i] = i B[i,i] = i if i > 0: A[i,i-1] = 1 B[i,i-1] = 1 if i < n-1: A[i,i+1] = 1 B[i,i-1] = 1 t1 = time.clock() C = spmatrix.matrixmultiply(A, B) t_mult = time.clock() - t1 print 'time for multiplying %dx%d matrices: %.2f sec' % (n, n, t_mult) print C[:10,:10] pysparse-1.1.1/Examples/poisson2dvec.py0000644010116400000240000000217011402270402017112 0ustar wd15dialout# Poisson 2D constructors. Illustrate vectorization. from pysparse import spmatrix import numpy def poisson2d_vec(n): n2 = n*n L = spmatrix.ll_mat(n2, n2, 5*n2-4*n) d = numpy.arange(n2, dtype=numpy.int) L.put(4.0, d) L.put(-1.0, d[:-n], d[n:]) L.put(-1.0, d[n:], d[:-n]) for i in xrange(n): di = d[i*n:(i+1)*n] L.put(-1.0, di[1:], di[:-1]) L.put(-1.0, di[:-1], di[1:]) return L def poisson2d_vec_sym(n): n2 = n*n L = spmatrix.ll_mat_sym(n2, 3*n2-2*n) d = numpy.arange(n2, dtype=numpy.int) L.put(4.0, d) L.put(-1.0, d[n:], d[:-n]) for i in xrange(n): di = d[i*n:(i+1)*n] L.put(-1.0, di[:-1], di[1:]) return L def poisson2d_vec_sym_blk(n): n2 = n*n L = spmatrix.ll_mat_sym(n2, 3*n2-2*n) D = spmatrix.ll_mat_sym(n, 2*n-1) d = numpy.arange(n, dtype=numpy.int) D.put(4.0, d) D.put(-1.0, d[1:], d[:-1]) P = spmatrix.ll_mat_sym(n, n-1) P.put(-1,d) for i in xrange(n-1): L[i*n:(i+1)*n, i*n:(i+1)*n] = D L[(i+1)*n:(i+2)*n, i*n:(i+1)*n] = P # Last diagonal block L[-n:,-n:] = D return L pysparse-1.1.1/Examples/poisson_gmres.py0000644010116400000240000001027011402270403017364 0ustar wd15dialoutimport Numeric import math from pysparse import spmatrix from pysparse import itsolvers from pysparse import precon import time def poisson2d(n): L = spmatrix.ll_mat(n*n, n*n) for i in range(n): for j in range(n): k = i + n*j L[k,k] = 4 if i > 0: L[k,k-1] = -1 if i < n-1: L[k,k+1] = -1 if j > 0: L[k,k-n] = -1 if j < n-1: L[k,k+n] = -1 return L def poisson2d_sym(n): L = spmatrix.ll_mat_sym(n*n) for i in range(n): for j in range(n): k = i + n*j L[k,k] = 4 if i > 0: L[k,k-1] = -1 if j > 0: L[k,k-n] = -1 return L def poisson2d_sym_blk(n): L = spmatrix.ll_mat_sym(n*n) I = spmatrix.ll_mat_sym(n) P = spmatrix.ll_mat_sym(n) for i in range(n): I[i,i] = -1 for i in range(n): P[i,i] = 4 if i > 0: P[i,i-1] = -1 for i in range(0, n*n, n): L[i:i+n,i:i+n] = P if i > 0: L[i:i+n,i-n:i] = I return L n = 50 t1 = time.clock() L = poisson2d(n) print 'Time for constructing the matrix: %8.2f sec' % (time.clock() - t1, ) #L.export_mtx('poi2d_100.mtx') A = L.to_csr() S = L.to_sss() print L.nnz print S.nnz print A.nnz b = Numeric.ones(n*n, 'd') e = Numeric.ones(n*n, 'd') c = Numeric.ones(n*n, 'd') for loop in xrange(n*n): b[loop]= loop c[loop] = loop y = Numeric.ones(n*n, 'd') S.matvec(b,y) b = y #print b # --------------------------------------------------------------------------------------- t1 = time.clock() x = Numeric.zeros(n*n, 'd') info, iter, relres = itsolvers.gmres(S, b, x, 1e-12, 200, None, 100) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using SSS matrix: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(Numeric.dot(x, x)) r = Numeric.zeros(n*n, 'd') S.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(Numeric.dot(r, r)) # --------------------------------------------------------------------------------------- t1 = time.clock() x = Numeric.zeros(n*n, 'd') info, iter, relres = itsolvers.gmres(A, b, x, 1e-12, 200) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using CSR matrix: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(Numeric.dot(x, x)) r = Numeric.zeros(n*n, 'd') A.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(Numeric.dot(r, r)) # --------------------------------------------------------------------------------------- t1 = time.clock() x = Numeric.zeros(n*n, 'd') info, iter, relres = itsolvers.gmres(L, b, x, 1e-12, 200) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using LL matrix: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(Numeric.dot(x, x)) r = Numeric.zeros(n*n, 'd') A.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(Numeric.dot(r, r)) # --------------------------------------------------------------------------------------- K_ssor = precon.ssor(S, 1.0) t1 = time.clock() x = Numeric.zeros(n*n, 'd') info, iter, relres = itsolvers.gmres(S, b, x, 1e-12, 500, K_ssor, 20) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using SSS matrix and SSOR preconditioner: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(Numeric.dot(x, x)) r = Numeric.zeros(n*n, 'd') S.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(Numeric.dot(r, r)) # --------------------------------------------------------------------------------------- #import jdsym #jdsym.jdsym(S, None, None, 5, 0.0, 1e-8, 20, itsolvers.qmrs, clvl=1) x = Numeric.zeros(n*n, 'd') info, iter, relres = itsolvers.gmres(S, b, x, 1e-15, 500, K_ssor, 50) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using SSS matrix and SSOR preconditioner: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(Numeric.dot(x, x)) r = Numeric.zeros(n*n, 'd') S.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(Numeric.dot(r, r)) print 'bye' pysparse-1.1.1/Examples/poisson_test.py0000644010116400000240000000750711402270400017234 0ustar wd15dialoutimport numpy import math from pysparse import spmatrix from pysparse import itsolvers from pysparse import precon import time def poisson2d(n): L = spmatrix.ll_mat(n*n, n*n) for i in range(n): for j in range(n): k = i + n*j L[k,k] = 4 if i > 0: L[k,k-1] = -1 if i < n-1: L[k,k+1] = -1 if j > 0: L[k,k-n] = -1 if j < n-1: L[k,k+n] = -1 return L def poisson2d_sym(n): L = spmatrix.ll_mat_sym(n*n) for i in range(n): for j in range(n): k = i + n*j L[k,k] = 4 if i > 0: L[k,k-1] = -1 if j > 0: L[k,k-n] = -1 return L def poisson2d_sym_blk(n): L = spmatrix.ll_mat_sym(n*n) I = spmatrix.ll_mat_sym(n) P = spmatrix.ll_mat_sym(n) for i in range(n): I[i,i] = -1 for i in range(n): P[i,i] = 4 if i > 0: P[i,i-1] = -1 for i in range(0, n*n, n): L[i:i+n,i:i+n] = P if i > 0: L[i:i+n,i-n:i] = I return L tol = 1e-8 n = 100 t1 = time.clock() L = poisson2d_sym_blk(n) print 'Time for constructing the matrix using poisson2d_sym_blk: %8.2f sec' % (time.clock() - t1, ) t1 = time.clock() L = poisson2d_sym(n) print 'Time for constructing the matrix using poisson2d_sym : %8.2f sec' % (time.clock() - t1, ) t1 = time.clock() L = poisson2d(n) print 'Time for constructing the matrix using poisson2d : %8.2f sec' % (time.clock() - t1, ) A = L.to_csr() S = L.to_sss() print L.nnz print S.nnz print A.nnz b = numpy.ones(n*n, 'd') # --------------------------------------------------------------------------------------- t1 = time.clock() x = numpy.zeros(n*n, 'd') info, iter, relres = itsolvers.pcg(S, b, x, tol, 2000) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using SSS matrix: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(numpy.dot(x, x)) r = numpy.zeros(n*n, 'd') S.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(numpy.dot(r, r)) print x[0:10] # --------------------------------------------------------------------------------------- t1 = time.clock() x = numpy.zeros(n*n, 'd') info, iter, relres = itsolvers.pcg(A, b, x, tol, 2000) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using CSR matrix: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(numpy.dot(x, x)) r = numpy.zeros(n*n, 'd') A.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(numpy.dot(r, r)) # --------------------------------------------------------------------------------------- t1 = time.clock() x = numpy.zeros(n*n, 'd') info, iter, relres = itsolvers.pcg(L, b, x, tol, 2000) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using LL matrix: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(numpy.dot(x, x)) r = numpy.zeros(n*n, 'd') A.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(numpy.dot(r, r)) # --------------------------------------------------------------------------------------- K_ssor = precon.ssor(S, 1.9) t1 = time.clock() x = numpy.zeros(n*n, 'd') info, iter, relres = itsolvers.pcg(S, b, x, tol, 2000, K_ssor) print 'info=%d, iter=%d, relres=%e' % (info, iter, relres) print 'Time for solving the system using SSS matrix and SSOR preconditioner: %8.2f sec' % (time.clock() - t1, ) print 'norm(x) = %g' % math.sqrt(numpy.dot(x, x)) r = numpy.zeros(n*n, 'd') S.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(numpy.dot(r, r)) # --------------------------------------------------------------------------------------- from pysparse import jdsym jdsym.jdsym(S, None, None, 5, 0.0, 1e-8, 100, itsolvers.qmrs, clvl=1) pysparse-1.1.1/Examples/poisson_test_eig.py0000644010116400000240000000161011402270402020047 0ustar wd15dialoutimport numpy as Numeric import math from pysparse import spmatrix from pysparse import itsolvers from pysparse import precon from pysparse import jdsym import time def poisson2d_sym_blk(n): L = spmatrix.ll_mat_sym(n*n) I = spmatrix.ll_mat_sym(n) P = spmatrix.ll_mat_sym(n) for i in range(n): I[i,i] = -1 for i in range(n): P[i,i] = 4 if i > 0: P[i,i-1] = -1 for i in range(0, n*n, n): L[i:i+n,i:i+n] = P if i > 0: L[i:i+n,i-n:i] = I return L n = 200 t1 = time.clock() L = poisson2d_sym_blk(n) print 'Time for constructing the matrix: %8.2f sec' % (time.clock() - t1, ) print L.nnz # --------------------------------------------------------------------------------------- t1 = time.clock() jdsym.jdsym(L.to_sss(), None, None, 5, 0.0, 1e-8, 100, itsolvers.qmrs, clvl=1) print 'Time spend in jdsym: %8.2f sec' % (time.clock() - t1, ) pysparse-1.1.1/Examples/pysparse_test.py0000644010116400000240000002012611402270401017401 0ustar wd15dialoutimport math, os, sys, time import numpy as Numeric from pysparse import spmatrix from pysparse import itsolvers from pysparse import precon ll = spmatrix.ll_mat(5,5) print ll print ll[1,1] print ll ll[2,1] = 1.0 ll[1,3] = 2.0 print ll print ll.to_csr() print ll[1,3] print ll[1,-1] print ll.nnz ll.export_mtx('test.mtx') L = spmatrix.ll_mat(10, 10) for i in range(0, 10): L[i,i] = float(i+1) A = L.to_csr() x = Numeric.ones([10], 'd') y = Numeric.zeros([10], 'd') print A, x, y A.matvec(x, y) print y ll = spmatrix.ll_mat(100, 100) for i in range(0, 100, 5): for j in range(0, 100, 4): ll[i,j] = 1.0/float(i+j+1) A = ll.to_csr() x = Numeric.arange(100).astype(Numeric.float) y = Numeric.zeros(100, 'd') z = Numeric.zeros(100, 'd') A.matvec(x, y) print y print 'norm(y) = ', math.sqrt(Numeric.add.reduce(y)) ##A.matvec_transp(x, z) ##print z ##print 'norm(z) = ', math.sqrt(Numeric.add.reduce(z)) L = spmatrix.ll_mat(10,10) for i in range(10): L[i,i] = float(i+1) A = L.to_csr() print A x = Numeric.zeros(10, 'd') b = Numeric.ones(10, 'd') info, iter, relres = itsolvers.pcg(A, b, x, 1e-8, 100) print info, iter, relres print x if (info != 0): print >> sys.stderr, 'cg not converged' L2 = L.copy() x = Numeric.zeros(10, 'd') info, iter, relres = itsolvers.pcg(A, b, x, 1e-8, 100) print info, iter, relres # ----------------------------------------------------------- print 'remove test' n = 100 L = spmatrix.ll_mat(n, n) for run in range(5): print 'adding elements...' for i in range(0,n,2): for j in range (n): L[i,j] = i+j+1 # print L print L.nnz print 'removing elements...' for j in range(0,n,2): for i in range (n): L[i,j] = 0.0 # print L print L.nnz # ----------------------------------------------------------- print 'submatrix test' n = 100 L = spmatrix.ll_mat(n, n) for i in range (0, n, 2): for j in range (1, n, 2): L[i,j] = float(n*i + j); print L[10:18,75:80] print L[10:15,35:10] print L[19:15,35:10] # ----------------------------------------------------------- print 'submatrix assign test' n = 10 L = spmatrix.ll_mat(n, n); for i in range (0, n, 1): for j in range (0, n, 1): L[i,j] = 1.0; print L Z = spmatrix.ll_mat(n-2, n-2) L[1:n-1,1:n-1] = Z print L print L.nnz #------------------------------------------------------------ if 0: f = open(os.environ['HOME']+'/matrices/poi2d_300.mtx') t1 = time.clock() L = ll_mat_from_mtx(f) t_read = time.clock() - t1 f.close() print 'time for reading matrix data from file: %.2f sec' % t_read if 1: t1 = time.clock() L = spmatrix.ll_mat_from_mtx(os.environ['HOME']+'/matrices/poi2d_300.mtx') t_read = time.clock() - t1 print 'time for reading matrix data from file: %.2f sec' % t_read #------------------------------------------------------------ L = spmatrix.ll_mat_from_mtx(os.environ['HOME']+'/matrices/node4x3x1_A.mtx') print L.shape, L.nnz A = L.to_sss() class diag_prec: def __init__(self, A): self.shape = A.shape n = self.shape[0] self.dinv = Numeric.zeros(n, 'd') for i in xrange(n): self.dinv[i] = 1.0 / A[i,i] def precon(self, x, y): Numeric.multiply(x, self.dinv, y) def resid(A, b, x): r = x.copy() A.matvec(x, r) r = b - r return math.sqrt(Numeric.dot(r, r)) K_diag = diag_prec(A) K_jac = precon.jacobi(A, 1.0, 1) K_ssor = precon.ssor(A, 1.0, 1) # K_ilu = precon.ilutp(L) n = L.shape[0]; b = Numeric.arange(n).astype(Numeric.Float) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.pcg(A, b, x, 1e-6, 1000) print 'pcg, K_none: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.pcg(A, b, x, 1e-6, 1000, K_diag) print 'pcg, K_diag: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.pcg(A, b, x, 1e-6, 1000, K_jac) print 'pcg, K_jac: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.pcg(A, b, x, 1e-6, 1000, K_ssor) print 'pcg, K_ssor: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.minres(A, b, x, 1e-6, 1000) print 'minres, K_none: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.minres(A, b, x, 1e-6, 1000, K_diag) print 'minres, K_diag: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.minres(A, b, x, 1e-6, 1000, K_jac) print 'minres, K_jac: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.minres(A, b, x, 1e-6, 1000, K_ssor) print 'minres, K_ssor: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.qmrs(A, b, x, 1e-6, 1000) print 'qmrs, K_none: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.qmrs(A, b, x, 1e-6, 1000, K_diag) print 'qmrs, K_diag: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.qmrs(A, b, x, 1e-6, 1000, K_jac) print 'qmrs, K_jac: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.qmrs(A, b, x, 1e-6, 1000, K_ssor) print 'qmrs, K_ssor: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.cgs(A, b, x, 1e-6, 1000) print 'cgs, K_none: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.cgs(A, b, x, 1e-6, 1000, K_diag) print 'cgs, K_diag: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.cgs(A, b, x, 1e-6, 1000, K_jac) print 'cgs, K_jac: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.cgs(A, b, x, 1e-6, 1000, K_ssor) print 'cgs, K_ssor: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.bicgstab(A, b, x, 1e-6, 1000) print 'bicgstab, K_none: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.bicgstab(A, b, x, 1e-6, 1000, K_diag) print 'bicgstab, K_diag: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.bicgstab(A, b, x, 1e-6, 1000, K_jac) print 'bicgstab, K_jac: ', info, iter, relres, resid(A, b, x) x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.bicgstab(A, b, x, 1e-6, 1000, K_ssor) print 'bicgstab, K_ssor: ', info, iter, relres, resid(A, b, x) #------------------------------------------------------------ import superlu L = spmatrix.ll_mat_from_mtx(os.environ['HOME']+'/matrices/cop18_el3_A.mtx') ##f = open('cop18_el5_A.mtx') ##L = ll_mat_from_mtx(f) ##f.close() n11 = 4688 L = L[0:n11, 0:n11] # extract (1,1)-block # make matrix regular for i in xrange(n11): L[i,i] = 1 print L.shape, L.nnz n = L.shape[0] B = L.to_csr() su = superlu.factorize(B, diag_pivot_thresh=0.0) print su.nnz b = Numeric.arange(n).astype(Numeric.Float) / n x = Numeric.zeros(n, 'd') su.solve(b, x) print 'norm(b) = %g' % math.sqrt(Numeric.dot(b, b)) print 'norm(x) = %g' % math.sqrt(Numeric.dot(x, x)) r = Numeric.zeros(n, 'd') B.matvec(x, r) r = b - r print 'norm(b - A*x) = %g' % math.sqrt(Numeric.dot(r, r)) if 1: for panel_size in [5, 10, 15]: for relax in [1, 3, 5]: for permc_spec in [0, 1, 2]: for diag_pivot_thresh in [0.0, 0.5, 1.0]: t1 = time.clock() su = superlu.factorize(B, panel_size=panel_size, relax=relax, permc_spec=permc_spec, diag_pivot_thresh=diag_pivot_thresh) t_fact = time.clock() - t1 t1 = time.clock() su.solve(b, x) t_solve = time.clock() - t1 print 'panel_size=%2d, relax=%d, permc_spec=%d, diag_pivot_thresh=%.1f nnz=%d, t_fact=%.2f, t_solve=%.2f' % \ (panel_size, relax, permc_spec, diag_pivot_thresh, su.nnz, t_fact, t_solve) pysparse-1.1.1/Examples/sortedLL_test.py0000644010116400000240000000052411402270403017265 0ustar wd15dialoutfrom pysparse.spmatrix import * import RandomArray import time n = 1000 nnz = 50000 A = ll_mat(n, n, nnz) R = RandomArray.randint(0, n, (nnz,2)) t1 = time.clock() for k in xrange(nnz): A[R[k,0],R[k,1]] = k print 'Time for populating matrix: %8.2f sec' % (time.clock() - t1, ) print A.nnz B = A[:,:] A.shift(-1.0, B) print A pysparse-1.1.1/Examples/spmatrix_test.py0000644010116400000240000000601011402270401017376 0ustar wd15dialoutimport numpy as Numeric import traceback from pysparse import spmatrix_util, spmatrix def printMatrix(M): n, m = M.shape Z = Numeric.zeros((n,m), 'd') for i in range(n): for j in range(m): Z[i,j] = M[i,j] print str(Z) + '\n' n = 10 A = spmatrix.ll_mat(n,n) As = spmatrix.ll_mat_sym(n) Is = spmatrix.ll_mat_sym(n) I = spmatrix.ll_mat(n,n) Os = spmatrix.ll_mat_sym(n) O = spmatrix.ll_mat(n,n) for i in range(n): for j in range(n): if i >= j: A[i,j] = 10*i + j else: A[i,j] = 10*j + i O[i,j] = 1 for i in range(n): for j in range(n): if i >= j: As[i,j] = 10*i + j Os[i,j] = 1 for i in range(n): I[i,i] = 1 Is[i,i] = 1 print 'Setting matrix elements' printMatrix(A) printMatrix(As) print 'Extracting submatrices' printMatrix(A[4:8,1:3]) printMatrix(As[4:8,1:3]) printMatrix(A[1:3,4:8]) printMatrix(As[1:3,4:8]) printMatrix(A[6:9,6:9]) printMatrix(As[6:9,6:9]) print As[5:9,5:9] print print 'this should raise an execption...\n' try: As[5:9, 4:10] except: traceback.print_exc() print 'Setting submatrices' T = spmatrix.ll_mat_sym(n) T[6:9,6:9] = As[6:9,6:9] T[4:8,1:3] = As[4:8,1:3] printMatrix(T) print 'this should raise execptions...\n' try: T[6:9,6:9] = A[6:9,6:9] except: traceback.print_exc() try: T[5:9, 4:10] = A[5:9, 4:10] except: traceback.print_exc() print 'Matrix multiplications' printMatrix(spmatrix.matrixmultiply(I, A)) printMatrix(spmatrix.matrixmultiply(Is, A)) printMatrix(spmatrix.matrixmultiply(O, O)) printMatrix(spmatrix.matrixmultiply(Os, O)) print 'Dot product' printMatrix(spmatrix.dot(I, A)) print 'Matrix export' A[:4,:4].export_mtx('A.mtx', 3) As[:4,:4].export_mtx('As.mtx', 3) print open('A.mtx').read() print open('As.mtx').read() print 'Matrix import' printMatrix(spmatrix.ll_mat_from_mtx('A.mtx')) printMatrix(spmatrix.ll_mat_from_mtx('As.mtx')) print 'Conversion to CSR' print A[:4,:4] print A[:4,:4].to_csr() print As[:4,:4].to_csr() print 'update_add_mask operations' ind = Numeric.array([3, 4, 5, 6], 'i') mask = Numeric.array([1, 1, 1, 1], 'i') B = Numeric.ones((4,4), 'd') Ac = A.copy() Ac.update_add_mask(B, ind, ind, mask, mask) A.update_add_mask_sym(B, ind, mask) As.update_add_mask_sym(B, ind, mask) printMatrix(Ac[2:8,2:8]) printMatrix(A[2:8,2:8]) printMatrix(As[2:8,2:8]) print 'deleting rows' Atemp = A.copy() print 'original matrix:' printMatrix(Atemp) print 'Matrix with rows 7 and 8 and deleted:' mask = Numeric.ones(n, 'l') mask[7:9] = 0 Atemp.delete_rows(mask) printMatrix(Atemp) print Atemp.delete_rows.__doc__ print 'deleting rows and column' Atemp = As.copy() print 'original matrix:' printMatrix(Atemp) print 'Matrix with rows/cols 7 and 8 and deleted:' mask = Numeric.ones(n, 'l') mask[7:9] = 0 Atemp.delete_rowcols(mask) printMatrix(Atemp) nn = 100 R = spmatrix_util.ll_mat_rand(nn, nn, 0.3) ##print R.nnz for i in range(nn-5): mask = Numeric.ones(nn, 'l') mask[0] = 0 R.delete_rowcols(mask) nn -= 1 ##print R pysparse-1.1.1/Examples/ssor_test.py0000644010116400000240000000163611402270402016527 0ustar wd15dialoutimport math, time import Numeric from pysparse import spmatrix, itsolvers, precon, poisson N = 200 TOL = 1e-8 MAXIT = 800 SSOR_STEPS = 2 L = poisson.poisson2d_sym_blk(N) S = L.to_sss() b = Numeric.ones(N*N, 'd') print 'Solving 2D-Laplace equation using PCG and SSOR preconditioner with variable omega' print print 'omega nit time resid' print '--------------------------------' for omega in [0.1*(i+1) for i in range(20)]: K_ssor = precon.ssor(S, omega, SSOR_STEPS) t1 = time.clock() x = Numeric.zeros(N*N, 'd') info, iter, relres = itsolvers.pcg(S, b, x, TOL, MAXIT, K_ssor) elapsed_time = time.clock() - t1 r = Numeric.zeros(N*N, 'd') S.matvec(x, r) r = b - r res_nrm2 = math.sqrt(Numeric.dot(r, r)) if info == 0: iter_str = str(iter) else: iter_str = '---' print '%5.1f %5s %6.2f %10.3e' % (omega, iter_str, elapsed_time, res_nrm2) pysparse-1.1.1/Examples/tendigit.py0000644010116400000240000000160411402270401016303 0ustar wd15dialout""" Solves problem 7 of the One Hundred Dollars, One Hundred Digits Challenge """ import Numeric from pysparse import spmatrix, itsolvers, precon def get_primes(nofPrimes): primes = Numeric.zeros(nofPrimes, 'i') primes[0] = 2 nof = 1 i = 3 while 1: for p in primes[:nof]: if i%p == 0 or p*p > i: break if i%p <> 0: primes[nof] = i nof += 1 if nof >= nofPrimes: break i = i+2 return primes n = 20000 primes = get_primes(n) A = spmatrix.ll_mat_sym(n, n*8) d = 1 while d < n: for i in range(d, n): A[i,i-d] = 1.0 d *= 2 for i in range(n): A[i,i] = primes[i] A = A.to_sss() K = precon.ssor(A) b = Numeric.zeros(n, 'd'); b[0] = 1.0 x = Numeric.zeros(n, 'd') info, iter, relres = itsolvers.minres(A, b, x, 1e-16, n, K) print info, iter, relres print '%.16e' % x[0] pysparse-1.1.1/Examples/umftest.py0000644010116400000240000000141111402270403016161 0ustar wd15dialoutfrom pysparse import spmatrix from pysparse import umfpack import numpy as Numeric from pysparse import poisson l = spmatrix.ll_mat(5, 5) l[0,0] = 2.0 l[0,1] = 3.0 l[1,4] = 6.0 l[1,0] = 3.0 l[1,2] = 4.0 l[2,1] = -1.0 l[2,2] = -3.0 l[2,3] = 2.0 l[3,2] = 1.0 l[4,1] = 4.0 l[4,2] = 2.0 l[4,4] = 1.0 b = Numeric.array([8.0, 45.0, -3.0, 3.0, 19.0], "d") x = Numeric.zeros(5, "d") umf = umfpack.factorize(l) umf.solve(b, x, 'UMFPACK_A') print umf.getlists() print x print "------------------------------" n = 50 L = poisson.poisson2d_sym_blk(n) b = Numeric.ones(n * n, 'd') x = Numeric.zeros(n * n, 'd') umf = umfpack.factorize(L) umf.solve(b, x, 'UMFPACK_A') r = Numeric.zeros(n * n, 'd') L.matvec(x, r) r = b - r print 'norm(b - A * x) = %f' % Numeric.sqrt(Numeric.dot(r, r)) pysparse-1.1.1/Include/0000755010116400000240000000000011402271037013734 5ustar wd15dialoutpysparse-1.1.1/Include/pysparse/0000755010116400000240000000000011402271040015574 5ustar wd15dialoutpysparse-1.1.1/Include/pysparse/bicgstab.h0000644010116400000240000000054311402267755017547 0ustar wd15dialout#ifndef BICGSTAB_H #define BICGSTAB_H #include "Python.h" int Itsolvers_bicgstab_kernel(int n, double *x, double *b, double tol, int maxit, int clvl, int *iter, double *relres, int *flag, double *work, PyObject *mat_obj, PyObject *prec_obj); #endif pysparse-1.1.1/Include/pysparse/blas.h0000644010116400000240000006001411402267756016712 0ustar wd15dialout#ifndef _BLAS_H #define _BLAS_H #include "fortran.h" #define integer int #define real float #define doublereal double #define character char #define logical int #define ftnlen int typedef struct { real r, i; } complex; typedef struct { doublereal r, i; } doublecomplex; complex F77(cdotc)(integer *,complex *,integer *,complex *,integer *), F77(cdotu)(integer *,complex *,integer *,complex *,integer *); void F77(caxpy)(integer *,complex *,complex *,integer *,complex *, integer *), F77(ccopy)(integer *,complex *,integer *,complex *,integer *), F77(cgbmv)(character *,integer *,integer *,integer *,integer *, complex *, complex *,integer *,complex *,integer *, complex *,complex *,integer *,ftnlen), F77(cgemm)(character *,character *,integer *,integer *, integer *,complex *,complex *,integer *,complex *, integer *,complex *,complex *,integer *,ftnlen, ftnlen), F77(cgemv)(character *,integer *,integer *,complex *,complex *, integer *,complex *,integer *,complex *,complex *, integer *,ftnlen), F77(cgerc)(integer *,integer *,complex *,complex *,integer *, complex *,integer *,complex *,integer *), F77(cgeru)(integer *,integer *,complex *,complex *,integer *, complex *,integer *,complex *,integer *), F77(chbmv)(character *,integer *,integer *,complex *,complex *, integer *,complex *,integer *,complex *,complex *, integer *,ftnlen), F77(chemm)(character *,character *,integer *,integer *, complex *,complex *,integer *,complex *,integer *, complex *,complex *,integer *,ftnlen,ftnlen), F77(chemv)(character *,integer *,complex *,complex *,integer *, complex *,integer *,complex *,complex *,integer *, ftnlen), F77(cher)(character *,integer *,real *,complex *,integer *, complex *,integer *,ftnlen), F77(cher2)(character *,integer *,complex *,complex *,integer *, complex *,integer *,complex *,integer *,ftnlen), F77(cher2k)(character *,character *,integer *,integer *, complex *,complex *,integer *,complex *,integer *, real *,complex *,integer *,ftnlen,ftnlen), F77(cherk)(character *,character *,integer *,integer *,real *, complex *,integer *,real *,complex *,integer *, ftnlen,ftnlen), F77(chpmv)(character *,integer *,complex *,complex *,complex *, integer *,complex *,complex *,integer *,ftnlen), F77(chpr)(character *,integer *,real *,complex *,integer *, complex *,ftnlen), F77(chpr2)(character *,integer *,complex *,complex *,integer *, complex *,integer *,complex *,ftnlen), F77(crotg)(complex *,complex *,real *,complex *), F77(cscal)(integer *,complex *,complex *,integer *), F77(csscal)(integer *,real *,complex *,integer *), F77(cswap)(integer *,complex *,integer *,complex *,integer *), F77(csymm)(character *,character *,integer *,integer *, complex *,complex *,integer *,complex *,integer *, complex *,complex *,integer *,ftnlen,ftnlen), F77(csyr2k)(character *,character *,integer *,integer *, complex *,complex *,integer *,complex *,integer *, complex *,complex *,integer *,ftnlen,ftnlen), F77(csyrk)(character *,character *,integer *,integer *, complex *,complex *,integer *,complex *,complex *, integer *,ftnlen,ftnlen), F77(ctbmv)(character *,character *,character *,integer *, integer *,complex *,integer *,complex *,integer *, ftnlen,ftnlen,ftnlen), F77(ctbsv)(character *,character *,character *,integer *, integer *,complex *,integer *,complex *,integer *, ftnlen,ftnlen,ftnlen), F77(ctpmv)(character *,character *,character *,integer *, complex *,complex *,integer *,ftnlen,ftnlen,ftnlen), F77(ctpsv)(character *,character *,character *,integer *, complex *,complex *,integer *,ftnlen,ftnlen,ftnlen), F77(ctrmm)(character *,character *,character *,character *, integer *,integer *,complex *,complex *,integer *, complex *,integer *,ftnlen,ftnlen,ftnlen,ftnlen), F77(ctrmv)(character *,character *,character *,integer *, complex *,integer *,complex *,integer *,ftnlen, ftnlen,ftnlen), F77(ctrsm)(character *,character *,character *,character *, integer *,integer *,complex *,complex *,integer *, complex *,integer *,ftnlen,ftnlen,ftnlen,ftnlen), F77(ctrsv)(character *,character *,character *,integer *, complex *,integer *,complex *,integer *,ftnlen, ftnlen,ftnlen); doublereal F77(dasum)(integer *,doublereal *,integer *); void F77(daxpy)(integer *,doublereal *,doublereal *,integer *, doublereal *,integer *); doublereal F77(dcabs1)(doublecomplex *); void F77(dcopy)(integer *,doublereal *,integer *,doublereal *, integer *); doublereal F77(ddot)(integer *,doublereal *,integer *,doublereal *, integer *); void F77(dgbmv)(character *,integer *,integer *,integer *,integer *, doublereal *,doublereal *,integer *,doublereal *, integer *,doublereal *,doublereal *,integer *, ftnlen), F77(dgemm)(character *,character *,integer *,integer *, integer *,doublereal *,doublereal *,integer *, doublereal *,integer *,doublereal *,doublereal *, integer *,ftnlen,ftnlen), F77(dgemv)(character *,integer *,integer *,doublereal *, doublereal *,integer *,doublereal *,integer *, doublereal *,doublereal *,integer *,ftnlen), F77(dger)(integer *,integer *,doublereal *,doublereal *, integer *,doublereal *,integer *,doublereal *, integer *); doublereal F77(dnrm2)(integer *,doublereal *,integer *); void F77(drot)(integer *,doublereal *,integer *,doublereal *, integer *,doublereal *,doublereal *), F77(drotg)(doublereal *,doublereal *,doublereal *, doublereal *), F77(dsbmv)(character *,integer *,integer *,doublereal *, doublereal *,integer *,doublereal *,integer *, doublereal *,doublereal *,integer *,ftnlen), F77(dscal)(integer *,doublereal *,doublereal *,integer *), F77(dspmv)(character *,integer *,doublereal *,doublereal *, doublereal *,integer *,doublereal *,doublereal *, integer *,ftnlen), F77(dspr)(character *,integer *,doublereal *,doublereal *, integer *,doublereal *,ftnlen), F77(dspr2)(character *,integer *,doublereal *,doublereal *, integer *,doublereal *,integer *,doublereal *, ftnlen), F77(dswap)(integer *n,doublereal *,integer *,doublereal *, integer *), F77(dsymm)(character *,character *,integer *,integer *, doublereal *,doublereal *,integer *,doublereal *, integer *,doublereal *,doublereal *,integer *, ftnlen,ftnlen), F77(dsymv)(character *,integer *,doublereal *,doublereal *, integer *,doublereal *,integer *,doublereal *, doublereal *,integer *,ftnlen), F77(dsyr)(character *,integer *,doublereal *,doublereal *, integer *,doublereal *,integer *,ftnlen), F77(dsyr2)(character *,integer *,doublereal *,doublereal *, integer *,doublereal *,integer *,doublereal *, integer *,ftnlen), F77(dsyr2k)(character *,character *,integer *,integer *, doublereal *,doublereal *,integer *,doublereal *, integer *,doublereal *,doublereal *,integer *, ftnlen,ftnlen), F77(dsyrk)(character *,character *,integer *,integer *, doublereal *,doublereal *,integer *,doublereal *, doublereal *,integer *,ftnlen,ftnlen), F77(dtbmv)(character *,character *,character *,integer *, integer *,doublereal *,integer *,doublereal *, integer *,ftnlen,ftnlen,ftnlen), F77(dtbsv)(character *,character *,character *,integer *, integer *,doublereal *,integer *,doublereal *, integer *,ftnlen,ftnlen,ftnlen), F77(dtpmv)(character *,character *,character *,integer *, doublereal *,doublereal *,integer *,ftnlen,ftnlen, ftnlen), F77(dtpsv)(character *,character *,character *,integer *, doublereal *,doublereal *,integer *,ftnlen,ftnlen, ftnlen), F77(dtrmm)(character *,character *,character *,character *, integer *,integer *,doublereal *,doublereal *, integer *,doublereal *,integer *,ftnlen,ftnlen, ftnlen,ftnlen), F77(dtrmv)(character *,character *,character *,integer *, doublereal *,integer *,doublereal *,integer *, ftnlen,ftnlen,ftnlen), F77(dtrsm)(character *,character *,character *,character *, integer *,integer *,doublereal *,doublereal *, integer *,doublereal *,integer *,ftnlen,ftnlen, ftnlen,ftnlen), F77(dtrsv)(character *,character *,character *,integer *, doublereal *,integer *,doublereal *,integer *, ftnlen,ftnlen,ftnlen); doublereal F77(dzasum)(integer *,doublecomplex *,integer *), F77(dznrm2)(integer *, doublecomplex *,integer *); real F77(sasum)(integer *,real *,integer *), F77(scasum)(integer *,complex *,integer *), F77(snrm2)(integer *,real *,integer *), F77(scnrm2)(integer *,complex *,integer *), F77(sdot)(integer *,real *,integer *,real *,integer *); extern void F77(sgemm)(character *,character *,integer *,integer *, integer *,real *,real *,integer *,real *,integer *, real *,real *,integer *,ftnlen,ftnlen), F77(sscal)(integer *,real *,real *,integer *), F77(ssyr)(character *,integer *,real *,real *,integer *,real *, integer *,ftnlen), F77(stpsv)(character *,character *,character *,integer *, real *,real *,integer *,ftnlen,ftnlen,ftnlen), F77(saxpy)(integer *,real *,real *,integer *,real *,integer *), F77(sgemv)(character *,integer *,integer *,real *,real *, integer *,real *,integer *,real *,real *,integer *, ftnlen), F77(sspmv)(character *,integer *,real *,real *,real *, integer *,real *,real *,integer *,ftnlen), F77(ssyr2)(character *,integer *,real *,real *,integer *, real *,integer *,real *,integer *,ftnlen), F77(strmm)(character *,character *,character *,character *, integer *,integer *,real *,real *,integer *,real *, integer *,ftnlen,ftnlen,ftnlen,ftnlen), F77(sger)(integer *,integer *,real *,real *,integer *,real *, integer *,real *,integer *), F77(sspr)(character *,integer *,real *,real *,integer *,real *, ftnlen), F77(ssyr2k)(character *u,character *,integer *,integer *, real *,real *,integer *,real *,integer *,real *, real *,integer *,ftnlen,ftnlen), F77(strmv)(character *,character *,character *,integer *, real *,integer *,real *,integer *,ftnlen,ftnlen, ftnlen), F77(sspr2)(character *,integer *,real *,real *,integer *, real *,integer *,real *,ftnlen), F77(ssyrk)(character *,character *,integer *,integer *,real *, real *,integer *,real *,real *,integer *,ftnlen, ftnlen), F77(strsm)(character *,character *,character *,character *, integer *,integer *,real *,real *,integer *,real *, integer *,ftnlen,ftnlen,ftnlen,ftnlen), F77(scopy)(integer *,real *,integer *,real *,integer *), F77(srot)(integer *,real *,integer *,real *,integer *,real *, real *), F77(sswap)(integer *,real *,integer *,real *,integer *), F77(stbmv)(character *,character *,character *,integer *n, integer *,real *,integer *,real *,integer *,ftnlen, ftnlen,ftnlen), F77(strsv)(character *,character *,character *,integer *, real *,integer *,real *,integer *,ftnlen,ftnlen, ftnlen), F77(srotg)(real *,real *,real *,real *), F77(ssymm)(character *,character *,integer *,integer *,real *, real *,integer *,real *,integer *,real *,real *, integer *,ftnlen,ftnlen), F77(stbsv)(character *,character *,character *,integer *, integer *,real *,integer *,real *,integer *,ftnlen, ftnlen,ftnlen), F77(sgbmv)(character *,integer *,integer *,integer *,integer *, real *,real *,integer *,real *,integer *,real *, real *,integer *,ftnlen), F77(ssbmv)(character *,integer *,integer *,real *,real *, integer *,real *,integer *,real *,real *,integer *, ftnlen), F77(ssymv)(character *,integer *,real *,real *,integer *, real *,integer *,real *,real *,integer *, ftnlen), F77(stpmv)(character *,character *,character *,integer *, real *,real *,integer *,ftnlen,ftnlen,ftnlen); doublecomplex F77(zdotc)(doublecomplex *,integer *,doublecomplex *,integer *, doublecomplex *,integer *), F77(zdotu)(doublecomplex *,integer *,doublecomplex *,integer *, doublecomplex *,integer *); void F77(zaxpy)(integer *,doublecomplex *,doublecomplex *,integer *, doublecomplex *,integer *), F77(zgemv)(character *,integer *,integer *,doublecomplex *, doublecomplex *,integer *,doublecomplex *,integer *, doublecomplex *,doublecomplex *,integer *,ftnlen), F77(zher2)(character *,integer *,doublecomplex *, doublecomplex *,integer *,doublecomplex *,integer *, doublecomplex *,integer *,ftnlen), F77(zscal)(integer *,doublecomplex *,doublecomplex *, integer *), F77(ztpmv)(character *,character *,character *,integer *, doublecomplex *,doublecomplex *,integer *,ftnlen, ftnlen,ftnlen), F77(zcopy)(integer *,doublecomplex *,integer *,doublecomplex *, integer *), F77(zgerc)(integer *,integer *,doublecomplex *,doublecomplex *, integer *,doublecomplex *,integer *,doublecomplex *, integer *), F77(zher2k)(character *,character *,integer *,integer *, doublecomplex *,doublecomplex *,integer *, doublecomplex *,integer *,doublereal *, doublecomplex *,integer *,ftnlen,ftnlen), F77(zswap)(integer *,doublecomplex *,integer *,doublecomplex *, integer *), F77(ztpsv)(character *,character *,character *,integer *, doublecomplex *,doublecomplex *,integer *,ftnlen, ftnlen,ftnlen), F77(zgeru)(integer *,integer *,doublecomplex *,doublecomplex *, integer *,doublecomplex *,integer *,doublecomplex *, integer *), F77(zherk)(character *,character *,integer *,integer *, doublereal *,doublecomplex *,integer *,doublereal *, doublecomplex *,integer *,ftnlen,ftnlen), F77(zsymm)(character *,character *,integer *,integer *, doublecomplex *,doublecomplex *,integer *, doublecomplex *,integer *,doublecomplex *, doublecomplex *,integer *,ftnlen,ftnlen), F77(ztrmm)(character *,character *,character *,character *, integer *,integer *,doublecomplex *,doublecomplex *, integer *,doublecomplex *,integer *,ftnlen,ftnlen, ftnlen,ftnlen), F77(zhbmv)(character *,integer *,integer *,doublecomplex *, doublecomplex *,integer *,doublecomplex *,integer *, doublecomplex *,doublecomplex *,integer *,ftnlen), F77(zhpmv)(character *,integer *,doublecomplex *, doublecomplex *,doublecomplex *,integer *, doublecomplex *,doublecomplex *,integer *,ftnlen), F77(zsyr2k)(character *,character *,integer *,integer *, doublecomplex *,doublecomplex *,integer *, doublecomplex *,integer *,doublecomplex *, doublecomplex *,integer *,ftnlen,ftnlen), F77(ztrmv)(character *,character *,character *,integer *, doublecomplex *,integer *,doublecomplex *,integer *, ftnlen,ftnlen,ftnlen), F77(zdscal)(integer *,doublecomplex *,doublecomplex *, integer *), F77(zhemm)(character *,character *,integer *,integer *, doublecomplex *,doublecomplex *,integer *, doublecomplex *,integer *,doublecomplex *, doublecomplex *,integer *,ftnlen,ftnlen), F77(zhpr)(character *,integer *,doublereal *,doublecomplex *, integer *,doublecomplex *,ftnlen), F77(zsyrk)(character *,character *,integer *,integer *, doublecomplex *,doublecomplex *,integer *, doublecomplex *,doublecomplex *,integer *,ftnlen, ftnlen), F77(ztrsm)(character *,character *,character *,character *, integer *,integer *,doublecomplex *,doublecomplex *, integer *,doublecomplex *,integer *,ftnlen,ftnlen, ftnlen,ftnlen), F77(zgbmv)(character *,integer *,integer *,integer *,integer *, doublecomplex *,doublecomplex *,integer *, doublecomplex *,integer *,doublecomplex *, doublecomplex *,integer *,ftnlen), F77(zhemv)(character *,integer *,doublecomplex *, doublecomplex *,integer *,doublecomplex *,integer *, doublecomplex *,doublecomplex *,integer *,ftnlen), F77(zhpr2)(character *,integer *,doublecomplex *, doublecomplex *,integer *,doublecomplex *,integer *, doublecomplex *,ftnlen), F77(ztbmv)(character *,character *,character *,integer *, integer *,doublecomplex *,integer *,doublecomplex *, integer *,ftnlen,ftnlen,ftnlen), F77(ztrsv)(character *,character *,character *,integer *, doublecomplex *,integer *,doublecomplex *,integer *, ftnlen,ftnlen,ftnlen), F77(zgemm)(character *,character *,integer *,integer *, integer *,doublecomplex *,doublecomplex *,integer *, doublecomplex *,integer *,doublecomplex *, doublecomplex *,integer *,ftnlen,ftnlen), F77(zher)(character *,integer *,doublereal *,doublecomplex *, integer *,doublecomplex *,integer *,ftnlen), F77(zrotg)(doublecomplex *,doublecomplex *,doublereal *, doublecomplex *), F77(ztbsv)(character *,character *,character *,integer *, integer *,doublecomplex *,integer *,doublecomplex *, integer *,ftnlen,ftnlen,ftnlen); integer F77(icamax)(integer *,complex *,integer *), F77(idamax)(integer *,doublereal *,integer *), F77(isamax)(integer *,real *,integer *), F77(izamax)(integer *,doublecomplex *,integer *), F77(lsame)(character *,character *,ftnlen,ftnlen); void F77(xerbla)(character *,integer *,ftnlen); #undef integer #undef real #undef doublereal #undef character #undef logical #undef ftnlen #endif /* _BLAS_H */ pysparse-1.1.1/Include/pysparse/cgs.h0000644010116400000240000000037511402267754016547 0ustar wd15dialout#ifndef CGS_H #define CGS_H #include int Itsolvers_cgs_kernel(int n, double *b, double *x, int maxit, double tol, double *work, int *iter, double *res, PyObject *mat_obj, PyObject *prec_obj); #endif pysparse-1.1.1/Include/pysparse/csr_mat.h0000644010116400000240000000075211402267757017425 0ustar wd15dialout#ifndef CSR_MAT_H #define CSR_MAT_H #include "Python.h" typedef struct { PyObject_VAR_HEAD int dim[2]; /* array dimension */ int nnz; /* number of stored items */ double *val; /* pointer to array of values */ int *col; /* pointer to array of indices */ int *ind; /* pointer to array of indices */ } CSRMatObject; #ifdef SPMATRIX_MODULE /* forward declarations */ static PyTypeObject CSRMatType; static PyObject *newCSRMatObject(int dim[], int nnz); #endif #endif pysparse-1.1.1/Include/pysparse/dsp_defs.h0000644010116400000240000002263711402267756017571 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #ifndef __SUPERLU_dSP_DEFS /* allow multiple inclusions */ #define __SUPERLU_dSP_DEFS /* * File name: dsp_defs.h * Purpose: Sparse matrix types and function prototypes * History: */ #ifdef _CRAY #include #include #endif #include "Cnames.h" #include "supermatrix.h" /* No of marker arrays used in the symbolic factorization, each of size n */ #define NO_MARKER 3 #define NUM_TEMPV(m,w,t,b) ( MAX(m, (t + b)*w) ) typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; typedef enum {HEAD, TAIL} stack_end_t; typedef enum {SYSTEM, USER} LU_space_t; /* * Global data structures used in LU factorization - * * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. * (xsup,supno): supno[i] is the supernode no to which i belongs; * xsup(s) points to the beginning of the s-th supernode. * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) * xsup 0 1 2 4 7 12 * Note: dfs will be performed on supernode rep. relative to the new * row pivoting ordering * * (xlsub,lsub): lsub[*] contains the compressed subscript of * rectangular supernodes; xlsub[j] points to the starting * location of the j-th column in lsub[*]. Note that xlsub * is indexed by column. * Storage: original row subscripts * * During the course of sparse LU factorization, we also use * (xlsub,lsub) for the purpose of symmetric pruning. For each * supernode {s,s+1,...,t=s+r} with first column s and last * column t, the subscript set * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 * is the structure of column s (i.e. structure of this supernode). * It is used for the storage of numerical values. * Furthermore, * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 * is the structure of the last column t of this supernode. * It is for the purpose of symmetric pruning. Therefore, the * structural subscripts can be rearranged without making physical * interchanges among the numerical values. * * However, if the supernode has only one column, then we * only keep one set of subscripts. For any subscript interchange * performed, similar interchange must be done on the numerical * values. * * The last column structures (for pruning) will be removed * after the numercial LU factorization phase. * * (xlusup,lusup): lusup[*] contains the numerical values of the * rectangular supernodes; xlusup[j] points to the starting * location of the j-th column in storage vector lusup[*] * Note: xlusup is indexed by column. * Each rectangular supernode is stored by column-major * scheme, consistent with Fortran 2-dim array storage. * * (xusub,ucol,usub): ucol[*] stores the numerical values of * U-columns outside the rectangular supernodes. The row * subscript of nonzero ucol[k] is stored in usub[k]. * xusub[i] points to the starting location of column i in ucol. * Storage: new row subscripts; that is subscripts of PA. */ typedef struct { int *xsup; /* supernode and column mapping */ int *supno; int *lsub; /* compressed L subscripts */ int *xlsub; double *lusup; /* L supernodes */ int *xlusup; double *ucol; /* U columns */ int *usub; int *xusub; int nzlmax; /* current max size of lsub */ int nzumax; /* " " " ucol */ int nzlumax; /* " " " lusup */ int n; /* number of columns in the matrix */ LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ } GlobalLU_t; typedef struct { int panel_size; int relax; double diag_pivot_thresh; double drop_tol; } factor_param_t; typedef struct { float for_lu; float total_needed; int expansions; } mem_usage_t; #ifdef __cplusplus extern "C" { #endif /* Driver routines */ extern void dgssv(SuperMatrix *, int *, int *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *); extern void dgssvx(char *, char *, char *, SuperMatrix *, factor_param_t *, int *, int *, int *, char *, double *, double *, SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, double *, double *, double *, double *, mem_usage_t *, int *); /* Supernodal LU factor related */ extern void dCreate_CompCol_Matrix(SuperMatrix *, int, int, int, double *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void dCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); extern void dCreate_Dense_Matrix(SuperMatrix *, int, int, double *, int, Stype_t, Dtype_t, Mtype_t); extern void dCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, double *, int *, int *, int *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void dCopy_Dense_Matrix(int, int, double *, int, double *, int); extern void Destroy_SuperMatrix_Store(SuperMatrix *); extern void Destroy_CompCol_Matrix(SuperMatrix *); extern void Destroy_SuperNode_Matrix(SuperMatrix *); extern void Destroy_CompCol_Permuted(SuperMatrix *); extern void Destroy_Dense_Matrix(SuperMatrix *); extern void get_perm_c(int, SuperMatrix *, int *); extern void sp_preorder (char*, SuperMatrix*, int*, int*, SuperMatrix*); extern void countnz (const int, int *, int *, int *, GlobalLU_t *); extern void fixupL (const int, const int *, GlobalLU_t *); extern void dallocateA (int, int, double **, int **, int **); extern void dgstrf (char*, SuperMatrix*, double, double, int, int, int*, void *, int, int *, int *, SuperMatrix *, SuperMatrix *, int *); extern int dsnode_dfs (const int, const int, const int *, const int *, const int *, int *, int *, GlobalLU_t *); extern int dsnode_bmod (const int, const int, const int, double *, double *, GlobalLU_t *); extern void dpanel_dfs (const int, const int, const int, SuperMatrix *, int *, int *, double *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern void dpanel_bmod (const int, const int, const int, const int, double *, double *, int *, int *, GlobalLU_t *); extern int dcolumn_dfs (const int, const int, int *, int *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern int dcolumn_bmod (const int, const int, double *, double *, int *, int *, int, GlobalLU_t *); extern int dcopy_to_ucol (int, int, int *, int *, int *, double *, GlobalLU_t *); extern int dpivotL (const int, const double, int *, int *, int *, int *, int *, GlobalLU_t *); extern void dpruneL (const int, const int *, const int, const int, const int *, const int *, int *, GlobalLU_t *); extern void dreadmt (int *, int *, int *, double **, int **, int **); extern void dGenXtrue (int, int, double *, int); extern void dFillRHS (char *, int, double *, int, SuperMatrix *, SuperMatrix *); extern void dgstrs (char *, SuperMatrix *, SuperMatrix *, int *, int *, SuperMatrix *, int *); /* Driver related */ extern void dgsequ (SuperMatrix *, double *, double *, double *, double *, double *, int *); extern void dlaqgs (SuperMatrix *, double *, double *, double, double, double, char *); extern void dgscon (char *, SuperMatrix *, SuperMatrix *, double, double *, int *); extern double dPivotGrowth(int, SuperMatrix *, int *, SuperMatrix *, SuperMatrix *); extern void dgsrfs (char *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *, int *, char *, double *, double *, SuperMatrix *, SuperMatrix *, double *, double *, int *); extern int sp_dtrsv (char *, char *, char *, SuperMatrix *, SuperMatrix *, double *, int *); extern int sp_dgemv (char *, double, SuperMatrix *, double *, int, double, double *, int); extern int sp_dgemm (char *, char *, int, int, int, double, SuperMatrix *, double *, int, double, double *, int); /* Memory-related */ extern int dLUMemInit (char *, void *, int, int, int, int, int, SuperMatrix *, SuperMatrix *, GlobalLU_t *, int **, double **); extern void dSetRWork (int, int, double *, double **, double **); extern void dLUWorkFree (int *, double *, GlobalLU_t *); extern int dLUMemXpand (int, int, MemType, int *, GlobalLU_t *); extern double *doubleMalloc(int); extern double *doubleCalloc(int); extern int dmemory_usage(const int, const int, const int, const int); extern int dQuerySpace (SuperMatrix *, SuperMatrix *, int, mem_usage_t *); /* Auxiliary routines */ extern void dreadhb(int *, int *, int *, double **, int **, int **); extern void dCompRow_to_CompCol(int, int, int, double*, int*, int*, double **, int **, int **); extern void dfill (double *, int, double); extern void dinf_norm_error (int, SuperMatrix *, double *); extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, double, double, double *, double *, char *); /* Routines for debugging */ extern void dPrint_CompCol_Matrix(char *, SuperMatrix *); extern void dPrint_SuperNode_Matrix(char *, SuperMatrix *); extern void dPrint_Dense_Matrix(char *, SuperMatrix *); extern void print_lu_col(char *, int, int, int *, GlobalLU_t *); extern void check_tempv(int, double *); #ifdef __cplusplus } #endif #endif /* __SUPERLU_dSP_DEFS */ pysparse-1.1.1/Include/pysparse/fortran.h0000644010116400000240000000071511402267754017444 0ustar wd15dialout#ifndef FORTRAN_H #define FORTRAN_H #if defined(NOF77UNDERSCORE) #define F77(s) s #elif defined (F77UPPERCASE) #define F77(s) s #define dgemv DGEMV #define dgetrf DGETRF #define dgetrs DGETRS #define dscal DSCAL #define ilaenv ILAENV #define dsyev DSYEV #define dgemm DGEMM #define daxpy DAXPY #define dnrm2 DNRM2 #define dcopy DCOPY #define ddot DDOT #define dlaset DLASET #define dlacpy DLACPY #define dlarnv DLARNV #else #define F77(s) s##_ #endif #endif pysparse-1.1.1/Include/pysparse/gmres.h0000644010116400000240000000350211402267755017104 0ustar wd15dialout/************************************************************************** * * * Swiss Federal Institute of Technology (ETH), * * CH-8092 Zuerich, Switzerland * * * * (C) 1999 All Rights Reserved * * * * NOTICE * * * * Permission to use, copy, modify, and distribute this software and * * its documentation for any purpose and without fee is hereby granted * * provided that the above copyright notice appear in all copies and * * that both the copyright notice and this permission notice appear in * * supporting documentation. * * * * Neither the Swiss Federal Institute of Technology nor the author make * * any representations about the suitability of this software for any * * purpose. This software is provided ``as is'' without express or * * implied warranty. * * * **************************************************************************/ #ifndef GMRES_H #define GMRES_H #include "Python.h" int Itsolvers_gmres_kernel(int n, double errtol, int it_max, int *it, double *relres, int dim, double *x, double *b, double *work, PyObject *mat_obj, PyObject *prec_obj); #endif pysparse-1.1.1/Include/pysparse/lapack.h0000644010116400000240000026201711402267751017226 0ustar wd15dialout#ifndef LAPACK_H #define LAPACK_H #include "fortran.h" /* typedefs for the FORTRAN COMPLEX*8 and COMPLEX*16 data types */ /* COMPLEX*8 type */ #ifndef __COMPLEX8_T #define __COMPLEX8_T 1 typedef struct { float re, im; } complex8_t; #endif /* COMPLEX*16 type */ #ifndef __COMPLEX16_T #define __COMPLEX16_T 1 typedef struct { double re, im; } complex16_t; #endif extern void F77(cgbcon)(char* norm, int* n, int* kl, int* ku, complex8_t ab[], int* ldab, int ipiv[], float* anorm, float* rcond, complex8_t work[], float rwork[], int* info, int len_norm); extern void F77(cgbsv)(int* n, int* kl, int* ku, int* nrhs, complex8_t ab[], int* ldab, int ipiv[], complex8_t b[], int* ldb, int* info); extern void F77(cgbsvx)(char* fact, char* trans, int* n, int* kl, int* ku, int* nrhs, complex8_t ab[], int* ldab, complex8_t afb[], int* ldafb, int ipiv[], char* equed, float r[], float c[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(cgbtrf)(int* m, int* n, int* kl, int* ku, complex8_t ab[], int* ldab, int ipiv[], int* info); extern void F77(cgbtrs)(char* trans, int* n, int* kl, int* ku, int* nrhs, complex8_t ab[], int* ldab, int ipiv[], complex8_t b[], int* ldb, int* info, int len_trans); extern void F77(cgecon)(char* norm, int* n, complex8_t a[], int* lda, float* anorm, float* rcond, complex8_t work[], float rwork[], int* info, int len_norm); extern void F77(cgees)(char* jobvs, char* sort, int (*select)(), int* n, complex8_t a[], int* lda, int* sdim, complex8_t w[], complex8_t vs[], int* ldvs, complex8_t work[], int* lwork, float rwork[], int bwork[], int* info, int len_jobvs, int len_sort); extern void F77(cgeesx)(char* jobvs, char* sort, int (*select)(), char* sense, int* n, complex8_t a[], int* lda, int* sdim, complex8_t w[], complex8_t vs[], int* ldvs, float* rconde, float* rcondv, complex8_t work[], int* lwork, float rwork[], int bwork[], int* info, int len_jobvs, int len_sort, int len_sense); extern void F77(cgeev)(char* jobvl, char* jobvr, int* n, complex8_t a[], int* lda, complex8_t w[], complex8_t vl[], int* ldvl, complex8_t vr[], int* ldvr, complex8_t work[], int* lwork, float rwork[], int* info, int len_jobvl, int len_jobvr); extern void F77(cgeevx)(char* balanc, char* jobvl, char* jobvr, char* sense, int* n, complex8_t a[], int* lda, complex8_t w[], complex8_t vl[], int* ldvl, complex8_t vr[], int* ldvr, int* ilo, int* ihi, float scale[], float* abnrm, float rconde[], float rcondv[], complex8_t work[], int* lwork, float rwork[], int* info, int len_balanc, int len_jobvl, int len_jobvr, int len_sense); extern void F77(cgegs)(char* jobvsl, char* jobvsr, int* n, complex8_t a[], int* lda, complex8_t b[], int* ldb, complex8_t alpha[], complex8_t beta[], complex8_t vsl[], int* ldvsl, complex8_t vsr[], int* ldvsr, complex8_t work[], int* lwork, float rwork[], int* info, int len_jobvsl, int len_jobvsr); extern void F77(cgegv)(char* jobvl, char* jobvr, int* n, complex8_t a[], int* lda, complex8_t b[], int* ldb, complex8_t alpha[], complex8_t beta[], complex8_t vl[], int* ldvl, complex8_t vr[], int* ldvr, complex8_t work[], int* lwork, float rwork[], int* info, int len_jobvl, int len_jobvr); extern void F77(cgelqf)(int* m, int* n, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cgels)(char* trans, int* m, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t b[], int* ldb, complex8_t work[], int* lwork, int* info, int len_trans); extern void F77(cgelss)(int* m, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t b[], int* ldb, float s[], float* rcond, int* rank, complex8_t work[], int* lwork, float rwork[], int* info); extern void F77(cgelsx)(int* m, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t b[], int* ldb, int jpvt[], float* rcond, int* rank, complex8_t work[], float rwork[], int* info); extern void F77(cgeqlf)(int* m, int* n, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cgeqpf)(int* m, int* n, complex8_t a[], int* lda, int jpvt[], complex8_t tau[], complex8_t work[], float rwork[], int* info); extern void F77(cgeqrf)(int* m, int* n, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cgerqf)(int* m, int* n, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cgesv)(int* n, int* nrhs, complex8_t a[], int* lda, int ipiv[], complex8_t b[], int* ldb, int* info); extern void F77(cgesvd)(char* jobu, char* jobvt, int* m, int* n, complex8_t a[], int* lda, float s[], complex8_t u[], int* ldu, complex8_t vt[], int* ldvt, complex8_t work[], int* lwork, float rwork[], int* info, int len_jobu, int len_jobvt); extern void F77(cgesvx)(char* fact, char* trans, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t af[], int* ldaf, int ipiv[], char* equed, float r[], float c[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(cgetrf)(int* m, int* n, complex8_t a[], int* lda, int ipiv[], int* info); extern void F77(cgetri)(int* n, complex8_t a[], int* lda, int ipiv[], complex8_t work[], int* lwork, int* info); extern void F77(cgetrs)(char* trans, int* n, int* nrhs, complex8_t a[], int* lda, int ipiv[], complex8_t b[], int* ldb, int* info, int len_trans); extern void F77(cggglm)(int* n, int* m, int* p, complex8_t a[], int* lda, complex8_t b[], int* ldb, complex8_t d[], complex8_t x[], complex8_t y[], complex8_t work[], int* lwork, int* info); extern void F77(cgglse)(int* m, int* n, int* p, complex8_t a[], int* lda, complex8_t b[], int* ldb, complex8_t c[], complex8_t d[], complex8_t x[], complex8_t work[], int* lwork, int* info); extern void F77(cggqrf)(int* m, int* n, int* p, complex8_t a[], int* lda, complex8_t taua[], complex8_t b[], int* ldb, complex8_t taub[], complex8_t work[], int* lwork, int* info); extern void F77(cggrqf)(int* m, int* n, int* p, complex8_t a[], int* lda, complex8_t taua[], complex8_t b[], int* ldb, complex8_t taub[], complex8_t work[], int* lwork, int* info); extern void F77(cggsvd)(char* jobu, char* jobv, char* jobq, int* m, int* n, int* p, int* k, int* l, complex8_t a[], int* lda, complex8_t b[], int* ldb, float alpha[], float beta[], complex8_t u[], int* ldu, complex8_t v[], int* ldv, complex8_t q[], int* ldq, complex8_t work[], float rwork[], int iwork[], int* info, int len_jobu, int len_jobv, int len_jobq); extern void F77(cgtcon)(char* norm, int* n, complex8_t dl[], complex8_t d[], complex8_t du[], complex8_t du2[], int ipiv[], float* anorm, float* rcond, complex8_t work[], int* info, int len_norm); extern void F77(cgtsv)(int* n, int* nrhs, complex8_t dl[], complex8_t d[], complex8_t du[], complex8_t b[], int* ldb, int* info); extern void F77(cgtsvx)(char* fact, char* trans, int* n, int* nrhs, complex8_t dl[], complex8_t d[], complex8_t du[], complex8_t dlf[], complex8_t df[], complex8_t duf[], complex8_t du2[], int ipiv[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_trans); extern void F77(cgttrf)(int* n, complex8_t dl[], complex8_t d[], complex8_t du[], complex8_t du2[], int ipiv[], int* info); extern void F77(cgttrs)(char* trans, int* n, int* nrhs, complex8_t dl[], complex8_t d[], complex8_t du[], complex8_t du2[], int ipiv[], complex8_t b[], int* ldb, int* info, int len_trans); extern void F77(chbev)(char* jobz, char* uplo, int* n, int* kd, complex8_t ab[], int* ldab, float w[], complex8_t z[], int* ldz, complex8_t work[], float rwork[], int* info, int len_jobz, int len_uplo); extern void F77(chbevd)(char* jobz, char* uplo, int* n, int* kd, complex8_t ab[], int* ldab, float w[], complex8_t z[], int* ldz, complex8_t work[], int* lwork, float rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(chbevx)(char* jobz, char* range, char* uplo, int* n, int* kd, complex8_t ab[], int* ldab, complex8_t q[], int* ldq, float* vl, float* vu, int* il, int* iu, float* abstol, int* m, float w[], complex8_t z[], int* ldz, complex8_t work[], float rwork[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(chbgv)(char* jobz, char* uplo, int* n, int* ka, int* kb, complex8_t ab[], int* ldab, complex8_t bb[], int* ldbb, float w[], complex8_t z[], int* ldz, complex8_t work[], float rwork[], int* info, int len_jobz, int len_uplo); extern void F77(checon)(char* uplo, int* n, complex8_t a[], int* lda, int ipiv[], float* anorm, float* rcond, complex8_t work[], int* info, int len_uplo); extern void F77(cheev)(char* jobz, char* uplo, int* n, complex8_t a[], int* lda, float w[], complex8_t work[], int* lwork, float rwork[], int* info, int len_jobz, int len_uplo); extern void F77(cheevd)(char* jobz, char* uplo, int* n, complex8_t a[], int* lda, float w[], complex8_t work[], int* lwork, float rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(cheevx)(char* jobz, char* range, char* uplo, int* n, complex8_t a[], int* lda, float* vl, float* vu, int* il, int* iu, float* abstol, int* m, float w[], complex8_t z[], int* ldz, complex8_t work[], int* lwork, float rwork[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(chegv)(int* itype, char* jobz, char* uplo, int* n, complex8_t a[], int* lda, complex8_t b[], int* ldb, float w[], complex8_t work[], int* lwork, float rwork[], int* info, int len_jobz, int len_uplo); extern void F77(chesv)(char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, int ipiv[], complex8_t b[], int* ldb, complex8_t work[], int* lwork, int* info, int len_uplo); extern void F77(chesvx)(char* fact, char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t af[], int* ldaf, int ipiv[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], int* lwork, float rwork[], int* info, int len_fact, int len_uplo); extern void F77(chetrf)(char* uplo, int* n, complex8_t a[], int* lda, int ipiv[], complex8_t work[], int* lwork, int* info, int len_uplo); extern void F77(chetri)(char* uplo, int* n, complex8_t a[], int* lda, int ipiv[], complex8_t work[], int* info, int len_uplo); extern void F77(chetrs)(char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, int ipiv[], complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(chpcon)(char* uplo, int* n, complex8_t ap[], int ipiv[], float* anorm, float* rcond, complex8_t work[], int* info, int len_uplo); extern void F77(chpev)(char* jobz, char* uplo, int* n, complex8_t ap[], float w[], complex8_t z[], int* ldz, complex8_t work[], float rwork[], int* info, int len_jobz, int len_uplo); extern void F77(chpevd)(char* jobz, char* uplo, int* n, complex8_t ap[], float w[], complex8_t z[], int* ldz, complex8_t work[], int* lwork, float rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(chpevx)(char* jobz, char* range, char* uplo, int* n, complex8_t ap[], float* vl, float* vu, int* il, int* iu, float* abstol, int* m, float w[], complex8_t z[], int* ldz, complex8_t work[], float rwork[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(chpgv)(int* itype, char* jobz, char* uplo, int* n, complex8_t ap[], complex8_t bp[], float w[], complex8_t z[], int* ldz, complex8_t work[], float rwork[], int* info, int len_jobz, int len_uplo); extern void F77(chpsv)(char* uplo, int* n, int* nrhs, complex8_t ap[], int ipiv[], complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(chpsvx)(char* fact, char* uplo, int* n, int* nrhs, complex8_t ap[], complex8_t afp[], int ipiv[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_uplo); extern void F77(chptrf)(char* uplo, int* n, complex8_t ap[], int ipiv[], int* info, int len_uplo); extern void F77(chptri)(char* uplo, int* n, complex8_t ap[], int ipiv[], complex8_t work[], int* info, int len_uplo); extern void F77(chptrs)(char* uplo, int* n, int* nrhs, complex8_t ap[], int ipiv[], complex8_t b[], int* ldb, int* info, int len_uplo); extern float F77(clangb)(char* norm, int* n, int* kl, int* ku, complex8_t ab[], int* ldab, float rwork[], int len_norm); extern float F77(clange)(char* norm, int* m, int* n, complex8_t a[], int* lda, float rwork[], int len_norm); extern float F77(clangt)(char* norm, int* n, complex8_t dl[], complex8_t d[], complex8_t du[], int len_norm); extern float F77(clanhb)(char* norm, char* uplo, int* n, int* kd, complex8_t ab[], int* ldab, float rwork[], int len_norm, int len_uplo); extern float F77(clanhe)(char* norm, char* uplo, int* n, complex8_t a[], int* lda, float rwork[], int len_norm, int len_uplo); extern float F77(clanhp)(char* norm, char* uplo, int* n, complex8_t ap[], float rwork[], int len_norm, int len_uplo); extern float F77(clanht)(char* norm, int* n, float d[], complex8_t e[], int len_norm); extern float F77(clansb)(char* norm, char* uplo, int* n, int* kd, complex8_t ab[], int* ldab, float rwork[], int len_norm, int len_uplo); extern float F77(clansp)(char* norm, char* uplo, int* n, complex8_t ap[], float rwork[], int len_norm, int len_uplo); extern float F77(clansy)(char* norm, char* uplo, int* n, complex8_t a[], int* lda, float rwork[], int len_norm, int len_uplo); extern void F77(cpbcon)(char* uplo, int* n, int* kd, complex8_t ab[], int* ldab, float* anorm, float* rcond, complex8_t work[], float rwork[], int* info, int len_uplo); extern void F77(cpbsv)(char* uplo, int* n, int* kd, int* nrhs, complex8_t ab[], int* ldab, complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cpbsvx)(char* fact, char* uplo, int* n, int* kd, int* nrhs, complex8_t ab[], int* ldab, complex8_t afb[], int* ldafb, char* equed, float s[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(cpbtrf)(char* uplo, int* n, int* kd, complex8_t ab[], int* ldab, int* info, int len_uplo); extern void F77(cpbtrs)(char* uplo, int* n, int* kd, int* nrhs, complex8_t ab[], int* ldab, complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cpocon)(char* uplo, int* n, complex8_t a[], int* lda, float* anorm, float* rcond, complex8_t work[], float rwork[], int* info, int len_uplo); extern void F77(cposv)(char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cposvx)(char* fact, char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t af[], int* ldaf, char* equed, float s[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(cpotrf)(char* uplo, int* n, complex8_t a[], int* lda, int* info, int len_uplo); extern void F77(cpotri)(char* uplo, int* n, complex8_t a[], int* lda, int* info, int len_uplo); extern void F77(cpotrs)(char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cppcon)(char* uplo, int* n, complex8_t ap[], float* anorm, float* rcond, complex8_t work[], float rwork[], int* info, int len_uplo); extern void F77(cppsv)(char* uplo, int* n, int* nrhs, complex8_t ap[], complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cppsvx)(char* fact, char* uplo, int* n, int* nrhs, complex8_t ap[], complex8_t afp[], char* equed, float s[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(cpptrf)(char* uplo, int* n, complex8_t ap[], int* info, int len_uplo); extern void F77(cpptri)(char* uplo, int* n, complex8_t ap[], int* info, int len_uplo); extern void F77(cpptrs)(char* uplo, int* n, int* nrhs, complex8_t ap[], complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cptcon)(int* n, float d[], complex8_t e[], float* anorm, float* rcond, float rwork[], int* info); extern void F77(cptsv)(int* n, int* nrhs, float d[], complex8_t e[], complex8_t b[], int* ldb, int* info); extern void F77(cptsvx)(char* fact, int* n, int* nrhs, float d[], complex8_t e[], float df[], complex8_t ef[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact); extern void F77(cpttrf)(int* n, float d[], complex8_t e[], int* info); extern void F77(cpttrs)(char* uplo, int* n, int* nrhs, float d[], complex8_t e[], complex8_t b[], int* ldb, int* info, int len_uplo); extern float F77(cputime)(float* tzero); extern void F77(cspcon)(char* uplo, int* n, complex8_t ap[], int ipiv[], float* anorm, float* rcond, complex8_t work[], int* info, int len_uplo); extern void F77(cspsv)(char* uplo, int* n, int* nrhs, complex8_t ap[], int ipiv[], complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cspsvx)(char* fact, char* uplo, int* n, int* nrhs, complex8_t ap[], complex8_t afp[], int ipiv[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], float rwork[], int* info, int len_fact, int len_uplo); extern void F77(csptrf)(char* uplo, int* n, complex8_t ap[], int ipiv[], int* info, int len_uplo); extern void F77(csptri)(char* uplo, int* n, complex8_t ap[], int ipiv[], complex8_t work[], int* info, int len_uplo); extern void F77(csptrs)(char* uplo, int* n, int* nrhs, complex8_t ap[], int ipiv[], complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(cstedc)(char* jobz, int* n, float d[], float e[], complex8_t z[], int* ldz, complex8_t work[], int* lwork, float rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz); extern void F77(csteqr)(char* jobz, int* n, float d[], float e[], complex8_t z[], int* ldz, float work[], int* info, int len_jobz); extern void F77(csycon)(char* uplo, int* n, complex8_t a[], int* lda, int ipiv[], float* anorm, float* rcond, complex8_t work[], int* info, int len_uplo); extern void F77(csysv)(char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, int ipiv[], complex8_t b[], int* ldb, complex8_t work[], int* lwork, int* info, int len_uplo); extern void F77(csysvx)(char* fact, char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t af[], int* ldaf, int ipiv[], complex8_t b[], int* ldb, complex8_t x[], int* ldx, float* rcond, float ferr[], float berr[], complex8_t work[], int* lwork, float rwork[], int* info, int len_fact, int len_uplo); extern void F77(csytrf)(char* uplo, int* n, complex8_t a[], int* lda, int ipiv[], complex8_t work[], int* lwork, int* info, int len_uplo); extern void F77(csytri)(char* uplo, int* n, complex8_t a[], int* lda, int ipiv[], complex8_t work[], int* info, int len_uplo); extern void F77(csytrs)(char* uplo, int* n, int* nrhs, complex8_t a[], int* lda, int ipiv[], complex8_t b[], int* ldb, int* info, int len_uplo); extern void F77(ctbcon)(char* norm, char* uplo, char* diag, int* n, int* kd, complex8_t ab[], int* ldab, float* rcond, complex8_t work[], float rwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(ctbtrs)(char* uplo, char* trans, char* diag, int* n, int* kd, int* nrhs, complex8_t ab[], int* ldab, complex8_t b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(ctpcon)(char* norm, char* uplo, char* diag, int* n, complex8_t ap[], float* rcond, complex8_t work[], float rwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(ctptri)(char* uplo, char* diag, int* n, complex8_t ap[], int* info, int len_uplo, int len_diag); extern void F77(ctptrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, complex8_t ap[], complex8_t b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(ctrcon)(char* norm, char* uplo, char* diag, int* n, complex8_t a[], int* lda, float* rcond, complex8_t work[], float rwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(ctrtri)(char* uplo, char* diag, int* n, complex8_t a[], int* lda, int* info, int len_uplo, int len_diag); extern void F77(ctrtrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, complex8_t a[], int* lda, complex8_t b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(ctzrqf)(int* m, int* n, complex8_t a[], int* lda, complex8_t tau[], int* info); extern void F77(cunglq)(int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cungql)(int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cungqr)(int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cungrq)(int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t work[], int* lwork, int* info); extern void F77(cunmlq)(char* side, char* trans, int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t c[], int* ldc, complex8_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(cunmql)(char* side, char* trans, int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t c[], int* ldc, complex8_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(cunmqr)(char* side, char* trans, int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t c[], int* ldc, complex8_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(cunmrq)(char* side, char* trans, int* m, int* n, int* k, complex8_t a[], int* lda, complex8_t tau[], complex8_t c[], int* ldc, complex8_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(dgbcon)(char* norm, int* n, int* kl, int* ku, double ab[], int* ldab, int ipiv[], double* anorm, double* rcond, double work[], int iwork[], int* info, int len_norm); extern void F77(dgbsv)(int* n, int* kl, int* ku, int* nrhs, double ab[], int* ldab, int ipiv[], double b[], int* ldb, int* info); extern void F77(dgbsvx)(char* fact, char* trans, int* n, int* kl, int* ku, int* nrhs, double ab[], int* ldab, double afb[], int* ldafb, int ipiv[], char* equed, double r[], double c[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int iwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(dgbtrf)(int* m, int* n, int* kl, int* ku, double ab[], int* ldab, int ipiv[], int* info); extern void F77(dgbtrs)(char* trans, int* n, int* kl, int* ku, int* nrhs, double ab[], int* ldab, int ipiv[], double b[], int* ldb, int* info, int len_trans); extern void F77(dgecon)(char* norm, int* n, double a[], int* lda, double* anorm, double* rcond, double work[], int iwork[], int* info, int len_norm); extern void F77(dgees)(char* jobvs, char* sort, int (*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, int len_jobvs, int len_sort); extern void F77(dgeesx)(char* jobvs, char* sort, int (*select)(), char* sense, int* n, double a[], int* lda, int* sdim, double wr[], double wi[], double vs[], int* ldvs, double* rconde, double* rcondv, double work[], int* lwork, int iwork[], int* liwork, int bwork[], int* info, int len_jobvs, int len_sort, int len_sense); extern void F77(dgeev)(char* jobvl, char* jobvr, int* n, double a[], int* lda, double wr[], double wi[], double vl[], int* ldvl, double vr[], int* ldvr, double work[], int* lwork, int* info, int len_jobvl, int len_jobvr); extern void F77(dgeevx)(char* balanc, char* jobvl, char* jobvr, char* sense, int* n, double a[], int* lda, double wr[], double wi[], double vl[], int* ldvl, double vr[], int* ldvr, int* ilo, int* ihi, double scale[], double* abnrm, double rconde[], double rcondv[], double work[], int* lwork, int iwork[], int* info, int len_balanc, int len_jobvl, int len_jobvr, int len_sense); extern void F77(dgegs)(char* jobvsl, char* jobvsr, int* n, double a[], int* lda, double b[], int* ldb, double alphar[], double alphai[], double beta[], double vsl[], int* ldvsl, double vsr[], int* ldvsr, double work[], int* lwork, int* info, int len_jobvsl, int len_jobvsr); extern void F77(dgegv)(char* jobvl, char* jobvr, int* n, double a[], int* lda, double b[], int* ldb, double alphar[], double alphai[], double beta[], double vl[], int* ldvl, double vr[], int* ldvr, double work[], int* lwork, int* info, int len_jobvl, int len_jobvr); extern void F77(dgelqf)(int* m, int* n, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(dgels)(char* trans, int* m, int* n, int* nrhs, double a[], int* lda, double b[], int* ldb, double work[], int* lwork, int* info, int len_trans); extern void F77(dgelss)(int* m, int* n, int* nrhs, double a[], int* lda, double b[], int* ldb, double s[], double* rcond, int* rank, double work[], int* lwork, int* info); extern void F77(dgelsx)(int* m, int* n, int* nrhs, double a[], int* lda, double b[], int* ldb, int jpvt[], double* rcond, int* rank, double work[], int* info); extern void F77(dgeqlf)(int* m, int* n, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(dgeqpf)(int* m, int* n, double a[], int* lda, int jpvt[], double tau[], double work[], int* info); extern void F77(dgeqrf)(int* m, int* n, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(dgerqf)(int* m, int* n, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(dgesv)(int* n, int* nrhs, double a[], int* lda, int ipiv[], double b[], int* ldb, int* info); extern void F77(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, int len_jobu, int len_jobvt); extern void F77(dgesvx)(char* fact, char* trans, int* n, int* nrhs, double a[], int* lda, double af[], int* ldaf, int ipiv[], char* equed, double r[], double c[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int iwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(dgetrf)(int* m, int* n, double a[], int* lda, int ipiv[], int* info); extern void F77(dgetri)(int* n, double a[], int* lda, int ipiv[], double work[], int* lwork, int* info); extern void F77(dgetrs)(char* trans, int* n, int* nrhs, double a[], int* lda, int ipiv[], double b[], int* ldb, int* info, int len_trans); extern void F77(dggglm)(int* n, int* m, int* p, double a[], int* lda, double b[], int* ldb, double d[], double x[], double y[], double work[], int* lwork, int* info); extern void F77(dgglse)(int* m, int* n, int* p, double a[], int* lda, double b[], int* ldb, double c[], double d[], double x[], double work[], int* lwork, int* info); extern void F77(dggqrf)(int* m, int* n, int* p, double a[], int* lda, double taua[], double b[], int* ldb, double taub[], double work[], int* lwork, int* info); extern void F77(dggrqf)(int* m, int* n, int* p, double a[], int* lda, double taua[], double b[], int* ldb, double taub[], double work[], int* lwork, int* info); extern void F77(dggsvd)(char* jobu, char* jobv, char* jobq, int* m, int* n, int* p, int* k, int* l, double a[], int* lda, double b[], int* ldb, double alpha[], double beta[], double u[], int* ldu, double v[], int* ldv, double q[], int* ldq, double work[], int iwork[], int* info, int len_jobu, int len_jobv, int len_jobq); extern void F77(dgtcon)(char* norm, int* n, double dl[], double d[], double du[], double du2[], int ipiv[], double* anorm, double* rcond, double work[], int iwork[], int* info, int len_norm); extern void F77(dgtsv)(int* n, int* nrhs, double dl[], double d[], double du[], double b[], int* ldb, int* info); extern void F77(dgtsvx)(char* fact, char* trans, int* n, int* nrhs, double dl[], double d[], double du[], double dlf[], double df[], double duf[], double du2[], int ipiv[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int iwork[], int* info, int len_fact, int len_trans); extern void F77(dgttrf)(int* n, double dl[], double d[], double du[], double du2[], int ipiv[], int* info); extern void F77(dgttrs)(char* trans, int* n, int* nrhs, double dl[], double d[], double du[], double du2[], int ipiv[], double b[], int* ldb, int* info, int len_trans); extern double F77(dlamch)(char* name, int len_name); extern double F77(dlangb)(char* norm, int* n, int* kl, int* ku, double ab[], int* ldab, double work[], int len_norm); extern double F77(dlange)(char* norm, int* m, int* n, double a[], int* lda, double work[], int len_norm); extern double F77(dlangt)(char* norm, int* n, double dl[], double d[], double du[], int len_norm); extern double F77(dlansb)(char* norm, char* uplo, int* n, int* kd, double ab[], int* ldab, double work[], int len_norm, int len_uplo); extern double F77(dlansp)(char* norm, char* uplo, int* n, double ap[], double work[], int len_norm, int len_uplo); extern double F77(dlanst)(char* norm, int* n, double d[], double e[], int len_norm); extern double F77(dlansy)(char* norm, char* uplo, int* n, double a[], int* lda, double work[], int len_norm, int len_uplo); extern void F77(dorglq)(int* m, int* n, int* k, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(dorgql)(int* m, int* n, int* k, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(dorgqr)(int* m, int* n, int* k, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(dorgrq)(int* m, int* n, int* k, double a[], int* lda, double tau[], double work[], int* lwork, int* info); extern void F77(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, int len_side, int len_trans); extern void F77(dormql)(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, int len_side, int len_trans); extern void F77(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, int len_side, int len_trans); extern void F77(dormrq)(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, int len_side, int len_trans); extern void F77(dpbcon)(char* uplo, int* n, int* kd, double ab[], int* ldab, double* anorm, double* rcond, double work[], int iwork[], int* info, int len_uplo); extern void F77(dpbsv)(char* uplo, int* n, int* kd, int* nrhs, double ab[], int* ldab, double b[], int* ldb, int* info, int len_uplo); extern void F77(dpbsvx)(char* fact, char* uplo, int* n, int* kd, int* nrhs, double ab[], int* ldab, double afb[], int* ldafb, char* equed, double s[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int iwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(dpbtrf)(char* uplo, int* n, int* kd, double ab[], int* ldab, int* info, int len_uplo); extern void F77(dpbtrs)(char* uplo, int* n, int* kd, int* nrhs, double ab[], int* ldab, double b[], int* ldb, int* info, int len_uplo); extern void F77(dpocon)(char* uplo, int* n, double a[], int* lda, double* anorm, double* rcond, double work[], int iwork[], int* info, int len_uplo); extern void F77(dposv)(char* uplo, int* n, int* nrhs, double a[], int* lda, double b[], int* ldb, int* info, int len_uplo); extern void F77(dposvx)(char* fact, char* uplo, int* n, int* nrhs, double a[], int* lda, double af[], int* ldaf, char* equed, double s[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int iwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(dpotrf)(char* uplo, int* n, double a[], int* lda, int* info, int len_uplo); extern void F77(dpotri)(char* uplo, int* n, double a[], int* lda, int* info, int len_uplo); extern void F77(dpotrs)(char* uplo, int* n, int* nrhs, double a[], int* lda, double b[], int* ldb, int* info, int len_uplo); extern void F77(dppcon)(char* uplo, int* n, double ap[], double* anorm, double* rcond, double work[], int iwork[], int* info, int len_uplo); extern void F77(dppsv)(char* uplo, int* n, int* nrhs, double ap[], double b[], int* ldb, int* info, int len_uplo); extern void F77(dppsvx)(char* fact, char* uplo, int* n, int* nrhs, double ap[], double afp[], char* equed, double s[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int iwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(dpptrf)(char* uplo, int* n, double ap[], int* info, int len_uplo); extern void F77(dpptri)(char* uplo, int* n, double ap[], int* info, int len_uplo); extern void F77(dpptrs)(char* uplo, int* n, int* nrhs, double ap[], double b[], int* ldb, int* info, int len_uplo); extern void F77(dptcon)(int* n, double d[], double e[], double* anorm, double* rcond, double work[], int* info); extern void F77(dptsv)(int* n, int* nrhs, double d[], double e[], double b[], int* ldb, int* info); extern void F77(dptsvx)(char* fact, int* n, int* nrhs, double d[], double e[], double df[], double ef[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int* info, int len_fact); extern void F77(dpttrf)(int* n, double d[], double e[], int* info); extern void F77(dpttrs)(int* n, int* nrhs, double d[], double e[], double b[], int* ldb, int* info); extern void F77(dsbev)(char* jobz, char* uplo, int* n, int* kd, double ab[], int* ldab, double w[], double z[], int* ldz, double work[], int* info, int len_jobz, int len_uplo); extern void F77(dsbevd)(char* jobz, char* uplo, int* n, int* kd, double ab[], int* ldab, double w[], double z[], int* ldz, double work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(dsbevx)(char* jobz, char* range, char* uplo, int* n, int* kd, double ab[], int* ldab, double q[], int* ldq, double* vl, double* vu, int* il, int* iu, double* abstol, int* m, double w[], double z[], int* ldz, double work[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(dsbgv)(char* jobz, char* uplo, int* n, int* ka, int* kb, double ab[], int* ldab, double bb[], int* ldbb, double w[], double z[], int* ldz, double work[], int* info, int len_jobz, int len_uplo); extern void F77(dspcon)(char* uplo, int* n, double ap[], int ipiv[], double* anorm, double* rcond, double work[], int iwork[], int* info, int len_uplo); extern void F77(dspev)(char* jobz, char* uplo, int* n, double ap[], double w[], double z[], int* ldz, double work[], int* info, int len_jobz, int len_uplo); extern void F77(dspevd)(char* jobz, char* uplo, int* n, double ap[], double w[], double z[], int* ldz, double work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(dspevx)(char* jobz, char* range, char* uplo, int* n, double ap[], double* vl, double* vu, int* il, int* iu, double* abstol, int* m, double w[], double z[], int* ldz, double work[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(dspgv)(int* itype, char* jobz, char* uplo, int* n, double ap[], double bp[], double w[], double z[], int* ldz, double work[], int* info, int len_jobz, int len_uplo); extern void F77(dspsv)(char* uplo, int* n, int* nrhs, double ap[], int ipiv[], double b[], int* ldb, int* info, int len_uplo); extern void F77(dspsvx)(char* fact, char* uplo, int* n, int* nrhs, double ap[], double afp[], int ipiv[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int iwork[], int* info, int len_fact, int len_uplo); extern void F77(dsptrf)(char* uplo, int* n, double ap[], int ipiv[], int* info, int len_uplo); extern void F77(dsptri)(char* uplo, int* n, double ap[], int ipiv[], double work[], int* info, int len_uplo); extern void F77(dsptrs)(char* uplo, int* n, int* nrhs, double ap[], int ipiv[], double b[], int* ldb, int* info, int len_uplo); extern void F77(dstedc)(char* jobz, int* n, double d[], double e[], double z[], int* ldz, double work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz); extern void F77(dsteqr)(char* jobz, int* n, double d[], double e[], double z[], int* ldz, double work[], int* info, int len_jobz); extern void F77(dstev)(char* jobz, int* n, double d[], double e[], double z[], int* ldz, double work[], int* info, int len_jobz); extern void F77(dstevd)(char* jobz, int* n, double d[], double e[], double z[], int* ldz, double work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz); extern void F77(dstevx)(char* jobz, char* range, int* n, double d[], double e[], double* vl, double* vu, int* il, int* iu, double* abstol, int* m, double w[], double z[], int* ldz, double work[], int iwork[], int ifail[], int* info, int len_jobz, int len_range); extern void F77(dsycon)(char* uplo, int* n, double a[], int* lda, int ipiv[], double* anorm, double* rcond, double work[], int iwork[], int* info, int len_uplo); extern void F77(dsyev)(char* jobz, char* uplo, int* n, double a[], int* lda, double w[], double work[], int* lwork, int* info, int len_jobz, int len_uplo); extern void F77(dsyevd)(char* jobz, char* uplo, int* n, double a[], int* lda, double w[], double work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(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, int len_jobz, int len_range, int len_uplo); extern void F77(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, int len_jobz, int len_uplo); extern void F77(dsysv)(char* uplo, int* n, int* nrhs, double a[], int* lda, int ipiv[], double b[], int* ldb, double work[], int* lwork, int* info, int len_uplo); extern void F77(dsysvx)(char* fact, char* uplo, int* n, int* nrhs, double a[], int* lda, double af[], int* ldaf, int ipiv[], double b[], int* ldb, double x[], int* ldx, double* rcond, double ferr[], double berr[], double work[], int* lwork, int iwork[], int* info, int len_fact, int len_uplo); extern void F77(dsytrf)(char* uplo, int* n, double a[], int* lda, int ipiv[], double work[], int* lwork, int* info, int len_uplo); extern void F77(dsytri)(char* uplo, int* n, double a[], int* lda, int ipiv[], double work[], int* info, int len_uplo); extern void F77(dsytrs)(char* uplo, int* n, int* nrhs, double a[], int* lda, int ipiv[], double b[], int* ldb, int* info, int len_uplo); extern void F77(dtbcon)(char* norm, char* uplo, char* diag, int* n, int* kd, double ab[], int* ldab, double* rcond, double work[], int iwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(dtbtrs)(char* uplo, char* trans, char* diag, int* n, int* kd, int* nrhs, double ab[], int* ldab, double b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(dtpcon)(char* norm, char* uplo, char* diag, int* n, double ap[], double* rcond, double work[], int iwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(dtptri)(char* uplo, char* diag, int* n, double ap[], int* info, int len_uplo, int len_diag); extern void F77(dtptrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, double ap[], double b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(dtrcon)(char* norm, char* uplo, char* diag, int* n, double a[], int* lda, double* rcond, double work[], int iwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(dtrtri)(char* uplo, char* diag, int* n, double a[], int* lda, int* info, int len_uplo, int len_diag); extern void F77(dtrtrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, double a[], int* lda, double b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(dtzrqf)(int* m, int* n, double a[], int* lda, double tau[], int* info); extern int F77(ilaenv)(int* ispec, char* name, char* opts, int* n1, int* n2, int* n3, int* n4, int len_name, int len_opts); extern void F77(sgbcon)(char* norm, int* n, int* kl, int* ku, float ab[], int* ldab, int ipiv[], float* anorm, float* rcond, float work[], int iwork[], int* info, int len_norm); extern void F77(sgbsv)(int* n, int* kl, int* ku, int* nrhs, float ab[], int* ldab, int ipiv[], float b[], int* ldb, int* info); extern void F77(sgbsvx)(char* fact, char* trans, int* n, int* kl, int* ku, int* nrhs, float ab[], int* ldab, float afb[], int* ldafb, int ipiv[], char* equed, float r[], float c[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int iwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(sgbtrf)(int* m, int* n, int* kl, int* ku, float ab[], int* ldab, int ipiv[], int* info); extern void F77(sgbtrs)(char* trans, int* n, int* kl, int* ku, int* nrhs, float ab[], int* ldab, int ipiv[], float b[], int* ldb, int* info, int len_trans); extern void F77(sgecon)(char* norm, int* n, float a[], int* lda, float* anorm, float* rcond, float work[], int iwork[], int* info, int len_norm); extern void F77(sgees)(char* jobvs, char* sort, int (*select)(), int* n, float a[], int* lda, int* sdim, float wr[], float wi[], float vs[], int* ldvs, float work[], int* lwork, int bwork[], int* info, int len_jobvs, int len_sort); extern void F77(sgeesx)(char* jobvs, char* sort, int (*select)(), char* sense, int* n, float a[], int* lda, int* sdim, float wr[], float wi[], float vs[], int* ldvs, float* rconde, float* rcondv, float work[], int* lwork, int iwork[], int* liwork, int bwork[], int* info, int len_jobvs, int len_sort, int len_sense); extern void F77(sgeev)(char* jobvl, char* jobvr, int* n, float a[], int* lda, float wr[], float wi[], float vl[], int* ldvl, float vr[], int* ldvr, float work[], int* lwork, int* info, int len_jobvl, int len_jobvr); extern void F77(sgeevx)(char* balanc, char* jobvl, char* jobvr, char* sense, int* n, float a[], int* lda, float wr[], float wi[], float vl[], int* ldvl, float vr[], int* ldvr, int* ilo, int* ihi, float scale[], float* abnrm, float rconde[], float rcondv[], float work[], int* lwork, int iwork[], int* info, int len_balanc, int len_jobvl, int len_jobvr, int len_sense); extern void F77(sgegs)(char* jobvsl, char* jobvsr, int* n, float a[], int* lda, float b[], int* ldb, float alphar[], float alphai[], float beta[], float vsl[], int* ldvsl, float vsr[], int* ldvsr, float work[], int* lwork, int* info, int len_jobvsl, int len_jobvsr); extern void F77(sgegv)(char* jobvl, char* jobvr, int* n, float a[], int* lda, float b[], int* ldb, float alphar[], float alphai[], float beta[], float vl[], int* ldvl, float vr[], int* ldvr, float work[], int* lwork, int* info, int len_jobvl, int len_jobvr); extern void F77(sgelqf)(int* m, int* n, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sgels)(char* trans, int* m, int* n, int* nrhs, float a[], int* lda, float b[], int* ldb, float work[], int* lwork, int* info, int len_trans); extern void F77(sgelss)(int* m, int* n, int* nrhs, float a[], int* lda, float b[], int* ldb, float s[], float* rcond, int* rank, float work[], int* lwork, int* info); extern void F77(sgelsx)(int* m, int* n, int* nrhs, float a[], int* lda, float b[], int* ldb, int jpvt[], float* rcond, int* rank, float work[], int* info); extern void F77(sgeqlf)(int* m, int* n, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sgeqpf)(int* m, int* n, float a[], int* lda, int jpvt[], float tau[], float work[], int* info); extern void F77(sgeqrf)(int* m, int* n, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sgerqf)(int* m, int* n, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sgesv)(int* n, int* nrhs, float a[], int* lda, int ipiv[], float b[], int* ldb, int* info); extern void F77(sgesvd)(char* jobu, char* jobvt, int* m, int* n, float a[], int* lda, float s[], float u[], int* ldu, float vt[], int* ldvt, float work[], int* lwork, int* info, int len_jobu, int len_jobvt); extern void F77(sgesvx)(char* fact, char* trans, int* n, int* nrhs, float a[], int* lda, float af[], int* ldaf, int ipiv[], char* equed, float r[], float c[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int iwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(sgetrf)(int* m, int* n, float a[], int* lda, int ipiv[], int* info); extern void F77(sgetri)(int* n, float a[], int* lda, int ipiv[], float work[], int* lwork, int* info); extern void F77(sgetrs)(char* trans, int* n, int* nrhs, float a[], int* lda, int ipiv[], float b[], int* ldb, int* info, int len_trans); extern void F77(sggglm)(int* n, int* m, int* p, float a[], int* lda, float b[], int* ldb, float d[], float x[], float y[], float work[], int* lwork, int* info); extern void F77(sgglse)(int* m, int* n, int* p, float a[], int* lda, float b[], int* ldb, float c[], float d[], float x[], float work[], int* lwork, int* info); extern void F77(sggqrf)(int* m, int* n, int* p, float a[], int* lda, float taua[], float b[], int* ldb, float taub[], float work[], int* lwork, int* info); extern void F77(sggrqf)(int* m, int* n, int* p, float a[], int* lda, float taua[], float b[], int* ldb, float taub[], float work[], int* lwork, int* info); extern void F77(sggsvd)(char* jobu, char* jobv, char* jobq, int* m, int* n, int* p, int* k, int* l, float a[], int* lda, float b[], int* ldb, float alpha[], float beta[], float u[], int* ldu, float v[], int* ldv, float q[], int* ldq, float work[], int iwork[], int* info, int len_jobu, int len_jobv, int len_jobq); extern void F77(sgtcon)(char* norm, int* n, float dl[], float d[], float du[], float du2[], int ipiv[], float* anorm, float* rcond, float work[], int iwork[], int* info, int len_norm); extern void F77(sgtsv)(int* n, int* nrhs, float dl[], float d[], float du[], float b[], int* ldb, int* info); extern void F77(sgtsvx)(char* fact, char* trans, int* n, int* nrhs, float dl[], float d[], float du[], float dlf[], float df[], float duf[], float du2[], int ipiv[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int iwork[], int* info, int len_fact, int len_trans); extern void F77(sgttrf)(int* n, float dl[], float d[], float du[], float du2[], int ipiv[], int* info); extern void F77(sgttrs)(char* trans, int* n, int* nrhs, float dl[], float d[], float du[], float du2[], int ipiv[], float b[], int* ldb, int* info, int len_trans); extern float F77(slamch)(char* name, int len_name); extern float F77(slangb)(char* norm, int* n, int* kl, int* ku, float ab[], int* ldab, float work[], int len_norm); extern float F77(slange)(char* norm, int* m, int* n, float a[], int* lda, float work[], int len_norm); extern float F77(slangt)(char* norm, int* n, float dl[], float d[], float du[], int len_norm); extern float F77(slansb)(char* norm, char* uplo, int* n, int* kd, float ab[], int* ldab, float work[], int len_norm, int len_uplo); extern float F77(slansp)(char* norm, char* uplo, int* n, float ap[], float work[], int len_norm, int len_uplo); extern float F77(slanst)(char* norm, int* n, float d[], float e[], int len_norm); extern float F77(slansy)(char* norm, char* uplo, int* n, float a[], int* lda, float work[], int len_norm, int len_uplo); extern void F77(sorglq)(int* m, int* n, int* k, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sorgql)(int* m, int* n, int* k, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sorgqr)(int* m, int* n, int* k, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sorgrq)(int* m, int* n, int* k, float a[], int* lda, float tau[], float work[], int* lwork, int* info); extern void F77(sormlq)(char* side, char* trans, int* m, int* n, int* k, float a[], int* lda, float tau[], float c[], int* ldc, float work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(sormql)(char* side, char* trans, int* m, int* n, int* k, float a[], int* lda, float tau[], float c[], int* ldc, float work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(sormqr)(char* side, char* trans, int* m, int* n, int* k, float a[], int* lda, float tau[], float c[], int* ldc, float work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(sormrq)(char* side, char* trans, int* m, int* n, int* k, float a[], int* lda, float tau[], float c[], int* ldc, float work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(spbcon)(char* uplo, int* n, int* kd, float ab[], int* ldab, float* anorm, float* rcond, float work[], int iwork[], int* info, int len_uplo); extern void F77(spbsv)(char* uplo, int* n, int* kd, int* nrhs, float ab[], int* ldab, float b[], int* ldb, int* info, int len_uplo); extern void F77(spbsvx)(char* fact, char* uplo, int* n, int* kd, int* nrhs, float ab[], int* ldab, float afb[], int* ldafb, char* equed, float s[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int iwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(spbtrf)(char* uplo, int* n, int* kd, float ab[], int* ldab, int* info, int len_uplo); extern void F77(spbtrs)(char* uplo, int* n, int* kd, int* nrhs, float ab[], int* ldab, float b[], int* ldb, int* info, int len_uplo); extern void F77(spocon)(char* uplo, int* n, float a[], int* lda, float* anorm, float* rcond, float work[], int iwork[], int* info, int len_uplo); extern void F77(sposv)(char* uplo, int* n, int* nrhs, float a[], int* lda, float b[], int* ldb, int* info, int len_uplo); extern void F77(sposvx)(char* fact, char* uplo, int* n, int* nrhs, float a[], int* lda, float af[], int* ldaf, char* equed, float s[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int iwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(spotrf)(char* uplo, int* n, float a[], int* lda, int* info, int len_uplo); extern void F77(spotri)(char* uplo, int* n, float a[], int* lda, int* info, int len_uplo); extern void F77(spotrs)(char* uplo, int* n, int* nrhs, float a[], int* lda, float b[], int* ldb, int* info, int len_uplo); extern void F77(sppcon)(char* uplo, int* n, float ap[], float* anorm, float* rcond, float work[], int iwork[], int* info, int len_uplo); extern void F77(sppsv)(char* uplo, int* n, int* nrhs, float ap[], float b[], int* ldb, int* info, int len_uplo); extern void F77(sppsvx)(char* fact, char* uplo, int* n, int* nrhs, float ap[], float afp[], char* equed, float s[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int iwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(spptrf)(char* uplo, int* n, float ap[], int* info, int len_uplo); extern void F77(spptri)(char* uplo, int* n, float ap[], int* info, int len_uplo); extern void F77(spptrs)(char* uplo, int* n, int* nrhs, float ap[], float b[], int* ldb, int* info, int len_uplo); extern void F77(sptcon)(int* n, float d[], float e[], float* anorm, float* rcond, float work[], int* info); extern void F77(sptsv)(int* n, int* nrhs, float d[], float e[], float b[], int* ldb, int* info); extern void F77(sptsvx)(char* fact, int* n, int* nrhs, float d[], float e[], float df[], float ef[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int* info, int len_fact); extern void F77(spttrf)(int* n, float d[], float e[], int* info); extern void F77(spttrs)(int* n, int* nrhs, float d[], float e[], float b[], int* ldb, int* info); extern void F77(ssbev)(char* jobz, char* uplo, int* n, int* kd, float ab[], int* ldab, float w[], float z[], int* ldz, float work[], int* info, int len_jobz, int len_uplo); extern void F77(ssbevd)(char* jobz, char* uplo, int* n, int* kd, float ab[], int* ldab, float w[], float z[], int* ldz, float work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(ssbevx)(char* jobz, char* range, char* uplo, int* n, int* kd, float ab[], int* ldab, float q[], int* ldq, float* vl, float* vu, int* il, int* iu, float* abstol, int* m, float w[], float z[], int* ldz, float work[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(ssbgv)(char* jobz, char* uplo, int* n, int* ka, int* kb, float ab[], int* ldab, float bb[], int* ldbb, float w[], float z[], int* ldz, float work[], int* info, int len_jobz, int len_uplo); extern void F77(sspcon)(char* uplo, int* n, float ap[], int ipiv[], float* anorm, float* rcond, float work[], int iwork[], int* info, int len_uplo); extern void F77(sspev)(char* jobz, char* uplo, int* n, float ap[], float w[], float z[], int* ldz, float work[], int* info, int len_jobz, int len_uplo); extern void F77(sspevd)(char* jobz, char* uplo, int* n, float ap[], float w[], float z[], int* ldz, float work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(sspevx)(char* jobz, char* range, char* uplo, int* n, float ap[], float* vl, float* vu, int* il, int* iu, float* abstol, int* m, float w[], float z[], int* ldz, float work[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(sspgv)(int* itype, char* jobz, char* uplo, int* n, float ap[], float bp[], float w[], float z[], int* ldz, float work[], int* info, int len_jobz, int len_uplo); extern void F77(sspsv)(char* uplo, int* n, int* nrhs, float ap[], int ipiv[], float b[], int* ldb, int* info, int len_uplo); extern void F77(sspsvx)(char* fact, char* uplo, int* n, int* nrhs, float ap[], float afp[], int ipiv[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int iwork[], int* info, int len_fact, int len_uplo); extern void F77(ssptrf)(char* uplo, int* n, float ap[], int ipiv[], int* info, int len_uplo); extern void F77(ssptri)(char* uplo, int* n, float ap[], int ipiv[], float work[], int* info, int len_uplo); extern void F77(ssptrs)(char* uplo, int* n, int* nrhs, float ap[], int ipiv[], float b[], int* ldb, int* info, int len_uplo); extern void F77(sstedc)(char* jobz, int* n, float d[], float e[], float z[], int* ldz, float work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz); extern void F77(ssteqr)(char* jobz, int* n, float d[], float e[], float z[], int* ldz, float work[], int* info, int len_jobz); extern void F77(sstev)(char* jobz, int* n, float d[], float e[], float z[], int* ldz, float work[], int* info, int len_jobz); extern void F77(sstevd)(char* jobz, int* n, float d[], float e[], float z[], int* ldz, float work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz); extern void F77(sstevx)(char* jobz, char* range, int* n, float d[], float e[], float* vl, float* vu, int* il, int* iu, float* abstol, int* m, float w[], float z[], int* ldz, float work[], int iwork[], int ifail[], int* info, int len_jobz, int len_range); extern void F77(ssycon)(char* uplo, int* n, float a[], int* lda, int ipiv[], float* anorm, float* rcond, float work[], int iwork[], int* info, int len_uplo); extern void F77(ssyev)(char* jobz, char* uplo, int* n, float a[], int* lda, float w[], float work[], int* lwork, int* info, int len_jobz, int len_uplo); extern void F77(ssyevd)(char* jobz, char* uplo, int* n, float a[], int* lda, float w[], float work[], int* lwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(ssyevx)(char* jobz, char* range, char* uplo, int* n, float a[], int* lda, float* vl, float* vu, int* il, int* iu, float* abstol, int* m, float w[], float z[], int* ldz, float work[], int* lwork, int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(ssygv)(int* itype, char* jobz, char* uplo, int* n, float a[], int* lda, float b[], int* ldb, float w[], float work[], int* lwork, int* info, int len_jobz, int len_uplo); extern void F77(ssysv)(char* uplo, int* n, int* nrhs, float a[], int* lda, int ipiv[], float b[], int* ldb, float work[], int* lwork, int* info, int len_uplo); extern void F77(ssysvx)(char* fact, char* uplo, int* n, int* nrhs, float a[], int* lda, float af[], int* ldaf, int ipiv[], float b[], int* ldb, float x[], int* ldx, float* rcond, float ferr[], float berr[], float work[], int* lwork, int iwork[], int* info, int len_fact, int len_uplo); extern void F77(ssytrf)(char* uplo, int* n, float a[], int* lda, int ipiv[], float work[], int* lwork, int* info, int len_uplo); extern void F77(ssytri)(char* uplo, int* n, float a[], int* lda, int ipiv[], float work[], int* info, int len_uplo); extern void F77(ssytrs)(char* uplo, int* n, int* nrhs, float a[], int* lda, int ipiv[], float b[], int* ldb, int* info, int len_uplo); extern void F77(stbcon)(char* norm, char* uplo, char* diag, int* n, int* kd, float ab[], int* ldab, float* rcond, float work[], int iwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(stbtrs)(char* uplo, char* trans, char* diag, int* n, int* kd, int* nrhs, float ab[], int* ldab, float b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(stpcon)(char* norm, char* uplo, char* diag, int* n, float ap[], float* rcond, float work[], int iwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(stptri)(char* uplo, char* diag, int* n, float ap[], int* info, int len_uplo, int len_diag); extern void F77(stptrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, float ap[], float b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(strcon)(char* norm, char* uplo, char* diag, int* n, float a[], int* lda, float* rcond, float work[], int iwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(strtri)(char* uplo, char* diag, int* n, float a[], int* lda, int* info, int len_uplo, int len_diag); extern void F77(strtrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, float a[], int* lda, float b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(stzrqf)(int* m, int* n, float a[], int* lda, float tau[], int* info); extern float F77(walltime)(float* tzero); extern void F77(xerbla)(char* name, int* iarg, int len_name); extern void F77(zgbcon)(char* norm, int* n, int* kl, int* ku, complex16_t ab[], int* ldab, int ipiv[], double* anorm, double* rcond, complex16_t work[], double rwork[], int* info, int len_norm); extern void F77(zgbsv)(int* n, int* kl, int* ku, int* nrhs, complex16_t ab[], int* ldab, int ipiv[], complex16_t b[], int* ldb, int* info); extern void F77(zgbsvx)(char* fact, char* trans, int* n, int* kl, int* ku, int* nrhs, complex16_t ab[], int* ldab, complex16_t afb[], int* ldafb, int ipiv[], char* equed, double r[], double c[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(zgbtrf)(int* m, int* n, int* kl, int* ku, complex16_t ab[], int* ldab, int ipiv[], int* info); extern void F77(zgbtrs)(char* trans, int* n, int* kl, int* ku, int* nrhs, complex16_t ab[], int* ldab, int ipiv[], complex16_t b[], int* ldb, int* info, int len_trans); extern void F77(zgecon)(char* norm, int* n, complex16_t a[], int* lda, double* anorm, double* rcond, complex16_t work[], double rwork[], int* info, int len_norm); extern void F77(zgees)(char* jobvs, char* sort, int (*select)(), int* n, complex16_t a[], int* lda, int* sdim, complex16_t w[], complex16_t vs[], int* ldvs, complex16_t work[], int* lwork, double rwork[], int bwork[], int* info, int len_jobvs, int len_sort); extern void F77(zgeesx)(char* jobvs, char* sort, int (*select)(), char* sense, int* n, complex16_t a[], int* lda, int* sdim, complex16_t w[], complex16_t vs[], int* ldvs, double* rconde, double* rcondv, complex16_t work[], int* lwork, double rwork[], int bwork[], int* info, int len_jobvs, int len_sort, int len_sense); extern void F77(zgeev)(char* jobvl, char* jobvr, int* n, complex16_t a[], int* lda, complex16_t w[], complex16_t vl[], int* ldvl, complex16_t vr[], int* ldvr, complex16_t work[], int* lwork, double rwork[], int* info, int len_jobvl, int len_jobvr); extern void F77(zgeevx)(char* balanc, char* jobvl, char* jobvr, char* sense, int* n, complex16_t a[], int* lda, complex16_t w[], complex16_t vl[], int* ldvl, complex16_t vr[], int* ldvr, int* ilo, int* ihi, double scale[], double* abnrm, double rconde[], double rcondv[], complex16_t work[], int* lwork, double rwork[], int* info, int len_balanc, int len_jobvl, int len_jobvr, int len_sense); extern void F77(zgegs)(char* jobvsl, char* jobvsr, int* n, complex16_t a[], int* lda, complex16_t b[], int* ldb, complex16_t alpha[], complex16_t beta[], complex16_t vsl[], int* ldvsl, complex16_t vsr[], int* ldvsr, complex16_t work[], int* lwork, double rwork[], int* info, int len_jobvsl, int len_jobvsr); extern void F77(zgegv)(char* jobvl, char* jobvr, int* n, complex16_t a[], int* lda, complex16_t b[], int* ldb, complex16_t alpha[], complex16_t beta[], complex16_t vl[], int* ldvl, complex16_t vr[], int* ldvr, complex16_t work[], int* lwork, double rwork[], int* info, int len_jobvl, int len_jobvr); extern void F77(zgelqf)(int* m, int* n, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zgels)(char* trans, int* m, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t b[], int* ldb, complex16_t work[], int* lwork, int* info, int len_trans); extern void F77(zgelss)(int* m, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t b[], int* ldb, double s[], double* rcond, int* rank, complex16_t work[], int* lwork, double rwork[], int* info); extern void F77(zgelsx)(int* m, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t b[], int* ldb, int jpvt[], double* rcond, int* rank, complex16_t work[], double rwork[], int* info); extern void F77(zgeqlf)(int* m, int* n, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zgeqpf)(int* m, int* n, complex16_t a[], int* lda, int jpvt[], complex16_t tau[], complex16_t work[], double rwork[], int* info); extern void F77(zgeqrf)(int* m, int* n, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zgerqf)(int* m, int* n, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zgesv)(int* n, int* nrhs, complex16_t a[], int* lda, int ipiv[], complex16_t b[], int* ldb, int* info); extern void F77(zgesvd)(char* jobu, char* jobvt, int* m, int* n, complex16_t a[], int* lda, double s[], complex16_t u[], int* ldu, complex16_t vt[], int* ldvt, complex16_t work[], int* lwork, double rwork[], int* info, int len_jobu, int len_jobvt); extern void F77(zgesvx)(char* fact, char* trans, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t af[], int* ldaf, int ipiv[], char* equed, double r[], double c[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_trans, int len_equed); extern void F77(zgetrf)(int* m, int* n, complex16_t a[], int* lda, int ipiv[], int* info); extern void F77(zgetri)(int* n, complex16_t a[], int* lda, int ipiv[], complex16_t work[], int* lwork, int* info); extern void F77(zgetrs)(char* trans, int* n, int* nrhs, complex16_t a[], int* lda, int ipiv[], complex16_t b[], int* ldb, int* info, int len_trans); extern void F77(zggglm)(int* n, int* m, int* p, complex16_t a[], int* lda, complex16_t b[], int* ldb, complex16_t d[], complex16_t x[], complex16_t y[], complex16_t work[], int* lwork, int* info); extern void F77(zgglse)(int* m, int* n, int* p, complex16_t a[], int* lda, complex16_t b[], int* ldb, complex16_t c[], complex16_t d[], complex16_t x[], complex16_t work[], int* lwork, int* info); extern void F77(zggqrf)(int* m, int* n, int* p, complex16_t a[], int* lda, complex16_t taua[], complex16_t b[], int* ldb, complex16_t taub[], complex16_t work[], int* lwork, int* info); extern void F77(zggrqf)(int* m, int* n, int* p, complex16_t a[], int* lda, complex16_t taua[], complex16_t b[], int* ldb, complex16_t taub[], complex16_t work[], int* lwork, int* info); extern void F77(zggsvd)(char* jobu, char* jobv, char* jobq, int* m, int* n, int* p, int* k, int* l, complex16_t a[], int* lda, complex16_t b[], int* ldb, double alpha[], double beta[], complex16_t u[], int* ldu, complex16_t v[], int* ldv, complex16_t q[], int* ldq, complex16_t work[], double rwork[], int iwork[], int* info, int len_jobu, int len_jobv, int len_jobq); extern void F77(zgtcon)(char* norm, int* n, complex16_t dl[], complex16_t d[], complex16_t du[], complex16_t du2[], int ipiv[], double* anorm, double* rcond, complex16_t work[], int* info, int len_norm); extern void F77(zgtsv)(int* n, int* nrhs, complex16_t dl[], complex16_t d[], complex16_t du[], complex16_t b[], int* ldb, int* info); extern void F77(zgtsvx)(char* fact, char* trans, int* n, int* nrhs, complex16_t dl[], complex16_t d[], complex16_t du[], complex16_t dlf[], complex16_t df[], complex16_t duf[], complex16_t du2[], int ipiv[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_trans); extern void F77(zgttrf)(int* n, complex16_t dl[], complex16_t d[], complex16_t du[], complex16_t du2[], int ipiv[], int* info); extern void F77(zgttrs)(char* trans, int* n, int* nrhs, complex16_t dl[], complex16_t d[], complex16_t du[], complex16_t du2[], int ipiv[], complex16_t b[], int* ldb, int* info, int len_trans); extern void F77(zhbev)(char* jobz, char* uplo, int* n, int* kd, complex16_t ab[], int* ldab, double w[], complex16_t z[], int* ldz, complex16_t work[], double rwork[], int* info, int len_jobz, int len_uplo); extern void F77(zhbevd)(char* jobz, char* uplo, int* n, int* kd, complex16_t ab[], int* ldab, double w[], complex16_t z[], int* ldz, complex16_t work[], int* lwork, double rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(zhbevx)(char* jobz, char* range, char* uplo, int* n, int* kd, complex16_t ab[], int* ldab, complex16_t q[], int* ldq, double* vl, double* vu, int* il, int* iu, double* abstol, int* m, double w[], complex16_t z[], int* ldz, complex16_t work[], double rwork[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(zhbgv)(char* jobz, char* uplo, int* n, int* ka, int* kb, complex16_t ab[], int* ldab, complex16_t bb[], int* ldbb, double w[], complex16_t z[], int* ldz, complex16_t work[], double rwork[], int* info, int len_jobz, int len_uplo); extern void F77(zhecon)(char* uplo, int* n, complex16_t a[], int* lda, int ipiv[], double* anorm, double* rcond, complex16_t work[], int* info, int len_uplo); extern void F77(zheev)(char* jobz, char* uplo, int* n, complex16_t a[], int* lda, double w[], complex16_t work[], int* lwork, double rwork[], int* info, int len_jobz, int len_uplo); extern void F77(zheevd)(char* jobz, char* uplo, int* n, complex16_t a[], int* lda, double w[], complex16_t work[], int* lwork, double rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(zheevx)(char* jobz, char* range, char* uplo, int* n, complex16_t a[], int* lda, double* vl, double* vu, int* il, int* iu, double* abstol, int* m, double w[], complex16_t z[], int* ldz, complex16_t work[], int* lwork, double rwork[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(zhegv)(int* itype, char* jobz, char* uplo, int* n, complex16_t a[], int* lda, complex16_t b[], int* ldb, double w[], complex16_t work[], int* lwork, double rwork[], int* info, int len_jobz, int len_uplo); extern void F77(zhesv)(char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, int ipiv[], complex16_t b[], int* ldb, complex16_t work[], int* lwork, int* info, int len_uplo); extern void F77(zhesvx)(char* fact, char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t af[], int* ldaf, int ipiv[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], int* lwork, double rwork[], int* info, int len_fact, int len_uplo); extern void F77(zhetrf)(char* uplo, int* n, complex16_t a[], int* lda, int ipiv[], complex16_t work[], int* lwork, int* info, int len_uplo); extern void F77(zhetri)(char* uplo, int* n, complex16_t a[], int* lda, int ipiv[], complex16_t work[], int* info, int len_uplo); extern void F77(zhetrs)(char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, int ipiv[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zhpcon)(char* uplo, int* n, complex16_t ap[], int ipiv[], double* anorm, double* rcond, complex16_t work[], int* info, int len_uplo); extern void F77(zhpev)(char* jobz, char* uplo, int* n, complex16_t ap[], double w[], complex16_t z[], int* ldz, complex16_t work[], double rwork[], int* info, int len_jobz, int len_uplo); extern void F77(zhpevd)(char* jobz, char* uplo, int* n, complex16_t ap[], double w[], complex16_t z[], int* ldz, complex16_t work[], int* lwork, double rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz, int len_uplo); extern void F77(zhpevx)(char* jobz, char* range, char* uplo, int* n, complex16_t ap[], double* vl, double* vu, int* il, int* iu, double* abstol, int* m, double w[], complex16_t z[], int* ldz, complex16_t work[], double rwork[], int iwork[], int ifail[], int* info, int len_jobz, int len_range, int len_uplo); extern void F77(zhpgv)(int* itype, char* jobz, char* uplo, int* n, complex16_t ap[], complex16_t bp[], double w[], complex16_t z[], int* ldz, complex16_t work[], double rwork[], int* info, int len_jobz, int len_uplo); extern void F77(zhpsv)(char* uplo, int* n, int* nrhs, complex16_t ap[], int ipiv[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zhpsvx)(char* fact, char* uplo, int* n, int* nrhs, complex16_t ap[], complex16_t afp[], int ipiv[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_uplo); extern void F77(zhptrf)(char* uplo, int* n, complex16_t ap[], int ipiv[], int* info, int len_uplo); extern void F77(zhptri)(char* uplo, int* n, complex16_t ap[], int ipiv[], complex16_t work[], int* info, int len_uplo); extern void F77(zhptrs)(char* uplo, int* n, int* nrhs, complex16_t ap[], int ipiv[], complex16_t b[], int* ldb, int* info, int len_uplo); extern double F77(zlangb)(char* norm, int* n, int* kl, int* ku, complex16_t ab[], int* ldab, double rwork[], int len_norm); extern double F77(zlange)(char* norm, int* m, int* n, complex16_t a[], int* lda, double rwork[], int len_norm); extern double F77(zlangt)(char* norm, int* n, complex16_t dl[], complex16_t d[], complex16_t du[], int len_norm); extern double F77(zlanhb)(char* norm, char* uplo, int* n, int* kd, complex16_t ab[], int* ldab, double rwork[], int len_norm, int len_uplo); extern double F77(zlanhe)(char* norm, char* uplo, int* n, complex16_t a[], int* lda, double rwork[], int len_norm, int len_uplo); extern double F77(zlanhp)(char* norm, char* uplo, int* n, complex16_t ap[], double rwork[], int len_norm, int len_uplo); extern double F77(zlanht)(char* norm, int* n, double d[], complex16_t e[], int len_norm); extern double F77(zlansb)(char* norm, char* uplo, int* n, int* kd, complex16_t ab[], int* ldab, double rwork[], int len_norm, int len_uplo); extern double F77(zlansp)(char* norm, char* uplo, int* n, complex16_t ap[], double rwork[], int len_norm, int len_uplo); extern double F77(zlansy)(char* norm, char* uplo, int* n, complex16_t a[], int* lda, double rwork[], int len_norm, int len_uplo); extern void F77(zpbcon)(char* uplo, int* n, int* kd, complex16_t ab[], int* ldab, double* anorm, double* rcond, complex16_t work[], double rwork[], int* info, int len_uplo); extern void F77(zpbsv)(char* uplo, int* n, int* kd, int* nrhs, complex16_t ab[], int* ldab, complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zpbsvx)(char* fact, char* uplo, int* n, int* kd, int* nrhs, complex16_t ab[], int* ldab, complex16_t afb[], int* ldafb, char* equed, double s[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(zpbtrf)(char* uplo, int* n, int* kd, complex16_t ab[], int* ldab, int* info, int len_uplo); extern void F77(zpbtrs)(char* uplo, int* n, int* kd, int* nrhs, complex16_t ab[], int* ldab, complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zpocon)(char* uplo, int* n, complex16_t a[], int* lda, double* anorm, double* rcond, complex16_t work[], double rwork[], int* info, int len_uplo); extern void F77(zposv)(char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zposvx)(char* fact, char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t af[], int* ldaf, char* equed, double s[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(zpotrf)(char* uplo, int* n, complex16_t a[], int* lda, int* info, int len_uplo); extern void F77(zpotri)(char* uplo, int* n, complex16_t a[], int* lda, int* info, int len_uplo); extern void F77(zpotrs)(char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zppcon)(char* uplo, int* n, complex16_t ap[], double* anorm, double* rcond, complex16_t work[], double rwork[], int* info, int len_uplo); extern void F77(zppsv)(char* uplo, int* n, int* nrhs, complex16_t ap[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zppsvx)(char* fact, char* uplo, int* n, int* nrhs, complex16_t ap[], complex16_t afp[], char* equed, double s[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_uplo, int len_equed); extern void F77(zpptrf)(char* uplo, int* n, complex16_t ap[], int* info, int len_uplo); extern void F77(zpptri)(char* uplo, int* n, complex16_t ap[], int* info, int len_uplo); extern void F77(zpptrs)(char* uplo, int* n, int* nrhs, complex16_t ap[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zptcon)(int* n, double d[], complex16_t e[], double* anorm, double* rcond, double rwork[], int* info); extern void F77(zptsv)(int* n, int* nrhs, double d[], complex16_t e[], complex16_t b[], int* ldb, int* info); extern void F77(zptsvx)(char* fact, int* n, int* nrhs, double d[], complex16_t e[], double df[], complex16_t ef[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact); extern void F77(zpttrf)(int* n, double d[], complex16_t e[], int* info); extern void F77(zpttrs)(char* uplo, int* n, int* nrhs, double d[], complex16_t e[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zspcon)(char* uplo, int* n, complex16_t ap[], int ipiv[], double* anorm, double* rcond, complex16_t work[], int* info, int len_uplo); extern void F77(zspsv)(char* uplo, int* n, int* nrhs, complex16_t ap[], int ipiv[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zspsvx)(char* fact, char* uplo, int* n, int* nrhs, complex16_t ap[], complex16_t afp[], int ipiv[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], double rwork[], int* info, int len_fact, int len_uplo); extern void F77(zsptrf)(char* uplo, int* n, complex16_t ap[], int ipiv[], int* info, int len_uplo); extern void F77(zsptri)(char* uplo, int* n, complex16_t ap[], int ipiv[], complex16_t work[], int* info, int len_uplo); extern void F77(zsptrs)(char* uplo, int* n, int* nrhs, complex16_t ap[], int ipiv[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(zstedc)(char* jobz, int* n, double d[], double e[], complex16_t z[], int* ldz, complex16_t work[], int* lwork, double rwork[], int* lrwork, int iwork[], int* liwork, int* info, int len_jobz); extern void F77(zsteqr)(char* jobz, int* n, double d[], double e[], complex16_t z[], int* ldz, double work[], int* info, int len_jobz); extern void F77(zsycon)(char* uplo, int* n, complex16_t a[], int* lda, int ipiv[], double* anorm, double* rcond, complex16_t work[], int* info, int len_uplo); extern void F77(zsysv)(char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, int ipiv[], complex16_t b[], int* ldb, complex16_t work[], int* lwork, int* info, int len_uplo); extern void F77(zsysvx)(char* fact, char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t af[], int* ldaf, int ipiv[], complex16_t b[], int* ldb, complex16_t x[], int* ldx, double* rcond, double ferr[], double berr[], complex16_t work[], int* lwork, double rwork[], int* info, int len_fact, int len_uplo); extern void F77(zsytrf)(char* uplo, int* n, complex16_t a[], int* lda, int ipiv[], complex16_t work[], int* lwork, int* info, int len_uplo); extern void F77(zsytri)(char* uplo, int* n, complex16_t a[], int* lda, int ipiv[], complex16_t work[], int* info, int len_uplo); extern void F77(zsytrs)(char* uplo, int* n, int* nrhs, complex16_t a[], int* lda, int ipiv[], complex16_t b[], int* ldb, int* info, int len_uplo); extern void F77(ztbcon)(char* norm, char* uplo, char* diag, int* n, int* kd, complex16_t ab[], int* ldab, double* rcond, complex16_t work[], double rwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(ztbtrs)(char* uplo, char* trans, char* diag, int* n, int* kd, int* nrhs, complex16_t ab[], int* ldab, complex16_t b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(ztpcon)(char* norm, char* uplo, char* diag, int* n, complex16_t ap[], double* rcond, complex16_t work[], double rwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(ztptri)(char* uplo, char* diag, int* n, complex16_t ap[], int* info, int len_uplo, int len_diag); extern void F77(ztptrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, complex16_t ap[], complex16_t b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(ztrcon)(char* norm, char* uplo, char* diag, int* n, complex16_t a[], int* lda, double* rcond, complex16_t work[], double rwork[], int* info, int len_norm, int len_uplo, int len_diag); extern void F77(ztrtri)(char* uplo, char* diag, int* n, complex16_t a[], int* lda, int* info, int len_uplo, int len_diag); extern void F77(ztrtrs)(char* uplo, char* trans, char* diag, int* n, int* nrhs, complex16_t a[], int* lda, complex16_t b[], int* ldb, int* info, int len_uplo, int len_trans, int len_diag); extern void F77(ztzrqf)(int* m, int* n, complex16_t a[], int* lda, complex16_t tau[], int* info); extern void F77(zunglq)(int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zungql)(int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zungqr)(int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zungrq)(int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t work[], int* lwork, int* info); extern void F77(zunmlq)(char* side, char* trans, int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t c[], int* ldc, complex16_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(zunmql)(char* side, char* trans, int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t c[], int* ldc, complex16_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(zunmqr)(char* side, char* trans, int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t c[], int* ldc, complex16_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(zunmrq)(char* side, char* trans, int* m, int* n, int* k, complex16_t a[], int* lda, complex16_t tau[], complex16_t c[], int* ldc, complex16_t work[], int* lwork, int* info, int len_side, int len_trans); extern void F77(dlacpy)(char *UPLO, int *M, int *N, double *A, int *LDA, double *B, int *LDB, int len_uplo); extern void F77(dlaset)(char *UPLO, int *M, int *N, double *ALPHA, double *BETA, double *A, int *LDA, int len_uplo ); extern void F77(dlarnv)(int *IDIST, int *ISEED, int *N, double *X); #endif pysparse-1.1.1/Include/pysparse/ll_mat.h0000644010116400000240000000323511402267753017240 0ustar wd15dialout#ifndef LL_MAT_H #define LL_MAT_H #include "Python.h" typedef struct { PyObject_VAR_HEAD int dim[2]; /* array dimension */ int issym; /* non-zero, if obj represents a symmetric matrix */ int nnz; /* number of stored items */ int nalloc; /* allocated size of value and index arrays */ int free; /* index to first element in free chain */ double *val; /* pointer to array of values */ int *col; /* pointer to array of indices */ int *link; /* pointer to array of indices */ int *root; /* pointer to array of indices */ } LLMatObject; /****************************************************************************** * * * llColIndexlinked -- list data structure which links the entries of * * each column of a llmat matrix * * * ******************************************************************************/ struct llColIndex{ int *root; /* ptr to array storing first element of each column */ int *row; /* ptr to array of row indices */ int *link; /* ptr to array storing index of next element in column */ int nzLo; /* number of non-zero entries in lower triangle */ int nzDiag; /* number of non-zero entries on diagonal */ int nzUp; /* number of non-zero entries in upper triangle */ }; #ifdef SPMATRIX_MODULE /* forward declarations */ static PyTypeObject LLMatType; /* forward declaration */ #endif #endif pysparse-1.1.1/Include/pysparse/minres.h0000644010116400000240000000350711402267752017266 0ustar wd15dialout/************************************************************************** * * * Swiss Federal Institute of Technology (ETH), * * CH-8092 Zuerich, Switzerland * * * * (C) 1999 All Rights Reserved * * * * NOTICE * * * * Permission to use, copy, modify, and distribute this software and * * its documentation for any purpose and without fee is hereby granted * * provided that the above copyright notice appear in all copies and * * that both the copyright notice and this permission notice appear in * * supporting documentation. * * * * Neither the Swiss Federal Institute of Technology nor the author make * * any representations about the suitability of this software for any * * purpose. This software is provided ``as is'' without express or * * implied warranty. * * * **************************************************************************/ #ifndef MINRES_H #define MINRES_H #include "Python.h" int Itsolvers_minres_kernel(int n, double errtol, int it_max, int *it, double *nrm_res, int clvl, double *x, double *b, double *work, PyObject *mat_obj, PyObject *prec_obj); #endif pysparse-1.1.1/Include/pysparse/mmio.h0000644010116400000240000001013611402267752016726 0ustar wd15dialout/* * Matrix Market I/O library for ANSI C * * See http://math.nist.gov/MatrixMarket for details. * * */ #ifndef MM_IO_H #define MM_IO_H #define MM_MAX_LINE_LENGTH 1025 #define MatrixMarketBanner "%%MatrixMarket" #define MM_MAX_TOKEN_LENGTH 64 typedef char MM_typecode[4]; char *mm_typecode_to_str(MM_typecode matcode); int mm_read_banner(FILE *f, MM_typecode matcode); int mm_read_mtx_crd_size(FILE *f, int *M, int *N, int *nz); int mm_read_mtx_array_size(FILE *f, int *M, int *N); int mm_write_banner(FILE *f, MM_typecode matcode); int mm_write_mtx_crd_size(FILE *f, int M, int N, int nz); int mm_write_mtx_array_size(FILE *f, int M, int N); /********************* MM_typecode query fucntions ***************************/ #define mm_is_matrix(typecode) ((typecode)[0]=='M') #define mm_is_sparse(typecode) ((typecode)[1]=='C') #define mm_is_coordinate(typecode)((typecode)[1]=='C') #define mm_is_dense(typecode) ((typecode)[1]=='A') #define mm_is_array(typecode) ((typecode)[1]=='A') #define mm_is_complex(typecode) ((typecode)[2]=='C') #define mm_is_real(typecode) ((typecode)[2]=='R') #define mm_is_pattern(typecode) ((typecode)[2]=='P') #define mm_is_integer(typecode) ((typecode)[2]=='I') #define mm_is_symmetric(typecode)((typecode)[3]=='S') #define mm_is_general(typecode) ((typecode)[3]=='G') #define mm_is_skew(typecode) ((typecode)[3]=='K') #define mm_is_hermitian(typecode)((typecode)[3]=='H') int mm_is_valid(MM_typecode matcode); /* too complex for a macro */ /********************* MM_typecode modify fucntions ***************************/ #define mm_set_matrix(typecode) ((typecode)[0]='M') #define mm_set_coordinate(typecode) ((typecode)[1]='C') #define mm_set_array(typecode) ((typecode)[1]='A') #define mm_set_dense(typecode) mm_set_array(typecode) #define mm_set_sparse(typecode) mm_set_coordinate(typecode) #define mm_set_complex(typecode)((typecode)[2]='C') #define mm_set_real(typecode) ((typecode)[2]='R') #define mm_set_pattern(typecode)((typecode)[2]='P') #define mm_set_integer(typecode)((typecode)[2]='I') #define mm_set_symmetric(typecode)((typecode)[3]='S') #define mm_set_general(typecode)((typecode)[3]='G') #define mm_set_skew(typecode) ((typecode)[3]='K') #define mm_set_hermitian(typecode)((typecode)[3]='H') #define mm_clear_typecode(typecode) ((typecode)[0]=(typecode)[1]= \ (typecode)[2]=' ',(typecode)[3]='G') #define mm_initialize_typecode(typecode) mm_clear_typecode(typecode) /********************* Matrix Market error codes ***************************/ #define MM_COULD_NOT_READ_FILE 11 #define MM_PREMATURE_EOF 12 #define MM_NOT_MTX 13 #define MM_NO_HEADER 14 #define MM_UNSUPPORTED_TYPE 15 #define MM_LINE_TOO_LONG 16 #define MM_COULD_NOT_WRITE_FILE 17 /******************** Matrix Market internal definitions ******************** MM_matrix_typecode: 4-character sequence ojbect sparse/ data storage dense type scheme string position: [0] [1] [2] [3] Matrix typecode: M(atrix) C(oord) R(eal) G(eneral) A(array) C(omplex) H(ermitian) P(attern) S(ymmetric) I(nteger) K(kew) ***********************************************************************/ #define MM_MTX_STR "matrix" #define MM_ARRAY_STR "array" #define MM_DENSE_STR "array" #define MM_COORDINATE_STR "coordinate" #define MM_SPARSE_STR "coordinate" #define MM_COMPLEX_STR "complex" #define MM_REAL_STR "real" #define MM_INT_STR "integer" #define MM_GENERAL_STR "general" #define MM_SYMM_STR "symmetric" #define MM_HERM_STR "hermitian" #define MM_SKEW_STR "skew-symmetric" #define MM_PATTERN_STR "pattern" /* high level routines */ int mm_write_mtx_crd(char fname[], int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode); int mm_read_mtx_crd_data(FILE *f, int M, int N, int nz, int I[], int J[], double val[], MM_typecode matcode); int mm_read_mtx_crd_entry(FILE *f, int *I, int *J, double *real, double *img, MM_typecode matcode); int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_); #endif pysparse-1.1.1/Include/pysparse/pcg.h0000644010116400000240000000043511402267753016540 0ustar wd15dialout#ifndef PCG_H #define PCG_H #include "Python.h" int Itsolvers_pcg_kernel(int n, double *x, double *b, double tol, int maxit, int clvl, int *iter, double *relres, int *flag, double *work, PyObject *mat_obj, PyObject *prec_obj); #endif pysparse-1.1.1/Include/pysparse/qmrs.h0000644010116400000240000000044411402267756016754 0ustar wd15dialout#ifndef QMRS_H #define QMRS_H #include "fortran.h" #include "Python.h" int Itsolvers_qmrs_kernel(int n, double *b, double *x, double *work, double tol, int maxitera, int *itera, double *err, PyObject *mat_obj, PyObject *prec_obj); #endif pysparse-1.1.1/Include/pysparse/spmatrix.h0000644010116400000240000000437111402267753017641 0ustar wd15dialout#ifndef SPMATRIX_H #define SPMATRIX_H #include "ll_mat.h" #include "csr_mat.h" #include "sss_mat.h" #include "spmatrix_api.h" /* * Macro definitions */ /** SPMATRIX_PARSE_ARGS_ARR_ARR * * Macro for parsing arguments for matvec and precon type operations */ #define SPMATRIX_PARSE_ARGS_ARR_ARR(args, arg1, arg2, n1, n2) \ if (!PyArg_ParseTuple((args), "O!O!", &PyArray_Type, &(arg1), &PyArray_Type, &(arg2))) \ return NULL; \ \ if ((arg1)->nd != 1 || \ (arg1)->descr->type_num != PyArray_DOUBLE || \ (arg1)->dimensions[0] != (n1) || \ !((arg1)->flags & CONTIGUOUS)) { \ PyErr_SetString(PyExc_ValueError, "arg 1 must be a contiguous 1-dimensional double array of appropriate size."); \ return NULL; \ } \ \ if ((arg2)->nd != 1 || \ (arg2)->descr->type_num != PyArray_DOUBLE || \ (arg2)->dimensions[0] != (n2) || \ !((arg2)->flags & CONTIGUOUS)) { \ PyErr_SetString(PyExc_ValueError, "arg 2 must be a contiguous 1-dimensional double array of appropriate size."); \ return NULL; \ } #define SPMATRIX_PARSE_ARGS_ARR_ARR_STRIDE(args, arg1, arg2, n1, n2) \ if (!PyArg_ParseTuple((args), "O!O!", &PyArray_Type, &(arg1), &PyArray_Type, &(arg2))) \ return NULL; \ \ if ((arg1)->nd != 1 || \ (arg1)->descr->type_num != PyArray_DOUBLE || \ (arg1)->dimensions[0] != (n1)) { \ PyErr_SetString(PyExc_ValueError, "arg 1 must be a 1-dimensional double array of appropriate size."); \ return NULL; \ } \ \ if ((arg2)->nd != 1 || \ (arg2)->descr->type_num != PyArray_DOUBLE || \ (arg2)->dimensions[0] != (n2)) { \ PyErr_SetString(PyExc_ValueError, "arg 2 must be a 1-dimensional double array of appropriate size."); \ return NULL; \ } /** SPMATRIX_CHECK_ARR_DIM_SIZE * * Macro for checking the type and size of vector arguments */ #define SPMATRIX_CHECK_ARR_DIM_SIZE(arr, dim, size) \ if ((arr)->nd != (dim) || \ (arr)->descr->type_num != PyArray_DOUBLE || \ (arr)->dimensions[0] != (size) || \ !((arr)->flags & CONTIGUOUS)) { \ PyErr_SetString(PyExc_ValueError, "argument must be a contiguous 1-dimensional double array of appropriate size."); \ return NULL; \ } #ifdef SPMATRIX_MODULE extern PyObject *SpMatrix_ErrorObject; #endif #endif pysparse-1.1.1/Include/pysparse/spmatrix_api.h0000644010116400000240000001726611402267752020500 0ustar wd15dialout#ifndef SPMATRIX_API_H #define SPMATRIX_API_H /* * C API */ /* Type definitions */ #define LLMatType_NUM 0 #define CSRMatType_NUM 1 #define SSSMatType_NUM 2 /* Function definitions */ #define SpMatrix_ParseVecOpArgs_NUM 3 #define SpMatrix_ParseVecOpArgs_RET int #define SpMatrix_ParseVecOpArgs_PROTO (PyObject *args, double **x_data, double **y_data, int n) #define SpMatrix_GetShape_NUM 4 #define SpMatrix_GetShape_RET int #define SpMatrix_GetShape_PROTO (PyObject *, int[]) #define SpMatrix_GetOrder_NUM 5 #define SpMatrix_GetOrder_RET int #define SpMatrix_GetOrder_PROTO (PyObject *, int*) #define SpMatrix_GetItem_NUM 6 #define SpMatrix_GetItem_RET double #define SpMatrix_GetItem_PROTO (PyObject *, int, int) #define SpMatrix_Matvec_NUM 7 #define SpMatrix_Matvec_RET int #define SpMatrix_Matvec_PROTO (PyObject *matrix, int nx, double *x, int ny, double *y) #define SpMatrix_Precon_NUM 8 #define SpMatrix_Precon_RET int #define SpMatrix_Precon_PROTO (PyObject *repc, int n, double *x, double *y) #define SpMatrix_NewLLMatObject_NUM 9 #define SpMatrix_NewLLMatObject_RET PyObject * #define SpMatrix_NewLLMatObject_PROTO (int dim[], int sym, int sizeHint) #define SpMatrix_LLMatGetItem_NUM 10 #define SpMatrix_LLMatGetItem_RET double #define SpMatrix_LLMatGetItem_PROTO (LLMatObject *a, int i, int j) #define SpMatrix_LLMatSetItem_NUM 11 #define SpMatrix_LLMatSetItem_RET int #define SpMatrix_LLMatSetItem_PROTO (LLMatObject *a, int i, int j, double x) #define SpMatrix_LLMatUpdateItemAdd_NUM 12 #define SpMatrix_LLMatUpdateItemAdd_RET int #define SpMatrix_LLMatUpdateItemAdd_PROTO (LLMatObject *a, int i, int j, double x) #define SpMatrix_LLMatBuildColIndex_NUM 13 #define SpMatrix_LLMatBuildColIndex_RET int #define SpMatrix_LLMatBuildColIndex_PROTO (struct llColIndex **idx, LLMatObject *self, int includeDiagonal) #define SpMatrix_LLMatDestroyColIndex_NUM 14 #define SpMatrix_LLMatDestroyColIndex_RET void #define SpMatrix_LLMatDestroyColIndex_PROTO (struct llColIndex **idx) #define ItSolvers_Solve_NUM 15 #define ItSolvers_Solve_RET int #define ItSolvers_Solve_PROTO (PyObject *linsolver, PyObject *A, int n, \ double *b, double *x, double tol, int itmax, PyObject *K, \ int *info, int *iter, double *relres) /* Total number of C API pointers */ #define SpMatrix_API_pointers 16 #ifdef SPMATRIX_MODULE static SpMatrix_ParseVecOpArgs_RET SpMatrix_ParseVecOpArgs SpMatrix_ParseVecOpArgs_PROTO; static SpMatrix_GetShape_RET SpMatrix_GetShape SpMatrix_GetShape_PROTO; static SpMatrix_GetOrder_RET SpMatrix_GetOrder SpMatrix_GetOrder_PROTO; static SpMatrix_GetItem_RET SpMatrix_GetItem SpMatrix_GetItem_PROTO; static SpMatrix_Matvec_RET SpMatrix_Matvec SpMatrix_Matvec_PROTO; static SpMatrix_Precon_RET SpMatrix_Precon SpMatrix_Precon_PROTO; static SpMatrix_NewLLMatObject_RET SpMatrix_NewLLMatObject SpMatrix_NewLLMatObject_PROTO; static SpMatrix_LLMatGetItem_RET SpMatrix_LLMatGetItem SpMatrix_LLMatGetItem_PROTO; static SpMatrix_LLMatSetItem_RET SpMatrix_LLMatSetItem SpMatrix_LLMatSetItem_PROTO; static SpMatrix_LLMatUpdateItemAdd_RET SpMatrix_LLMatUpdateItemAdd SpMatrix_LLMatUpdateItemAdd_PROTO; static SpMatrix_LLMatBuildColIndex_RET SpMatrix_LLMatBuildColIndex SpMatrix_LLMatBuildColIndex_PROTO; static SpMatrix_LLMatDestroyColIndex_RET SpMatrix_LLMatDestroyColIndex SpMatrix_LLMatDestroyColIndex_PROTO; static ItSolvers_Solve_RET ItSolvers_Solve ItSolvers_Solve_PROTO; #define init_c_api(MODULE_DICT) \ { \ static void *SpMatrix_API[SpMatrix_API_pointers]; \ PyObject *c_api_object; \ \ /* initialize C API pointer array */ \ SpMatrix_API[LLMatType_NUM] = (void *) &LLMatType; \ SpMatrix_API[CSRMatType_NUM] = (void *) &CSRMatType; \ SpMatrix_API[SSSMatType_NUM] = (void *) &SSSMatType; \ SpMatrix_API[SpMatrix_ParseVecOpArgs_NUM] = (void *) SpMatrix_ParseVecOpArgs; \ SpMatrix_API[SpMatrix_GetShape_NUM] = (void *) SpMatrix_GetShape; \ SpMatrix_API[SpMatrix_GetOrder_NUM] = (void *) SpMatrix_GetOrder; \ SpMatrix_API[SpMatrix_GetItem_NUM] = (void *) SpMatrix_GetItem; \ SpMatrix_API[SpMatrix_Matvec_NUM] = (void *) SpMatrix_Matvec; \ SpMatrix_API[SpMatrix_Precon_NUM] = (void *) SpMatrix_Precon; \ SpMatrix_API[SpMatrix_NewLLMatObject_NUM] = (void *) SpMatrix_NewLLMatObject; \ SpMatrix_API[SpMatrix_LLMatGetItem_NUM] = (void *) SpMatrix_LLMatGetItem; \ SpMatrix_API[SpMatrix_LLMatSetItem_NUM] = (void *) SpMatrix_LLMatSetItem; \ SpMatrix_API[SpMatrix_LLMatUpdateItemAdd_NUM] = (void *) SpMatrix_LLMatUpdateItemAdd; \ SpMatrix_API[SpMatrix_LLMatBuildColIndex_NUM] = (void *) SpMatrix_LLMatBuildColIndex; \ SpMatrix_API[SpMatrix_LLMatDestroyColIndex_NUM] = (void *) SpMatrix_LLMatDestroyColIndex; \ SpMatrix_API[ItSolvers_Solve_NUM] = (void *) ItSolvers_Solve; \ \ /* Create a CObject containing the API pointer array s address */ \ c_api_object = PyCObject_FromVoidPtr((void *)SpMatrix_API, NULL); \ \ /* create a name for this object in the module's namespace */ \ if (c_api_object != NULL) { \ PyDict_SetItemString((MODULE_DICT), "_C_API", c_api_object); \ Py_DECREF(c_api_object); \ } \ } #else #ifdef SPMATRIX_UNIQUE_SYMBOL #define SpMatrix_API SPMATRIX_UNIQUE_SYMBOL #endif /* C API address pointer */ #ifdef NO_IMPORT_SPMATRIX extern void **SpMatrix_API; #else #ifdef SPMATRIX_UNIQUE_SYMBOL void **SpMatrix_API; #else static void **SpMatrix_API; #endif #endif #define LLMatType *(PyTypeObject *)SpMatrix_API[LLMatType_NUM] #define CSRMatType *(PyTypeObject *)SpMatrix_API[CSRMatType_NUM] #define SSSMatType *(PyTypeObject *)SpMatrix_API[SSSMatType_NUM] #define SpMatrix_ParseVecOpArgs \ (*(SpMatrix_ParseVecOpArgs_RET (*)SpMatrix_ParseVecOpArgs_PROTO) \ SpMatrix_API[SpMatrix_ParseVecOpArgs_NUM]) #define SpMatrix_GetShape \ (*(SpMatrix_GetShape_RET (*)SpMatrix_GetShape_PROTO) \ SpMatrix_API[SpMatrix_GetShape_NUM]) #define SpMatrix_GetOrder \ (*(SpMatrix_GetOrder_RET (*)SpMatrix_GetOrder_PROTO) \ SpMatrix_API[SpMatrix_GetOrder_NUM]) #define SpMatrix_GetItem \ (*(SpMatrix_GetItem_RET (*)SpMatrix_GetItem_PROTO) \ SpMatrix_API[SpMatrix_GetItem_NUM]) #define SpMatrix_Matvec \ (*(SpMatrix_Matvec_RET (*)SpMatrix_Matvec_PROTO) \ SpMatrix_API[SpMatrix_Matvec_NUM]) #define SpMatrix_Precon \ (*(SpMatrix_Precon_RET (*)SpMatrix_Precon_PROTO) \ SpMatrix_API[SpMatrix_Precon_NUM]) #define SpMatrix_NewLLMatObject \ (*(SpMatrix_NewLLMatObject_RET (*)SpMatrix_NewLLMatObject_PROTO) \ SpMatrix_API[SpMatrix_NewLLMatObject_NUM]) #define SpMatrix_LLMatGetItem \ (*(SpMatrix_LLMatGetItem_RET (*)SpMatrix_LLMatGetItem_PROTO) \ SpMatrix_API[SpMatrix_LLMatGetItem_NUM]) #define SpMatrix_LLMatSetItem \ (*(SpMatrix_LLMatSetItem_RET (*)SpMatrix_LLMatSetItem_PROTO) \ SpMatrix_API[SpMatrix_LLMatSetItem_NUM]) #define SpMatrix_LLMatUpdateItemAdd \ (*(SpMatrix_LLMatUpdateItemAdd_RET (*)SpMatrix_LLMatUpdateItemAdd_PROTO) \ SpMatrix_API[SpMatrix_LLMatUpdateItemAdd_NUM]) #define SpMatrix_LLMatBuildColIndex \ (*(SpMatrix_LLMatBuildColIndex_RET (*)SpMatrix_LLMatBuildColIndex_PROTO) \ SpMatrix_API[SpMatrix_LLMatBuildColIndex_NUM]) #define SpMatrix_LLMatDestroyColIndex \ (*(SpMatrix_LLMatDestroyColIndex_RET (*)SpMatrix_LLMatDestroyColIndex_PROTO) \ SpMatrix_API[SpMatrix_LLMatDestroyColIndex_NUM]) #define ItSolvers_Solve \ (*(ItSolvers_Solve_RET (*)ItSolvers_Solve_PROTO) \ SpMatrix_API[ItSolvers_Solve_NUM]) #define import_spmatrix() \ { \ PyObject *spmatrix = PyImport_ImportModule("pysparse.spmatrix"); \ if (spmatrix != NULL) { \ PyObject *module_dict = PyModule_GetDict(spmatrix); \ PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \ if (PyCObject_Check(c_api_object)) { \ SpMatrix_API = (void **)PyCObject_AsVoidPtr(c_api_object); \ } \ } \ assert(SpMatrix_API != NULL); \ } #endif #endif pysparse-1.1.1/Include/pysparse/sss_mat.h0000644010116400000240000000102611402267754017436 0ustar wd15dialout#ifndef SSS_MAT_H #define SSS_MAT_H #include "Python.h" typedef struct { PyObject_VAR_HEAD int n; /* array dimension */ int nnz; /* number of stored items */ double *val; /* pointer to array of values */ double *diag; /* pointer to diagonal elements */ int *col; /* pointer to array of indices */ int *ind; /* pointer to array of indices */ } SSSMatObject; #ifdef SPMATRIX_MODULE /* forward declarations */ static PyTypeObject SSSMatType; static PyObject *newSSSMatObject(int n, int nnz); #endif #endif pysparse-1.1.1/Include/pysparse/util.h0000644010116400000240000000642211402267755016750 0ustar wd15dialout#ifndef __SUPERLU_UTIL /* allow multiple inclusions */ #define __SUPERLU_UTIL #include #include #include #include /* Macros */ #ifndef USER_ABORT #define USER_ABORT(msg) superlu_abort_and_exit(msg) #endif #define ABORT(err_msg) \ { char msg[256];\ sprintf(msg,"%s at line %d in file %s\n",err_msg,__LINE__, __FILE__);\ USER_ABORT(msg); } #ifndef USER_MALLOC #define USER_MALLOC(size) superlu_malloc(size) #endif #define SUPERLU_MALLOC(size) USER_MALLOC(size) #ifndef USER_FREE #define USER_FREE(addr) superlu_free(addr) #endif #define SUPERLU_FREE(addr) USER_FREE(addr) #define MAX(x, y) ( (x) > (y) ? (x) : (y) ) #define MIN(x, y) ( (x) < (y) ? (x) : (y) ) /* * Constants */ #define EMPTY (-1) #define NO (-1) #define FALSE 0 #define TRUE 1 /* * Type definitions */ typedef float flops_t; typedef unsigned char Logical; /* * The following enumerate type is used by the statistics variable * SuperLUStat, to keep track of flop count and time spent at various stages. * * Note that not all of the fields are disjoint. */ typedef enum { COLPERM, /* find a column ordering that minimizes fills */ RELAX, /* find artificial supernodes */ ETREE, /* compute column etree */ EQUIL, /* equilibrate the original matrix */ FACT, /* perform LU factorization */ RCOND, /* estimate reciprocal condition number */ SOLVE, /* forward and back solves */ REFINE, /* perform iterative refinement */ FLOAT, /* time spent in floating-point operations */ TRSV, /* fraction of FACT spent in xTRSV */ GEMV, /* fraction of FACT spent in xGEMV */ FERR, /* estimate error bounds after iterative refinement */ NPHASES /* total number of phases */ } PhaseType; typedef struct { int *panel_histo; /* histogram of panel size distribution */ double *utime; /* running time at various phases */ flops_t *ops; /* operation count at various phases */ } SuperLUStat_t; /* Macros */ #define FIRSTCOL_OF_SNODE(i) (xsup[i]) #ifdef __cplusplus extern "C" { #endif extern void superlu_abort_and_exit(char*); extern void *superlu_malloc (int); extern int *intMalloc (int); extern int *intCalloc (int); extern void superlu_free (void*); extern void SetIWork (int, int, int, int *, int **, int **, int **, int **, int **, int **, int **); extern void StatInit(int, int); extern void StatFree(); extern int sp_coletree (int *, int *, int *, int, int, int *); extern void relax_snode (const int, int *, const int, int *, int *); extern void resetrep_col (const int, const int *, int *); extern int spcoletree (int *, int *, int *, int, int, int *); extern int *TreePostorder (int, int *); extern double SuperLU_timer_ (); extern int sp_ienv (int); extern int lsame_ (char *, char *); extern int xerbla_ (char *, int *); extern void ifill (int *, int, int); extern void snode_profile (int, int *); extern void super_stats (int, int *); extern void PrintSumm (char *, int, int, int); extern void PrintStat (SuperLUStat_t *); extern void print_panel_seg(int, int, int, int, int *, int *); extern void check_repfnz(int, int, int, int *); #ifdef __cplusplus } #endif #endif /* __SUPERLU_UTIL */ pysparse-1.1.1/Lib/0000755010116400000240000000000011402271040013051 5ustar wd15dialoutpysparse-1.1.1/Lib/__init__.py0000644010116400000240000000033411402270344015170 0ustar wd15dialoutimport os execfile(os.path.join(__path__[0], '__version__.py')) try: import spmatrix import itsolvers import jdsym import precon import superlu import umfpack import sparray except: pass pysparse-1.1.1/Lib/__version__.py0000644010116400000240000000002611402270344015710 0ustar wd15dialout__version__ = '1.1.1' pysparse-1.1.1/Lib/directSolver.py0000644010116400000240000000065511402270345016105 0ustar wd15dialout""" A framework for solving sparse linear systems of equations using a direct factorization. """ __docformat__ = 'restructuredtext' import pysparseMatrix as psm import numpy class PysparseDirectSolver: """ `PysparseDirectSolver` is a generic class and should be subclassed. """ def __init__(self, A, **kwargs): return def solve(self, b, **kwargs): raise NotImplementedError return pysparse-1.1.1/Lib/itsolvers_util.py0000644010116400000240000000607711402270345016533 0ustar wd15dialout"""This module defines encapsulation classes for all iterative solvers implemented in the itsolvers module. All classes provide a method "solve(b, x)" for approximatively compute x = inv(A)*b. The classes are intended to replace superlu.superlu_context in cases where appropriate.""" import itsolvers class ItSolver: "abstract base class for iteravtive solver classes" def __init__(self, A, tol, maxit, K, debug): self.A = A self.tol = tol self.maxit = maxit self.K = K self.nofCalled = 0 self.totalIterations = 0 self.lastIterations = 0 self.lastInfo = 0 self.debug = debug def solve(self, b, x): "solve A*x = b iteratively with zero initial guess" x[:] = 0 info, iter, relres = self.itsolver(self.A, b, x, self.tol, self.maxit, self.K) self.nofCalled += 1 self.totalIterations += iter self.lastIterations = iter self.lastInfo = info if self.debug: print 'iterative solver returned:', info, iter, relres if info < 0: raise 'error', ('iterative solver %s returned error code %d' % (self.__class__.__name__, info), info, iter, relres) def __str__(self): s = '<%s.%s instance>\n\n' % (self.__class__.__module__, self.__class__.__name__) for name in ['nofCalled', 'totalIterations', 'lastIterations', 'lastInfo']: s += ' %s: %s\n' % (name, getattr(self, name)) s += '\n' return s def __repr__(self): return self.__str__() class Pcg(ItSolver): def __init__(self, A, tol, maxit, K=None, debug=0): ItSolver.__init__(self, A, tol, maxit, K, debug) self.itsolver = itsolvers.pcg class Minres(ItSolver): def __init__(self, A, tol, maxit, K=None, debug=0): ItSolver.__init__(self, A, tol, maxit, K, debug) self.itsolver = itsolvers.minres class Qmrs(ItSolver): def __init__(self, A, tol, maxit, K=None, debug=0): ItSolver.__init__(self, A, tol, maxit, K, debug) self.itsolver = itsolvers.qmrs class Cgs(ItSolver): """wrapper class for the itsolvers.cgs iterative solver Cgs(A, tol, maxit, K=None) constructs the Cgs object. methods: solve(b, x) solves the linear system A*x = b with a zero initial guess """ def __init__(self, A, tol, maxit, K=None, debug=0): ItSolver.__init__(self, A, tol, maxit, K, debug) self.itsolver = itsolvers.cgs if __name__ == '__main__': import math import numpy import precon, poisson A = poisson.poisson2d_sym(100) n = A.shape[0]; b = numpy.ones(n, 'd'); b = b / math.sqrt(numpy.dot(b, b)) x = numpy.zeros(n, 'd') def resid(A, b, x): r = x.copy() A.matvec(x, r) r = b - r return math.sqrt(numpy.dot(r, r)) solver = Pcg(A, 1e-10, 300) solver.solve(b, x) print resid(A, b, x), solver.nofCalled, solver.totalIterations solver.K = precon.ssor(A.to_sss()) solver.solve(b, x) print resid(A, b, x), solver.nofCalled, solver.totalIterations pysparse-1.1.1/Lib/poisson.py0000644010116400000240000000270511402270343015126 0ustar wd15dialoutimport spmatrix import numpy def poisson1d(n): L = spmatrix.ll_mat(n, n, 3*n-2) for i in range(n): L[i,i] = 2 if i > 0: L[i,i-1] = -1 if i < n-1: L[i,i+1] = -1 return L def poisson1d_sym(n): L = spmatrix.ll_mat_sym(n, 2*n-1) for i in range(n): L[i,i] = 2 if i > 0: L[i,i-1] = -1 return L def poisson2d(n): n2 = n*n L = spmatrix.ll_mat(n2, n2, 5*n2-4*n) for i in range(n): for j in range(n): k = i + n*j L[k,k] = 4 if i > 0: L[k,k-1] = -1 if i < n-1: L[k,k+1] = -1 if j > 0: L[k,k-n] = -1 if j < n-1: L[k,k+n] = -1 return L def poisson2d_sym(n): n2 = n*n L = spmatrix.ll_mat_sym(n2, 3*n2-2*n) for i in range(n): for j in range(n): k = i + n*j L[k,k] = 4 if i > 0: L[k,k-1] = -1 if j > 0: L[k,k-n] = -1 return L def poisson2d_sym_blk(n): n2 = n*n L = spmatrix.ll_mat_sym(n2, 3*n2-2*n) I = spmatrix.ll_mat_sym(n, n) for i in range(n): I[i,i] = -1 P = spmatrix.ll_mat_sym(n, 2*n-1) for i in range(n): P[i,i] = 4 if i > 0: P[i,i-1] = -1 for i in range(0, n*n, n): L[i:i+n,i:i+n] = P if i > 0: L[i:i+n,i-n:i] = I return L pysparse-1.1.1/Lib/poisson_vec.py0000644010116400000240000000506511402270346015770 0ustar wd15dialout# A vectorized Poisson module from pysparse import spmatrix import numpy def poisson1d_vec(n): L = spmatrix.ll_mat(n, n, 3*n-2) e = numpy.ones(n) d = numpy.arange(n, dtype=numpy.int) L.put(2*e, d, d) L.put(-e[1:], d[1:], d[:-1]) L.put(-e[1:], d[:-1], d[1:]) return L def poisson1d_sym_vec(n): L = spmatrix.ll_mat_sym(n, 2*n-1) e = numpy.ones(n) d = numpy.arange(n, dtype=numpy.int) L.put(2*e, d, d) L.put(-e[1:], d[1:], d[:-1]) return L def poisson2d_vec(n): # First version, proceed block by block n2 = n*n L = spmatrix.ll_mat(n2, n2, 5*n2-4*n) e = numpy.ones(n) d = numpy.arange(n, dtype=numpy.int) din = d for i in xrange(n): # Diagonal blocks L.put(4*e, din, din) L.put(-e[1:], din[1:], din[:-1]) L.put(-e[1:], din[:-1], din[1:]) # Outer blocks L.put(-e, n+din, din) L.put(-e, din, n+din) din = d + i*n # Last diagonal block L.put(4*e, din, din) L.put(-e[1:], din[1:], din[:-1]) L.put(-e[1:], din[:-1], din[1:]) return L def poisson2d_vec2(n): # Second version, allocate long arrays n2 = n*n L = spmatrix.ll_mat(n2, n2, 5*n2-4*n) e = numpy.ones(n2) d = numpy.arange(n2, dtype=numpy.int) L.put(4*e, d, d) din = d[:n] for i in xrange(n): # Diagonal blocks L.put(-e[:n-1], din[1:], din[:-1]) L.put(-e[:n-1], din[:-1], din[1:]) # Outer blocks L.put(-e[:n], n+din, din) L.put(-e[:n], din, n+din) din = d[i*n:(i+1)*n] # Last diagonal block L.put(-e[:n-1], din[1:], din[:-1]) L.put(-e[:n-1], din[:-1], din[1:]) return L def poisson2d_sym_vec(n): n2 = n*n L = spmatrix.ll_mat_sym(n2, 3*n2-2*n) e = numpy.ones(n) d = numpy.arange(n, dtype=numpy.int) din = d for i in xrange(n): # Diagonal blocks L.put(4*e, din, din) L.put(-e[1:], din[1:], din[:-1]) # Outer blocks L.put(-e, n+din, din) din = d + i*n # Last diagonal block L.put(4*e, din, din) L.put(-e[1:], din[1:], din[:-1]) return L def poisson2d_sym_blk_vec(n): n2 = n*n L = spmatrix.ll_mat_sym(n2, 3*n2-2*n) D = spmatrix.ll_mat_sym(n, 2*n-1) e = numpy.ones(n) d = numpy.arange(n, dtype=numpy.int) D.put(4*e, d, d) D.put(-e[1:], d[1:], d[:-1]) P = spmatrix.ll_mat(n, n, n-1) P.put(-e,d,d) for i in xrange(n-1): L[i*n:(i+1)*n, i*n:(i+1)*n] = D L[(i+1)*n:(i+2)*n, i*n:(i+1)*n] = P # Last diagonal block L[n2-n:n2, n2-n:n2] = D return L pysparse-1.1.1/Lib/pysparseMatrix.py0000644010116400000240000004547011402270343016475 0ustar wd15dialout#!/usr/bin/env python ## -*-Pyth-*- # ################################################################### # FiPy - Python-based finite volume PDE solver # # FILE: "pysparseMatrix.py" # created: 11/10/03 {3:15:38 PM} # last update: 1/3/07 {3:03:32 PM} # Author: Jonathan Guyer # Author: Daniel Wheeler # Author: James Warren # mail: NIST # www: http://www.ctcms.nist.gov/fipy/ # # ======================================================================== # This software was developed at the National Institute of Standards # and Technology by employees of the Federal Government in the course # of their official duties. Pursuant to title 17 Section 105 of the # United States Code this software is not subject to copyright # protection and is in the public domain. FiPy is an experimental # system. NIST assumes no responsibility whatsoever for its use by # other parties, and makes no guarantees, expressed or implied, about # its quality, reliability, or any other characteristic. We would # appreciate acknowledgement if the software is used. # # This software can be redistributed and/or modified freely # provided that any derivative works bear some notice that they are # derived from it, and any modified versions bear some notice that # they have been modified. # ======================================================================== # # Description: # # History # # modified by rev reason # ---------- --- --- ----------- # 2003-11-10 JEG 1.0 original # ################################################################### ## # A number of updates by Dominique Orban # - allow creation of rectangular and square symmetric matrices # - updates to __add__ and others to allow addition/subtraction of symmetric # matrices # - new creator function PysparseMatrixSpDiags() to create banded matrices # with given diagonals. __docformat__ = 'restructuredtext' from pysparse import spmatrix from sparseMatrix import SparseMatrix import numpy class PysparseMatrix(SparseMatrix): """ A PysparseMatrix is a class wrapper for the pysparse spmatrix sparse matrix type. This class facilitates matrix populating and allows intuitive operations on sparse matrices and vectors. :Currently accepted keywords include: +-------------+------------------------------------------------------------+ | `nrow` | The number of rows of the matrix | +-------------+------------------------------------------------------------+ | `ncol` | The number of columns of the matrix | +-------------+------------------------------------------------------------+ | `size` | The common number of rows and columns, for a square matrix | +-------------+------------------------------------------------------------+ | `bandwidth` | The bandwidth (if creating a band matrix) | +-------------+------------------------------------------------------------+ | `matrix` | The starting `spmatrix` if there is one | +-------------+------------------------------------------------------------+ | `sizeHint` | A guess on the number of nonzero elements of the matrix | +-------------+------------------------------------------------------------+ | `symmetric` | A boolean indicating whether the matrix is symmetric. | +-------------+------------------------------------------------------------+ """ def __init__(self, **kwargs): nrow = kwargs.get('nrow', 0) ncol = kwargs.get('ncol', 0) bandwidth = kwargs.get('bandwidth', 0) matrix = kwargs.get('matrix', None) sizeHint = kwargs.get('sizeHint', 0) symmetric = 'symmetric' in kwargs and kwargs['symmetric'] size = kwargs.get('size',0) if size > 0: if nrow > 0 or ncol > 0: if size != nrow or size != ncol: msg = 'size argument was given but does not match ' msg += 'nrow and ncol' raise ValueError, msg else: nrow = ncol = size if matrix is not None: self.matrix = matrix else: if symmetric and nrow==ncol: if sizeHint is None: sizeHint = nrow if bandwidth > 0: sizeHint += 2*(bandwidth-1)*(2*nrow-bandwidth-2) self.matrix = spmatrix.ll_mat_sym(nrow, sizeHint) else: if sizeHint is None: sizeHint = min(nrow,ncol) if bandwidth > 0: sizeHint = bandwidth * (2*sizeHint-bandwidth-1)/2 self.matrix = spmatrix.ll_mat(nrow, ncol, sizeHint) def isSymmetric(self): "Returns `True` is `self` is a symmetric matrix or `False` otherwise" if self.matrix.issym: return True return False def getNnz(self): "Returns the number of nonzero elements of `self`" return self.matrix.nnz def getMatrix(self): "Returns the underlying `ll_mat` sparse matrix of `self`" return self.matrix def copy(self): "Returns a (deep) copy of a sparse matrix" return PysparseMatrix(matrix = self.matrix.copy()) def __coerce__(self, other): return self, other def __getattr__(self, name): if name == 'nnz': return self.getNnz() elif name == 'shape': return self.getShape() msg = 'No such attribute: %s' % name raise ValueError, msg def __getitem__(self, index): m = self.matrix[index] if isinstance(m, int) or isinstance(m, float): return m else: return PysparseMatrix(matrix = m, symmetric=self.matrix.issym) def __setitem__(self, index, value): #if type(value) is type(self): if isinstance(value, PysparseMatrix): self.matrix[index] = value.matrix else: self.matrix[index] = value def __iadd__(self, other): # In-place addition return self._iadd(self.getMatrix(), other) def _iadd(self, L, other, sign = 1): # In-place addition helper if other != 0: if self.isSymmetric() and not other.isSymmetric(): L.generalize() L.shift(sign, other.getMatrix()) return self def __add__(self, other): """ Add two sparse matrices, return a new sparse matrix >>> L = PysparseMatrix(size = 3) >>> L.put([3.,10.,numpy.pi,2.5], [0,0,1,2], [2,1,1,0]) >>> print L + PysparseIdentityMatrix(size = 3) 1.000000 10.000000 3.000000 --- 4.141593 --- 2.500000 --- 1.000000 >>> print L + 0 --- 10.000000 3.000000 --- 3.141593 --- 2.500000 --- --- >>> print L + 3 --- 13.000000 6.000000 --- 6.141593 --- 5.500000 --- --- """ if other is 0 or other is 0.0: return self elif isinstance(other, int) or isinstance(other, float): #type(other) in [type(1), type(1.0)]: # Add give value to all elements of sparse matrix in nonzero pattern L = self.copy() val, irow, jcol = L.find() L.matrix.update_add_at( other*numpy.ones(val.shape), irow, jcol) return L elif type(self) is type(other): if self.getShape() != other.getShape(): msg = 'Only sparse matrices of the same size may be added' raise TypeError, msg L = self.matrix.copy() if self.isSymmetric() and not other.isSymmetric(): L.generalize() L.shift(1, other.getMatrix()) return PysparseMatrix(matrix = L) def __sub__(self, other): if isinstance(other,int) or isinstance(other, float): #type(other) in [type(1), type(1.0)]: return self.__add__(-other) else: if self.getShape() != other.getShape(): msg = 'Only sparse matrices of the same size may be subtracted' raise TypeError, msg L = self.matrix.copy() if self.isSymmetric() and not other.isSymmetric(): L.generalize() L.shift(-1, other.getMatrix()) return PysparseMatrix(matrix = L) def __isub__(self, other): # In-place subtraction return self._iadd(self.getMatrix(), other, sign=-1) def __mul__(self, other): """ Multiply a sparse matrix by another sparse matrix >>> L1 = PysparseMatrix(size = 3) >>> L1.put([3.,10.,numpy.pi,2.5], [0,0,1,2], [2,1,1,0]) >>> L2 = PysparseMatrix(size = 3) >>> L2.put(numpy.ones(3), numpy.arange(3), numpy.arange(3)) >>> L2.put([4.38,12357.2,1.1], [2,1,0], [1,0,2]) >>> tmp = numpy.array(((1.23572000e+05, 2.31400000e+01, 3.00000000e+00), ... (3.88212887e+04, 3.14159265e+00, 0.00000000e+00), ... (2.50000000e+00, 0.00000000e+00, 2.75000000e+00))) >>> numpy.allclose((L1 * L2).getNumpyArray(), tmp) 1 or a sparse matrix by a vector >>> tmp = numpy.array((29., 6.28318531, 2.5)) >>> numpy.allclose(L1 * numpy.array((1,2,3),'d'), tmp) 1 or a vector by a sparse matrix >>> tmp = numpy.array((7.5, 16.28318531, 3.)) >>> numpy.allclose(numpy.array((1,2,3),'d') * L1, tmp) ## The multiplication is broken. Numpy is calling __rmul__ for every element instead of with the whole array. 1 """ M, N = self.getShape() if isinstance(other, PysparseMatrix): if N != other.getShape()[0]: raise TypeError, 'Matrices dimensions do not match for product' p = spmatrix.matrixmultiply(self.matrix, other.getMatrix()) return PysparseMatrix(matrix=p) else: shape = numpy.shape(other) if shape == (): # other is a scalar p = self.matrix.copy() p.scale(other) return PysparseMatrix(matrix=p) elif shape == (N,): y = numpy.empty(M) self.matrix.matvec(other, y) return y else: raise TypeError, 'Cannot multiply objects' def __imul__(self, other): # In-place multiplication (by a scalar) #if type(other) not in [type(0), type(0.0)]: if not (isinstance(other, int) or isinstance(other, float)): raise TypeError, 'In-place multiplication is with scalars only' p = self.matrix p.scale(other) return self def __rmul__(self, other): # Compute other * A which is really A^T * other if type(numpy.ones(1.0)) == type(other): M, N = self.getShape() y = numpy.empty(N) self.matrix.matvec_transp(other, y) return y else: return self * other def getShape(self): "Returns the shape ``(nrow,ncol)`` of a sparse matrix" return self.matrix.shape def find(self): """ Returns three Numpy arrays to describe the sparsity pattern of ``self`` in so-called coordinate (or triplet) format: >>> L = PysparseMatrix(size = 3) >>> L.put([3.,10.,numpy.pi,2.5], [0,0,1,2], [2,1,1,0]) >>> (val,irow,jcol) = L.find() >>> val array([ 10. , 3. , 3.14159265, 2.5 ]) >>> irow array([0, 0, 1, 2]) >>> jcol array([1, 2, 1, 0]) """ return self.matrix.find() def put(self, value, id1, id2): """ Put elements of ``value`` at positions of the matrix corresponding to ``(id1, id2)`` >>> L = PysparseMatrix(size = 3) >>> L.put( [3.,10.,numpy.pi,2.5], [0,0,1,2], [2,1,1,0] ) >>> print L --- 10.000000 3.000000 --- 3.141593 --- 2.500000 --- --- >>> L.put(2*numpy.pi, range(3), range(3)) >>> print L 6.283185 10.000000 3.000000 --- 6.283185 --- 2.500000 --- 6.283185 If ``value`` is a scalar, it has the same effect as the vector of appropriate length with all values equal to ``value``. If ``id1`` is omitted, it is replaced with ``range(nrow)``. If ``id2`` is omitted, it is replaced with ``range(ncol)``. """ self.matrix.put(value, id1, id2) return None def putDiagonal(self, vector): """ Put elements of ``vector`` along diagonal of matrix >>> L = PysparseMatrix(size = 3) >>> L.putDiagonal([3.,10.,numpy.pi]) >>> print L 3.000000 --- --- --- 10.000000 --- --- --- 3.141593 >>> L.putDiagonal([10.,3.]) >>> print L 10.000000 --- --- --- 3.000000 --- --- --- 3.141593 >>> L.putDiagonal(2.7182) >>> print L 2.718200 --- --- --- 2.718200 --- --- --- 2.718200 """ if isinstance(vector, int) or isinstance(vector, float): ids = numpy.arange(self.getShape()[0]) #tmp = numpy.zeros((self.getShape()[0],), 'd') #tmp[:] = vector self.put(vector, ids, ids) else: #ids = numpy.arange(len(vector)) self.matrix.put(vector) #, ids, ids) def take(self, id1, id2): """ Extract elements at positions ``(irow[i], jcol[i])`` and place them in the array ``val``. In other words:: for i in range(len(val)): val[i] = A[irow[i],jcol[i]] """ vector = numpy.zeros(len(id1), 'd') self.matrix.take(vector, id1, id2) return vector def takeDiagonal(self): """ Extract the diagonal of a matrix and place it in a Numpy array. """ ids = numpy.arange(self.getShape()[0]) return self.take(ids, ids) def addAt(self, vector, id1, id2): """ Add elements of ``vector`` to the positions in the matrix corresponding to ``(id1,id2)`` >>> L = PysparseMatrix(size = 3) >>> L.put([3.,10.,numpy.pi,2.5], [0,0,1,2], [2,1,1,0]) >>> L.addAt((1.73,2.2,8.4,3.9,1.23), (1,2,0,0,1), (2,2,0,0,2)) >>> print L 12.300000 10.000000 3.000000 --- 3.141593 2.960000 2.500000 --- 2.200000 """ self.matrix.update_add_at(vector, id1, id2) def addAtDiagonal(self, vector): """ Add the components of vector ``vector`` to the diagonal elements of the matrix. """ #if type(vector) in [type(1), type(1.)]: if isinstance(vector, int) or isinstance(vector, float): ids = numpy.arange(self.getShape()[0]) tmp = numpy.empty((self.getShape()[0],), 'd') tmp[:] = vector self.addAt(tmp, ids, ids) else: ids = numpy.arange(len(vector)) self.addAt(vector, ids, ids) def getNumpyArray(self): """ Convert a sparse matrix to a dense Numpy matrix. """ shape = self.getShape() indices = numpy.indices(shape) numMatrix = self.take(indices[0].ravel(), indices[1].ravel()) return numpy.reshape(numMatrix, shape) def matvec(self, x): """ This method is required for scipy solvers. """ return self * x def exportMmf(self, filename): """ Exports the matrix to a Matrix Market file of the given filename. """ self.matrix.export_mtx(filename) class PysparseIdentityMatrix(PysparseMatrix): """ Represents a sparse identity matrix for pysparse. >>> print PysparseIdentityMatrix(size = 3) 1.000000 --- --- --- 1.000000 --- --- --- 1.000000 """ def __init__(self, size): PysparseMatrix.__init__(self, nrow=size, ncol=size, bandwidth=1, symmetric=True) ids = numpy.arange(size) self.put(numpy.ones(size), ids, ids) class PysparseSpDiagsMatrix(PysparseMatrix): """ Represents a banded matrix with specified diagonals. *Example:* Create a tridiagonal matrix with 1's on the diagonal, 2's above the diagonal, and -2's below the diagonal. >>> from numpy import ones >>> e = ones(5) >>> print PysparseSpDiagsMatrix(size=5, vals=(-2*e,e,2*e), pos=(-1,0,1)) 1.000000 2.000000 --- --- --- -2.000000 1.000000 2.000000 --- --- --- -2.000000 1.000000 2.000000 --- --- --- -2.000000 1.000000 2.000000 --- --- --- -2.000000 1.000000 Note that since the `pos[k]`-th diagonal has `size-|pos[k]|` elements, only that many first elements of `vals[k]` will be inserted. If the banded matrix is requested to be symmetric, elements above the main diagonal are not inserted. """ def __init__(self, size, vals, pos, **kwargs): if type(pos) in [ type(()), type([]) ]: pos = numpy.array(pos) bw = max(numpy.abs(pos)) diags = size - numpy.abs(pos) nz = sum(diags) kwargs.pop('bandwidth', True) kwargs.pop('sizeHint', True) PysparseMatrix.__init__(self, nrow=size, ncol=size, bandwidth=bw, sizeHint=nz, **kwargs) # Insert elements on specified diagonals ndiags = len(pos) for k in range(ndiags): dk = diags[k] d = pos[k] if d >= 0 and not self.isSymmetric(): self.put(vals[k][:dk], numpy.arange(dk), d + numpy.arange(dk)) else: self.put(vals[k][:dk], -d + numpy.arange(dk), numpy.arange(dk)) def _test(): import doctest return doctest.testmod() if __name__ == "__main__": _test() pysparse-1.1.1/Lib/pysparseSuperLU.py0000644010116400000240000001257611402270345016573 0ustar wd15dialout""" A framework for solving sparse linear systems of equations using an LU factorization, by means of the supernodal sparse LU factorization package SuperLU ([DEGLL99]_, [DGL99]_, [LD03]_). This package is appropriate for factorizing sparse square unsymmetric or rectangular matrices. See [SLU]_ for more information. **References:** .. [DEGLL99] J. W. Demmel, S. C. Eisenstat, J. R. Gilbert, X. S. Li and J. W. H. Liu, *A supernodal approach to sparse partial pivoting*, SIAM Journal on Matrix Analysis and Applications **20**\ (3), pp. 720-755, 1999. .. [DGL99] J. W. Demmel, J. R. Gilbert and X. S. Li, *An Asynchronous Parallel Supernodal Algorithm for Sparse Gaussian Elimination*, SIAM Journal on Matrix Analysis and Applications **20**\ (4), pp. 915-952, 1999. .. [LD03] X. S. Li and J. W. Demmel, *SuperLU_DIST: A Scalable Distributed-Memory Sparse Direct Solver for Unsymmetric Linear Systems*, ACM Transactions on Mathematical Software **29**\ (2), pp. 110-140, 2003. .. [SLU] http://crd.lbl.gov/~xiaoye/SuperLU """ # To look into: # - allow other data types __docformat__ = 'restructuredtext' import pysparseMatrix as psm import numpy import resource from directSolver import PysparseDirectSolver from pysparse import superlu def cputime(): return resource.getrusage(resource.RUSAGE_SELF)[0] class PysparseSuperLUSolver( PysparseDirectSolver ): """ `PysparseSuperLUSolver` is a wrapper class around the SuperLu library for the factorization of full-rank n-by-m matrices. Only matrices with real coefficients are currently supported. :parameters: :A: The matrix to be factorized, supplied as a PysparseMatrix instance. :keywords: :symmetric: a boolean indicating that the user wishes to use symmetric mode. In symmetric mode, ``permc_spec=2`` must be chosen and ``diag_pivot_thresh`` must be small, e.g., 0.0 or 0.1. Since the value of ``diag_pivot_thresh`` is up to the user, setting ``symmetric`` to ``True`` does *not* automatically set ``permc_spec`` and ``diag_pivot_thresh`` to appropriate values. :diag_pivot_thresh: a float value between 0 and 1 representing the threshold for partial pivoting (0 = no pivoting, 1 = always perform partial pivoting). Default: 1.0. :drop_tol: the value of a drop tolerance, between 0 and 1, if an incomplete factorization is desired (0 = exact factorization). This keyword does not exist if using SuperLU version 2.0 and below. In more recent version of SuperLU, the keyword is accepted but has no effect. Default: 0.0 :relax: an integer controling the degree of relaxing supernodes. Default: 1. :panel_size: an integer specifying the maximum number of columns to form a panel. Default: 10. :permc_spec: an integer specifying the ordering strategy used during the factorization. 0. natural ordering, 1. MMD applied to the structure of :math:`\mathbf{A}^T \mathbf{A}` 2. MMD applied to the structure of :math:`\mathbf{A}^T + \mathbf{A}` 3. COLAMD. Default: 2. .. attribute:: LU A :class:`superlu_context` object encapsulating the factorization. .. attribute:: sol The solution of the linear system after a call to :meth:`solve`. .. attribute:: factorizationTime The CPU time to perform the factorization. .. attribute:: solutionTime The CPU time to perform the forward and backward sweeps. .. attribute:: lunz The number of nonzero elements in the factors L and U together after a call to :meth:`fetch_lunz`. """ def __init__(self, A, **kwargs): PysparseDirectSolver.__init__(self, A, **kwargs) self.type = numpy.float self.nrow, self.ncol = A.getShape() t = cputime() self.LU = superlu.factorize(A.matrix.to_csr(), **kwargs) self.factorizationTime = cputime() - t self.solutionTime = 0.0 self.sol = None self.L = self.U = None return def solve(self, rhs, transpose = False): """ Solve the linear system ``A x = rhs``, where ``A`` is the input matrix and ``rhs`` is a Numpy vector of appropriate dimension. The result is placed in the :attr:`sol` member of the class instance. If the optional argument ``transpose`` is ``True``, the transpose system ``A^T x = rhs`` is solved. """ if self.sol is None: self.sol = numpy.empty(self.ncol, self.type) transp = 'N' if transpose: transp = 'T' t = cputime() self.LU.solve(rhs, self.sol, transp) self.solutionTime = cputime() - t return def fetch_lunz(self): """ Retrieve the number of nonzeros in the factors L and U together. The result is stored in the member :attr:`lunz` of the class instance. """ self.lunz = self.LU.nnz def fetch_factors(self): """ Not yet available. """ raise NotImplementedError pysparse-1.1.1/Lib/pysparseUmfpack.py0000644010116400000240000002047611402270344016617 0ustar wd15dialout""" A framework for solving sparse linear systems of equations using an LU factorization, by means of the unsymmetric multifrontal sparse LU factorization package UMFPACK ([D04a]_, [D04b]_, [DD99]_, [DD97]_). This package is appropriate for factorizing sparse square unsymmetric or rectangular matrices. See [UMF]_ for more information. **References:** .. [D04a] T. A. Davis, *A column pre-ordering strategy for the unsymmetric-pattern multifrontal method*, ACM Transactions on Mathematical Software, **30**\ (2), pp. 165-195, 2004. .. [D04b] T. A. Davis, *Algorithm 832: UMFPACK, an unsymmetric-pattern multifrontal method*, ACM Transactions on Mathematical Software, **30**\ (2), pp. 196-199, 2004. .. [DD99] T. A. Davis and I. S. Duff, *A combined unifrontal/multifrontal method for unsymmetric sparse matrices*, ACM Transactions on Mathematical Software, **25**\ (1), pp. 1-19, 1999. .. [DD97] T. A. Davis and I. S. Duff, *An unsymmetric-pattern multifrontal method for sparse LU factorization*, SIAM Journal on Matrix Analysis and Applications, **18**\ (1), pp. 140-158, 1997. .. [UMF] http://www.cise.ufl.edu/research/sparse/umfpack """ # To look into: # - wrap up other useful methods of UMFPACK # - allow other data types __docformat__ = 'restructuredtext' import pysparseMatrix as psm import numpy import resource from directSolver import PysparseDirectSolver from pysparse import umfpack from string import upper def cputime(): return resource.getrusage(resource.RUSAGE_SELF)[0] class PysparseUmfpackSolver( PysparseDirectSolver ): """ `PysparseUmfpackSolver` is a wrapper class around the UMFPACK library for the factorization of full-rank n-by-m matrices. Only matrices with real coefficients are currently supported. :parameters: :A: A PysparseMatrix instance representing the matrix to be factorized. :keywords: :strategy: string that specifies what kind of ordering and pivoting strategy UMFPACK should use. Valid values are 'auto', 'unsymmetric', 'symmetric' and '2by2'. Default: 'auto' :tol2by2: tolerance for the 2 by 2 strategy. Default: 0.1 :scale: string that specifies the scaling UMFPACK should use. Valid values are 'none', 'sum', and 'max'. Default: 'sum'. :tolpivot: relative pivot tolerance for threshold partial pivoting with row interchanges. Default: 0.1 :tolsympivot: if diagonal pivoting is attempted, this parameter is used to control when the diagonal is selected in a given pivot column. Default: 0.0 .. attribute:: LU An :class:`umfpack_context` object encapsulating the factorization. .. attribute:: sol The solution of the linear system after a call to :meth:`solve`. .. attribute:: L The L factor of the input matrix. .. attribute:: U The U factor of the input matrix. .. attribute:: P The row permutation used for the factorization. .. attribute:: Q The column permutation used for the factorization. .. attribute:: R The row scaling used during the factorization. See the documentation of :meth:`fetch_factors`. .. attribute:: factorizationTime The CPU time to perform the factorization. .. attribute:: solutionTime The CPU time to perform the forward and backward sweeps. .. attribute:: do_recip Nature of the row scaling. See :meth:`fetch_factors`. .. attribute:: lnz The number of nonzero elements in the factor L. .. attribute:: unz The number of nonzero elements in the factor U from which the diagonal was removed. .. attribute:: nz_udiag The number of nonzero elements on the diagonal of the factor U. """ def __init__(self, A, **kwargs): PysparseDirectSolver.__init__(self, A, **kwargs) if 'strategy' in kwargs.keys(): strategy = upper(kwargs.get('strategy')) if strategy not in ['AUTO', 'UNSYMMETRIC', 'SYMMETRIC', '2BY2']: strategy = 'AUTO' kwargs['strategy'] = 'UMFPACK_STRATEGY_' + strategy if 'scale' in kwargs.keys(): scale = upper(kwargs.get('scale')) if scale not in ['NONE', 'SUM', 'MAX']: scale = 'SUM' kwargs['scale'] = 'UMFPACK_SCALE_' + scale self.type = numpy.float self.nrow, self.ncol = A.getShape() t = cputime() self.LU = umfpack.factorize(A.matrix, **kwargs) self.factorizationTime = cputime() - t self.solutionTime = 0.0 self.sol = None self.L = self.U = None self.P = self.Q = self.R = None self.do_recip = False self.lnz = self.unz = self.nz_udiag = None return def solve(self, rhs, **kwargs): """ Solve the linear system ``A x = rhs``. The result is placed in the :attr:`sol` member of the class instance. :parameters: :rhs: a Numpy vector of appropriate dimension. :keywords: :method: specifies the type of system being solved: +-------------------+--------------------------------------+ |``"UMFPACK_A"`` | :math:`\mathbf{A} x = b` (default) | +-------------------+--------------------------------------+ |``"UMFPACK_At"`` | :math:`\mathbf{A}^T x = b` | +-------------------+--------------------------------------+ |``"UMFPACK_Pt_L"`` | :math:`\mathbf{P}^T \mathbf{L} x = b`| +-------------------+--------------------------------------+ |``"UMFPACK_L"`` | :math:`\mathbf{L} x = b` | +-------------------+--------------------------------------+ |``"UMFPACK_Lt_P"`` | :math:`\mathbf{L}^T \mathbf{P} x = b`| +-------------------+--------------------------------------+ |``"UMFPACK_Lt"`` | :math:`\mathbf{L}^T x = b` | +-------------------+--------------------------------------+ |``"UMFPACK_U_Qt"`` | :math:`\mathbf{U} \mathbf{Q}^T x = b`| +-------------------+--------------------------------------+ |``"UMFPACK_U"`` | :math:`\mathbf{U} x = b` | +-------------------+--------------------------------------+ |``"UMFPACK_Q_Ut"`` | :math:`\mathbf{Q} \mathbf{U}^T x = b`| +-------------------+--------------------------------------+ |``"UMFPACK_Ut"`` | :math:`\mathbf{U}^T x = b` | +-------------------+--------------------------------------+ :irsteps: number of iterative refinement steps to attempt. Default: 2 """ method = kwargs.get('method', 'UMFPACK_A') irsteps = kwargs.get('irsteps', 2) if self.sol is None: self.sol = numpy.empty(self.ncol, self.type) t = cputime() self.LU.solve(rhs, self.sol, method, irsteps) self.solutionTime = cputime() - t return def fetch_lunz(self): """ Retrieve the number of nonzeros in the factors. The results are stored in the members :attr:`lnz`, :attr:`unz` and :attr:`nz_udiag` of the class instance. """ self.lnz, self.unz, self.nz_udiag = self.LU.lunz() def fetch_factors(self): """ Retrieve the L and U factors of the input matrix along with the permutation matrices P and Q and the row scaling matrix R such that .. math:: \mathbf{P R A Q} = \mathbf{L U}. The matrices P, R and Q are stored as Numpy arrays. L and U are stored as PysparseMatrix instances and are lower triangular and upper triangular, respectively. R is a row-scaling diagonal matrix such that - the i-th row of A has been divided by R[i] if ``do_recip = True``, - the i-th row of A has been multiplied by R[i] if ``do_recip = False``. """ (L, U, self.P, self.Q, self.R, self.do_recip) = self.LU.lu() self.L = psm.PysparseMatrix(matrix=L) self.U = psm.PysparseMatrix(matrix=U) return pysparse-1.1.1/Lib/sparray.py0000644010116400000240000000655411402270344015124 0ustar wd15dialout# -*- coding: iso-8859-1 -*- from types import IntType,SliceType import operator import spmatrix class sparray: """ d-dimensionnal sparse array emulation by a long sparse vector. supports syntax like: a[2,1,6,5]=2 a[:,5,6,6]=list of appropriate length (one slice at a time only) b=a[:,5,6,6] (b is a numeric array) b=a[n], a[n]=6 if n in range a=sparray((2,6,9,8),dicto,shifts) where, optionnally, dicto is a dictionnary whose keys are tuple in range of (2,6,9,8), and shifts is a tuple to shift origins in case the smallest coordinate in dicto is not (0,...,0) """ def __init__(self,dim,dicto=None,shifts=None): """ attributes: shifts, dims, data, is1D, length methods : dump """ self.shifts=shifts if type(dim)==type(()) or type(dim)==type([]): self.data = spmatrix.ll_mat(reduce(operator.mul, dim), 1) self.dims = dim if dicto: for k, v in dicto.iteritems(): shk = map(operator.__sub__, k, shifts) self.data[self.comp(shk), 0]=v elif type(dim)==IntType: self.data = spmatrix.ll_mat(dim,1) self.dims = dim if dicto: for k, v in dicto.iteritems(): shk = k - shifts self.data[shk,0] = v self.is1D = type(self.dims)==IntType def __get_shape0(self):return self.data.shape[0] length = property(__get_shape0, doc="sparray linear length") def decomp(self,ind): "from linear to multi indice" a = ind l = len(self.dims) res = [0]*l for i in range(l - 1, -1, -1): a, b = divmod(a,self.dims[i]) res[i] = b return tuple(res) def comp(self,indice): "from multi indice to linear" l = len(self.dims) a = 0 for i in range(l-1): a += reduce(operator.mul, self.dims[i+1:]) * indice[i] a += indice[l-1] return a def __setitem__(self, k, value): if type(k) is IntType: self.data[k, 0] = value return vec = map(lambda x: type(x) is SliceType, k) if True in vec: # suppose only one slice ii = vec.index(True) indices = [] k = list(k) comp = self.comp for i in range(self.dims[ii]): k[ii] = i self.data[comp(k), 0] = value[i] else: self.data[self.comp(k),0]=value def __getitem__(self,k): """ output a Numeric vector if slice in coordinates (one slice present only) """ if type(k) is IntType: return self.data[k, 0] vec = map(lambda x: type(x) is SliceType, k) if True in vec: #suppose only one slice ii=vec.index(True) indices=[] k = list(k) import numpy rep = numpy.zeros((self.dims[ii],), 'd') for i in range(self.dims[ii]): k[ii] = i rep[i] = self.data[self.comp(k), 0] return rep else: return self.data[self.comp(k), 0] def dump(self): print self.data pysparse-1.1.1/Lib/sparseMatrix.py0000644010116400000240000001077311402270344016123 0ustar wd15dialout#!/usr/bin/env python ## -*-Pyth-*- # ################################################################### # FiPy - Python-based finite volume PDE solver # # FILE: "sparseMatrix.py" # created: 11/10/03 {3:15:38 PM} # last update: 1/3/07 {3:03:32 PM} # Author: Jonathan Guyer # Author: Daniel Wheeler # Author: James Warren # Author: Maxsim Gibiansky # mail: NIST # www: http://www.ctcms.nist.gov/fipy/ # # ======================================================================== # This software was developed at the National Institute of Standards # and Technology by employees of the Federal Government in the course # of their official duties. Pursuant to title 17 Section 105 of the # United States Code this software is not subject to copyright # protection and is in the public domain. FiPy is an experimental # system. NIST assumes no responsibility whatsoever for its use by # other parties, and makes no guarantees, expressed or implied, about # its quality, reliability, or any other characteristic. We would # appreciate acknowledgement if the software is used. # # This software can be redistributed and/or modified freely # provided that any derivative works bear some notice that they are # derived from it, and any modified versions bear some notice that # they have been modified. # ======================================================================== # # Description: # # History # # modified by rev reason # ---------- --- --- ----------- # 2003-11-10 JEG 1.0 original # 2006-06-12 MLG 1.0 made abstract # ################################################################### ## __docformat__ = 'restructuredtext' import numpy class SparseMatrix: """ .. attention:: This class is abstract. Always create one of its subclasses. """ def __init__(self, size=None, bandwidth=0, matrix=None, sizeHint=None): pass __array_priority__ = 100.0 def getMatrix(self): pass def __array_wrap(self, arr, context=None): if context is None: return arr else: return NotImplemented def copy(self): pass def __getitem__(self, index): pass def __str__(self): s = "" cellWidth = 11 shape = self.getShape() for i in range(shape[0]): for j in range(shape[1]): v = self[i,j] if v == 0: s += "---".center(cellWidth) else: exp = numpy.log(abs(v)) if abs(exp) <= 4: if exp < 0: s += ("%9.6f" % v).ljust(cellWidth) else: s += ("%9.*f" % (6,v)).ljust(cellWidth) else: s += ("%9.2e" % v).ljust(cellWidth) s += "\n" return s[:-1] def __repr__(self): return repr(self.matrix) def __setitem__(self, index, value): pass def __add__(self, other): pass __radd__ = __add__ def __iadd__(self, other): pass def __sub__(self, other): pass # Ask about this rsub def __rsub__(self, other): return -(__sub__(self, other)) def __isub__(self, other): pass def __mul__(self, other): pass def __rmul__(self, other): pass def __neg__(self): return self * -1 def __pos__(self): return self ## def __eq__(self,other): ## return self.matrix.__eq__(other._getMatrix()) def getShape(self): pass ## def transpose(self): ## pass def put(self, vector, id1, id2): pass def putDiagonal(self, vector): pass def take(self, id1, id2): pass def takeDiagonal(self): pass def addAt(self, vector, id1, id2): pass def addAtDiagonal(self, vector): pass def getNumpyArray(self): pass def exportMmf(self, filename): pass ## def __array__(self): ## shape = self._getShape() ## indices = numpy.indices(shape) ## numMatrix = self.take(indices[0].ravel(), indices[1].ravel()) ## return numpy.reshape(numMatrix, shape) pysparse-1.1.1/Lib/spmatrix_util.py0000644010116400000240000000722411402270345016343 0ustar wd15dialoutimport math, random import spmatrix def bytesToString(n): if n < 1024: return '%d Bytes' % n n /= 1024.0 if n < 1024: return '%.1f Kbytes' % n n /= 1024.0 if n < 1024: return '%.1f Mbytes' % n n /= 1024.0 return '%.1f Gbytes' % n def printInfo(mat, name): if type(mat) == spmatrix.LLMatType: if mat.issym: typeName = 'LL symmetric' else: typeName = 'LL general' storage = bytesToString(4*mat.shape[0] + 16*mat.nnz) elif type(mat) == spmatrix.SSSMatType: typeName = 'SSS' storage = bytesToString(12*mat.shape[0] + 12*(mat.nnz - mat.shape[0])) elif type(mat) == spmatrix.CSRMatType: typeName = 'CSR' storage = bytesToString(4*mat.shape[0] + 12*mat.nnz) else: typeName = 'Unknown' storage = 'Unknown' print 'Matrix statistics:' print '%-20s: %s' % ('name', name) print '%-20s: %s' % ('type', typeName) print '%-20s: %dx%d' % ('dimensions', mat.shape[0], mat.shape[1]) print '%-20s: %d' % ('#non-zeros', mat.nnz) print '%-20s: %s' % ('storage', storage) print def ll_mat_rand(n, m, density): """return a ll_mat object representing a general n-by-m sparse matrix filled with random non-zero values The number of non-zero entries is less or equal than n*m*density. The values of the non-zero entries are in the range [0.0, 1.0).""" nnz = int(density*n*m) A = spmatrix.ll_mat(n, m, nnz) for k in xrange(nnz): i = random.randrange(n) j = random.randrange(m) A[i, j] = random.random() return A def exportVtk(mat, fileName): "export matrix to a VTK data file" print 'Write VTK file...' # write VTK file f = open(fileName, 'w') f.write('# vtk DataFile Version 3.0\n') import pysparse comment = 'generated using pysparse-%s\n' % (pysparse.__version__, ) f.write(comment[:256]) f.write('ASCII\n\n') f.write('DATASET STRUCTURED_POINTS\n') f.write('DIMENSIONS %d %d 1\n' % (mat.shape[0], mat.shape[1])) f.write('ORIGIN 1 1 1\n') f.write('SPACING 1 1 1\n\n') f.write('\nPOINT_DATA %d\n' % (mat.shape[0]*mat.shape[1])) f.write('SCALARS entries float\n') f.write('LOOKUP_TABLE default\n\n') for i in xrange(mat.shape[0]): for j in xrange(mat.shape[1]): v = mat[i,j] if v <> 0.0: v = math.log(math.fabs(v)) f.write('%lf\n' % v) f.close() def viewVtk(mat): import vtk imageData = vtk.vtkImageData() imageData.SetDimensions(mat.shape[0], mat.shape[1], 1) imageData.SetScalarTypeToUnsignedShort() imageData.SetNumberOfScalarComponents(1) imageData.AllocateScalars() viewer = vtk.vtkImageViewer() viewer.SetInput(imageData) viewer.SetZSlice(0) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(viewer.GetRenderWindow()) iren.Initialize() iren.Start() imageData = vtk.vtkImageSinusoidSource() imageData.SetWholeExtent(0, 300, 0, 300, 0, 10) imageData.SetAmplitude(63) imageData.SetDirection(1, 1, 0) imageData.SetPeriod(25) viewer = vtk.vtkImageViewer() viewer.SetInput(imageData.GetOutput()) viewer.SetColorWindow(126) viewer.SetColorLevel(0) viewer.SetZSlice(0) def hamschti(obj, event): print 'Haam:' print obj print event iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(viewer.GetRenderWindow()) iren.Initialize() interactor = vtk.vtkInteractorStyleImage() ##interactor.AddObserver('LeftButtonPressEvent', hamschti) iren.SetInteractorStyle(interactor) iren.Start() pysparse-1.1.1/Src/0000755010116400000240000000000011402271041013073 5ustar wd15dialoutpysparse-1.1.1/Src/bicgstab.c0000644010116400000240000001776311402270127015037 0ustar wd15dialout#include "Python.h" #include "pysparse/blas.h" #include "pysparse/fortran.h" #define SPMATRIX_UNIQUE_SYMBOL itsolvers_spmatrix #include "pysparse/spmatrix.h" #include "pysparse/bicgstab.h" /* function prototypes */ static void itermsg(double tol, int maxit, int info, int iter, double relres); void v_plus_cw(int n, double *v, double *w, double c, double *z); #define SpMatrix_PRECON(prec_obj, n, x, y) \ {if (SpMatrix_Precon((prec_obj),(n),(x),(y))) return -1;} #define SpMatrix_MATVEC(mat_obj, n, x, m, y) \ {if (SpMatrix_Matvec((mat_obj), (n), (x), (m), (y))) return -1;} /* BICGSTAB - stabilized BiConjugate Gradients algorithm */ int Itsolvers_bicgstab_kernel2(int n, double *x, double *b, double tol, int maxit, int clvl, int *iter, double *relres, int *info, double *work, PyObject *mat_obj, PyObject *prec_obj) { int ONE = 1; /* to BLAS routines */ int i; double n2b; /* 2 nrm of residual */ double *r,*rhat,*p,*v,*w,*z,*bb; double c,rho,old_rho,alpha,beta,omega,old_omega; double res,res0; *info = -6; /* Check for all zero right hand side vector => all zero solution */ n2b = F77(dnrm2)(&n, b, &ONE);/* Norm of rhs vector, b */ if (n2b == 0.0) { /* if rhs vector is all zeros */ for (i = 0; i < n; i ++) /* then solution is all zeros */ x[i] = 0.0; *info = 0; /* a valid solution has been obtained */ *relres = 0.0; /* the relative residual is actually 0/0 */ *iter = 0; /* no iterations need be performed */ if (clvl) itermsg(tol,maxit,*info,*iter,*relres); return(0); } /* setup pointers into work */ r = work; rhat = work + n; p = work + 2*n; v = work + 3*n; w = work + 4*n; z = work + 5*n; bb = work + 6*n; c = -1.0; old_rho = 1.0; alpha = 1.0; old_omega = 1.0; printf("initial solution norm in bicgstab: %e\n", F77(dnrm2)(&n, x, &ONE)); if (prec_obj) { SpMatrix_PRECON(prec_obj, n, b, bb); } else { F77(dcopy)(&n, b, &ONE, bb, &ONE); } /* compute initial residual */ SpMatrix_MATVEC(mat_obj,n,x,n,w); if (prec_obj) { SpMatrix_PRECON(prec_obj, n, w, z); } else { F77(dcopy)(&n, w, &ONE, z, &ONE); } v_plus_cw(n,bb,z,c,r); F77(dcopy)(&n, r, &ONE, rhat, &ONE); res0 = F77(dnrm2)(&n, bb, &ONE); printf("initial residual in bicgstab: %e\n", res0); *iter = 0; do { (*iter)++; rho = F77(ddot)(&n, r, &ONE, rhat, &ONE); beta = (rho/old_rho)*(alpha/old_omega); #if 0 printf("iter: %d rho = %e, beta = %e\n",*iter,rho,beta); #endif /* compute new p */ v_plus_cw(n,p,v,-old_omega,z); v_plus_cw(n,r,z,beta,p); /* compute new v, r, and alpha */ SpMatrix_MATVEC(mat_obj,n,p,n,w); if (prec_obj) { SpMatrix_PRECON(prec_obj, n, w, v); } else { F77(dcopy)(&n, w, &ONE, v, &ONE); } alpha = rho/F77(ddot)(&n, rhat, &ONE, v, &ONE); v_plus_cw(n,r,v,-alpha,w); F77(dcopy)(&n, w, &ONE, r, &ONE); /* compute new omega */ SpMatrix_MATVEC(mat_obj,n,r,n,w); if (prec_obj) { SpMatrix_PRECON(prec_obj, n, w, z); } else { F77(dcopy)(&n, w, &ONE, z, &ONE); } omega = F77(ddot)(&n, z, &ONE, r, &ONE)/F77(ddot)(&n, z, &ONE, z, &ONE); /* compute new x and new r */ v_plus_cw(n,x,p,alpha,w); v_plus_cw(n,w,r,omega,x); v_plus_cw(n,r,z,-omega,w); F77(dcopy)(&n, w, &ONE, r, &ONE); old_rho = rho; old_omega = omega; /* compute exact residual -> w */ SpMatrix_MATVEC(mat_obj,n,x,n,w); if (prec_obj) { SpMatrix_PRECON(prec_obj, n, w, z); } else { F77(dcopy)(&n, w, &ONE, z, &ONE); } v_plus_cw(n,bb,z,c,w); res = F77(dnrm2)(&n, w, &ONE); } while ((res/res0 > tol) && (*iter < maxit)); *relres = res/res0; if (*relres>=tol) { *info = -1; } else { *info = 0; } if (clvl) itermsg(tol,maxit,*info,*iter,*relres); return(0); } /* BICGSTAB - stabilized BiConjugate Gradients algorithm */ int Itsolvers_bicgstab_kernel(int n, double *x, double *b, double tol, int maxit, int clvl, int *iter, double *relres, int *info, double *work, PyObject *mat_obj, PyObject *prec_obj) { int ONE = 1; /* to BLAS routines */ int i; double n2b; /* 2 nrm of residual */ double *r,*rhat,*p,*phat,*v,*s,*shat,*t; double alpha,omega,rho_im1,rho_im2,beta; double res,res0; *info = -6; /* Check for all zero right hand side vector => all zero solution */ n2b = F77(dnrm2)(&n, b, &ONE);/* Norm of rhs vector, b */ if (n2b == 0.0) { /* if rhs vector is all zeros */ for (i = 0; i < n; i ++) /* then solution is all zeros */ x[i] = 0.0; *info = 0; /* a valid solution has been obtained */ *relres = 0.0; /* the relative residual is actually 0/0 */ *iter = 0; /* no iterations need be performed */ if (clvl) itermsg(tol,maxit,*info,*iter,*relres); return(0); } /* setup pointers into work */ r = work; rhat = work + n; p = work + 2*n; phat = work + 3*n; v = work + 4*n; s = work + 5*n; shat = work + 6*n; t = work + 7*n; omega = 0.0; beta = 0.0; alpha = 0.0; rho_im2 = 0.0; /* compute residual */ SpMatrix_MATVEC(mat_obj,n,x,n,r); for (i=0;i tol) && (*iter < maxit)); *relres = res/res0; if (*relres>=tol) { *info = -1; } else { *info = 0; } if (clvl) itermsg(tol,maxit,*info,*iter,*relres); return(0); } /* ITERMSG - Displays the final message for BICGSTAB method */ static void itermsg(double tol, int maxit, int info, int iter, double relres) { if (info != 0) { printf("BICGSTAB stopped at iteration %d without converging to the desired tolerance %0.2g", iter, tol); } switch(info) { case 0: if (iter == 0) printf("The initial guess has relative residual %0.2g which is within\nthe desired tolerance %0.2g so BICGSTAB returned it without iterating.", relres, tol); else printf("BICGSTAB converged at iteration %d to a solution with relative residual %0.2g", iter, relres); break; case -1: printf("\nbecause the maximum number of iterations was reached."); break; case -2: printf("\nbecause the system involving the preconditioner was ill conditioned."); break; case -5: printf("\nbecause the method stagnated."); break; case -6: printf("\nbecause a scalar quantity became too small or too large to continue computing."); break; } if (info != 0) printf("\nThe iterate returned (number %d) has relative residual %0.2g",iter,relres); printf("\n"); } void v_plus_cw(int n, double *v, double *w, double c, double *z) { int i; for (i=0; i #include "Python.h" #include "pysparse/blas.h" #define SPMATRIX_UNIQUE_SYMBOL itsolvers_spmatrix #include "pysparse/spmatrix.h" #include "pysparse/cgs.h" #define SpMatrix_PRECON(prec_obj, n, p, tmp) \ {if (SpMatrix_Precon((prec_obj),(n),(p),(tmp))) return -1;} #define SpMatrix_MATVEC(mat_obj, n, x, m, y) \ {if (SpMatrix_Matvec((mat_obj), (n), (x), (m), (y))) return -1;} int Itsolvers_cgs_kernel(int n, double *b, double *x, int maxit, double tol, double *work, int *iter, double *res, PyObject *mat_obj, PyObject *prec_obj) { double *r0, *r, *p, *q, *u, *v, *tmp, *tmp2, alpha, beta, rho, rho_new, tol_sq, bnrm_sq, ddummy; double DMONE = -1.0, DONE = 1.0; int ONE = 1; /* Place vectors in WorkSpace */ r0 = work; r = work + n; p = work + 2*n; q = work + 3*n; u = work + 4*n; v = work + 5*n; tmp = work + 6*n; tmp2 = work + 7*n; /* For ease */ tol_sq = tol*tol; /* Initializing Values : r0 = b - A*x */ *iter = 0; SpMatrix_MATVEC(mat_obj, n, x, n, tmp); F77(dcopy)(&n, b, &ONE, r0, &ONE); F77(daxpy)(&n, &DMONE, tmp, &ONE, r0, &ONE); /* p := u := r := r0 */ F77(dcopy)(&n, r0, &ONE, r, &ONE); F77(dcopy)(&n, r0, &ONE, u, &ONE); F77(dcopy)(&n, r0, &ONE, p, &ONE); /* rho = r0'*r0 , bnrm_sq = b'*b */ rho = F77(ddot)(&n, r0, &ONE, r0, &ONE); bnrm_sq = F77(ddot)(&n, b, &ONE, b, &ONE); /* Starting-vector is already good enough */ if (rho < bnrm_sq*tol_sq) { *res = sqrt(rho / bnrm_sq); return 0; } /* Iterate for at most maxit steps ...*/ for (; *iter < maxit; (*iter) ++) { if (prec_obj != NULL) { SpMatrix_PRECON(prec_obj, n, p, tmp); SpMatrix_MATVEC(mat_obj, n, tmp, n, v); } else SpMatrix_MATVEC(mat_obj, n, p, n, v); alpha = rho/F77(ddot)(&n, v, &ONE, r0, &ONE); /* alpha = rho/(v'*inv(K)*A*r0) */ ddummy = -alpha; /* ddummy = -alpha */ F77(dcopy)(&n, u, &ONE, q, &ONE); F77(daxpy)(&n, &ddummy, v, &ONE, q, &ONE); /* q = u - alpha*v */ F77(dcopy)(&n, u, &ONE, tmp, &ONE); F77(daxpy)(&n, &DONE, q, &ONE, tmp, &ONE); /* tmp = u + q */ if (prec_obj != NULL) /* x = x + alpha*tmp2 = x + alpha*inv(K)*(u + q) */ SpMatrix_PRECON(prec_obj, n, tmp, tmp2) else F77(dcopy)(&n, tmp, &ONE, tmp2, &ONE); F77(daxpy)(&n, &alpha, tmp2, &ONE, x, &ONE); SpMatrix_MATVEC(mat_obj, n, tmp2, n, tmp); F77(daxpy)(&n, &ddummy, tmp, &ONE, r, &ONE); /* r = r - alpha*A*tmp2 = r - alpha*A*inv(K)*(u + q) */ *res = F77(ddot)(&n, r, &ONE, r, &ONE); if (*res < bnrm_sq*tol_sq) { /* Test covergence ... */ *res = sqrt(*res / bnrm_sq); return 0; } rho_new = F77(ddot)(&n, r, &ONE, r0, &ONE); /* rho_new = r_(i+1)'*r0 */ beta = rho_new/rho; /* beta = rho_new/rho */ rho = rho_new; /* rho = rho_new */ F77(dcopy)(&n, r, &ONE, u, &ONE); F77(daxpy)(&n, &beta, q, &ONE, u, &ONE); /* u = r + beta*q */ F77(dcopy)(&n, q, &ONE, tmp, &ONE); F77(daxpy)(&n, &beta, p, &ONE, tmp, &ONE); F77(dcopy)(&n, u, &ONE, p, &ONE); F77(daxpy)(&n, &beta, tmp, &ONE, p, &ONE); /* p = u + beta*(q + beta*p) */ } /* CGS did not converge */ *res = sqrt(*res / bnrm_sq) ; return -1; } pysparse-1.1.1/Src/correq.c0000644010116400000240000002136211402270131014535 0ustar wd15dialout#define JDSYM_OP_UNSYM 1 #define JDSYM_OP_SYM 2 typedef struct CorrEqObject { PyObject_VAR_HEAD int op_type; int n; int k; PyObject *amat; PyObject *mmat; PyObject *prec; double theta; double *Q; double *Qm; double *Y; /* ldQ and ldQm are equal to n */ int *Hpiv; double *Hlu; int ldh; double *work; void (*right)(struct CorrEqObject *, double *); void (*update)(struct CorrEqObject *, int, double); } CorrEqObject; static void CorrEq_A_theta_M(CorrEqObject *self, int n, double *x, double *y, double *w) { double alpha = -self->theta; SpMatrix_Matvec(self->amat, n, x, n, y); /* y := A*x; */ if (alpha != 0.0) { SpMatrix_Matvec(self->mmat, n, x, n, w); /* work := M*x */ F77(daxpy)(&n, &alpha, w, &ONE, y, &ONE); /* y := -theta*work + y */ } } static void CorrEq_A_theta_I(CorrEqObject *self, int n, double *x, double *y) { double alpha = -self->theta; SpMatrix_Matvec(self->amat, n, x, n, y); /* y := A*x; */ F77(daxpy)(&n, &alpha, x, &ONE, y, &ONE); /* y := -theta*x + y*/ } /* PROJECT1 - compute y := (I - A*B')*x * * sizes of matrices and vectors: * A and B -- r-by-c matrices, ldim = r * x, y and w -- r vectors * * (x, y) and also (A, B) may point to the same memory locations */ static void CorrEq_project1(int r, int c, double *A, double *B, double *x, double *y, double *w){ /* if x and y do not refer to the same vector, we copy x to y */ if (x != y) F77(dcopy)(&r, x, &ONE, y, &ONE); /* w = B'*y */ F77(dgemv)("t", &r, &c, &DONE, B, &r, y, &ONE, &DZER, w, &ONE, 1); /* y = y - A*w */ F77(dgemv)("n", &r, &c, &DMONE, A, &r, w, &ONE, &DONE, y, &ONE, 1); } /* PROJECT2 - compute y := (I - Y*inv(H)*Qm') * x * or * y := (I - Y*inv(H)*Q' ) * x * * depending on parameter Qx */ static void CorrEq_project2(CorrEqObject *self, double *Qx, double *x, double *y, double *w){ int info; int n = self->n; int k = self->k; /* if x and y do not refer to the same vector, we copy x to y */ if (x != y) F77(dcopy)(&n, x, &ONE, y, &ONE); /* w = Qx'*x */ F77(dgemv)("t", &n, &k, &DONE, Qx, &n, x, &ONE, &DZER, w, &ONE, 1); /* w = inv(H)*w */ F77(dgetrs)("n", &k, &ONE, self->Hlu, &(self->ldh), self->Hpiv, w, &n, &info, 1); assert(info == 0); /* y = y - Y*w */ F77(dgemv)("n", &n, &k, &DMONE, self->Y, &n, w, &ONE, &DONE, y, &ONE, 1); } static void CorrEq_update(CorrEqObject *self, int k, double theta) { self->k = k; self->theta = theta; } static void CorrEq_right(CorrEqObject *self, double *r) { int n = self->n; int k = self->k; if (self->op_type == JDSYM_OP_SYM) if (self->mmat) { /* r = r - Qb*(Q'*r); */ CorrEq_project1(n, k, self->Qm, self->Q, r, r, self->work); } else { /* r := (I - Q*Q')*r */ mgs(r, n, k, self->Q); } else /* op_type = JDSYM_OP_UNSYM */ if (self->mmat) if (self->prec) { /* mmat && prec */ /* r := (I - Y'*inv(H)*Qb')*inv(K)*r */ SpMatrix_Precon(self->prec, n, r, self->work); CorrEq_project2(self, self->Qm, self->work, r, self->work + n); } else { /* mmat && !prec */ /* r := (I - Q*Qb')*r */ CorrEq_project1(n, k, self->Q, self->Qm, r, r, self->work); } else if (self->prec) { /* !mmat && prec */ /* r := (I - Y'*inv(H)*Q')*inv(K)*r */ SpMatrix_Precon(self->prec, n, r, self->work); CorrEq_project2(self, self->Q, self->work, r, self->work + n); } else { /* !mmat && !prec */ /* r := (I - Q*Q')*r */ mgs(r, n, k, self->Q); } } static PyObject * CorrEq_matvec(CorrEqObject *self, PyObject *args) { PyArrayObject *xp, *yp; double *x, *y; int n = self->n; int k = self->k; /* parse input arguments */ SPMATRIX_PARSE_ARGS_ARR_ARR(args, xp, yp, self->n, self->n); x = (double *)(xp->data); y = (double *)(yp->data); if (self->op_type == JDSYM_OP_SYM) { if (self->mmat) { /* y := (I - Qm*Q')*(A - theta*M)*x */ CorrEq_A_theta_M(self, n, x, y, self->work); CorrEq_project1(n, k, self->Qm, self->Q, y, y, self->work); } else { /* y := (I - Q*Q')*(A - theta*I)*x */ CorrEq_A_theta_I(self, n, x, y); CorrEq_project1(n, k, self->Q, self->Q, y, y, self->work); } } else { /* self->op_type = JDSYM_OP_UNSYM */ if (self->mmat) if (self->prec) { /* mmat && prec */ /* y := (I - Y'*inv(H)*QM')*inv(K)*(A-theta*M)*x */ CorrEq_A_theta_M(self, n, x, self->work + n, self->work); SpMatrix_Precon(self->prec, n, self->work + n, y); CorrEq_project2(self, self->Qm, y, y, self->work); } else { /* mmat && !prec */ /* y := (I - Q*Qm')*(A-theta*M)*x */ CorrEq_A_theta_M(self, n, x, y, self->work); CorrEq_project1(n, k, self->Q, self->Qm, y, y, self->work); } else /* ! self->mmat */ if (self->prec) { /* !mmat && prec */ /* y := (I - Y'*inv(H)*Q')*inv(K)*(A-theta*I)*x */ CorrEq_A_theta_I(self, n, x, self->work + n); SpMatrix_Precon(self->prec, n, self->work + n, y); CorrEq_project2(self, self->Q, y, y, self->work); } else { /* !mmat && !prec */ /* y := (I - Q*Q')*(A-theta*I)*x */ CorrEq_A_theta_I(self, n, x, y); CorrEq_project1(n, k, self->Q, self->Q, y, y, self->work); } } /* return Py_None */ Py_INCREF(Py_None); return Py_None; } static PyObject * CorrEq_precon(CorrEqObject *self, PyObject *args) { PyArrayObject *xp, *yp; double *x, *y; int n = self->n; int k = self->k; /* parse input arguments */ SPMATRIX_PARSE_ARGS_ARR_ARR(args, xp, yp, self->n, self->n); x = (double *)(xp->data); y = (double *)(yp->data); if (self->op_type == JDSYM_OP_SYM) if (self->mmat) if (self->prec) { /* mmat && prec */ /* y = (I-Y*H\Qm')*inv(K)*x */ SpMatrix_Precon(self->prec, n, x, y); CorrEq_project2(self, self->Qm, y, y, self->work); } else { /* mmat && !prec */ /* y = (I - Q*Qm')*x */ CorrEq_project1(n, k, self->Q, self->Qm, x, y, self->work); } else if (self->prec) { /* !mmat && prec */ /* y = (I-Y*H\Q')*inv(K)*x */ SpMatrix_Precon(self->prec, n, x, y); CorrEq_project2(self, self->Q, y, y, self->work); } else { /* !mmat && !prec */ /* y = x */ F77(dcopy)(&n, x, &ONE, y, &ONE); } else { /* self->optype == JDSYM_OP_UNSYM */ /* the Preconditioner is contained in the operator */ F77(dcopy)(&n, x, &ONE, y, &ONE); } /* return Py_None */ Py_INCREF(Py_None); return Py_None; } /** table of object methods */ PyMethodDef CorrEq_methods[] = { {"matvec", (PyCFunction)CorrEq_matvec, METH_VARARGS}, {"precon", (PyCFunction)CorrEq_precon, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; /*********************************************************************** * CorrEqType methods */ static void CorrEq_dealloc(CorrEqObject *self) { PyMem_DEL(self->work); PyObject_Del(self); } static PyObject * CorrEq_getattr(CorrEqObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->n, self->n); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(CorrEq_methods, (PyObject *)self, name); } /*********************************************************************** * Type structures */ PyTypeObject CorrEqType = { PyObject_HEAD_INIT(NULL) 0, "CorrEqSystem", sizeof(CorrEqObject), 0, (destructor)CorrEq_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc)CorrEq_getattr, /* 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 */ }; /*********************************************************************** * Object construction functions */ PyObject * newCorrEqObject(int op_type, int n, PyObject *amat, PyObject *mmat, PyObject *prec, double *Q, double *Qm, double *Y, int *Hpiv, double *Hlu, int ldh) { CorrEqObject *self; /* create new CorrEqObject */ self = PyObject_New(CorrEqObject, &CorrEqType); if (self == NULL) return PyErr_NoMemory(); /* setup work arrays */ self->work = PyMem_New(double, 2*n); if (self->work == NULL) { PyObject_Del(self); return PyErr_NoMemory(); } /* set function pointers */ self->right = CorrEq_right; self->update = CorrEq_update; self->op_type = op_type; self->n = n; self->amat = amat; self->mmat = mmat; self->prec = prec; self->Q = Q; self->Qm = Qm; self->Y = Y; self->Hpiv = Hpiv; self->Hlu = Hlu; self->ldh = ldh; return (PyObject *)self; } pysparse-1.1.1/Src/csr_mat.c0000644010116400000240000001600411402270130014666 0ustar wd15dialout#include "Python.h" #define SPMATRIX_MODULE #include "pysparse/spmatrix.h" #define PY_ARRAY_UNIQUE_SYMBOL spmatrix //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #define UNROLL_LOOPS 0 /*********************************************************************** * CSRMatObject methods */ static void csr_matvec_kernel(int m, double *x, double *y, double *va, int *ja, int *ia) { double s; int i, k; #if UNROLL_LOOPS int k1, *ja_ptr; ja_ptr = ja; k = ia[0]; for (i = 0; i < m; i ++) { s = 0.0; k1 = ia[i+1]; for (; k+10 < k1; k += 10) { s += va[k+9]*x[ja_ptr[9]] + va[k+8]*x[ja_ptr[8]] + va[k+7]*x[ja_ptr[7]] + va[k+6]*x[ja_ptr[6]] + va[k+5]*x[ja_ptr[5]] + va[k+4]*x[ja_ptr[4]] + va[k+3]*x[ja_ptr[3]] + va[k+2]*x[ja_ptr[2]] + va[k+1]*x[ja_ptr[1]] + va[k]*x[*ja_ptr]; ja_ptr += 10; } for (; k < ia[i+1]; k ++) s += va[k]*x[*ja_ptr++]; y[i] = s; } #else for (i = 0; i < m; i ++) { s = 0.0; for (k = ia[i]; k < ia[i+1]; k ++) s += va[k] * x[ja[k]]; y[i] = s; } #endif } static void csr_matvec_kernel_stride(int m, double *x, int incx, double *y, int incy, double *va, int *ja, int *ia) { double s; int i, k; for (i = 0; i < m; i ++) { s = 0.0; for (k = ia[i]; k < ia[i+1]; k ++) s += va[k] * x[ja[k]*incx]; y[i*incy] = s; } } static void csr_matvec_transp_kernel(int m, int n, double *x, double *y, double *va, int *ja, int *ia) { double xi; int i, k; for (i = 0; i < n; i ++) y[i] = 0.0; for (i = 0; i < m; i ++) { xi = x[i]; for (k = ia[i]; k < ia[i+1]; k ++) y[ja[k]] += va[k] * xi; } } static void csr_matvec_transp_kernel_stride(int m, int n, double *x, int incx, double *y, int incy, double *va, int *ja, int *ia) { double xi; int i, k; for (i = 0; i < n; i ++) y[i*incy] = 0.0; for (i = 0; i < m; i ++) { xi = x[i*incx]; for (k = ia[i]; k < ia[i+1]; k ++) y[ja[k]*incy] += va[k] * xi; } } static char matvec_transp_doc[] = "a.matvec_transp(x, y)\n\ \n\ compute the sparse matrix-vector product y := a^T * x. \n\ a^T is the transpose of a, which is a d1 by d2 sparse matrix.\n\ x and y are two 1-dimensional Numeric arrays of appropriate size."; static PyObject * CSRMat_matvec_transp(CSRMatObject *self, PyObject *args) { PyArrayObject *xp, *yp; SPMATRIX_PARSE_ARGS_ARR_ARR_STRIDE(args, xp, yp, self->dim[0], self->dim[1]); if (xp->flags & CONTIGUOUS && yp->flags & CONTIGUOUS) csr_matvec_transp_kernel(self->dim[0], self->dim[1], (double *)(xp->data), (double *)(yp->data), self->val, self->col, self->ind); else { csr_matvec_transp_kernel_stride(self->dim[0], self->dim[1], (double *)(xp->data), xp->strides[0] / sizeof(double), (double *)(yp->data), yp->strides[0] / sizeof(double), self->val, self->col, self->ind); } Py_INCREF(Py_None); return Py_None; } static char matvec_doc[] = "a.matvec(x, y)\n\ \n\ compute the sparse matrix-vector product y := a * x. \n\ a is a d1 by d2 sparse matrix.\n\ x and y are two 1-dimensional Numeric arrays of appropriate size."; static PyObject * CSRMat_matvec(CSRMatObject *self, PyObject *args) { PyArrayObject *xp, *yp; SPMATRIX_PARSE_ARGS_ARR_ARR_STRIDE(args, xp, yp, self->dim[1], self->dim[0]); if (xp->flags & CONTIGUOUS && yp->flags & CONTIGUOUS) csr_matvec_kernel(self->dim[0], (double *)(xp->data), (double *)(yp->data), self->val, self->col, self->ind); else { int incx = xp->strides[0] / sizeof(double); int incy = yp->strides[0] / sizeof(double); csr_matvec_kernel_stride(self->dim[0], (double *)(xp->data), incx, (double *)(yp->data), incy, self->val, self->col, self->ind); } Py_INCREF(Py_None); return Py_None; } /** table of object methods */ PyMethodDef CSRMat_methods[] = { {"matvec", (PyCFunction)CSRMat_matvec, METH_VARARGS, matvec_doc}, {"matvec_transp", (PyCFunction)CSRMat_matvec_transp, METH_VARARGS, matvec_transp_doc}, {NULL, NULL} /* sentinel */ }; /*********************************************************************** * CSRMatType methods */ static void CSRMatType_dealloc(CSRMatObject *a) { PyMem_DEL(a->ind); PyMem_DEL(a->val); PyMem_DEL(a->col); PyObject_Del(a); } static int CSRMatType_print(CSRMatObject *a, FILE *fp, int flags) { int i, k, first = 1; if (a->nnz == 0) { fprintf(fp, "csr_mat([%d,%d])", a->dim[0], a->dim[1]); return 0; } fprintf(fp, "csr_mat([%d,%d], [", a->dim[0], a->dim[1]); for (i = 0; i < a->dim[0]; i ++) { for (k = a->ind[i]; k < a->ind[i+1]; k ++) { if (!first) fprintf(fp, ", "); first = 0; fprintf(fp, "(%d,%d): %g", i, a->col[k], a->val[k]); } } fprintf(fp, "])"); return 0; } static PyObject * CSRMatType_getattr(CSRMatObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->dim[0], self->dim[1]); if (strcmp(name, "nnz") == 0) return PyInt_FromLong(self->nnz); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape", "nnz"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(CSRMat_methods, (PyObject *)self, name); } /*********************************************************************** * CSRMatType structure */ static PyTypeObject CSRMatType = { PyObject_HEAD_INIT(NULL) 0, "csr_mat", sizeof(CSRMatObject), 0, (destructor)CSRMatType_dealloc, /* tp_dealloc */ (printfunc)CSRMatType_print, /* tp_print */ (getattrfunc)CSRMatType_getattr, /* 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 */ }; /** newCSRMatObject -- allocate a new CSRMatObject instance * * a newly allocated, uninitialized CSRMatObject is returned */ static PyObject * newCSRMatObject(int dim[], int nnz) { CSRMatObject *op; /* create new SparseArrayt object */ op = PyObject_New(CSRMatObject, &CSRMatType); if (op == NULL) PyErr_NoMemory(); op->val = NULL; op->ind = NULL; op->col = NULL; /* allocate arrays */ op->ind = PyMem_New(int, dim[0] + 1); if (op->ind == NULL) goto fail; op->val = PyMem_New(double, nnz); if (op->val == NULL) goto fail; op->col = PyMem_New(int, nnz); if (op->col == NULL) goto fail; /* initialize rest of fields */ op->dim[0] = dim[0]; op->dim[1] = dim[1]; op->nnz = nnz; return (PyObject *) op; fail: PyMem_Del(op->ind); PyMem_Del(op->val); PyMem_Del(op->col); PyObject_Del(op); return PyErr_NoMemory(); } pysparse-1.1.1/Src/gmres.c0000644010116400000240000001304711402270126014364 0ustar wd15dialout#include #include #include "Python.h" #include "pysparse/fortran.h" #include "pysparse/blas.h" #define SPMATRIX_UNIQUE_SYMBOL itsolvers_spmatrix #include "pysparse/spmatrix.h" #include "pysparse/gmres.h" #define SpMatrix_PRECON(prec_obj, n, x, y) \ {if (SpMatrix_Precon((prec_obj),(n),(x),(y))) return -1;} #define SpMatrix_MATVEC(mat_obj, n, x, m, y) \ {if (SpMatrix_Matvec((mat_obj), (n), (x), (m), (y))) return -1;} static double InnerProd(int n, double *x, double *y) { double result; int one = 1; result = F77(ddot)(&n, x, &one, y, &one); return result; } static void CopyVector(int n, double *x, double *y) { int one = 1; F77(dcopy)(&n, x, &one, y, &one); } static void ScaleVector(int n, double alpha, double *x) { int one = 1; F77(dscal)(&n, &alpha, x, &one); } static void Axpy(int n, double alpha, double *x, double *y) { int one = 1; F77(daxpy)(&n, &alpha, x, &one, y, &one); } /* simulate 2-D arrays at the cost of some arithmetic */ #define V(i) (&V[(i)*n]) #define W(i) (&W[(i)*n]) #define H(i,j) (H[(j)*m1+(i)]) static void GeneratePlaneRotation(double dx, double dy, double *cs, double *sn) { if (dy == 0.0) { *cs = 1.0; *sn = 0.0; } else if (fabs(dy) > fabs(dx)) { double temp = dx / dy; *sn = 1.0 / sqrt( 1.0 + temp*temp ); *cs = temp * *sn; } else { double temp = dy / dx; *cs = 1.0 / sqrt( 1.0 + temp*temp ); *sn = temp * *cs; } } static void ApplyPlaneRotation(double *dx, double *dy, double cs, double sn) { double temp = cs * *dx + sn * *dy; *dy = -sn * *dx + cs * *dy; *dx = temp; } int Itsolvers_gmres_kernel(int n, double errtol, int it_max, int *it, double *relres, int dim, double *x, double *b, double *work, PyObject *mat_obj, PyObject *prec_obj) { int ONE = 1; int mype = 1; /* use 0 for monitoring results */ int iter; double rel_resid; double *H = (double *) malloc(dim*(dim+1) * sizeof(double)); int m1 = dim+1; /* used inside H macro */ int i, j, k; double beta, resid0, n2b; double *s = (double *) malloc((dim+1) * sizeof(double)); double *cs = (double *) malloc(dim * sizeof(double)); double *sn = (double *) malloc(dim * sizeof(double)); double *V = (double *) malloc(n*(dim+1) * sizeof(double)); double *W = (double *) malloc(n*dim * sizeof(double)); /* Check for all zero right hand side vector => all zero solution */ n2b = F77(dnrm2)(&n, b, &ONE);/* Norm of rhs vector, b */ if (n2b == 0.0) { /* if rhs vector is all zeros */ for (i = 0; i < n; i ++) /* then solution is all zeros */ x[i] = 0.0; /* a valid solution has been obtained */ *relres = 0.0; /* the relative residual is actually 0/0 */ *it = 0; /* no iterations need be performed */ return(0); } iter = 0; do { /* compute initial residual and its norm */ SpMatrix_MATVEC(mat_obj, n, x, n, V(0)); /* V(0) = A*x */ Axpy(n, -1.0, b, V(0)); /* V(0) = V(0) - b */ beta = sqrt(InnerProd(n, V(0), V(0))); /* beta = norm(V(0)) */ ScaleVector(n, -1.0/beta, V(0)); /* V(0) = -V(0)/beta */ /* save very first residual norm */ if (iter == 0) resid0 = beta; for (i = 1; i < dim+1; i++) s[i] = 0.0; s[0] = beta; i = -1; do { i++; iter++; if (prec_obj){ SpMatrix_PRECON(prec_obj, n, V(i), W(i)); } else { CopyVector(n, V(i), W(i)); } SpMatrix_MATVEC(mat_obj, n, W(i), n, V(i+1)); for (k = 0; k <= i; k++) { H(k, i) = InnerProd(n, V(i+1), V(k)); /* V(i+1) -= H(k, i) * V(k); */ Axpy(n, -H(k,i), V(k), V(i+1)); } H(i+1, i) = sqrt(InnerProd(n, V(i+1), V(i+1))); /* V(i+1) = V(i+1) / H(i+1, i) */ ScaleVector(n, 1.0 / H(i+1, i), V(i+1)); for (k = 0; k < i; k++) ApplyPlaneRotation(&H(k,i), &H(k+1,i), cs[k], sn[k]); GeneratePlaneRotation(H(i,i), H(i+1,i), &cs[i], &sn[i]); ApplyPlaneRotation(&H(i,i), &H(i+1,i), cs[i], sn[i]); ApplyPlaneRotation(&s[i], &s[i+1], cs[i], sn[i]); rel_resid = fabs(s[i+1]) / resid0; if (mype == 0) printf("Iter (%d): rel. resid. norm: %e\n", iter, rel_resid); if (rel_resid <= errtol) break; } while (i+1 < dim && iter+1 <= it_max); /* solve upper triangular system in place */ for (j = i; j >= 0; j--) { s[j] /= H(j,j); for (k = j-1; k >= 0; k--) s[k] -= H(k,j) * s[j]; } /* update the solution */ for (j = 0; j <= i; j++) { /* x = x + s[j] * W(j) */ Axpy(n, s[j], W(j), x); } } while (rel_resid > errtol && iter+1 <= it_max); /* compute exact residual norm reduction */ SpMatrix_MATVEC(mat_obj, n, x, n, V(0)); /* V(0) = A*x */ Axpy(n, -1.0, b, V(0)); /* V(0) = V(0) - b */ beta = sqrt(InnerProd(n, V(0), V(0))); /* beta = norm(V(0)) */ rel_resid = beta / resid0; if (mype == 0) printf("Iter (%d): computed true norm : %e\n", iter, beta); *it = iter; *relres = rel_resid; free(H); free(s); free(cs); free(sn); free(V); free(W); return 0; } pysparse-1.1.1/Src/itsolversmodule.c0000644010116400000240000004051311402270124016503 0ustar wd15dialout/** MODULE itsolvers * */ #include "Python.h" #define PY_ARRAY_UNIQUE_SYMBOL itsolvers_pyarray //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #define SPMATRIX_UNIQUE_SYMBOL itsolvers_spmatrix #include "pysparse/spmatrix.h" #include "pysparse/pcg.h" #include "pysparse/bicgstab.h" #include "pysparse/minres.h" #include "pysparse/gmres.h" #include "pysparse/qmrs.h" #include "pysparse/cgs.h" /*********************************************************************** * Module functions */ static char pcg_doc[] = "info, iter, relres = pcg(A, b, x, tol, maxit)\n\ \n\ Preconditioned Conjugate Gradient method."; static PyObject * ItSolvers_pcg(PyObject *self, PyObject *args) { /* input arguments */ PyObject *amat; PyArrayObject *b; PyArrayObject *x; double tol; int maxit; int clvl = 0; /* output arguments */ int info; int iter; double relres; /* other variables */ int n; double *work; int res; intp nx, nb; double *x_data, *b_data; PyObject *precon = Py_None; /* default value for precon */ /* Parse input arguments */ if (!PyArg_ParseTuple(args, "OOOdi|O", &amat, &b, &x, &tol, &maxit, &precon)) return NULL; /* check shape of matrix object */ res = SpMatrix_GetOrder((PyObject *)amat, &n); if (res) return NULL; /* Make sure that x and b are contiguous double arrays */ res = PyArray_AsCArray((PyObject **)&x, (void *)&x_data, &nx, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert x to double array"); return NULL; } res = PyArray_AsCArray((PyObject **)&b, (void *)&b_data, &nb, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert b to double array"); return NULL; } if (nx != nb || n != nx) { PyErr_SetString(PyExc_ValueError, "incompatible operand shapes"); return NULL; } /* allocate workspace for temporary vectors */ work = PyMem_New(double, 4*n); /* call pcg routine */ Itsolvers_pcg_kernel(n, x_data, b_data, tol, maxit, clvl, &iter, &relres, &info, work, amat, precon == Py_None ? NULL : precon); /* free workspace */ PyMem_DEL(work); res = PyArray_Free((PyObject *)x, (void *)&x_data); assert(res != -1); res = PyArray_Free((PyObject *)b, (void *)&b_data); assert(res != -1); /* return result tuple */ if (PyErr_Occurred()) return NULL; else return Py_BuildValue("iid", info, iter, relres); } static char bicgstab_doc[] = "info, iter, relres = bicgstab(A, b, x, tol, maxit)\n\ \n\ Preconditioned Stabilized BiConjugate Gradient method."; static PyObject * ItSolvers_bicgstab(PyObject *self, PyObject *args) { /* input arguments */ PyObject *amat; PyArrayObject *b; PyArrayObject *x; double tol; int maxit; int clvl = 0; /* output arguments */ int info; int iter; double relres; /* other variables */ int n; double *work; int res; intp nx, nb; double *x_data, *b_data; PyObject *precon = Py_None; /* default value for precon */ /* Parse input arguments */ if (!PyArg_ParseTuple(args, "OOOdi|O", &amat, &b, &x, &tol, &maxit, &precon)) return NULL; /* check shape of matrix object */ res = SpMatrix_GetOrder((PyObject *)amat, &n); if (res) return NULL; /* Make sure that x and b are continous double arrays */ res = PyArray_AsCArray((PyObject **)&x, (void *)&x_data, &nx, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert x to double array"); return NULL; } res = PyArray_AsCArray((PyObject **)&b, (void *)&b_data, &nb, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert b to double array"); return NULL; } if (nx != nb || n != nx) { PyErr_SetString(PyExc_ValueError, "incompatible operand shapes"); return NULL; } /* allocate workspace for temporary vectors */ work = PyMem_New(double, 8*n); /* call bicgstab routine */ Itsolvers_bicgstab_kernel(n, x_data, b_data, tol, maxit, clvl, &iter, &relres, &info, work, amat, precon == Py_None ? NULL : precon); /* free workspace */ PyMem_DEL(work); res = PyArray_Free((PyObject *)x, (void *)&x_data); assert(res != -1); res = PyArray_Free((PyObject *)b, (void *)&b_data); assert(res != -1); /* return result tuple */ if (PyErr_Occurred()) return NULL; else return Py_BuildValue("iid", info, iter, relres); } static char minres_doc[] = "info, iter, relres = minres(A, b, x, tol, maxit, K)\n\ \n\ Minimal Residual method."; static PyObject * ItSolvers_minres(PyObject *self, PyObject *args) { /* input arguments */ PyObject *amat; PyArrayObject *b; PyArrayObject *x; double tol; int maxit; int clvl = 0; /* output arguments */ int info; int iter; double relres; /* other variables */ int n; double *work; int res; intp nx, nb; double *x_data, *b_data; int dim[2]; /* shape of amat */ PyObject *precon = Py_None; /* default value for precon */ /* Parse input arguments */ if (!PyArg_ParseTuple(args, "OOOdi|O", &amat, &b, &x, &tol, &maxit, &precon)) return NULL; /* check shape of matrix object */ SpMatrix_GetShape((PyObject *)amat, dim); if (dim[0] != dim[1] || dim[0] <= 0) { PyErr_SetString(PyExc_ValueError, "invalid matrix shape"); return NULL; } n = dim[0]; /* Make sure that x and b are continous double arrays */ res = PyArray_AsCArray((PyObject **)&x, (void *)&x_data, &nx, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert x to double array"); return NULL; } res = PyArray_AsCArray((PyObject **)&b, (void *)&b_data, &nb, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert b to double array"); return NULL; } if (nx != nb || n != nx) { PyErr_SetString(PyExc_ValueError, "incompatible operand shapes"); return NULL; } /* allocate workspace for temporary vectors */ work = PyMem_New(double, 7*n); /* call minres routine */ info = Itsolvers_minres_kernel(n, tol, maxit, &iter, &relres, clvl, x_data, b_data, work, amat, precon == Py_None ? NULL : precon); /* free workspace */ PyMem_DEL(work); res = PyArray_Free((PyObject *)x, (void *)&x_data); assert(res != -1); res = PyArray_Free((PyObject *)b, (void *)&b_data); assert(res != -1); /* return result tuple */ if (PyErr_Occurred()) return NULL; else return Py_BuildValue("iid", info, iter, relres); } static char gmres_doc[] = "info, iter, relres = gmres(A, b, x, tol, maxit, K, dim)\n\ \n\ General Minimal Residual method GMRES(m) (m=dim) of Saad and Schultz."; static PyObject * ItSolvers_gmres(PyObject *self, PyObject *args) { /* input arguments */ PyObject *amat; PyArrayObject *b; PyArrayObject *x; double tol; int maxit; int dim_gmres = 20; /* output arguments */ int info; int iter; double relres; /* other variables */ int n; double *work; int res; intp nx, nb; double *x_data, *b_data; int dim[2]; /* shape of amat */ PyObject *precon = Py_None; /* default value for precon */ /* Parse input arguments */ if (!PyArg_ParseTuple(args, "OOOdi|Oi", &amat, &b, &x, &tol, &maxit, &precon,&dim_gmres)) return NULL; /* check shape of matrix object */ SpMatrix_GetShape((PyObject *)amat, dim); if (dim[0] != dim[1] || dim[0] <= 0) { PyErr_SetString(PyExc_ValueError, "invalid matrix shape"); return NULL; } n = dim[0]; /* Make sure that x and b are continous double arrays */ res = PyArray_AsCArray((PyObject **)&x, (void *)&x_data, &nx, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert x to double array"); return NULL; } res = PyArray_AsCArray((PyObject **)&b, (void *)&b_data, &nb, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert b to double array"); return NULL; } if (nx != nb || n != nx) { PyErr_SetString(PyExc_ValueError, "incompatible operand shapes"); return NULL; } /* allocate workspace for temporary vectors */ work = PyMem_New(double, n); /* call gmres routine */ info = Itsolvers_gmres_kernel(n, tol, maxit, &iter, &relres, dim_gmres, x_data, b_data, work, amat, precon == Py_None ? NULL : precon); /* free workspace */ PyMem_DEL(work); res = PyArray_Free((PyObject *)x, (void *)&x_data); assert(res != -1); res = PyArray_Free((PyObject *)b, (void *)&b_data); assert(res != -1); /* return result tuple */ if (PyErr_Occurred()) return NULL; else return Py_BuildValue("iid", info, iter, relres); } static char qmrs_doc[] = "info, iter, relres = qmrs(A, b, x, tol, maxit, K)\n\ \n\ Minimal Residual method."; static PyObject * ItSolvers_qmrs(PyObject *self, PyObject *args) { /* input arguments */ PyObject *amat; PyArrayObject *b; PyArrayObject *x; double tol; int maxit; /* output arguments */ int info; int iter; double relres; /* other variables */ int n; double *work; int res; intp nx, nb; double *x_data, *b_data; int dim[2]; /* shape of amat */ PyObject *precon = Py_None; /* default value for precon */ /* Parse input arguments */ if (!PyArg_ParseTuple(args, "OOOdi|O", &amat, &b, &x, &tol, &maxit, &precon)) return NULL; /* check shape of matrix object */ SpMatrix_GetShape((PyObject *)amat, dim); if (dim[0] != dim[1] || dim[0] <= 0) { PyErr_SetString(PyExc_ValueError, "invalid matrix shape"); return NULL; } n = dim[0]; /* Make sure that x and b are continous double arrays */ res = PyArray_AsCArray((PyObject **)&x, (void *)&x_data, &nx, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert x to double array"); return NULL; } res = PyArray_AsCArray((PyObject **)&b, (void *)&b_data, &nb, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert b to double array"); return NULL; } if (nx != nb || n != nx) { PyErr_SetString(PyExc_ValueError, "incompatible operand shapes"); return NULL; } /* allocate workspace for temporary vectors */ work = PyMem_New(double, 6*n); /* call qmrs routine */ info = Itsolvers_qmrs_kernel(n, b_data, x_data, work, tol, maxit, &iter, &relres, amat, precon == Py_None ? NULL : precon); /* free workspace */ PyMem_DEL(work); res = PyArray_Free((PyObject *)x, (void *)&x_data); assert(res != -1); res = PyArray_Free((PyObject *)b, (void *)&b_data); assert(res != -1); /* return result tuple */ if (PyErr_Occurred()) return NULL; else return Py_BuildValue("iid", info, iter, relres); } static char cgs_doc[] = "info, iter, relres = cgs(A, b, x, tol, maxit, K)\n\ \n\ Conjugate Gradient Square method."; static PyObject * ItSolvers_cgs(PyObject *self, PyObject *args) { /* input arguments */ PyObject *amat; PyArrayObject *b; PyArrayObject *x; double tol; int maxit; /* output arguments */ int info; int iter; double relres; /* other variables */ int n; double *work; int res; intp nx, nb; double *x_data, *b_data; int dim[2]; /* shape of amat */ PyObject *precon = Py_None; /* default value for precon */ /* Parse input arguments */ if (!PyArg_ParseTuple(args, "OOOdi|O", &amat, &b, &x, &tol, &maxit, &precon)) return NULL; /* check shape of matrix object */ SpMatrix_GetShape((PyObject *)amat, dim); if (dim[0] != dim[1] || dim[0] <= 0) { PyErr_SetString(PyExc_ValueError, "invalid matrix shape"); return NULL; } n = dim[0]; /* Make sure that x and b are continous double arrays */ res = PyArray_AsCArray((PyObject **)&x, (void *)&x_data, &nx, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert x to double array"); return NULL; } res = PyArray_AsCArray((PyObject **)&b, (void *)&b_data, &nb, 1, PyArray_DescrFromType(NPY_DOUBLE)); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert b to double array"); return NULL; } if (nx != nb || n != nx) { PyErr_SetString(PyExc_ValueError, "incompatible operand shapes"); return NULL; } /* allocate workspace for temporary vectors */ work = PyMem_New(double, 8*n); /* call cgs routine */ info = Itsolvers_cgs_kernel(n, b_data, x_data, maxit, tol, work, &iter, &relres, amat, precon == Py_None ? NULL : precon); /* free workspace */ PyMem_DEL(work); res = PyArray_Free((PyObject *)x, (void *)&x_data); assert(res != -1); res = PyArray_Free((PyObject *)b, (void *)&b_data); assert(res != -1); /* return result tuple */ if (PyErr_Occurred()) return NULL; else return Py_BuildValue("iid", info, iter, relres); } /** table of module functions */ static PyMethodDef itsolvers_methods[] = { {"pcg", (PyCFunction)ItSolvers_pcg, METH_VARARGS, pcg_doc}, {"bicgstab",(PyCFunction)ItSolvers_bicgstab, METH_VARARGS, bicgstab_doc}, {"minres", (PyCFunction)ItSolvers_minres, METH_VARARGS, minres_doc}, {"gmres", (PyCFunction)ItSolvers_gmres, METH_VARARGS, gmres_doc}, {"qmrs", (PyCFunction)ItSolvers_qmrs, METH_VARARGS, qmrs_doc}, {"cgs", (PyCFunction)ItSolvers_cgs, METH_VARARGS, cgs_doc}, {NULL, NULL} /* sentinel */ }; static char module_doc[] = "This module ...\n\ \n\ All iterative solvers in this module provide the following interface\n\ \n\ info, iter, relres = pcg(A, b, x, tol, maxit, K)\n\ \n\ parameters\n\ ----------\n\ \n\ A system matrix\n\ b right hand side\n\ x initial guess on input, solution vector on output\n\ tol requested error tolerance\n\ maxit maximum number of iteration to be executed\n\ K preconditioner\n\ (optional parameter)\n\ \n\ the iterative solvers defined in this module may accept additional\n\ parameters, which are passed as keyword arguments.\n\ \n\ return value\n\ ------------\n\ \n\ The result is tuple with 3 elements:\n\ \n\ info return code with the following meaning\n\ \n\ 2 iteration converged, residual is as small as seems reasonable on this machine.\n\ \n\ 1 iteration converged, b = 0, so the exact solution is x = 0.\n\ \n\ 0 iteration converged, relative error appears to be less than tol\n\ \n\ -1 iteration not converged, maximum number of iterations was reached\n\ \n\ -2 iteration not converged, the system involving the preconditioner was ill conditioned\n\ \n\ -3 iteration not converged, an inner product of the form x(t)*K^(-1)*x\n\ was not positive, so the preconditioning matrix K does not appear to be positive \n\ definite.\n\ \n\ -4 iteration not converged, the matrix A appears to be very ill-conditioned\n\ \n\ -5 iteration not converged, the method stagnated\n\ \n\ -6 iteration not converged, a scalar quantity became too small or too large to \n\ continue computing\n\ \n\ Note that not all iterative solvers check for all above error conditions.\n\ \n\ iter number of iterations executed\n\ \n\ relres relative error of the solution\n\ \n\ "; DL_EXPORT(void) inititsolvers(void) { PyObject *m; m = Py_InitModule3("itsolvers", itsolvers_methods, module_doc); /* initialize Numeric array module */ import_array(); /* initialize spmatrix module */ import_spmatrix(); /* No need to check the error here, the caller will do that */ } pysparse-1.1.1/Src/jdsym.c0000644010116400000240000007255611402270127014410 0ustar wd15dialout/************************************************************************** * * * Swiss Federal Institute of Technology (ETH) * * CH-8092 Zuerich, Switzerland * * * * (C) 1999 All Rights Reserved * * * * NOTICE * * * * Permission to use, copy, modify, and distribute this software and * * its documentation for any purpose and without fee is hereby granted * * provided that the above copyright notice appear in all copies and * * that both the copyright notice and this permission notice appear in * * supporting documentation. * * * * Neither the Swiss Federal Institute of Technology nor the author make * * any representations about the suitability of this software for any * * purpose. This software is provided ``as is'' without express or * * implied warranty. * * * *************************************************************************** * * Main routine of eigensolver * * $Id: jdsym.c 38 2005-01-04 14:28:01Z hamsel $ * * **************************************************************************/ /**************************************************************************** * * * Prototypes of static functions * * * ****************************************************************************/ static void print_status(int clvl, int it, int k, int j, int kmax, int blksize, int actblksize, double *s, double *resnrm, int *actcorrits); static void quicksort(int n, double arr[], int idx[]); static void sorteig(int j, double S[], double U[], int ldu, double tau, double dtemp[], int idx1[], int idx2[], int strategy); /**************************************************************************** * * * Main eigensolver routine * * * ****************************************************************************/ static int jdsym (int n, double tau, double jdtol, int kmax, int jmax, int jmin, int itmax, int blksize, int blkwise, PyArrayObject *V0, PyObject *linsolver, int optype, int linitmax, double eps_tr, double toldecay, int strategy, int clvl, int *k_conv, double *Q, double *lambda, int *it, int *it_inner, PyObject *amat, PyObject *mmat, PyObject *prec, PyObject *proj) { /**************************************************************************** * * * Local variables * * * ****************************************************************************/ /* Correction equation object */ CorrEqObject *correq = NULL; /* allocatables: * initialize with NULL, so we can free even unallocated ptrs */ double *V = NULL, *Vtmp = NULL, *U = NULL, *Qm = NULL, *Y = NULL, *s = NULL, *Res = NULL, *resnrm = NULL, *M = NULL, *H = NULL, *Hlu = NULL, *eigwork = NULL, *temp1 = NULL, *temp2 = NULL; int *Hpiv = NULL, *idx1 = NULL, *idx2 = NULL, *convind = NULL, *keepind = NULL, *solvestep = NULL, *actcorrits = NULL; /* non-allocated ptrs */ double *q, *v, *u, *r, *y, *qm; double *matdummy, *vecdummy; /* scalar vars */ double theta, alpha, it_tol; int eigworklen, found, conv, keep, act, cnt, idummy, info, ret; double linres; /* return values from linear solver */ int linit; int k; /* number of already converged eigenpairs */ int j; /* dimension of serach subspace (matrix V) */ int nof_ce_its = 0; /* number of inner iterations spent in CE */ int nof_ce = 0; /* number of CE solved */ int actblksize; /* current block size (may be smaller than blksize) */ int i; /* look variable */ /* variables for random number generator */ int IDIST = 1; int ISEED[4] = {2, 3, 5, 7}; /**************************************************************************** * * * Execution starts here... * * * ****************************************************************************/ /* print info header */ if (clvl >= 1) { printf("JDSYM Solving %s %s preconditioning.\n\n", !mmat ? "A*x = lambda*x" : "A*x = lambda*M*x", !prec ? "without" : "with"); printf(" N= %10d ITMAX=%4d\n", n, itmax); printf(" KMAX=%3d JMIN=%3d JMAX=%3d V0DIM=%3d\n", kmax, jmin, jmax, V0 == NULL ? 0 : (V0->nd == 1 ? 1 : V0->dimensions[1])); printf(" BLKSIZE= %2d BLKWISE= %5s\n", blksize, blkwise ? "TRUE" : "FALSE"); printf(" TAU= %11.4e JDTOL= %11.4e STRATEGY= %8d\n", tau, jdtol, strategy); printf(" OPTYPE=%12s\n", optype == JDSYM_OP_UNSYM ? "UNSYM" : "SYM"); printf(" LINITMAX= %5d EPS_TR= %10.3e TOLDECAY=%9.2e\n", linitmax, eps_tr, toldecay); printf("\n"); } /* validate input parameters */ assert(0 < jdtol); assert(0 < kmax && kmax <= n); assert(0 < jmax && jmax <= n); assert(0 < jmin && jmin < jmax); assert(0 <= itmax); assert(blksize <= jmin); assert(blksize <= jmax - jmin); assert(0 < blksize && blksize <= kmax); assert(blkwise == 0 || blkwise == 1); assert(optype == JDSYM_OP_UNSYM || optype == JDSYM_OP_SYM); assert(0 <= linitmax); assert(0.0 <= eps_tr); assert(1.0 < toldecay); /* Get hardware-dependent values: * Opt size of workspace for DSYEV is (NB+2)*j, where NB is the opt. * block size... */ eigworklen = (2 + F77(ilaenv)(&ONE, "dsytrd", "vu", &jmax, &MONE, &MONE, &MONE, 6, 2)) * jmax; /* * Allocate memory */ V = (double *)malloc(n * jmax * sizeof(double)); U = (double *)malloc(jmax * jmax * sizeof(double)); s = (double *)malloc(jmax * sizeof(double)); Res = (double *)malloc(n * blksize * sizeof(double)); resnrm = (double *)malloc(blksize * sizeof(double)); M = (double *)malloc(jmax * jmax * sizeof(double)); Vtmp = (double *)malloc(jmax * jmax * sizeof(double)); idx1 = (int *)malloc(jmax * sizeof(int)); idx2 = (int *)malloc(jmax * sizeof(int)); convind = (int *)malloc(blksize * sizeof(int)); keepind = (int *)malloc(blksize * sizeof(int)); solvestep = (int *)malloc(blksize * sizeof(int)); actcorrits = (int *)malloc(blksize * sizeof(int)); eigwork = (double *)malloc(eigworklen * sizeof(double)); temp1 = (double *)malloc(n * sizeof(double)); temp2 = (double *)malloc(n * sizeof(double)); if (!(V && U && s && Res && resnrm && M && Vtmp && idx1 && idx2 && convind && keepind && solvestep && actcorrits && eigwork && temp1 && temp2)) { PyErr_NoMemory(); goto fail; } /* Allocate matrices H, Y and G only if necessary */ if (prec) { H = (double *)malloc(kmax * kmax * sizeof(double)); Hlu = (double *)malloc(kmax * kmax * sizeof(double)); Hpiv = (int *)malloc(kmax * sizeof(int)); Y = (double *)malloc(n * kmax * sizeof(double)); if (!(H && Hlu && Hpiv && Y)) { PyErr_NoMemory(); goto fail; } } /* Analogous for Qm only if necessary */ if (mmat) { Qm = (double *)malloc(n * kmax * sizeof(double)); if (!Qm) { PyErr_NoMemory(); goto fail; } } /* Create CorrEqObject */ correq = (CorrEqObject *)newCorrEqObject(optype, n, amat, mmat, prec, Q, Qm, Y, Hpiv, Hlu, kmax); if (!correq) goto fail; /************************************************************************** * * * Generate initial search subspace V. Vectors are taken from V0 and if * * necessary randomly generated. * * * **************************************************************************/ /* copy V0 to V */ if (V0 != NULL) { if (V0->nd == 1) { j = 1; for (i = 0; i < n; i ++) V[i] = *(double *)(V0->data + i*V0->strides[0]); } else { j = V0->dimensions[1]; if (j > jmax) j = jmax; for (k = 0; k < j; k ++) for (i = 0; i < n; i ++) V[n*k + i] = *(double *)(V0->data + i*V0->strides[0] + k*V0->strides[1]); } } else j = 0; /* if j < blksize: generate additional random vectors */ if (j < blksize) { idummy = (blksize - j)*n; /* nof random numbers */ F77(dlarnv)(&IDIST, ISEED, &idummy, V + j*n); j = blksize; } /* Project into user subspace */ if (proj) for (cnt = 0; cnt < j; cnt ++) Jdsym_Proj(proj, n, V + cnt*n); /* (M-)orthogonalize columns of V */ if (!mmat) { for (cnt = 0; cnt < j; cnt ++) { mgs(V + cnt*n, n, cnt, V); alpha = 1.0 / F77(dnrm2)(&n, V + cnt*n, &ONE); F77(dscal)(&n, &alpha, V + cnt*n, &ONE); } } else { for (cnt = 0; cnt < j; cnt ++) { icgsm(V + cnt*n, &alpha, n, cnt, V, mmat, temp1, temp2); alpha = 1.0/alpha; assert(alpha > 0.0); F77(dscal)(&n, &alpha, V + cnt*n, &ONE); } } /* Generate interaction matrix M = V'*A*V. Only the upper triangle is computed. */ for (cnt = 0; cnt < j; cnt++){ ret = SpMatrix_Matvec(amat, n, V+cnt*n, n, temp1); assert(ret == 0); idummy = cnt+1; F77(dgemv)("t", &n, &idummy, &DONE, V, &n, temp1, &ONE, &DZER, M+cnt*jmax, &ONE, 1); } /* Other initializations */ k = 0; *it = 0; actblksize = blksize; for(act = 0; act < blksize; act ++) solvestep[act] = 1; /**************************************************************************** * * * Main JD-iteration loop * * * ****************************************************************************/ while(*it < itmax) { /**************************************************************************** * * * Solving the projected eigenproblem * * * * M*u = V'*A*V*u = s*u * * M is symmetric, only the upper triangle is stored * * * ****************************************************************************/ F77(dlacpy)("u", &j, &j, M, &jmax, U, &jmax, 1); F77(dsyev)("v", "u", &j, U, &jmax, s, eigwork, &eigworklen, &info, 1, 1); if (info != 0) { printf("jdsym: error solving the projected eigenproblem."); printf(" dsyev: info = %d\n", info); } assert(info == 0); /* sort eigenpairs, such that |S(i)-tau| <= |S(i+1)-tau| for i=1..j-1 */ sorteig(j, s, U, jmax, tau, temp1, idx1, idx2, strategy); /**************************************************************************** * * * Convergence/Restart Check * * * * In case of convergence, strip off a whole block or just the converged * * ones and put 'em into Q. Update the matrices Q, V, U, s and if * * necessary Qm, Y, and H. * * * * In case of a restart update the V, U and M matrices and recompute the * * Eigenvectors * * * ****************************************************************************/ found = 1; while(found) { /* conv/keep = Number of converged/non-converged Approximations */ conv = 0; keep = 0; for(act=0; act < actblksize; act++) { /* Setting pointers for single vectors */ q = Q + (act+k)*n; u = U + act*jmax; r = Res + act*n; qm = Qm + (act+k)*n; y = Y + (act+k)*n; /* Compute Ritz-Vector Q[:,k+cnt1]=V*U[:,cnt1] */ theta = s[act]; F77(dgemv)("n", &n, &j, &DONE, V, &n, u, &ONE, &DZER, q, &ONE, 1); /* Compute the residual and update the matrix Qm if necessary. */ if (!mmat){ /* M is Identity */ SpMatrix_Matvec(amat, n, q, n, r); theta = -theta; F77(daxpy)(&n, &theta, q, &ONE, r, &ONE); } else{ /* M is NOT Identity */ SpMatrix_Matvec(mmat, n, q, n, qm); SpMatrix_Matvec(amat, n, q, n, r); theta = -theta; F77(daxpy)(&n, &theta, qm, &ONE, r, &ONE); } /* Finally update matrices H, Y if necessary */ if (prec){ if (mmat) { matdummy = Qm; vecdummy = qm; /* If M exists, then also Qm does */ } else { matdummy = Q; vecdummy = q; /* Without M, no Qm */ } /* Calculate y = inv(K)*qm */ SpMatrix_Precon(prec, n, vecdummy, y); /* update H, starting with the column ... */ idummy=k+act+1; F77(dgemv)("t", &n, &idummy, &DONE, matdummy, &n, y, &ONE, &DZER, H+(k+act)*kmax, &ONE, 1); /* ... and then the row */ F77(dgemv)("t", &n, &idummy, &DONE, Y, &n, vecdummy, &ONE, &DZER, H+(k+act), &kmax, 1); } /* Compute norm of the residual and update arrays convind/keepind*/ resnrm[act] = F77(dnrm2)(&n, r, &ONE); if (resnrm[act] < jdtol) { convind[conv] = act; conv = conv + 1; } else { keepind[keep] = act; keep = keep + 1; } } /* for(act = 0; act < actblksize; act ++) */ /* Check whether the blkwise-mode is chosen and ALL the approximations converged, or whether the strip-off mode is active and SOME of the approximations converged */ found = ((blkwise==1 && conv==actblksize) || (blkwise==0 && conv!=0)) && (j > actblksize || k == kmax - actblksize); /*************************************************************************** * * * Convergence Case * * * * In case of convergence, strip off a whole block or just the converged * * ones and put 'em into Q. Update the matrices Q, V, U, s and if * * necessary Qm, Y, and H. * * * **************************************************************************/ if (found) { /* Store Eigenvalues */ for(act = 0; act < conv; act++) lambda[k+act] = s[convind[act]]; /* Re-use non approximated Ritz-Values */ for(act = 0; act < keep; act++) s[act] = s[keepind[act]]; /* Shift the others in the right position */ for(act = 0; act < (j-actblksize); act ++) s[act+keep] = s[act+actblksize]; /* Update V. Re-use the V-Vectors not looked at yet. */ idummy = j - actblksize; for (act = 0; act < n; act = act + jmax) { cnt = act + jmax > n ? n-act : jmax; F77(dlacpy)("a", &cnt, &j, V+act, &n, Vtmp, &jmax, 1); F77(dgemm)("n", "n", &cnt, &idummy, &j, &DONE, Vtmp, &jmax, U+actblksize*jmax, &jmax, &DZER, V+act+keep*n, &n, 1, 1); } /* Insert the not converged approximations as first columns in V */ for(act = 0; act < keep; act++){ F77(dlacpy)("a",&n,&ONE,Q+(k+keepind[act])*n,&n,V+act*n,&n,1); } /* Store Eigenvectors */ for(act = 0; act < conv; act++) F77(dlacpy)("a",&n,&ONE,Q+(k+convind[act])*n,&n,Q+(k+act)*n,&n,1); /* Update Qm if necessary */ if (mmat){ for(act = 0; act < conv; act++) F77(dlacpy)("a",&n,&ONE,Qm+(k+convind[act])*n,&n,Qm+(k+act)*n,&n,1); } /* Update H and Y if necessary */ if (prec){ for(act = 0; act < conv; act++) /* Y */ F77(dlacpy)("a",&n,&ONE,Y+(k+convind[act])*n,&n,Y+(k+act)*n,&n,1); for(act=0; act < conv; act++){ /* H */ idummy = k + act; /* Copy column ... */ F77(dlacpy)("a",&idummy,&ONE,H+(k+convind[act])*kmax,&kmax,H+idummy*kmax,&kmax,1); /* ... diagonalelement ... */ H[idummy*(kmax+1)]=H[(k+convind[act])*(kmax+1)]; /* ... and row */ F77(dlacpy)("a",&ONE,&idummy,H+(k+convind[act]),&kmax,H+idummy,&kmax,1); } } /* Update SearchSpaceSize j */ j = j - conv; /* Let M become a diagonal matrix with the Ritzvalues as entries ... */ F77(dlaset)("u", &j, &j, &DZER, &DZER, M, &jmax, 1); for (act = 0; act < j; act++) M[act*jmax + act] = s[act]; /* ... and U the Identity(jnew,jnew) */ F77(dlaset)("a", &j, &j, &DZER, &DONE, U, &jmax, 1); /* Avoid computation of zero eigenvalues: If STRATEGY == 1: set tau to the largest of the now converged eigenvalues. Warning: This may not work well if BLKSIZE > 1. */ if (strategy == 1) for(act = 0; act < conv; act ++) if (lambda[k+act] > tau) tau = lambda[k+act]; /* Update Converged-Eigenpair-counter and Pro_k */ k = k + conv; /* Update the new blocksize */ actblksize = blksize < kmax-k ? blksize : kmax-k; /* Exit main iteration loop when kmax eigenpairs have been approximated */ if (k == kmax) goto end; /* Counter for the linear-solver-accuracy */ for(act = 0; act < keep; act++) solvestep[act] = solvestep[keepind[act]]; for(act = keep; act < blksize; act++) solvestep[act] = 1; } /* if(found) */ /************************************************************************** * * * Restart * * * * The Eigenvector-Aproximations corresponding to the first jmin * * Petrov-Vectors are kept. if (j+actblksize > jmax) { * * * **************************************************************************/ if (j+actblksize > jmax) { idummy = j; j = jmin; for (act = 0; act < n; act = act + jmax) { /* V = V * U(:,1:j) */ cnt = act+jmax > n ? n-act : jmax; F77(dlacpy)("a", &cnt, &idummy, V+act, &n, Vtmp, &jmax, 1); F77(dgemm)("n", "n", &cnt, &j, &idummy, &DONE, Vtmp, &jmax, U, &jmax, &DZER, V+act, &n, 1, 1); } F77(dlaset)("a", &j, &j, &DZER, &DONE, U, &jmax, 1); F77(dlaset)("u", &j, &j, &DZER, &DZER, M, &jmax, 1); for (act = 0; act < j; act++) M[act*jmax + act] = s[act]; } } /* while(found) */ /**************************************************************************** * * * Solving the correction equations * * * * Depending on the input-arguments we choose an appropriate lin.solver. * * * ****************************************************************************/ /* calculate Hlu (LU-factorization), if necessary */ if (prec){ idummy = k + actblksize; F77(dlacpy)("a", &idummy, &idummy, H, &kmax, Hlu, &kmax, 1); F77(dgetrf)(&idummy, &idummy, Hlu, &kmax, Hpiv, &info); if (info != 0) printf("jdsym: factorization of H failed: info=%d\n", info); assert(info == 0); } /* Solve actblksize times the correction equation ... */ for (act = 0; act < actblksize; act ++) { /* Setting start-value for vector v as zeros(n,1). Guarantees (M-)orthogonality */ v = V + j*n; for (cnt = 0; cnt < n; cnt ++) v[cnt] = 0.0; /* Adaptive accuracy and shift for the lin.solver. In case the residual is big, we don't need a too precise solution for the correction equation, since even in exact arithmetic the solution wouldn't be too useful for the Eigenproblem. */ r = Res + act*n; if (resnrm[act] < eps_tr) correq->update(correq, k + actblksize, s[act]); else correq->update(correq, k + actblksize, tau); it_tol = pow(toldecay, (double)(-solvestep[act])); solvestep[act] = solvestep[act] + 1; /* Form the right hand side of the correction equation */ correq->right(correq, r); /* Solve the correction equation ... */ ret = ItSolvers_Solve(linsolver, (PyObject *)correq, n, r, v, it_tol, linitmax, (PyObject *)correq, &info, &linit, &linres); if (ret == -1) goto fail; /* Actualizing profiling data */ /*#warning error check after iteative solver?*/ nof_ce ++; nof_ce_its += linit; actcorrits[act] = linit; /* (M-)orthonormalize v to Q, project into user subspace and finally (M-)orthonormalize to V (M-)orthonormalize v to Q is necessary, because the implicit orthogonalization in the solvers may be too inaccurate. IteratedCGS is used to prevent numerical breakdown */ if (mmat) { mgsm(v, n, k+actblksize, Q, Qm); if (proj) Jdsym_Proj(proj, n, v); icgsm(v, &alpha, n, j, V, mmat, temp1, temp2); } else { mgs(v, n, k+actblksize, Q); if (proj) Jdsym_Proj(proj, n, v); icgs(v, &alpha, n, j, V, temp1); } alpha = 1.0 / alpha; F77(dscal)(&n, &alpha, v, &ONE); /* update interaction matrix M */ SpMatrix_Matvec(amat, n, v, n, temp1); idummy = j+1; F77(dgemv)("t", &n, &idummy, &DONE, V, &n, temp1, &ONE, &DZER, M+j*jmax, &ONE, 1); /* Increasing SearchSpaceSize j */ j ++; } /* for (act = 0;act < actblksize; act ++) */ /* Print information line */ print_status(clvl, *it, k, j - blksize, kmax, blksize, actblksize, s, resnrm, actcorrits); /* Increase iteration-counter for outer loop */ (*it) ++; } /* Main iteration loop */ end: /****************************************************************** * * * Eigensolutions converged or iteration limit reached * * * * Print statistics. Free memory. Return. * * * ******************************************************************/ *k_conv = k; *it_inner = nof_ce_its; if (clvl >= 1) { printf("\nJDSYM execution statistics\n\n"); printf("IT_OUTER=%d IT_INNER_TOT=%d IT_INNER_AVG=%8.2f IT_INNER_PER_OUTER=%8.2f\n", (*it), nof_ce_its, (double)nof_ce_its/(*it), (double)nof_ce_its/nof_ce); printf("\nConverged eigensolutions in order of convergence:\n"); printf("\n I LAMBDA(I) RES(I)\n"); printf("---------------------------------------\n"); for (act = 0; act < *k_conv; act ++) { /* Compute the residual for solution act */ q = Q + act*n; qm = Qm + act*n; theta = -lambda[act]; ret = SpMatrix_Matvec(amat, n, q, n, r); assert(ret == 0); if (!mmat) F77(daxpy)(&n, &theta, q, &ONE, r, &ONE); else { ret = SpMatrix_Matvec(mmat, n, q, n, qm); assert(ret == 0); F77(daxpy)(&n, &theta, qm, &ONE, r, &ONE); } printf("%3d %22.15e %12.5e\n", act+1, lambda[act], F77(dnrm2)(&n, r, &ONE)); } printf("\n"); } free(V); free(Vtmp); free(U); free(Qm); free(Y); free(s); free(Res); free(resnrm); free(M); free(H); free(Hlu); free(eigwork); free(temp1); free(temp2); free(Hpiv); free(idx1); free(idx2); free(convind); free(keepind); free(solvestep); free(actcorrits); Py_DECREF(correq); return 0; fail: free(V); free(Vtmp); free(U); free(Qm); free(Y); free(s); free(Res); free(resnrm); free(M); free(H); free(Hlu); free(eigwork); free(temp1); free(temp2); free(Hpiv); free(idx1); free(idx2); free(convind); free(keepind); free(solvestep); free(actcorrits); Py_XDECREF(correq); return -1; } /* jdsym(.....) */ /**************************************************************************** * * * Supporting functions * * * ****************************************************************************/ /* PRINT_STATUS - print status line (called for each outer iteration) */ static void print_status(int clvl, int it, int k, int j, int kmax, int blksize, int actblksize, double *s, double *resnrm, int *actcorrits) { const int max_vals = 5; int i, idummy; if (clvl >= 1) { if (blksize == 1) { if (it == 0) { printf(" IT K J RES CGIT RITZVALS(1:5)\n"); idummy = 27 + ( 13 > max_vals*10 ? 13 : max_vals*10); for (i = 0; i < idummy; i ++) putchar('-'); printf("\n"); } printf("%4d %3d %3d %9.2e %4d", it + 1, k, j, resnrm[0], actcorrits[0]); for (i = 0; i < (j < max_vals ? j : max_vals); i ++) printf(" %9.2e", s[i]); printf("\n"); } else { /* blksize > 1 */ if (it == 0) { printf(" IT K J RITZVALS "); for (i = 1; i < actblksize; i ++) printf(" "); printf(" RES "); for (i = 1; i < actblksize; i ++) printf(" "); printf(" CGIT\n"); idummy = 12 + 4 + blksize*(10 + 10 + 5); for (i = 0; i < idummy; i ++) putchar('-'); printf("\n"); } printf("%4d %3d %3d", it + 1, k, j); for (i = 0; i < blksize; i ++) if (i < actblksize) printf(" %9.2e", s[i]); else printf(" "); printf(" "); for (i = 0; i < blksize; i ++) if (i < actblksize) printf(" %9.2e", resnrm[i]); else printf(" "); printf(" "); for (i = 0; i < blksize; i ++) if (i < actblksize) printf(" %4d", actcorrits[i]); else printf(" "); printf("\n"); } } } /* * SORTEIG * * Default behaviour (strategy == 0): * * Sort eigenpairs (S(i),U(:,i)), such that * * |S(i) - tau| <= |S(i+1) -tau| for i=1..j-1. * * j : dimension of S * ldu: leading dimension of U * dtemp: double array of length j * idx: int array of length j * * Alternate behaviour (strategy == 1): * * Same as above but put all S(i) < tau to the end. This is used to * avoid computation of zero eigenvalues. */ static void sorteig(int j, double S[], double U[], int ldu, double tau, double dtemp[], int idx1[], int idx2[], int strategy) { int i; /* setup vector to be sorted and index vector */ switch (strategy) { case 0: for (i = 0; i < j; i ++) dtemp[i] = fabs(S[i] - tau); break; case 1: for (i = 0; i < j; i ++) if (S[i] < tau) dtemp[i] = DBL_MAX; else dtemp[i] = fabs(S[i] - tau); break; default: assert(0); } for (i = 0; i < j; i ++) idx1[i] = i; /* sort dtemp in ascending order carrying itemp along */ quicksort(j, dtemp, idx1); /* compute 'inverse' index vector */ for (i = 0; i < j; i ++) idx2[idx1[i]] = i; /* sort eigenvalues */ memcpy(dtemp, S, j * sizeof(double)); for (i = 0; i < j; i ++) S[i] = dtemp[idx1[i]]; /* sort eigenvectors (in place) */ for (i = 0; i < j; i ++) { if (i != idx1[i]) { memcpy(dtemp, U+i*ldu, j*sizeof(double)); memcpy(U+i*ldu, U+idx1[i]*ldu, j*sizeof(double)); memcpy(U+idx1[i]*ldu, dtemp, j*sizeof(double)); idx1[idx2[i]] = idx1[i]; idx2[idx1[i]] = idx2[i]; } } } /* * QUICKSORT * * Sorts a double array using a non-recursive quicksort algorithm in * ascending order carrying along an int array. * */ static void quicksort(int n, double arr[], int idx[]) { double v, td; int i, j, l, r, ti, tos, stack[32]; l = 0; r = n-1; tos = -1; for (;;) { while (r > l) { v = arr[r]; i = l; j = r-1; for (;;) { while (arr[i] < v) i ++; /* j > l prevents underflow */ while (arr[j] >= v && j > l) j --; if (i >= j) break; td = arr[i]; arr[i] = arr[j]; arr[j] = td; ti = idx[i]; idx[i] = idx[j]; idx[j] = ti; } td = arr[i]; arr[i] = arr[r]; arr[r] = td; ti = idx[i]; idx[i] = idx[r]; idx[r] = ti; if (i-l > r-i) { stack[++tos] = l; stack[++tos] = i-1; l = i+1; } else { stack[++tos] = i+1; stack[++tos] = r; r = i-1; } assert(tos < 32); } if (tos == -1) break; r = stack[tos--]; l = stack[tos--]; } } pysparse-1.1.1/Src/jdsymmodule.c0000644010116400000240000002046711402270132015604 0ustar wd15dialout/** MODULE jdsym * */ #include #include #include #include #include #include #include #include "Python.h" #define PY_ARRAY_UNIQUE_SYMBOL jdsym_API //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #include "pysparse/fortran.h" #include "pysparse/blas.h" #include "pysparse/lapack.h" #include "pysparse/spmatrix.h" /*********************************************************************** * Static constant variables */ static double DONE = 1.0; static double DZER = 0.0; static double DMONE = -1.0; static int MONE = -1; static int ONE = 1; /*********************************************************************** * Helper code for jdsym: Calls the 'proj' method of a python object * passing a double array. */ static int Jdsym_Proj(PyObject *proj, int n, double *x) { PyObject *x_arr = NULL; int dimensions[1]; PyObject *res; dimensions[0] = n; /* create array objects from x and y */ x_arr = PyArray_FromDimsAndData(1, dimensions, PyArray_DOUBLE, (char *)x); if (x_arr == NULL) goto fail; /* Call "project" method of "proj" object */ res = PyObject_CallMethod(proj, "project", "O", x_arr); if (res != Py_None) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_RuntimeError, "error when calling projector"); goto fail; } Py_DECREF(res); /* free array objects */ Py_DECREF(x_arr); return 0; fail: Py_XDECREF(x_arr); return -1; } /*********************************************************************** * Include additional C code */ #include "orthopack.c" #include "correq.c" #include "jdsym.c" /*********************************************************************** * Module functions */ static char jdsym_doc[] = "\ Jacobi davidson eigenvalue solver for symmetric matrices\n\ \n\ kconv, lmbd, Q, it, it_inner = jdsym(amat, mmat, prec, kmax, tau, jdtol, itmax, linsolver, ...)\n\ \n\ jdsym computes kmax eigenpairs in the vincinity of target tau of the generalized \n\ eigenvalue problem\n\ \n\ amat * x = lambda * mmat * x\n\ \n\ If mmat is None, jdsym computes eigenpairs of the standart eigenvalue problem\n\ \n\ amat * x = lambda * x\n\ \n\ Required arguments:\n\ \n\ amat: matrix object. Must be symmetric.\n\ \n\ mmat: matrix object or None. Must be symmetric positive definite.\n\ \n\ prec: preconditioner object or None. The preconditioner must be symmetric and\n\ should approximate amat - tau mmat.\n\ \n\ kmax: number of eigenpairs to be computed\n\ \n\ tau: float value, target value\n\ \n\ jdtol: required error tolerance for computed eigensolutions\n\ \n\ itmax: maximum number of JD iterations to be performed\n\ \n\ linsolver: callable object which implements a linear solver such as\n\ itsolvers.cgs or itsolvers.qmrs\n\ \n\ Additional keyword arguments:\n\ \n\ jmax: integer, maximal dimension of search subspace (default value: 25)\n\ \n\ jmin: integer, dimension of search subspace after restart (default value: 10)\n\ \n\ Result values:\n\ \n\ kconv: integer, number of converged eigenpairs\n\ \n\ lmbd: double array of dimension kconv, eigenvalues\n\ \n\ Q: double array of dimension n x kconv, eigenvectors, \n\ lmbd[k], Q[:,k] is the kth eigenpair\n\ \n\ it: integer, number of JD iterations\n\ \n\ it_inner: number of inner iterations performed"; static PyObject * JDSym_jdsym(PyObject *self, PyObject *args, PyObject *keywds) { /* required arguments */ PyObject *amat; PyObject *mmat; PyObject *prec; int kmax; double tau; double jdtol; int itmax; PyObject* linsolver; /* optional arguments (default values) */ int jmax = 25; int jmin = 10; int blksize = 1; int blkwise = 0; PyArrayObject *V0 = NULL; int optype = 2; int linitmax = 200; double eps_tr = 1.0e-3; double toldecay = 1.5; int clvl = 0; int strategy = 0; PyObject *proj = NULL; /* result */ int kconv; int it_outer; int it_inner; double *Q = NULL; double *lambda = NULL; PyArrayObject *Q_obj = NULL; PyArrayObject *lambda_obj = NULL; PyObject *result; /* other local variables */ int n, na, nm, nk, np; /* order of eigensystem */ int i, k, ret; int dimensions[2]; static char *kwlist[] = { "A", "M", "K", "kmax", "tau", "jdtol", "itmax", "linsolver", "jmax", "jmin", "blksize", "blkwise", "V0", "optype", "linitmax", "eps_tr", "toldecay", "clvl", "strategy", "projector", NULL}; ret = PyArg_ParseTupleAndKeywords(args, keywds, "OOOiddiO|iiiiO!iiddiiO", kwlist, /* required args */ &amat, &mmat, &prec, &kmax, &tau, &jdtol, &itmax, &linsolver, /* optional args */ &jmax, &jmin, &blksize, &blkwise, &PyArray_Type, &V0, &optype, &linitmax, &eps_tr, &toldecay, &clvl, &strategy, &proj); if (!ret) return NULL; /* * Check shapes of matrix, preconditioner and projector objects */ if (SpMatrix_GetOrder((PyObject *)amat, &na)) return NULL; if (mmat != Py_None) { if (SpMatrix_GetOrder((PyObject *)mmat, &nm)) return NULL; } else nm = na; if (prec != Py_None) { if (SpMatrix_GetOrder((PyObject *)prec, &nk)) return NULL; } else nk = na; if (proj != NULL) { if (SpMatrix_GetOrder((PyObject *)proj, &np)) return NULL; } else np = na; if (na != nm || na != nk || na != np) { PyErr_SetString(PyExc_ValueError, "matrix, preconditioner or projector shapes differ"); return NULL; } n = na; /* Check V0 argument * * Here the V0 argument should be converted to Fortran ordering */ if (V0 != NULL) { if (!((V0->nd == 1 || V0->nd == 2) && V0->descr->type_num == PyArray_DOUBLE && V0->dimensions[0] == n)) { PyErr_SetString(PyExc_ValueError, "V0 is not of correct type or shape"); goto fail; } } /* allocate (max.) space for eigenvectors and eigenvalues */ Q = PyMem_New(double, n*kmax); if (Q == NULL) { PyErr_NoMemory(); goto fail; } lambda = PyMem_New(double, kmax); if (lambda == NULL) { PyErr_NoMemory(); goto fail; } /* call Jacobi-Davidson eigensolver */ ret = jdsym(n, tau, jdtol, kmax, jmax, jmin, itmax, blksize, blkwise, V0, linsolver, optype, linitmax, eps_tr, toldecay, strategy, clvl, &kconv, Q, lambda, &it_outer, &it_inner, amat, mmat == Py_None ? NULL : mmat, prec == Py_None ? NULL : prec, proj); if (ret == -1) goto fail; /* * prepare and return results */ /* allocate array objects for *converged* eigenvectors */ dimensions[0] = n; dimensions[1] = kconv; Q_obj = (PyArrayObject *)PyArray_FromDims(2, dimensions, PyArray_DOUBLE); if (Q_obj == NULL) goto fail; /* copy converged eigenvectors, convert from Fortran to C ordering */ for (k = 0; k < kconv; k ++) for (i = 0; i < n; i ++) ((double *)Q_obj->data)[i*kconv + k] = Q[k*n + i]; /* allocate array objects for *converged* eigenvalues */ dimensions[0] = kconv; lambda_obj = (PyArrayObject *)PyArray_FromDims(1, dimensions, PyArray_DOUBLE); if (lambda_obj == NULL) goto fail; for (k = 0; k < kconv; k ++) ((double *)lambda_obj->data)[k] = lambda[k]; /* delete original arrays */ PyMem_DEL(Q); PyMem_DEL(lambda); result = Py_BuildValue("iOOii", kconv, lambda_obj, Q_obj, it_outer, it_inner); /* Py_BuildValue increased refcount, so decrease it or it would never be freed */ Py_DECREF(lambda_obj); Py_DECREF(Q_obj); return result; fail: PyMem_DEL(Q); PyMem_DEL(lambda); Py_XDECREF(Q_obj); Py_XDECREF(lambda_obj); return NULL; } /** table of module functions */ static PyMethodDef jdsym_methods[] = { {"jdsym", (PyCFunction)JDSym_jdsym, METH_VARARGS|METH_KEYWORDS, jdsym_doc}, {NULL, NULL} /* sentinel */ }; static char module_doc[] = "This module ...\n\ "; DL_EXPORT(void) initjdsym(void) { PyObject *m; m = Py_InitModule3("jdsym", jdsym_methods, module_doc); /* initialize Numeric array module */ import_array(); /* initialize spmatrix module */ import_spmatrix(); /* No need to check the error here, the caller will do that */ } pysparse-1.1.1/Src/ll_mat.c0000644010116400000240000027422611402270125014526 0ustar wd15dialout#include "Python.h" #include #include "pysparse/mmio.h" #include "pysparse/ll_mat.h" #include "pysparse/csr_mat.h" #include "pysparse/sss_mat.h" #define SPMATRIX_MODULE //#include "pysparse/spmatrix.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #define PY_ARRAY_UNIQUE_SYMBOL spmatrix //#include "Numeric/arrayobject.h" #define INCREASE_FACTOR 1.5 // increase rate for reallocation of ll_mat arrays #define PPRINT_ROW_THRESH 500 // row threshold for choosing print format #define PPRINT_COL_THRESH 20 // column threshold for choosing print format #define OPT_MATMATMUL 1 // enable optimised matrix-matrix-multiplication #define PYSP_MAX(A,B) ( (A) > (B) ? (A) : (B) ) // Iterator object #define SLICE 0 #define LIST 1 #define ARRAY 2 typedef struct PysparseIterator { int type; // Slice, list or array PyObject *object; // Python slice, list or Numpy array int (*init)(void *); // Iterator initialization function int (*notDone)(void *); // Determines whether iterations are finished void (*next)(void *); // Move to next iteration PyObject* (*data)(void *); // Get current iteration data long (*size)(void *); // Get total number of iterations long counter; long length; long start; long step; long stop; } PysparseIterator; // Prototypes static PyObject *LLMat_Find(LLMatObject *self, PyObject *args); PysparseIterator* PysparseIterator_Create( int type, PyObject *object ); void PysparseIterator_Destroy( PysparseIterator **iterator ); int PysparseIterator_List_Init( void *self ); int PysparseIterator_List_NotDone( void *self ); void PysparseIterator_List_Next( void *self ); PyObject *PysparseIterator_List_Data( void *self ); long PysparseIterator_List_Size( void *self ); // Iterator creation function: No argument check for now PysparseIterator* PysparseIterator_Create( int type, PyObject *object ) { PysparseIterator *iterator; iterator = calloc( 1, sizeof(PysparseIterator) ); if( iterator == NULL ) return NULL; iterator->type = type; iterator->object = object; iterator->init = PysparseIterator_List_Init; iterator->notDone = PysparseIterator_List_NotDone; iterator->next = PysparseIterator_List_Next; iterator->data = PysparseIterator_List_Data; iterator->size = PysparseIterator_List_Size; return iterator; } // Iterator destruction function: Let garbage collector take care of PyObjects // Call as: PysparseIterator_Destroy( &iterator ); void PysparseIterator_Destroy( PysparseIterator **iterator ) { if( *iterator ) { free(*iterator); *iterator = NULL; } return; } // Initialization of an iterator around a Python list int PysparseIterator_List_Init( void *self ) { PysparseIterator *iterator = (PysparseIterator *)self; if( !PyList_Check( iterator->object ) ) return -1; iterator->counter = 0; iterator->length = (long)PyList_Size( (PyObject *)(iterator->object) ); iterator->start = 0; iterator->step = 1; iterator->stop = iterator->length; return 0; } // Define iterator functions for a Python list int PysparseIterator_List_NotDone( void *self ) { PysparseIterator *iterator = (PysparseIterator *)self; return (iterator->counter < iterator->length); } void PysparseIterator_List_Next( void *self ) { PysparseIterator *iterator = (PysparseIterator *)self; iterator->counter++; return; } PyObject *PysparseIterator_List_Data( void *self ) { PysparseIterator *iterator = (PysparseIterator *)self; return (PyObject *)PyList_GetItem(iterator->object, (Py_ssize_t)(iterator->counter)); } long PysparseIterator_List_Size( void *self ) { PysparseIterator *iterator = (PysparseIterator *)self; return iterator->length; } // Define iterator functions for a Numpy array /******************************************************************************/ /* Routines for building data structure for columnwise traversal of ll_mat */ /* sparse matrix objects. */ /******************************************************************************/ /* * SpMatrix_LLMatBuildColIndex: build data structure for columnwise traversal * * build a (root,row,link) linked-list data structure which links the * entries of each column of self. * * if includeDiagonal is zero the diagonal elements of self are * not included in the linked-list data structure. */ static int SpMatrix_LLMatBuildColIndex(struct llColIndex **idx, LLMatObject *self, int includeDiagonal) { int i, j, k; if(!(*idx = (struct llColIndex*)malloc(sizeof(struct llColIndex)))) goto fail; /* Allocate (link,row,root) arrays. Can we do better than nalloc ??? */ if( !( (*idx)->link = PyMem_New(int, self->nalloc) ) ) goto fail; if( !( (*idx)->row = PyMem_New(int, self->nalloc) ) ) goto fail; if( !( (*idx)->root = PyMem_New(int, self->dim[1]) ) ) goto fail; /* Initialize root arrays */ for (i = 0; i < self->dim[1]; i ++) (*idx)->root[i] = -1; /* Scan matrix from bottom up so the resulting lists * are sorted by ascending row */ (*idx)->nzLo = 0; (*idx)->nzDiag = 0; (*idx)->nzUp = 0; for (i = self->dim[0] - 1; i >= 0; i--) { k = self->root[i]; while (k != -1) { j = self->col[k]; if (i > j) (*idx)->nzLo++; else if (i == j) (*idx)->nzDiag++; else (*idx)->nzUp++; if (includeDiagonal || i != j) { (*idx)->link[k] = (*idx)->root[j]; (*idx)->root[j] = k; (*idx)->row[k] = i; } k = self->link[k]; } } return 0; fail: if (*idx != NULL) { PyMem_Del((*idx)->link); PyMem_Del((*idx)->row); PyMem_Del((*idx)->root); free(*idx); *idx = NULL; } PyErr_NoMemory(); return 1; } /* * Free memory of (root,row,link) linked-list data */ static void SpMatrix_LLMatDestroyColIndex(struct llColIndex **idx) { if (*idx != NULL) { PyMem_Del((*idx)->link); PyMem_Del((*idx)->row); PyMem_Del((*idx)->root); free(*idx); *idx = NULL; } } /******************************************************************************/ /* Routines for setting, updating and reading entries of ll_mat objects */ /******************************************************************************/ /* * Return matrix entry a[i,j] as a double value */ static double SpMatrix_LLMatGetItem(LLMatObject *a, int i, int j) { int k, t; /* while( i < 0 ) i += a->dim[0]; while( j < 0 ) j += a->dim[1]; if( i >= a->dim[0] || j >= a->dim[1] ) { PyErr_SetString(PyExc_IndexError, "Index out of bounds"); return 0.0; } */ if(i < 0 || i >= a->dim[0] || j < 0 || j >= a->dim[1]) { PyErr_SetString(PyExc_IndexError, "indices out of range"); return 0.0; } if (a->issym && i < j) { t = i; i = j; j = t; } k = a->root[i]; while (k != -1) { if (a->col[k] == j) return a->val[k]; k = a->link[k]; } return 0.0; } /* * Set matrix entry: a[i,j] = x */ static int SpMatrix_LLMatSetItem(LLMatObject *a, int i, int j, double x) { void *temp; int k, new_elem, last, col; if (a->issym && i < j) { PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "write operation to upper triangle of symmetric matrix"); return -1; } //printf("LLMatSetItem: matrix dimensions=(%d,%d)\n", a->dim[0], a->dim[1]); //printf("LLMatSetItem: receiving row=%d, col=%d, val=%g\n", i, j, x); if(i < 0 || i >= a->dim[0] || j < 0 || j >= a->dim[1]) { PyErr_SetString(PyExc_IndexError, "indices out of range"); return -1; } /* Find element to be set (or removed) */ col = last = -1; k = a->root[i]; while (k != -1) { col = a->col[k]; if (col >= j) break; last = k; k = a->link[k]; } if (x != 0.0) { if (col == j) { /* element already exist */ a->val[k] = x; } else { /* new element */ /* find location for new element */ if (a->free != -1) { /* use element from the free chain */ new_elem = a->free; a->free = a->link[new_elem]; } else { /* append new element to the end */ new_elem = a->nnz; /* test if there is space for a new element */ if (a->nnz == a->nalloc) { int nalloc_new; /* increase size of idx, val and link arrays */ nalloc_new = (int)((double)INCREASE_FACTOR * a->nalloc) + 1; if ((temp = PyMem_Resize(a->col, int, nalloc_new)) == NULL) goto fail; else a->col = temp; if ((temp = PyMem_Resize(a->link, int, nalloc_new)) == NULL) goto fail; else a->link = temp; if ((temp = PyMem_Resize(a->val, double, nalloc_new)) == NULL) goto fail; else a->val = temp; a->nalloc = nalloc_new; } } a->val[new_elem] = x; a->col[new_elem] = j; a->link[new_elem] = k; if (last == -1) a->root[i] = new_elem; else a->link[last] = new_elem; a->nnz ++; } } else { /* x == 0.0 */ if (col == j) { /* relink row i */ if (last == -1) a->root[i] = a->link[k]; else a->link[last] = a->link[k]; /* add element to free list */ a->link[k] = a->free; a->free = k; a->nnz --; } } return 0; fail: PyErr_NoMemory(); return -1; } /* * Update-add matrix entry: a[i,j] += x */ static int SpMatrix_LLMatUpdateItemAdd(LLMatObject *a, int i, int j, double x) { void *temp; int k, new_elem, col, last; if (a->issym && i < j) { PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "write operation to upper triangle of symmetric matrix"); return -1; } if (x == 0.0) return 0; /* Find element to be updated */ col = last = -1; k = a->root[i]; while (k != -1) { col = a->col[k]; if (col >= j) break; last = k; k = a->link[k]; } if (col == j) { /* element already exists: compute updated value */ x += a->val[k]; if (x == 0.0) { /* the updated element is zero and must be removed */ /* relink row i */ if (last == -1) a->root[i] = a->link[k]; else a->link[last] = a->link[k]; /* add element to free list */ a->link[k] = a->free; a->free = k; a->nnz --; } else { a->val[k] = x; } } else { /* new item */ if (a->free != -1) { /* use element from the free chain */ new_elem = a->free; a->free = a->link[new_elem]; } else { /* append new element to the end */ new_elem = a->nnz; /* test if there is space for a new element */ if (a->nnz == a->nalloc) { int nalloc_new; /* increase size of idx, val and link arrays */ nalloc_new = (int)((double)INCREASE_FACTOR * a->nalloc) + 1; if ((temp = PyMem_Resize(a->col, int, nalloc_new)) == NULL) goto fail; else a->col = temp; if ((temp = PyMem_Resize(a->link, int, nalloc_new)) == NULL) goto fail; else a->link = temp; if ((temp = PyMem_Resize(a->val, double, nalloc_new)) == NULL) goto fail; else a->val = temp; a->nalloc = nalloc_new; } } a->val[new_elem] = x; a->col[new_elem] = j; a->link[new_elem] = k; if (last == -1) a->root[i] = new_elem; else a->link[last] = new_elem; a->nnz ++; } return 0; fail: PyErr_NoMemory(); return -1; } /* * Shrink val, col and link arrays of matrix to minimal size */ static int LLMat_Compress(LLMatObject *self, int *nofFreed) { double *val; int *col, *link; int i, k, k_next, k_last, k_new, nalloc_new; nalloc_new = self->nnz; /* new size for val, col and link arrays */ /* remove entries with k >= nalloc_new from free list */ k_last = -1; k = self->free; while (k != -1) { k_next = self->link[k]; if (k >= nalloc_new) { if (k_last == -1) self->free = k_next; else self->link[k_last] = k_next; } else k_last = k; k = k_next; } /* reposition matrix entries with k >= nalloc_new */ for (i = 0; i < self->dim[0]; i ++) { k_last = -1; for (k = self->root[i]; k != -1; k = self->link[k]) { if (k >= nalloc_new) { k_new = self->free; if (k_last == -1) self->root[i] = k_new; else self->link[k_last] = k_new; self->free = self->link[k_new]; self->val[k_new] = self->val[k]; self->col[k_new] = self->col[k]; self->link[k_new] = self->link[k]; k_last = k_new; } else k_last = k; } } /* shrink arrays */ if( !(col = PyMem_Resize(self->col, int, nalloc_new)) ) goto fail; self->col = col; if( !(link = PyMem_Resize(self->link, int, nalloc_new)) ) goto fail; self->link = link; if( !(val = PyMem_Resize(self->val, double, nalloc_new)) ) goto fail; self->val = val; *nofFreed = self->nalloc - nalloc_new; self->nalloc = nalloc_new; return 0; fail: PyErr_NoMemory(); return -1; } /***********************************************************************/ /* R o u t i n e s f o r h a n d l i n g s u b m a t r i c e s */ /***********************************************************************/ /* Create a index array from a Python list or slice */ long* create_indexlist(long *len, long maxlen, PyObject *A) { long *index; long i, j; Py_ssize_t start, stop, step, length; PyObject *val; /* Integer */ if( PyInt_Check(A) ) { i = PyInt_AS_LONG(A); if( (index = calloc(1, sizeof(long))) ) index[0] = i; *len = 1; return index; } /* Slice */ if( PySlice_Check(A) ) { if( PySlice_GetIndicesEx((PySliceObject*)A, maxlen, &start, &stop, &step, &length) < 0) return NULL; if( (index = calloc(length, sizeof(long))) ) for( i=start, j=0; jdim[0]; while( col < 0 ) col += self->dim[1]; if( row >= self->dim[0] || col >= self->dim[1] ) { PyErr_SetString(PyExc_IndexError, "Index ouf of bounds"); return NULL; } return PyFloat_FromDouble( SpMatrix_LLMatGetItem(self, row, col) ); } // Both index sets are Python slices if( PySlice_Check(index0) && PySlice_Check(index1) ) { int i, j, k, row, col, t, inslice1; Py_ssize_t start0, stop0, step0, length0; Py_ssize_t start1, stop1, step1, length1; double val; if( PySlice_GetIndicesEx((PySliceObject*)index0, self->dim[0], &start0, &stop0, &step0, &length0) < 0) return NULL; if( PySlice_GetIndicesEx((PySliceObject*)index1, self->dim[1], &start1, &stop1, &step1, &length1) < 0) return NULL; dim[0] = length0; dim[1] = length1; dst = (LLMatObject *)SpMatrix_NewLLMatObject(dim, symmetric, self->nnz); if( !dst ) return NULL; row = start0; i = 0; // Set row index of first element to be output // Scan each row in turn while( (step0 > 0 && row < stop0) || (step0 < 0 && row > stop0) ) { // Scan current row for( k = self->root[row]; k != -1; k = self->link[k] ) { col = self->col[k]; // Col index of current nonzero element inslice1 = 0; if( step1 > 0 && col >= start1 && col < stop1 ) inslice1 = (col % step1 == 0); else if( step1 < 0 && col <= start1 && col > stop1 ) inslice1 = (col % step1 == 0); if( inslice1 ) { // Want this element if( self->issym && row < col ) { // Swap row and col t = col; col = row; row = t; } val = SpMatrix_LLMatGetItem(self, row, col); j = (long)((col - start1)/step1); // Col index of element in output if( SpMatrix_LLMatSetItem(dst, i, j, val) ) { Py_DECREF(dst); PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return NULL; } } } row += step0; // Move to next row i++; } /* Here is another version of slicing which is less efficient since * it scans the whole slices and extracts every single element in the * slices, including all the potentially zero elements. */ /* row = start0; i = 0; while( (step0 > 0 && row < stop0) || (step0 < 0 && row > stop0) ) { col = start1; j = 0; while( (step1 > 0 && col < stop1) || (step1 < 0 && col > stop1) ) { val = SpMatrix_LLMatGetItem(self, row, col); if( SpMatrix_LLMatSetItem(dst, i, j, val) ) { Py_DECREF(dst); PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return NULL; } col += step1; j++; } row += step0; i++; } */ /* A third version of slicing would be to build a column index for the * input matrix, scan both the row and column linked lists and retain * only common elements. */ return (PyObject *)dst; } // Both index sets are Python lists if( PyList_Check(index0) && PyList_Check(index1) ) { int i, j; long row, col; Py_ssize_t length0 = PyList_Size(index0); Py_ssize_t length1 = PyList_Size(index1); PyObject *ind; double val; dim[0] = length0; dim[1] = length1; dst = (LLMatObject *)SpMatrix_NewLLMatObject(dim, symmetric, self->nnz); if( !dst ) return NULL; for( i = 0; i < length0; i++ ) { ind = PyList_GetItem(index0, (Py_ssize_t)i); if( PyInt_Check(ind) ) row = PyInt_AS_LONG(ind); else { Py_DECREF(dst); PyErr_SetString(PyExc_ValueError, "Invalid list item"); return NULL; } for( j = 0; j < length1; j++ ) { ind = PyList_GetItem(index1, (Py_ssize_t)j); if( PyInt_Check(ind) ) col = PyInt_AS_LONG(ind); else { Py_DECREF(dst); PyErr_SetString(PyExc_ValueError, "Invalid list item"); return NULL; } val = SpMatrix_LLMatGetItem(self, row, col); if( SpMatrix_LLMatSetItem(dst, i, j, val) ) { Py_DECREF(dst); PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return NULL; } } } return (PyObject *)dst; } // Both index sets are Numpy arrays if( PyArray_Check(index0) && PyArray_Check(index1) ) { int i, j; long row, col; double val; PyObject *iterator0 = PyArray_IterNew(index0); // Use iterators because may PyObject *iterator1 = PyArray_IterNew(index1); // not be contiguous npy_intp length0 = PyArray_DIM(index0, 0); npy_intp length1 = PyArray_DIM(index1, 0); dim[0] = length0; dim[1] = length1; dst = (LLMatObject *)SpMatrix_NewLLMatObject(dim, symmetric, self->nnz); if( !dst ) { Py_XDECREF(iterator0); Py_XDECREF(iterator1); return NULL; } PyArray_ITER_RESET(iterator0); i = 0; while( PyArray_ITER_NOTDONE(iterator0) ) { row = *(long*)PyArray_ITER_DATA(iterator0); PyArray_ITER_RESET(iterator1); j = 0; while( PyArray_ITER_NOTDONE(iterator1) ) { col = *(long*)PyArray_ITER_DATA(iterator1); val = SpMatrix_LLMatGetItem(self, row, col); if( SpMatrix_LLMatSetItem(dst, i, j, val) ) { Py_DECREF(dst); Py_DECREF(iterator0); Py_DECREF(iterator1); PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return NULL; } PyArray_ITER_NEXT(iterator1); j++; } PyArray_ITER_NEXT(iterator0); i++; } Py_DECREF(iterator0); Py_DECREF(iterator1); return (PyObject *)dst; } // If we have a mixture of index sets, gather both sets into arrays. { long *irow, *jcol; long nrow, ncol; // Create index list from first index if( !(irow = create_indexlist(&nrow, self->dim[0], index0)) ) { PyErr_SetString(PyExc_IndexError, "Error creating first index list"); return NULL; } // Create index list from second index if( !(jcol = create_indexlist(&ncol, self->dim[1], index1)) ) { PyErr_SetString(PyExc_IndexError, "Error creating second index list"); return NULL; } dim[0] = nrow; dim[1] = ncol; dst = (LLMatObject *)SpMatrix_NewLLMatObject(dim, symmetric, self->nnz); if( !dst ) return NULL; res = copySubMatrix_FromList(self, (LLMatObject*)dst, irow, nrow, jcol, ncol); if( res ) { Py_DECREF(dst); return NULL; } return (PyObject *)dst; } } /* * Delete all non-zero entries from slice self[start0:stop0, start1:stop1] */ static int clear_submatrix(LLMatObject *self, int start0, int stop0, int start1, int stop1) { int i, j, k, next, last; for (i = start0; i < stop0; i ++) { last = -1; k = self->root[i]; while (k != -1) { j = self->col[k]; next = self->link[k]; if (start1 <= j && j < stop1) { /* remove element */ if (last == -1) self->root[i] = next; else self->link[last] = next; /* add element to free list */ self->link[k] = self->free; self->free = k; self->nnz--; } else last = k; k = next; } } return 0; } /* * Assign slice self[irow,jcol] = other. */ //static int setSubMatrix_FromList(LLMatObject *self, LLMatObject *other, // long *irow, int nrow, long *jcol, int ncol) { static void //int setSubMatrix_FromList(LLMatObject *self, PyObject *other, PyObject *index0, PyObject *index1) { LLMatObject *mat = NULL; int other_is_num = 0, other_is_sym; double val = 0.0; if( PyInt_Check(other) ) { val = (double)PyInt_AsLong(other); other_is_num = 1; } else if( PyFloat_Check(other) ) { val = PyFloat_AsDouble(other); other_is_num = 1; } //other_is_num = PyArg_Parse(other, "d;array item must be float", &val); // Both index sets are a single integer if( PyInt_Check(index0) && PyInt_Check(index1) ) { long row = PyInt_AS_LONG(index0); long col = PyInt_AS_LONG(index1); if( !other_is_num ) { //return -1; PyErr_SetString(PyExc_ValueError, "Value must be double"); return; } //return SpMatrix_LLMatSetItem(self, row, col, val); while( row < 0 ) row += self->dim[0]; while( col < 0 ) col += self->dim[1]; if( row >= self->dim[0] || col >= self->dim[1] ) { PyErr_SetString(PyExc_IndexError, "Index out of bounds"); return; } SpMatrix_LLMatSetItem(self, row, col, val); return; } if( !other_is_num ) { mat = (LLMatObject *)other; other_is_sym = mat->issym; } else other_is_sym = 0; // Both index sets are Python slices if( PySlice_Check(index0) && PySlice_Check(index1) ) { long i, j, k, row, col, t; Py_ssize_t start0, stop0, step0, length0; Py_ssize_t start1, stop1, step1, length1; if( PySlice_GetIndicesEx((PySliceObject*)index0, self->dim[0], &start0, &stop0, &step0, &length0) < 0) { PyErr_SetString(PyExc_IndexError, "Erroneous indices"); return; //return -1; } if( PySlice_GetIndicesEx((PySliceObject*)index1, self->dim[1], &start1, &stop1, &step1, &length1) < 0) { PyErr_SetString(PyExc_IndexError, "Erroneous indices"); return; //return -1; } //printf("New block of size (%ld,%ld)\n", length0, length1); if( other_is_num) { // Special case for A[slice,slice] = scalar row = start0; while( (step0 > 0 && row < stop0) || (step0 < 0 && row > stop0) ) { col = start1; while( (step1 > 0 && col < stop1) || (step1 < 0 && col > stop1) ) { if( self->issym && row < col ) { PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "Writing to upper triangle of symmetric matrix"); return; // -1; } if( SpMatrix_LLMatSetItem(self, row, col, val) ) { PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return; // -1; } col += step1; } row += step0; } } else { if( mat->dim[0] != length0 || mat->dim[1] != length1 ) { PyErr_SetString(PyExc_ValueError, "Matrix shapes are different"); return; // -1; } row = start0; i = 0; // Set row index of first element to be assigned // Scan each row in turn while( (step0 > 0 && row < stop0) || (step0 < 0 && row > stop0) ) { // Scan current row in matrix to be assigned for( k = mat->root[i]; k != -1; k = mat->link[k] ) { j = mat->col[k]; // Col index of current nonzero element col = start1 + j * step1; // Col index to be assigned to if( mat->issym && row < col ) { // Swap row and col t = col; col = row; row = t; } // Ensure write operation is permitted if( self->issym && row < col ) { PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "Writing to upper triangle of symmetric matrix"); return; // -1; } val = SpMatrix_LLMatGetItem(mat, i, j); //printf(" (%ld,%ld) -> (%ld,%ld). Val = %g\n", i,j,row,col,val); if( SpMatrix_LLMatSetItem(self, row, col, val) ) { PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return; // -1; } } row += step0; // Move to next row i++; } } return; // 0; } // Both index sets are Python lists if( PyList_Check(index0) && PyList_Check(index1) ) { //printf("We have two lists...\n"); long i, j, row, col, t; Py_ssize_t length0 = PyList_Size(index0); Py_ssize_t length1 = PyList_Size(index1); PyObject *ind; if( !other_is_num ) if( mat->dim[0] != length0 || mat->dim[1] != length1 ) { PyErr_SetString(PyExc_ValueError, "Matrix shapes are different"); return; // -1; } for( i = 0; i < length0; i++ ) { ind = PyList_GetItem(index0, (Py_ssize_t)i); if( PyInt_Check(ind) ) row = PyInt_AS_LONG(ind); else { PyErr_SetString(PyExc_IndexError, "Invalid list item"); return; // -1; } for( j = 0; j < length1; j++ ) { ind = PyList_GetItem(index1, (Py_ssize_t)j); if( PyInt_Check(ind) ) col = PyInt_AS_LONG(ind); else { PyErr_SetString(PyExc_IndexError, "Invalid list item"); return; // -1; } if( !other_is_num ) val = SpMatrix_LLMatGetItem(mat, i, j); if( other_is_sym && row < col ) { t = col; col = row; row = t; } //printf("Val = %g goes to position (%ld,%ld)\n", val, row, col); // Ensure write operation is permitted if( self->issym && row < col ) { PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "Writing to upper triangle of symmetric matrix"); return; // -1; } if( SpMatrix_LLMatSetItem(self, row, col, val) ) { PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return; // -1; } } } return; // 0; } // Both index sets are Numpy arrays if( PyArray_Check(index0) && PyArray_Check(index1) ) { long i, j, row, col, t; PyObject *iterator0 = PyArray_IterNew(index0); // Use iterators because may PyObject *iterator1 = PyArray_IterNew(index1); // not be contiguous npy_intp length0 = PyArray_DIM(index0, 0); npy_intp length1 = PyArray_DIM(index1, 0); if( !other_is_num ) if( mat->dim[0] != length0 || mat->dim[1] != length1 ) { Py_DECREF(iterator0); Py_DECREF(iterator1); PyErr_SetString(PyExc_ValueError, "Matrix shapes are different"); return; // -1; } PyArray_ITER_RESET(iterator0); i = 0; while( PyArray_ITER_NOTDONE(iterator0) ) { row = *(long*)PyArray_ITER_DATA(iterator0); PyArray_ITER_RESET(iterator1); j = 0; while( PyArray_ITER_NOTDONE(iterator1) ) { col = *(long*)PyArray_ITER_DATA(iterator1); if( !other_is_num ) val = SpMatrix_LLMatGetItem(mat, i, j); if( other_is_sym && row < col ) { t = col; col = row; row = t; } // Ensure write operation is permitted if( self->issym && row < col ) { Py_DECREF(iterator0); Py_DECREF(iterator1); PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "Writing to upper triangle of symmetric matrix"); return; // -1; } if( SpMatrix_LLMatSetItem(self, row, col, val) ) { Py_DECREF(iterator0); Py_DECREF(iterator1); PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return; // -1; } PyArray_ITER_NEXT(iterator1); j++; } PyArray_ITER_NEXT(iterator0); i++; } Py_DECREF(iterator0); Py_DECREF(iterator1); return; // 0; } // If we have a mixture of index sets, gather both sets into arrays. { long *irow, *jcol; long i, j, nrow, ncol, row, col; // Create index list from first index if( !(irow = create_indexlist(&nrow, self->dim[0], index0)) ) { PyErr_SetString(PyExc_IndexError, "Error creating first index list"); return; // -1; } // Create index list from second index if( !(jcol = create_indexlist(&ncol, self->dim[1], index1)) ) { PyErr_SetString(PyExc_IndexError, "Error creating second index list"); return; // -1; } if( !other_is_num ) if( mat->dim[0] != nrow || mat->dim[1] != ncol ) { PyErr_SetString(PyExc_ValueError, "Matrix shapes are different"); return; // -1; } for( i = 0; i < nrow; i++ ) { row = irow[i]; for( j = 0; j < ncol; j++ ) { col = jcol[j]; if( other_is_sym && row < col ) { col = row; row = jcol[j]; } // Ensure write operation is permitted if( self->issym && row < col ) { PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "Writing to upper triangle of symmetric matrix"); return; // -1; } // Insert element into self if( !other_is_num ) val = SpMatrix_LLMatGetItem(mat, i, j); if( SpMatrix_LLMatSetItem(self, row, col, val) ) { PyErr_SetString(PyExc_ValueError, "SpMatrix_LLMatSetItem failed"); return; // -1; } } } return; // 0; } } /*****************************************************************************/ /* M a t r i x - v e c t o r m u l t i p l i c a t i o n k e r n e l s */ /*****************************************************************************/ static void ll_matvec_kernel(int m, double *x, double *y, double *val, int *col, int *link, int *root) { double s; int i, k; for (i = 0; i < m; i ++) { s = 0.0; k = root[i]; while (k != -1) { s += val[k] * x[col[k]]; k = link[k]; } y[i] = s; } } static void ll_matvec_kernel_stride(int m, double *x, int incx, double *y, int incy, double *val, int *col, int *link, int *root) { double s; int i, k; for (i = 0; i < m; i ++) { s = 0.0; k = root[i]; while (k != -1) { s += val[k] * x[col[k]*incx]; k = link[k]; } y[i*incy] = s; } } static void ll_matvec_kernel_sym(int m, double *x, double *y, double *val, int *col, int *link, int *root) { double s, v, xi; int i, j, k; for (i = 0; i < m; i ++) { xi = x[i]; s = 0.0; k = root[i]; while (k != -1) { j = col[k]; v = val[k]; s += v * x[j]; if (i != j) y[j] += v * xi; k = link[k]; } y[i] = s; } } static void ll_matvec_kernel_stride_sym(int m, double *x, int incx, double *y, int incy, double *val, int *col, int *link, int *root) { double s, v, xi; int i, j, k; for (i = 0; i < m; i ++) { xi = x[i*incx]; s = 0.0; k = root[i]; while (k != -1) { j = col[k]; v = val[k]; s += v * x[j*incx]; if (i != j) y[j*incy] += v * xi; k = link[k]; } y[i*incy] = s; } } static void ll_matvec_transp_kernel(int m, int n, double *x, double *y, double *val, int *col, int *link, int *root) { double xi; int i, k; for (i = 0; i < n; i ++) y[i] = 0.0; for (i = 0; i < m; i ++) { xi = x[i]; k = root[i]; while (k != -1) { y[col[k]] += val[k] * xi; k = link[k]; } } } static void ll_matvec_transp_kernel_stride(int m, int n, double *x, int incx, double *y, int incy, double *val, int *col, int *link, int *root) { double xi; int i, k; for (i = 0; i < n; i ++) y[i*incy] = 0.0; for (i = 0; i < m; i ++) { xi = x[i*incx]; k = root[i]; while (k != -1) { y[col[k]*incy] += val[k] * xi; k = link[k]; } } } /*********************************************/ /* L L M a t o b j e c t m e t h o d s */ /*********************************************/ static char LLMat_matvec_transp_doc[] = "A.matvec_transp(x, y)\n\ \n\ compute the sparse matrix-vector product y := A^T * x. \n\ A^T is the transpose of A, which is a d1 by d2 sparse matrix.\n\ x and y are two 1-dimensional Numpy arrays of appropriate size."; static PyObject * LLMat_matvec_transp(LLMatObject *self, PyObject *args) { PyArrayObject *xp, *yp; size_t sd = sizeof(double); SPMATRIX_PARSE_ARGS_ARR_ARR_STRIDE(args, xp, yp, self->dim[0], self->dim[1]); if (xp->flags & CONTIGUOUS && yp->flags & CONTIGUOUS) if (self->issym) ll_matvec_kernel_sym(self->dim[0], (double *)(xp->data), (double *)(yp->data), self->val, self->col, self->link, self->root); else ll_matvec_transp_kernel(self->dim[0], self->dim[1], (double *)(xp->data), (double *)(yp->data), self->val, self->col, self->link, self->root); else if (self->issym) ll_matvec_kernel_stride_sym(self->dim[0], (double *)(xp->data), xp->strides[0] / sd, (double *)(yp->data), yp->strides[0] / sd, self->val, self->col, self->link, self->root); else ll_matvec_transp_kernel_stride(self->dim[0], self->dim[1], (double *)(xp->data), xp->strides[0] / sd, (double *)(yp->data), yp->strides[0] / sd, self->val, self->col, self->link, self->root); Py_INCREF(Py_None); return Py_None; } static char LLMat_matvec_doc[] = "A.matvec(x, y)\n\ \n\ compute the sparse matrix-vector product y := A * x. \n\ A is a d1 by d2 sparse matrix.\n\ x and y are two 1-dimensional Numpy arrays of appropriate size."; static PyObject * LLMat_matvec(LLMatObject *self, PyObject *args) { PyArrayObject *xp, *yp; size_t sd = sizeof(double); SPMATRIX_PARSE_ARGS_ARR_ARR_STRIDE(args, xp, yp, self->dim[1], self->dim[0]); if (xp->flags & CONTIGUOUS && yp->flags & CONTIGUOUS) if (self->issym) ll_matvec_kernel_sym(self->dim[0], (double *)(xp->data), (double *)(yp->data), self->val, self->col, self->link, self->root); else ll_matvec_kernel(self->dim[0], (double *)(xp->data), (double *)(yp->data), self->val, self->col, self->link, self->root); else if (self->issym) ll_matvec_kernel_stride_sym(self->dim[0], (double *)(xp->data), xp->strides[0] / sd, (double *)(yp->data), yp->strides[0] / sd, self->val, self->col, self->link, self->root); else ll_matvec_kernel_stride(self->dim[0], (double *)(xp->data), xp->strides[0] / sd, (double *)(yp->data), yp->strides[0] / sd, self->val, self->col, self->link, self->root); Py_INCREF(Py_None); return Py_None; } static char to_csr_doc[] = "A.to_csr()\n\ \n\ return a new CSRMatObject constructed from data of A"; static PyObject * LLMat_to_csr(LLMatObject *self, PyObject *args) { CSRMatObject *op; int i, j, k, r; if (!PyArg_ParseTuple(args, "")) return NULL; if (self->issym) { /* Symmetric case */ struct llColIndex *colIdx; if (SpMatrix_LLMatBuildColIndex(&colIdx, self, 0)) return NULL; assert(colIdx->nzUp == 0); op = (CSRMatObject *)newCSRMatObject(self->dim, 2*colIdx->nzLo + colIdx->nzDiag); if (op == NULL) { SpMatrix_LLMatDestroyColIndex(&colIdx); return NULL; } r = 0; op->ind[0] = 0; for (i = 0; i < self->dim[0]; i ++) { /* store self[0:i+1,i] in op[0:i+1,i] */ k = self->root[i]; while (k != -1) { op->val[r] = self->val[k]; op->col[r] = self->col[k]; r ++; k = self->link[k]; } /* store self[i,i+1:n] in op[i+1:n,i] */ k = colIdx->root[i]; while (k != -1) { j = colIdx->row[k]; op->val[r] = self->val[k]; op->col[r] = j; r ++; k = colIdx->link[k]; } op->ind[i+1] = r; } SpMatrix_LLMatDestroyColIndex(&colIdx); } else { /* Unsymmetric case */ op = (CSRMatObject *)newCSRMatObject(self->dim, self->nnz); if (op == NULL) return NULL; r = 0; op->ind[0] = 0; for (i = 0; i < self->dim[0]; i ++) { k = self->root[i]; while (k != -1) { op->val[r] = self->val[k]; op->col[r] = self->col[k]; r ++; k = self->link[k]; } op->ind[i+1] = r; } } return (PyObject *)op; } static char to_sss_doc[] = "a.to_sss()\n\ \n\ return a new SSSMatObject constructed from the lower triangle of a"; static PyObject * LLMat_to_sss(LLMatObject *self, PyObject *args) { SSSMatObject *op; int i, j, k, r, n, nnz; if (!PyArg_ParseTuple(args, "")) return NULL; /* test for square matrix */ n = self->dim[0]; if (n != self->dim[1]) { PyErr_SetString(PyExc_ValueError, "Matrix must be square"); return NULL; } /* 1st pass: compute number of non-zeros in lower triangle */ nnz = 0; for (i = 0; i < n; i ++) { k = self->root[i]; while (k != -1) { j = self->col[k]; if (i > j) nnz ++; k = self->link[k]; } } /* allocate new SSS matrix */ op = (SSSMatObject *)newSSSMatObject(n, nnz); if (op == NULL) return NULL; /* 2nd pass: fill SSSMatObject */ for (i = 0; i < n; i ++) op->diag[i] = 0.0; r = 0; op->ind[0] = 0; for (i = 0; i < n; i ++) { k = self->root[i]; while (k != -1) { j = self->col[k]; if (i > j) { op->val[r] = self->val[k]; op->col[r] = j; r ++; } else if (i == j) op->diag[i] = self->val[k]; k = self->link[k]; } op->ind[i+1] = r; } return (PyObject *)op; } static char LLMat_generalize_doc[] = \ "convert ll_mat object from symmetric to non-symmetric form (in-place)."; static PyObject * LLMat_generalize(LLMatObject *self, PyObject *args) { int i, j, k; if (!PyArg_ParseTuple(args, "")) return NULL; if (self->issym) { self->issym = 0; for (i = 0; i < self->dim[0]; i ++) { /* New elements are inserted into the matrix while it is being traversed. However, this should not be a problem */ for (k = self->root[i]; k != -1; k = self->link[k]) { j = self->col[k]; if (i > j) if (SpMatrix_LLMatSetItem(self, j, i, self->val[k])) return NULL; } } } Py_INCREF(Py_None); return Py_None; } static char LLMat_compress_doc[] = "A.compress() frees memory by reclaiming unused space in the data structures of A. Returns number of elements freed."; static PyObject * LLMat_compress(LLMatObject *self, PyObject *args) { int nofFreed; if (!PyArg_ParseTuple(args, "")) return NULL; if (LLMat_Compress(self, &nofFreed)) return NULL; return PyInt_FromLong(nofFreed); } static char export_mtx_doc[] = "A.export_mtx(fileName, precision=16)\n\ \n\ write matrix in Matrix Market format to fileName.\n\ \n\ Parameters:\n\ \n\ fileName: string, name of the file to be created.\n\ precision: number of significant digits to be written for double values."; static PyObject * LLMat_export_mtx(LLMatObject *self, PyObject *args) { char *fileName; int precision = 16; MM_typecode matcode; FILE *f; int ret, i, k; if (!PyArg_ParseTuple(args, "s|i", &fileName, &precision)) return NULL; if( !(f = fopen(fileName, "w")) ) return PyErr_SetFromErrno(PyExc_IOError); mm_set_matrix(matcode); mm_set_sparse(matcode); mm_set_real(matcode); self->issym ? mm_set_symmetric(matcode) : mm_set_general(matcode); ret = mm_write_banner(f, matcode); if (ret) { PyErr_SetString(SpMatrix_ErrorObject, "Error writing file header"); return NULL; } ret = fprintf(f, "%% file created by pysparse module\n"); if (ret < 0) { PyErr_SetString(PyExc_IOError, "Error writing file header"); return NULL; } ret = mm_write_mtx_crd_size(f, self->dim[0], self->dim[1], self->nnz); if (ret) { PyErr_SetString(SpMatrix_ErrorObject, "Error writing file header"); return NULL; } for (i = 0; i < self->dim[0]; i ++) { k = self->root[i]; while (k != -1) { ret = fprintf(f, "%d %d %.*e\n", i+1, self->col[k]+1, precision-1, self->val[k]); if (ret < 0) { PyErr_SetString(PyExc_IOError, "Error writing matrix data"); return NULL; } k = self->link[k]; } } ret = fclose(f); if (ret) return PyErr_SetFromErrno(PyExc_IOError); Py_INCREF(Py_None); return Py_None; } static char copy_doc[] = "A.copy()\n\ \n\ return a (deep) copy of the matrix A."; static PyObject * LLMat_copy(LLMatObject *self, PyObject *args) { LLMatObject *new; int i, k; if (!PyArg_ParseTuple(args, "")) return NULL; new = (LLMatObject *)SpMatrix_NewLLMatObject(self->dim, self->issym, self->nnz); if (new == NULL) return NULL; for (i = 0; i < self->dim[0]; i++) { k = self->root[i]; while (k != -1) { if (SpMatrix_LLMatSetItem(new, i, self->col[k], self->val[k]) == -1) { Py_DECREF(new); return NULL; } k = self->link[k]; } } return (PyObject *)new; } static char update_add_at_doc[] = "A.update_add_at(val,id1,id2)\n\ \n\ for i in range(len(val)):\n\ A[id1[i],id2[i]] += val[i]"; static PyObject * LLMat_update_add_at(LLMatObject *self, PyObject *args) { PyObject *bIn; PyObject *id1in; PyObject *id2in; PyArrayObject *b = NULL; PyArrayObject *id1 = NULL; PyArrayObject *id2 = NULL; double v; int lenb, i, err; if (!PyArg_ParseTuple(args, "OOO", &bIn, &id1in, &id2in)) return NULL; b = (PyArrayObject *)PyArray_ContiguousFromObject(bIn, PyArray_DOUBLE, 1,1); if (b == NULL) goto fail; lenb = b->dimensions[0]; id1 = (PyArrayObject *)PyArray_ContiguousFromObject(id1in, PyArray_LONG, 1,1); if (id1 == NULL) goto fail; id2 = (PyArrayObject *)PyArray_ContiguousFromObject(id2in, PyArray_LONG, 1,1); if (id2 == NULL) goto fail; if (lenb < 0 ) { PyErr_SetString(PyExc_IndexError, "Vector b has a negative size"); goto fail; } if (id1->dimensions[0] != lenb ) { PyErr_SetString(PyExc_IndexError, "id1 does not have the same size as b"); goto fail; } if (id2->dimensions[0] != lenb ) { PyErr_SetString(PyExc_IndexError, "id2 does not have the same size as b"); goto fail; } /* Perform update add operation */ for (i = 0; i < lenb; i ++) { v = ((double *)b->data)[i]; err = SpMatrix_LLMatUpdateItemAdd(self, ((long *)id1->data)[i], ((long *)id2->data)[i], v); if( err == -1 ) goto fail; } Py_XDECREF(b); Py_XDECREF(id1); Py_XDECREF(id2); Py_INCREF(Py_None); return Py_None; fail: if(b) Py_XDECREF(b); if(id1) Py_XDECREF(id1); if(id2) Py_XDECREF(id2); return NULL; } static char LLMat_norm_doc[] = "return p-norm of matrix\n\ \n\ A.norm(p) returns the p-norm of matrix A\n\ \n\ p is a string identifying the type of norm to be returned\n\ \n\ '1' -- return the 1-norm of A\n\ 'inf' -- return the infinity norm of A\n\ 'fro' -- return the frobenius norm of A"; static PyObject * LLMat_norm(LLMatObject *self, PyObject *args) { char *normType; struct llColIndex *colIdx; double norm, s, v; int i, k; if (!PyArg_ParseTuple(args, "s", &normType)) return NULL; if (strcmp(normType, "1") == 0) { /* l1 norm */ if (self->issym) { PyErr_SetString(PyExc_NotImplementedError, "Not implemented for symmetric matrices"); return NULL; } else { if (SpMatrix_LLMatBuildColIndex(&colIdx, self, 1)) return NULL; for( norm = 0.0, i = 0; i < self->dim[1]; i++ ) { for( s = 0.0, k = colIdx->root[i]; k != -1; k = colIdx->link[k] ) s += fabs(self->val[k]); norm = s > norm ? s : norm; } SpMatrix_LLMatDestroyColIndex(&colIdx); } } else if (strcmp(normType, "inf") == 0) { /* infinity norm */ if (self->issym) { PyErr_SetString(PyExc_NotImplementedError, "Not implemented for symmetric matrices"); return NULL; } else { for( norm = 0.0, i = 0; i < self->dim[0]; i++ ) { for( s = 0.0, k = self->root[i]; k != -1; k = self->link[k] ) s += fabs(self->val[k]); norm = s > norm ? s : norm; } } } else if (strcmp(normType, "fro") == 0) { /* Frobenius norm */ for( norm = 0.0, i = 0; i < self->dim[0]; i++ ) for (k = self->root[i]; k != -1; k = self->link[k]) { v = self->val[k]; norm += v*v; if (self->issym && self->col[k] != i) norm += v*v; } norm = sqrt(norm); } else { PyErr_SetString(PyExc_ValueError, "unknown norm type"); return NULL; } return Py_BuildValue("d", norm); } static char shift_doc[] = "A.shift(sigma, B)\n\ \n\ shift the matrix:\n\ compute A = A + sigma * B\n\ where sigma is a scalar and B is a matrix of compatible size."; static PyObject * LLMat_shift(LLMatObject *self, PyObject *args) { LLMatObject *mat; double sigma, v; int i, j, k, err; if (!PyArg_ParseTuple(args, "dO!", &sigma, &LLMatType, &mat)) return NULL; if (self->dim[0] != mat->dim[0] || self->dim[1] != mat->dim[1]) { PyErr_SetString(PyExc_ValueError, "matrix shapes do not match"); return NULL; } if (self->issym == mat->issym) { for (i = 0; i < mat->dim[0]; i ++) { k = mat->root[i]; while (k != -1) { err = SpMatrix_LLMatUpdateItemAdd(self, i, mat->col[k], sigma * mat->val[k]); if( err == -1 ) return NULL; k = mat->link[k]; } } } else if (mat->issym) { for (i = 0; i < mat->dim[0]; i ++) { k = mat->root[i]; while (k != -1) { j = mat->col[k]; v = sigma * mat->val[k]; if (SpMatrix_LLMatUpdateItemAdd(self, i, j, v) == -1) return NULL; if (i != j) if (SpMatrix_LLMatUpdateItemAdd(self, j, i, v) == -1) return NULL; k = mat->link[k]; } } } else { PyErr_SetString(PyExc_NotImplementedError, "Cannot shift symmetric matrix by non-symmetric matrix."); return NULL; } Py_INCREF(Py_None); return Py_None; } static char keys_doc[] = "A.keys()\n\ \n\ Return a list of tuples (i,j) of non-zero matrix entries."; /* static PyObject * */ /* LLMat_keys(LLMatObject *a, PyObject *args) { */ /* PyObject *list; /\* the list that will hold the keys *\/ */ /* int i, j, k; */ /* int pos = 0; /\* position in list *\/ */ /* if (!PyArg_ParseTuple(args, "")) return NULL; */ /* if (!a->issym) { */ /* if ((list = PyList_New(a->nnz)) == NULL) return NULL; */ /* for (i = 0; i < a->dim[0]; i ++) { */ /* k = a->root[i]; */ /* while (k != -1) { */ /* j = a->col[k]; */ /* PyList_SET_ITEM(list, pos++, Py_BuildValue("ii", i, j)); */ /* k = a->link[k]; */ /* } */ /* } */ /* return list; */ /* } else { */ /* PyErr_SetString(PyExc_NotImplementedError, */ /* "keys() doesn't yet support symmetric matrices"); */ /* return NULL; */ /* } */ /* } */ static PyObject * LLMat_keys(LLMatObject *a, PyObject *args) { PyObject *listi; /* the list that will hold keys i */ PyObject *listj; /* the list that will hold keys j */ PyObject *list; /* the list that will hold the keys */ int i, j, k; int pos = 0; /* position in list */ if (!PyArg_ParseTuple(args, "")) return NULL; if (!a->issym) { // printf("nnz is %i\n", a->nnz); if ((list = PyList_New(2)) == NULL) return NULL; if ((listi = PyList_New(a->nnz)) == NULL) return NULL; if ((listj = PyList_New(a->nnz)) == NULL) return NULL; for (i = 0; i < a->dim[0]; i ++) { k = a->root[i]; while (k != -1) { j = a->col[k]; PyList_SET_ITEM(listi, pos, PyInt_FromLong(i)); PyList_SET_ITEM(listj, pos, PyInt_FromLong(j)); pos++; k = a->link[k]; } } PyList_SET_ITEM(list, 0, listi); PyList_SET_ITEM(list, 1, listj); return list; } else { PyErr_SetString(PyExc_NotImplementedError, "keys() doesn't yet support symmetric matrices"); return NULL; } } static char values_doc[] = "A.values()\n\ \n\ Return a list of the non-zero matrix entries as floats."; static PyObject * LLMat_values(LLMatObject *a, PyObject *args) { PyObject *list; /* the list that will hold the values */ int i, k; int pos = 0; /* position in list */ if (!PyArg_ParseTuple(args, "")) return NULL; if (!a->issym) { if ((list = PyList_New(a->nnz)) == NULL) return NULL; for (i = 0; i < a->dim[0]; i ++) { k = a->root[i]; while (k != -1) { PyList_SET_ITEM(list, pos++, PyFloat_FromDouble(a->val[k])); k = a->link[k]; } } return list; } else { PyErr_SetString(PyExc_NotImplementedError, "values() doesn't yet support symmetric matrices"); return NULL; } } static char items_doc[] = "A.items()\n\ \n\ Return a list of tuples (indices, value) of\n\ the non-zero matrix entries' keys and values.\n\ \n\ The indices are themselves tuples (i,j) of row\n\ and column values."; static PyObject * LLMat_items(LLMatObject *a, PyObject *args) { PyObject *list; /* the list that will hold the values */ int i, j, k; int pos = 0; /* position in list */ double val; if (!PyArg_ParseTuple(args, "")) return NULL; if ((list = PyList_New(a->nnz)) == NULL) return NULL; for (i = 0; i < a->dim[0]; i ++) { for( k=a->root[i]; k != -1; k=a->link[k] ) { j = a->col[k]; val = a->val[k]; PyList_SET_ITEM(list, pos++, Py_BuildValue("((ii)d)", i, j, val)); } } return list; } static char scale_doc[] = "A.scale(sigma)\n\ \n\ Scale each element in the matrix by the constant sigma.\n"; static PyObject * LLMat_scale(LLMatObject *self, PyObject *args) { double sigma; int i, k; if (!PyArg_ParseTuple(args, "d", &sigma)) return NULL; for (i = 0; i < self->dim[0]; i++) for( k=self->root[i]; k != -1; k=self->link[k] ) self->val[k] *= sigma; Py_INCREF(Py_None); return Py_None; } static char update_add_mask_doc[] = \ "A.update_add_mask(b, ind0, ind1, mask0, mask1)\n\ \n\ Update of global FEM matrix. Equivalent to:\n\ \n\ for i in range(len(ind0)):\n\ for j in range(len(ind1)):\n\ if mask0[i] and mask1[j]:\n\ a[ind0[i],ind1[j]] += b[i,j]"; static PyObject * LLMat_update_add_mask(LLMatObject *self, PyObject *args) { PyObject *bIn, *ind0In, *ind1In, *mask0In, *mask1In; PyArrayObject *b, *ind0, *ind1, *mask0, *mask1; double v; int len0, len1, i, j, i1, j1, ldb; if (self->issym) { PyErr_SetString(SpMatrix_ErrorObject, "Method not allowed for symmetric matrices"); return NULL; } if (!PyArg_ParseTuple(args, "OOOOO", &bIn, &ind0In, &ind1In, &mask0In, &mask1In)) return NULL; b = (PyArrayObject *)PyArray_ContiguousFromObject(bIn, PyArray_DOUBLE, 2, 2); ind0 = (PyArrayObject *)PyArray_ContiguousFromObject(ind0In,PyArray_LONG,1,1); ind1 = (PyArrayObject *)PyArray_ContiguousFromObject(ind1In,PyArray_LONG,1,1); mask0 = (PyArrayObject *)PyArray_ContiguousFromObject(mask0In, PyArray_LONG, 1, 1); mask1 = (PyArrayObject *)PyArray_ContiguousFromObject(mask1In, PyArray_LONG, 1, 1); if (b==NULL || ind0==NULL || ind1==NULL || mask0==NULL || mask1==NULL) goto fail; len0 = ind0->dimensions[0]; len1 = ind1->dimensions[0]; /* validate array shapes */ if (mask0->dimensions[0] != len0 || mask1->dimensions[0] != len1) { PyErr_SetString(PyExc_ValueError, "Shapes of index and mask array do not match"); goto fail; } if (b->dimensions[0] != len0 || b->dimensions[1] != len1) { PyErr_SetString(PyExc_ValueError, "Shapes of input matrix and index arrays do not match"); goto fail; } /* perform update add operation */ ldb = b->dimensions[0]; for (i = 0; i < len0; i ++) { if (((long *)mask0->data)[i]) { i1 = ((long *)ind0->data)[i]; if (i1 < 0) i1 += self->dim[0]; if (i1 < 0 || i1 >= self->dim[0]) { PyErr_SetString(PyExc_IndexError, "element of arg 2 out of range"); goto fail; } for (j = 0; j < len1; j ++) { if (((long *)mask1->data)[j]) { j1 = ((long *)ind1->data)[j]; if (j1 < 0) j1 += self->dim[1]; if (j1 < 0 || j1 >= self->dim[1]) { PyErr_SetString(PyExc_IndexError, "element of arg 3 out of range"); goto fail; } v = ((double *)b->data)[i + ldb*j]; if (SpMatrix_LLMatUpdateItemAdd(self, i1, j1, v) == -1) goto fail; } } } } Py_DECREF(b); Py_DECREF(ind0); Py_DECREF(ind1); Py_DECREF(mask0); Py_DECREF(mask1); Py_INCREF(Py_None); return Py_None; fail: Py_XDECREF(b); Py_XDECREF(ind0); Py_XDECREF(ind1); Py_XDECREF(mask0); Py_XDECREF(mask1); return NULL; } static char update_add_mask_sym_doc[] = "A.update_add_mask(b, ind, mask)\n\ \n\ Symmetric update of global FEM matrix. Equivalent to:\n\ \n\ for i in range(len(ind)):\n\ for j in range(len(ind)):\n\ if mask[i] and mask[i]:\n\ i1 = ind[i]; j1 = ind[j]\n\ if i >= j:\n\ a[i1,j1] += b[i,j]\n\ \n\ Only operates on the lower triangle of A. Used for symmetric matrices."; static PyObject * LLMat_update_add_mask_sym(LLMatObject *self, PyObject *args) { PyObject *bIn, *indIn, *maskIn; PyArrayObject *b, *ind, *mask; double v; int len, i, j, i1, j1, ldb; if (!PyArg_ParseTuple(args, "OOO", &bIn, &indIn, &maskIn)) return NULL; b = (PyArrayObject *)PyArray_ContiguousFromObject(bIn, PyArray_DOUBLE, 2, 2); ind = (PyArrayObject *)PyArray_ContiguousFromObject(indIn, PyArray_LONG, 1,1); mask = (PyArrayObject *)PyArray_ContiguousFromObject(maskIn,PyArray_LONG,1,1); if (b == NULL || ind == NULL || mask == NULL) goto fail; len = ind->dimensions[0]; /* validate array shapes */ if (mask->dimensions[0] != len) { PyErr_SetString(PyExc_ValueError, "Shapes of index and mask array do not match"); goto fail; } if (b->dimensions[0] != len || b->dimensions[1] != len) { PyErr_SetString(PyExc_ValueError, "Shapes of input matrix and index arrays do not match"); goto fail; } /* perform update add operation */ ldb = b->dimensions[0]; for (i = 0; i < len; i ++) { if (((long *)mask->data)[i]) { i1 = ((long *)ind->data)[i]; if (i1 < 0) i1 += self->dim[0]; if (i1 < 0 || i1 >= self->dim[0]) { PyErr_SetString(PyExc_IndexError, "element of arg 2 out of range"); goto fail; } for (j = 0; j <= i; j ++) { if (((long *)mask->data)[j]) { j1 = ((long *)ind->data)[j]; /* index check not necessary here */ if (j1 < 0) j1 += self->dim[1]; v = ((double *)b->data)[i + ldb*j]; if (self->issym) { /* symmetric matrix: update entry in lower triangle */ if (i1 > j1) { if (SpMatrix_LLMatUpdateItemAdd(self, i1, j1, v) == -1) goto fail; } else { if (SpMatrix_LLMatUpdateItemAdd(self, j1, i1, v) == -1) goto fail; } } else { /* non-symmetric matrix: update two entries if not on diagonal */ if (SpMatrix_LLMatUpdateItemAdd(self, i1, j1, v) == -1) goto fail; if (i1 != j1) { if (SpMatrix_LLMatUpdateItemAdd(self, j1, i1, v) == -1) goto fail; } } } } } } Py_DECREF(b); Py_DECREF(ind); Py_DECREF(mask); Py_INCREF(Py_None); return Py_None; fail: Py_XDECREF(b); Py_XDECREF(ind); Py_XDECREF(mask); return NULL; } static char LLMat_take_doc[] = "A.take(b,id1,id2)\n\ \n\ for i in range(len(b)):\n\ b[i] = A[id1[i],id2[i]]"; static PyObject * LLMat_take(LLMatObject *self, PyObject *args) { PyObject *bIn; PyObject *id1in = NULL; PyObject *id2in = NULL; PyArrayObject *b; PyArrayObject *id1 = NULL; PyArrayObject *id2 = NULL; int lenb,i; if (!PyArg_ParseTuple(args, "O|OO", &bIn,&id1in,&id2in)) return NULL; b = (PyArrayObject *)PyArray_ContiguousFromObject(bIn, PyArray_DOUBLE, 1, 1); if (b == NULL) goto fail; lenb = b->dimensions[0]; if (id1in) { id1 = (PyArrayObject *)PyArray_ContiguousFromObject(id1in,PyArray_LONG,1,1); if (id1 == NULL) goto fail; } if (id2in) { id2 = (PyArrayObject *)PyArray_ContiguousFromObject(id2in,PyArray_LONG,1,1); if (id2 == NULL) goto fail; } if (lenb < 0 ) { PyErr_SetString(PyExc_IndexError, "vector b has a negative size"); goto fail; } if (id1 && id1->dimensions[0] != lenb ) { PyErr_SetString(PyExc_IndexError, "id1 does not have the same size as b"); goto fail; } if (id2 && id2->dimensions[0] != lenb ) { PyErr_SetString(PyExc_IndexError, "id2 does not have the same size as b"); goto fail; } if (id1 != id2 && self->issym) { PyErr_SetString(SpMatrix_ErrorObject, "Symmetric matrices require identical sets of indices"); goto fail; } /* Perform take operation */ for( i = 0; i < lenb; i++ ) { int i1, j1; if( id1 ) i1 = ((long *) id1->data)[i]; else i1 = i; if( id2 ) j1 = ((long *) id2->data)[i]; else j1 = i1; if( i1 > j1 || !self->issym ) /* Get entries as given */ ((double *)b->data)[i] = SpMatrix_LLMatGetItem(self, i1, j1); else /* Symmetric matrix: get entries from lower triangle */ ((double *)b->data)[i] = SpMatrix_LLMatGetItem(self, j1, i1); } Py_DECREF(b); if (id1) { Py_DECREF(id1); } if (id2) { Py_DECREF(id2); } Py_INCREF(Py_None); return Py_None; fail: Py_XDECREF(b); if (id1) { Py_XDECREF(id1); } if (id2) { Py_XDECREF(id2); } return NULL; } static char LLMat_put_doc[] = "a.put(b,id1,id2)\n\ \n\ for i in range(len(b)):\n\ a[id1[i],id2[i]] = b[i]\n\n\ If b is a scalar, it has the same effect as the list [b, b, ..., b]\n\ If id1 and/or id2 is omitted, it is considered to be [1, 2, 3, ...].\n"; static PyObject * LLMat_put(LLMatObject *self, PyObject *args) { // For simplicity, we use iterators to parse Numpy arrays. We could gain in // efficiency by checking whether the array is contiguous or not. If it is, // a simple loop over the elements will be faster than the iterator. PyObject *bIn, *ind; PyObject *id1in = NULL; PyObject *id2in = NULL; //PyArrayObject *b = NULL; //PyArrayObject *id1 = NULL; //PyArrayObject *id2 = NULL; long lenb = 0, lenid1 = 0, lenid2 = 0, i; char b_is_scalar = 0, b_is_list = 0, id1_is_list = 0, id2_is_list = 0; double bval = 0.0; PyObject *iterator0 = NULL, *iterator1 = NULL, *iterator2 = NULL; if (!PyArg_ParseTuple(args, "O|OO", &bIn,&id1in,&id2in)) return NULL; // Determine nature of value array b if( PyInt_Check(bIn) ) { // b is an integer //printf("put: b is an Int\n"); bval = (double)PyInt_AsLong(bIn); if( PyErr_Occurred() ) { PyErr_SetString(PyExc_TypeError, "Could not convert int to double"); goto fail; } b_is_scalar = 1; lenb = 1; } else if( PyLong_Check(bIn) ) { // b in a long int bval = PyLong_AsDouble(bIn); b_is_scalar = 1; lenb = 1; } else if( PyFloat_Check(bIn) ) { // b is a float //printf("put: b is a Float\n"); bval = PyFloat_AsDouble(bIn); b_is_scalar = 1; lenb = 1; } else if( PyList_Check(bIn) ) { // b is a list //printf("put: b is a list\n"); lenb = (long)PyList_Size(bIn); b_is_list = 1; } else if( PyArray_Check(bIn) ) { // b is an array //printf("put: b is an array\n"); if( !PyArray_ISINTEGER(bIn) && !PyArray_ISFLOAT(bIn) ) { PyErr_SetString(PyExc_TypeError, "Value array must be Int, Long or Float"); goto fail; } iterator0 = PyArray_IterNew(bIn); lenb = (long)PyArray_DIM(bIn, 0); PyArray_ITER_RESET(iterator0); } else { PyErr_SetString(PyExc_TypeError, "Values must be Int, Long, Float, list or Numpy array"); goto fail; } if (lenb < 0 ) { PyErr_SetString(PyExc_IndexError, "vector b has a negative size"); goto fail; } // Determine nature of first index, if given if (id1in) { if( PyList_Check(id1in) ) { // id1 is a list //printf("put: id1in is a list\n"); lenid1 = (long)PyList_Size(id1in); id1_is_list = 1; } else if( PyArray_Check(id1in) ) { // id1 is a Numpy array //printf("put: id1in is an array\n"); iterator1 = PyArray_IterNew(id1in); // id1 may not be contiguous lenid1 = (long)PyArray_DIM(id1in, 0); PyArray_ITER_RESET(iterator1); } else { PyErr_SetString(PyExc_TypeError, "First index must be list or Numpy array"); goto fail; } if( !b_is_scalar ) if( lenid1 != lenb ) { PyErr_SetString(PyExc_IndexError, "Not as many row indices as values"); goto fail; } if( b_is_scalar ) lenb = lenid1; } // Determine nature of second index, if given if( id2in ) { if( PyList_Check(id2in) ) { // id2 is a list //printf("put: id2in is a list\n"); lenid2 = (long)PyList_Size(id2in); id2_is_list = 1; } else if( PyArray_Check(id2in) ) { // id2 is a Numpy array //printf("put: id2in is an array\n"); iterator2 = PyArray_IterNew(id2in); // id2 may not be contiguous lenid2 = (long)PyArray_DIM(id2in, 0); PyArray_ITER_RESET(iterator2); } else { PyErr_SetString(PyExc_TypeError, "Second index must be list or Numpy array"); goto fail; } if( !b_is_scalar ) { if( lenid2 != lenb ) { PyErr_SetString(PyExc_IndexError, "Not as many column indices as values"); goto fail; } } if( id1in ) { if( lenid1 != lenid2 ) { PyErr_SetString(PyExc_IndexError, "Not as many row indices as column indices"); goto fail; } } if( b_is_scalar ) lenb = lenid2; } // Perform put operation for( i = 0; i < lenb; i++ ) { long i1, j1; i1 = i; if( id1in ) { if( id1_is_list ) { ind = PyList_GetItem(id1in, (Py_ssize_t)i); if( PyInt_Check(ind) ) i1 = PyInt_AS_LONG(ind); else { PyErr_SetString(PyExc_ValueError, "Invalid list item"); return NULL; } } else { i1 = *(long*)PyArray_ITER_DATA(iterator1); PyArray_ITER_NEXT(iterator1); } } j1 = i1; if( id2in ) { if( id2_is_list ) { ind = PyList_GetItem(id2in, (Py_ssize_t)i); if( PyInt_Check(ind) ) j1 = PyInt_AS_LONG(ind); else { PyErr_SetString(PyExc_ValueError, "Invalid list item"); return NULL; } } else { j1 = *(long*)PyArray_ITER_DATA(iterator2); PyArray_ITER_NEXT(iterator2); } } if( !b_is_scalar ) { if( b_is_list ) { ind = PyList_GetItem(bIn, (Py_ssize_t)i); if( PyInt_Check(ind) ) bval = (double)PyInt_AS_LONG(ind); else if( PyFloat_Check(ind) ) bval = PyFloat_AsDouble(ind); else { PyErr_SetString(PyExc_ValueError, "Invalid list item"); return NULL; } } else { // Convert value to double appropriately if( PyArray_ISINTEGER(bIn) ) bval = (double)(*(long*)(PyArray_ITER_DATA(iterator0))); else // float bval = *(double*)(PyArray_ITER_DATA(iterator0)); PyArray_ITER_NEXT(iterator0); } } //printf(" %g --> (%ld,%ld)\n", bval, i1, j1); if (i1 > j1 || !self->issym) { /* Update entries as given */ //printf("mat[%d,%d] <- %g\n", i1, j1, bval); if( SpMatrix_LLMatSetItem(self, i1, j1, bval) == -1 ) goto fail; } else { /* Symmetric matrix: update entries in lower triangle */ if( SpMatrix_LLMatSetItem(self, j1, i1, bval) == -1 ) goto fail; } } /* if( !b_is_scalar ) { Py_DECREF(b); } if (id1) { Py_DECREF(id1); } if (id2) { Py_DECREF(id2); } */ Py_XDECREF(iterator0); Py_XDECREF(iterator1); Py_XDECREF(iterator2); Py_INCREF(Py_None); return Py_None; fail: /* if( !b_is_scalar ) { Py_XDECREF(b); } if (id1) { Py_XDECREF(id1); } if (id2) { Py_XDECREF(id2); } */ Py_XDECREF(iterator0); Py_XDECREF(iterator1); Py_XDECREF(iterator2); return NULL; } static char LLMat_delete_rows_doc[] = "Delete rows from matrix (inplace). The rows to be deleted are specified by the mask array.\n\ \n\ Arguments:\n\ \n\ mask: A 1D integer NumPy array. If mask[i] == 0, then row i is deleted,\n\ otherwise row i is kept.\n\ \n\ This method may not be applied to a matrix in symmetric format."; static PyObject* LLMat_delete_rows(LLMatObject *self, PyObject* args){ PyArrayObject *maskObj; int newm, newnnz; int act, row; if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &maskObj)) return NULL; if (maskObj->nd != 1 || maskObj->descr->type_num != PyArray_LONG || maskObj->dimensions[0] != self->dim[0]) { PyErr_SetString(PyExc_ValueError, "mask must be a 1D integer NumPy array of appropriate length"); return NULL; } if (self->issym) { PyErr_SetString(SpMatrix_ErrorObject, "method not allowed for symmetric matrices"); return NULL; } /* Delete the rows to be cancelled by rearranging the row */ /* array. After having done so, newdim is the new matrix dim. */ newm = 0; newnnz = self->nnz; for(row = 0; row < self->dim[0]; row ++){ if (*(int *)(maskObj->data + row*maskObj->strides[0]) != 0){ /* This row has to be kept */ self->root[newm] = self->root[row]; newm ++; } else { /* row let out; update free list */ act = self->root[row]; if(act != -1){ /* only do smth. for non-empty rows */ newnnz --; while(self->link[act] != -1) { /* Walk to the end of the list */ act = self->link[act]; newnnz --; } self->link[act] = self->free; /* Attach end of row to free list */ self->free = self->root[row]; /* Start free list where row began */ } } } /* Set the new values */ self->dim[0] = newm; self->nnz = newnnz; Py_INCREF(Py_None); return Py_None; } static char LLMat_delete_cols_doc[] = "Delete columns from matrix (inplace). The columns to be deleted are\n\ specified by the mask array.\n\ \n\ Arguments:\n\ \n\ mask: A 1D integer NumPy array. If mask[i] == 0, then column i is deleted,\n\ otherwise column i is kept."; static PyObject* LLMat_delete_cols(LLMatObject *self, PyObject* args){ PyArrayObject *maskObj; int newn, newnnz; int act, old, col, row; int *shift; if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &maskObj)) return NULL; if (maskObj->nd != 1 || maskObj->descr->type_num != PyArray_LONG || maskObj->dimensions[0] != self->dim[1]) { PyErr_SetString(PyExc_ValueError, "mask must be a 1D integer NumPy array of appropriate length"); return NULL; } if (self->issym) { PyErr_SetString(SpMatrix_ErrorObject, "method not allowed for symmetric matrices"); return NULL; } #define MASK(i) *(long *)(maskObj->data + (i)*maskObj->strides[0]) /* Allocate column shift vector (after deletion col[i] is at */ /* col[i] - shift[i]). */ shift = (int*)malloc((self->dim[1])*sizeof(int)); newn = self->dim[1]; if (MASK(0)) shift[0] = 0; else {shift[0] = 1; newn --;} for (col = 1; col < self->dim[1]; col++){ if (MASK(col)) shift[col] = shift[col-1]; else {shift[col] = shift[col-1]+1; newn --; } } /* Deleteting columns in the remainig rows */ newnnz = self->nnz; for(row = 0; row < self->dim[0]; row ++) { old = -1; act = self->root[row]; while (act != -1){ if (MASK(self->col[act])) { // Keep this column self->col[act] -= shift[self->col[act]]; old = act; act = self->link[act]; } else { // Drop the column newnnz--; if (self->root[row] == act) { // Special case: first row element self->root[row] = self->link[act]; old = act; act = self->link[act]; self->link[old] = self->free; // Append element into freelist self->free = old; } else { // Regular case: element inbetween act = self->link[act]; self->link[self->link[old]] = self->free; self->free = self->link[old]; self->link[old] = act; // Append element into freelist } } } } /* Set the new values */ self->dim[1] = newn; self->nnz = newnnz; /* clean up */ free(shift); Py_INCREF(Py_None); return Py_None; #undef MASK } static char LLMat_delete_rowcols_doc[] = "Delete rows and columns from matrix (inplace). The rows and columns to be deleted are\n\ specified by the mask array.\n\ \n\ Arguments:\n\ \n\ mask: A 1D integer NumPy array. If mask[i] == 0, then row and column i are deleted,\n\ otherwise row and column i are kept."; static PyObject* LLMat_delete_rowcols(LLMatObject *self, PyObject* args){ PyArrayObject *maskObj; int newn, newm, newnnz; int act, old, col, row; int *shift; if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &maskObj)) return NULL; if (maskObj->nd != 1 || maskObj->descr->type_num != PyArray_LONG || maskObj->dimensions[0] != self->dim[0]) { PyErr_SetString(PyExc_ValueError, "mask must be a 1D integer NumPy array of appropriate length"); return NULL; } if (self->dim[0] != self->dim[1]) { PyErr_SetString(SpMatrix_ErrorObject, "method only allowed for square matrices"); return NULL; } #define MASK(i) *(long *)(maskObj->data + (i)*maskObj->strides[0]) /* Delete the rows to be cancelled by rearranging the row */ /* array. After having done so, newdim is the new matrix dim. */ newm = 0; newnnz = self->nnz; for(row = 0; row < self->dim[0]; row ++){ if (MASK(row)){ // This row has to be kept self->root[newm] = self->root[row]; newm ++; } else { // row let out; update free list act = self->root[row]; if(act != -1){ // only do sth for non-empty rows newnnz --; while(self->link[act] != -1) { // Walk to the end of the list act = self->link[act]; newnnz --; } self->link[act] = self->free; // Attach end of row to free list self->free = self->root[row]; // Start free list where row began } } } /* Set the new values */ self->dim[0] = newm; self->nnz = newnnz; /* Allocate column shift vector (after deletion col[i] is at */ /* col[i] - shift[i]). */ shift = (int*)malloc((self->dim[1])*sizeof(int)); newn = self->dim[1]; if (MASK(0)) shift[0] = 0; else {shift[0] = 1; newn --;} for (col = 1; col < self->dim[1]; col++){ if (MASK(col)) shift[col] = shift[col-1]; else {shift[col] = shift[col-1]+1; newn --; } } /* Deleteting columns in the remainig rows */ newnnz = self->nnz; for(row = 0; row < self->dim[0]; row ++) { old = -1; act = self->root[row]; while (act != -1){ if (MASK(self->col[act])) { /* Keep this column */ self->col[act] -= shift[self->col[act]]; old = act; act = self->link[act]; } else { /* Drop the column */ newnnz--; if (self->root[row] == act) { // Special case: first row element self->root[row] = self->link[act]; old = act; act = self->link[act]; self->link[old] = self->free; // Append element into freelist self->free = old; } else { // Regular case: element inbetween act = self->link[act]; self->link[self->link[old]] = self->free; self->free = self->link[old]; self->link[old] = act; // Append element into freelist } } } } /* Set the new values */ self->dim[1] = newn; self->nnz = newnnz; /* clean up */ free(shift); Py_INCREF(Py_None); return Py_None; #undef MASK } static char LLMat_Find_Doc[] = "Get LL matrix in coord format (val,irow,jcol)."; static PyObject *LLMat_Find( LLMatObject *self, PyObject *args ) { /* Convert an LL matrix into coordinate format */ PyArrayObject *a_row, *a_col, *a_val; /* Matrix in coordinate format */ npy_intp dmat[1]; /* Dimension descriptor */ int *pi, *pj; /* Intermediate pointers to matrix data */ double *pv; int i, k, elem; dmat[0] = (npy_intp)(self->nnz); /* Allocate numarrays */ a_row = (PyArrayObject *)PyArray_SimpleNew( 1, dmat, NPY_INT32 ); a_col = (PyArrayObject *)PyArray_SimpleNew( 1, dmat, NPY_INT32 ); a_val = (PyArrayObject *)PyArray_SimpleNew( 1, dmat, NPY_FLOAT64 ); pi = (int *)a_row->data; pj = (int *)a_col->data; pv = (double *)a_val->data; elem = 0; for( i = 0; i < self->dim[0]; i++ ) { for( k = self->root[i]; k != -1; k = self->link[k] ) { pi[ elem ] = i; pj[ elem ] = self->col[k]; pv[ elem ] = self->val[k]; elem++; } } /* Descriptor 'N' does not increment reference count */ return Py_BuildValue( "NNN", PyArray_Return( a_val ), PyArray_Return( a_row ), PyArray_Return( a_col ) ); } /*********************************/ /* O b j e c t m e t h o d s */ /*********************************/ PyMethodDef LLMat_methods[] = { {"matvec", (PyCFunction)LLMat_matvec, METH_VARARGS, LLMat_matvec_doc}, {"matvec_transp", (PyCFunction)LLMat_matvec_transp, METH_VARARGS, LLMat_matvec_transp_doc}, {"to_csr", (PyCFunction)LLMat_to_csr, METH_VARARGS, to_csr_doc}, {"to_sss", (PyCFunction)LLMat_to_sss, METH_VARARGS, to_sss_doc}, {"generalize", (PyCFunction)LLMat_generalize, METH_VARARGS, LLMat_generalize_doc}, {"compress", (PyCFunction)LLMat_compress, METH_VARARGS, LLMat_compress_doc}, {"export_mtx", (PyCFunction)LLMat_export_mtx, METH_VARARGS, export_mtx_doc}, {"copy", (PyCFunction)LLMat_copy, METH_VARARGS, copy_doc}, {"norm", (PyCFunction)LLMat_norm, METH_VARARGS, LLMat_norm_doc}, {"shift", (PyCFunction)LLMat_shift, METH_VARARGS, shift_doc}, {"scale", (PyCFunction)LLMat_scale, METH_VARARGS, scale_doc}, {"keys", (PyCFunction)LLMat_keys, METH_VARARGS, keys_doc}, {"values", (PyCFunction)LLMat_values, METH_VARARGS, values_doc}, {"items", (PyCFunction)LLMat_items, METH_VARARGS, items_doc}, {"put", (PyCFunction)LLMat_put, METH_VARARGS, LLMat_put_doc}, {"take", (PyCFunction)LLMat_take, METH_VARARGS, LLMat_take_doc}, { "find", (PyCFunction)LLMat_Find, METH_VARARGS, LLMat_Find_Doc }, {"update_add_mask", (PyCFunction)LLMat_update_add_mask, METH_VARARGS, update_add_mask_doc}, {"update_add_mask_sym", (PyCFunction)LLMat_update_add_mask_sym, METH_VARARGS, update_add_mask_sym_doc}, {"delete_rows", (PyCFunction)LLMat_delete_rows, METH_VARARGS, LLMat_delete_rows_doc}, {"delete_cols", (PyCFunction)LLMat_delete_cols, METH_VARARGS, LLMat_delete_cols_doc}, {"delete_rowcols", (PyCFunction)LLMat_delete_rowcols, METH_VARARGS, LLMat_delete_rowcols_doc}, {"update_add_at", (PyCFunction)LLMat_update_add_at, METH_VARARGS, update_add_at_doc}, {NULL, NULL} /* sentinel */ }; /*****************************************/ /* L L M a t t y p e m e t h o d s */ /*****************************************/ static void LLMatType_dealloc(LLMatObject *a) { PyMem_DEL(a->root); PyMem_DEL(a->val); PyMem_DEL(a->col); PyMem_DEL(a->link); PyObject_Del(a); } static int LLMatType_print(LLMatObject *a, FILE *fp, int flags) { int i, k, first = 1; char *symStr; if (a->issym) symStr = "symmetric"; else symStr = "general"; if (a->dim[1] <= PPRINT_COL_THRESH && a->dim[0] <= PPRINT_ROW_THRESH) { double *mat; int j; double val; mat = (double *)malloc(a->dim[0]*a->dim[1] * sizeof(double)); if (mat == NULL) { PyErr_NoMemory(); return -1; } fprintf(fp, "ll_mat(%s, [%d,%d]):\n", symStr, a->dim[0], a->dim[1]); for (i = 0; i < a->dim[0]; i ++) { for (j = 0; j < a->dim[1]; j ++) mat[i*a->dim[1] + j] = 0.0; k = a->root[i]; while (k != -1) { mat[(i*a->dim[1])+a->col[k]] = a->val[k]; k = a->link[k]; } } for (i = 0; i < a->dim[0]; i ++) { for (j = 0; j < a->dim[1]; j ++) { val = mat[(i*a->dim[1])+j]; if (val != 0.0) { int exp = (int)log10(fabs(val)); if (abs(exp) <= 4) { if (exp < 0) fprintf(fp, "%9.*f ", 6, val); else fprintf(fp, "%9.*f ", 6-exp, val); } else fprintf(fp, "%9.1e ", val); } else if (!(a->issym) || i > j) fprintf(fp, " -------- "); } fprintf(fp, "\n"); } free(mat); } else { if (a->nnz == 0) { fprintf(fp, "ll_mat(%s, [%d,%d])", symStr, a->dim[0], a->dim[1]); return 0; } fprintf(fp, "ll_mat(%s, [%d,%d], [", symStr, a->dim[0], a->dim[1]); for (i = 0; i < a->dim[0]; i ++) { k = a->root[i]; while (k != -1) { if (!first) fprintf(fp, ", "); first = 0; fprintf(fp, "(%d,%d): %g", i, a->col[k], a->val[k]); k = a->link[k]; } } fprintf(fp, "])"); } return 0; } static PyObject * LLMatType_getattr(LLMatObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->dim[0], self->dim[1]); if (strcmp(name, "nnz") == 0) return PyInt_FromLong(self->nnz); if (strcmp(name, "issym") == 0) return PyInt_FromLong(self->issym); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape", "nnz", "issym"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(LLMat_methods, (PyObject *)self, name); } /*********************************************************************** * mapping functions */ /** LLMat_length - number of items in mapping * == number of matrix entries */ static int LLMat_length(LLMatObject *self) { return self->dim[0] * self->dim[1]; } /** LLMat_subscript * Called when treating array object like a mapping. This is used to * implement two-dimensional idices, e.g. A[i,j] or A[i1:i2:i3,j1:j2] */ static PyObject *LLMat_subscript(LLMatObject *self, PyObject *index) { PyObject *index0, *index1; // Check that input is a double index if( !PySequence_Check(index) ) { PyErr_SetString(PyExc_IndexError, "Index must be a sequence"); return NULL; } if( PySequence_Length(index) != 2 ) { PyErr_SetString(PyExc_IndexError, "There must be exactly two indices"); return NULL; } // Parse first index if( !(index0 = PySequence_GetItem(index, 0)) ) { PyErr_SetString(PyExc_IndexError, "First index is invalid"); return NULL; } // Parse second index if( !(index1 = PySequence_GetItem(index, 1)) ) { PyErr_SetString(PyExc_IndexError, "Second index is invalid"); return NULL; } // Return submatrix return getSubMatrix_FromList(self, index0, index1); } /** LLMat_ass_subscript * Called when treating array object like a mapping. This is used * implement two-dimensional indices, e.g. A[::2,1:5] */ static int LLMat_ass_subscript(LLMatObject *self, PyObject *index, PyObject *value ) { PyObject *index0, *index1; // Check that input is a double index if( !PySequence_Check(index) ) { PyErr_SetString(PyExc_IndexError, "Index must be a sequence"); return -1; } if( PySequence_Length(index) != 2 ) { PyErr_SetString(PyExc_IndexError, "There must be exactly two indices"); return -1; } // Parse first index if( !(index0 = PySequence_GetItem(index, 0)) ) { PyErr_SetString(PyExc_IndexError, "First index is invalid"); return -1; } // Parse second index if( !(index1 = PySequence_GetItem(index, 1)) ) { PyErr_SetString(PyExc_IndexError, "Second index is invalid"); return -1; } // Assign a submatrix //return setSubMatrix_FromList(self, value, index0, index1); setSubMatrix_FromList(self, value, index0, index1); if( PyErr_Occurred() ) return -1; return 0; } static PyMappingMethods LLMat_as_mapping = { #ifdef LENFUNC_OK (lenfunc)LLMat_length, /*mp_length*/ #else (inquiry)LLMat_length, /*mp_length*/ #endif (binaryfunc)LLMat_subscript, /*mp_subscript*/ (objobjargproc)LLMat_ass_subscript, /*mp_ass_subscript*/ }; /*************************************/ /* L L M a t T y p e o b j e c t */ /*************************************/ static PyTypeObject LLMatType = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "ll_mat", /* tp_name */ sizeof(LLMatObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)LLMatType_dealloc, /* tp_dealloc */ (printfunc)LLMatType_print, /* tp_print */ (getattrfunc)LLMatType_getattr, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ &LLMat_as_mapping, /* 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, /* tp_flags */ "LLMat objects", /* tp_doc */ }; /*************************************************/ /* M i s c . h e l p e r f u n c t i o n s */ /*************************************************/ static PyObject * SpMatrix_NewLLMatObject(int dim[], int sym, int sizeHint) { int i; LLMatObject *op; if (dim[0] < 0 || dim[1] < 0) { PyErr_SetString(PyExc_ValueError, "matrix dimension must be non-negative"); return NULL; } if (sizeHint < 1) sizeHint = 1; /* create new SparseArrayt object */ op = PyObject_New(LLMatObject, &LLMatType); if (op == NULL) return PyErr_NoMemory(); op->root = NULL; op->val = NULL; op->col = NULL; op->link = NULL; /* allocate ob_val and on_idx arrays */ op->root = PyMem_New(int, dim[0]); if (op->root == NULL) goto fail; op->val = PyMem_New(double, sizeHint); if (op->val == NULL) goto fail; op->col = PyMem_New(int, sizeHint); if (op->col == NULL) goto fail; op->link = PyMem_New(int, sizeHint); if (op->link == NULL) goto fail; /* initialize rest of fields */ for (i = 0; i < dim[0]; i ++) op->root[i] = -1; op->dim[0] = dim[0]; op->dim[1] = dim[1]; op->issym = sym; op->nnz = 0; op->nalloc = sizeHint; op->free = -1; return (PyObject *) op; fail: PyMem_Del(op->link); PyMem_Del(op->col); PyMem_Del(op->val); PyMem_Del(op->root); PyObject_Del(op); return PyErr_NoMemory(); } static PyObject* LLMat_from_mtx(PyObject *module, PyObject *args) { LLMatObject *self = NULL; char *fileName; MM_typecode matcode; int dim[2], nz; FILE *f; int ret, i; double val; int row, col; if (!PyArg_ParseTuple(args, "s", &fileName)) return NULL; /* open file */ f = fopen(fileName, "r"); if (f == NULL) return PyErr_SetFromErrno(PyExc_IOError); /* read MTX header */ ret = mm_read_banner(f, matcode); if (ret != 0) { PyErr_SetString(PyExc_IOError, "error reading MTX file header"); goto fail; } if (!(mm_is_real(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))) { PyErr_SetString(SpMatrix_ErrorObject, "must be real, sparse matrix"); goto fail; } ret = mm_read_mtx_crd_size(f, dim, dim+1, &nz); if (ret != 0) { PyErr_SetString(PyExc_IOError, "error reading MTX file size information"); goto fail; } /* allocate matrix object */ self = (LLMatObject *)SpMatrix_NewLLMatObject(dim, mm_is_symmetric(matcode), nz); if (self == NULL) goto fail; for (i = 0; i < nz; i ++) { ret = fscanf(f, "%d %d %lg\n", &row, &col, &val); if (ret != 3) { PyErr_SetString(PyExc_IOError, "error reading MTX file data"); goto fail; } row --; col --; if (!(0 <= row && row < dim[0] && 0 <= col && col < dim[1])) { PyErr_SetString(PyExc_IndexError, //SpMatrix_ErrorObject, "matrix indices out of range"); fclose(f); return NULL; } ret = SpMatrix_LLMatSetItem(self, row, col, val); if (ret) goto fail; } fclose(f); return (PyObject *)self; fail: fclose(f); Py_XDECREF(self); return NULL; } char LLMat_matrixmultiply_doc[] = "matrixmultiply(A, B)\n\ \n\ Returns a new ll_mat object representing the matrix A*B"; static PyObject * LLMat_matrixmultiply(PyObject *self, PyObject *args) { int sizeHint = 1000; LLMatObject *matA, *matB, *matC; int dimC[2]; int symCode, ret; if (!PyArg_ParseTuple(args, "O!O!", &LLMatType, &matA, &LLMatType, &matB)) return NULL; /* matrix dimensions */ dimC[0] = matA->dim[0]; dimC[1] = matB->dim[1]; if (matA->dim[1] != matB->dim[0]) { PyErr_SetString(PyExc_ValueError, "matrix dimensions must agree"); return NULL; } /* create result object */ matC = (LLMatObject *)SpMatrix_NewLLMatObject(dimC, 0, sizeHint); if (matC == NULL) return NULL; symCode = matB->issym << 1 | matA->issym; if (symCode == 0) { /* unsym-unsym multiplication */ #if !OPT_MATMATMUL double valA; int iA, jA, kA, kB; for (iA = 0; iA < matA->dim[0]; iA ++) { kA = matA->root[iA]; while (kA != -1) { valA = matA->val[kA]; jA = matA->col[kA]; kA = matA->link[kA]; /* add jA-th row of B to iA-th row of C */ kB = matB->root[jA]; while (kB != -1) { ret = SpMatrix_LLMatUpdateItemAdd(matC, iA, matB->col[kB], valA*matB->val[kB]); if (ret == -1) goto fail; kB = matB->link[kB]; } } } #else int *tmpage = NULL; int *tmpind = NULL; int *tmpcol = NULL; double *tmpval = NULL; int tmpsize; int nxttmp; int row; int indA, colA, colB, dummy, indB; double valA; tmpsize = 5; nxttmp = -1; tmpage = (int*)malloc(matB->dim[1] * sizeof(int)); tmpind = (int*)malloc(matB->dim[1] * sizeof(int)); tmpcol = (int*)malloc(tmpsize * sizeof(int)); tmpval = (double*)malloc(tmpsize * sizeof(double)); if (tmpage == NULL || tmpind == NULL || tmpcol == NULL ||tmpval == NULL) { PyErr_NoMemory(); goto fail_unsym_unsym; } /* main loop */ for(row=0; row < matB->dim[1]; row++){ tmpage[row] = -1;} /* Go through each row of A and perform necessary computations */ for(row=0; row < matA->dim[0]; row++) { indA = matA->root[row]; // Pick first entry of A[row,:] while(indA != -1){ // As long as there is an element in A[row,:] ... colA = matA->col[indA]; // ... get its column number ... valA = matA->val[indA]; // ... and value ... indB = matB->root[colA]; // colA is equivalent to rowB! while(indB != -1){ colB = matB->col[indB]; if(tmpage[colB] != row){ // This column never appeared so far nxttmp++; tmpage[colB] = row; tmpind[colB] = nxttmp; if(nxttmp >= tmpsize){ // If tmp storage too small, realloc tmpsize = (int)((tmpsize*12)/10)+1; tmpcol = (int*)realloc(tmpcol, tmpsize * sizeof(int)); tmpval = (double*)realloc(tmpval, tmpsize * sizeof(double)); if (tmpcol == NULL ||tmpval == NULL) { PyErr_NoMemory(); goto fail_unsym_unsym; } } tmpcol[nxttmp] = colB; tmpval[nxttmp] = valA * matB->val[indB]; }else{ // This column appeared at least once already dummy = tmpind[colB]; tmpval[dummy] += valA * matB->val[indB]; } indB = matB->link[indB]; } indA = matA->link[indA]; } /* All the new values for rowC = rowA have now to be filled in */ /* into the matrix C */ for(dummy=0; dummy<=nxttmp; dummy++) { if (SpMatrix_LLMatSetItem(matC,row,tmpcol[dummy],tmpval[dummy])) goto fail_unsym_unsym; } nxttmp=-1; /* For the next row of A we need a "fresh" tmp storage */ } /* Get the memory back ... */ free(tmpage); free(tmpind); free(tmpcol); free(tmpval); return (PyObject *)matC; fail_unsym_unsym: free(tmpage); free(tmpind); free(tmpcol); free(tmpval); goto fail; #endif } else if (symCode == 1) { /* sym-unsym multiplication */ double valA; int iA, jA, kA, kB; for (iA = 0; iA < matA->dim[0]; iA ++) { kA = matA->root[iA]; while (kA != -1) { valA = matA->val[kA]; jA = matA->col[kA]; kA = matA->link[kA]; /* add jA-th row of B to iA-th row of C */ kB = matB->root[jA]; while (kB != -1) { ret = SpMatrix_LLMatUpdateItemAdd(matC, iA, matB->col[kB], valA*matB->val[kB]); if (ret == -1) goto fail; kB = matB->link[kB]; } if (iA == jA) continue; /* add iA-th row of B to jA-th row of C */ kB = matB->root[iA]; while (kB != -1) { ret = SpMatrix_LLMatUpdateItemAdd(matC, jA, matB->col[kB], valA*matB->val[kB]); if (ret == -1) goto fail; kB = matB->link[kB]; } } } } else if (symCode == 2) { /* unsym-sym multiplication */ PyErr_SetString(PyExc_NotImplementedError, "multiply of an unsymmetric and a symmetric matrix not supported"); goto fail; } else { /* sym-sym multiplication */ PyErr_SetString(PyExc_NotImplementedError, "multiply of two symmetric matrices not supported"); goto fail; } return (PyObject *)matC; fail: Py_DECREF(matC); return NULL; } static char LLMat_dot_doc[] = "dot(A, B)\n\ \n\ Returns a new ll_mat object representing the matrix transpose(A)*B"; static PyObject *LLMat_dot(PyObject *self, PyObject *args) { int sizeHint = 1000; LLMatObject *matA, *matB, *matC; int dimC[2]; double valA; int iA, kA, iC, kB, ret; if (!PyArg_ParseTuple(args, "O!O!", &LLMatType, &matA, &LLMatType, &matB)) return NULL; dimC[0] = matA->dim[1]; dimC[1] = matB->dim[1]; if (matA->dim[0] != matB->dim[0]) { PyErr_SetString(PyExc_ValueError, "matrix dimensions must agree"); return NULL; } if (matA->issym || matB->issym) { PyErr_SetString(PyExc_NotImplementedError, "ddot operation with symmetric matrices not supported"); return NULL; } matC = (LLMatObject *)SpMatrix_NewLLMatObject(dimC, 0, sizeHint); if (matC == NULL) return NULL; for( iA = 0; iA < matA->dim[0]; iA++ ) { for( kA = matA->root[iA]; kA != -1; kA = matA->link[kA] ) { valA = matA->val[kA]; iC = matA->col[kA]; for( kB = matB->root[iA]; kB != -1; kB = matB->link[kB] ) { ret = SpMatrix_LLMatUpdateItemAdd(matC, iC, matB->col[kB], valA*matB->val[kB]); if (ret == -1) goto fail; } } } return (PyObject *)matC; fail: Py_DECREF(matC); return NULL; } /* For backward compatibility. This is still called by sss_mat. */ static int LLMat_parse_index(PyObject *op, int dim[], int *start0, int *stop0, int *step0, int *len0, int *start1, int *stop1, int *step1, int *len1) { PyErr_SetString(PyExc_IndexError, "Not yet transitioned to fancy indexing for SSS matrices"); return -1; } pysparse-1.1.1/Src/minres.c0000644010116400000240000001444611402270133014546 0ustar wd15dialout/************************************************************************** * * * Swiss Federal Institute of Technology (ETH), * * CH-8092 Zuerich, Switzerland * * * * (C) 1999 All Rights Reserved * * * * NOTICE * * * * Permission to use, copy, modify, and distribute this software and * * its documentation for any purpose and without fee is hereby granted * * provided that the above copyright notice appear in all copies and * * that both the copyright notice and this permission notice appear in * * supporting documentation. * * * * Neither the Swiss Federal Institute of Technology nor the author make * * any representations about the suitability of this software for any * * purpose. This software is provided ``as is'' without express or * * implied warranty. * * * *************************************************************************** * * Implementation of the MINRES iterative linear solver * * $Id: minres.c 2 2003-11-09 12:35:47Z geus $ * * **************************************************************************/ #include #include #include "Python.h" #include "pysparse/fortran.h" #include "pysparse/blas.h" #define SPMATRIX_UNIQUE_SYMBOL itsolvers_spmatrix #include "pysparse/spmatrix.h" #include "pysparse/minres.h" #define SpMatrix_PRECON(prec_obj, n, x, y) \ {if (SpMatrix_Precon((prec_obj),(n),(x),(y))) return -1;} #define SpMatrix_MATVEC(mat_obj, n, x, m, y) \ {if (SpMatrix_Matvec((mat_obj), (n), (x), (m), (y))) return -1;} int Itsolvers_minres_kernel(int n, double errtol, int it_max, int *it, double *nrm_res, int clvl, double *x, double *b, double *work, PyObject *mat_obj, PyObject *prec_obj) { int ONE = 1; double norm_r0, beta, beta_old, c, c_old, c_oold, s, s_old, s_oold, eta, norm_rmr, alpha, dconst1, dconst2, r1, r1_hat, r2, r3, tmp; int i; double *v, *v_hat, *v_hat_old, *av, *y, *w, *w_old; v_hat_old = work; v_hat = work + n; y = work + 2*n; w = work + 3*n; w_old = work + 4*n; v = work + 5*n; av = work + 6*n; *it = 0; /* v_hat_old=zeros(N,1); */ for (i = 0; i < n; i ++) v_hat_old[i] = 0.0; /* v_hat = b - A*x0; */ SpMatrix_MATVEC(mat_obj, n, x, n, v_hat); for (i = 0; i < n; i ++) v_hat[i] = b[i] - v_hat[i]; /* norm_r0=norm(v_hat); */ norm_r0 = F77(dnrm2)(&n, v_hat, &ONE); /* y = M\v_hat; */ if (prec_obj) SpMatrix_PRECON(prec_obj, n, v_hat, y) else F77(dcopy)(&n, v_hat, &ONE, y, &ONE); /* beta=sqrt(v_hat'*y); beta_old=1; */ beta = F77(ddot)(&n, v_hat, &ONE, y, &ONE); if (beta < 0.0) return -3; /* preconditioner is not SPD */ beta = sqrt(beta); beta_old = 1.0; /* c=1; c_old=1; s_old=0; s=0; */ c = 1.0; c_old = 1.0; s = 0.0; s_old = 0.0; /* w=zeros(N,1); w_old=w; eta=beta; */ for (i = 0; i < n; i ++) w[i] = 0.0; for (i = 0; i < n; i ++) w_old[i] = 0.0; eta = beta; /* xMR=x0; norm_rMR=norm_r0; */ norm_rmr = norm_r0; while (1) { if (clvl >= 1) { if (*it == 0) { printf("MINRES. Solution of symmetric Ax = b\n" "N =%7d\n" "IT_MAX =%7d R_TOL =%11.2e\n\n", n, it_max, errtol*norm_r0); printf(" ITN NORM(R)\n"); } printf(" %5d %19.10e\n", *it, norm_rmr); if (*it % 10 == 0) printf("\n"); } /* * Lanczos */ if (*it >= it_max || norm_rmr < errtol*norm_r0) break; *it = *it + 1; /* * Lanczos */ /* v=y/beta; y=v_hat; */ for (i = 0; i < n; i ++) v[i] = y[i] / beta; F77(dcopy)(&n, v_hat, &ONE, y, &ONE); /* Av = A*v */ SpMatrix_MATVEC(mat_obj, n, v, n, av); /* alpha=v'*Av; */ alpha = F77(ddot)(&n, v, &ONE, av, &ONE); /* v_hat=Av-(alpha/beta)*v_hat-(beta/beta_old)*v_hat_old; */ dconst1 = alpha/beta; dconst2 = beta/beta_old; for (i = 0; i < n; i ++) v_hat[i] = av[i] - dconst1*v_hat[i] - dconst2*v_hat_old[i]; /* v_hat_old=y; */ F77(dcopy)(&n, y, &ONE, v_hat_old, &ONE); /* y = M\v_hat; */ if (prec_obj) SpMatrix_PRECON(prec_obj, n, v_hat, y) else F77(dcopy)(&n, v_hat, &ONE, y, &ONE); /* beta_old=beta; beta=sqrt(v_hat'*y); */ beta_old=beta; beta = F77(ddot)(&n, v_hat, &ONE, y, &ONE); if (beta < 0.0) return -3; /* preconditioner is not SPD */ beta = sqrt(beta); /* * QR factorization */ c_oold = c_old; c_old = c; s_oold = s_old; s_old = s; r1_hat = c_old*alpha - c_oold*s_old*beta_old; r1 = sqrt(r1_hat*r1_hat + beta*beta); r2 = s_old*alpha + c_oold*c_old*beta_old; r3 = s_oold*beta_old; /* * Givens rotation */ if (r1 == 0.0) return -6; c = r1_hat/r1; s = beta/r1; /* * Update */ /* w_oold=w_old; w_old=w; */ /* w=(v-r3*w_oold-r2*w_old)/r1; */ /* Vector w_oold eliminated */ for (i = 0; i < n; i ++) { tmp = w[i]; w[i] = (v[i] - r3*w_old[i] - r2*tmp)/r1; w_old[i] = tmp; } /* xMR=xMR+c*eta*w; eta=-s*eta; */ dconst1 = c*eta; for (i = 0; i < n; i ++) x[i] += dconst1*w[i]; eta = -s*eta; /* * Norm * on illconditioned problems the estimate of norm_rMR may * depart from the true norm_rMR and thus cause premature * termination. * To overcome this, norm_rMR can be computed from xMR: * if isstr(A), norm_rMR = norm(b - feval(A,xMR,varargin{:})); * else norm_rMR=norm(b - A*xMR); end */ norm_rmr *= fabs(s); /* Updated norm w.r.t. preconditioned system */ } *nrm_res = norm_rmr / norm_r0; if (norm_rmr < errtol*norm_r0) return 0; else return -1; } pysparse-1.1.1/Src/mmio_patched.c0000644010116400000240000003040611402270130015671 0ustar wd15dialout/* * Matrix Market I/O library for ANSI C * * See http://math.nist.gov/MatrixMarket for details. * * */ #include #include #include #include #include "pysparse/mmio.h" int mm_read_unsymmetric_sparse(const char *fname, int *M_, int *N_, int *nz_, double **val_, int **I_, int **J_) { FILE *f; MM_typecode matcode; int M, N, nz; int i; double *val; int *I, *J; if ((f = fopen(fname, "r")) == NULL) return -1; if (mm_read_banner(f, matcode) != 0) { printf("mm_read_unsymetric: Could not process Matrix Market banner "); printf(" in file [%s]\n", fname); return -1; } if ( !(mm_is_real(matcode) && mm_is_matrix(matcode) && mm_is_sparse(matcode))) { fprintf(stderr, "Sorry, this application does not support "); fprintf(stderr, "Market Market type: [%s]\n", mm_typecode_to_str(matcode)); return -1; } /* find out size of sparse matrix: M, N, nz .... */ if (mm_read_mtx_crd_size(f, &M, &N, &nz) !=0) { fprintf(stderr, "read_unsymmetric_sparse(): could not parse matrix size.\n"); return -1; } *M_ = M; *N_ = N; *nz_ = nz; /* reseve memory for matrices */ I = (int *) malloc(nz * sizeof(int)); J = (int *) malloc(nz * sizeof(int)); val = (double *) malloc(nz * sizeof(double)); *val_ = val; *I_ = I; *J_ = J; /* NOTE: when reading in doubles, ANSI C requires the use of the "l" */ /* specifier as in "%lg", "%lf", "%le", otherwise errors will occur */ /* (ANSI C X3.159-1989, Sec. 4.9.6.2, p. 136 lines 13-15) */ for (i=0; i alpha*unrm_old); } if (i >= maxcgsit) { printf("warning: loss of orthogonality. "); printf("icgs() not converged after %d steps.\n", maxcgsit); } } /****************************************************************************** * * * ICGSM -- Iterated Classical M-orthogonal Gram-Schmidt * * * * M-orthogonalizes u against the columns of Q. * * * ******************************************************************************/ static void icgsm(double *u, double *unrm, int n, int m, double *Q, PyObject *mmat, double *um, double *temp) { const int maxcgsit = 5; const double alpha = 0.5; double unrm_old; int ret, i, isorth = 0; ret = SpMatrix_Matvec(mmat, n, u, n, um); assert(ret == 0); *unrm = sqrt(F77(ddot)(&n, u, &ONE, um, &ONE)); if (m == 0) return; for (i = 0; !isorth && i < maxcgsit; i ++) { F77(dgemv)("t", &n, &m, &DONE, Q, &n, um, &ONE, &DZER, temp, &ONE, 1); F77(dgemv)("n", &n, &m, &DMONE, Q, &n, temp, &ONE, &DONE, u, &ONE, 1); ret = SpMatrix_Matvec(mmat, n, u, n, um); assert(ret == 0); unrm_old = (*unrm); *unrm = sqrt(F77(ddot)(&n, u, &ONE, um, &ONE)); isorth=((*unrm) > alpha*unrm_old); } if (i >= maxcgsit) { printf("warning: loss of orthogonality. "); printf("icgsm() not converged after %d steps.\n", maxcgsit); } } /****************************************************************************** * * * MGS -- Modified Gram-Schmidt * * * * Orthogonlaizes v with respect to span{A[:,1:m]} * * * ******************************************************************************/ static void mgs(double *u, int n, int m, double *Q) { int i; double s; for (i = 0; i < m; i ++) { s = - F77(ddot)(&n, Q+i*n, &ONE, u, &ONE); F77(daxpy)(&n, &s, Q+i*n, &ONE, u, &ONE); } } /****************************************************************************** * * * MGSM -- Modified M-orthogonal GramSchmidt * * * * M-Orthogonalizes u against the columns of Q. * * * ******************************************************************************/ static void mgsm(double *u, int n, int m, double *Q, double *QM) { int i; double s; for (i = 0; i < m; i ++) { s = - F77(ddot)(&n, QM+i*n, &ONE, u, &ONE); F77(daxpy)(&n, &s, Q+i*n, &ONE, u, &ONE); } } pysparse-1.1.1/Src/pcg.c0000644010116400000240000001303411402270126014014 0ustar wd15dialout#include "Python.h" #include "pysparse/blas.h" #include "pysparse/fortran.h" #define SPMATRIX_UNIQUE_SYMBOL itsolvers_spmatrix #include "pysparse/spmatrix.h" #include "pysparse/pcg.h" #define SpMatrix_PRECON(prec_obj, n, x, y) \ {if (SpMatrix_Precon((prec_obj),(n),(x),(y))) return -1;} #define SpMatrix_MATVEC(mat_obj, n, x, m, y) \ {if (SpMatrix_Matvec((mat_obj), (n), (x), (m), (y))) return -1;} /* function prototypes */ static void itermsg(double tol, int maxit, int flag, int iter, double relres); /* PCG - Conjugate Gradients Algorithm */ int Itsolvers_pcg_kernel(int n, double *x, double *b, double tol, int maxit, int clvl, int *iter, double *relres, int *flag, double *work, PyObject *mat_obj, PyObject *prec_obj) { double ALPHA; /* used for passing parameters */ int ONE = 1; /* to BLAS routines */ double n2b; /* norm of rhs vector */ double tolb; /* requested tolerance for residual */ double normr; /* residual norm */ double alpha, beta; double rho, rho1; double pq; double dmax, ddum; /* used to detect stagnation */ int stag; /* flag to indicate stagnation */ int it; /* current iteration number */ int i; /* index variable */ double *r, *z, *p, *q; /* pointers to vectors in PCG algorithm */ /* setup pointers into work */ r = work; z = work + n; p = work + 2*n; q = work + 3*n; /* Check for all zero right hand side vector => all zero solution */ n2b = F77(dnrm2)(&n, b, &ONE);/* Norm of rhs vector, b */ if (n2b == 0.0) { /* if rhs vector is all zeros */ for (i = 0; i < n; i ++) /* then solution is all zeros */ x[i] = 0.0; *flag = 0; /* a valid solution has been obtained */ *relres = 0.0; /* the relative residual is actually 0/0 */ *iter = 0; /* no iterations need be performed */ if (clvl) itermsg(tol,maxit,*flag,*iter,*relres); return 0; } /* Set up for the method */ *flag = -1; tolb = tol * n2b; /* Relative tolerance */ SpMatrix_MATVEC(mat_obj, n, x, n, r); /* Zero-th residual: r = b - A * x*/ for (i = 0; i < n; i ++) /* then solution is all zeros */ r[i] = b[i] - r[i]; normr = F77(dnrm2)(&n, r, &ONE); /* Norm of residual */ if (normr <= tolb) { /* Initial guess is a good enough solution */ *flag = 0; *relres = normr / n2b; *iter = 0; if (clvl) itermsg(tol,maxit,*flag,*iter,*relres); return 0; } rho = 1.0; stag = 0; /* stagnation of the method */ /* loop over maxit iterations (unless convergence or failure) */ for (it = 1; it <= maxit; it ++) { if (prec_obj) { SpMatrix_PRECON(prec_obj, n, r, z); } else { F77(dcopy)(&n, r, &ONE, z, &ONE); } rho1 = rho; rho = F77(ddot)(&n, r, &ONE, z, &ONE); if (rho == 0.0) { /* or isinf(rho) */ *flag = -2; break; } if (it == 1) { F77(dcopy)(&n, z, &ONE, p, &ONE); } else { beta = rho / rho1; if (beta == 0.0) { /* | isinf(beta) */ *flag = -6; break; } for (i = 0; i < n; i ++) /* p = z + beta * p; */ p[i] = z[i] + beta * p[i]; } SpMatrix_MATVEC(mat_obj, n, p, n, q); /* q = A * p */ pq = F77(ddot)(&n, p, &ONE, q, &ONE); /* pq = p' * q */ if (pq == 0.0) { /* | isinf(pq) */ *flag = -6; break; } else { alpha = rho / pq; } if (alpha == 0.0) /* stagnation of the method */ stag = 1; /* Check for stagnation of the method */ if (stag == 0) { dmax = 0.0; for (i = 0; i < n; i ++) if (x[i] != 0.0) { ddum = fabs(alpha * p[i]/x[i]); if (ddum > dmax) dmax = ddum; } else if (p[i] != 0.0) dmax = 1.0; stag = (1.0 + dmax == 1.0); } F77(daxpy)(&n, &alpha, p, &ONE, x, &ONE); /* form new iterate */ ALPHA = -alpha; F77(daxpy)(&n, &ALPHA, q, &ONE, r, &ONE); /* r = r - alpha * q */ /* check for convergence */ #ifdef EXPENSIVE_CRIT SpMatrix_MATVEC(mat_obj, n, x, n, z); /* normr = norm(b - A * x) */ for (i = 0; i < n; i ++) z[i] = b[i] - z[i]; normr = F77(dnrm2)(&n, z, &ONE); #else normr = F77(dnrm2)(&n, r, &ONE); /* normr = norm(r) */ #endif if (normr <= tolb) { *flag = 0; break; } if (stag == 1) { *flag = -5; break; } } /* for it = 1 : maxit */ *iter = it; *relres = normr / n2b; if (clvl) itermsg(tol,maxit,*flag,*iter,*relres); return 0; } /* ITERMSG - Displays the final message for PCG method */ static void itermsg(double tol, int maxit, int flag, int iter, double relres) { if (flag != 0) { printf("PCG stopped at iteration %d without converging to the desired tolerance %0.2g", iter, tol); } switch(flag) { case 0: if (iter == 0) printf("The initial guess has relative residual %0.2g which is within\nthe desired tolerance %0.2g so PCG returned it without iterating.", relres, tol); else printf("PCG converged at iteration %d to a solution with relative residual %0.2g", iter, relres); break; case -1: printf("\nbecause the maximum number of iterations was reached."); break; case -2: printf("\nbecause the system involving the preconditioner was ill conditioned."); break; case -5: printf("\nbecause the method stagnated."); break; case -6: printf("\nbecause a scalar quantity became too small or too large to continue computing."); break; } if (flag != 0) printf("\nThe iterate returned (number %d) has relative residual %0.2g",iter,relres); printf("\n"); } pysparse-1.1.1/Src/preconmodule.c0000644010116400000240000003161311402270132015737 0ustar wd15dialout#include "Python.h" #define PY_ARRAY_UNIQUE_SYMBOL precon //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #include "pysparse/blas.h" #include "pysparse/fortran.h" #include "pysparse/spmatrix.h" typedef struct JacobiObject { PyObject_VAR_HEAD int n; PyObject *matrix; double *dinv; double *temp; double omega; int steps; } JacobiObject; typedef struct SSORObject { PyObject_VAR_HEAD int n; SSSMatObject *matrix; double *temp; double *temp2; double omega; int steps; } SSORObject; /*********************************************************************** * JacobiObject methods */ static int jacobi(PyObject *matrix, int n, double *dinv, int steps, double *x, double *y, double *temp) { int ONE = 1; int i, step, res; /* 1st step */ for (i = 0; i < n; i ++) y[i] = x[i]*dinv[i]; /* following steps */ for(step = 1; step < steps; step ++) { F77(dcopy)(&n, y, &ONE, temp, &ONE); res = SpMatrix_Matvec(matrix, n, temp, n, y); if (res == -1) return res; for (i = 0; i < n; i ++) y[i] = (x[i] - y[i])*dinv[i] + temp[i]; } return 0; } static char Jacobi_precon_doc[] = "self.precon(x, y)\n\ \n\ apply preconditioner self on x, store result in y. x is unchanged."; static PyObject * Jacobi_precon(JacobiObject *self, PyObject *args) { PyArrayObject *xp, *yp; int res; /* parse input arguments */ SPMATRIX_PARSE_ARGS_ARR_ARR(args, xp, yp, self->n, self->n); res = jacobi(self->matrix, self->n, self->dinv, self->steps, (double *)(xp->data), (double *)(yp->data), self->temp); if (res) { PyErr_SetString(PyExc_RuntimeError, "unknown error in Jacobi iteration"); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } /** table of object methods */ PyMethodDef Jacobi_methods[] = { {"precon", (PyCFunction)Jacobi_precon, METH_VARARGS, Jacobi_precon_doc}, {NULL, NULL} /* sentinel */ }; /*********************************************************************** * SSORObject methods */ /** SSOR_KERNEL -- SSOR iteration kernel */ static void ssor_kernel(int n, double *b, double *x, double *h, double *temp, double *va, double *da, int *ja, int *ia, double omega, int steps) { double s; /* runnung sum in innermost loop */ int step; /* current iteration step */ int i; /* current row of L */ int j; /* column index */ int k; /* loop variable */ /* main iteration loop */ for (step = 0; step < steps; step ++) { /* 1st half-step: x = (omega*L + D) \ (D*x - omega*(L^T + D)*x) and h = -omega*L*x */ if (step == 0) for (i = 0; i < n; i ++) temp[i] = omega*b[i]; else for (i = 0; i < n; i ++) temp[i] = (1.0 - omega)*x[i]*da[i] + h[i] + omega*b[i]; for (i = 0; i < n; i ++) { s = 0.0; for (k = ia[i]; k < ia[i+1]; k ++) { j = ja[k]; s -= va[k] * x[j]; } h[i] = omega*s; x[i] = (temp[i] + h[i])/da[i]; } /* 2nd half-step: x = (omega*L^T + D) \ (D*x - omega*(L+D)*x) and h = -omega*L^T*x */ for (i = 0; i < n; i ++) { temp[i] = (1.0 - omega)*x[i]*da[i] + h[i] + omega*b[i]; h[i] = 0.0; } for (i = n-1; i >= 0; i --) { h[i] = omega*h[i]; x[i] = (temp[i] + h[i]) / da[i]; s = x[i]; for (k = ia[i]; k < ia[i+1]; k ++) { j = ja[k]; h[j] -= va[k] * s; } } } /* end of main iteration loop */ } /** SYMGS_KERNEL -- SYMGS iteration kernel, optimized version of * SSOR_KERNEL for omega==1.0 */ static void symgs_kernel(int n, double *b, double *x, double *y, double *va, double *da, int *ja, int *ia, int steps) { double s; /* runnung sum in innermost loop */ int step; /* current iteration step */ int i; /* current row of L */ int j; /* column index */ int k; /* loop variable */ /* initialize iteration: y = 0 */ for (k = 0; k < n; k ++) y[k] = 0.0; /* main iteration loop */ for (step = 0; step < steps; step ++) { /* 1st half-step: x = (L + D) \ (b - y) and y = L*x */ for (i = 0; i < n; i ++) { s = 0.0; for (k = ia[i]; k < ia[i+1]; k ++) { j = ja[k]; s += va[k] * x[j]; } x[i] = (b[i] - y[i] - s)/da[i]; y[i] = s; } /* 2nd half-step: x = (L^T + D) \ (b - y) and y = L^T*x */ for (k = 0; k < n; k ++) { x[k] = y[k]; y[k] = 0.0; } for (i = n-1; i >= 0; i --) { x[i] = (b[i] - x[i] - y[i]) / da[i]; s = x[i]; for (k = ia[i]; k < ia[i+1]; k ++) { j = ja[k]; y[j] += va[k] * s; } } } /* end of main iteration loop */ } static char SSOR_precon_doc[] = "self.precon(x, y)\n\ \n\ apply preconditioner self on x, store result in y. x is unchanged."; static PyObject * SSOR_precon(SSORObject *self, PyObject *args) { PyArrayObject *xp, *yp; /* parse input arguments */ SPMATRIX_PARSE_ARGS_ARR_ARR(args, xp, yp, self->n, self->n); if (self->omega == 1.0) /* call SSOR iteration kernel */ symgs_kernel(self->n, (double *)(xp->data), (double *)(yp->data), self->temp, self->matrix->val, self->matrix->diag, self->matrix->col, self->matrix->ind, self->steps); else /* call SSOR iteration kernel */ ssor_kernel(self->n, (double *)(xp->data), (double *)(yp->data), self->temp, self->temp2, self->matrix->val, self->matrix->diag, self->matrix->col, self->matrix->ind, self->omega, self->steps); Py_INCREF(Py_None); return Py_None; } /** table of object methods */ PyMethodDef SSOR_methods[] = { {"precon", (PyCFunction)SSOR_precon, METH_VARARGS, SSOR_precon_doc}, {NULL, NULL} /* sentinel */ }; /*********************************************************************** * JacobiType methods */ static void Jacobi_dealloc(JacobiObject *self) { Py_DECREF(self->matrix); PyMem_DEL(self->dinv); PyMem_DEL(self->temp); PyObject_Del(self); } static PyObject * Jacobi_getattr(JacobiObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->n, self->n); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(Jacobi_methods, (PyObject *)self, name); } /*********************************************************************** * SSORType methods */ static void SSOR_dealloc(SSORObject *self) { Py_DECREF(self->matrix); PyMem_DEL(self->temp); PyMem_DEL(self->temp2); PyObject_Del(self); } static PyObject * SSOR_getattr(SSORObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->n, self->n); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(SSOR_methods, (PyObject *)self, name); } /*********************************************************************** * JacobiType structure */ PyTypeObject JacobiType = { PyObject_HEAD_INIT(NULL) 0, "jacobi_prec", sizeof(JacobiObject), 0, (destructor)Jacobi_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc)Jacobi_getattr, /* 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 */ }; /*********************************************************************** * SSORType structure */ PyTypeObject SSORType = { PyObject_HEAD_INIT(NULL) 0, "ssor_prec", sizeof(SSORObject), 0, (destructor)SSOR_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc)SSOR_getattr, /* 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 */ }; /*********************************************************************** * Object construction functions */ static PyObject * newJacobiObject(PyObject *matrix, double omega, int steps) { JacobiObject *op; int n; /* order of matrix */ double d; int i; /* check shape of matrix object */ if (SpMatrix_GetOrder(matrix, &n)) return NULL; /* create new JacobiObject */ op = PyObject_New(JacobiObject, &JacobiType); if (op == NULL) return PyErr_NoMemory(); op->matrix = matrix; op->n = n; op->omega = omega; op->steps = steps; op->dinv = NULL; op->temp = NULL; /* allocate temp array if steps > 1 */ if (steps > 1) { op->temp = PyMem_New(double, n); if (op->temp == NULL) { PyErr_NoMemory(); goto fail; } } /* allocate and fill dinv array */ op->dinv = PyMem_New(double, n); if (op->dinv == NULL) { PyErr_NoMemory(); goto fail; } for (i = 0; i < n; i ++) { /* get diagonal element (i,i) */ d = SpMatrix_GetItem(matrix, i, i); if (PyErr_Occurred()) goto fail; /* check for singularity */ if (1.0 + d == 1.0) { PyErr_SetString(PyExc_ValueError, "diagonal element close to zero"); goto fail; } /* store inverse */ op->dinv[i] = omega / d; } /* increment ref count of matrix */ Py_INCREF(matrix); return (PyObject *)op; fail: PyMem_Del(op->dinv); PyMem_Del(op->temp); PyObject_Del(op); return NULL; } static PyObject * newSSORObject(SSSMatObject *matrix, double omega, int steps) { SSORObject *self; int n; /* order of matrix */ /* check shape of matrix object */ if (SpMatrix_GetOrder((PyObject *)matrix, &n)) return NULL; /* create new SSORObject */ self = PyObject_New(SSORObject, &SSORType); if (self == NULL) return PyErr_NoMemory(); self->matrix = matrix; self->n = n; self->omega = omega; self->steps = steps; self->temp = NULL; self->temp2 = NULL; /* allocate temp array */ self->temp = PyMem_New(double, n); if (self->temp == NULL) { PyErr_NoMemory(); goto fail; } /* allocate temp2 array if omega != 0.0 */ if (omega != 1.0) { self->temp2 = PyMem_New(double, n); if (self->temp2 == NULL) { PyErr_NoMemory(); goto fail; } } /* increment ref count of matrix */ Py_INCREF(matrix); return (PyObject *)self; fail: PyMem_Del(self->temp); PyMem_Del(self->temp2); PyObject_Del(self); return NULL; } /*********************************************************************** * Module functions */ static char jacobi_doc[] = "jacobi(A, omega=1.0, steps=1)\n\ \n\ return Jacobi preconditioner object."; static PyObject * jacobi_prec(PyObject *self, PyObject *args) { PyObject *matrix; double omega; int steps; /* parse input arguments */ omega = 1.0; steps = 1; if (!PyArg_ParseTuple(args, "O|di", &matrix, &omega, &steps)) return NULL; /* construct SSORObject */ return newJacobiObject(matrix, omega, steps); } static char ssor_doc[] = "ssor(A, omega, steps) -- return SSOR preconditioner object\n\ \n\ This preconditioner executes 'steps' SSOR steps with a zero initial guess.\n\ \n\ parameters\n\ ----------\n\ \n\ A 'sss_mat' object, symmetric sparse matrix\n\ omega relaxation parameter (default value: 1.0)\n\ steps number of SSOR steps"; static PyObject * ssor(PyObject *self, PyObject *args) { SSSMatObject *matrix; double omega; int steps; /* parse input arguments */ omega = 1.0; steps = 1; if (!PyArg_ParseTuple(args, "O!|di", &SSSMatType, &matrix, &omega, &steps)) return NULL; /* construct JacobiObject */ return newSSORObject(matrix, omega, steps); } /** table of module functions */ static PyMethodDef precon_methods[] = { {"jacobi", (PyCFunction)jacobi_prec, METH_VARARGS, jacobi_doc}, {"ssor", (PyCFunction)ssor, METH_VARARGS, ssor_doc}, {NULL, NULL} /* sentinel */ }; DL_EXPORT(void) initprecon(void) { PyObject *m, *d; JacobiType.ob_type = &PyType_Type; SSORType.ob_type = &PyType_Type; m = Py_InitModule("precon", precon_methods); d = PyModule_GetDict(m); PyDict_SetItemString(d, "JacobiType", (PyObject *)&JacobiType); PyDict_SetItemString(d, "SSORType", (PyObject *)&SSORType); /* initialize Numeric array module */ import_array(); /* initialize spmatrix module */ import_spmatrix(); /* No need to check the error here, the caller will do that */ } pysparse-1.1.1/Src/qmrs.c0000644010116400000240000000735411402270127014236 0ustar wd15dialout#include #include #include "Python.h" #include "pysparse/blas.h" #include "pysparse/fortran.h" #define SPMATRIX_UNIQUE_SYMBOL itsolvers_spmatrix #include "pysparse/spmatrix.h" #include "pysparse/qmrs.h" #define SpMatrix_PRECON(prec_obj, n, x, y) \ {if (SpMatrix_Precon((prec_obj),(n),(x),(y))) return -1;} #define SpMatrix_MATVEC(mat_obj, n, x, m, y) \ {if (SpMatrix_Matvec((mat_obj), (n), (x), (m), (y))) return -1;} /******************************************************************************* parameters: ----------- n order of linear system b right hand side of linear system x solution vector matvec matrix vector product function, y := A*x precon preconditioning function, y := M^-1*x my be a NULL pointer work work array of size 6*n tol requested error tolerance maxit maximum allowed iteration steps iter number of iterations err error of solution simplified decoupled QMR method for J-symmetric matrices (Freund & Nachtigal) ********************************************************************************/ int Itsolvers_qmrs_kernel(int n, double *b, double *x, double *work, double tol, int maxit, int *iter, double *err, PyObject *mat_obj, PyObject *prec_obj) { /* Local variables */ int ONE = 1; double beta; double res_init; int i; double delta, theta; double c0, c1, theta0, cc, xi1, rho1inv, tau, eta0, eps0, rho0, rho1, d__1; /* work arrays */ double *wrk1; double *p; double *d; double *v1; double *t; double *g; /* setup pointers into work */ wrk1 = work; p = work + n; d = work + 2*n; v1 = work + 3*n; t = work + 4*n; g = work + 5*n; F77(dcopy)(&n, b, &ONE, v1, &ONE); rho0 = F77(dnrm2)(&n, v1, &ONE); tau = rho0; for (i = 0; i < n; ++i) { v1[i] /= rho0; p[i] = 0.0; g[i] = 0.0; d[i] = 0.0; x[i] = 0.0; } c0 = 1.0; eps0 = 1.0; xi1 = 1.0; theta0 = 0.0; eta0 = -1.0; res_init = rho0; *err = 1.0; *iter = 0; while(*err > tol && *iter < maxit) { ++(*iter); if (eps0 == 0.0) { return -6; } if (prec_obj != NULL) SpMatrix_PRECON(prec_obj, n, v1, wrk1) else F77(dcopy)(&n, v1, &ONE, wrk1, &ONE); delta = F77(ddot)(&n, wrk1, &ONE, v1, &ONE); if (delta == 0.0) { return -2; } cc = xi1 * (delta / eps0); /* it is: g = P\p */ for (i = 0; i < n; ++ i) { p[i] = v1[i] - p[i] * cc; g[i] = wrk1[i] - g[i] * cc; } SpMatrix_MATVEC(mat_obj, n, g, n, t); eps0 = F77(ddot)(&n, g, &ONE, t, &ONE); beta = eps0 / delta; for (i = 0; i < n; ++ i) { v1[i] = t[i] - v1[i] * beta; } rho1 = F77(dnrm2)(&n, v1, &ONE); xi1 = rho1; if (c0 * fabs(beta) == 0.0) { return -6; } theta = rho1 / (c0 * fabs(beta)); c1 = 1.0 / sqrt(theta * theta + 1.0); if (beta * (c0 * c0) == 0.0) { return -6; } eta0 = -eta0 * rho0 * (c1 * c1) / (beta * (c0 * c0)); tau = tau * theta * c1; if (rho1 == 0.0) { return -6; } /* Computing 2nd power */ d__1 = theta0 * c1; cc = d__1 * d__1; rho1inv = 1.0 / rho1; for (i = 0; i < n; ++i) { d[i] = p[i] * eta0 + d[i] * cc; x[i] += d[i]; v1[i] *= rho1inv; } if (xi1 == 0.0) { return -6; } rho0 = rho1; *err = tau / res_init; c0 = c1; theta0 = theta; /* print *,iter,err,tau/res_init */ } /* print *,iter,err */ /* if (err.gt.tol) print *,'convergence not reached' */ if (prec_obj != NULL) { SpMatrix_PRECON(prec_obj, n, x, wrk1); F77(dcopy)(&n, wrk1, &ONE, x, &ONE); } if (*err < tol) return 0; else return -1; } pysparse-1.1.1/Src/spmatrixmodule.c0000644010116400000240000003552711402270126016333 0ustar wd15dialout#include "Python.h" #define SPMATRIX_MODULE #include "pysparse/spmatrix.h" #define PY_ARRAY_UNIQUE_SYMBOL spmatrix //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif PyObject *SpMatrix_ErrorObject; /****************************************************************************** * * * Include C code from other C files * * * ******************************************************************************/ #include "mmio_patched.c" #include "ll_mat.c" #include "csr_mat.c" #include "sss_mat.c" /****************************************************************************** ****************************************************************************** * * * C API functions of the spmatrix package * * * ****************************************************************************** ******************************************************************************/ /****************************************************************************** * * * SpMatrix_ParseVecOpArgs -- parse arguments * * * * parses arguments of Python functions, that expect two one dimensional * * Py_Array objects. * * * * This function should not be used, since it doesn't allow free the * * created objects. * * * * Use the macro SPMATRIX_PARSE_ARGS_ARR_ARR defined in spmatrix.h instead. * * * ******************************************************************************/ static int SpMatrix_ParseVecOpArgs(PyObject *args, double **x_data, double **y_data, int n) { PyObject *x_obj, *y_obj; int nx, ny, res; /* parse input arguments */ if (!PyArg_ParseTuple(args, "OO", &x_obj, &y_obj)) return -1; /* Make sure that x and b are continous double arrays */ res = PyArray_As1D((PyObject **)&x_obj, (char **)x_data, &nx, PyArray_DOUBLE); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert first argument to double array"); return -1; } res = PyArray_As1D((PyObject **)&y_obj, (char **)y_data, &ny, PyArray_DOUBLE); if (res == -1) { PyErr_SetString(PyExc_ValueError, "Unable to convert second argument to double array"); return -1; } /* check operand shapes */ if (nx != n || ny != n) { PyErr_SetString(PyExc_ValueError, "incompatible operand shapes"); return -1; } return 0; } /****************************************************************************** * * * SpMatrix_GetShape -- get object shape * * * * Query the shape attribute of an object. * * * * Used to get the number of row and columns of a sparse matrix or a * * preconditioner. * * * ******************************************************************************/ static int SpMatrix_GetShape(PyObject *op, int dim[]) { PyObject *sh, *elem; if ((sh = PyObject_GetAttrString(op, "shape")) == NULL) return -1; if (PySequence_Size(sh) != 2) { PyErr_SetString(PyExc_ValueError, "invalid matrix shape"); return -1; } elem = PySequence_GetItem(sh, 0); dim[0] = PyInt_AsLong(elem); Py_DECREF(elem); elem = PySequence_GetItem(sh, 1); dim[1] = PyInt_AsLong(elem); Py_DECREF(elem); Py_DECREF(sh); if (PyErr_Occurred() != NULL) { PyErr_SetString(PyExc_ValueError, "invalid matrix shape"); return -1; } return 0; } /****************************************************************************** * * * SpMatrix_GetOrder -- get object order * * * * Queries the shape attribute of an object. * * * * Used to get the number of row and columns of a sparse matrix or a * * preconditioner. * * * * Fails if the shape is not square. * * * ******************************************************************************/ static int SpMatrix_GetOrder(PyObject *op, int *n) { int dim[2]; if (SpMatrix_GetShape(op, dim) == -1) return -1; if (dim[0] != dim[1]) { PyErr_SetString(PyExc_ValueError, "matrix is not square"); return -1; } *n = dim[0]; return 0; } /****************************************************************************** * * * SpMatrix_GetItem -- access matrix entry (i,j) * * * * returns matrix entry op[i,j] as a double * * * ******************************************************************************/ static double SpMatrix_GetItem(PyObject *op, int i, int j) { PyObject *index; PyObject *fo; double d; index = Py_BuildValue("(ii)", i, j); assert(index); fo = PyObject_GetItem(op, index); Py_DECREF(index); if (fo == NULL) return 0.0; d = PyFloat_AsDouble(fo); Py_DECREF(fo); return d; } /****************************************************************************** * * * SpMatrix_Matvec -- invoke matrix-vector multiplication * * * * Invokes matrix-vector multiplication, by calling the 'matvec'-method of * * 'matrix', y = matrix*x. The vectors 'x' and 'y' are given as arrays of * * double. * * * * Returns 0 if the operation was successful, or -1 if an error occured. * * * ******************************************************************************/ static int SpMatrix_Matvec(PyObject *matrix, int nx, double *x, int ny, double *y) { PyObject *x_arr = NULL; PyObject *y_arr = NULL; PyObject *res; /* create array objects from x and y */ x_arr = PyArray_FromDimsAndData(1, &nx, PyArray_DOUBLE, (char *)x); if (x_arr == NULL) goto fail; y_arr = PyArray_FromDimsAndData(1, &ny, PyArray_DOUBLE, (char *)y); if (y_arr == NULL) goto fail; /* Call matvec method of matrix object */ res = PyObject_CallMethod(matrix, "matvec", "OO", x_arr, y_arr); if (res == NULL) goto fail; Py_DECREF(res); /* free array objects */ Py_DECREF(x_arr); Py_DECREF(y_arr); return 0; fail: Py_XDECREF(x_arr); Py_XDECREF(y_arr); return -1; } /****************************************************************************** * * * SpMatrix_Precon -- invoke preconditioner * * * * Applies the preconditioner 'prec' on the vector 'x' and stores the result * * in vector 'y'. This is done by calling the 'precon' method of 'prec'. The * * vectors 'x' and 'y' are given as arrays of double. * * * * Returns 0 if the operation was successful, or -1 if an error occured. * * * ******************************************************************************/ static int SpMatrix_Precon(PyObject *prec, int n, double *x, double *y) { PyObject *x_arr = NULL; PyObject *y_arr = NULL; int dimensions[1]; PyObject *res; dimensions[0] = n; /* create array objects from x and y */ x_arr = PyArray_FromDimsAndData(1, dimensions, PyArray_DOUBLE, (char *)x); if (x_arr == NULL) goto fail; y_arr = PyArray_FromDimsAndData(1, dimensions, PyArray_DOUBLE, (char *)y); if (y_arr == NULL) goto fail; /* Call matvec method of matrix object */ res = PyObject_CallMethod(prec, "precon", "OO", x_arr, y_arr); if (res == NULL) goto fail; Py_DECREF(res); /* free array objects */ Py_DECREF(x_arr); Py_DECREF(y_arr); return 0; fail: Py_XDECREF(x_arr); Py_XDECREF(y_arr); return -1; } /****************************************************************************** * * * Itsolvers_Solve -- Invoke linear solver * * * * Invoke iterative linear solver 'linsolver', to (approximately) solve the * * linear system * * * * A * x = b * * * * to an accuracy of 'tol'. The maximum number of iteration steps taken is * * 'itmax'. The vectors 'x' and 'y' are given as arrays of double of length * * 'n'. * * * * Returns 0 if the operation was successful, or -1 if an error occured. * * * ******************************************************************************/ static int ItSolvers_Solve(PyObject *linsolver, PyObject *A, int n, double *b, double *x, double tol, int itmax, PyObject *K, int *info, int *iter, double *relres) { PyObject *b_arr = NULL; PyObject *x_arr = NULL; int dimensions[1]; PyObject *res; dimensions[0] = n; /* create array objects from x and y */ b_arr = PyArray_FromDimsAndData(1, dimensions, PyArray_DOUBLE, (char *)b); if (b_arr == NULL) goto fail; x_arr = PyArray_FromDimsAndData(1, dimensions, PyArray_DOUBLE, (char *)x); if (x_arr == NULL) goto fail; /* Call iterative solver */ if (K == NULL) res = PyObject_CallFunction(linsolver, "OOOdi", A, b_arr, x_arr, tol, itmax); else res = PyObject_CallFunction(linsolver, "OOOdiO", A, b_arr, x_arr, tol, itmax, K); if (res == NULL) goto fail; /* Parse result Abuse PyArg_ParseTuple to parse res tuple (is this safe?) */ PyArg_ParseTuple(res, "iid", info, iter, relres); Py_DECREF(res); /* free array objects */ Py_DECREF(b_arr); Py_DECREF(x_arr); return 0; fail: Py_XDECREF(b_arr); Py_XDECREF(x_arr); return -1; } /****************************************************************************** * * * LLMatType_alloc * * * * construct an ll_mat object that represents an empty sparse matrix. * * * ******************************************************************************/ static PyObject * LLMat_zeros(PyObject *self, PyObject *args) { int dim[2], sizeHint; sizeHint = 1000; if (!PyArg_ParseTuple(args, "ii|i", dim, dim + 1, &sizeHint)) return NULL; return SpMatrix_NewLLMatObject(dim, 0, sizeHint); } static PyObject * LLMat_sym_zeros(PyObject *self, PyObject *args) { int dim[2], n, sizeHint; sizeHint = 1000; if (!PyArg_ParseTuple(args, "i|i", &n, &sizeHint)) return NULL; dim[0] = dim[1] = n; return SpMatrix_NewLLMatObject(dim, 1, sizeHint); } /****************************************************************************** * * * table of module functions * * * ******************************************************************************/ static PyMethodDef spmatrix_methods[] = { {"ll_mat", LLMat_zeros, METH_VARARGS, 0}, {"ll_mat_sym", LLMat_sym_zeros, METH_VARARGS, 0}, {"ll_mat_from_mtx", LLMat_from_mtx, METH_VARARGS, 0}, {"matrixmultiply", LLMat_matrixmultiply, METH_VARARGS, LLMat_matrixmultiply_doc}, {"dot", LLMat_dot, METH_VARARGS, LLMat_dot_doc}, {NULL, NULL} /* sentinel */ }; DL_EXPORT(void) initspmatrix(void) { PyObject *m, *d; LLMatType.ob_type = &PyType_Type; CSRMatType.ob_type = &PyType_Type; SSSMatType.ob_type = &PyType_Type; m = Py_InitModule("spmatrix", spmatrix_methods); if (m == NULL) goto fail; d = PyModule_GetDict(m); if (d == NULL) goto fail; PyDict_SetItemString(d, "LLMatType", (PyObject *)&LLMatType); PyDict_SetItemString(d, "CSRMatType", (PyObject *)&CSRMatType); PyDict_SetItemString(d, "SSSMatType", (PyObject *)&SSSMatType); SpMatrix_ErrorObject = PyString_FromString("spmatrix.error"); PyDict_SetItemString(d, "error", SpMatrix_ErrorObject); /* initialise C API */ init_c_api(d); /* initialise Numeric array module */ import_array(); /* Check for errors */ if (PyErr_Occurred()) goto fail; return; fail: Py_FatalError("can't initialize module spmatrix"); } pysparse-1.1.1/Src/sss_mat.c0000644010116400000240000001572111402270125014720 0ustar wd15dialout#include "Python.h" #define SPMATRIX_MODULE #include "pysparse/spmatrix.h" #define PY_ARRAY_UNIQUE_SYMBOL spmatrix //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif /** getitem * */ static PyObject * getitem(SSSMatObject *self, int i, int j) { int k, t; if (i == j) return PyFloat_FromDouble(self->diag[i]); if (i < j) { t = i; i = j; j = t; } for (k = self->ind[i]; k < self->ind[i+1]; k ++) { if (self->col[k] == j) return PyFloat_FromDouble(self->val[k]); } return PyFloat_FromDouble(0.0); } /*********************************************************************** * SSSMatObject methods */ static char SSSMat_matvec_doc[] = "a.matvec(x, y)\n\ \n\ compute the sparse matrix-vector product y := a * x. \n\ a is a d1 by d2 sparse matrix.\n\ x and y are two 1-dimensional Numeric arrays of appropriate size."; void sss_matvec(int n, double *x, double *y, double *va, double *da, int *ja, int *ia) { double s, v, xi; int i, j, k; for (i = 0; i < n; i ++) { xi = x[i]; s = 0.0; for (k = ia[i]; k < ia[i+1]; k ++) { j = ja[k]; v = va[k]; s += v * x[j]; y[j] += v * xi; } y[i] = s + da[i]*xi; } } void sss_matvec_stride(int n, double *x, int incx, double *y, int incy, double *va, double *da, int *ja, int *ia) { double s, v, xi; int i, j, k; for (i = 0; i < n; i ++) { xi = x[i * incx]; s = 0.0; for (k = ia[i]; k < ia[i+1]; k ++) { j = ja[k]; v = va[k]; s += v * x[j * incx]; y[j * incy] += v * xi; } y[i * incy] = s + da[i]*xi; } } static PyObject * SSSMat_matvec(SSSMatObject *self, PyObject *args) { PyArrayObject *xp, *yp; SPMATRIX_PARSE_ARGS_ARR_ARR_STRIDE(args, xp, yp, self->n, self->n); if (xp->flags & CONTIGUOUS && yp->flags & CONTIGUOUS) { sss_matvec(self->n, (double *)(xp->data), (double *)(yp->data), self->val, self->diag, self->col, self->ind); } else { sss_matvec_stride(self->n, (double *)(xp->data), xp->strides[0] / sizeof(double), (double *)(yp->data), yp->strides[0] / sizeof(double), self->val, self->diag, self->col, self->ind); } Py_INCREF(Py_None); return Py_None; } static char SSSMat_matvec_transp_doc[] = "a.matvec_transp(x, y)\n\ \n\ compute the sparse matrix-vector product y := a^T * x. \n\ a^T is the transpose of a, which is a d1 by d2 sparse matrix.\n\ x and y are two 1-dimensional Numeric arrays of appropriate size."; /** table of object methods */ PyMethodDef SSSMat_methods[] = { {"matvec", (PyCFunction)SSSMat_matvec, METH_VARARGS, SSSMat_matvec_doc}, {"matvec_transp", (PyCFunction)SSSMat_matvec, METH_VARARGS, SSSMat_matvec_transp_doc}, {NULL, NULL} /* sentinel */ }; /*********************************************************************** * SSSMatType methods */ static void SSSMatType_dealloc(SSSMatObject *self) { PyMem_DEL(self->ind); PyMem_DEL(self->val); PyMem_DEL(self->col); PyMem_DEL(self->diag); PyObject_Del(self); } static int SSSMatType_print(SSSMatObject *a, FILE *fp, int flags) { int i, k, first = 1; if (a->nnz == 0) { fprintf(fp, "sss_mat([%d,%d])", a->n, a->n); return 0; } fprintf(fp, "sss_mat([%d,%d], [", a->n, a->n); for (i = 0; i < a->n; i ++) { for (k = a->ind[i]; k < a->ind[i+1]; k ++) { if (!first) fprintf(fp, ", "); first = 0; fprintf(fp, "(%d,%d): %g", i, a->col[k], a->val[k]); } fprintf(fp, "(%d,%d): %g", i, i, a->diag[i]); } fprintf(fp, "])"); return 0; } static PyObject * SSSMatType_getattr(SSSMatObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->n, self->n); if (strcmp(name, "nnz") == 0) return PyInt_FromLong(self->nnz + self->n); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape", "nnz"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(SSSMat_methods, (PyObject *)self, name); } /*********************************************************************** * mapping functions */ /** SSSMat_length - number of items in mapping * == number of matrix entries */ static int SSSMat_length(SSSMatObject *self) { return self->n * self->n; } /** SSSMat_subscript * Called when treating array object like a mapping. This is used * implement two-dimensional idices, e.g. A[i,j] or A[i1:i2,j1:j2] */ static PyObject * SSSMat_subscript(SSSMatObject *self, PyObject *idx) { int type, start0, stop0, step0, len0, start1, stop1, step1, len1; int dim[2]; dim[0] = dim[1] = self->n; if ((type = LLMat_parse_index(idx, dim, &start0, &stop0, &step0, &len0, &start1, &stop1, &step1, &len1)) == -1) return NULL; if (type == 1) return getitem(self, start0, start1); else { PyErr_SetString(PyExc_IndexError, "slices not supported"); return NULL; } } static PyMappingMethods SSSMat_as_mapping = { #ifdef LENFUNC_OK (lenfunc)SSSMat_length, /*mp_length*/ #else (inquiry)SSSMat_length, /*mp_length*/ #endif (binaryfunc)SSSMat_subscript, /*mp_subscript*/ (objobjargproc)0, }; /*********************************************************************** * SSSMatType structure */ static PyTypeObject SSSMatType = { PyObject_HEAD_INIT(NULL) 0, "sss_mat", sizeof(SSSMatObject), 0, (destructor)SSSMatType_dealloc, /* tp_dealloc */ (printfunc)SSSMatType_print, /* tp_print */ (getattrfunc)SSSMatType_getattr, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number*/ 0, /* tp_as_sequence*/ &SSSMat_as_mapping, /* tp_as_mapping*/ 0, /* tp_hash */ }; /** newSSSMatObject -- allocate a new SSSMatObject instance * * a newly allocated, uninitialized SSSMatObject is returned */ static PyObject * newSSSMatObject(int n, int nnz) { SSSMatObject *op; /* create new SparseArrayt object */ op = PyObject_New(SSSMatObject, &SSSMatType); if (op == NULL) PyErr_NoMemory(); op->val = NULL; op->diag = NULL; op->ind = NULL; op->col = NULL; /* allocate arrays */ op->ind = PyMem_New(int, n + 1); if (op->ind == NULL) goto fail; op->diag = PyMem_New(double, n); if (op->diag == NULL) goto fail; op->val = PyMem_New(double, nnz); if (op->val == NULL) goto fail; op->col = PyMem_New(int, nnz); if (op->col == NULL) goto fail; /* initialize rest of fields */ op->n = n; op->nnz = nnz; return (PyObject *) op; fail: PyMem_Del(op->ind); PyMem_Del(op->diag); PyMem_Del(op->val); PyMem_Del(op->col); PyObject_Del(op); return PyErr_NoMemory(); } pysparse-1.1.1/Src/superlu3module.c0000644010116400000240000002774011402270130016237 0ustar wd15dialout#include #include "Python.h" #define PY_ARRAY_UNIQUE_SYMBOL superlu #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #include "slu_ddefs.h" #include "slu_util.h" #include "pysparse/spmatrix.h" /*********************************************************************** * static variable */ /*********************************************************************** * SuperLUObject definition */ typedef struct SuperLUObject { PyObject_VAR_HEAD int n; SuperMatrix L; SuperMatrix U; int *perm_r; int *perm_c; SuperLUStat_t stat; int StatInit_done; /* flag showing whether StatInit was already called */ superlu_options_t options; } SuperLUObject; /*********************************************************************** * SuperLUObject methods */ static char solve_doc[] = "self.solve(b, x, trans)\n\ \n\ solves linear system of equations with one or sereral right hand sides.\n\ \n\ parameters\n\ ----------\n\ \n\ b array, right hand side(s) of equation\n\ x array, solution vector(s)\n\ trans 'N': solve A * x == b\n\ 'T': solve A^T * x == b\n\ (optional, default value 'N')\n\ "; static PyObject *SuperLU_solve(SuperLUObject *self, PyObject *args) { PyArrayObject *b, *x; SuperMatrix B; char trans = 'N'; trans_t Trans; int i, info = 0; if (!PyArg_ParseTuple(args, "O!O!|c", &PyArray_Type, &b, &PyArray_Type, &x, &trans)) return NULL; SPMATRIX_CHECK_ARR_DIM_SIZE(b, 1, self->n); SPMATRIX_CHECK_ARR_DIM_SIZE(x, 1, self->n); /* solve transposed system: * matrix was passed row-wise instead of column-wise */ if (trans == 'n' || trans == 'N') Trans = TRANS; //trans = 'T'; else if (trans == 't' || trans == 'T') Trans = NOTRANS; //trans = 'N'; else { PyErr_SetString(PyExc_ValueError, "trans"); return NULL; } /* copy b to x */ for (i = 0; i < self->n; i ++) ((double *)x->data)[i] = ((double *)b->data)[i]; /* Create data structure for right hand side */ dCreate_Dense_Matrix(&B, self->n, 1, (double *)x->data, self->n, SLU_DN, SLU_D, SLU_GE); /* Solve the system, overwriting vector x. */ dgstrs(Trans, &self->L, &self->U, self->perm_c, self->perm_r, &B, &self->stat, &info); /* free memory */ Destroy_SuperMatrix_Store(&B); if (info) { PyErr_SetString(PyExc_SystemError, "dgstrs was called with invalid arguments"); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } /** table of object methods */ PyMethodDef SuperLU_special_methods[] = { {"solve", (PyCFunction)SuperLU_solve, METH_VARARGS, solve_doc}, {NULL, NULL, 0, NULL } /* sentinel */ }; /*********************************************************************** * SuperLUType methods */ static void SuperLU_dealloc(SuperLUObject *self) { SUPERLU_FREE(self->perm_r); SUPERLU_FREE(self->perm_c); Destroy_SuperNode_Matrix(&self->L); Destroy_CompCol_Matrix(&self->U); StatFree(&self->stat); PyObject_Del(self); } static PyObject *SuperLU_getattr(SuperLUObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->n, self->n); if (strcmp(name, "nnz") == 0) return Py_BuildValue("i", ((SCformat *)self->L.Store)->nnz + ((SCformat *)self->U.Store)->nnz); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape", "nnz"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(SuperLU_special_methods, (PyObject *)self, name); } /*********************************************************************** * SuperLUType structure */ PyTypeObject SuperLUType = { PyObject_HEAD_INIT(NULL) 0, "superlu_context", sizeof(SuperLUObject), 0, (destructor)SuperLU_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc)SuperLU_getattr, /* 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, /* tp_flags*/ "SuperLU Context Object", /* tp_doc */ }; /*********************************************************************** * Object construction functions */ /*********************************************************************** * Module functions */ static PyObject *newSuperLUObject(int n, CSRMatObject *matrix, PyObject *issym, double diag_pivot_thresh, double drop_tol, int relax, int panel_size, int permc_spec) { SuperLUObject *self; SuperMatrix A; /* A in NC format used by the factorization routine. */ SuperMatrix AC; /* Matrix postmultiplied by Pc */ mem_usage_t mem_usage; int *etree; int info = 0; //printf("Creating new object\n"); /* Create SuperLUObject */ self = PyObject_New(SuperLUObject, &SuperLUType); if (self == NULL) return NULL; // PyErr_NoMemory(); self->n = n; self->perm_r = NULL; self->perm_c = NULL; self->StatInit_done = 0; //printf("Setting options (permc_spec = %d)\n", permc_spec); set_default_options(&self->options); switch( permc_spec ) { case 0: self->options.ColPerm = NATURAL; break; case 1: self->options.ColPerm = MMD_ATA; break; case 2: self->options.ColPerm = MMD_AT_PLUS_A; break; case 3: self->options.ColPerm = COLAMD; break; default: //self->options.ColPerm = MY_PERMC; break; } self->options.DiagPivotThresh = diag_pivot_thresh; self->options.PrintStat = YES; self->options.SymmetricMode = (issym == Py_True) ? YES : NO; //printf("Setting up stats\n"); /* Make sure StatInit is only called once */ if(! self->StatInit_done) { StatInit(&self->stat); // StatInit(panel_size, relax); self->StatInit_done = 1; } //printf("Creating matrix structure\n"); /* Create matrix structure ; indicate that A is stored by rows (SLU_NR) */ dCreate_CompCol_Matrix(&A, n, n, matrix->nnz, matrix->val, matrix->col, matrix->ind, SLU_NR, SLU_D, (issym == Py_True) ? SLU_SYL : SLU_GE); //dPrint_CompCol_Matrix("A", &A); //printf("Allocating room for permutations\n"); etree = intMalloc(n); self->perm_r = intMalloc(n); self->perm_c = intMalloc(n); if (etree == NULL || self->perm_r == NULL || self->perm_c == NULL) { PyErr_NoMemory(); goto fail; } //printf("Obtaining permutation\n"); /* Obtain and apply column permutation */ get_perm_c(permc_spec, &A, self->perm_c); sp_preorder(&self->options, &A, self->perm_c, etree, &AC); //print_int_vec("\nperm_c", n, self->perm_c); //printf("Factorizing with drop_tol = %g\n", drop_tol); /* Perform factorization (perm_c and perm_r are swapped because our matrix * is stored in compressed-row format and not in compressed-column format! */ dgstrf(&self->options, &AC, drop_tol, relax, panel_size, etree, NULL, 0, self->perm_c, self->perm_r, &self->L, &self->U, &self->stat, &info); //dPrint_SuperNode_Matrix("L", &self->L); //dPrint_CompCol_Matrix("U", &self->U); //printf("Freeing memory\n"); /* free memory */ SUPERLU_FREE(etree); Destroy_SuperMatrix_Store(&A); /* arrays of input matrix will not be freed */ Destroy_CompCol_Permuted(&AC); if (info) { if (info < 0) PyErr_SetString(PyExc_SystemError, "dgstrf was called with invalid arguments"); else { if (info <= n) PyErr_SetString(PyExc_RuntimeError, "Factor is exactly singular"); else PyErr_NoMemory(); } goto fail; } return (PyObject *)self; fail: PyMem_Del(self->perm_r); PyMem_Del(self->perm_c); StatFree(&self->stat); PyObject_Del(self); return NULL; } static char factorize_doc[] = "factorize(A, ...)\n\ \n\ performs a factorization of the sparse matrix A (which is a csr_mat object) and \n\ return a superlu_context object.\n\ \n\ arguments\n\ ---------\n\ \n\ A spmatrix.csr_mat object.\n\ Matrix to be factorized\n\ \n\ additional keyword arguments:\n\ -----------------------------\n\ \n\ diag_pivot_thresh threshhold for partial pivoting.\n\ 0.0 <= diag_pivot_thresh <= 1.0\n\ 0.0 corresponds to no pivoting\n\ 1.0 corresponds to partial pivoting\n\ (default: 1.0)\n\ \n\ drop_tol drop tolerance parameter\n\ 0.0 <= drop_tol <= 1.0\n\ 0.0 corresponds to exact factorization\n\ CAUTION: the drop_tol is not implemented in SuperLU 2.0\n\ (default: 0.0)\n\ \n\ relax to control degree of relaxing supernodes\n\ (default: 1)\n\ \n\ panel_size a panel consist of at most panel_size consecutive columns.\n\ (default: 10)\n\ \n\ permc_spec specifies the matrix ordering used for the factorization\n\ 0: natural ordering\n\ 1: MMD applied to the structure of A^T * A\n\ 2: MMD applied to the structure of A^T + A\n\ 3: COLAMD, approximate minimum degree column ordering\n\ (default: 2)\n\ "; /* ========================================================================== */ static PyObject *factorize(PyObject *self, PyObject *args, PyObject *keywds) { int n; /* dimension of matrix */ /* default value for SuperLU parameters*/ double diag_pivot_thresh = 1.0; double drop_tol = 0.0; PyObject *symmetric = Py_False; int relax = 1; int panel_size = 10; int permc_spec = 2; PyObject *matrix; static char *kwlist[] = {"", "symmetric", "diag_pivot_thresh", "drop_tol", "relax", "panel_size", "permc_spec", NULL}; int res = PyArg_ParseTupleAndKeywords(args, keywds, "O|Oddiii", kwlist, &matrix, &symmetric, &diag_pivot_thresh, &drop_tol, &relax, &panel_size, &permc_spec); if (!res) return NULL; /* check shape of matrix object */ if (SpMatrix_GetOrder(matrix, &n)) return NULL; return newSuperLUObject(n, (CSRMatObject *)matrix, symmetric, diag_pivot_thresh, drop_tol, relax, panel_size, permc_spec); } /* ========================================================================== */ /* * D e f i n i t i o n o f S u p e r L U m e t h o d s */ /* ========================================================================== */ static PyMethodDef SuperLU_methods[] = { {"factorize", (PyCFunction)factorize, METH_VARARGS|METH_KEYWORDS, factorize_doc}, {NULL, NULL, 0, NULL }// sentinel }; /* ========================================================================== */ DL_EXPORT(void) initsuperlu(void) { PyObject *m, *d; //SuperLUType.ob_type = &PyType_Type; if( PyType_Ready( &SuperLUType ) < 0 ) return; m = Py_InitModule3("superlu", SuperLU_methods, "Python interface to SuperLU"); d = PyModule_GetDict(m); PyDict_SetItemString(d, "SuperLUType", (PyObject *)&SuperLUType); import_array(); /* Initialize the NumPy module */ import_spmatrix(); /* Initialize PySparse module */ /* Check for errors */ if (PyErr_Occurred()) Py_FatalError("Unable to initialize module superlu"); return; } pysparse-1.1.1/Src/superlumodule.c0000644010116400000240000002322511402270125016152 0ustar wd15dialout#include #include "Python.h" #define PY_ARRAY_UNIQUE_SYMBOL superlu //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #include "pysparse/dsp_defs.h" #include "pysparse/util.h" #include "pysparse/spmatrix.h" /*********************************************************************** * static variable */ static int StatInit_done = 0; /* flag showing whether StatInit was already called */ /*********************************************************************** * SuperLUObject definition */ typedef struct SuperLUObject { PyObject_VAR_HEAD int n; SuperMatrix L; SuperMatrix U; int *perm_r; int *perm_c; } SuperLUObject; /*********************************************************************** * SuperLUObject methods */ static char solve_doc[] = "self.solve(b, x, trans)\n\ \n\ solves linear system of equations with one or sereral right hand sides.\n\ \n\ parameters\n\ ----------\n\ \n\ b array, right hand side(s) of equation\n\ x array, solution vector(s)\n\ trans 'N': solve A * x == b\n\ 'T': solve A^T * x == b\n\ (optional, default value 'N')\n\ "; static PyObject * SuperLU_solve(SuperLUObject *self, PyObject *args) { PyArrayObject *b, *x; SuperMatrix B; char trans = 'N'; int i, info; if (!PyArg_ParseTuple(args, "O!O!|c", &PyArray_Type, &b, &PyArray_Type, &x, &trans)) return NULL; SPMATRIX_CHECK_ARR_DIM_SIZE(b, 1, self->n); SPMATRIX_CHECK_ARR_DIM_SIZE(x, 1, self->n); /* solve transposed system: matrix was passed row-wise instead of column-wise */ if (trans == 'n' || trans == 'N') trans = 'T'; else if (trans == 't' || trans == 'T') trans = 'N'; else { PyErr_SetString(PyExc_ValueError, "trans"); return NULL; } /* copy b to x */ for (i = 0; i < self->n; i ++) ((double *)x->data)[i] = ((double *)b->data)[i]; /* Create data structure for right hand side */ #ifdef OLD_SUPERLU dCreate_Dense_Matrix(&B, self->n, 1, (double *)x->data, self->n, DN, _D, GE); #else dCreate_Dense_Matrix(&B, self->n, 1, (double *)x->data, self->n, DN, D_, GE); #endif /* Solve the system, overwriting vector x. */ dgstrs(&trans, &self->L, &self->U, self->perm_r, self->perm_c, &B, &info); /* free memory */ Destroy_SuperMatrix_Store(&B); if (info) { PyErr_SetString(PyExc_SystemError, "dgstrs was called with invalid arguments"); return NULL; } else { Py_INCREF(Py_None); return Py_None; } } static char precon_doc[] = ""; static PyObject * SuperLU_precon(LLMatObject *self, PyObject *args) {} /** table of object methods */ PyMethodDef SuperLU_methods[] = { {"solve", (PyCFunction)SuperLU_solve, METH_VARARGS, solve_doc}, {NULL, NULL} /* sentinel */ }; /*********************************************************************** * SuperLUType methods */ static void SuperLU_dealloc(SuperLUObject *self) { SUPERLU_FREE(self->perm_r); SUPERLU_FREE(self->perm_c); Destroy_SuperNode_Matrix(&self->L); Destroy_CompCol_Matrix(&self->U); PyObject_Del(self); } static PyObject * SuperLU_getattr(SuperLUObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->n, self->n); if (strcmp(name, "nnz") == 0) return Py_BuildValue("i", ((SCformat *)self->L.Store)->nnz + ((SCformat *)self->U.Store)->nnz); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape", "nnz"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(SuperLU_methods, (PyObject *)self, name); } /*********************************************************************** * SuperLUType structure */ PyTypeObject SuperLUType = { PyObject_HEAD_INIT(NULL) 0, "superlu_context", sizeof(SuperLUObject), 0, (destructor)SuperLU_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc)SuperLU_getattr, /* 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 */ }; /*********************************************************************** * Object construction functions */ /*********************************************************************** * Module functions */ static PyObject * newSuperLUObject(int n, CSRMatObject *matrix, double diag_pivot_thresh, double drop_tol, int relax, int panel_size, int permc_spec) { SuperLUObject *self; char refact[1]; SuperMatrix A; /* A in NC format used by the factorization routine. */ SuperMatrix AC; /* Matrix postmultiplied by Pc */ mem_usage_t mem_usage; int lwork = 0; int *etree; int info; *refact = 'N'; /* make sure StatInit is only called once */ if (!StatInit_done) { StatInit(panel_size, relax); StatInit_done = 1; } /* Create SuperLUObject */ self = PyObject_New(SuperLUObject, &SuperLUType); if (self == NULL) return PyErr_NoMemory(); self->n = n; self->perm_r = NULL; self->perm_c = NULL; /* Create matrix structure */ #ifdef OLD_SUPERLU dCreate_CompCol_Matrix(&A, n, n, matrix->nnz, matrix->val, matrix->col, matrix->ind, NC, _D, GE); #else dCreate_CompCol_Matrix(&A, n, n, matrix->nnz, matrix->val, matrix->col, matrix->ind, NC, D_, GE); #endif /* Calculate and apply minimum degree ordering*/ etree = intMalloc(n); self->perm_r = intMalloc(n); self->perm_c = intMalloc(n); if (self->perm_r == NULL || self->perm_c == NULL) { PyErr_NoMemory(); goto fail; } get_perm_c(permc_spec, &A, self->perm_c); /* calc column permutation */ sp_preorder(refact, &A, self->perm_c, etree, &AC); /* apply column permutation */ /* Perform factorization */ dgstrf(refact, &AC, diag_pivot_thresh, drop_tol, relax, panel_size, etree, NULL, lwork, self->perm_r, self->perm_c, &self->L, &self->U, &info); /* free memory */ SUPERLU_FREE(etree); Destroy_SuperMatrix_Store(&A); /* arrays of input matrix will not be freed */ Destroy_CompCol_Permuted(&AC); if (info) { if (info < 0) PyErr_SetString(PyExc_SystemError, "dgstrf was called with invalid arguments"); else { if (info <= n) PyErr_SetString(PyExc_RuntimeError, "Factor is exactly singular"); else PyErr_NoMemory(); } goto fail; } return (PyObject *)self; fail: PyMem_Del(self->perm_r); PyMem_Del(self->perm_c); PyObject_Del(self); return NULL; } static char factorize_doc[] = "factorize(A, ...)\n\ \n\ performs a factorization of the sparse matrix A (which is a csr_mat object) and \n\ return a superlu_context object.\n\ \n\ arguments\n\ ---------\n\ \n\ A spmatrix.csr_mat object.\n\ Matrix to be factorized\n\ \n\ additional keyword arguments:\n\ -----------------------------\n\ \n\ diag_pivot_thresh threshhold for partial pivoting.\n\ 0.0 <= diag_pivot_thresh <= 1.0\n\ 0.0 corresponds to no pivoting\n\ 1.0 corresponds to partial pivoting\n\ (default: 1.0)\n\ \n\ drop_tol drop tolerance parameter\n\ 0.0 <= drop_tol <= 1.0\n\ 0.0 corresponds to exact factorization\n\ CAUTION: the drop_tol is not implemented in SuperLU 2.0\n\ (default: 0.0)\n\ \n\ relax to control degree of relaxing supernodes\n\ (default: 1)\n\ \n\ panel_size a panel consist of at most panel_size consecutive columns.\n\ (default: 10)\n\ \n\ permc_spec specifies the matrix ordering used for the factorization\n\ 0: natural ordering\n\ 1: MMD applied to the structure of A^T * A\n\ 2: MMD applied to the structure of A^T + A\n\ 3: COLAMD, approximate minimum degree column ordering\n\ (default: 2)\n\ "; static PyObject * factorize(PyObject *self, PyObject *args, PyObject *keywds) { int n; /* dimension of matrix */ /* default value for SuperLU parameters*/ double diag_pivot_thresh = 1.0; double drop_tol = 0.0; int relax = 1; int panel_size = 10; int permc_spec = 2; CSRMatObject *matrix; static char *kwlist[] = {"", "diag_pivot_thresh", "drop_tol", "relax", "panel_size", "permc_spec", NULL}; int res = PyArg_ParseTupleAndKeywords(args, keywds, "O!|ddiii", kwlist, &CSRMatType, &matrix, &diag_pivot_thresh, &drop_tol, &relax, &panel_size, &permc_spec); if (!res) return NULL; if (drop_tol != 0.0) printf("CAUTION: the drop_tol is not implemented in SuperLU 2.0 and earlier\n"); /* check shape of matrix object */ if (SpMatrix_GetOrder((PyObject *)matrix, &n)) return NULL; return newSuperLUObject(n, matrix, diag_pivot_thresh, drop_tol, relax, panel_size, permc_spec); } /** table of module functions */ static PyMethodDef precon_methods[] = { {"factorize", (PyCFunction)factorize, METH_VARARGS|METH_KEYWORDS, factorize_doc}, {NULL, NULL} /* sentinel */ }; DL_EXPORT(void) initsuperlu(void) { PyObject *m, *d; SuperLUType.ob_type = &PyType_Type; m = Py_InitModule("superlu", precon_methods); d = PyModule_GetDict(m); PyDict_SetItemString(d, "SuperLUType", (PyObject *)&SuperLUType); /* initialize Numeric array module */ import_array(); /* initialize spmatrix module */ import_spmatrix(); /* No need to check the error here, the caller will do that */ } pysparse-1.1.1/Src/umfpackmodule.c0000644010116400000240000005454411402270132016107 0ustar wd15dialout/* This module provides an interface to the UMFPACK library. The license of the UMFPACK library is available below. UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis. All Rights Reserved. UMFPACK License: Your use or distribution of UMFPACK or any modified version of UMFPACK implies that you agree to this License. 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 or copy this program, 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 UMFPACK or any modified version of UMFPACK 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. This software was developed with support from the National Science Foundation, and is provided to you free of charge. Availability: http://www.cise.ufl.edu/research/sparse/umfpack -------------------------------------------------------------------------------- AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved. AMD License: Your use or distribution of AMD or any modified version of AMD implies that you agree to this License. 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 or copy this program, 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 AMD or any modified version of AMD 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. This software was developed with support from the National Science Foundation, and is provided to you free of charge. Availability: http://www.cise.ufl.edu/research/sparse/amd */ #include #include #include "Python.h" #define PY_ARRAY_UNIQUE_SYMBOL umfpack //#include "Numeric/arrayobject.h" #if NUMPY #include "numpy/arrayobject.h" #include "numpy/noprefix.h" #else #include "Numeric/arrayobject.h" #endif #include "umfpack.h" #include "pysparse/spmatrix.h" #include "pysparse/ll_mat.h" #define SYMMETRIC 1 /* Symmetric SpMatrix */ #define GENERAL 0 /* General SpMatrix */ /*********************************************************************** * UMFPackObject definition */ typedef struct UMFPackObject { PyObject_VAR_HEAD int n; int nnz; double *val; /* pointer to array of values */ int *row; /* pointer to array of indices */ int *ind; /* pointer to array of indices */ void *Numeric; double *Control; double *Info; } UMFPackObject; /*********************************************************************** * UMFPackObject methods */ static char getlists_doc[] = ""; static PyObject * UMFPack_getlists(UMFPackObject *self, PyObject *args) { PyObject *ind=NULL, *row=NULL, *val=NULL, *tupleret=NULL; int i; if (!PyArg_ParseTuple(args, "")) return NULL; ind = PyList_New(self->n+1); if (ind == NULL) goto failmemory; PyList_SetItem(ind, 0, Py_BuildValue("i", 0)); for (i=1; i < (self->n + 1); i++) { PyList_SetItem(ind, i, Py_BuildValue("i", self->ind[i] )); } row = PyList_New(self->nnz); if (row == NULL) goto failmemory; for (i=0; i < self->nnz; i++) { PyList_SetItem(row, i, Py_BuildValue("i", self->row[i])); } val = PyList_New(self->nnz); if (val == NULL) goto failmemory; for (i=0; i < self->nnz; i++) { PyList_SetItem(val, i, Py_BuildValue("d", self->val[i])); } tupleret = PyTuple_New(3); if (tupleret == NULL) goto failmemory; PyTuple_SetItem(tupleret, 0, ind); PyTuple_SetItem(tupleret, 1, row); PyTuple_SetItem(tupleret, 2, val); return tupleret; failmemory: if (ind != NULL) PyObject_Del(ind); if (row != NULL) PyObject_Del(row); if (val != NULL) PyObject_Del(val); if (tupleret != NULL) PyObject_Del(tupleret); return PyErr_NoMemory(); } static char lunz_doc[] = "self.lunz(): Returns number of nonzeros in factors\n"; static PyObject *UMFPack_Lunz(UMFPackObject *self, PyObject *args) { int nrow, ncol, lnz, unz, nz_udiag, status; void *Numeric = self->Numeric; /* Obtain number of nonzeros in factors */ status = umfpack_di_get_lunz(&lnz, &unz, &nrow, &ncol, &nz_udiag, Numeric); if( status != UMFPACK_OK ) { switch(status) { case UMFPACK_ERROR_invalid_Numeric_object: PyErr_SetString(PyExc_SystemError, "Get_Lunz:: Invalid Numeric object"); return NULL; case UMFPACK_ERROR_argument_missing: PyErr_SetString(PyExc_SystemError, "Get_Lunz:: Invalid arguments"); return NULL; } } return Py_BuildValue("iii", lnz, unz, nz_udiag); } static char lu_doc[] = "self.lu()\n\ Returns L and U factors, permutation and scaling information.\n\n\ Use: (L, U, P, Q, R, do_recip) = self.lu().\n\ The original matrix A is factorized into\n\ L U = P R A Q\n\ where L is unit lower triangular,\n\ U is upper triangular,\n\ P and Q are permutation matrices,\n\ R is a row-scaling diagonal matrix such that\n\ the i-th row of A has been divided by R[i] if do_recip = True,\n\ the i-th row of A has been multiplied by R[i] if do_recip = False.\n\ \n\ L and U are returned as ll_mat sparse matrices.\n\ P, Q and R are returned as NumPy arrays.\ "; static PyObject *UMFPack_Lu(UMFPackObject *self, PyObject *args) { int nrow, ncol, do_recip, lnz, unz, nz_udiag, status, i, j; int *Lp, *Lj, *Up, *Ui; double *Lx, *Ux, *D; void *Numeric = self->Numeric; PyArrayObject *P, *Q, *R; npy_int *pval, *qval; npy_double *rval; npy_intp dp[1], dq[1], dr[1]; PyObject *Lmat, *Umat; int ldims[2], udims[2]; /* Obtain number of nonzeros in factors */ status = umfpack_di_get_lunz(&lnz, &unz, &nrow, &ncol, &nz_udiag, Numeric); if( status != UMFPACK_OK ) { switch(status) { case UMFPACK_ERROR_invalid_Numeric_object: PyErr_SetString(PyExc_SystemError, "Get_Lunz:: Invalid Numeric object"); return NULL; case UMFPACK_ERROR_argument_missing: PyErr_SetString(PyExc_SystemError, "Get_Lunz:: Invalid arguments"); return NULL; } } /* Allocate memory to hold factors */ Lp = (int *)calloc(nrow+1, sizeof(int)); Lj = (int *)calloc(lnz, sizeof(int)); Lx = (double *)calloc(lnz, sizeof(double)); Up = (int *)calloc(ncol+1, sizeof(int)); Ui = (int *)calloc(unz, sizeof(int)); Ux = (double *)calloc(unz, sizeof(double)); dp[0] = nrow; dq[0] = ncol; dr[0] = nrow; P = (PyArrayObject *)PyArray_SimpleNew(1, dp, NPY_INT); pval = (npy_int *)P->data; Q = (PyArrayObject *)PyArray_SimpleNew(1, dq, NPY_INT); qval = (npy_int *)Q->data; D = NULL; /* Force diagonal terms into U */ R = (PyArrayObject *)PyArray_SimpleNew(1, dr, NPY_DOUBLE); rval = (npy_double *)R->data; /* Retrieve factors, permutation vectors and row scaling */ status = umfpack_di_get_numeric(Lp, Lj, Lx, Up, Ui, Ux, pval, qval, D, &do_recip, rval, Numeric); if( status != UMFPACK_OK ) { switch(status) { case UMFPACK_ERROR_out_of_memory: PyErr_SetString(PyExc_SystemError, "Get_Numeric:: out of memory"); return NULL; case UMFPACK_ERROR_invalid_Numeric_object: PyErr_SetString(PyExc_SystemError, "Get_Numeric:: Numeric object is invalid"); return NULL; } } /* Create LL_Mat structure for factor L and populate it */ ldims[0] = nrow; ldims[1] = nrow < ncol ? nrow : ncol; Lmat = SpMatrix_NewLLMatObject( ldims, GENERAL, lnz ); for( i=0; in); SPMATRIX_CHECK_ARR_DIM_SIZE(x, 1, self->n); if (strcmp(method, "UMFPACK_A") == 0) sys = UMFPACK_A; else if (strcmp(method, "UMFPACK_At") == 0) sys = UMFPACK_At; else if (strcmp(method, "UMFPACK_Pt_L") == 0) sys = UMFPACK_Pt_L; else if (strcmp(method, "UMFPACK_L") == 0) sys = UMFPACK_L; else if (strcmp(method, "UMFPACK_Lt_P") == 0) sys = UMFPACK_Lt_P; else if (strcmp(method, "UMFPACK_Lt") == 0) sys = UMFPACK_Lt; else if (strcmp(method, "UMFPACK_U_Qt") == 0) sys = UMFPACK_U_Qt; else if (strcmp(method, "UMFPACK_U") == 0) sys = UMFPACK_U; else if (strcmp(method, "UMFPACK_Q_Ut") == 0) sys = UMFPACK_Q_Ut; else if (strcmp(method, "UMFPACK_Ut") == 0) sys = UMFPACK_Ut; else { PyErr_SetString(PyExc_ValueError, "method"); return NULL; } if( irsteps != -1 ) self->Control[UMFPACK_IRSTEP] = irsteps; status = umfpack_di_solve(sys, self->ind, self->row, self->val, (double *)x->data, (double *)b->data, self->Numeric, self->Control, self->Info); switch( status ) { case UMFPACK_WARNING_singular_matrix: PyErr_SetString(PyExc_SystemError, "singular matrix"); return NULL; case UMFPACK_ERROR_out_of_memory: PyErr_SetString(PyExc_SystemError, "insufficient memory"); return NULL; case UMFPACK_ERROR_argument_missing: PyErr_SetString(PyExc_SystemError, "one or more argument missing"); return NULL; case UMFPACK_ERROR_invalid_system: PyErr_SetString(PyExc_SystemError, "matrix is not square"); return NULL; case UMFPACK_ERROR_invalid_Numeric_object: PyErr_SetString(PyExc_SystemError, "invalid Numeric object"); return NULL; } Py_INCREF(Py_None); return Py_None; } /** table of object methods */ PyMethodDef UMFPack_methods[] = { {"solve", (PyCFunction)UMFPack_solve, METH_VARARGS, solve_doc}, {"getlists", (PyCFunction)UMFPack_getlists, METH_VARARGS, getlists_doc}, {"lunz", (PyCFunction)UMFPack_Lunz, METH_VARARGS, lunz_doc}, {"lu", (PyCFunction)UMFPack_Lu, METH_VARARGS, lu_doc}, {NULL, NULL} /* sentinel */ }; /*********************************************************************** * UMFPackType methods */ static void UMFPack_dealloc(UMFPackObject *self) { umfpack_di_free_numeric(&(self->Numeric)); PyMem_Free(self->val); PyMem_Free(self->row); PyMem_Free(self->ind); PyMem_Free(self->Control); PyMem_Free(self->Info); PyObject_Del(self); } static PyObject * UMFPack_getattr(UMFPackObject *self, char *name) { if (strcmp(name, "shape") == 0) return Py_BuildValue("(i,i)", self->n, self->n); if (strcmp(name, "nnz") == 0) return Py_BuildValue("i", self->nnz); if (strcmp(name, "__members__") == 0) { char *members[] = {"shape", "nnz"}; int i; PyObject *list = PyList_New(sizeof(members)/sizeof(char *)); if (list != NULL) { for (i = 0; i < sizeof(members)/sizeof(char *); i ++) PyList_SetItem(list, i, PyString_FromString(members[i])); if (PyErr_Occurred()) { Py_DECREF(list); list = NULL; } } return list; } return Py_FindMethod(UMFPack_methods, (PyObject *)self, name); } /*********************************************************************** * UMFPackType structure */ PyTypeObject UMFPackType = { PyObject_HEAD_INIT(NULL) 0, "umfpack_context", sizeof(UMFPackObject), 0, (destructor)UMFPack_dealloc, /* tp_dealloc */ 0, /* tp_print */ (getattrfunc)UMFPack_getattr, /* 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 */ }; /*********************************************************************** * Object construction functions */ /*********************************************************************** * Module functions */ static void sortcol(int *row, double *val, int n) { int i, j, tmpint; double tmpdbl; for (i=n-1; i > 0; i--) { for (j=0; j < i; j++) { if (row[j] > row[j+1]) { /* swap row indices */ tmpint = row[j+1]; row[j+1] = row[j]; row[j] = tmpint; /* swap values */ tmpdbl = val[j+1]; val[j+1] = val[j]; val[j] = tmpdbl; } } } return; } static PyObject * newUMFPackObject(LLMatObject *matrix, int strategy, double tol2by2, int scale, double tolpivot, double tolsympivot) { UMFPackObject *self; void *Symbolic; struct llColIndex *colidx; int i, validx, curridx, status; if (SpMatrix_LLMatBuildColIndex(&colidx, matrix, 1) == 1) return NULL; self = PyObject_New(UMFPackObject, &UMFPackType); if (self == NULL) return PyErr_NoMemory(); /* initialize pointers to arrays */ self->val = NULL; self->row = NULL; self->ind = NULL; self->Control = NULL; self->Info = NULL; self->Numeric = NULL; self->n = matrix->dim[0]; if (matrix->issym) self->nnz = 2 * colidx->nzLo + colidx->nzDiag + 2 * colidx->nzUp; else self->nnz = matrix->nnz; self->val = (double *)PyMem_Malloc(self->nnz * sizeof(double)); if (self->val == NULL) goto failmemory; self->row = (int *)PyMem_Malloc(self->nnz * sizeof(int)); if (self->row == NULL) { goto failmemory; } self->ind = (int *)PyMem_Malloc((self->n + 1) * sizeof(int) ); if (self->ind == NULL) { goto failmemory; } self->ind[self->n] = self->nnz; self->Control = (double *)PyMem_Malloc(UMFPACK_CONTROL * sizeof(double)); if (self->Control == NULL) { goto failmemory; } umfpack_di_defaults(self->Control); if (strategy != -1) self->Control[UMFPACK_STRATEGY] = strategy; if (tol2by2 != -1) self->Control[UMFPACK_2BY2_TOLERANCE] = tol2by2; if (scale != -1) self->Control[UMFPACK_SCALE] = scale; if (tolpivot != -1) self->Control[UMFPACK_PIVOT_TOLERANCE] = tolpivot; if (tolsympivot != -1) self->Control[UMFPACK_SYM_PIVOT_TOLERANCE] = tolsympivot; self->Info = (double *)PyMem_Malloc(UMFPACK_INFO * sizeof(double)); if (self->Info == NULL) { goto failmemory; } validx = 0; for (i=0; i < self->n; i++) { self->ind[i] = validx; for (curridx=colidx->root[i]; curridx != -1; curridx=colidx->link[curridx]){ self->val[validx] = matrix->val[curridx]; self->row[validx++] = colidx->row[curridx]; } if (matrix->issym) { for (curridx=matrix->root[i]; curridx != -1; curridx=matrix->link[curridx]){ if (i != matrix->col[curridx]) { self->val[validx] = matrix->val[curridx]; self->row[validx++] = matrix->col[curridx]; } } } sortcol(&(self->row[self->ind[i]]), &(self->val[self->ind[i]]), validx - self->ind[i]); } status = umfpack_di_symbolic(self->n, self->n, self->ind, self->row, self->val, &Symbolic, self->Control, self->Info); switch(status) { case UMFPACK_ERROR_n_nonpositive: PyErr_SetString(PyExc_SystemError, "n must be positive"); return NULL; case UMFPACK_ERROR_out_of_memory: PyErr_SetString(PyExc_SystemError, "insufficient memory"); return NULL; case UMFPACK_ERROR_argument_missing: PyErr_SetString(PyExc_SystemError, "one or more argument missing"); return NULL; case UMFPACK_ERROR_invalid_matrix: PyErr_SetString(PyExc_SystemError, "invalid matrix"); return NULL; case UMFPACK_ERROR_internal_error: PyErr_SetString(PyExc_SystemError, "bug in umfpack"); return NULL; } status = umfpack_di_numeric(self->ind, self->row, self->val, Symbolic, &(self->Numeric), self->Control, self->Info); switch(status) { case UMFPACK_WARNING_singular_matrix: PyErr_SetString(PyExc_SystemError, "singular matrix"); return NULL; case UMFPACK_ERROR_out_of_memory: PyErr_SetString(PyExc_SystemError, "insufficient memory"); return NULL; case UMFPACK_ERROR_argument_missing: PyErr_SetString(PyExc_SystemError, "one or more argument missing"); return NULL; case UMFPACK_ERROR_invalid_Symbolic_object: PyErr_SetString(PyExc_SystemError, "invalid symbolic object"); return NULL; case UMFPACK_ERROR_different_pattern: PyErr_SetString(PyExc_SystemError, "matrix has changed since last factorization"); return NULL; } umfpack_di_free_symbolic(&Symbolic); return (PyObject *)self; failmemory: SpMatrix_LLMatDestroyColIndex(&colidx); if (self->val != NULL) PyMem_Free(self->val); if (self->row != NULL) PyMem_Free(self->row); if (self->ind != NULL) PyMem_Free(self->ind); if (self->Control != NULL) PyMem_Free(self->Control); if (self->Info != NULL) PyMem_Free(self->Info); PyObject_Del(self); return PyErr_NoMemory(); } static char factorize_doc[] = "factorize(A, ...)\n\ \n\ performs a factorization of the sparse matrix A (which is a ll_mat object) and \n\ return a umfpack_context object.\n\ \n\ arguments\n\ ---------\n\ \n\ A spmatrix.ll_mat object.\n\ Matrix to be factorized\n\ \n\ additional keyword arguments:\n\ -----------------------------\n\ \n\ strategy determines what kind of ordering and\n\ pivoting strategy that UMFPACK should use.\n\ \"UMFPACK_STRATEGY_AUTO\"\n\ \"UMFPACK_STRATEGY_UNSYMMETRIC\"\n\ \"UMFPACK_STRATEGY_SYMMETRIC\"\n\ \"UMFPACK_STRATEGY_2BY2\"\n\ \n\ tol2by2 tolerance for the 2 by 2 strategy\n\ \n\ scale scaling UMFPACK would use\n\ \"UMFPACK_SCALE_NONE\"\n\ \"UMFPACK_SCALE_SUM\"\n\ \"UMFPACK_SCALE_MAX\"\n\ \n\ tolpivot relative pivot tolerance for threshold partial\n\ pivoting with row interchanges.\n\ \n\ tolsympivot if diagonal pivoting is attempted then this\n\ parameter is used to control when the diagonal\n\ is selected in a given pivot column.\n\ "; static PyObject * factorize(PyObject *self, PyObject *args, PyObject *keywds) { LLMatObject *matrix; char *strategy="UMFPACK_STRATEGY_AUTO"; double tol2by2 = 0.1; char *scale="UMFPACK_SCALE_SUM"; double tolpivot = 0.1; double tolsympivot = 0.0; int res; int strategyval = UMFPACK_STRATEGY_AUTO, scaleval = UMFPACK_SCALE_SUM; static char *kwlist[] = {"", "strategy", "tol2by2", "scale", "tolpivot", "tolsympivot", NULL}; res = PyArg_ParseTupleAndKeywords(args, keywds, "O!|sdsdd", kwlist, &LLMatType, &matrix, &strategy, &tol2by2, &scale, &tolpivot, &tolsympivot); if (!res) return NULL; if (strcmp("UMFPACK_STRATEGY_AUTO", strategy) == 0) strategyval = UMFPACK_STRATEGY_AUTO; else if (strcmp("UMFPACK_STRATEGY_UNSYMMETRIC", strategy) == 0) strategyval = UMFPACK_STRATEGY_UNSYMMETRIC; else if (strcmp("UMFPACK_STRATEGY_SYMMETRIC", strategy) == 0) strategyval = UMFPACK_STRATEGY_SYMMETRIC; else if (strcmp("UMFPACK_STRATEGY_2BY2", strategy) == 0) strategyval = UMFPACK_STRATEGY_2BY2; if (strcmp("UMFPACK_SCALE_NONE", scale) == 0) scaleval = UMFPACK_SCALE_NONE; else if (strcmp("UMFPACK_SCALE_SUM", scale) == 0) scaleval = UMFPACK_SCALE_SUM; if (strcmp("UMFPACK_SCALE_MAX", scale) == 0) scaleval = UMFPACK_SCALE_MAX; return newUMFPackObject(matrix, strategyval, tol2by2, scaleval, tolpivot, tolsympivot); } /** table of module functions */ static PyMethodDef precon_methods[] = { {"factorize", (PyCFunction)factorize, METH_VARARGS|METH_KEYWORDS, factorize_doc}, {NULL, NULL} /* sentinel */ }; DL_EXPORT(void) initumfpack(void) { PyObject *m, *d; UMFPackType.ob_type = &PyType_Type; m = Py_InitModule("umfpack", precon_methods); d = PyModule_GetDict(m); PyDict_SetItemString(d, "UMFPackType", (PyObject *)&UMFPackType); /* initialize Numeric array module */ import_array(); /* initialize spmatrix module */ import_spmatrix(); /* No need to check the error here, the caller will do that */ } pysparse-1.1.1/Test/0000755010116400000240000000000011402271041013263 5ustar wd15dialoutpysparse-1.1.1/Test/testSuperlu.py0000644010116400000240000002265311402267741016220 0ustar wd15dialoutimport math, unittest import numpy from pysparse import poisson from pysparse.pysparseMatrix import PysparseMatrix, PysparseIdentityMatrix, PysparseSpDiagsMatrix from pysparse.pysparseSuperLU import PysparseSuperLUSolver import sys def macheps(): "compute machine epsilon" eps = 1.0 while (1.0 + eps > 1.0): eps /= 2.0 return 2.0 * eps # # Tests that are commented out work fine but take a long time... # class SpDiagsTestCase(unittest.TestCase): def setUp(self): self.n = 10000 self.e = numpy.ones(self.n) self.A = PysparseSpDiagsMatrix(size=self.n, vals=(-2*self.e,self.e,2*self.e), pos=(-1,0,1)) self.b = self.A * self.e self.tol = 100*macheps() self.LU = None self.relerr = 0.0 self.descr = '' self.fmt = '\t%10s %8.2e %8.2e %8d %8d %6.2f %6.2f\n' def tearDown(self): self.LU.fetch_lunz() sys.stdout.write(self.fmt % (self.descr, self.relerr, self.tol, self.A.getNnz(), self.LU.lunz, self.LU.factorizationTime, self.LU.solutionTime)) def computeError(self, x): self.relerr = numpy.linalg.norm(x - self.e, ord=numpy.inf) return self.relerr #def testVanilla(self): # self.descr = 'spdgs-dflt' # self.LU = PysparseSuperLUSolver(self.A) # self.LU.solve(self.b) # self.failUnless(self.computeError(self.LU.sol) < self.tol) def testTrivialThresh(self): self.descr = 'spdgs-trsh' self.LU = PysparseSuperLUSolver(self.A, diag_pivot_thresh=0.5) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) #def testTrivialRelax(self): # self.descr = 'spdgs-relx' # self.LU = PysparseSuperLUSolver(self.A, relax=20) # self.LU.solve(self.b) # self.failUnless(self.computeError(self.LU.sol) < self.tol) #def testTrivialPanel(self): # self.descr = 'spdgs-size' # self.LU = PysparseSuperLUSolver(self.A, panel_size=1) # self.LU.solve(self.b) # self.failUnless(self.computeError(self.LU.sol) < self.tol) def testTrivialperm0(self): self.descr = 'spdgs-prm0' self.LU = PysparseSuperLUSolver(self.A, permc_spec=0) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testTrivialperm1(self): self.descr = 'spdgs-prm1' self.LU = PysparseSuperLUSolver(self.A, permc_spec=1) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) #def testTrivialperm2(self): # self.descr = 'spdgs-prm2' # self.LU = PysparseSuperLUSolver(self.A, permc_spec=2) # self.LU.solve(self.b) # self.failUnless(self.computeError(self.LU.sol) < self.tol) def testTrivialperm3(self): self.descr = 'spdgs-prm3' self.LU = PysparseSuperLUSolver(self.A, permc_spec=3) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) class Poisson1dTestCase(unittest.TestCase): def setUp(self): self.n = 50000 self.A = PysparseMatrix(matrix=poisson.poisson1d_sym(self.n)) self.x_exact = numpy.ones(self.n)/math.sqrt(self.n) self.normx = 1.0/math.sqrt(self.n) self.b = self.A * self.x_exact lmbd_min = 4.0 * math.sin(math.pi/2.0/self.n) ** 2 lmbd_max = 4.0 * math.sin((self.n - 1)*math.pi/2.0/self.n) ** 2 cond = lmbd_max/lmbd_min self.tol = cond * macheps() self.LU = None self.relerr = 0.0 self.descr = '' self.fmt = '\t%10s %8.2e %8.2e %8d %8d %6.2f %6.2f\n' def tearDown(self): self.LU.fetch_lunz() sys.stdout.write(self.fmt % (self.descr, self.relerr, self.tol, self.A.getNnz(), self.LU.lunz, self.LU.factorizationTime, self.LU.solutionTime)) def computeError(self, x): absErr = numpy.linalg.norm(x-self.x_exact, ord=numpy.inf) self.relerr = absErr/(1+self.normx) return self.relerr def testPoisson1dDefault(self): self.descr = 'poi1d-dflt' self.LU = PysparseSuperLUSolver(self.A) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dThresh(self): self.descr = 'poi1d-trsh' self.LU = PysparseSuperLUSolver(self.A, diag_pivot_thresh=0.5) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dRelax(self): self.descr = 'poi1d-relx' self.LU = PysparseSuperLUSolver(self.A, relax=20) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dPanel(self): self.descr = 'poi1d-size' self.LU = PysparseSuperLUSolver(self.A, panel_size=1) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dperm0(self): self.descr = 'poi1d-prm0' self.LU = PysparseSuperLUSolver(self.A, permc_spec=0) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dperm1(self): self.descr = 'poi1d-prm1' self.LU = PysparseSuperLUSolver(self.A, permc_spec=1) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dperm2(self): self.descr = 'poi1d-prm2' self.LU = PysparseSuperLUSolver(self.A, permc_spec=2) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dperm3(self): self.descr = 'poi1d-prm3' self.LU = PysparseSuperLUSolver(self.A, permc_spec=3) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) class Poisson2dTestCase(unittest.TestCase): def setUp(self): self.n = 200 self.A = PysparseMatrix(matrix=poisson.poisson2d_sym_blk(self.n)) self.x_exact = numpy.ones(self.n*self.n)/self.n self.normx = 1.0/self.n self.b = self.A * self.x_exact h = 1.0 / self.n lmbd_min = 4.0/h/h * (math.sin(math.pi*h/2.0) ** 2 + math.sin(math.pi*h/2.0) ** 2) lmbd_max = 4.0/h/h * (math.sin((self.n - 1)*math.pi*h/2.0) ** 2 + math.sin((self.n - 1)*math.pi*h/2.0) ** 2) cond = lmbd_max/lmbd_min self.tol = cond * macheps() self.LU = None self.relerr = 0.0 self.descr = '' self.fmt = '\t%10s %8.2e %8.2e %8d %8d %6.2f %6.2f\n' def tearDown(self): self.LU.fetch_lunz() sys.stdout.write(self.fmt % (self.descr, self.relerr, self.tol, self.A.getNnz(), self.LU.lunz, self.LU.factorizationTime, self.LU.solutionTime)) def computeError(self, x): absErr = numpy.linalg.norm(x-self.x_exact, ord=numpy.inf) self.relerr = absErr/(1+self.normx) return self.relerr def testPoisson2dDefault(self): self.descr = 'poi2d-dftl' self.LU = PysparseSuperLUSolver(self.A) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dThresh(self): self.descr = 'poi2d-trsh' self.LU = PysparseSuperLUSolver(self.A, diag_pivot_thresh=0.5) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dRelax(self): self.descr = 'poi2d-relx' self.LU = PysparseSuperLUSolver(self.A, relax=20) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dPanel(self): self.descr = 'poi2d-size' self.LU = PysparseSuperLUSolver(self.A, panel_size=1) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dperm0(self): self.descr = 'poi2d-prm0' self.LU = PysparseSuperLUSolver(self.A, permc_spec=0) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dperm1(self): self.descr = 'poi2d-prm1' self.LU = PysparseSuperLUSolver(self.A, permc_spec=1) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dperm2(self): self.descr = 'poi2d-prm2' self.LU = PysparseSuperLUSolver(self.A, permc_spec=2) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dperm3(self): self.descr = 'poi2d-prm3' self.LU = PysparseSuperLUSolver(self.A, permc_spec=3) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) if __name__ == '__main__': headfmt = '\t%10s %8s %8s %8s %8s %6s %6s' header = headfmt % ('Test','RelErr','Tol','nnz(A)', 'nnz(L+U)','Fact','Solve') lhead = len(header) sys.stderr.write(header + '\n') sys.stderr.write('\t' + '-' * lhead + '\n') unittest.main() pysparse-1.1.1/Test/testUmfpack.py0000644010116400000240000001665411402267741016153 0ustar wd15dialoutimport math, unittest import numpy from pysparse import poisson from pysparse.pysparseMatrix import PysparseMatrix, PysparseIdentityMatrix, PysparseSpDiagsMatrix from pysparse.pysparseUmfpack import PysparseUmfpackSolver import sys def macheps(): "compute machine epsilon" eps = 1.0 while (1.0 + eps > 1.0): eps /= 2.0 return 2.0 * eps class SpDiagsTestCase(unittest.TestCase): def setUp(self): self.n = 10000 self.e = numpy.ones(self.n) self.A = PysparseSpDiagsMatrix(size=self.n, vals=(-2*self.e,self.e,2*self.e), pos=(-1,0,1)) self.b = self.A * self.e self.tol = 100*macheps() self.LU = None self.err = 0.0 self.fmt = '\t%8.2e %8.2e %8d %8d %8d %6.2f %6.2f\n' def tearDown(self): self.LU.fetch_lunz() sys.stdout.write(self.fmt % (self.err, self.tol, self.A.getNnz(), self.LU.lnz, self.LU.unz, self.LU.factorizationTime, self.LU.solutionTime)) def computeError(self, x): self.err = numpy.linalg.norm(x - self.e, ord=numpy.inf) return self.err def testVanilla(self): self.LU = PysparseUmfpackSolver(self.A) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testUnsymmetric(self): self.LU = PysparseUmfpackSolver(self.A, strategy='unsymmetric') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testSymmetric(self): self.LU = PysparseUmfpackSolver(self.A, strategy='symmetric') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def test2by2(self): self.LU = PysparseUmfpackSolver(self.A, strategy='2by2') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testNoScaling(self): self.LU = PysparseUmfpackSolver(self.A, scale='none') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testScaleMax(self): self.LU = PysparseUmfpackSolver(self.A, scale='max') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) class Poisson1dTestCase(unittest.TestCase): def setUp(self): self.n = 50000 self.B = PysparseMatrix( matrix=poisson.poisson1d(self.n) ) self.x_exact = numpy.ones(self.n)/math.sqrt(self.n) self.normx = 1.0/math.sqrt(self.n) self.b = self.B * self.x_exact lmbd_min = 4.0 * math.sin(math.pi/2.0/self.n) ** 2 lmbd_max = 4.0 * math.sin((self.n - 1)*math.pi/2.0/self.n) ** 2 cond = lmbd_max/lmbd_min self.tol = cond * macheps() self.relerr = 0.0 self.nnz = self.B.getNnz() self.LU = None self.fmt = '\t%8.2e %8.2e %8d %8d %8d %6.2f %6.2f\n' def computeError(self, x): absErr = numpy.linalg.norm(x - self.x_exact, ord=numpy.inf) self.relerr = absErr/(1 + self.normx) return self.relerr def tearDown(self): self.LU.fetch_lunz() sys.stdout.write(self.fmt % (self.relerr, self.tol, self.nnz, self.LU.lnz, self.LU.unz, self.LU.factorizationTime, self.LU.solutionTime)) def testPoisson1dDefault(self): self.LU = PysparseUmfpackSolver(self.B) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dUnsymmetric(self): self.LU = PysparseUmfpackSolver(self.B, strategy='unsymmetric') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dSymmetric(self): self.LU = PysparseUmfpackSolver(self.B, strategy='symmetric') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1d2by2(self): self.LU = PysparseUmfpackSolver(self.B, strategy='2by2') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dNoScaling(self): self.LU = PysparseUmfpackSolver(self.B, scale='none') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson1dScaleMax(self): self.LU = PysparseUmfpackSolver(self.B, scale='max') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) class Poisson2dTestCase(unittest.TestCase): def setUp(self): self.n = 200 self.B = PysparseMatrix( matrix=poisson.poisson2d(self.n) ) self.x_exact = numpy.ones(self.n*self.n)/self.n self.normx = 1.0/self.n self.b = self.B * self.x_exact h = 1.0/self.n lmbd_min = 4.0/h/h * (math.sin(math.pi*h/2.0) ** 2 + math.sin(math.pi*h/2.0) ** 2) lmbd_max = 4.0/h/h * (math.sin((self.n - 1)*math.pi*h/2.0) ** 2 + math.sin((self.n - 1)*math.pi*h/2.0) ** 2) cond = lmbd_max/lmbd_min self.tol = cond * macheps() self.relerr = 0.0 self.nnz = self.B.getNnz() self.LU = None self.fmt = '\t%8.2e %8.2e %8d %8d %8d %6.2f %6.2f\n' def computeError(self, x): absErr = numpy.linalg.norm(x - self.x_exact, ord=numpy.inf) self.relerr = absErr/(1 + self.normx) return self.relerr def tearDown(self): self.LU.fetch_lunz() sys.stdout.write(self.fmt % (self.relerr, self.tol, self.nnz, self.LU.lnz, self.LU.unz, self.LU.factorizationTime, self.LU.solutionTime)) def testPoisson2dDefault(self): self.LU = PysparseUmfpackSolver(self.B) self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dUnsymmetric(self): self.LU = PysparseUmfpackSolver(self.B, strategy='unsymmetric') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dSymmetric(self): self.LU = PysparseUmfpackSolver(self.B, strategy='symmetric') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2d2by2(self): self.LU = PysparseUmfpackSolver(self.B, strategy='2by2') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dNoScaling(self): self.LU = PysparseUmfpackSolver(self.B, scale='none') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) def testPoisson2dScaleMax(self): self.LU = PysparseUmfpackSolver(self.B, scale='max') self.LU.solve(self.b) self.failUnless(self.computeError(self.LU.sol) < self.tol) if __name__ == '__main__': headfmt = '\t%8s %8s %8s %8s %8s %6s %6s' header = headfmt % ('RelErr','Tol','nnz(A)','nnz(L)', 'nnz(U)','Fact','Solve') lhead = len(header) sys.stderr.write(header + '\n') sys.stderr.write('\t' + '-' * lhead + '\n') unittest.main() pysparse-1.1.1/Test/test_sparray.py0000644010116400000240000000224611402267741016375 0ustar wd15dialout# -*- coding: iso-8859-1 -*- import unittest from pysparse.sparray import sparray class test_sparray(unittest.TestCase): def testinit(self): a = sparray((5,5)) a = sparray((5,5), {(3,3):13}, (0,0)) a = sparray((5,5), {(123,-48):13}, (120,-50)) self.assertEqual(a.length, 25) #tableaux 1D a=sparray(5) a=sparray(5, {13:10}, 9) self.assertEqual(a.is1D,True) def testsetitem(self): a = sparray((5,5)) a[5] = 2 a[3,3] = 7 self.assertEqual(a.comp((3,3)), 18) self.assertEqual(a.decomp(17), (3,2)) self.assertEqual(a[3,3], a[18]) a[:,3] = (1,2,3,4,5) self.assertEqual(a[3,3], 4) def testgetitem(self): a = sparray((5,5)) a[:,3] = (1,2,3,4,5) import numpy self.assertTrue(numpy.allclose(a[:,3], map(float, (1,2,3,4,5)))) a[3,3] = 7 self.assertEqual(a[3,3], 7) self.assertTrue(numpy.allclose(a[3,:], map(float, (0,0,0,7,0)))) if __name__=='__main__': suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(test_sparray)) unittest.TextTestRunner(verbosity=2).run(suite) pysparse-1.1.1/Test/test_spmatrix.py0000644010116400000240000002027311402267742016564 0ustar wd15dialoutimport unittest import math, random from pysparse import spmatrix from pysparse import spmatrix_util from pysparse import poisson import numpy import numpy.oldnumeric.random_array as RandomArray ##import Numeric, RandomArray def llmat_isEqual(aMat, bMat): if aMat.issym and not bMat.issym: temp = aMat; aMat = bMat; bMat = temp zMat = aMat.copy() zMat.shift(-1.0, bMat) return zMat.nnz == 0 class LLMatSimpleTestCase(unittest.TestCase): def setUp(self): self.n = 10 self.A = spmatrix.ll_mat(self.n, self.n) self.S = spmatrix.ll_mat_sym(self.n) def testCreate(self): self.failUnless(self.A.shape == (self.n, self.n)) self.failUnless(self.A.nnz == 0) self.failUnless(not self.A.issym) self.failUnless(self.S.shape == (self.n, self.n)) self.failUnless(self.S.nnz == 0) self.failUnless(self.S.issym) def testEntry(self): def assignUP(): self.S[0,1] = 1.0 def assignLeft(): self.S[-11,0] = 1.0 def assignRight(): self.S[10,0] = 1.0 def assignTop(): self.S[0,-11] = 1.0 def assignBottom(): self.S[0,10] = 1.0 self.A[0,0] = 1.0 self.S[0,0] = 1.0 self.failUnless(self.A[0,0] == 1.0) self.failUnless(self.A.nnz == 1) self.failUnless(self.S[0,0] == 1.0) self.failUnless(self.S.nnz == 1) self.failUnlessRaises(IndexError, assignUP) self.A[0,0] += 1.0 self.failUnless(self.A[0,0] == 2.0) self.failUnless(self.A.nnz == 1) self.A[0,0] -= 2.0 self.failUnless(self.A[0,0] == 0.0) self.failUnless(self.A.nnz == 0) # indices out of bounds #for f in [assignLeft, assignRight, assignTop, assignBottom]: #for f in [assignRight, assignTop, assignBottom]: # self.failUnlessRaises(IndexError, f) self.failUnlessRaises(IndexError, assignRight) self.failUnlessRaises(IndexError, assignTop) self.failUnlessRaises(IndexError, assignBottom) # negative indices I = spmatrix.ll_mat(10, 10, 100) for i in range(10): for j in range(10): I[i,j] = 10*i + j for i in range(-10, 0): for j in range(-10, 0): self.failUnless(I[i,j] == I[10+i,10+j]) class LLMatPoissonTestCase(unittest.TestCase): def setUp(self): self.n = 20 self.A = poisson.poisson2d(self.n) self.S = poisson.poisson2d_sym(self.n) self.B = poisson.poisson2d_sym_blk(self.n) def testBasic(self): self.failUnless(self.S.nnz == self.n*(3*self.n - 2)) self.failUnless(self.A.nnz == self.n*(5*self.n - 4)) self.failUnless(llmat_isEqual(self.A, self.A)) self.failUnless(llmat_isEqual(self.S, self.S)) self.failUnless(llmat_isEqual(self.A, self.S)) self.failUnless(llmat_isEqual(self.A, self.B)) def testSubmatrix(self): n = self.n Psym = poisson.poisson1d_sym(n) P = poisson.poisson1d(n) for i in range(n): P[i,i] = 4.0 Psym[i,i] = 4.0 # read and test diagonal blocks for i in range(n): self.failUnless(llmat_isEqual(self.A[n*i:n*(i+1),n*i:n*(i+1)], P)) self.failUnless(llmat_isEqual(self.S[n*i:n*(i+1),n*i:n*(i+1)], P)) self.failUnless(llmat_isEqual(self.A[n*i:n*(i+1),n*i:n*(i+1)], Psym)) self.failUnless(llmat_isEqual(self.S[n*i:n*(i+1),n*i:n*(i+1)], Psym)) # store and get diagonal blocks R = spmatrix_util.ll_mat_rand(n*n, n*n, 0.01) # random matrix for i in range(n): R[n*i:n*(i+1),n*i:n*(i+1)] = P self.failUnless(llmat_isEqual(R[n*i:n*(i+1),n*i:n*(i+1)], P)) R[n*i:n*(i+1),n*i:n*(i+1)] = Psym self.failUnless(llmat_isEqual(R[n*i:n*(i+1),n*i:n*(i+1)], Psym)) # store and get off-diagonal blocks for i in range(n-1): R[n*i:n*(i+1),n*(i+1):n*(i+2)] = P self.failUnless(llmat_isEqual(R[n*i:n*(i+1),n*(i+1):n*(i+2)], P)) R[n*i:n*(i+1),n*(i+1):n*(i+2)] = Psym self.failUnless(llmat_isEqual(R[n*i:n*(i+1),n*(i+1):n*(i+2)], Psym)) # store and get diagonal blocks in symmetric matrix R = spmatrix.ll_mat_sym(n*n) for i in range(n): R[n*i:n*(i+1),n*i:n*(i+1)] = Psym self.failUnless(llmat_isEqual(R[n*i:n*(i+1),n*i:n*(i+1)], Psym)) # store and get off-diagonal blocks in symmetric matrix for i in range(n-1): R[n*(i+1):n*(i+2),n*i:n*(i+1)] = P self.failUnless(llmat_isEqual(R[n*(i+1):n*(i+2),n*i:n*(i+1)], P)) R[n*(i+1):n*(i+2),n*i:n*(i+1)] = Psym self.failUnless(llmat_isEqual(R[n*(i+1):n*(i+2),n*i:n*(i+1)], Psym)) class LLMatDeleteRowColsTestCase(unittest.TestCase): def setUp(self): import numpy self.n = 30 self.P = poisson.poisson1d(self.n) for i in range(self.n): self.P[i,i] = 4.0 self.A = poisson.poisson2d(self.n) self.S = poisson.poisson2d_sym(self.n) self.I = spmatrix.ll_mat_sym(self.n) for i in range(self.n): self.I[i,i] = -1.0 self.mask = numpy.zeros(self.n**2, 'l') self.mask[self.n/2*self.n:(self.n/2 + 1)*self.n] = 1 self.mask1 = numpy.zeros(self.n**2, 'l') self.mask1[(self.n/2 + 1)*self.n:(self.n/2 + 2)*self.n] = 1 def testDeleteRowColsSym(self): self.S.delete_rowcols(self.mask) self.failUnless(llmat_isEqual(self.S, self.P)) def testDeleteRowColsGen(self): self.A.delete_rowcols(self.mask) self.failUnless(llmat_isEqual(self.A, self.P)) def testDeleteRowColsGen2Step(self): self.A.delete_rows(self.mask) self.A.delete_cols(self.mask) self.failUnless(llmat_isEqual(self.A, self.P)) def testDeleteRowColsGen2StepOff(self): self.A.delete_rows(self.mask) self.A.delete_cols(self.mask1) self.failUnless(llmat_isEqual(self.A, self.I)) def testCompress(self): self.A.delete_rows(self.mask) self.A.delete_cols(self.mask1) norm1 = self.A.norm('fro') self.A.compress() norm2 = self.A.norm('fro') self.failUnless(norm1 == norm2) def testCompressStress(self): n = 20 A = spmatrix.ll_mat(n, n) for k in range(20): for i in range(n*n/2): i = random.randrange(n) j = random.randrange(n) A[i, j] = 1.0 for i in range(n*n/2): i = random.randrange(n) j = random.randrange(n) A[i, j] = 0.0 class LLMatNorm(unittest.TestCase): def setUp(self): self.n = 30 def testNormGeneral(self): A = poisson.poisson2d(self.n) self.failUnless(A.norm('1') == 8) self.failUnless(A.norm('inf') == 8) self.failUnless(poisson.poisson1d(3).norm('fro') == 4) def testNormSymmetric(self): A = spmatrix.ll_mat_sym(4) A[0,0] = 1; A[1,1] = 2; A[2,2] = 3; A[3,3] = 4; A[1,0] = 3; A[2,0] = 2; A[3,0] = 2; self.failUnless(A.norm('fro') == 8) def testNormSymmetricNotImplemented(self): def f(): return A.norm('1') def g(): return A.norm('inf') A = poisson.poisson2d_sym(self.n) self.failUnlessRaises(NotImplementedError, f) self.failUnlessRaises(NotImplementedError, g) class LLMatMatMul(unittest.TestCase): def testRandomMat(self): eps = 2.2204460492503131E-16 n = 30; m = 60; k = 30 for i in range(100): A = spmatrix_util.ll_mat_rand(n, k, 0.9) B = spmatrix_util.ll_mat_rand(k, m, 0.4) C = spmatrix.matrixmultiply(A, B) t = numpy.zeros(k, 'd') y1 = numpy.zeros(n, 'd') y2 = numpy.zeros(n, 'd') for s in range(10): x = RandomArray.random((m, )) C.matvec(x, y1) B.matvec(x, t) A.matvec(t, y2) self.failUnless(math.sqrt(numpy.dot(y1 - y2, y1 - y2)) < eps * n*m*k) if __name__ == '__main__': unittest.main() pysparse-1.1.1/Test/test_superlu.py0000644010116400000240000001563711402267740016422 0ustar wd15dialoutimport math, unittest import numpy from pysparse import spmatrix, superlu from pysparse import poisson def residual(A, x, b): n = A.shape[0] r = numpy.zeros(n, 'd') A.matvec(x, r) r -= b return math.sqrt(numpy.dot(r, r)) def error(x, y): n = len(x) t = x.copy(); t -= y return math.sqrt(numpy.dot(t, t)) def speye(n): A = spmatrix.ll_mat_sym(n, n) for i in xrange(n): A[i,i] = 1.0 return A def macheps(): "compute machine epsilon" eps = 1.0 while (1.0 + eps > 1.0): eps /= 2.0 return 2.0 * eps class EyeTestCase(unittest.TestCase): def setUp(self): self.n = 10000 self.A = speye(self.n).to_csr() self.b = numpy.ones(self.n, 'd') self.x = numpy.zeros(self.n, 'd') def testTrivial(self): luA = superlu.factorize(self.A) luA.solve(self.b, self.x) self.failUnless(residual(self.A, self.x, self.b) == 0.0) luA = superlu.factorize(self.A, diag_pivot_thresh=0.0) luA.solve(self.b, self.x) self.failUnless(residual(self.A, self.x, self.b) == 0.0) luA = superlu.factorize(self.A, relax=20) luA.solve(self.b, self.x) self.failUnless(residual(self.A, self.x, self.b) == 0.0) luA = superlu.factorize(self.A, panel_size=1) luA.solve(self.b, self.x) self.failUnless(residual(self.A, self.x, self.b) == 0.0) for permc_spec in [0, 1, 2, 3]: luA = superlu.factorize(self.A, permc_spec=permc_spec) luA.solve(self.b, self.x) self.failUnless(residual(self.A, self.x, self.b) == 0.0) class Poisson1dTestCase(unittest.TestCase): def setUp(self): self.n = 50000 self.B = poisson.poisson1d(self.n).to_csr() self.b = numpy.zeros(self.n, 'd') self.x = numpy.zeros(self.n, 'd') self.x_exact = numpy.ones(self.n, 'd') self.x_exact /= math.sqrt(self.n) self.B.matvec(self.x_exact, self.b) lmbd_min = 4.0 * math.sin(math.pi/2.0/self.n) ** 2 lmbd_max = 4.0 * math.sin((self.n - 1)*math.pi/2.0/self.n) ** 2 cond = lmbd_max/lmbd_min self.tol = cond * macheps() def testPoisson1dDefault(self): luA = superlu.factorize(self.B) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson1dNoPivot(self): luA = superlu.factorize(self.B, diag_pivot_thresh=0.0) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson1dRelax(self): luA = superlu.factorize(self.B, relax=20) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson1dSmallPanel(self): luA = superlu.factorize(self.B, panel_size=1) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson1dOrigOrdering(self): luA = superlu.factorize(self.B, permc_spec=0) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson1dMMD_AtimesA(self): luA = superlu.factorize(self.B, permc_spec=1) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson1dMMD_AplusA(self): luA = superlu.factorize(self.B, permc_spec=2) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson1dCOLAMD(self): luA = superlu.factorize(self.B, permc_spec=3) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) class Poisson2dTestCase(unittest.TestCase): def setUp(self): self.n = 200 self.B = poisson.poisson2d(self.n).to_csr() self.b = numpy.zeros(self.n*self.n, 'd') self.x = numpy.zeros(self.n*self.n, 'd') self.x_exact = numpy.ones(self.n*self.n, 'd') self.x_exact /= math.sqrt(self.n*self.n) self.B.matvec(self.x_exact, self.b) h = 1.0 / self.n lmbd_min = 4.0/h/h * (math.sin(math.pi*h/2.0) ** 2 + math.sin(math.pi*h/2.0) ** 2) lmbd_max = 4.0/h/h * (math.sin((self.n - 1)*math.pi*h/2.0) ** 2 + math.sin((self.n - 1)*math.pi*h/2.0) ** 2) cond = lmbd_max/lmbd_min self.tol = cond * macheps() def testPoisson2dDefault(self): luA = superlu.factorize(self.B) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson2dNoPivot(self): luA = superlu.factorize(self.B, diag_pivot_thresh=0.0) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson2dRelax(self): luA = superlu.factorize(self.B, relax=20) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson2dSmallPanel(self): luA = superlu.factorize(self.B, panel_size=1) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson2dOrigOrdering(self): luA = superlu.factorize(self.B, permc_spec=0) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson2dMMD_AtimesA(self): luA = superlu.factorize(self.B, permc_spec=1) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson2dMMD_AplusA(self): luA = superlu.factorize(self.B, permc_spec=2) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) def testPoisson2dCOLAMD(self): luA = superlu.factorize(self.B, permc_spec=3) luA.solve(self.b, self.x) print error(self.x, self.x_exact), self.tol, luA.nnz self.failUnless(error(self.x, self.x_exact) < self.tol) if __name__ == '__main__': unittest.main() pysparse-1.1.1/amd/0000755010116400000240000000000011402271041013105 5ustar wd15dialoutpysparse-1.1.1/amd/amd.h0000644010116400000240000003044111402270273014027 0ustar wd15dialout/* ========================================================================== */ /* === AMD: approximate minimum degree ordering ============================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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 "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 unchanged. They compute the identical ordering as described in * the above paper. */ #ifndef AMD_H #define AMD_H int amd_order ( /* returns 0 if OK, negative value if error */ 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 */ ) ; long amd_l_order ( /* see above for description of arguments */ long n, const long Ap [ ], const long Ai [ ], long P [ ], double Control [ ], double Info [ ] ) ; /* Input arguments (not modified): * * n: the matrix A is n-by-n. * Ap: an int/long array of size n+1, containing the column pointers of A. * Ai: an int/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/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]. * The row indices must appear in ascending order in each column, and there * must not be any duplicate entries. 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. For all j in the range 0 to n-1, * and for all p in the range Ap [j] to Ap [j+1]-2, Ai [p] < Ai [p+1] must * hold. Ai [0..nz-1] must be in the range 0 to n-1. To avoid integer * overflow, (2.4*nz + 8*n) < INT_MAX / sizeof (int) for must hold for the * "int" version. (2.4*nz + 8*n) < LONG_MAX / sizeof (long) must hold * for the "long" version. 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. * * 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_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. */ /* -------------------------------------------------------------------------- */ /* 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 2.4*nz+9*n is too large */ #define AMD_INVALID -2 /* input arguments are not valid */ #endif pysparse-1.1.1/amd/amd_1.c0000644010116400000240000001327311402270271014244 0ustar wd15dialout/* ========================================================================== */ /* === AMD_1 ================================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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_aat). */ #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)) ; /* 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) ; } pysparse-1.1.1/amd/amd_2.c0000644010116400000240000017634111402270272014254 0ustar wd15dialout/* ========================================================================== */ /* === AMD_2 ================================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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" 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 "long" versions are provided. In the descriptions below * and integer is and "int" or "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) 2003 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 DMS-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, x, 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, LONG_MAX - n for the * "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 ; wflg = 2 ; mindeg = 0 ; ncmpa = 0 ; nel = 0 ; lemax = 0 ; /* this is called dmax in the Fortran version */ #ifdef TEST_FOR_INTEGER_OVERFLOW /* for testing only */ wbig = 3*n ; #else /* normal operation */ wbig = Int_MAX - n ; #endif /* 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 ; } if (alpha < 0) { /* no dense rows/columns */ dense = n ; } else { dense = alpha * sqrt ((double) n) ; } dense = MAX (16, dense) ; dense = MIN (n, dense) ; AMD_DEBUG1 (("AMD (debug), alpha %g, aggr. "ID"\n", alpha, aggressive)) ; for (i = 0 ; i < n ; i++) { Last [i] = EMPTY ; Head [i] = EMPTY ; Next [i] = EMPTY ; /* if seperate 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"\n", nel)) ; AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last, Head, Elen, Degree, W, -1) ; #endif /* ---------------------------------------------------------------------- */ /* initialize degree lists and eliminate dense and empty rows */ /* ---------------------------------------------------------------------- */ ndense = 0 ; /* for (i = n-1 ; i >= 0 ; i--) */ 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 */ if (wflg >= wbig) { for (x = 0 ; x < n ; x++) { if (W [x] != 0) W [x] = 1 ; } wflg = 2 ; } /* ========================================================================== */ /* 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] + Iw [Pe [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 seperate 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 ; if (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 */ /* ========================================================================== */ /* 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 seperate 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) ; /* skop 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 ; } /* -------------------------------------------------------------------------- * 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.) * -------------------------------------------------------------------------- */ for (i = 0 ; i < n ; i++) { Pe [i] = FLIP (Pe [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, and 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)) ; } } pysparse-1.1.1/amd/amd_aat.c0000644010116400000240000001131511402270273014646 0ustar wd15dialout/* ========================================================================== */ /* === AMD_aat ============================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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). Assume the input * matrix has no errors. */ #include "amd_internal.h" GLOBAL Int 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, nzaat ; double sym ; #ifndef NDEBUG AMD_debug_init ("AMD AAT") ; for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ; ASSERT (AMD_valid (n, n, Ap, Ai)) ; #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 = ((double) (2 * 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) = "ID"\n", 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) ; } pysparse-1.1.1/amd/amd_control.c0000644010116400000240000000335011402270272015560 0ustar wd15dialout/* ========================================================================== */ /* === AMD_control ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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: approximate minimum degree ordering, parameters:\n" " dense row parameter: %g\n", 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\n")) ; } else { PRINTF ((" aggressive absorption: no\n\n")) ; } } pysparse-1.1.1/amd/amd_defaults.c0000644010116400000240000000215011402270274015706 0ustar wd15dialout/* ========================================================================== */ /* === AMD_defaults ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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" 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 ; } } pysparse-1.1.1/amd/amd_dump.c0000644010116400000240000001167411402270274015057 0ustar wd15dialout/* ========================================================================== */ /* === AMD_dump ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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) ; 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 < 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 < 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": ", 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 pysparse-1.1.1/amd/amd_info.c0000644010116400000240000001003711402270274015035 0ustar wd15dialout/* ========================================================================== */ /* === AMD_info ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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 ; 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 (( "\namd: approximate minimum degree ordering, results:\n" " 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 { 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)) ; } } pysparse-1.1.1/amd/amd_internal.h0000644010116400000240000002327611402270272015732 0ustar wd15dialout/* ========================================================================== */ /* === amd_internal.h ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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. Use amd.h instead. * * The following compile-time definitions affect how AMD is compiled. * * -DMATLAB_MEX_FILE * * This flag is turned on when compiling the amd mexFunction for * use in MATLAB. * * -DMATHWORKS * * This flag is turned on when compiling amd as a built-in routine * in MATLAB. Internal routines utMalloc, utFree, utRealloc, and * utPrintf are used, and the MathWorks "util.h" file is included. * This option is intended for use by The MathWorks, Inc., only. * * -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. * * You can change the memory allocator routines by editting the definitions * of ALLOCATE and FREE, below, and recompilng AMD. */ /* ========================================================================== */ /* === NDEBUG =============================================================== */ /* ========================================================================== */ /* 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: malloc, free, realloc (when not compiling for MATLAB) */ #include /* from stdio.h: printf, NULL. When in debug mode: fopen, fscanf */ #include /* from limits.h: INT_MAX and LONG_MAX */ #include /* from math.h: sqrt */ #include /* -------------------------------------------------------------------------- */ /* MATLAB include files */ /* -------------------------------------------------------------------------- */ #ifdef MATHWORKS #include "util.h" #endif #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 /* 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). */ #ifdef NULL #undef NULL #endif #define NULL 0 /* -------------------------------------------------------------------------- */ /* integer type for AMD: int or long */ /* -------------------------------------------------------------------------- */ #if defined (DLONG) || defined (ZLONG) #define Int long #define ID "%ld" #define Int_MAX LONG_MAX #define Int_MIN LONG_MIN #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 #else #define Int int #define ID "%d" #define Int_MAX INT_MAX #define Int_MIN INT_MIN #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 #endif /* ========================================================================== */ /* === Memory allocator ===================================================== */ /* ========================================================================== */ /* The MATLAB mexFunction uses MATLAB's memory manager, while the C-callable */ /* AMD routine uses the ANSI C malloc, free, and realloc routines. */ #ifdef MATLAB_MEX_FILE #define ALLOCATE mxMalloc #define FREE mxFree #else #ifdef MATHWORKS /* Compiling as a built-in routine. Since out-of-memory conditions are checked * after every allocation, we can use ut* routines here. */ #define ALLOCATE utMalloc #define FREE utFree #else /* use the ANSI C memory allocation routines */ #define ALLOCATE malloc #define FREE free #endif #endif /* ========================================================================== */ /* === PRINTF macro ========================================================= */ /* ========================================================================== */ /* All output goes through the PRINTF macro. */ #ifdef MATLAB_MEX_FILE #define PRINTF(params) { (void) mexPrintf params ; } #else #ifdef MATHWORKS #define PRINTF(params) { (void) utPrintf params ; } #else #define PRINTF(params) { (void) printf params ; } #endif #endif /* -------------------------------------------------------------------------- */ /* AMD routine definitions (user-callable) */ /* -------------------------------------------------------------------------- */ #include "amd.h" /* -------------------------------------------------------------------------- */ /* AMD routine definitions (not user-callable) */ /* -------------------------------------------------------------------------- */ GLOBAL Int AMD_valid ( Int n_row, Int n_col, const Int Ap [ ], const Int Ai [ ] ) ; GLOBAL Int 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_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 [ ] ) ; 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 ) ; /* -------------------------------------------------------------------------- */ /* debugging definitions */ /* -------------------------------------------------------------------------- */ /* from assert.h: assert macro */ #if !defined (MATHWORKS) && !defined (MATLAB_MEX_FILE) #include #endif #ifndef NDEBUG GLOBAL 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 MATLAB_MEX_FILE #define ASSERT(expression) (mxAssert ((expression), "")) #else #ifdef MATHWORKS #define ASSERT(expression) (utAssert (expression)) #else #define ASSERT(expression) (assert (expression)) #endif #endif /* MATLAB_MEX_FILE */ #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 #define AMD_DEBUG0(params) #define AMD_DEBUG1(params) #define AMD_DEBUG2(params) #define AMD_DEBUG3(params) #define AMD_DEBUG4(params) #define ASSERT(expression) #endif pysparse-1.1.1/amd/amd_order.c0000644010116400000240000001031511402270274015214 0ustar wd15dialout/* ========================================================================== */ /* === AMD_order ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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" GLOBAL Int AMD_order ( Int n, const Int Ap [ ], const Int Ai [ ], Int P [ ], double Control [ ], double Info [ ] ) { Int slen, *Len, *S, nz, nzaat, i, *Pinv, info ; #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) ; } /* Avoid integer overflow in memory size calculations. The space required * by AMD is at most 2.4nz + 8n for S, and n for Len. * Note nz - n <= nzaat <= 2*nz, below. */ if ((2.4 * (double) nz + 8 * (double) n) > (double) Int_MAX / sizeof (Int)) { /* :: int overflow :: */ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } if (!AMD_valid (n, n, Ap, Ai)) { if (info) Info [AMD_STATUS] = AMD_INVALID ; return (AMD_INVALID) ; /* matrix is invalid */ } /* ---------------------------------------------------------------------- */ /* determine the symmetry and count off-diagonal nonzeros in A+A' */ /* ---------------------------------------------------------------------- */ /* allocate size-n integer workspace */ Len = (Int *) ALLOCATE (n * sizeof (Int)) ; if (!Len) { /* :: out of memory :: */ if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } nzaat = AMD_aat (n, Ap, Ai, Len, P, Info) ; AMD_DEBUG1 (("nzaat: "ID"\n", nzaat)) ; ASSERT (nz-n <= nzaat && nzaat <= 2*nz) ; /* ---------------------------------------------------------------------- */ /* allocate workspace for matrix, elbow room, and 7 size-n vectors */ /* ---------------------------------------------------------------------- */ slen = (nzaat + nzaat/5 + n) + 7*n ; if (info) { /* memory usage (Len and S), in bytes. */ Info [AMD_MEMORY] = ((double) slen + n) * sizeof (Int) ; } S = (Int *) ALLOCATE (slen * sizeof (Int)) ; AMD_DEBUG1 ((" S "ID" Len "ID" n "ID" nzaat "ID" slen "ID"\n", (Int) S, (Int) Len, n, nzaat, slen)) ; if (S == (Int *) NULL) { /* :: out of memory :: */ FREE (Len) ; if (Info != (double *) NULL) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ; return (AMD_OUT_OF_MEMORY) ; } /* allocate space from S for Pinv */ Pinv = S + slen - n ; slen -= n ; /* ---------------------------------------------------------------------- */ /* order the matrix */ /* ---------------------------------------------------------------------- */ AMD_1 (n, Ap, Ai, P, Pinv, Len, slen, S, Control, Info) ; /* ---------------------------------------------------------------------- */ /* free the workspace */ /* ---------------------------------------------------------------------- */ FREE (Len) ; FREE (S) ; return (AMD_OK) ; /* successful ordering */ } pysparse-1.1.1/amd/amd_post_tree.c0000644010116400000240000000736011402270273016112 0ustar wd15dialout/* ========================================================================== */ /* === AMD_post_tree ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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) ; } pysparse-1.1.1/amd/amd_postorder.c0000644010116400000240000001300211402270272016114 0ustar wd15dialout/* ========================================================================== */ /* === AMD_postorder ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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 ) ; } } } pysparse-1.1.1/amd/amd_valid.c0000644010116400000240000000476411402270270015207 0ustar wd15dialout/* ========================================================================== */ /* === AMD_valid ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* AMD Version 1.0 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. Davis, */ /* Patrick R. Amestoy, and Iain S. Duff. See ../README for License. */ /* email: davis@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. * row indices in Ai [Ap [j] ... Ap [j+1]-1] must be sorted in ascending * order, must be in the range 0 to n_row-1, and no duplicate entries * can exist. * * Not user-callable. */ #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 ; if (n_row < 0 || n_col < 0) { AMD_DEBUG0 (("n must be >= 0: "ID" "ID"\n", n_row, n_col)) ; return (FALSE) ; } 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 (FALSE) ; } 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 (FALSE) ; } ilast = EMPTY ; for (p = p1 ; p < p2 ; p++) { i = Ai [p] ; AMD_DEBUG3 (("row: "ID"\n", i)) ; if (i <= ilast || i >= n_row) { /* row index out of range, or unsorted */ AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i)) ; return (FALSE) ; } ilast = i ; } } return (TRUE) ; } pysparse-1.1.1/superlu/0000755010116400000240000000000011402271043014045 5ustar wd15dialoutpysparse-1.1.1/superlu/Cnames.h0000644010116400000240000001221111402270226015423 0ustar wd15dialout/* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 1, 1997 * */ #ifndef __SUPERLU_CNAMES /* allow multiple inclusions */ #define __SUPERLU_CNAMES /* * These macros define how C routines will be called. ADD_ assumes that * they will be called by fortran, which expects C routines to have an * underscore postfixed to the name (Suns, and the Intel expect this). * NOCHANGE indicates that fortran will be calling, and that it expects * the name called by fortran to be identical to that compiled by the C * (RS6K's do this). UPCASE says it expects C routines called by fortran * to be in all upcase (CRAY wants this). */ #define ADD_ 0 #define NOCHANGE 1 #define UPCASE 2 #define C_CALL 3 #ifdef UpCase #define F77_CALL_C UPCASE #endif #ifdef NoChange #define F77_CALL_C NOCHANGE #endif #ifdef Add_ #define F77_CALL_C ADD_ #endif #ifndef F77_CALL_C #define F77_CALL_C ADD_ #endif #if (F77_CALL_C == ADD_) /* * These defines set up the naming scheme required to have a fortran 77 * routine call a C routine * No redefinition necessary to have following Fortran to C interface: * FORTRAN CALL C DECLARATION * call dgemm(...) void dgemm_(...) * * This is the default. */ #endif #if (F77_CALL_C == UPCASE) /* * These defines set up the naming scheme required to have a fortran 77 * routine call a C routine * following Fortran to C interface: * FORTRAN CALL C DECLARATION * call dgemm(...) void DGEMM(...) */ #define sasum_ SASUM #define isamax_ ISAMAX #define scopy_ SCOPY #define sscal_ SSCAL #define sger_ SGER #define snrm2_ SNRM2 #define ssymv_ SSYMV #define sdot_ SDOT #define saxpy_ SAXPY #define ssyr2_ SSYR2 #define srot_ SROT #define sgemv_ SGEMV #define strsv_ STRSV #define sgemm_ SGEMM #define strsm_ STRSM #ifdef _CRAY /* Original UPCASE mapping (appearently for the CRAY platform) */ #define dasum_ SASUM #define idamax_ ISAMAX #define dcopy_ SCOPY #define dscal_ SSCAL #define dger_ SGER #define dnrm2_ SNRM2 #define dsymv_ SSYMV #define ddot_ SDOT #define daxpy_ SAXPY #define dsyr2_ SSYR2 #define drot_ SROT #define dgemv_ SGEMV #define dtrsv_ STRSV #define dgemm_ SGEMM #define dtrsm_ STRSM #else /* UPCASE mapping for Windows MSVC/ACML */ #define dasum_ DASUM #define idamax_ IDAMAX #define dcopy_ DCOPY #define dscal_ DSCAL #define dger_ DGER #define dnrm2_ DNRM2 #define dsymv_ DSYMV #define ddot_ DDOT #define daxpy_ DAXPY #define dsyr2_ DSYR2 #define drot_ DROT #define dgemv_ DGEMV #define dtrsv_ DTRSV #define dgemm_ DGEMM #define dtrsm_ DTRSM #endif #define scasum_ SCASUM #define icamax_ ICAMAX #define ccopy_ CCOPY #define cscal_ CSCAL #define scnrm2_ SCNRM2 #define caxpy_ CAXPY #define cgemv_ CGEMV #define ctrsv_ CTRSV #define cgemm_ CGEMM #define ctrsm_ CTRSM #define cgerc_ CGERC #define chemv_ CHEMV #define cher2_ CHER2 #define dzasum_ SCASUM #define izamax_ ICAMAX #define zcopy_ CCOPY #define zscal_ CSCAL #define dznrm2_ SCNRM2 #define zaxpy_ CAXPY #define zgemv_ CGEMV #define ztrsv_ CTRSV #define zgemm_ CGEMM #define ztrsm_ CTRSM #define zgerc_ CGERC #define zhemv_ CHEMV #define zher2_ CHER2 #define c_bridge_dgssv_ C_BRIDGE_DGSSV #endif #if (F77_CALL_C == NOCHANGE) /* * These defines set up the naming scheme required to have a fortran 77 * routine call a C routine * for following Fortran to C interface: * FORTRAN CALL C DECLARATION * call dgemm(...) void dgemm(...) */ #define sasum_ sasum #define isamax_ isamax #define scopy_ scopy #define sscal_ sscal #define sger_ sger #define snrm2_ snrm2 #define ssymv_ ssymv #define sdot_ sdot #define saxpy_ saxpy #define ssyr2_ ssyr2 #define srot_ srot #define sgemv_ sgemv #define strsv_ strsv #define sgemm_ sgemm #define strsm_ strsm #define dasum_ dasum #define idamax_ idamax #define dcopy_ dcopy #define dscal_ dscal #define dger_ dger #define dnrm2_ dnrm2 #define dsymv_ dsymv #define ddot_ ddot #define daxpy_ daxpy #define dsyr2_ dsyr2 #define drot_ drot #define dgemv_ dgemv #define dtrsv_ dtrsv #define dgemm_ dgemm #define dtrsm_ dtrsm #define scasum_ scasum #define icamax_ icamax #define ccopy_ ccopy #define cscal_ cscal #define scnrm2_ scnrm2 #define caxpy_ caxpy #define cgemv_ cgemv #define ctrsv_ ctrsv #define cgemm_ cgemm #define ctrsm_ ctrsm #define cgerc_ cgerc #define chemv_ chemv #define cher2_ cher2 #define dzasum_ dzasum #define izamax_ izamax #define zcopy_ zcopy #define zscal_ zscal #define dznrm2_ dznrm2 #define zaxpy_ zaxpy #define zgemv_ zgemv #define ztrsv_ ztrsv #define zgemm_ zgemm #define ztrsm_ ztrsm #define zgerc_ zgerc #define zhemv_ zhemv #define zher2_ zher2 #define c_bridge_dgssv_ c_bridge_dgssv #endif #endif /* __SUPERLU_CNAMES */ pysparse-1.1.1/superlu/colamd.c0000644010116400000240000023332611402270225015462 0ustar wd15dialout/* ========================================================================== */ /* === colamd - a sparse matrix column ordering algorithm =================== */ /* ========================================================================== */ /* colamd: An approximate minimum degree column ordering algorithm. 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 user-contributed software for Matlab 5.2, 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) prior to LU factorization using sparse partial pivoting, in the built-in Matlab LU(A) routine. Authors: The authors of the code itself are Stefan I. Larimore and Timothy A. Davis (davis@cise.ufl.edu), University of Florida. The algorithm was developed in collaboration with John Gilbert, Xerox PARC, and Esmond Ng, Oak Ridge National Laboratory. Date: August 3, 1998. Version 1.0. Acknowledgements: This work was supported by the National Science Foundation, under grants DMS-9504974 and DMS-9803599. Notice: Copyright (c) 1998 by the University of Florida. 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 or copy this program for any purpose, provided the above notices are retained on all copies. User documentation of any code that uses this code must cite the Authors, the Copyright, and "Used by permission." If this code is accessible from within Matlab, then typing "help colamd" or "colamd" (with no arguments) must cite the Authors. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. You must also retain the Availability information below, of the original version. This software is provided free of charge. Availability: This file is located at http://www.cise.ufl.edu/~davis/colamd/colamd.c The colamd.h file is required, located in the same directory. The colamdmex.c file provides a Matlab interface for colamd. The symamdmex.c file provides a Matlab interface for symamd, which is a symmetric ordering based on this code, colamd.c. All codes are purely ANSI C compliant (they use no Unix-specific routines, include files, etc.). */ /* ========================================================================== */ /* === Description of user-callable routines ================================ */ /* ========================================================================== */ /* Each user-callable routine (declared as PUBLIC) is briefly described below. Refer to the comments preceding each routine for more details. ---------------------------------------------------------------------------- colamd_recommended: ---------------------------------------------------------------------------- Usage: Alen = colamd_recommended (nnz, n_row, n_col) ; Purpose: Returns recommended value of Alen for use by colamd. Returns -1 if any input argument is negative. 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: ---------------------------------------------------------------------------- Usage: colamd_set_defaults (knobs) ; Purpose: Sets the default parameters. Arguments: double knobs [COLAMD_KNOBS] ; Output only. Rows with more than (knobs [COLAMD_DENSE_ROW] * n_col) entries are removed prior to ordering. Columns with more than (knobs [COLAMD_DENSE_COL] * n_row) entries are removed prior to ordering, and placed last in the output column ordering. 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. ---------------------------------------------------------------------------- colamd: ---------------------------------------------------------------------------- Usage: colamd (n_row, n_col, Alen, A, p, knobs) ; 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. Arguments: int n_row ; Number of rows in the matrix A. Restriction: n_row >= 0. Colamd returns FALSE if n_row is negative. int n_col ; Number of columns in the matrix A. Restriction: n_col >= 0. Colamd returns FALSE if n_col is negative. int Alen ; Restriction (see note): Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col + COLAMD_STATS Colamd returns FALSE if these conditions are not met. Note: this restriction makes an modest assumption regarding the size of the two typedef'd structures, below. We do, however, guarantee that Alen >= colamd_recommended (nnz, n_row, n_col) will be sufficient. int A [Alen] ; Input argument, stats 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 thus undefined on output with the exception of a few statistics about the ordering (A [0..COLAMD_STATS-1]): A [0]: number of dense or empty rows ignored. A [1]: number of dense or empty columns ignored (and ordered last in the output permutation p) A [2]: number of garbage collections performed. A [3]: 0, if all row indices in each column were in sorted order, and no duplicates were present. 1, otherwise (in which case colamd had to do more work) 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. Future versions may return more statistics in A, but the usage of these 4 entries in A will remain unchanged. 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 only. See colamd_set_defaults for a description. If the knobs array is not present (that is, if a (double *) NULL pointer is passed in its place), then the default values of the parameters are used instead. */ /* ========================================================================== */ /* === Include files ======================================================== */ /* ========================================================================== */ /* limits.h: the largest positive integer (INT_MAX) */ #include /* colamd.h: knob array size, stats output size, and global prototypes */ #include "colamd.h" /* ========================================================================== */ /* === Scaffolding code definitions ======================================== */ /* ========================================================================== */ /* Ensure that debugging is turned off: */ #ifndef NDEBUG #define NDEBUG #endif /* assert.h: the assert macro (no debugging if NDEBUG is defined) */ #include /* 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. 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). */ /* ========================================================================== */ /* === Row and Column structures ============================================ */ /* ========================================================================== */ typedef struct ColInfo_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 ; } ColInfo ; typedef struct RowInfo_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 ; } RowInfo ; /* ========================================================================== */ /* === Definitions ========================================================== */ /* ========================================================================== */ #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define ONES_COMPLEMENT(r) (-(r)-1) #define TRUE (1) #define FALSE (0) #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 ; } /* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */ #define PUBLIC #define PRIVATE static /* ========================================================================== */ /* === Prototypes of PRIVATE routines ======================================= */ /* ========================================================================== */ PRIVATE int init_rows_cols ( int n_row, int n_col, RowInfo Row [], ColInfo Col [], int A [], int p [] ) ; PRIVATE void init_scoring ( int n_row, int n_col, RowInfo Row [], ColInfo 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, RowInfo Row [], ColInfo Col [], int A [], int head [], int n_col2, int max_deg, int pfree ) ; PRIVATE void order_children ( int n_col, ColInfo Col [], int p [] ) ; PRIVATE void detect_super_cols ( #ifndef NDEBUG int n_col, RowInfo Row [], #endif ColInfo Col [], int A [], int head [], int row_start, int row_length ) ; PRIVATE int garbage_collection ( int n_row, int n_col, RowInfo Row [], ColInfo Col [], int A [], int *pfree ) ; PRIVATE int clear_mark ( int n_row, RowInfo Row [] ) ; /* ========================================================================== */ /* === Debugging definitions ================================================ */ /* ========================================================================== */ #ifndef NDEBUG /* === With debugging ======================================================= */ /* stdlib.h: for getenv and atoi, to get debugging level from environment */ #include /* stdio.h: for printf (no printing if debugging is turned off) */ #include PRIVATE void debug_deg_lists ( int n_row, int n_col, RowInfo Row [], ColInfo Col [], int head [], int min_score, int should, int max_deg ) ; PRIVATE void debug_mark ( int n_row, RowInfo Row [], int tag_mark, int max_mark ) ; PRIVATE void debug_matrix ( int n_row, int n_col, RowInfo Row [], ColInfo Col [], int A [] ) ; PRIVATE void debug_structures ( int n_row, int n_col, RowInfo Row [], ColInfo Col [], int A [], int n_col2 ) ; /* the following is the *ONLY* global variable in this file, and is only */ /* present when debugging */ PRIVATE int debug_colamd ; /* debug print level */ #define DEBUG0(params) { (void) printf params ; } #define DEBUG1(params) { if (debug_colamd >= 1) (void) printf params ; } #define DEBUG2(params) { if (debug_colamd >= 2) (void) printf params ; } #define DEBUG3(params) { if (debug_colamd >= 3) (void) printf params ; } #define DEBUG4(params) { if (debug_colamd >= 4) (void) printf params ; } #else /* === No debugging ========================================================= */ #define DEBUG0(params) ; #define DEBUG1(params) ; #define DEBUG2(params) ; #define DEBUG3(params) ; #define DEBUG4(params) ; #endif /* ========================================================================== */ /* ========================================================================== */ /* === 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. */ PUBLIC int 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 */ ) { /* === Local variables ================================================== */ int minimum ; /* bare minimum requirements */ int recommended ; /* recommended value of Alen */ if (nnz < 0 || n_row < 0 || n_col < 0) { /* return -1 if any input argument is corrupted */ DEBUG0 (("colamd_recommended error!")) ; DEBUG0 ((" nnz: %d, n_row: %d, n_col: %d\n", nnz, n_row, n_col)) ; return (-1) ; } minimum = 2 * (nnz) /* for A */ + (((n_col) + 1) * sizeof (ColInfo) / sizeof (int)) /* for Col */ + (((n_row) + 1) * sizeof (RowInfo) / sizeof (int)) /* for Row */ + n_col /* minimum elbow room to guarrantee success */ + COLAMD_STATS ; /* for output statistics */ /* recommended is equal to the minumum plus enough memory to keep the */ /* number garbage collections low */ recommended = minimum + nnz/5 ; return (recommended) ; } /* ========================================================================== */ /* === 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. knobs [1] columns with knobs[1]*n_row entries or more are removed prior to ordering, and placed last in the column permutation. knobs [2..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] = 0.5 ; /* ignore rows over 50% dense */ knobs [COLAMD_DENSE_COL] = 0.5 ; /* ignore columns over 50% dense */ } /* ========================================================================== */ /* === 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. On input, the nonzero patterns of the columns of A are stored in the array A, in order 0 to n_col-1. A is held in 0-based form (rows in the range 0 to n_row-1 and columns in the range 0 to n_col-1). Row indices for column c are located in A [(p [c]) ... (p [c+1]-1)], where p [0] = 0, and thus p [n_col] is the number of entries in A. The matrix is destroyed on output. The row indices within each column do not have to be sorted (from small to large row indices), and duplicate row indices may be present. However, colamd will work a little faster if columns are sorted and no duplicates are present. Matlab 5.2 always passes the matrix with sorted columns, and no duplicates. The integer array A is of size Alen. Alen must be at least of size (where nnz is the number of entries in A): nnz for the input column form of A + nnz for a row form of A that colamd generates + 6*(n_col+1) for a ColInfo Col [0..n_col] array (this assumes sizeof (ColInfo) is 6 int's). + 4*(n_row+1) for a RowInfo Row [0..n_row] array (this assumes sizeof (RowInfo) is 4 int's). + elbow_room must be at least n_col. We recommend at least nnz/5 in addition to that. If sufficient, changes in the elbow room affect the ordering time only, not the ordering itself. + COLAMD_STATS for the output statistics Colamd returns FALSE is memory is insufficient, or TRUE otherwise. On input, the caller must specify: n_row the number of rows of A n_col the number of columns of A Alen the size of the array A A [0 ... nnz-1] the row indices, where nnz = p [n_col] A [nnz ... Alen-1] (need not be initialized by the user) p [0 ... n_col] the column pointers, p [0] = 0, and p [n_col] is the number of entries in A. Column c of A is stored in A [p [c] ... p [c+1]-1]. knobs [0 ... 19] a set of parameters that control the behavior of colamd. If knobs is a NULL pointer the defaults are used. The user-callable colamd_set_defaults routine sets the default parameters. See that routine for a description of the user-controllable parameters. If the return value of Colamd is TRUE, then on output: p [0 ... n_col-1] the column permutation. p [0] is the first column index, and p [n_col-1] is the last. That is, p [k] = j means that column j of A is the kth column of AQ. A is undefined on output (the matrix pattern is destroyed), except for the following statistics: A [0] the number of dense (or empty) rows ignored A [1] the number of dense (or empty) columms. These are ordered last, in their natural order. A [2] the number of garbage collections performed. If this is excessive, then you would have gotten your results faster if Alen was larger. A [3] 0, if all row indices in each column were in sorted order and no duplicates were present. 1, if there were unsorted or duplicate row indices in the input. You would have gotten your results faster if A [3] was returned as 0. If the return value of Colamd is FALSE, then A and p are undefined on output. */ PUBLIC int colamd /* returns TRUE if successful */ ( /* === 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) */ ) { /* === Local variables ================================================== */ 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 */ int elbow_room ; /* remaining free space */ RowInfo *Row ; /* pointer into A of Row [0..n_row] array */ ColInfo *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 knobs array */ int init_result ; /* return code from initialization */ #ifndef NDEBUG debug_colamd = 0 ; /* no debug printing */ /* get "D" environment variable, which gives the debug printing level */ if (getenv ("D")) debug_colamd = atoi (getenv ("D")) ; DEBUG0 (("debug version, D = %d (THIS WILL BE SLOOOOW!)\n", debug_colamd)) ; #endif /* === Check the input arguments ======================================== */ if (n_row < 0 || n_col < 0 || !A || !p) { /* n_row and n_col must be non-negative, A and p must be present */ DEBUG0 (("colamd error! %d %d %d\n", n_row, n_col, Alen)) ; return (FALSE) ; } nnz = p [n_col] ; if (nnz < 0 || p [0] != 0) { /* nnz must be non-negative, and p [0] must be zero */ DEBUG0 (("colamd error! %d %d\n", nnz, p [0])) ; return (FALSE) ; } /* === If no knobs, set default parameters ============================== */ if (!knobs) { knobs = default_knobs ; colamd_set_defaults (knobs) ; } /* === Allocate the Row and Col arrays from array A ===================== */ Col_size = (n_col + 1) * sizeof (ColInfo) / sizeof (int) ; Row_size = (n_row + 1) * sizeof (RowInfo) / sizeof (int) ; elbow_room = Alen - (2*nnz + Col_size + Row_size) ; if (elbow_room < n_col + COLAMD_STATS) { /* not enough space in array A to perform the ordering */ DEBUG0 (("colamd error! elbow_room %d, %d\n", elbow_room,n_col)) ; return (FALSE) ; } Alen = 2*nnz + elbow_room ; Col = (ColInfo *) &A [Alen] ; Row = (RowInfo *) &A [Alen + Col_size] ; /* === Construct the row and column data structures ===================== */ init_result = init_rows_cols (n_row, n_col, Row, Col, A, p) ; if (init_result == -1) { /* input matrix is invalid */ DEBUG0 (("colamd error! 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) ; /* === Order the non-principal columns ================================== */ order_children (n_col, Col, p) ; /* === Return statistics in A =========================================== */ for (i = 0 ; i < COLAMD_STATS ; i++) { A [i] = 0 ; } A [COLAMD_DENSE_ROW] = n_row - n_row2 ; A [COLAMD_DENSE_COL] = n_col - n_col2 ; A [COLAMD_DEFRAG_COUNT] = ngarbage ; A [COLAMD_JUMBLED_COLS] = init_result ; return (TRUE) ; } /* ========================================================================== */ /* === 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 -1 on error, 1 if columns jumbled, or 0 if columns not jumbled. Not user-callable. */ PRIVATE int init_rows_cols /* returns status code */ ( /* === Parameters ======================================================= */ int n_row, /* number of rows of A */ int n_col, /* number of columns of A */ RowInfo Row [], /* of size n_row+1 */ ColInfo 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 */ ) { /* === 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_start ; /* start index of previous column in A */ int start ; /* start index of column in A */ int last_row ; /* previous row */ int jumbled_columns ; /* indicates if columns are jumbled */ /* === Initialize columns, and check column pointers ==================== */ last_start = 0 ; for (col = 0 ; col < n_col ; col++) { start = p [col] ; if (start < last_start) { /* column pointers must be non-decreasing */ DEBUG0 (("colamd error! last p %d p [col] %d\n",last_start,start)); return (-1) ; } Col [col].start = start ; Col [col].length = p [col+1] - start ; Col [col].shared1.thickness = 1 ; Col [col].shared2.score = 0 ; Col [col].shared3.prev = EMPTY ; Col [col].shared4.degree_next = EMPTY ; last_start = start ; } /* must check the end pointer for last column */ if (p [n_col] < last_start) { /* column pointers must be non-decreasing */ DEBUG0 (("colamd error! last p %d p [n_col] %d\n",p[col],last_start)) ; return (-1) ; } /* p [0..n_col] no longer needed, used as "head" in subsequent routines */ /* === Scan columns, compute row degrees, and check row indices ========= */ jumbled_columns = FALSE ; 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) { DEBUG0 (("colamd error! col %d row %d last_row %d\n", col, row, last_row)) ; return (-1) ; } else if (row <= last_row) { /* row indices are not sorted or repeated, thus cols */ /* are jumbled */ jumbled_columns = TRUE ; } /* prevent repeated row from being counted */ if (Row [row].shared2.mark != col) { Row [row].length++ ; Row [row].shared2.mark = col ; last_row = row ; } else { /* this is a repeated entry in the column, */ /* it will be removed */ Col [col].length-- ; } } } /* === 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 (jumbled_columns) { /* 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 (jumbled_columns) { #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 /* === 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 ; } } return (1) ; } else { /* no columns jumbled (this is faster) */ return (0) ; } } /* ========================================================================== */ /* === 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 */ RowInfo Row [], /* of size n_row+1 */ ColInfo 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 (# entries) 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 /* === Extract 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)) ; DEBUG0 (("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, 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) ; } } DEBUG0 (("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) ; } } DEBUG0 (("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) ; } } DEBUG0 (("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) */ DEBUG0 (("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 ; } } DEBUG0 (("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 /* === Initialize degree lists ========================================== */ #ifndef NDEBUG debug_count = 0 ; #endif /* 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 } } #ifndef NDEBUG DEBUG0 (("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 /* === 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 + elbow_room or larger */ RowInfo Row [], /* of size n_row+1 */ ColInfo 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) */ ) { /* === 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 ; /* # of columns in pivot row */ int pivot_row_length ; /* # 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" (# 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 /* === Initialization and clear mark ==================================== */ max_mark = INT_MAX - n_col ; /* INT_MAX defined in */ tag_mark = clear_mark (n_row, Row) ; min_score = 0 ; ngarbage = 0 ; DEBUG0 (("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) { DEBUG0 (("\n... Step k: %d out of n_col2: %d\n", k, n_col2)) ; } else { DEBUG1 (("\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 /* === 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 /* 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: %d\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 ; 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 } /* === 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_DEAD (row)) { continue ; } 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 /* === 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: %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] ; DEBUG2 (("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 ====================================== */ DEBUG1 (("** Computing set differences phase. **\n")) ; /* pivot row is currently dead - it will be revived later. */ DEBUG2 (("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) ; DEBUG2 (("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) { DEBUG1 (("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 /* === Add up set differences for each column ======================= */ DEBUG1 (("** 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 ; DEBUG2 (("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)) { continue ; } 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) { DEBUG1 (("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 ==================== */ DEBUG2 (("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 ; DEBUG2 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ; assert (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 ======================================== */ DEBUG1 (("** Supercolumn detection phase. **\n")) ; detect_super_cols ( #ifndef NDEBUG n_col, Row, #endif Col, A, head, pivot_row_start, pivot_row_length) ; /* === Kill the pivotal column ====================================== */ KILL_PRINCIPAL_COL (pivot_col) ; /* === Clear mark =================================================== */ tag_mark += (max_deg + 1) ; if (tag_mark >= max_mark) { DEBUG1 (("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 /* === Finalize the new pivot row, and column scores ================ */ DEBUG1 (("** 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 /* === 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]) ; Row [pivot_row].shared1.degree = pivot_row_degree ; Row [pivot_row].shared2.mark = 0 ; /* pivot row is no longer dead */ } } /* === 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 */ ColInfo 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 */ RowInfo Row [], /* of size n_row+1 */ #endif ColInfo 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 # 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 */ RowInfo Row [], /* row info */ ColInfo 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 ; DEBUG0 (("Defrag..\n")) ; for (psrc = &A[0] ; psrc < pfree ; psrc++) assert (*psrc >= 0) ; debug_rows = 0 ; #endif /* === 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) { /* this row is of zero length. cannot compact it, so kill it */ DEBUG0 (("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 } } } /* === 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 } } /* 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 */ RowInfo Row [] /* Row [0 ... n_row-1].shared2.mark is set to zero */ ) { /* === Local variables ================================================== */ int r ; DEBUG0 (("Clear mark\n")) ; for (r = 0 ; r < n_row ; r++) { if (ROW_IS_ALIVE (r)) { Row [r].shared2.mark = 0 ; } } return (1) ; } /* ========================================================================== */ /* === 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, RowInfo Row [], ColInfo 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, RowInfo Row [], ColInfo 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 && debug_colamd <= 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 && debug_colamd <= 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, RowInfo 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 && debug_colamd <= 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, RowInfo Row [], ColInfo 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 (debug_colamd < 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++ ; DEBUG3 ((" %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++ ; DEBUG3 ((" %d row %d\n", ROW_IS_ALIVE (r), r)) ; } } } #endif pysparse-1.1.1/superlu/colamd.h0000644010116400000240000000466511402270226015472 0ustar wd15dialout/* ========================================================================== */ /* === colamd prototypes and definitions ==================================== */ /* ========================================================================== */ /* This is the colamd include file, http://www.cise.ufl.edu/~davis/colamd/colamd.h for use in the colamd.c, colamdmex.c, and symamdmex.c files located at http://www.cise.ufl.edu/~davis/colamd/ See those files for a description of colamd and symamd, and for the copyright notice, which also applies to this file. August 3, 1998. Version 1.0. */ /* ========================================================================== */ /* === Definitions ========================================================== */ /* ========================================================================== */ /* size of the knobs [ ] array. Only knobs [0..1] are currently used. */ #define COLAMD_KNOBS 20 /* number of output statistics. Only A [0..2] are currently used. */ #define COLAMD_STATS 20 /* knobs [0] and A [0]: dense row knob and output statistic. */ #define COLAMD_DENSE_ROW 0 /* knobs [1] and A [1]: dense column knob and output statistic. */ #define COLAMD_DENSE_COL 1 /* A [2]: memory defragmentation count output statistic */ #define COLAMD_DEFRAG_COUNT 2 /* A [3]: whether or not the input columns were jumbled or had duplicates */ #define COLAMD_JUMBLED_COLS 3 /* ========================================================================== */ /* === Prototypes of user-callable routines ================================= */ /* ========================================================================== */ int colamd_recommended /* returns recommended value of Alen */ ( int nnz, /* nonzeros in A */ int n_row, /* number of rows in A */ int 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 */ ) ; int colamd /* returns TRUE if successful, FALSE 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 */ ) ; pysparse-1.1.1/superlu/csp_defs.h0000644010116400000240000002302411402270212016002 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #ifndef __SUPERLU_cSP_DEFS /* allow multiple inclusions */ #define __SUPERLU_cSP_DEFS /* * File name: csp_defs.h * Purpose: Sparse matrix types and function prototypes * History: */ #ifdef _CRAY #include #include #endif #include "Cnames.h" #include "supermatrix.h" #include "scomplex.h" /* No of marker arrays used in the symbolic factorization, each of size n */ #define NO_MARKER 3 #define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) ) typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; typedef enum {HEAD, TAIL} stack_end_t; typedef enum {SYSTEM, USER} LU_space_t; /* * Global data structures used in LU factorization - * * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. * (xsup,supno): supno[i] is the supernode no to which i belongs; * xsup(s) points to the beginning of the s-th supernode. * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) * xsup 0 1 2 4 7 12 * Note: dfs will be performed on supernode rep. relative to the new * row pivoting ordering * * (xlsub,lsub): lsub[*] contains the compressed subscript of * rectangular supernodes; xlsub[j] points to the starting * location of the j-th column in lsub[*]. Note that xlsub * is indexed by column. * Storage: original row subscripts * * During the course of sparse LU factorization, we also use * (xlsub,lsub) for the purpose of symmetric pruning. For each * supernode {s,s+1,...,t=s+r} with first column s and last * column t, the subscript set * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 * is the structure of column s (i.e. structure of this supernode). * It is used for the storage of numerical values. * Furthermore, * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 * is the structure of the last column t of this supernode. * It is for the purpose of symmetric pruning. Therefore, the * structural subscripts can be rearranged without making physical * interchanges among the numerical values. * * However, if the supernode has only one column, then we * only keep one set of subscripts. For any subscript interchange * performed, similar interchange must be done on the numerical * values. * * The last column structures (for pruning) will be removed * after the numercial LU factorization phase. * * (xlusup,lusup): lusup[*] contains the numerical values of the * rectangular supernodes; xlusup[j] points to the starting * location of the j-th column in storage vector lusup[*] * Note: xlusup is indexed by column. * Each rectangular supernode is stored by column-major * scheme, consistent with Fortran 2-dim array storage. * * (xusub,ucol,usub): ucol[*] stores the numerical values of * U-columns outside the rectangular supernodes. The row * subscript of nonzero ucol[k] is stored in usub[k]. * xusub[i] points to the starting location of column i in ucol. * Storage: new row subscripts; that is subscripts of PA. */ typedef struct { int *xsup; /* supernode and column mapping */ int *supno; int *lsub; /* compressed L subscripts */ int *xlsub; complex *lusup; /* L supernodes */ int *xlusup; complex *ucol; /* U columns */ int *usub; int *xusub; int nzlmax; /* current max size of lsub */ int nzumax; /* " " " ucol */ int nzlumax; /* " " " lusup */ int n; /* number of columns in the matrix */ LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ } GlobalLU_t; typedef struct { int panel_size; int relax; float diag_pivot_thresh; float drop_tol; } factor_param_t; typedef struct { float for_lu; float total_needed; int expansions; } mem_usage_t; #ifdef __cplusplus extern "C" { #endif /* Driver routines */ extern void cgssv(SuperMatrix *, int *, int *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *); extern void cgssvx(char *, char *, char *, SuperMatrix *, factor_param_t *, int *, int *, int *, char *, float *, float *, SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, float *, float *, float *, float *, mem_usage_t *, int *); /* Supernodal LU factor related */ extern void cCreate_CompCol_Matrix(SuperMatrix *, int, int, int, complex *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void cCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); extern void cCreate_Dense_Matrix(SuperMatrix *, int, int, complex *, int, Stype_t, Dtype_t, Mtype_t); extern void cCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, complex *, int *, int *, int *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void cCopy_Dense_Matrix(int, int, complex *, int, complex *, int); extern void Destroy_SuperMatrix_Store(SuperMatrix *); extern void Destroy_CompCol_Matrix(SuperMatrix *); extern void Destroy_SuperNode_Matrix(SuperMatrix *); extern void Destroy_CompCol_Permuted(SuperMatrix *); extern void Destroy_Dense_Matrix(SuperMatrix *); extern void get_perm_c(int, SuperMatrix *, int *); extern void sp_preorder (char*, SuperMatrix*, int*, int*, SuperMatrix*); extern void countnz (const int, int *, int *, int *, GlobalLU_t *); extern void fixupL (const int, const int *, GlobalLU_t *); extern void callocateA (int, int, complex **, int **, int **); extern void cgstrf (char*, SuperMatrix*, float, float, int, int, int*, void *, int, int *, int *, SuperMatrix *, SuperMatrix *, int *); extern int csnode_dfs (const int, const int, const int *, const int *, const int *, int *, int *, GlobalLU_t *); extern int csnode_bmod (const int, const int, const int, complex *, complex *, GlobalLU_t *); extern void cpanel_dfs (const int, const int, const int, SuperMatrix *, int *, int *, complex *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern void cpanel_bmod (const int, const int, const int, const int, complex *, complex *, int *, int *, GlobalLU_t *); extern int ccolumn_dfs (const int, const int, int *, int *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern int ccolumn_bmod (const int, const int, complex *, complex *, int *, int *, int, GlobalLU_t *); extern int ccopy_to_ucol (int, int, int *, int *, int *, complex *, GlobalLU_t *); extern int cpivotL (const int, const float, int *, int *, int *, int *, int *, GlobalLU_t *); extern void cpruneL (const int, const int *, const int, const int, const int *, const int *, int *, GlobalLU_t *); extern void creadmt (int *, int *, int *, complex **, int **, int **); extern void cGenXtrue (int, int, complex *, int); extern void cFillRHS (char *, int, complex *, int, SuperMatrix *, SuperMatrix *); extern void cgstrs (char *, SuperMatrix *, SuperMatrix *, int *, int *, SuperMatrix *, int *); /* Driver related */ extern void cgsequ (SuperMatrix *, float *, float *, float *, float *, float *, int *); extern void claqgs (SuperMatrix *, float *, float *, float, float, float, char *); extern void cgscon (char *, SuperMatrix *, SuperMatrix *, float, float *, int *); extern float cPivotGrowth(int, SuperMatrix *, int *, SuperMatrix *, SuperMatrix *); extern void cgsrfs (char *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *, int *, char *, float *, float *, SuperMatrix *, SuperMatrix *, float *, float *, int *); extern int sp_ctrsv (char *, char *, char *, SuperMatrix *, SuperMatrix *, complex *, int *); extern int sp_cgemv (char *, complex, SuperMatrix *, complex *, int, complex, complex *, int); extern int sp_cgemm (char *, char *, int, int, int, complex, SuperMatrix *, complex *, int, complex, complex *, int); /* Memory-related */ extern int cLUMemInit (char *, void *, int, int, int, int, int, SuperMatrix *, SuperMatrix *, GlobalLU_t *, int **, complex **); extern void cSetRWork (int, int, complex *, complex **, complex **); extern void cLUWorkFree (int *, complex *, GlobalLU_t *); extern int cLUMemXpand (int, int, MemType, int *, GlobalLU_t *); extern complex *complexMalloc(int); extern complex *complexCalloc(int); extern float *floatMalloc(int); extern float *floatCalloc(int); extern int cmemory_usage(const int, const int, const int, const int); extern int cQuerySpace (SuperMatrix *, SuperMatrix *, int, mem_usage_t *); /* Auxiliary routines */ extern void creadhb(int *, int *, int *, complex **, int **, int **); extern void cCompRow_to_CompCol(int, int, int, complex*, int*, int*, complex **, int **, int **); extern void cfill (complex *, int, complex); extern void cinf_norm_error (int, SuperMatrix *, complex *); extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, complex, complex, complex *, complex *, char *); /* Routines for debugging */ extern void cPrint_CompCol_Matrix(char *, SuperMatrix *); extern void cPrint_SuperNode_Matrix(char *, SuperMatrix *); extern void cPrint_Dense_Matrix(char *, SuperMatrix *); extern void print_lu_col(char *, int, int, int *, GlobalLU_t *); extern void check_tempv(int, complex *); #ifdef __cplusplus } #endif #endif /* __SUPERLU_cSP_DEFS */ pysparse-1.1.1/superlu/dcolumn_bmod.c0000644010116400000240000002356611402270217016671 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include #include #include "dsp_defs.h" #include "util.h" /* * Function prototypes */ void dusolve(int, int, double*, double*); void dlsolve(int, int, double*, double*); void dmatvec(int, int, int, double*, double*, double*); /* Return value: 0 - successful return * > 0 - number of bytes allocated when run out of space */ int dcolumn_bmod ( const int jcol, /* in */ const int nseg, /* in */ double *dense, /* in */ double *tempv, /* working array */ int *segrep, /* in */ int *repfnz, /* in */ int fpanelc, /* in -- first column in the current panel */ GlobalLU_t *Glu /* modified */ ) { /* * Purpose: * ======== * Performs numeric block updates (sup-col) in topological order. * It features: col-col, 2cols-col, 3cols-col, and sup-col updates. * Special processing on the supernodal portion of L\U[*,j] * */ #ifdef _CRAY _fcd ftcs1 = _cptofcd("L", strlen("L")), ftcs2 = _cptofcd("N", strlen("N")), ftcs3 = _cptofcd("U", strlen("U")); #endif int incx = 1, incy = 1; double alpha, beta; /* krep = representative of current k-th supernode * fsupc = first supernodal column * nsupc = no of columns in supernode * nsupr = no of rows in supernode (used as leading dimension) * luptr = location of supernodal LU-block in storage * kfnz = first nonz in the k-th supernodal segment * no_zeros = no of leading zeros in a supernodal U-segment */ double ukj, ukj1, ukj2; int luptr, luptr1, luptr2; int fsupc, nsupc, nsupr, segsze; int nrow; /* No of rows in the matrix of matrix-vector */ int jcolp1, jsupno, k, ksub, krep, krep_ind, ksupno; register int lptr, kfnz, isub, irow, i; register int no_zeros, new_next; int ufirst, nextlu; int fst_col; /* First column within small LU update */ int d_fsupc; /* Distance between the first column of the current panel and the first column of the current snode. */ int *xsup, *supno; int *lsub, *xlsub; double *lusup; int *xlusup; int nzlumax; double *tempv1; double zero = 0.0; double one = 1.0; double none = -1.0; int mem_error; extern SuperLUStat_t SuperLUStat; flops_t *ops = SuperLUStat.ops; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; lusup = Glu->lusup; xlusup = Glu->xlusup; nzlumax = Glu->nzlumax; jcolp1 = jcol + 1; jsupno = supno[jcol]; /* * For each nonz supernode segment of U[*,j] in topological order */ k = nseg - 1; for (ksub = 0; ksub < nseg; ksub++) { krep = segrep[k]; k--; ksupno = supno[krep]; if ( jsupno != ksupno ) { /* Outside the rectangular supernode */ fsupc = xsup[ksupno]; fst_col = SUPERLU_MAX ( fsupc, fpanelc ); /* Distance from the current supernode to the current panel; d_fsupc=0 if fsupc > fpanelc. */ d_fsupc = fst_col - fsupc; luptr = xlusup[fst_col] + d_fsupc; lptr = xlsub[fsupc] + d_fsupc; kfnz = repfnz[krep]; kfnz = SUPERLU_MAX ( kfnz, fpanelc ); segsze = krep - kfnz + 1; nsupc = krep - fst_col + 1; nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */ nrow = nsupr - d_fsupc - nsupc; krep_ind = lptr + nsupc - 1; ops[TRSV] += segsze * (segsze - 1); ops[GEMV] += 2 * nrow * segsze; /* * Case 1: Update U-segment of size 1 -- col-col update */ if ( segsze == 1 ) { ukj = dense[lsub[krep_ind]]; luptr += nsupr*(nsupc-1) + nsupc; for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { irow = lsub[i]; dense[irow] -= ukj*lusup[luptr]; luptr++; } } else if ( segsze <= 3 ) { ukj = dense[lsub[krep_ind]]; luptr += nsupr*(nsupc-1) + nsupc-1; ukj1 = dense[lsub[krep_ind - 1]]; luptr1 = luptr - nsupr; if ( segsze == 2 ) { /* Case 2: 2cols-col update */ ukj -= ukj1 * lusup[luptr1]; dense[lsub[krep_ind]] = ukj; for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { irow = lsub[i]; luptr++; luptr1++; dense[irow] -= ( ukj*lusup[luptr] + ukj1*lusup[luptr1] ); } } else { /* Case 3: 3cols-col update */ ukj2 = dense[lsub[krep_ind - 2]]; luptr2 = luptr1 - nsupr; ukj1 -= ukj2 * lusup[luptr2-1]; ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; dense[lsub[krep_ind]] = ukj; dense[lsub[krep_ind-1]] = ukj1; for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { irow = lsub[i]; luptr++; luptr1++; luptr2++; dense[irow] -= ( ukj*lusup[luptr] + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); } } } else { /* * Case: sup-col update * Perform a triangular solve and block update, * then scatter the result of sup-col update to dense */ no_zeros = kfnz - fst_col; /* Copy U[*,j] segment from dense[*] to tempv[*] */ isub = lptr + no_zeros; for (i = 0; i < segsze; i++) { irow = lsub[isub]; tempv[i] = dense[irow]; ++isub; } /* Dense triangular solve -- start effective triangle */ luptr += nsupr * no_zeros + no_zeros; #ifdef USE_VENDOR_BLAS #ifdef _CRAY STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], &nsupr, tempv, &incx ); #else dtrsv_( "L", "N", "U", &segsze, &lusup[luptr], &nsupr, tempv, &incx ); #endif luptr += segsze; /* Dense matrix-vector */ tempv1 = &tempv[segsze]; alpha = one; beta = zero; #ifdef _CRAY SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr], &nsupr, tempv, &incx, &beta, tempv1, &incy ); #else dgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr], &nsupr, tempv, &incx, &beta, tempv1, &incy ); #endif #else dlsolve ( nsupr, segsze, &lusup[luptr], tempv ); luptr += segsze; /* Dense matrix-vector */ tempv1 = &tempv[segsze]; dmatvec (nsupr, nrow , segsze, &lusup[luptr], tempv, tempv1); #endif /* Scatter tempv[] into SPA dense[] as a temporary storage */ isub = lptr + no_zeros; for (i = 0; i < segsze; i++) { irow = lsub[isub]; dense[irow] = tempv[i]; tempv[i] = zero; ++isub; } /* Scatter tempv1[] into SPA dense[] */ for (i = 0; i < nrow; i++) { irow = lsub[isub]; dense[irow] -= tempv1[i]; tempv1[i] = zero; ++isub; } } } /* if jsupno ... */ } /* for each segment... */ /* * Process the supernodal portion of L\U[*,j] */ nextlu = xlusup[jcol]; fsupc = xsup[jsupno]; /* Copy the SPA dense into L\U[*,j] */ new_next = nextlu + xlsub[fsupc+1] - xlsub[fsupc]; while ( new_next > nzlumax ) { if (mem_error = dLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, Glu)) return (mem_error); lusup = Glu->lusup; lsub = Glu->lsub; } for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) { irow = lsub[isub]; lusup[nextlu] = dense[irow]; dense[irow] = zero; ++nextlu; } xlusup[jcolp1] = nextlu; /* Close L\U[*,jcol] */ /* For more updates within the panel (also within the current supernode), * should start from the first column of the panel, or the first column * of the supernode, whichever is bigger. There are 2 cases: * 1) fsupc < fpanelc, then fst_col := fpanelc * 2) fsupc >= fpanelc, then fst_col := fsupc */ fst_col = SUPERLU_MAX ( fsupc, fpanelc ); if ( fst_col < jcol ) { /* Distance between the current supernode and the current panel. d_fsupc=0 if fsupc >= fpanelc. */ d_fsupc = fst_col - fsupc; lptr = xlsub[fsupc] + d_fsupc; luptr = xlusup[fst_col] + d_fsupc; nsupr = xlsub[fsupc+1] - xlsub[fsupc]; /* Leading dimension */ nsupc = jcol - fst_col; /* Excluding jcol */ nrow = nsupr - d_fsupc - nsupc; /* Points to the beginning of jcol in snode L\U(jsupno) */ ufirst = xlusup[jcol] + d_fsupc; ops[TRSV] += nsupc * (nsupc - 1); ops[GEMV] += 2 * nrow * nsupc; #ifdef USE_VENDOR_BLAS #ifdef _CRAY STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr], &nsupr, &lusup[ufirst], &incx ); #else dtrsv_( "L", "N", "U", &nsupc, &lusup[luptr], &nsupr, &lusup[ufirst], &incx ); #endif alpha = none; beta = one; /* y := beta*y + alpha*A*x */ #ifdef _CRAY SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); #else dgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); #endif #else dlsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] ); dmatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc], &lusup[ufirst], tempv ); /* Copy updates from tempv[*] into lusup[*] */ isub = ufirst + nsupc; for (i = 0; i < nrow; i++) { lusup[isub] -= tempv[i]; tempv[i] = 0.0; ++isub; } #endif } /* if fst_col < jcol ... */ return 0; } pysparse-1.1.1/superlu/dcolumn_dfs.c0000644010116400000240000001764211402270225016521 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "dsp_defs.h" #include "util.h" /* What type of supernodes we want */ #define T2_SUPER int dcolumn_dfs( const int m, /* in - number of rows in the matrix */ const int jcol, /* in */ int *perm_r, /* in */ int *nseg, /* modified - with new segments appended */ int *lsub_col, /* in - defines the RHS vector to start the dfs */ int *segrep, /* modified - with new segments appended */ int *repfnz, /* modified */ int *xprune, /* modified */ int *marker, /* modified */ int *parent, /* working array */ int *xplore, /* working array */ GlobalLU_t *Glu /* modified */ ) { /* * Purpose * ======= * "column_dfs" performs a symbolic factorization on column jcol, and * decide the supernode boundary. * * This routine does not use numeric values, but only use the RHS * row indices to start the dfs. * * A supernode representative is the last column of a supernode. * The nonzeros in U[*,j] are segments that end at supernodal * representatives. The routine returns a list of such supernodal * representatives in topological order of the dfs that generates them. * The location of the first nonzero in each such supernodal segment * (supernodal entry location) is also returned. * * Local parameters * ================ * nseg: no of segments in current U[*,j] * jsuper: jsuper=NO if column j does not belong to the same * supernode as j-1. Otherwise, jsuper=nsuper. * * marker2: A-row --> A-row/col (0/1) * repfnz: SuperA-col --> PA-row * parent: SuperA-col --> SuperA-col * xplore: SuperA-col --> index to L-structure * * Return value * ============ * 0 success; * > 0 number of bytes allocated when run out of space. * */ int jcolp1, jcolm1, jsuper, nsuper, nextl; int k, krep, krow, kmark, kperm; int *marker2; /* Used for small panel LU */ int fsupc; /* First column of a snode */ int myfnz; /* First nonz column of a U-segment */ int chperm, chmark, chrep, kchild; int xdfs, maxdfs, kpar, oldrep; int jptr, jm1ptr; int ito, ifrom, istop; /* Used to compress row subscripts */ int mem_error; int *xsup, *supno, *lsub, *xlsub; int nzlmax; static int first = 1, maxsuper; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; nzlmax = Glu->nzlmax; if ( first ) { maxsuper = sp_ienv(3); first = 0; } jcolp1 = jcol + 1; jcolm1 = jcol - 1; nsuper = supno[jcol]; jsuper = nsuper; nextl = xlsub[jcol]; marker2 = &marker[2*m]; /* For each nonzero in A[*,jcol] do dfs */ for (k = 0; lsub_col[k] != EMPTY; k++) { krow = lsub_col[k]; lsub_col[k] = EMPTY; kmark = marker2[krow]; /* krow was visited before, go to the next nonz */ if ( kmark == jcol ) continue; /* For each unmarked nbr krow of jcol * krow is in L: place it in structure of L[*,jcol] */ marker2[krow] = jcol; kperm = perm_r[krow]; if ( kperm == EMPTY ) { lsub[nextl++] = krow; /* krow is indexed into A */ if ( nextl >= nzlmax ) { if ( mem_error = dLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu) ) return (mem_error); lsub = Glu->lsub; } if ( kmark != jcolm1 ) jsuper = NO; /* Row index subset testing */ } else { /* krow is in U: if its supernode-rep krep * has been explored, update repfnz[*] */ krep = xsup[supno[kperm]+1] - 1; myfnz = repfnz[krep]; if ( myfnz != EMPTY ) { /* Visited before */ if ( myfnz > kperm ) repfnz[krep] = kperm; /* continue; */ } else { /* Otherwise, perform dfs starting at krep */ oldrep = EMPTY; parent[krep] = oldrep; repfnz[krep] = kperm; xdfs = xlsub[krep]; maxdfs = xprune[krep]; do { /* * For each unmarked kchild of krep */ while ( xdfs < maxdfs ) { kchild = lsub[xdfs]; xdfs++; chmark = marker2[kchild]; if ( chmark != jcol ) { /* Not reached yet */ marker2[kchild] = jcol; chperm = perm_r[kchild]; /* Case kchild is in L: place it in L[*,k] */ if ( chperm == EMPTY ) { lsub[nextl++] = kchild; if ( nextl >= nzlmax ) { if ( mem_error = dLUMemXpand(jcol,nextl,LSUB,&nzlmax,Glu) ) return (mem_error); lsub = Glu->lsub; } if ( chmark != jcolm1 ) jsuper = NO; } else { /* Case kchild is in U: * chrep = its supernode-rep. If its rep has * been explored, update its repfnz[*] */ chrep = xsup[supno[chperm]+1] - 1; myfnz = repfnz[chrep]; if ( myfnz != EMPTY ) { /* Visited before */ if ( myfnz > chperm ) repfnz[chrep] = chperm; } else { /* Continue dfs at super-rep of kchild */ xplore[krep] = xdfs; oldrep = krep; krep = chrep; /* Go deeper down G(L^t) */ parent[krep] = oldrep; repfnz[krep] = chperm; xdfs = xlsub[krep]; maxdfs = xprune[krep]; } /* else */ } /* else */ } /* if */ } /* while */ /* krow has no more unexplored nbrs; * place supernode-rep krep in postorder DFS. * backtrack dfs to its parent */ segrep[*nseg] = krep; ++(*nseg); kpar = parent[krep]; /* Pop from stack, mimic recursion */ if ( kpar == EMPTY ) break; /* dfs done */ krep = kpar; xdfs = xplore[krep]; maxdfs = xprune[krep]; } while ( kpar != EMPTY ); /* Until empty stack */ } /* else */ } /* else */ } /* for each nonzero ... */ /* Check to see if j belongs in the same supernode as j-1 */ if ( jcol == 0 ) { /* Do nothing for column 0 */ nsuper = supno[0] = 0; } else { fsupc = xsup[nsuper]; jptr = xlsub[jcol]; /* Not compressed yet */ jm1ptr = xlsub[jcolm1]; #ifdef T2_SUPER if ( (nextl-jptr != jptr-jm1ptr-1) ) jsuper = NO; #endif /* Make sure the number of columns in a supernode doesn't exceed threshold. */ if ( jcol - fsupc >= maxsuper ) jsuper = NO; /* If jcol starts a new supernode, reclaim storage space in * lsub from the previous supernode. Note we only store * the subscript set of the first and last columns of * a supernode. (first for num values, last for pruning) */ if ( jsuper == NO ) { /* starts a new supernode */ if ( (fsupc < jcolm1-1) ) { /* >= 3 columns in nsuper */ #ifdef CHK_COMPRESS printf(" Compress lsub[] at super %d-%d\n", fsupc, jcolm1); #endif ito = xlsub[fsupc+1]; xlsub[jcolm1] = ito; istop = ito + jptr - jm1ptr; xprune[jcolm1] = istop; /* Initialize xprune[jcol-1] */ xlsub[jcol] = istop; for (ifrom = jm1ptr; ifrom < nextl; ++ifrom, ++ito) lsub[ito] = lsub[ifrom]; nextl = ito; /* = istop + length(jcol) */ } nsuper++; supno[jcol] = nsuper; } /* if a new supernode */ } /* else: jcol > 0 */ /* Tidy up the pointers before exit */ xsup[nsuper+1] = jcolp1; supno[jcolp1] = nsuper; xprune[jcol] = nextl; /* Initialize upper bound for pruning */ xlsub[jcolp1] = nextl; return 0; } pysparse-1.1.1/superlu/dcomplex.c0000644010116400000240000000367311402270250016034 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * This file defines common arithmetic operations for complex type. */ #include #include "dcomplex.h" #include "util.h" /* Complex Division c = a/b */ void z_div(doublecomplex *c, doublecomplex *a, doublecomplex *b) { double ratio, den; double abr, abi, cr, ci; if( (abr = b->r) < 0.) abr = - abr; if( (abi = b->i) < 0.) abi = - abi; if( abr <= abi ) { if (abi == 0) { ABORT("z_div.c: division by zero"); } ratio = b->r / b->i ; den = b->i * (1 + ratio*ratio); cr = (a->r*ratio + a->i) / den; ci = (a->i*ratio - a->r) / den; } else { ratio = b->i / b->r ; den = b->r * (1 + ratio*ratio); cr = (a->r + a->i*ratio) / den; ci = (a->i - a->r*ratio) / den; } c->r = cr; c->i = ci; } /* Returns sqrt(z.r^2 + z.i^2) */ double z_abs(doublecomplex *z) { double temp; double real = z->r; double imag = z->i; if (real < 0) real = -real; if (imag < 0) imag = -imag; if (imag > real) { temp = real; real = imag; imag = temp; } if ((real+imag) == real) return(real); temp = imag/real; temp = real*sqrt(1.0 + temp*temp); /*overflow!!*/ return (temp); } /* Approximates the abs */ /* Returns abs(z.r) + abs(z.i) */ double z_abs1(doublecomplex *z) { double real = z->r; double imag = z->i; if (real < 0) real = -real; if (imag < 0) imag = -imag; return (real + imag); } /* Return the exponentiation */ void z_exp(doublecomplex *r, doublecomplex *z) { double expx; expx = exp(z->r); r->r = expx * cos(z->i); r->i = expx * sin(z->i); } /* Return the complex conjugate */ void d_cnjg(doublecomplex *r, doublecomplex *z) { r->r = z->r; r->i = -z->i; } /* Return the imaginary part */ double d_imag(doublecomplex *z) { return (z->i); } pysparse-1.1.1/superlu/dcomplex.h0000644010116400000240000000310611402270251016031 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #ifndef __SUPERLU_DCOMPLEX /* allow multiple inclusions */ #define __SUPERLU_DCOMPLEX /* * This header file is to be included in source files z*.c */ #ifndef DCOMPLEX_INCLUDE #define DCOMPLEX_INCLUDE typedef struct { double r, i; } doublecomplex; /* Macro definitions */ /* Complex Addition c = a + b */ #define z_add(c, a, b) { (c)->r = (a)->r + (b)->r; \ (c)->i = (a)->i + (b)->i; } /* Complex Subtraction c = a - b */ #define z_sub(c, a, b) { (c)->r = (a)->r - (b)->r; \ (c)->i = (a)->i - (b)->i; } /* Complex-Double Multiplication */ #define zd_mult(c, a, b) { (c)->r = (a)->r * (b); \ (c)->i = (a)->i * (b); } /* Complex-Complex Multiplication */ #define zz_mult(c, a, b) { \ double cr, ci; \ cr = (a)->r * (b)->r - (a)->i * (b)->i; \ ci = (a)->i * (b)->r + (a)->r * (b)->i; \ (c)->r = cr; \ (c)->i = ci; \ } /* Complex equality testing */ #define z_eq(a, b) ( (a)->r == (b)->r && (a)->i == (b)->i ) #ifdef __cplusplus extern "C" { #endif /* Prototypes for functions in dcomplex.c */ void z_div(doublecomplex *, doublecomplex *, doublecomplex *); double z_abs(doublecomplex *); /* exact */ double z_abs1(doublecomplex *); /* approximate */ void z_exp(doublecomplex *, doublecomplex *); void d_cnjg(doublecomplex *r, doublecomplex *z); double d_imag(doublecomplex *); #ifdef __cplusplus } #endif #endif #endif /* __SUPERLU_DCOMPLEX */ pysparse-1.1.1/superlu/dcopy_to_ucol.c0000644010116400000240000000513511402270247017064 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "dsp_defs.h" #include "util.h" int dcopy_to_ucol( int jcol, /* in */ int nseg, /* in */ int *segrep, /* in */ int *repfnz, /* in */ int *perm_r, /* in */ double *dense, /* modified - reset to zero on return */ GlobalLU_t *Glu /* modified */ ) { /* * Gather from SPA dense[*] to global ucol[*]. */ int ksub, krep, ksupno; int i, k, kfnz, segsze; int fsupc, isub, irow; int jsupno, nextu; int new_next, mem_error; int *xsup, *supno; int *lsub, *xlsub; double *ucol; int *usub, *xusub; int nzumax; double zero = 0.0; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; ucol = Glu->ucol; usub = Glu->usub; xusub = Glu->xusub; nzumax = Glu->nzumax; jsupno = supno[jcol]; nextu = xusub[jcol]; k = nseg - 1; for (ksub = 0; ksub < nseg; ksub++) { krep = segrep[k--]; ksupno = supno[krep]; if ( ksupno != jsupno ) { /* Should go into ucol[] */ kfnz = repfnz[krep]; if ( kfnz != EMPTY ) { /* Nonzero U-segment */ fsupc = xsup[ksupno]; isub = xlsub[fsupc] + kfnz - fsupc; segsze = krep - kfnz + 1; new_next = nextu + segsze; while ( new_next > nzumax ) { if (mem_error = dLUMemXpand(jcol, nextu, UCOL, &nzumax, Glu)) return (mem_error); ucol = Glu->ucol; if (mem_error = dLUMemXpand(jcol, nextu, USUB, &nzumax, Glu)) return (mem_error); usub = Glu->usub; lsub = Glu->lsub; } for (i = 0; i < segsze; i++) { irow = lsub[isub]; usub[nextu] = perm_r[irow]; ucol[nextu] = dense[irow]; dense[irow] = zero; nextu++; isub++; } } } } /* for each segment... */ xusub[jcol + 1] = nextu; /* Close U[*,jcol] */ return 0; } pysparse-1.1.1/superlu/dgscon.c0000644010116400000240000001011611402270202015461 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * File name: dgscon.c * History: Modified from lapack routines DGECON. */ #include #include "util.h" #include "dsp_defs.h" void dgscon(char *norm, SuperMatrix *L, SuperMatrix *U, double anorm, double *rcond, int *info) { /* Purpose ======= DGSCON estimates the reciprocal of the condition number of a general real matrix A, in either the 1-norm or the infinity-norm, using the LU factorization computed by DGETRF. An estimate is obtained for norm(inv(A)), and the reciprocal of the condition number is computed as RCOND = 1 / ( norm(A) * norm(inv(A)) ). See supermatrix.h for the definition of 'SuperMatrix' structure. Arguments ========= NORM (input) char* Specifies whether the 1-norm condition number or the infinity-norm condition number is required: = '1' or 'O': 1-norm; = 'I': Infinity-norm. L (input) SuperMatrix* The factor L from the factorization Pr*A*Pc=L*U as computed by dgstrf(). Use compressed row subscripts storage for supernodes, i.e., L has types: Stype = SC, Dtype = D_, Mtype = TRLU. U (input) SuperMatrix* The factor U from the factorization Pr*A*Pc=L*U as computed by dgstrf(). Use column-wise storage scheme, i.e., U has types: Stype = NC, Dtype = D_, Mtype = TRU. ANORM (input) double If NORM = '1' or 'O', the 1-norm of the original matrix A. If NORM = 'I', the infinity-norm of the original matrix A. RCOND (output) double* The reciprocal of the condition number of the matrix A, computed as RCOND = 1/(norm(A) * norm(inv(A))). INFO (output) int* = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value ===================================================================== */ /* Local variables */ int kase, kase1, onenrm, i; double ainvnm; double *work; int *iwork; extern int drscl_(int *, double *, double *, int *); extern int dlacon_(int *, double *, double *, int *, double *, int *); /* Test the input parameters. */ *info = 0; onenrm = *(unsigned char *)norm == '1' || lsame_(norm, "O"); if (! onenrm && ! lsame_(norm, "I")) *info = -1; else if (L->nrow < 0 || L->nrow != L->ncol || L->Stype != SC || L->Dtype != D_ || L->Mtype != TRLU) *info = -2; else if (U->nrow < 0 || U->nrow != U->ncol || U->Stype != NC || U->Dtype != D_ || U->Mtype != TRU) *info = -3; if (*info != 0) { i = -(*info); xerbla_("dgscon", &i); return; } /* Quick return if possible */ *rcond = 0.; if ( L->nrow == 0 || U->nrow == 0) { *rcond = 1.; return; } work = doubleCalloc( 3*L->nrow ); iwork = intMalloc( L->nrow ); if ( !work || !iwork ) ABORT("Malloc fails for work arrays in dgscon."); /* Estimate the norm of inv(A). */ ainvnm = 0.; if ( onenrm ) kase1 = 1; else kase1 = 2; kase = 0; do { dlacon_(&L->nrow, &work[L->nrow], &work[0], &iwork[0], &ainvnm, &kase); if (kase == 0) break; if (kase == kase1) { /* Multiply by inv(L). */ sp_dtrsv("Lower", "No transpose", "Unit", L, U, &work[0], info); /* Multiply by inv(U). */ sp_dtrsv("Upper", "No transpose", "Non-unit", L, U, &work[0],info); } else { /* Multiply by inv(U'). */ sp_dtrsv("Upper", "Transpose", "Non-unit", L, U, &work[0], info); /* Multiply by inv(L'). */ sp_dtrsv("Lower", "Transpose", "Unit", L, U, &work[0], info); } } while ( kase != 0 ); /* Compute the estimate of the reciprocal condition number. */ if (ainvnm != 0.) *rcond = (1. / ainvnm) / anorm; SUPERLU_FREE (work); SUPERLU_FREE (iwork); return; } /* dgscon */ pysparse-1.1.1/superlu/dgsequ.c0000644010116400000240000001260411402270231015502 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * File name: dgsequ.c * History: Modified from LAPACK routine DGEEQU */ #include #include "dsp_defs.h" #include "util.h" void dgsequ(SuperMatrix *A, double *r, double *c, double *rowcnd, double *colcnd, double *amax, int *info) { /* Purpose ======= DGSEQU computes row and column scalings intended to equilibrate an M-by-N sparse matrix A and reduce its condition number. R returns the row scale factors and C the column scale factors, chosen to try to make the largest element in each row and column of the matrix B with elements B(i,j)=R(i)*A(i,j)*C(j) have absolute value 1. R(i) and C(j) are restricted to be between SMLNUM = smallest safe number and BIGNUM = largest safe number. Use of these scaling factors is not guaranteed to reduce the condition number of A but works well in practice. See supermatrix.h for the definition of 'SuperMatrix' structure. Arguments ========= A (input) SuperMatrix* The matrix of dimension (A->nrow, A->ncol) whose equilibration factors are to be computed. The type of A can be: Stype = NC; Dtype = D_; Mtype = GE. R (output) double*, size A->nrow If INFO = 0 or INFO > M, R contains the row scale factors for A. C (output) double*, size A->ncol If INFO = 0, C contains the column scale factors for A. ROWCND (output) double* If INFO = 0 or INFO > M, ROWCND contains the ratio of the smallest R(i) to the largest R(i). If ROWCND >= 0.1 and AMAX is neither too large nor too small, it is not worth scaling by R. COLCND (output) double* If INFO = 0, COLCND contains the ratio of the smallest C(i) to the largest C(i). If COLCND >= 0.1, it is not worth scaling by C. AMAX (output) double* Absolute value of largest matrix element. If AMAX is very close to overflow or very close to underflow, the matrix should be scaled. INFO (output) int* = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value > 0: if INFO = i, and i is <= A->nrow: the i-th row of A is exactly zero > A->ncol: the (i-M)-th column of A is exactly zero ===================================================================== */ /* Local variables */ NCformat *Astore; double *Aval; int i, j, irow; double rcmin, rcmax; double bignum, smlnum; extern double dlamch_(char *); /* Test the input parameters. */ *info = 0; if ( A->nrow < 0 || A->ncol < 0 || A->Stype != NC || A->Dtype != D_ || A->Mtype != GE ) *info = -1; if (*info != 0) { i = -(*info); xerbla_("dgsequ", &i); return; } /* Quick return if possible */ if ( A->nrow == 0 || A->ncol == 0 ) { *rowcnd = 1.; *colcnd = 1.; *amax = 0.; return; } Astore = A->Store; Aval = Astore->nzval; /* Get machine constants. */ smlnum = dlamch_("S"); bignum = 1. / smlnum; /* Compute row scale factors. */ for (i = 0; i < A->nrow; ++i) r[i] = 0.; /* Find the maximum element in each row. */ for (j = 0; j < A->ncol; ++j) for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { irow = Astore->rowind[i]; r[irow] = SUPERLU_MAX( r[irow], fabs(Aval[i]) ); } /* Find the maximum and minimum scale factors. */ rcmin = bignum; rcmax = 0.; for (i = 0; i < A->nrow; ++i) { rcmax = SUPERLU_MAX(rcmax, r[i]); rcmin = SUPERLU_MIN(rcmin, r[i]); } *amax = rcmax; if (rcmin == 0.) { /* Find the first zero scale factor and return an error code. */ for (i = 0; i < A->nrow; ++i) if (r[i] == 0.) { *info = i + 1; return; } } else { /* Invert the scale factors. */ for (i = 0; i < A->nrow; ++i) r[i] = 1. / SUPERLU_MIN( SUPERLU_MAX( r[i], smlnum ), bignum ); /* Compute ROWCND = min(R(I)) / max(R(I)) */ *rowcnd = SUPERLU_MAX( rcmin, smlnum ) / SUPERLU_MIN( rcmax, bignum ); } /* Compute column scale factors */ for (j = 0; j < A->ncol; ++j) c[j] = 0.; /* Find the maximum element in each column, assuming the row scalings computed above. */ for (j = 0; j < A->ncol; ++j) for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { irow = Astore->rowind[i]; c[j] = SUPERLU_MAX( c[j], fabs(Aval[i]) * r[irow] ); } /* Find the maximum and minimum scale factors. */ rcmin = bignum; rcmax = 0.; for (j = 0; j < A->ncol; ++j) { rcmax = SUPERLU_MAX(rcmax, c[j]); rcmin = SUPERLU_MIN(rcmin, c[j]); } if (rcmin == 0.) { /* Find the first zero scale factor and return an error code. */ for (j = 0; j < A->ncol; ++j) if ( c[j] == 0. ) { *info = A->nrow + j + 1; return; } } else { /* Invert the scale factors. */ for (j = 0; j < A->ncol; ++j) c[j] = 1. / SUPERLU_MIN( SUPERLU_MAX( c[j], smlnum ), bignum); /* Compute COLCND = min(C(J)) / max(C(J)) */ *colcnd = SUPERLU_MAX( rcmin, smlnum ) / SUPERLU_MIN( rcmax, bignum ); } return; } /* dgsequ */ pysparse-1.1.1/superlu/dgsrfs.c0000644010116400000240000003365311402270223015512 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * File name: dgsrfs.c * History: Modified from lapack routine DGERFS */ #include #include "dsp_defs.h" #include "util.h" void dgsrfs(char *trans, SuperMatrix *A, SuperMatrix *L, SuperMatrix *U, int *perm_r, int *perm_c, char *equed, double *R, double *C, SuperMatrix *B, SuperMatrix *X, double *ferr, double *berr, int *info) { /* * Purpose * ======= * * DGSRFS improves the computed solution to a system of linear * equations and provides error bounds and backward error estimates for * the solution. * * If equilibration was performed, the system becomes: * (diag(R)*A_original*diag(C)) * X = diag(R)*B_original. * * See supermatrix.h for the definition of 'SuperMatrix' structure. * * Arguments * ========= * * trans (input) char* * Specifies the form of the system of equations: * = 'N': A * X = B (No transpose) * = 'T': A**T * X = B (Transpose) * = 'C': A**H * X = B (Conjugate transpose = Transpose) * * A (input) SuperMatrix* * The original matrix A in the system, or the scaled A if * equilibration was done. The type of A can be: * Stype = NC, Dtype = D_, Mtype = GE. * * L (input) SuperMatrix* * The factor L from the factorization Pr*A*Pc=L*U. Use * compressed row subscripts storage for supernodes, * i.e., L has types: Stype = SC, Dtype = D_, Mtype = TRLU. * * U (input) SuperMatrix* * The factor U from the factorization Pr*A*Pc=L*U as computed by * dgstrf(). Use column-wise storage scheme, * i.e., U has types: Stype = NC, Dtype = D_, Mtype = TRU. * * perm_r (input) int*, dimension (A->nrow) * Row permutation vector, which defines the permutation matrix Pr; * perm_r[i] = j means row i of A is in position j in Pr*A. * * perm_c (input) int*, dimension (A->ncol) * Column permutation vector, which defines the * permutation matrix Pc; perm_c[i] = j means column i of A is * in position j in A*Pc. * * equed (input) Specifies the form of equilibration that was done. * = 'N': No equilibration. * = 'R': Row equilibration, i.e., A was premultiplied by diag(R). * = 'C': Column equilibration, i.e., A was postmultiplied by * diag(C). * = 'B': Both row and column equilibration, i.e., A was replaced * by diag(R)*A*diag(C). * * R (input) double*, dimension (A->nrow) * The row scale factors for A. * If equed = 'R' or 'B', A is premultiplied by diag(R). * If equed = 'N' or 'C', R is not accessed. * * C (input) double*, dimension (A->ncol) * The column scale factors for A. * If equed = 'C' or 'B', A is postmultiplied by diag(C). * If equed = 'N' or 'R', C is not accessed. * * B (input) SuperMatrix* * B has types: Stype = DN, Dtype = D_, Mtype = GE. * The right hand side matrix B. * if equed = 'R' or 'B', B is premultiplied by diag(R). * * X (input/output) SuperMatrix* * X has types: Stype = DN, Dtype = D_, Mtype = GE. * On entry, the solution matrix X, as computed by dgstrs(). * On exit, the improved solution matrix X. * if *equed = 'C' or 'B', X should be premultiplied by diag(C) * in order to obtain the solution to the original system. * * FERR (output) double*, dimension (B->ncol) * The estimated forward error bound for each solution vector * X(j) (the j-th column of the solution matrix X). * If XTRUE is the true solution corresponding to X(j), FERR(j) * is an estimated upper bound for the magnitude of the largest * element in (X(j) - XTRUE) divided by the magnitude of the * largest element in X(j). The estimate is as reliable as * the estimate for RCOND, and is almost always a slight * overestimate of the true error. * * BERR (output) double*, dimension (B->ncol) * The componentwise relative backward error of each solution * vector X(j) (i.e., the smallest relative change in * any element of A or B that makes X(j) an exact solution). * * info (output) int* * = 0: successful exit * < 0: if INFO = -i, the i-th argument had an illegal value * * Internal Parameters * =================== * * ITMAX is the maximum number of steps of iterative refinement. * */ #define ITMAX 5 /* Table of constant values */ int ione = 1; double ndone = -1.; double done = 1.; /* Local variables */ NCformat *Astore; double *Aval; SuperMatrix Bjcol; DNformat *Bstore, *Xstore, *Bjcol_store; double *Bmat, *Xmat, *Bptr, *Xptr; int kase; double safe1, safe2; int i, j, k, irow, nz, count, notran, rowequ, colequ; int ldb, ldx, nrhs; double s, xk, lstres, eps, safmin; char transt[1]; double *work; double *rwork; int *iwork; extern double dlamch_(char *); extern int dlacon_(int *, double *, double *, int *, double *, int *); #ifdef _CRAY extern int SCOPY(int *, double *, int *, double *, int *); extern int SSAXPY(int *, double *, double *, int *, double *, int *); #else extern int dcopy_(int *, double *, int *, double *, int *); extern int daxpy_(int *, double *, double *, int *, double *, int *); #endif Astore = A->Store; Aval = Astore->nzval; Bstore = B->Store; Xstore = X->Store; Bmat = Bstore->nzval; Xmat = Xstore->nzval; ldb = Bstore->lda; ldx = Xstore->lda; nrhs = B->ncol; /* Test the input parameters */ *info = 0; notran = lsame_(trans, "N"); if ( !notran && !lsame_(trans, "T") && !lsame_(trans, "C")) *info = -1; else if ( A->nrow != A->ncol || A->nrow < 0 || A->Stype != NC || A->Dtype != D_ || A->Mtype != GE ) *info = -2; else if ( L->nrow != L->ncol || L->nrow < 0 || L->Stype != SC || L->Dtype != D_ || L->Mtype != TRLU ) *info = -3; else if ( U->nrow != U->ncol || U->nrow < 0 || U->Stype != NC || U->Dtype != D_ || U->Mtype != TRU ) *info = -4; else if ( ldb < SUPERLU_MAX(0, A->nrow) || B->Stype != DN || B->Dtype != D_ || B->Mtype != GE ) *info = -10; else if ( ldx < SUPERLU_MAX(0, A->nrow) || X->Stype != DN || X->Dtype != D_ || X->Mtype != GE ) *info = -11; if (*info != 0) { i = -(*info); xerbla_("dgsrfs", &i); return; } /* Quick return if possible */ if ( A->nrow == 0 || nrhs == 0) { for (j = 0; j < nrhs; ++j) { ferr[j] = 0.; berr[j] = 0.; } return; } rowequ = lsame_(equed, "R") || lsame_(equed, "B"); colequ = lsame_(equed, "C") || lsame_(equed, "B"); /* Allocate working space */ work = doubleMalloc(2*A->nrow); rwork = (double *) SUPERLU_MALLOC( A->nrow * sizeof(double) ); iwork = intMalloc(2*A->nrow); if ( !work || !rwork || !iwork ) ABORT("Malloc fails for work/rwork/iwork."); if ( notran ) { *(unsigned char *)transt = 'T'; } else { *(unsigned char *)transt = 'N'; } /* NZ = maximum number of nonzero elements in each row of A, plus 1 */ nz = A->ncol + 1; eps = dlamch_("Epsilon"); safmin = dlamch_("Safe minimum"); safe1 = nz * safmin; safe2 = safe1 / eps; /* Compute the number of nonzeros in each row (or column) of A */ for (i = 0; i < A->nrow; ++i) iwork[i] = 0; if ( notran ) { for (k = 0; k < A->ncol; ++k) for (i = Astore->colptr[k]; i < Astore->colptr[k+1]; ++i) ++iwork[Astore->rowind[i]]; } else { for (k = 0; k < A->ncol; ++k) iwork[k] = Astore->colptr[k+1] - Astore->colptr[k]; } /* Copy one column of RHS B into Bjcol. */ Bjcol.Stype = B->Stype; Bjcol.Dtype = B->Dtype; Bjcol.Mtype = B->Mtype; Bjcol.nrow = B->nrow; Bjcol.ncol = 1; Bjcol.Store = (void *) SUPERLU_MALLOC( sizeof(DNformat) ); if ( !Bjcol.Store ) ABORT("SUPERLU_MALLOC fails for Bjcol.Store"); Bjcol_store = Bjcol.Store; Bjcol_store->lda = ldb; Bjcol_store->nzval = work; /* address aliasing */ /* Do for each right hand side ... */ for (j = 0; j < nrhs; ++j) { count = 0; lstres = 3.; Bptr = &Bmat[j*ldb]; Xptr = &Xmat[j*ldx]; while (1) { /* Loop until stopping criterion is satisfied. */ /* Compute residual R = B - op(A) * X, where op(A) = A, A**T, or A**H, depending on TRANS. */ #ifdef _CRAY SCOPY(&A->nrow, Bptr, &ione, work, &ione); #else dcopy_(&A->nrow, Bptr, &ione, work, &ione); #endif sp_dgemv(trans, ndone, A, Xptr, ione, done, work, ione); /* Compute componentwise relative backward error from formula max(i) ( abs(R(i)) / ( abs(op(A))*abs(X) + abs(B) )(i) ) where abs(Z) is the componentwise absolute value of the matrix or vector Z. If the i-th component of the denominator is less than SAFE2, then SAFE1 is added to the i-th component of the numerator and denominator before dividing. */ for (i = 0; i < A->nrow; ++i) rwork[i] = fabs( Bptr[i] ); /* Compute abs(op(A))*abs(X) + abs(B). */ if (notran) { for (k = 0; k < A->ncol; ++k) { xk = fabs( Xptr[k] ); for (i = Astore->colptr[k]; i < Astore->colptr[k+1]; ++i) rwork[Astore->rowind[i]] += fabs(Aval[i]) * xk; } } else { for (k = 0; k < A->ncol; ++k) { s = 0.; for (i = Astore->colptr[k]; i < Astore->colptr[k+1]; ++i) { irow = Astore->rowind[i]; s += fabs(Aval[i]) * fabs(Xptr[irow]); } rwork[k] += s; } } s = 0.; for (i = 0; i < A->nrow; ++i) { if (rwork[i] > safe2) s = SUPERLU_MAX( s, fabs(work[i]) / rwork[i] ); else s = SUPERLU_MAX( s, (fabs(work[i]) + safe1) / (rwork[i] + safe1) ); } berr[j] = s; /* Test stopping criterion. Continue iterating if 1) The residual BERR(J) is larger than machine epsilon, and 2) BERR(J) decreased by at least a factor of 2 during the last iteration, and 3) At most ITMAX iterations tried. */ if (berr[j] > eps && berr[j] * 2. <= lstres && count < ITMAX) { /* Update solution and try again. */ dgstrs (trans, L, U, perm_r, perm_c, &Bjcol, info); #ifdef _CRAY SAXPY(&A->nrow, &done, work, &ione, &Xmat[j*ldx], &ione); #else daxpy_(&A->nrow, &done, work, &ione, &Xmat[j*ldx], &ione); #endif lstres = berr[j]; ++count; } else { break; } } /* end while */ /* Bound error from formula: norm(X - XTRUE) / norm(X) .le. FERR = norm( abs(inv(op(A)))* ( abs(R) + NZ*EPS*( abs(op(A))*abs(X)+abs(B) ))) / norm(X) where norm(Z) is the magnitude of the largest component of Z inv(op(A)) is the inverse of op(A) abs(Z) is the componentwise absolute value of the matrix or vector Z NZ is the maximum number of nonzeros in any row of A, plus 1 EPS is machine epsilon The i-th component of abs(R)+NZ*EPS*(abs(op(A))*abs(X)+abs(B)) is incremented by SAFE1 if the i-th component of abs(op(A))*abs(X) + abs(B) is less than SAFE2. Use DLACON to estimate the infinity-norm of the matrix inv(op(A)) * diag(W), where W = abs(R) + NZ*EPS*( abs(op(A))*abs(X)+abs(B) ))) */ for (i = 0; i < A->nrow; ++i) rwork[i] = fabs( Bptr[i] ); /* Compute abs(op(A))*abs(X) + abs(B). */ if ( notran ) { for (k = 0; k < A->ncol; ++k) { xk = fabs( Xptr[k] ); for (i = Astore->colptr[k]; i < Astore->colptr[k+1]; ++i) rwork[Astore->rowind[i]] += fabs(Aval[i]) * xk; } } else { for (k = 0; k < A->ncol; ++k) { s = 0.; for (i = Astore->colptr[k]; i < Astore->colptr[k+1]; ++i) { irow = Astore->rowind[i]; xk = fabs( Xptr[irow] ); s += fabs(Aval[i]) * xk; } rwork[k] += s; } } for (i = 0; i < A->nrow; ++i) if (rwork[i] > safe2) rwork[i] = fabs(work[i]) + (iwork[i]+1)*eps*rwork[i]; else rwork[i] = fabs(work[i])+(iwork[i]+1)*eps*rwork[i]+safe1; kase = 0; do { dlacon_(&A->nrow, &work[A->nrow], work, &iwork[A->nrow], &ferr[j], &kase); if (kase == 0) break; if (kase == 1) { /* Multiply by diag(W)*inv(op(A)**T)*(diag(C) or diag(R)). */ if ( notran && colequ ) for (i = 0; i < A->ncol; ++i) work[i] *= C[i]; else if ( !notran && rowequ ) for (i = 0; i < A->nrow; ++i) work[i] *= R[i]; dgstrs (transt, L, U, perm_r, perm_c, &Bjcol, info); for (i = 0; i < A->nrow; ++i) work[i] *= rwork[i]; } else { /* Multiply by (diag(C) or diag(R))*inv(op(A))*diag(W). */ for (i = 0; i < A->nrow; ++i) work[i] *= rwork[i]; dgstrs (trans, L, U, perm_r, perm_c, &Bjcol, info); if ( notran && colequ ) for (i = 0; i < A->ncol; ++i) work[i] *= C[i]; else if ( !notran && rowequ ) for (i = 0; i < A->ncol; ++i) work[i] *= R[i]; } } while ( kase != 0 ); /* Normalize error. */ lstres = 0.; if ( notran && colequ ) { for (i = 0; i < A->nrow; ++i) lstres = SUPERLU_MAX( lstres, C[i] * fabs( Xptr[i]) ); } else if ( !notran && rowequ ) { for (i = 0; i < A->nrow; ++i) lstres = SUPERLU_MAX( lstres, R[i] * fabs( Xptr[i]) ); } else { for (i = 0; i < A->nrow; ++i) lstres = SUPERLU_MAX( lstres, fabs( Xptr[i]) ); } if ( lstres != 0. ) ferr[j] /= lstres; } /* for each RHS j ... */ SUPERLU_FREE(work); SUPERLU_FREE(rwork); SUPERLU_FREE(iwork); SUPERLU_FREE(Bjcol.Store); return; } /* dgsrfs */ pysparse-1.1.1/superlu/dgssv.c0000644010116400000240000001556511402270252015354 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include "dsp_defs.h" #include "util.h" void dgssv(SuperMatrix *A, int *perm_c, int *perm_r, SuperMatrix *L, SuperMatrix *U, SuperMatrix *B, int *info ) { /* * Purpose * ======= * * DGSSV solves the system of linear equations A*X=B, using the * LU factorization from DGSTRF. It performs the following steps: * * 1. If A is stored column-wise (A->Stype = NC): * * 1.1. Permute the columns of A, forming A*Pc, where Pc * is a permutation matrix. For more details of this step, * see sp_preorder.c. * * 1.2. Factor A as Pr*A*Pc=L*U with the permutation Pr determined * by Gaussian elimination with partial pivoting. * L is unit lower triangular with offdiagonal entries * bounded by 1 in magnitude, and U is upper triangular. * * 1.3. Solve the system of equations A*X=B using the factored * form of A. * * 2. If A is stored row-wise (A->Stype = NR), apply the * above algorithm to the transpose of A: * * 2.1. Permute columns of transpose(A) (rows of A), * forming transpose(A)*Pc, where Pc is a permutation matrix. * For more details of this step, see sp_preorder.c. * * 2.2. Factor A as Pr*transpose(A)*Pc=L*U with the permutation Pr * determined by Gaussian elimination with partial pivoting. * L is unit lower triangular with offdiagonal entries * bounded by 1 in magnitude, and U is upper triangular. * * 2.3. Solve the system of equations A*X=B using the factored * form of A. * * See supermatrix.h for the definition of 'SuperMatrix' structure. * * Arguments * ========= * * A (input) SuperMatrix* * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number * of linear equations is A->nrow. Currently, the type of A can be: * Stype = NC or NR; Dtype = D_; Mtype = GE. In the future, more * general A will be handled. * * perm_c (input/output) int* * If A->Stype = NC, column permutation vector of size A->ncol * which defines the permutation matrix Pc; perm_c[i] = j means * column i of A is in position j in A*Pc. * On exit, perm_c may be overwritten by the product of the input * perm_c and a permutation that postorders the elimination tree * of Pc'*A'*A*Pc; perm_c is not changed if the elimination tree * is already in postorder. * * If A->Stype = NR, column permutation vector of size A->nrow * which describes permutation of columns of transpose(A) * (rows of A) as described above. * * perm_r (output) int* * If A->Stype = NC, row permutation vector of size A->nrow, * which defines the permutation matrix Pr, and is determined * by partial pivoting. perm_r[i] = j means row i of A is in * position j in Pr*A. * * If A->Stype = NR, permutation vector of size A->ncol, which * determines permutation of rows of transpose(A) * (columns of A) as described above. * * L (output) SuperMatrix* * The factor L from the factorization * Pr*A*Pc=L*U (if A->Stype = NC) or * Pr*transpose(A)*Pc=L*U (if A->Stype = NR). * Uses compressed row subscripts storage for supernodes, i.e., * L has types: Stype = SC, Dtype = D_, Mtype = TRLU. * * U (output) SuperMatrix* * The factor U from the factorization * Pr*A*Pc=L*U (if A->Stype = NC) or * Pr*transpose(A)*Pc=L*U (if A->Stype = NR). * Uses column-wise storage scheme, i.e., U has types: * Stype = NC, Dtype = D_, Mtype = TRU. * * B (input/output) SuperMatrix* * B has types: Stype = DN, Dtype = D_, Mtype = GE. * On entry, the right hand side matrix. * On exit, the solution matrix if info = 0; * * info (output) int* * = 0: successful exit * > 0: if info = i, and i is * <= A->ncol: U(i,i) is exactly zero. The factorization has * been completed, but the factor U is exactly singular, * so the solution could not be computed. * > A->ncol: number of bytes allocated when memory allocation * failure occurred, plus A->ncol. * */ double t1; /* Temporary time */ char refact[1], trans[1]; DNformat *Bstore; SuperMatrix *AA; /* A in NC format used by the factorization routine.*/ SuperMatrix AC; /* Matrix postmultiplied by Pc */ int lwork = 0, *etree, i; /* Set default values for some parameters */ double diag_pivot_thresh = 1.0; double drop_tol = 0; int panel_size; /* panel size */ int relax; /* no of columns in a relaxed snodes */ double *utime; extern SuperLUStat_t SuperLUStat; /* Test the input parameters ... */ *info = 0; Bstore = B->Store; if ( A->nrow != A->ncol || A->nrow < 0 || (A->Stype != NC && A->Stype != NR) || A->Dtype != D_ || A->Mtype != GE ) *info = -1; else if ( B->ncol < 0 || Bstore->lda < SUPERLU_MAX(0, A->nrow) || B->Stype != DN || B->Dtype != D_ || B->Mtype != GE ) *info = -6; if ( *info != 0 ) { i = -(*info); xerbla_("dgssv", &i); return; } *refact = 'N'; *trans = 'N'; panel_size = sp_ienv(1); relax = sp_ienv(2); StatInit(panel_size, relax); utime = SuperLUStat.utime; /* Convert A to NC format when necessary. */ if ( A->Stype == NR ) { NRformat *Astore = A->Store; AA = (SuperMatrix *) SUPERLU_MALLOC( sizeof(SuperMatrix) ); dCreate_CompCol_Matrix(AA, A->ncol, A->nrow, Astore->nnz, Astore->nzval, Astore->colind, Astore->rowptr, NC, A->Dtype, A->Mtype); *trans = 'T'; } else if ( A->Stype == NC ) AA = A; etree = intMalloc(A->ncol); t1 = SuperLU_timer_(); sp_preorder(refact, AA, perm_c, etree, &AC); utime[ETREE] = SuperLU_timer_() - t1; /*printf("Factor PA = LU ... relax %d\tw %d\tmaxsuper %d\trowblk %d\n", relax, panel_size, sp_ienv(3), sp_ienv(4));*/ t1 = SuperLU_timer_(); /* Compute the LU factorization of A. */ dgstrf(refact, &AC, diag_pivot_thresh, drop_tol, relax, panel_size, etree, NULL, lwork, perm_r, perm_c, L, U, info); utime[FACT] = SuperLU_timer_() - t1; t1 = SuperLU_timer_(); if ( *info == 0 ) { /* Solve the system A*X=B, overwriting B with X. */ dgstrs (trans, L, U, perm_r, perm_c, B, info); } utime[SOLVE] = SuperLU_timer_() - t1; SUPERLU_FREE (etree); Destroy_CompCol_Permuted(&AC); if ( A->Stype == NR ) { Destroy_SuperMatrix_Store(AA); SUPERLU_FREE(AA); } /* PrintStat( &SuperLUStat ); */ StatFree(); } pysparse-1.1.1/superlu/dgssvx.c0000644010116400000240000006300211402270215015530 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include "dsp_defs.h" #include "util.h" void dgssvx(char *fact, char *trans, char *refact, SuperMatrix *A, factor_param_t *factor_params, int *perm_c, int *perm_r, int *etree, char *equed, double *R, double *C, SuperMatrix *L, SuperMatrix *U, void *work, int lwork, SuperMatrix *B, SuperMatrix *X, double *recip_pivot_growth, double *rcond, double *ferr, double *berr, mem_usage_t *mem_usage, int *info ) { /* * Purpose * ======= * * DGSSVX solves the system of linear equations A*X=B or A'*X=B, using * the LU factorization from dgstrf(). Error bounds on the solution and * a condition estimate are also provided. It performs the following steps: * * 1. If A is stored column-wise (A->Stype = NC): * * 1.1. If fact = 'E', scaling factors are computed to equilibrate the * system: * trans = 'N': diag(R)*A*diag(C) *inv(diag(C))*X = diag(R)*B * trans = 'T': (diag(R)*A*diag(C))**T *inv(diag(R))*X = diag(C)*B * trans = 'C': (diag(R)*A*diag(C))**H *inv(diag(R))*X = diag(C)*B * Whether or not the system will be equilibrated depends on the * scaling of the matrix A, but if equilibration is used, A is * overwritten by diag(R)*A*diag(C) and B by diag(R)*B (if trans='N') * or diag(C)*B (if trans = 'T' or 'C'). * * 1.2. Permute columns of A, forming A*Pc, where Pc is a permutation * matrix that usually preserves sparsity. * For more details of this step, see sp_preorder.c. * * 1.3. If fact = 'N' or 'E', the LU decomposition is used to factor the * matrix A (after equilibration if fact = 'E') as Pr*A*Pc = L*U, * with Pr determined by partial pivoting. * * 1.4. Compute the reciprocal pivot growth factor. * * 1.5. If some U(i,i) = 0, so that U is exactly singular, then the * routine returns with info = i. Otherwise, the factored form of * A is used to estimate the condition number of the matrix A. If * the reciprocal of the condition number is less than machine * precision, info = A->ncol+1 is returned as a warning, but the * routine still goes on to solve for X and computes error bounds * as described below. * * 1.6. The system of equations is solved for X using the factored form * of A. * * 1.7. Iterative refinement is applied to improve the computed solution * matrix and calculate error bounds and backward error estimates * for it. * * 1.8. If equilibration was used, the matrix X is premultiplied by * diag(C) (if trans = 'N') or diag(R) (if trans = 'T' or 'C') so * that it solves the original system before equilibration. * * 2. If A is stored row-wise (A->Stype = NR), apply the above algorithm * to the transpose of A: * * 2.1. If fact = 'E', scaling factors are computed to equilibrate the * system: * trans = 'N': diag(R)*A'*diag(C) *inv(diag(C))*X = diag(R)*B * trans = 'T': (diag(R)*A'*diag(C))**T *inv(diag(R))*X = diag(C)*B * trans = 'C': (diag(R)*A'*diag(C))**H *inv(diag(R))*X = diag(C)*B * Whether or not the system will be equilibrated depends on the * scaling of the matrix A, but if equilibration is used, A' is * overwritten by diag(R)*A'*diag(C) and B by diag(R)*B * (if trans='N') or diag(C)*B (if trans = 'T' or 'C'). * * 2.2. Permute columns of transpose(A) (rows of A), * forming transpose(A)*Pc, where Pc is a permutation matrix that * usually preserves sparsity. * For more details of this step, see sp_preorder.c. * * 2.3. If fact = 'N' or 'E', the LU decomposition is used to factor the * transpose(A) (after equilibration if fact = 'E') as * Pr*transpose(A)*Pc = L*U with the permutation Pr determined by * partial pivoting. * * 2.4. Compute the reciprocal pivot growth factor. * * 2.5. If some U(i,i) = 0, so that U is exactly singular, then the * routine returns with info = i. Otherwise, the factored form * of transpose(A) is used to estimate the condition number of the * matrix A. If the reciprocal of the condition number * is less than machine precision, info = A->nrow+1 is returned as * a warning, but the routine still goes on to solve for X and * computes error bounds as described below. * * 2.6. The system of equations is solved for X using the factored form * of transpose(A). * * 2.7. Iterative refinement is applied to improve the computed solution * matrix and calculate error bounds and backward error estimates * for it. * * 2.8. If equilibration was used, the matrix X is premultiplied by * diag(C) (if trans = 'N') or diag(R) (if trans = 'T' or 'C') so * that it solves the original system before equilibration. * * See supermatrix.h for the definition of 'SuperMatrix' structure. * * Arguments * ========= * * fact (input) char* * Specifies whether or not the factored form of the matrix * A is supplied on entry, and if not, whether the matrix A should * be equilibrated before it is factored. * = 'F': On entry, L, U, perm_r and perm_c contain the factored * form of A. If equed is not 'N', the matrix A has been * equilibrated with scaling factors R and C. * A, L, U, perm_r are not modified. * = 'N': The matrix A will be factored, and the factors will be * stored in L and U. * = 'E': The matrix A will be equilibrated if necessary, then * factored into L and U. * * trans (input) char* * Specifies the form of the system of equations: * = 'N': A * X = B (No transpose) * = 'T': A**T * X = B (Transpose) * = 'C': A**H * X = B (Transpose) * * refact (input) char* * Specifies whether we want to re-factor the matrix. * = 'N': Factor the matrix A. * = 'Y': Matrix A was factored before, now we want to re-factor * matrix A with perm_r and etree as inputs. Use * the same storage for the L\U factors previously allocated, * expand it if necessary. User should insure to use the same * memory model. In this case, perm_r may be modified due to * different pivoting determined by diagonal threshold. * If fact = 'F', then refact is not accessed. * * A (input/output) SuperMatrix* * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number * of the linear equations is A->nrow. Currently, the type of A can be: * Stype = NC or NR, Dtype = D_, Mtype = GE. In the future, * more general A can be handled. * * On entry, If fact = 'F' and equed is not 'N', then A must have * been equilibrated by the scaling factors in R and/or C. * A is not modified if fact = 'F' or 'N', or if fact = 'E' and * equed = 'N' on exit. * * On exit, if fact = 'E' and equed is not 'N', A is scaled as follows: * If A->Stype = NC: * equed = 'R': A := diag(R) * A * equed = 'C': A := A * diag(C) * equed = 'B': A := diag(R) * A * diag(C). * If A->Stype = NR: * equed = 'R': transpose(A) := diag(R) * transpose(A) * equed = 'C': transpose(A) := transpose(A) * diag(C) * equed = 'B': transpose(A) := diag(R) * transpose(A) * diag(C). * * factor_params (input) factor_param_t* * The structure defines the input scalar parameters, consisting of * the following fields. If factor_params = NULL, the default * values are used for all the fields; otherwise, the values * are given by the user. * - panel_size (int): Panel size. A panel consists of at most * panel_size consecutive columns. If panel_size = -1, use * default value 8. * - relax (int): To control degree of relaxing supernodes. If the * number of nodes (columns) in a subtree of the elimination * tree is less than relax, this subtree is considered as one * supernode, regardless of the row structures of those columns. * If relax = -1, use default value 8. * - diag_pivot_thresh (double): Diagonal pivoting threshold. * At step j of the Gaussian elimination, if * abs(A_jj) >= diag_pivot_thresh * (max_(i>=j) abs(A_ij)), * then use A_jj as pivot. 0 <= diag_pivot_thresh <= 1. * If diag_pivot_thresh = -1, use default value 1.0, * which corresponds to standard partial pivoting. * - drop_tol (double): Drop tolerance threshold. (NOT IMPLEMENTED) * At step j of the Gaussian elimination, if * abs(A_ij)/(max_i abs(A_ij)) < drop_tol, * then drop entry A_ij. 0 <= drop_tol <= 1. * If drop_tol = -1, use default value 0.0, which corresponds to * standard Gaussian elimination. * * perm_c (input/output) int* * If A->Stype = NC, Column permutation vector of size A->ncol, * which defines the permutation matrix Pc; perm_c[i] = j means * column i of A is in position j in A*Pc. * On exit, perm_c may be overwritten by the product of the input * perm_c and a permutation that postorders the elimination tree * of Pc'*A'*A*Pc; perm_c is not changed if the elimination tree * is already in postorder. * * If A->Stype = NR, column permutation vector of size A->nrow, * which describes permutation of columns of transpose(A) * (rows of A) as described above. * * perm_r (input/output) int* * If A->Stype = NC, row permutation vector of size A->nrow, * which defines the permutation matrix Pr, and is determined * by partial pivoting. perm_r[i] = j means row i of A is in * position j in Pr*A. * * If A->Stype = NR, permutation vector of size A->ncol, which * determines permutation of rows of transpose(A) * (columns of A) as described above. * * If refact is not 'Y', perm_r is output argument; * If refact = 'Y', the pivoting routine will try to use the input * perm_r, unless a certain threshold criterion is violated. * In that case, perm_r is overwritten by a new permutation * determined by partial pivoting or diagonal threshold pivoting. * * etree (input/output) int*, dimension (A->ncol) * Elimination tree of Pc'*A'*A*Pc. * If fact is not 'F' and refact = 'Y', etree is an input argument, * otherwise it is an output argument. * Note: etree is a vector of parent pointers for a forest whose * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol. * * equed (input/output) char* * Specifies the form of equilibration that was done. * = 'N': No equilibration. * = 'R': Row equilibration, i.e., A was premultiplied by diag(R). * = 'C': Column equilibration, i.e., A was postmultiplied by diag(C). * = 'B': Both row and column equilibration, i.e., A was replaced * by diag(R)*A*diag(C). * If fact = 'F', equed is an input argument, otherwise it is * an output argument. * * R (input/output) double*, dimension (A->nrow) * The row scale factors for A or transpose(A). * If equed = 'R' or 'B', A (if A->Stype = NC) or transpose(A) (if * A->Stype = NR) is multiplied on the left by diag(R). * If equed = 'N' or 'C', R is not accessed. * If fact = 'F', R is an input argument; otherwise, R is output. * If fact = 'F' and equed = 'R' or 'B', each element of R must * be positive. * * C (input/output) double*, dimension (A->ncol) * The column scale factors for A or transpose(A). * If equed = 'C' or 'B', A (if A->Stype = NC) or transpose(A) (if * A->Stype = NR) is multiplied on the right by diag(C). * If equed = 'N' or 'R', C is not accessed. * If fact = 'F', C is an input argument; otherwise, C is output. * If fact = 'F' and equed = 'C' or 'B', each element of C must * be positive. * * L (output) SuperMatrix* * The factor L from the factorization * Pr*A*Pc=L*U (if A->Stype = NC) or * Pr*transpose(A)*Pc=L*U (if A->Stype = NR). * Uses compressed row subscripts storage for supernodes, i.e., * L has types: Stype = SC, Dtype = D_, Mtype = TRLU. * * U (output) SuperMatrix* * The factor U from the factorization * Pr*A*Pc=L*U (if A->Stype = NC) or * Pr*transpose(A)*Pc=L*U (if A->Stype = NR). * Uses column-wise storage scheme, i.e., U has types: * Stype = NC, Dtype = D_, Mtype = TRU. * * work (workspace/output) void*, size (lwork) (in bytes) * User supplied workspace, should be large enough * to hold data structures for factors L and U. * On exit, if fact is not 'F', L and U point to this array. * * lwork (input) int * Specifies the size of work array in bytes. * = 0: allocate space internally by system malloc; * > 0: use user-supplied work array of length lwork in bytes, * returns error if space runs out. * = -1: the routine guesses the amount of space needed without * performing the factorization, and returns it in * mem_usage->total_needed; no other side effects. * * See argument 'mem_usage' for memory usage statistics. * * B (input/output) SuperMatrix* * B has types: Stype = DN, Dtype = D_, Mtype = GE. * On entry, the right hand side matrix. * On exit, * if equed = 'N', B is not modified; otherwise * if A->Stype = NC: * if trans = 'N' and equed = 'R' or 'B', B is overwritten by * diag(R)*B; * if trans = 'T' or 'C' and equed = 'C' of 'B', B is * overwritten by diag(C)*B; * if A->Stype = NR: * if trans = 'N' and equed = 'C' or 'B', B is overwritten by * diag(C)*B; * if trans = 'T' or 'C' and equed = 'R' of 'B', B is * overwritten by diag(R)*B. * * X (output) SuperMatrix* * X has types: Stype = DN, Dtype = D_, Mtype = GE. * If info = 0 or info = A->ncol+1, X contains the solution matrix * to the original system of equations. Note that A and B are modified * on exit if equed is not 'N', and the solution to the equilibrated * system is inv(diag(C))*X if trans = 'N' and equed = 'C' or 'B', * or inv(diag(R))*X if trans = 'T' or 'C' and equed = 'R' or 'B'. * * recip_pivot_growth (output) double* * The reciprocal pivot growth factor max_j( norm(A_j)/norm(U_j) ). * The infinity norm is used. If recip_pivot_growth is much less * than 1, the stability of the LU factorization could be poor. * * rcond (output) double* * The estimate of the reciprocal condition number of the matrix A * after equilibration (if done). If rcond is less than the machine * precision (in particular, if rcond = 0), the matrix is singular * to working precision. This condition is indicated by a return * code of info > 0. * * FERR (output) double*, dimension (B->ncol) * The estimated forward error bound for each solution vector * X(j) (the j-th column of the solution matrix X). * If XTRUE is the true solution corresponding to X(j), FERR(j) * is an estimated upper bound for the magnitude of the largest * element in (X(j) - XTRUE) divided by the magnitude of the * largest element in X(j). The estimate is as reliable as * the estimate for RCOND, and is almost always a slight * overestimate of the true error. * * BERR (output) double*, dimension (B->ncol) * The componentwise relative backward error of each solution * vector X(j) (i.e., the smallest relative change in * any element of A or B that makes X(j) an exact solution). * * mem_usage (output) mem_usage_t* * Record the memory usage statistics, consisting of following fields: * - for_lu (float) * The amount of space used in bytes for L\U data structures. * - total_needed (float) * The amount of space needed in bytes to perform factorization. * - expansions (int) * The number of memory expansions during the LU factorization. * * info (output) int* * = 0: successful exit * < 0: if info = -i, the i-th argument had an illegal value * > 0: if info = i, and i is * <= A->ncol: U(i,i) is exactly zero. The factorization has * been completed, but the factor U is exactly * singular, so the solution and error bounds * could not be computed. * = A->ncol+1: U is nonsingular, but RCOND is less than machine * precision, meaning that the matrix is singular to * working precision. Nevertheless, the solution and * error bounds are computed because there are a number * of situations where the computed solution can be more * accurate than the value of RCOND would suggest. * > A->ncol+1: number of bytes allocated when memory allocation * failure occurred, plus A->ncol. * */ DNformat *Bstore, *Xstore; double *Bmat, *Xmat; int ldb, ldx, nrhs; SuperMatrix *AA; /* A in NC format used by the factorization routine.*/ SuperMatrix AC; /* Matrix postmultiplied by Pc */ int colequ, equil, nofact, notran, rowequ; char trant[1], norm[1]; int i, j, info1; double amax, anorm, bignum, smlnum, colcnd, rowcnd, rcmax, rcmin; int relax, panel_size; double diag_pivot_thresh, drop_tol; double t0; /* temporary time */ double *utime; extern SuperLUStat_t SuperLUStat; /* External functions */ extern double dlangs(char *, SuperMatrix *); extern double dlamch_(char *); Bstore = B->Store; Xstore = X->Store; Bmat = Bstore->nzval; Xmat = Xstore->nzval; ldb = Bstore->lda; ldx = Xstore->lda; nrhs = B->ncol; #if 0 printf("dgssvx: fact=%c, trans=%c, refact=%c, equed=%c\n", *fact, *trans, *refact, *equed); #endif *info = 0; nofact = lsame_(fact, "N"); equil = lsame_(fact, "E"); notran = lsame_(trans, "N"); if (nofact || equil) { *(unsigned char *)equed = 'N'; rowequ = FALSE; colequ = FALSE; } else { rowequ = lsame_(equed, "R") || lsame_(equed, "B"); colequ = lsame_(equed, "C") || lsame_(equed, "B"); smlnum = dlamch_("Safe minimum"); bignum = 1. / smlnum; } /* Test the input parameters */ if (!nofact && !equil && !lsame_(fact, "F")) *info = -1; else if (!notran && !lsame_(trans, "T") && !lsame_(trans, "C")) *info = -2; else if ( !(lsame_(refact,"Y") || lsame_(refact, "N")) ) *info = -3; else if ( A->nrow != A->ncol || A->nrow < 0 || (A->Stype != NC && A->Stype != NR) || A->Dtype != D_ || A->Mtype != GE ) *info = -4; else if (lsame_(fact, "F") && !(rowequ || colequ || lsame_(equed, "N"))) *info = -9; else { if (rowequ) { rcmin = bignum; rcmax = 0.; for (j = 0; j < A->nrow; ++j) { rcmin = SUPERLU_MIN(rcmin, R[j]); rcmax = SUPERLU_MAX(rcmax, R[j]); } if (rcmin <= 0.) *info = -10; else if ( A->nrow > 0) rowcnd = SUPERLU_MAX(rcmin,smlnum) / SUPERLU_MIN(rcmax,bignum); else rowcnd = 1.; } if (colequ && *info == 0) { rcmin = bignum; rcmax = 0.; for (j = 0; j < A->nrow; ++j) { rcmin = SUPERLU_MIN(rcmin, C[j]); rcmax = SUPERLU_MAX(rcmax, C[j]); } if (rcmin <= 0.) *info = -11; else if (A->nrow > 0) colcnd = SUPERLU_MAX(rcmin,smlnum) / SUPERLU_MIN(rcmax,bignum); else colcnd = 1.; } if (*info == 0) { if ( lwork < -1 ) *info = -15; else if ( B->ncol < 0 || Bstore->lda < SUPERLU_MAX(0, A->nrow) || B->Stype != DN || B->Dtype != D_ || B->Mtype != GE ) *info = -16; else if ( X->ncol < 0 || Xstore->lda < SUPERLU_MAX(0, A->nrow) || B->ncol != X->ncol || X->Stype != DN || X->Dtype != D_ || X->Mtype != GE ) *info = -17; } } if (*info != 0) { i = -(*info); xerbla_("dgssvx", &i); return; } /* Default values for factor_params */ panel_size = sp_ienv(1); relax = sp_ienv(2); diag_pivot_thresh = 1.0; drop_tol = 0.0; if ( factor_params != NULL ) { if ( factor_params->panel_size != -1 ) panel_size = factor_params->panel_size; if ( factor_params->relax != -1 ) relax = factor_params->relax; if ( factor_params->diag_pivot_thresh != -1 ) diag_pivot_thresh = factor_params->diag_pivot_thresh; if ( factor_params->drop_tol != -1 ) drop_tol = factor_params->drop_tol; } StatInit(panel_size, relax); utime = SuperLUStat.utime; /* Convert A to NC format when necessary. */ if ( A->Stype == NR ) { NRformat *Astore = A->Store; AA = (SuperMatrix *) SUPERLU_MALLOC( sizeof(SuperMatrix) ); dCreate_CompCol_Matrix(AA, A->ncol, A->nrow, Astore->nnz, Astore->nzval, Astore->colind, Astore->rowptr, NC, A->Dtype, A->Mtype); if ( notran ) { /* Reverse the transpose argument. */ *trant = 'T'; notran = 0; } else { *trant = 'N'; notran = 1; } } else { /* A->Stype == NC */ *trant = *trans; AA = A; } if ( equil ) { t0 = SuperLU_timer_(); /* Compute row and column scalings to equilibrate the matrix A. */ dgsequ(AA, R, C, &rowcnd, &colcnd, &amax, &info1); if ( info1 == 0 ) { /* Equilibrate matrix A. */ dlaqgs(AA, R, C, rowcnd, colcnd, amax, equed); rowequ = lsame_(equed, "R") || lsame_(equed, "B"); colequ = lsame_(equed, "C") || lsame_(equed, "B"); } utime[EQUIL] = SuperLU_timer_() - t0; } /* Scale the right hand side if equilibration was performed. */ if ( notran ) { if ( rowequ ) { for (j = 0; j < nrhs; ++j) for (i = 0; i < A->nrow; ++i) { Bmat[i + j*ldb] *= R[i]; } } } else if ( colequ ) { for (j = 0; j < nrhs; ++j) for (i = 0; i < A->nrow; ++i) { Bmat[i + j*ldb] *= C[i]; } } if ( nofact || equil ) { t0 = SuperLU_timer_(); sp_preorder(refact, AA, perm_c, etree, &AC); utime[ETREE] = SuperLU_timer_() - t0; /* printf("Factor PA = LU ... relax %d\tw %d\tmaxsuper %d\trowblk %d\n", relax, panel_size, sp_ienv(3), sp_ienv(4)); fflush(stdout); */ /* Compute the LU factorization of A*Pc. */ t0 = SuperLU_timer_(); dgstrf(refact, &AC, diag_pivot_thresh, drop_tol, relax, panel_size, etree, work, lwork, perm_r, perm_c, L, U, info); utime[FACT] = SuperLU_timer_() - t0; if ( lwork == -1 ) { mem_usage->total_needed = *info - A->ncol; return; } } if ( *info > 0 ) { if ( *info <= A->ncol ) { /* Compute the reciprocal pivot growth factor of the leading rank-deficient *info columns of A. */ *recip_pivot_growth = dPivotGrowth(*info, AA, perm_c, L, U); } return; } /* Compute the reciprocal pivot growth factor *recip_pivot_growth. */ *recip_pivot_growth = dPivotGrowth(A->ncol, AA, perm_c, L, U); /* Estimate the reciprocal of the condition number of A. */ t0 = SuperLU_timer_(); if ( notran ) { *(unsigned char *)norm = '1'; } else { *(unsigned char *)norm = 'I'; } anorm = dlangs(norm, AA); dgscon(norm, L, U, anorm, rcond, info); utime[RCOND] = SuperLU_timer_() - t0; /* Compute the solution matrix X. */ for (j = 0; j < nrhs; j++) /* Save a copy of the right hand sides */ for (i = 0; i < B->nrow; i++) Xmat[i + j*ldx] = Bmat[i + j*ldb]; t0 = SuperLU_timer_(); dgstrs (trant, L, U, perm_r, perm_c, X, info); utime[SOLVE] = SuperLU_timer_() - t0; /* Use iterative refinement to improve the computed solution and compute error bounds and backward error estimates for it. */ t0 = SuperLU_timer_(); dgsrfs(trant, AA, L, U, perm_r, perm_c, equed, R, C, B, X, ferr, berr, info); utime[REFINE] = SuperLU_timer_() - t0; /* Transform the solution matrix X to a solution of the original system. */ if ( notran ) { if ( colequ ) { for (j = 0; j < nrhs; ++j) for (i = 0; i < A->nrow; ++i) { Xmat[i + j*ldx] *= C[i]; } } } else if ( rowequ ) { for (j = 0; j < nrhs; ++j) for (i = 0; i < A->nrow; ++i) { Xmat[i + j*ldx] *= R[i]; } } /* Set INFO = A->ncol+1 if the matrix is singular to working precision. */ if ( *rcond < dlamch_("E") ) *info = A->ncol + 1; dQuerySpace(L, U, panel_size, mem_usage); if ( nofact || equil ) Destroy_CompCol_Permuted(&AC); if ( A->Stype == NR ) { Destroy_SuperMatrix_Store(AA); SUPERLU_FREE(AA); } /* PrintStat( &SuperLUStat ); */ StatFree(); } pysparse-1.1.1/superlu/dgstrf.c0000644010116400000240000003735311402270240015513 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * * Last modified: June 6, 2002 */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "dsp_defs.h" #include "util.h" void dgstrf (char *refact, SuperMatrix *A, double diag_pivot_thresh, double drop_tol, int relax, int panel_size, int *etree, void *work, int lwork, int *perm_r, int *perm_c, SuperMatrix *L, SuperMatrix *U, int *info) { /* * Purpose * ======= * * DGSTRF computes an LU factorization of a general sparse m-by-n * matrix A using partial pivoting with row interchanges. * The factorization has the form * Pr * A = L * U * where Pr is a row permutation matrix, L is lower triangular with unit * diagonal elements (lower trapezoidal if A->nrow > A->ncol), and U is upper * triangular (upper trapezoidal if A->nrow < A->ncol). * * See supermatrix.h for the definition of 'SuperMatrix' structure. * * Arguments * ========= * * refact (input) char* * Specifies whether we want to use perm_r from a previous factor. * = 'Y': re-use perm_r; perm_r is input, and may be modified due to * different pivoting determined by diagonal threshold. * = 'N': perm_r is determined by partial pivoting, and output. * * A (input) SuperMatrix* * Original matrix A, permuted by columns, of dimension * (A->nrow, A->ncol). The type of A can be: * Stype = NCP; Dtype = D; Mtype = GE. * * diag_pivot_thresh (input) double * Diagonal pivoting threshold. At step j of the Gaussian elimination, * if abs(A_jj) >= thresh * (max_(i>=j) abs(A_ij)), use A_jj as pivot. * 0 <= thresh <= 1. The default value of thresh is 1, corresponding * to partial pivoting. * * drop_tol (input) double (NOT IMPLEMENTED) * Drop tolerance parameter. At step j of the Gaussian elimination, * if abs(A_ij)/(max_i abs(A_ij)) < drop_tol, drop entry A_ij. * 0 <= drop_tol <= 1. The default value of drop_tol is 0. * * relax (input) int * To control degree of relaxing supernodes. If the number * of nodes (columns) in a subtree of the elimination tree is less * than relax, this subtree is considered as one supernode, * regardless of the row structures of those columns. * * panel_size (input) int * A panel consists of at most panel_size consecutive columns. * * etree (input) int*, dimension (A->ncol) * Elimination tree of A'*A. * Note: etree is a vector of parent pointers for a forest whose * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol. * On input, the columns of A should be permuted so that the * etree is in a certain postorder. * * work (input/output) void*, size (lwork) (in bytes) * User-supplied work space and space for the output data structures. * Not referenced if lwork = 0; * * lwork (input) int * Specifies the size of work array in bytes. * = 0: allocate space internally by system malloc; * > 0: use user-supplied work array of length lwork in bytes, * returns error if space runs out. * = -1: the routine guesses the amount of space needed without * performing the factorization, and returns it in * *info; no other side effects. * * perm_r (input/output) int*, dimension (A->nrow) * Row permutation vector which defines the permutation matrix Pr, * perm_r[i] = j means row i of A is in position j in Pr*A. * If refact is not 'Y', perm_r is output argument; * If refact = 'Y', the pivoting routine will try to use the input * perm_r, unless a certain threshold criterion is violated. * In that case, perm_r is overwritten by a new permutation * determined by partial pivoting or diagonal threshold pivoting. * * perm_c (input) int*, dimension (A->ncol) * Column permutation vector, which defines the * permutation matrix Pc; perm_c[i] = j means column i of A is * in position j in A*Pc. * When searching for diagonal, perm_c[*] is applied to the * row subscripts of A, so that diagonal threshold pivoting * can find the diagonal of A, rather than that of A*Pc. * * L (output) SuperMatrix* * The factor L from the factorization Pr*A=L*U; use compressed row * subscripts storage for supernodes, i.e., L has type: * Stype = SC, Dtype = D_, Mtype = TRLU. * * U (output) SuperMatrix* * The factor U from the factorization Pr*A*Pc=L*U. Use column-wise * storage scheme, i.e., U has types: Stype = NC, * Dtype = D_, Mtype = TRU. * * info (output) int* * = 0: successful exit * < 0: if info = -i, the i-th argument had an illegal value * > 0: if info = i, and i is * <= A->ncol: U(i,i) is exactly zero. The factorization has * been completed, but the factor U is exactly singular, * and division by zero will occur if it is used to solve a * system of equations. * > A->ncol: number of bytes allocated when memory allocation * failure occurred, plus A->ncol. If lwork = -1, it is * the estimated amount of space needed, plus A->ncol. * * ====================================================================== * * Local Working Arrays: * ====================== * m = number of rows in the matrix * n = number of columns in the matrix * * xprune[0:n-1]: xprune[*] points to locations in subscript * vector lsub[*]. For column i, xprune[i] denotes the point where * structural pruning begins. I.e. only xlsub[i],..,xprune[i]-1 need * to be traversed for symbolic factorization. * * marker[0:3*m-1]: marker[i] = j means that node i has been * reached when working on column j. * Storage: relative to original row subscripts * NOTE: There are 3 of them: marker/marker1 are used for panel dfs, * see dpanel_dfs.c; marker2 is used for inner-factorization, * see dcolumn_dfs.c. * * parent[0:m-1]: parent vector used during dfs * Storage: relative to new row subscripts * * xplore[0:m-1]: xplore[i] gives the location of the next (dfs) * unexplored neighbor of i in lsub[*] * * segrep[0:nseg-1]: contains the list of supernodal representatives * in topological order of the dfs. A supernode representative is the * last column of a supernode. * The maximum size of segrep[] is n. * * repfnz[0:W*m-1]: for a nonzero segment U[*,j] that ends at a * supernodal representative r, repfnz[r] is the location of the first * nonzero in this segment. It is also used during the dfs: repfnz[r]>0 * indicates the supernode r has been explored. * NOTE: There are W of them, each used for one column of a panel. * * panel_lsub[0:W*m-1]: temporary for the nonzeros row indices below * the panel diagonal. These are filled in during dpanel_dfs(), and are * used later in the inner LU factorization within the panel. * panel_lsub[]/dense[] pair forms the SPA data structure. * NOTE: There are W of them. * * dense[0:W*m-1]: sparse accumulating (SPA) vector for intermediate values; * NOTE: there are W of them. * * tempv[0:*]: real temporary used for dense numeric kernels; * The size of this array is defined by NUM_TEMPV() in dsp_defs.h. * */ /* Local working arrays */ NCPformat *Astore; int *iperm_r; /* inverse of perm_r; not used if refact = 'N' */ int *iperm_c; /* inverse of perm_c */ int *iwork; double *dwork; int *segrep, *repfnz, *parent, *xplore; int *panel_lsub; /* dense[]/panel_lsub[] pair forms a w-wide SPA */ int *xprune; int *marker; double *dense, *tempv; int *relax_end; double *a; int *asub; int *xa_begin, *xa_end; int *xsup, *supno; int *xlsub, *xlusup, *xusub; int nzlumax; static GlobalLU_t Glu; /* persistent to facilitate multiple factors. */ /* Local scalars */ int pivrow; /* pivotal row number in the original matrix A */ int nseg1; /* no of segments in U-column above panel row jcol */ int nseg; /* no of segments in each U-column */ register int jcol; register int kcol; /* end column of a relaxed snode */ register int icol; register int i, k, jj, new_next, iinfo; int m, n, min_mn, jsupno, fsupc, nextlu, nextu; int w_def; /* upper bound on panel width */ int usepr, iperm_r_allocated = 0; int nnzL, nnzU; extern SuperLUStat_t SuperLUStat; int *panel_histo = SuperLUStat.panel_histo; flops_t *ops = SuperLUStat.ops; iinfo = 0; m = A->nrow; n = A->ncol; min_mn = SUPERLU_MIN(m, n); Astore = A->Store; a = Astore->nzval; asub = Astore->rowind; xa_begin = Astore->colbeg; xa_end = Astore->colend; /* Allocate storage common to the factor routines */ *info = dLUMemInit(refact, work, lwork, m, n, Astore->nnz, panel_size, L, U, &Glu, &iwork, &dwork); if ( *info ) return; xsup = Glu.xsup; supno = Glu.supno; xlsub = Glu.xlsub; xlusup = Glu.xlusup; xusub = Glu.xusub; SetIWork(m, n, panel_size, iwork, &segrep, &parent, &xplore, &repfnz, &panel_lsub, &xprune, &marker); dSetRWork(m, panel_size, dwork, &dense, &tempv); usepr = lsame_(refact, "Y"); if ( usepr ) { /* Compute the inverse of perm_r */ iperm_r = (int *) intMalloc(m); for (k = 0; k < m; ++k) iperm_r[perm_r[k]] = k; iperm_r_allocated = 1; } iperm_c = (int *) intMalloc(n); for (k = 0; k < n; ++k) iperm_c[perm_c[k]] = k; /* Identify relaxed snodes */ relax_end = (int *) intMalloc(n); relax_snode(n, etree, relax, marker, relax_end); ifill (perm_r, m, EMPTY); ifill (marker, m * NO_MARKER, EMPTY); supno[0] = -1; xsup[0] = xlsub[0] = xusub[0] = xlusup[0] = 0; w_def = panel_size; /* * Work on one "panel" at a time. A panel is one of the following: * (a) a relaxed supernode at the bottom of the etree, or * (b) panel_size contiguous columns, defined by the user */ for (jcol = 0; jcol < min_mn; ) { if ( relax_end[jcol] != EMPTY ) { /* start of a relaxed snode */ kcol = relax_end[jcol]; /* end of the relaxed snode */ panel_histo[kcol-jcol+1]++; /* -------------------------------------- * Factorize the relaxed supernode(jcol:kcol) * -------------------------------------- */ /* Determine the union of the row structure of the snode */ if ( (*info = dsnode_dfs(jcol, kcol, asub, xa_begin, xa_end, xprune, marker, &Glu)) != 0 ) return; nextu = xusub[jcol]; nextlu = xlusup[jcol]; jsupno = supno[jcol]; fsupc = xsup[jsupno]; new_next = nextlu + (xlsub[fsupc+1]-xlsub[fsupc])*(kcol-jcol+1); nzlumax = Glu.nzlumax; while ( new_next > nzlumax ) { if ( *info = dLUMemXpand(jcol, nextlu, LUSUP, &nzlumax, &Glu) ) return; } for (icol = jcol; icol<= kcol; icol++) { xusub[icol+1] = nextu; /* Scatter into SPA dense[*] */ for (k = xa_begin[icol]; k < xa_end[icol]; k++) dense[asub[k]] = a[k]; /* Numeric update within the snode */ dsnode_bmod(icol, jsupno, fsupc, dense, tempv, &Glu); if ( *info = dpivotL(icol, diag_pivot_thresh, &usepr, perm_r, iperm_r, iperm_c, &pivrow, &Glu) ) if ( iinfo == 0 ) iinfo = *info; #ifdef DEBUG dprint_lu_col("[1]: ", icol, pivrow, xprune, &Glu); #endif } jcol = icol; } else { /* Work on one panel of panel_size columns */ /* Adjust panel_size so that a panel won't overlap with the next * relaxed snode. */ panel_size = w_def; for (k = jcol + 1; k < SUPERLU_MIN(jcol+panel_size, min_mn); k++) if ( relax_end[k] != EMPTY ) { panel_size = k - jcol; break; } if ( k == min_mn ) panel_size = min_mn - jcol; panel_histo[panel_size]++; /* symbolic factor on a panel of columns */ dpanel_dfs(m, panel_size, jcol, A, perm_r, &nseg1, dense, panel_lsub, segrep, repfnz, xprune, marker, parent, xplore, &Glu); /* numeric sup-panel updates in topological order */ dpanel_bmod(m, panel_size, jcol, nseg1, dense, tempv, segrep, repfnz, &Glu); /* Sparse LU within the panel, and below panel diagonal */ for ( jj = jcol; jj < jcol + panel_size; jj++) { k = (jj - jcol) * m; /* column index for w-wide arrays */ nseg = nseg1; /* Begin after all the panel segments */ if ((*info = dcolumn_dfs(m, jj, perm_r, &nseg, &panel_lsub[k], segrep, &repfnz[k], xprune, marker, parent, xplore, &Glu)) != 0) return; /* Numeric updates */ if ((*info = dcolumn_bmod(jj, (nseg - nseg1), &dense[k], tempv, &segrep[nseg1], &repfnz[k], jcol, &Glu)) != 0) return; /* Copy the U-segments to ucol[*] */ if ((*info = dcopy_to_ucol(jj, nseg, segrep, &repfnz[k], perm_r, &dense[k], &Glu)) != 0) return; if ( *info = dpivotL(jj, diag_pivot_thresh, &usepr, perm_r, iperm_r, iperm_c, &pivrow, &Glu) ) if ( iinfo == 0 ) iinfo = *info; /* Prune columns (0:jj-1) using column jj */ dpruneL(jj, perm_r, pivrow, nseg, segrep, &repfnz[k], xprune, &Glu); /* Reset repfnz[] for this column */ resetrep_col (nseg, segrep, &repfnz[k]); #ifdef DEBUG dprint_lu_col("[2]: ", jj, pivrow, xprune, &Glu); #endif } jcol += panel_size; /* Move to the next panel */ } /* else */ } /* for */ *info = iinfo; if ( m > n ) { k = 0; for (i = 0; i < m; ++i) if ( perm_r[i] == EMPTY ) { perm_r[i] = n + k; ++k; } } countnz(min_mn, xprune, &nnzL, &nnzU, &Glu); fixupL(min_mn, perm_r, &Glu); dLUWorkFree(iwork, dwork, &Glu); /* Free work space and compress storage */ if ( lsame_(refact, "Y") ) { /* L and U structures may have changed due to possibly different pivoting, although the storage is available. There could also be memory expansions, so the array locations may have changed, */ ((SCformat *)L->Store)->nnz = nnzL; ((SCformat *)L->Store)->nsuper = Glu.supno[n]; ((SCformat *)L->Store)->nzval = Glu.lusup; ((SCformat *)L->Store)->nzval_colptr = Glu.xlusup; ((SCformat *)L->Store)->rowind = Glu.lsub; ((SCformat *)L->Store)->rowind_colptr = Glu.xlsub; ((NCformat *)U->Store)->nnz = nnzU; ((NCformat *)U->Store)->nzval = Glu.ucol; ((NCformat *)U->Store)->rowind = Glu.usub; ((NCformat *)U->Store)->colptr = Glu.xusub; } else { dCreate_SuperNode_Matrix(L, A->nrow, A->ncol, nnzL, Glu.lusup, Glu.xlusup, Glu.lsub, Glu.xlsub, Glu.supno, Glu.xsup, SC, D_, TRLU); dCreate_CompCol_Matrix(U, min_mn, min_mn, nnzU, Glu.ucol, Glu.usub, Glu.xusub, NC, D_, TRU); } ops[FACT] += ops[TRSV] + ops[GEMV]; if ( iperm_r_allocated ) SUPERLU_FREE (iperm_r); SUPERLU_FREE (iperm_c); SUPERLU_FREE (relax_end); } pysparse-1.1.1/superlu/dgstrs.c0000644010116400000240000002207511402270176015533 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "dsp_defs.h" #include "util.h" /* * Function prototypes */ void dusolve(int, int, double*, double*); void dlsolve(int, int, double*, double*); void dmatvec(int, int, int, double*, double*, double*); void dgstrs (char *trans, SuperMatrix *L, SuperMatrix *U, int *perm_r, int *perm_c, SuperMatrix *B, int *info) { /* * Purpose * ======= * * DGSTRS solves a system of linear equations A*X=B or A'*X=B * with A sparse and B dense, using the LU factorization computed by * DGSTRF. * * See supermatrix.h for the definition of 'SuperMatrix' structure. * * Arguments * ========= * * trans (input) char* * Specifies the form of the system of equations: * = 'N': A * X = B (No transpose) * = 'T': A'* X = B (Transpose) * = 'C': A**H * X = B (Conjugate transpose) * * L (input) SuperMatrix* * The factor L from the factorization Pr*A*Pc=L*U as computed by * dgstrf(). Use compressed row subscripts storage for supernodes, * i.e., L has types: Stype = SC, Dtype = D_, Mtype = TRLU. * * U (input) SuperMatrix* * The factor U from the factorization Pr*A*Pc=L*U as computed by * dgstrf(). Use column-wise storage scheme, i.e., U has types: * Stype = NC, Dtype = D_, Mtype = TRU. * * perm_r (input) int*, dimension (L->nrow) * Row permutation vector, which defines the permutation matrix Pr; * perm_r[i] = j means row i of A is in position j in Pr*A. * * perm_c (input) int*, dimension (L->ncol) * Column permutation vector, which defines the * permutation matrix Pc; perm_c[i] = j means column i of A is * in position j in A*Pc. * * B (input/output) SuperMatrix* * B has types: Stype = DN, Dtype = D_, Mtype = GE. * On entry, the right hand side matrix. * On exit, the solution matrix if info = 0; * * info (output) int* * = 0: successful exit * < 0: if info = -i, the i-th argument had an illegal value * */ #ifdef _CRAY _fcd ftcs1, ftcs2, ftcs3, ftcs4; #endif int incx = 1, incy = 1; double alpha = 1.0, beta = 1.0; DNformat *Bstore; double *Bmat; SCformat *Lstore; NCformat *Ustore; double *Lval, *Uval; int nrow, notran; int fsupc, nsupr, nsupc, luptr, istart, irow; int i, j, k, iptr, jcol, n, ldb, nrhs; double *work, *work_col, *rhs_work, *soln; flops_t solve_ops; extern SuperLUStat_t SuperLUStat; void dprint_soln(); /* Test input parameters ... */ *info = 0; Bstore = B->Store; ldb = Bstore->lda; nrhs = B->ncol; notran = lsame_(trans, "N"); if ( !notran && !lsame_(trans, "T") && !lsame_(trans, "C") ) *info = -1; else if ( L->nrow != L->ncol || L->nrow < 0 || L->Stype != SC || L->Dtype != D_ || L->Mtype != TRLU ) *info = -2; else if ( U->nrow != U->ncol || U->nrow < 0 || U->Stype != NC || U->Dtype != D_ || U->Mtype != TRU ) *info = -3; else if ( ldb < SUPERLU_MAX(0, L->nrow) || B->Stype != DN || B->Dtype != D_ || B->Mtype != GE ) *info = -6; if ( *info ) { i = -(*info); xerbla_("dgstrs", &i); return; } n = L->nrow; work = doubleCalloc(n * nrhs); if ( !work ) ABORT("Malloc fails for local work[]."); soln = doubleMalloc(n); if ( !soln ) ABORT("Malloc fails for local soln[]."); Bmat = Bstore->nzval; Lstore = L->Store; Lval = Lstore->nzval; Ustore = U->Store; Uval = Ustore->nzval; solve_ops = 0; if ( notran ) { /* Permute right hand sides to form Pr*B */ for (i = 0; i < nrhs; i++) { rhs_work = &Bmat[i*ldb]; for (k = 0; k < n; k++) soln[perm_r[k]] = rhs_work[k]; for (k = 0; k < n; k++) rhs_work[k] = soln[k]; } /* Forward solve PLy=Pb. */ for (k = 0; k <= Lstore->nsuper; k++) { fsupc = L_FST_SUPC(k); istart = L_SUB_START(fsupc); nsupr = L_SUB_START(fsupc+1) - istart; nsupc = L_FST_SUPC(k+1) - fsupc; nrow = nsupr - nsupc; solve_ops += nsupc * (nsupc - 1) * nrhs; solve_ops += 2 * nrow * nsupc * nrhs; if ( nsupc == 1 ) { for (j = 0; j < nrhs; j++) { rhs_work = &Bmat[j*ldb]; luptr = L_NZ_START(fsupc); for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); iptr++){ irow = L_SUB(iptr); ++luptr; rhs_work[irow] -= rhs_work[fsupc] * Lval[luptr]; } } } else { luptr = L_NZ_START(fsupc); #ifdef USE_VENDOR_BLAS #ifdef _CRAY ftcs1 = _cptofcd("L", strlen("L")); ftcs2 = _cptofcd("N", strlen("N")); ftcs3 = _cptofcd("U", strlen("U")); STRSM( ftcs1, ftcs1, ftcs2, ftcs3, &nsupc, &nrhs, &alpha, &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); SGEMM( ftcs2, ftcs2, &nrow, &nrhs, &nsupc, &alpha, &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb, &beta, &work[0], &n ); #else dtrsm_("L", "L", "N", "U", &nsupc, &nrhs, &alpha, &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); dgemm_( "N", "N", &nrow, &nrhs, &nsupc, &alpha, &Lval[luptr+nsupc], &nsupr, &Bmat[fsupc], &ldb, &beta, &work[0], &n ); #endif for (j = 0; j < nrhs; j++) { rhs_work = &Bmat[j*ldb]; work_col = &work[j*n]; iptr = istart + nsupc; for (i = 0; i < nrow; i++) { irow = L_SUB(iptr); rhs_work[irow] -= work_col[i]; /* Scatter */ work_col[i] = 0.0; iptr++; } } #else for (j = 0; j < nrhs; j++) { rhs_work = &Bmat[j*ldb]; dlsolve (nsupr, nsupc, &Lval[luptr], &rhs_work[fsupc]); dmatvec (nsupr, nrow, nsupc, &Lval[luptr+nsupc], &rhs_work[fsupc], &work[0] ); iptr = istart + nsupc; for (i = 0; i < nrow; i++) { irow = L_SUB(iptr); rhs_work[irow] -= work[i]; work[i] = 0.0; iptr++; } } #endif } /* else ... */ } /* for L-solve */ #ifdef DEBUG printf("After L-solve: y=\n"); dprint_soln(n, nrhs, Bmat); #endif /* * Back solve Ux=y. */ for (k = Lstore->nsuper; k >= 0; k--) { fsupc = L_FST_SUPC(k); istart = L_SUB_START(fsupc); nsupr = L_SUB_START(fsupc+1) - istart; nsupc = L_FST_SUPC(k+1) - fsupc; luptr = L_NZ_START(fsupc); solve_ops += nsupc * (nsupc + 1) * nrhs; if ( nsupc == 1 ) { rhs_work = &Bmat[0]; for (j = 0; j < nrhs; j++) { rhs_work[fsupc] /= Lval[luptr]; rhs_work += ldb; } } else { #ifdef USE_VENDOR_BLAS #ifdef _CRAY ftcs1 = _cptofcd("L", strlen("L")); ftcs2 = _cptofcd("U", strlen("U")); ftcs3 = _cptofcd("N", strlen("N")); STRSM( ftcs1, ftcs2, ftcs3, ftcs3, &nsupc, &nrhs, &alpha, &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); #else dtrsm_("L", "U", "N", "N", &nsupc, &nrhs, &alpha, &Lval[luptr], &nsupr, &Bmat[fsupc], &ldb); #endif #else for (j = 0; j < nrhs; j++) dusolve ( nsupr, nsupc, &Lval[luptr], &Bmat[fsupc+j*ldb] ); #endif } for (j = 0; j < nrhs; ++j) { rhs_work = &Bmat[j*ldb]; for (jcol = fsupc; jcol < fsupc + nsupc; jcol++) { solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++ ){ irow = U_SUB(i); rhs_work[irow] -= rhs_work[jcol] * Uval[i]; } } } } /* for U-solve */ #ifdef DEBUG printf("After U-solve: x=\n"); dprint_soln(n, nrhs, Bmat); #endif /* Compute the final solution X := Pc*X. */ for (i = 0; i < nrhs; i++) { rhs_work = &Bmat[i*ldb]; for (k = 0; k < n; k++) soln[k] = rhs_work[perm_c[k]]; for (k = 0; k < n; k++) rhs_work[k] = soln[k]; } SuperLUStat.ops[SOLVE] = solve_ops; } else { /* Solve A'*X=B */ /* Permute right hand sides to form Pc'*B. */ for (i = 0; i < nrhs; i++) { rhs_work = &Bmat[i*ldb]; for (k = 0; k < n; k++) soln[perm_c[k]] = rhs_work[k]; for (k = 0; k < n; k++) rhs_work[k] = soln[k]; } SuperLUStat.ops[SOLVE] = 0; for (k = 0; k < nrhs; ++k) { /* Multiply by inv(U'). */ sp_dtrsv("U", "T", "N", L, U, &Bmat[k*ldb], info); /* Multiply by inv(L'). */ sp_dtrsv("L", "T", "U", L, U, &Bmat[k*ldb], info); } /* Compute the final solution X := Pr'*X (=inv(Pr)*X) */ for (i = 0; i < nrhs; i++) { rhs_work = &Bmat[i*ldb]; for (k = 0; k < n; k++) soln[k] = rhs_work[perm_r[k]]; for (k = 0; k < n; k++) rhs_work[k] = soln[k]; } } SUPERLU_FREE(work); SUPERLU_FREE(soln); } /* * Diagnostic print of the solution vector */ void dprint_soln(int n, int nrhs, double *soln) { int i; for (i = 0; i < n; i++) printf("\t%d: %.4f\n", i, soln[i]); } pysparse-1.1.1/superlu/dlacon.c0000644010116400000240000001254111402270226015456 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include #include "Cnames.h" int dlacon_(int *n, double *v, double *x, int *isgn, double *est, int *kase) { /* Purpose ======= DLACON estimates the 1-norm of a square matrix A. Reverse communication is used for evaluating matrix-vector products. Arguments ========= N (input) INT The order of the matrix. N >= 1. V (workspace) DOUBLE PRECISION array, dimension (N) On the final return, V = A*W, where EST = norm(V)/norm(W) (W is not returned). X (input/output) DOUBLE PRECISION array, dimension (N) On an intermediate return, X should be overwritten by A * X, if KASE=1, A' * X, if KASE=2, and DLACON must be re-called with all the other parameters unchanged. ISGN (workspace) INT array, dimension (N) EST (output) DOUBLE PRECISION An estimate (a lower bound) for norm(A). KASE (input/output) INT On the initial call to DLACON, KASE should be 0. On an intermediate return, KASE will be 1 or 2, indicating whether X should be overwritten by A * X or A' * X. On the final return from DLACON, KASE will again be 0. Further Details ======= ======= Contributed by Nick Higham, University of Manchester. Originally named CONEST, dated March 16, 1988. Reference: N.J. Higham, "FORTRAN codes for estimating the one-norm of a real or complex matrix, with applications to condition estimation", ACM Trans. Math. Soft., vol. 14, no. 4, pp. 381-396, December 1988. ===================================================================== */ /* Table of constant values */ int c__1 = 1; double zero = 0.0; double one = 1.0; /* Local variables */ static int iter; static int jump, jlast; static double altsgn, estold; static int i, j; double temp; #ifdef _CRAY extern int ISAMAX(int *, double *, int *); extern double SASUM(int *, double *, int *); extern int SCOPY(int *, double *, int *, double *, int *); #else extern int idamax_(int *, double *, int *); extern double dasum_(int *, double *, int *); extern int dcopy_(int *, double *, int *, double *, int *); #endif #define d_sign(a, b) (b >= 0 ? fabs(a) : -fabs(a)) /* Copy sign */ #define i_dnnt(a) \ ( a>=0 ? floor(a+.5) : -floor(.5-a) ) /* Round to nearest integer */ if ( *kase == 0 ) { for (i = 0; i < *n; ++i) { x[i] = 1. / (double) (*n); } *kase = 1; jump = 1; return 0; } switch (jump) { case 1: goto L20; case 2: goto L40; case 3: goto L70; case 4: goto L110; case 5: goto L140; } /* ................ ENTRY (JUMP = 1) FIRST ITERATION. X HAS BEEN OVERWRITTEN BY A*X. */ L20: if (*n == 1) { v[0] = x[0]; *est = fabs(v[0]); /* ... QUIT */ goto L150; } #ifdef _CRAY *est = SASUM(n, x, &c__1); #else *est = dasum_(n, x, &c__1); #endif for (i = 0; i < *n; ++i) { x[i] = d_sign(one, x[i]); isgn[i] = i_dnnt(x[i]); } *kase = 2; jump = 2; return 0; /* ................ ENTRY (JUMP = 2) FIRST ITERATION. X HAS BEEN OVERWRITTEN BY TRANSPOSE(A)*X. */ L40: #ifdef _CRAY j = ISAMAX(n, &x[0], &c__1); #else j = idamax_(n, &x[0], &c__1); #endif --j; iter = 2; /* MAIN LOOP - ITERATIONS 2,3,...,ITMAX. */ L50: for (i = 0; i < *n; ++i) x[i] = zero; x[j] = one; *kase = 1; jump = 3; return 0; /* ................ ENTRY (JUMP = 3) X HAS BEEN OVERWRITTEN BY A*X. */ L70: #ifdef _CRAY SCOPY(n, x, &c__1, v, &c__1); #else dcopy_(n, x, &c__1, v, &c__1); #endif estold = *est; #ifdef _CRAY *est = SASUM(n, v, &c__1); #else *est = dasum_(n, v, &c__1); #endif for (i = 0; i < *n; ++i) if (i_dnnt(d_sign(one, x[i])) != isgn[i]) goto L90; /* REPEATED SIGN VECTOR DETECTED, HENCE ALGORITHM HAS CONVERGED. */ goto L120; L90: /* TEST FOR CYCLING. */ if (*est <= estold) goto L120; for (i = 0; i < *n; ++i) { x[i] = d_sign(one, x[i]); isgn[i] = i_dnnt(x[i]); } *kase = 2; jump = 4; return 0; /* ................ ENTRY (JUMP = 4) X HAS BEEN OVERWRITTEN BY TRANDPOSE(A)*X. */ L110: jlast = j; #ifdef _CRAY j = ISAMAX(n, &x[0], &c__1); #else j = idamax_(n, &x[0], &c__1); #endif --j; if (x[jlast] != fabs(x[j]) && iter < 5) { ++iter; goto L50; } /* ITERATION COMPLETE. FINAL STAGE. */ L120: altsgn = 1.; for (i = 1; i <= *n; ++i) { x[i-1] = altsgn * ((double)(i - 1) / (double)(*n - 1) + 1.); altsgn = -altsgn; } *kase = 1; jump = 5; return 0; /* ................ ENTRY (JUMP = 5) X HAS BEEN OVERWRITTEN BY A*X. */ L140: #ifdef _CRAY temp = SASUM(n, x, &c__1) / (double)(*n * 3) * 2.; #else temp = dasum_(n, x, &c__1) / (double)(*n * 3) * 2.; #endif if (temp > *est) { #ifdef _CRAY SCOPY(n, &x[0], &c__1, &v[0], &c__1); #else dcopy_(n, &x[0], &c__1, &v[0], &c__1); #endif *est = temp; } L150: *kase = 0; return 0; } /* dlacon_ */ pysparse-1.1.1/superlu/dlamch.c0000644010116400000240000005717411402270224015457 0ustar wd15dialout#include #define TRUE_ (1) #define FALSE_ (0) #define abs(x) ((x) >= 0 ? (x) : -(x)) #define min(a,b) ((a) <= (b) ? (a) : (b)) #define max(a,b) ((a) >= (b) ? (a) : (b)) double dlamch_(char *cmach) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 Purpose ======= DLAMCH determines double precision machine parameters. Arguments ========= CMACH (input) CHARACTER*1 Specifies the value to be returned by DLAMCH: = 'E' or 'e', DLAMCH := eps = 'S' or 's , DLAMCH := sfmin = 'B' or 'b', DLAMCH := base = 'P' or 'p', DLAMCH := eps*base = 'N' or 'n', DLAMCH := t = 'R' or 'r', DLAMCH := rnd = 'M' or 'm', DLAMCH := emin = 'U' or 'u', DLAMCH := rmin = 'L' or 'l', DLAMCH := emax = 'O' or 'o', DLAMCH := rmax where eps = relative machine precision sfmin = safe minimum, such that 1/sfmin does not overflow base = base of the machine prec = eps*base t = number of (base) digits in the mantissa rnd = 1.0 when rounding occurs in addition, 0.0 otherwise emin = minimum exponent before (gradual) underflow rmin = underflow threshold - base**(emin-1) emax = largest exponent before overflow rmax = overflow threshold - (base**emax)*(1-eps) ===================================================================== */ static int first = TRUE_; /* System generated locals */ int i__1; double ret_val; /* Builtin functions */ double pow_di(double *, int *); /* Local variables */ static double base; static int beta; static double emin, prec, emax; static int imin, imax; static int lrnd; static double rmin, rmax, t, rmach; /* extern int lsame_(char *, char *);*/ static double small, sfmin; extern /* Subroutine */ int dlamc2_(int *, int *, int *, double *, int *, double *, int *, double *); static int it; static double rnd, eps; if (first) { first = FALSE_; dlamc2_(&beta, &it, &lrnd, &eps, &imin, &rmin, &imax, &rmax); base = (double) beta; t = (double) it; if (lrnd) { rnd = 1.; i__1 = 1 - it; eps = pow_di(&base, &i__1) / 2; } else { rnd = 0.; i__1 = 1 - it; eps = pow_di(&base, &i__1); } prec = eps * base; emin = (double) imin; emax = (double) imax; sfmin = rmin; small = 1. / rmax; if (small >= sfmin) { /* Use SMALL plus a bit, to avoid the possibility of rounding causing overflow when computing 1/sfmin. */ sfmin = small * (eps + 1.); } } if (lsame_(cmach, "E")) { rmach = eps; } else if (lsame_(cmach, "S")) { rmach = sfmin; } else if (lsame_(cmach, "B")) { rmach = base; } else if (lsame_(cmach, "P")) { rmach = prec; } else if (lsame_(cmach, "N")) { rmach = t; } else if (lsame_(cmach, "R")) { rmach = rnd; } else if (lsame_(cmach, "M")) { rmach = emin; } else if (lsame_(cmach, "U")) { rmach = rmin; } else if (lsame_(cmach, "L")) { rmach = emax; } else if (lsame_(cmach, "O")) { rmach = rmax; } ret_val = rmach; return ret_val; /* End of DLAMCH */ } /* dlamch_ */ /* Subroutine */ int dlamc1_(int *beta, int *t, int *rnd, int *ieee1) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 Purpose ======= DLAMC1 determines the machine parameters given by BETA, T, RND, and IEEE1. Arguments ========= BETA (output) INT The base of the machine. T (output) INT The number of ( BETA ) digits in the mantissa. RND (output) INT Specifies whether proper rounding ( RND = .TRUE. ) or chopping ( RND = .FALSE. ) occurs in addition. This may not be a reliable guide to the way in which the machine performs its arithmetic. IEEE1 (output) INT Specifies whether rounding appears to be done in the IEEE 'round to nearest' style. Further Details =============== The routine is based on the routine ENVRON by Malcolm and incorporates suggestions by Gentleman and Marovich. See Malcolm M. A. (1972) Algorithms to reveal properties of floating-point arithmetic. Comms. of the ACM, 15, 949-951. Gentleman W. M. and Marovich S. B. (1974) More on algorithms that reveal properties of floating point arithmetic units. Comms. of the ACM, 17, 276-277. ===================================================================== */ /* Initialized data */ static int first = TRUE_; /* System generated locals */ double d__1, d__2; /* Local variables */ static int lrnd; static double a, b, c, f; static int lbeta; static double savec; extern double dlamc3_(double *, double *); static int lieee1; static double t1, t2; static int lt; static double one, qtr; if (first) { first = FALSE_; one = 1.; /* LBETA, LIEEE1, LT and LRND are the local values of BE TA, IEEE1, T and RND. Throughout this routine we use the function DLAMC3 to ens ure that relevant values are stored and not held in registers, or are not affected by optimizers. Compute a = 2.0**m with the smallest positive integer m s uch that fl( a + 1.0 ) = a. */ a = 1.; c = 1.; /* + WHILE( C.EQ.ONE )LOOP */ L10: if (c == one) { a *= 2; c = dlamc3_(&a, &one); d__1 = -a; c = dlamc3_(&c, &d__1); goto L10; } /* + END WHILE Now compute b = 2.0**m with the smallest positive integer m such that fl( a + b ) .gt. a. */ b = 1.; c = dlamc3_(&a, &b); /* + WHILE( C.EQ.A )LOOP */ L20: if (c == a) { b *= 2; c = dlamc3_(&a, &b); goto L20; } /* + END WHILE Now compute the base. a and c are neighbouring floating po int numbers in the interval ( beta**t, beta**( t + 1 ) ) and so their difference is beta. Adding 0.25 to c is to ensure that it is truncated to beta and not ( beta - 1 ). */ qtr = one / 4; savec = c; d__1 = -a; c = dlamc3_(&c, &d__1); lbeta = (int) (c + qtr); /* Now determine whether rounding or chopping occurs, by addin g a bit less than beta/2 and a bit more than beta/2 to a. */ b = (double) lbeta; d__1 = b / 2; d__2 = -b / 100; f = dlamc3_(&d__1, &d__2); c = dlamc3_(&f, &a); if (c == a) { lrnd = TRUE_; } else { lrnd = FALSE_; } d__1 = b / 2; d__2 = b / 100; f = dlamc3_(&d__1, &d__2); c = dlamc3_(&f, &a); if (lrnd && c == a) { lrnd = FALSE_; } /* Try and decide whether rounding is done in the IEEE 'round to nearest' style. B/2 is half a unit in the last place of the two numbers A and SAVEC. Furthermore, A is even, i.e. has last bit zero, and SAVEC is odd. Thus adding B/2 to A should not cha nge A, but adding B/2 to SAVEC should change SAVEC. */ d__1 = b / 2; t1 = dlamc3_(&d__1, &a); d__1 = b / 2; t2 = dlamc3_(&d__1, &savec); lieee1 = t1 == a && t2 > savec && lrnd; /* Now find the mantissa, t. It should be the integer part of log to the base beta of a, however it is safer to determine t by powering. So we find t as the smallest positive integer for which fl( beta**t + 1.0 ) = 1.0. */ lt = 0; a = 1.; c = 1.; /* + WHILE( C.EQ.ONE )LOOP */ L30: if (c == one) { ++lt; a *= lbeta; c = dlamc3_(&a, &one); d__1 = -a; c = dlamc3_(&c, &d__1); goto L30; } /* + END WHILE */ } *beta = lbeta; *t = lt; *rnd = lrnd; *ieee1 = lieee1; return 0; /* End of DLAMC1 */ } /* dlamc1_ */ /* Subroutine */ int dlamc2_(int *beta, int *t, int *rnd, double *eps, int *emin, double *rmin, int *emax, double *rmax) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 Purpose ======= DLAMC2 determines the machine parameters specified in its argument list. Arguments ========= BETA (output) INT The base of the machine. T (output) INT The number of ( BETA ) digits in the mantissa. RND (output) INT Specifies whether proper rounding ( RND = .TRUE. ) or chopping ( RND = .FALSE. ) occurs in addition. This may not be a reliable guide to the way in which the machine performs its arithmetic. EPS (output) DOUBLE PRECISION The smallest positive number such that fl( 1.0 - EPS ) .LT. 1.0, where fl denotes the computed value. EMIN (output) INT The minimum exponent before (gradual) underflow occurs. RMIN (output) DOUBLE PRECISION The smallest normalized number for the machine, given by BASE**( EMIN - 1 ), where BASE is the floating point value of BETA. EMAX (output) INT The maximum exponent before overflow occurs. RMAX (output) DOUBLE PRECISION The largest positive number for the machine, given by BASE**EMAX * ( 1 - EPS ), where BASE is the floating point value of BETA. Further Details =============== The computation of EPS is based on a routine PARANOIA by W. Kahan of the University of California at Berkeley. ===================================================================== */ /* Table of constant values */ static int c__1 = 1; /* Initialized data */ static int first = TRUE_; static int iwarn = FALSE_; /* System generated locals */ int i__1; double d__1, d__2, d__3, d__4, d__5; /* Builtin functions */ double pow_di(double *, int *); /* Local variables */ static int ieee; static double half; static int lrnd; static double leps, zero, a, b, c; static int i, lbeta; static double rbase; static int lemin, lemax, gnmin; static double small; static int gpmin; static double third, lrmin, lrmax, sixth; extern /* Subroutine */ int dlamc1_(int *, int *, int *, int *); extern double dlamc3_(double *, double *); static int lieee1; extern /* Subroutine */ int dlamc4_(int *, double *, int *), dlamc5_(int *, int *, int *, int *, int *, double *); static int lt, ngnmin, ngpmin; static double one, two; if (first) { first = FALSE_; zero = 0.; one = 1.; two = 2.; /* LBETA, LT, LRND, LEPS, LEMIN and LRMIN are the local values of BETA, T, RND, EPS, EMIN and RMIN. Throughout this routine we use the function DLAMC3 to ens ure that relevant values are stored and not held in registers, or are not affected by optimizers. DLAMC1 returns the parameters LBETA, LT, LRND and LIEEE1. */ dlamc1_(&lbeta, <, &lrnd, &lieee1); /* Start to find EPS. */ b = (double) lbeta; i__1 = -lt; a = pow_di(&b, &i__1); leps = a; /* Try some tricks to see whether or not this is the correct E PS. */ b = two / 3; half = one / 2; d__1 = -half; sixth = dlamc3_(&b, &d__1); third = dlamc3_(&sixth, &sixth); d__1 = -half; b = dlamc3_(&third, &d__1); b = dlamc3_(&b, &sixth); b = abs(b); if (b < leps) { b = leps; } leps = 1.; /* + WHILE( ( LEPS.GT.B ).AND.( B.GT.ZERO ) )LOOP */ L10: if (leps > b && b > zero) { leps = b; d__1 = half * leps; /* Computing 5th power */ d__3 = two, d__4 = d__3, d__3 *= d__3; /* Computing 2nd power */ d__5 = leps; d__2 = d__4 * (d__3 * d__3) * (d__5 * d__5); c = dlamc3_(&d__1, &d__2); d__1 = -c; c = dlamc3_(&half, &d__1); b = dlamc3_(&half, &c); d__1 = -b; c = dlamc3_(&half, &d__1); b = dlamc3_(&half, &c); goto L10; } /* + END WHILE */ if (a < leps) { leps = a; } /* Computation of EPS complete. Now find EMIN. Let A = + or - 1, and + or - (1 + BASE**(-3 )). Keep dividing A by BETA until (gradual) underflow occurs. T his is detected when we cannot recover the previous A. */ rbase = one / lbeta; small = one; for (i = 1; i <= 3; ++i) { d__1 = small * rbase; small = dlamc3_(&d__1, &zero); /* L20: */ } a = dlamc3_(&one, &small); dlamc4_(&ngpmin, &one, &lbeta); d__1 = -one; dlamc4_(&ngnmin, &d__1, &lbeta); dlamc4_(&gpmin, &a, &lbeta); d__1 = -a; dlamc4_(&gnmin, &d__1, &lbeta); ieee = FALSE_; if (ngpmin == ngnmin && gpmin == gnmin) { if (ngpmin == gpmin) { lemin = ngpmin; /* ( Non twos-complement machines, no gradual under flow; e.g., VAX ) */ } else if (gpmin - ngpmin == 3) { lemin = ngpmin - 1 + lt; ieee = TRUE_; /* ( Non twos-complement machines, with gradual und erflow; e.g., IEEE standard followers ) */ } else { lemin = min(ngpmin,gpmin); /* ( A guess; no known machine ) */ iwarn = TRUE_; } } else if (ngpmin == gpmin && ngnmin == gnmin) { if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1) { lemin = max(ngpmin,ngnmin); /* ( Twos-complement machines, no gradual underflow ; e.g., CYBER 205 ) */ } else { lemin = min(ngpmin,ngnmin); /* ( A guess; no known machine ) */ iwarn = TRUE_; } } else if ((i__1 = ngpmin - ngnmin, abs(i__1)) == 1 && gpmin == gnmin) { if (gpmin - min(ngpmin,ngnmin) == 3) { lemin = max(ngpmin,ngnmin) - 1 + lt; /* ( Twos-complement machines with gradual underflo w; no known machine ) */ } else { lemin = min(ngpmin,ngnmin); /* ( A guess; no known machine ) */ iwarn = TRUE_; } } else { /* Computing MIN */ i__1 = min(ngpmin,ngnmin), i__1 = min(i__1,gpmin); lemin = min(i__1,gnmin); /* ( A guess; no known machine ) */ iwarn = TRUE_; } /* ** Comment out this if block if EMIN is ok */ if (iwarn) { first = TRUE_; printf("\n\n WARNING. The value EMIN may be incorrect:- "); printf("EMIN = %8i\n",lemin); printf("If, after inspection, the value EMIN looks acceptable"); printf("please comment out \n the IF block as marked within the"); printf("code of routine DLAMC2, \n otherwise supply EMIN"); printf("explicitly.\n"); } /* ** Assume IEEE arithmetic if we found denormalised numbers abo ve, or if arithmetic seems to round in the IEEE style, determi ned in routine DLAMC1. A true IEEE machine should have both thi ngs true; however, faulty machines may have one or the other. */ ieee = ieee || lieee1; /* Compute RMIN by successive division by BETA. We could comp ute RMIN as BASE**( EMIN - 1 ), but some machines underflow dur ing this computation. */ lrmin = 1.; i__1 = 1 - lemin; for (i = 1; i <= 1-lemin; ++i) { d__1 = lrmin * rbase; lrmin = dlamc3_(&d__1, &zero); /* L30: */ } /* Finally, call DLAMC5 to compute EMAX and RMAX. */ dlamc5_(&lbeta, <, &lemin, &ieee, &lemax, &lrmax); } *beta = lbeta; *t = lt; *rnd = lrnd; *eps = leps; *emin = lemin; *rmin = lrmin; *emax = lemax; *rmax = lrmax; return 0; /* End of DLAMC2 */ } /* dlamc2_ */ double dlamc3_(double *a, double *b) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 Purpose ======= DLAMC3 is intended to force A and B to be stored prior to doing the addition of A and B , for use in situations where optimizers might hold one of these in a register. Arguments ========= A, B (input) DOUBLE PRECISION The values A and B. ===================================================================== */ /* >>Start of File<< System generated locals */ double ret_val; ret_val = *a + *b; return ret_val; /* End of DLAMC3 */ } /* dlamc3_ */ /* Subroutine */ int dlamc4_(int *emin, double *start, int *base) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 Purpose ======= DLAMC4 is a service routine for DLAMC2. Arguments ========= EMIN (output) EMIN The minimum exponent before (gradual) underflow, computed by setting A = START and dividing by BASE until the previous A can not be recovered. START (input) DOUBLE PRECISION The starting point for determining EMIN. BASE (input) INT The base of the machine. ===================================================================== */ /* System generated locals */ int i__1; double d__1; /* Local variables */ static double zero, a; static int i; static double rbase, b1, b2, c1, c2, d1, d2; extern double dlamc3_(double *, double *); static double one; a = *start; one = 1.; rbase = one / *base; zero = 0.; *emin = 1; d__1 = a * rbase; b1 = dlamc3_(&d__1, &zero); c1 = a; c2 = a; d1 = a; d2 = a; /* + WHILE( ( C1.EQ.A ).AND.( C2.EQ.A ).AND. $ ( D1.EQ.A ).AND.( D2.EQ.A ) )LOOP */ L10: if (c1 == a && c2 == a && d1 == a && d2 == a) { --(*emin); a = b1; d__1 = a / *base; b1 = dlamc3_(&d__1, &zero); d__1 = b1 * *base; c1 = dlamc3_(&d__1, &zero); d1 = zero; i__1 = *base; for (i = 1; i <= *base; ++i) { d1 += b1; /* L20: */ } d__1 = a * rbase; b2 = dlamc3_(&d__1, &zero); d__1 = b2 / rbase; c2 = dlamc3_(&d__1, &zero); d2 = zero; i__1 = *base; for (i = 1; i <= *base; ++i) { d2 += b2; /* L30: */ } goto L10; } /* + END WHILE */ return 0; /* End of DLAMC4 */ } /* dlamc4_ */ /* Subroutine */ int dlamc5_(int *beta, int *p, int *emin, int *ieee, int *emax, double *rmax) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 Purpose ======= DLAMC5 attempts to compute RMAX, the largest machine floating-point number, without overflow. It assumes that EMAX + abs(EMIN) sum approximately to a power of 2. It will fail on machines where this assumption does not hold, for example, the Cyber 205 (EMIN = -28625, EMAX = 28718). It will also fail if the value supplied for EMIN is too large (i.e. too close to zero), probably with overflow. Arguments ========= BETA (input) INT The base of floating-point arithmetic. P (input) INT The number of base BETA digits in the mantissa of a floating-point value. EMIN (input) INT The minimum exponent before (gradual) underflow. IEEE (input) INT A int flag specifying whether or not the arithmetic system is thought to comply with the IEEE standard. EMAX (output) INT The largest exponent before overflow RMAX (output) DOUBLE PRECISION The largest machine floating-point number. ===================================================================== First compute LEXP and UEXP, two powers of 2 that bound abs(EMIN). We then assume that EMAX + abs(EMIN) will sum approximately to the bound that is closest to abs(EMIN). (EMAX is the exponent of the required number RMAX). */ /* Table of constant values */ static double c_b5 = 0.; /* System generated locals */ int i__1; double d__1; /* Local variables */ static int lexp; static double oldy; static int uexp, i; static double y, z; static int nbits; extern double dlamc3_(double *, double *); static double recbas; static int exbits, expsum, try__; lexp = 1; exbits = 1; L10: try__ = lexp << 1; if (try__ <= -(*emin)) { lexp = try__; ++exbits; goto L10; } if (lexp == -(*emin)) { uexp = lexp; } else { uexp = try__; ++exbits; } /* Now -LEXP is less than or equal to EMIN, and -UEXP is greater than or equal to EMIN. EXBITS is the number of bits needed to store the exponent. */ if (uexp + *emin > -lexp - *emin) { expsum = lexp << 1; } else { expsum = uexp << 1; } /* EXPSUM is the exponent range, approximately equal to EMAX - EMIN + 1 . */ *emax = expsum + *emin - 1; nbits = exbits + 1 + *p; /* NBITS is the total number of bits needed to store a floating-point number. */ if (nbits % 2 == 1 && *beta == 2) { /* Either there are an odd number of bits used to store a floating-point number, which is unlikely, or some bits are not used in the representation of numbers, which is possible , (e.g. Cray machines) or the mantissa has an implicit bit, (e.g. IEEE machines, Dec Vax machines), which is perhaps the most likely. We have to assume the last alternative. If this is true, then we need to reduce EMAX by one because there must be some way of representing zero in an implicit-b it system. On machines like Cray, we are reducing EMAX by one unnecessarily. */ --(*emax); } if (*ieee) { /* Assume we are on an IEEE machine which reserves one exponent for infinity and NaN. */ --(*emax); } /* Now create RMAX, the largest machine number, which should be equal to (1.0 - BETA**(-P)) * BETA**EMAX . First compute 1.0 - BETA**(-P), being careful that the result is less than 1.0 . */ recbas = 1. / *beta; z = *beta - 1.; y = 0.; i__1 = *p; for (i = 1; i <= *p; ++i) { z *= recbas; if (y < 1.) { oldy = y; } y = dlamc3_(&y, &z); /* L20: */ } if (y >= 1.) { y = oldy; } /* Now multiply by BETA**EMAX to get RMAX. */ i__1 = *emax; for (i = 1; i <= *emax; ++i) { d__1 = y * *beta; y = dlamc3_(&d__1, &c_b5); /* L30: */ } *rmax = y; return 0; /* End of DLAMC5 */ } /* dlamc5_ */ double pow_di(double *ap, int *bp) { double pow, x; int n; pow = 1; x = *ap; n = *bp; if(n != 0){ if(n < 0) { n = -n; x = 1/x; } for( ; ; ) { if(n & 01) pow *= x; if(n >>= 1) x *= x; else break; } } return(pow); } pysparse-1.1.1/superlu/dlangs.c0000644010116400000240000000566611402270214015475 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * File name: dlangs.c * History: Modified from lapack routine DLANGE */ #include #include "dsp_defs.h" #include "util.h" double dlangs(char *norm, SuperMatrix *A) { /* Purpose ======= DLANGS returns the value of the one norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a real matrix A. Description =========== DLANGE returns the value DLANGE = ( max(abs(A(i,j))), NORM = 'M' or 'm' ( ( norm1(A), NORM = '1', 'O' or 'o' ( ( normI(A), NORM = 'I' or 'i' ( ( normF(A), NORM = 'F', 'f', 'E' or 'e' where norm1 denotes the one norm of a matrix (maximum column sum), normI denotes the infinity norm of a matrix (maximum row sum) and normF denotes the Frobenius norm of a matrix (square root of sum of squares). Note that max(abs(A(i,j))) is not a matrix norm. Arguments ========= NORM (input) CHARACTER*1 Specifies the value to be returned in DLANGE as described above. A (input) SuperMatrix* The M by N sparse matrix A. ===================================================================== */ /* Local variables */ NCformat *Astore; double *Aval; int i, j, irow; double value, sum; double *rwork; Astore = A->Store; Aval = Astore->nzval; if ( SUPERLU_MIN(A->nrow, A->ncol) == 0) { value = 0.; } else if (lsame_(norm, "M")) { /* Find max(abs(A(i,j))). */ value = 0.; for (j = 0; j < A->ncol; ++j) for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; i++) value = SUPERLU_MAX( value, fabs( Aval[i]) ); } else if (lsame_(norm, "O") || *(unsigned char *)norm == '1') { /* Find norm1(A). */ value = 0.; for (j = 0; j < A->ncol; ++j) { sum = 0.; for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; i++) sum += fabs(Aval[i]); value = SUPERLU_MAX(value,sum); } } else if (lsame_(norm, "I")) { /* Find normI(A). */ if ( !(rwork = (double *) SUPERLU_MALLOC(A->nrow * sizeof(double))) ) ABORT("SUPERLU_MALLOC fails for rwork."); for (i = 0; i < A->nrow; ++i) rwork[i] = 0.; for (j = 0; j < A->ncol; ++j) for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; i++) { irow = Astore->rowind[i]; rwork[irow] += fabs(Aval[i]); } value = 0.; for (i = 0; i < A->nrow; ++i) value = SUPERLU_MAX(value, rwork[i]); SUPERLU_FREE (rwork); } else if (lsame_(norm, "F") || lsame_(norm, "E")) { /* Find normF(A). */ ABORT("Not implemented."); } else ABORT("Illegal norm specified."); return (value); } /* dlangs */ pysparse-1.1.1/superlu/dlaqgs.c0000644010116400000240000000741611402270243015475 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * File name: dlaqgs.c * History: Modified from LAPACK routine DLAQGE */ #include #include "dsp_defs.h" #include "util.h" void dlaqgs(SuperMatrix *A, double *r, double *c, double rowcnd, double colcnd, double amax, char *equed) { /* Purpose ======= DLAQGS equilibrates a general sparse M by N matrix A using the row and scaling factors in the vectors R and C. See supermatrix.h for the definition of 'SuperMatrix' structure. Arguments ========= A (input/output) SuperMatrix* On exit, the equilibrated matrix. See EQUED for the form of the equilibrated matrix. The type of A can be: Stype = NC; Dtype = D_; Mtype = GE. R (input) double*, dimension (A->nrow) The row scale factors for A. C (input) double*, dimension (A->ncol) The column scale factors for A. ROWCND (input) double Ratio of the smallest R(i) to the largest R(i). COLCND (input) double Ratio of the smallest C(i) to the largest C(i). AMAX (input) double Absolute value of largest matrix entry. EQUED (output) char* Specifies the form of equilibration that was done. = 'N': No equilibration = 'R': Row equilibration, i.e., A has been premultiplied by diag(R). = 'C': Column equilibration, i.e., A has been postmultiplied by diag(C). = 'B': Both row and column equilibration, i.e., A has been replaced by diag(R) * A * diag(C). Internal Parameters =================== THRESH is a threshold value used to decide if row or column scaling should be done based on the ratio of the row or column scaling factors. If ROWCND < THRESH, row scaling is done, and if COLCND < THRESH, column scaling is done. LARGE and SMALL are threshold values used to decide if row scaling should be done based on the absolute size of the largest matrix element. If AMAX > LARGE or AMAX < SMALL, row scaling is done. ===================================================================== */ #define THRESH (0.1) /* Local variables */ NCformat *Astore; double *Aval; int i, j, irow; double large, small, cj; extern double dlamch_(char *); /* Quick return if possible */ if (A->nrow <= 0 || A->ncol <= 0) { *(unsigned char *)equed = 'N'; return; } Astore = A->Store; Aval = Astore->nzval; /* Initialize LARGE and SMALL. */ small = dlamch_("Safe minimum") / dlamch_("Precision"); large = 1. / small; if (rowcnd >= THRESH && amax >= small && amax <= large) { if (colcnd >= THRESH) *(unsigned char *)equed = 'N'; else { /* Column scaling */ for (j = 0; j < A->ncol; ++j) { cj = c[j]; for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { Aval[i] *= cj; } } *(unsigned char *)equed = 'C'; } } else if (colcnd >= THRESH) { /* Row scaling, no column scaling */ for (j = 0; j < A->ncol; ++j) for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { irow = Astore->rowind[i]; Aval[i] *= r[irow]; } *(unsigned char *)equed = 'R'; } else { /* Row and column scaling */ for (j = 0; j < A->ncol; ++j) { cj = c[j]; for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { irow = Astore->rowind[i]; Aval[i] *= cj * r[irow]; } } *(unsigned char *)equed = 'B'; } return; } /* dlaqgs */ pysparse-1.1.1/superlu/dmemory.c0000644010116400000240000004371311402270202015671 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include "dsp_defs.h" #include "util.h" /* Constants */ #define NO_MEMTYPE 4 /* 0: lusup; 1: ucol; 2: lsub; 3: usub */ #define GluIntArray(n) (5 * (n) + 5) /* Internal prototypes */ void *dexpand (int *, MemType,int, int, GlobalLU_t *); int dLUWorkInit (int, int, int, int **, double **, LU_space_t); void copy_mem_double (int, void *, void *); void dStackCompress (GlobalLU_t *); void dSetupSpace (void *, int, LU_space_t *); void *duser_malloc (int, int); void duser_free (int, int); /* External prototypes (in memory.c - prec-indep) */ extern void copy_mem_int (int, void *, void *); extern void user_bcopy (char *, char *, int); /* Headers for 4 types of dynamatically managed memory */ typedef struct e_node { int size; /* length of the memory that has been used */ void *mem; /* pointer to the new malloc'd store */ } ExpHeader; typedef struct { int size; int used; int top1; /* grow upward, relative to &array[0] */ int top2; /* grow downward */ void *array; } LU_stack_t; /* Variables local to this file */ static ExpHeader *expanders = 0; /* Array of pointers to 4 types of memory */ static LU_stack_t stack; static int no_expand; /* Macros to manipulate stack */ #define StackFull(x) ( x + stack.used >= stack.size ) #define NotDoubleAlign(addr) ( (long int)addr & 7 ) #define DoubleAlign(addr) ( ((long int)addr + 7) & ~7L ) #define TempSpace(m, w) ( (2*w + 4 + NO_MARKER) * m * sizeof(int) + \ (w + 1) * m * sizeof(double) ) #define Reduce(alpha) ((alpha + 1) / 2) /* i.e. (alpha-1)/2 + 1 */ /* * Setup the memory model to be used for factorization. * lwork = 0: use system malloc; * lwork > 0: use user-supplied work[] space. */ void dSetupSpace(void *work, int lwork, LU_space_t *MemModel) { if ( lwork == 0 ) { *MemModel = SYSTEM; /* malloc/free */ } else if ( lwork > 0 ) { *MemModel = USER; /* user provided space */ stack.used = 0; stack.top1 = 0; stack.top2 = (lwork/4)*4; /* must be word addressable */ stack.size = stack.top2; stack.array = (void *) work; } } void *duser_malloc(int bytes, int which_end) { void *buf; if ( StackFull(bytes) ) return (NULL); if ( which_end == HEAD ) { buf = (char*) stack.array + stack.top1; stack.top1 += bytes; } else { stack.top2 -= bytes; buf = (char*) stack.array + stack.top2; } stack.used += bytes; return buf; } void duser_free(int bytes, int which_end) { if ( which_end == HEAD ) { stack.top1 -= bytes; } else { stack.top2 += bytes; } stack.used -= bytes; } /* * mem_usage consists of the following fields: * - for_lu (float) * The amount of space used in bytes for the L\U data structures. * - total_needed (float) * The amount of space needed in bytes to perform factorization. * - expansions (int) * Number of memory expansions during the LU factorization. */ int dQuerySpace(SuperMatrix *L, SuperMatrix *U, int panel_size, mem_usage_t *mem_usage) { SCformat *Lstore; NCformat *Ustore; register int n, iword, dword; Lstore = L->Store; Ustore = U->Store; n = L->ncol; iword = sizeof(int); dword = sizeof(double); /* For LU factors */ mem_usage->for_lu = (float)( (4*n + 3) * iword + Lstore->nzval_colptr[n] * dword + Lstore->rowind_colptr[n] * iword ); mem_usage->for_lu += (float)( (n + 1) * iword + Ustore->colptr[n] * (dword + iword) ); /* Working storage to support factorization */ mem_usage->total_needed = mem_usage->for_lu + (float)( (2 * panel_size + 4 + NO_MARKER) * n * iword + (panel_size + 1) * n * dword ); mem_usage->expansions = --no_expand; return 0; } /* dQuerySpace */ /* * Allocate storage for the data structures common to all factor routines. * For those unpredictable size, make a guess as FILL * nnz(A). * Return value: * If lwork = -1, return the estimated amount of space required, plus n; * otherwise, return the amount of space actually allocated when * memory allocation failure occurred. */ int dLUMemInit(char *refact, void *work, int lwork, int m, int n, int annz, int panel_size, SuperMatrix *L, SuperMatrix *U, GlobalLU_t *Glu, int **iwork, double **dwork) { int info, iword, dword; SCformat *Lstore; NCformat *Ustore; int *xsup, *supno; int *lsub, *xlsub; double *lusup; int *xlusup; double *ucol; int *usub, *xusub; int nzlmax, nzumax, nzlumax; int FILL = sp_ienv(6); Glu->n = n; no_expand = 0; iword = sizeof(int); dword = sizeof(double); if ( !expanders ) expanders = (ExpHeader*)SUPERLU_MALLOC(NO_MEMTYPE * sizeof(ExpHeader)); if ( !expanders ) ABORT("SUPERLU_MALLOC fails for expanders"); if ( lsame_(refact, "N") ) { /* Guess for L\U factors */ nzumax = nzlumax = FILL * annz; nzlmax = SUPERLU_MAX(1, FILL/4.) * annz; if ( lwork == -1 ) { return ( GluIntArray(n) * iword + TempSpace(m, panel_size) + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n ); } else { dSetupSpace(work, lwork, &Glu->MemModel); } #ifdef DEBUG printf("dLUMemInit() called: annz %d, MemModel %d\n", annz, Glu->MemModel); #endif /* Integer pointers for L\U factors */ if ( Glu->MemModel == SYSTEM ) { xsup = intMalloc(n+1); supno = intMalloc(n+1); xlsub = intMalloc(n+1); xlusup = intMalloc(n+1); xusub = intMalloc(n+1); } else { xsup = (int *)duser_malloc((n+1) * iword, HEAD); supno = (int *)duser_malloc((n+1) * iword, HEAD); xlsub = (int *)duser_malloc((n+1) * iword, HEAD); xlusup = (int *)duser_malloc((n+1) * iword, HEAD); xusub = (int *)duser_malloc((n+1) * iword, HEAD); } lusup = (double *) dexpand( &nzlumax, LUSUP, 0, 0, Glu ); ucol = (double *) dexpand( &nzumax, UCOL, 0, 0, Glu ); lsub = (int *) dexpand( &nzlmax, LSUB, 0, 0, Glu ); usub = (int *) dexpand( &nzumax, USUB, 0, 1, Glu ); while ( !lusup || !ucol || !lsub || !usub ) { if ( Glu->MemModel == SYSTEM ) { SUPERLU_FREE(lusup); SUPERLU_FREE(ucol); SUPERLU_FREE(lsub); SUPERLU_FREE(usub); } else { duser_free((nzlumax+nzumax)*dword+(nzlmax+nzumax)*iword, HEAD); } nzlumax /= 2; nzumax /= 2; nzlmax /= 2; if ( nzlumax < annz ) { printf("Not enough memory to perform factorization.\n"); return (dmemory_usage(nzlmax, nzumax, nzlumax, n) + n); } lusup = (double *) dexpand( &nzlumax, LUSUP, 0, 0, Glu ); ucol = (double *) dexpand( &nzumax, UCOL, 0, 0, Glu ); lsub = (int *) dexpand( &nzlmax, LSUB, 0, 0, Glu ); usub = (int *) dexpand( &nzumax, USUB, 0, 1, Glu ); } } else { /* refact == 'Y' */ Lstore = L->Store; Ustore = U->Store; xsup = Lstore->sup_to_col; supno = Lstore->col_to_sup; xlsub = Lstore->rowind_colptr; xlusup = Lstore->nzval_colptr; xusub = Ustore->colptr; nzlmax = Glu->nzlmax; /* max from previous factorization */ nzumax = Glu->nzumax; nzlumax = Glu->nzlumax; if ( lwork == -1 ) { return ( GluIntArray(n) * iword + TempSpace(m, panel_size) + (nzlmax+nzumax)*iword + (nzlumax+nzumax)*dword + n ); } else if ( lwork == 0 ) { Glu->MemModel = SYSTEM; } else { Glu->MemModel = USER; stack.top2 = (lwork/4)*4; /* must be word-addressable */ stack.size = stack.top2; } lsub = expanders[LSUB].mem = Lstore->rowind; lusup = expanders[LUSUP].mem = Lstore->nzval; usub = expanders[USUB].mem = Ustore->rowind; ucol = expanders[UCOL].mem = Ustore->nzval;; expanders[LSUB].size = nzlmax; expanders[LUSUP].size = nzlumax; expanders[USUB].size = nzumax; expanders[UCOL].size = nzumax; } Glu->xsup = xsup; Glu->supno = supno; Glu->lsub = lsub; Glu->xlsub = xlsub; Glu->lusup = lusup; Glu->xlusup = xlusup; Glu->ucol = ucol; Glu->usub = usub; Glu->xusub = xusub; Glu->nzlmax = nzlmax; Glu->nzumax = nzumax; Glu->nzlumax = nzlumax; info = dLUWorkInit(m, n, panel_size, iwork, dwork, Glu->MemModel); if ( info ) return ( info + dmemory_usage(nzlmax, nzumax, nzlumax, n) + n); ++no_expand; return 0; } /* dLUMemInit */ /* Allocate known working storage. Returns 0 if success, otherwise returns the number of bytes allocated so far when failure occurred. */ int dLUWorkInit(int m, int n, int panel_size, int **iworkptr, double **dworkptr, LU_space_t MemModel) { int isize, dsize, extra; double *old_ptr; int maxsuper = sp_ienv(3), rowblk = sp_ienv(4); isize = ( (2 * panel_size + 3 + NO_MARKER ) * m + n ) * sizeof(int); dsize = (m * panel_size + NUM_TEMPV(m,panel_size,maxsuper,rowblk)) * sizeof(double); if ( MemModel == SYSTEM ) *iworkptr = (int *) intCalloc(isize/sizeof(int)); else *iworkptr = (int *) duser_malloc(isize, TAIL); if ( ! *iworkptr ) { fprintf(stderr, "dLUWorkInit: malloc fails for local iworkptr[]\n"); return (isize + n); } if ( MemModel == SYSTEM ) *dworkptr = (double *) SUPERLU_MALLOC(dsize); else { *dworkptr = (double *) duser_malloc(dsize, TAIL); if ( NotDoubleAlign(*dworkptr) ) { old_ptr = *dworkptr; *dworkptr = (double*) DoubleAlign(*dworkptr); *dworkptr = (double*) ((double*)*dworkptr - 1); extra = (char*)old_ptr - (char*)*dworkptr; #ifdef DEBUG printf("dLUWorkInit: not aligned, extra %d\n", extra); #endif stack.top2 -= extra; stack.used += extra; } } if ( ! *dworkptr ) { fprintf(stderr, "malloc fails for local dworkptr[]."); return (isize + dsize + n); } return 0; } /* * Set up pointers for real working arrays. */ void dSetRWork(int m, int panel_size, double *dworkptr, double **dense, double **tempv) { double zero = 0.0; int maxsuper = sp_ienv(3), rowblk = sp_ienv(4); *dense = dworkptr; *tempv = *dense + panel_size*m; dfill (*dense, m * panel_size, zero); dfill (*tempv, NUM_TEMPV(m,panel_size,maxsuper,rowblk), zero); } /* * Free the working storage used by factor routines. */ void dLUWorkFree(int *iwork, double *dwork, GlobalLU_t *Glu) { if ( Glu->MemModel == SYSTEM ) { SUPERLU_FREE (iwork); SUPERLU_FREE (dwork); } else { stack.used -= (stack.size - stack.top2); stack.top2 = stack.size; /* dStackCompress(Glu); */ } SUPERLU_FREE (expanders); expanders = 0; } /* Expand the data structures for L and U during the factorization. * Return value: 0 - successful return * > 0 - number of bytes allocated when run out of space */ int dLUMemXpand(int jcol, int next, /* number of elements currently in the factors */ MemType mem_type, /* which type of memory to expand */ int *maxlen, /* modified - maximum length of a data structure */ GlobalLU_t *Glu /* modified - global LU data structures */ ) { void *new_mem; #ifdef DEBUG printf("dLUMemXpand(): jcol %d, next %d, maxlen %d, MemType %d\n", jcol, next, *maxlen, mem_type); #endif if (mem_type == USUB) new_mem = dexpand(maxlen, mem_type, next, 1, Glu); else new_mem = dexpand(maxlen, mem_type, next, 0, Glu); if ( !new_mem ) { int nzlmax = Glu->nzlmax; int nzumax = Glu->nzumax; int nzlumax = Glu->nzlumax; fprintf(stderr, "Can't expand MemType %d: jcol %d\n", mem_type, jcol); return (dmemory_usage(nzlmax, nzumax, nzlumax, Glu->n) + Glu->n); } switch ( mem_type ) { case LUSUP: Glu->lusup = (double *) new_mem; Glu->nzlumax = *maxlen; break; case UCOL: Glu->ucol = (double *) new_mem; Glu->nzumax = *maxlen; break; case LSUB: Glu->lsub = (int *) new_mem; Glu->nzlmax = *maxlen; break; case USUB: Glu->usub = (int *) new_mem; Glu->nzumax = *maxlen; break; } return 0; } void copy_mem_double(int howmany, void *old, void *new) { register int i; double *dold = old; double *dnew = new; for (i = 0; i < howmany; i++) dnew[i] = dold[i]; } /* * Expand the existing storage to accommodate more fill-ins. */ void *dexpand ( int *prev_len, /* length used from previous call */ MemType type, /* which part of the memory to expand */ int len_to_copy, /* size of the memory to be copied to new store */ int keep_prev, /* = 1: use prev_len; = 0: compute new_len to expand */ GlobalLU_t *Glu /* modified - global LU data structures */ ) { float EXPAND = 1.5; float alpha; void *new_mem, *old_mem; int new_len, tries, lword, extra, bytes_to_copy; alpha = EXPAND; if ( no_expand == 0 || keep_prev ) /* First time allocate requested */ new_len = *prev_len; else { new_len = alpha * *prev_len; } if ( type == LSUB || type == USUB ) lword = sizeof(int); else lword = sizeof(double); if ( Glu->MemModel == SYSTEM ) { new_mem = (void *) SUPERLU_MALLOC(new_len * lword); /* new_mem = (void *) calloc(new_len, lword); */ if ( no_expand != 0 ) { tries = 0; if ( keep_prev ) { if ( !new_mem ) return (NULL); } else { while ( !new_mem ) { if ( ++tries > 10 ) return (NULL); alpha = Reduce(alpha); new_len = alpha * *prev_len; new_mem = (void *) SUPERLU_MALLOC(new_len * lword); /* new_mem = (void *) calloc(new_len, lword); */ } } if ( type == LSUB || type == USUB ) { copy_mem_int(len_to_copy, expanders[type].mem, new_mem); } else { copy_mem_double(len_to_copy, expanders[type].mem, new_mem); } SUPERLU_FREE (expanders[type].mem); } expanders[type].mem = (void *) new_mem; } else { /* MemModel == USER */ if ( no_expand == 0 ) { new_mem = duser_malloc(new_len * lword, HEAD); if ( NotDoubleAlign(new_mem) && (type == LUSUP || type == UCOL) ) { old_mem = new_mem; new_mem = (void *)DoubleAlign(new_mem); extra = (char*)new_mem - (char*)old_mem; #ifdef DEBUG printf("expand(): not aligned, extra %d\n", extra); #endif stack.top1 += extra; stack.used += extra; } expanders[type].mem = (void *) new_mem; } else { tries = 0; extra = (new_len - *prev_len) * lword; if ( keep_prev ) { if ( StackFull(extra) ) return (NULL); } else { while ( StackFull(extra) ) { if ( ++tries > 10 ) return (NULL); alpha = Reduce(alpha); new_len = alpha * *prev_len; extra = (new_len - *prev_len) * lword; } } if ( type != USUB ) { new_mem = (void*)((char*)expanders[type + 1].mem + extra); bytes_to_copy = (char*)stack.array + stack.top1 - (char*)expanders[type + 1].mem; user_bcopy(expanders[type+1].mem, new_mem, bytes_to_copy); if ( type < USUB ) { Glu->usub = expanders[USUB].mem = (void*)((char*)expanders[USUB].mem + extra); } if ( type < LSUB ) { Glu->lsub = expanders[LSUB].mem = (void*)((char*)expanders[LSUB].mem + extra); } if ( type < UCOL ) { Glu->ucol = expanders[UCOL].mem = (void*)((char*)expanders[UCOL].mem + extra); } stack.top1 += extra; stack.used += extra; if ( type == UCOL ) { stack.top1 += extra; /* Add same amount for USUB */ stack.used += extra; } } /* if ... */ } /* else ... */ } expanders[type].size = new_len; *prev_len = new_len; if ( no_expand ) ++no_expand; return (void *) expanders[type].mem; } /* dexpand */ /* * Compress the work[] array to remove fragmentation. */ void dStackCompress(GlobalLU_t *Glu) { register int iword, dword, bytes_to_copy, ndim; char *last, *fragment; char *src, *dest; int *ifrom, *ito; double *dfrom, *dto; int *xlsub, *lsub, *xusub, *usub, *xlusup; double *ucol, *lusup; iword = sizeof(int); dword = sizeof(double); ndim = Glu->n; xlsub = Glu->xlsub; lsub = Glu->lsub; xusub = Glu->xusub; usub = Glu->usub; xlusup = Glu->xlusup; ucol = Glu->ucol; lusup = Glu->lusup; dfrom = ucol; dto = (double *)((char*)lusup + xlusup[ndim] * dword); copy_mem_double(xusub[ndim], dfrom, dto); ucol = dto; ifrom = lsub; ito = (int *) ((char*)ucol + xusub[ndim] * iword); copy_mem_int(xlsub[ndim], ifrom, ito); lsub = ito; ifrom = usub; ito = (int *) ((char*)lsub + xlsub[ndim] * iword); copy_mem_int(xusub[ndim], ifrom, ito); usub = ito; last = (char*)usub + xusub[ndim] * iword; fragment = (char*) (((char*)stack.array + stack.top1) - last); stack.used -= (long int) fragment; stack.top1 -= (long int) fragment; Glu->ucol = ucol; Glu->lsub = lsub; Glu->usub = usub; #ifdef DEBUG printf("dStackCompress: fragment %d\n", fragment); /* for (last = 0; last < ndim; ++last) print_lu_col("After compress:", last, 0);*/ #endif } /* * Allocate storage for original matrix A */ void dallocateA(int n, int nnz, double **a, int **asub, int **xa) { *a = (double *) doubleMalloc(nnz); *asub = (int *) intMalloc(nnz); *xa = (int *) intMalloc(n+1); } double *doubleMalloc(int n) { double *buf; buf = (double *) SUPERLU_MALLOC(n * sizeof(double)); if ( !buf ) { ABORT("SUPERLU_MALLOC failed for buf in doubleMalloc()\n"); } return (buf); } double *doubleCalloc(int n) { double *buf; register int i; double zero = 0.0; buf = (double *) SUPERLU_MALLOC(n * sizeof(double)); if ( !buf ) { ABORT("SUPERLU_MALLOC failed for buf in doubleCalloc()\n"); } for (i = 0; i < n; ++i) buf[i] = zero; return (buf); } int dmemory_usage(const int nzlmax, const int nzumax, const int nzlumax, const int n) { register int iword, dword; iword = sizeof(int); dword = sizeof(double); return (10 * n * iword + nzlmax * iword + nzumax * (iword + dword) + nzlumax * dword); } pysparse-1.1.1/superlu/dpanel_bmod.c0000644010116400000240000003165311402270247016472 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include #include #include "dsp_defs.h" #include "util.h" /* * Function prototypes */ void dlsolve(int, int, double *, double *); void dmatvec(int, int, int, double *, double *, double *); extern void dcheck_tempv(); void dpanel_bmod ( const int m, /* in - number of rows in the matrix */ const int w, /* in */ const int jcol, /* in */ const int nseg, /* in */ double *dense, /* out, of size n by w */ double *tempv, /* working array */ int *segrep, /* in */ int *repfnz, /* in, of size n by w */ GlobalLU_t *Glu /* modified */ ) { /* * Purpose * ======= * * Performs numeric block updates (sup-panel) in topological order. * It features: col-col, 2cols-col, 3cols-col, and sup-col updates. * Special processing on the supernodal portion of L\U[*,j] * * Before entering this routine, the original nonzeros in the panel * were already copied into the spa[m,w]. * * Updated/Output parameters- * dense[0:m-1,w]: L[*,j:j+w-1] and U[*,j:j+w-1] are returned * collectively in the m-by-w vector dense[*]. * */ #ifdef USE_VENDOR_BLAS #ifdef _CRAY _fcd ftcs1 = _cptofcd("L", strlen("L")), ftcs2 = _cptofcd("N", strlen("N")), ftcs3 = _cptofcd("U", strlen("U")); #endif int incx = 1, incy = 1; double alpha, beta; #endif register int k, ksub; int fsupc, nsupc, nsupr, nrow; int krep, krep_ind; double ukj, ukj1, ukj2; int luptr, luptr1, luptr2; int segsze; int block_nrow; /* no of rows in a block row */ register int lptr; /* Points to the row subscripts of a supernode */ int kfnz, irow, no_zeros; register int isub, isub1, i; register int jj; /* Index through each column in the panel */ int *xsup, *supno; int *lsub, *xlsub; double *lusup; int *xlusup; int *repfnz_col; /* repfnz[] for a column in the panel */ double *dense_col; /* dense[] for a column in the panel */ double *tempv1; /* Used in 1-D update */ double *TriTmp, *MatvecTmp; /* used in 2-D update */ double zero = 0.0; double one = 1.0; register int ldaTmp; register int r_ind, r_hi; static int first = 1, maxsuper, rowblk, colblk; extern SuperLUStat_t SuperLUStat; flops_t *ops = SuperLUStat.ops; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; lusup = Glu->lusup; xlusup = Glu->xlusup; if ( first ) { maxsuper = sp_ienv(3); rowblk = sp_ienv(4); colblk = sp_ienv(5); first = 0; } ldaTmp = maxsuper + rowblk; /* * For each nonz supernode segment of U[*,j] in topological order */ k = nseg - 1; for (ksub = 0; ksub < nseg; ksub++) { /* for each updating supernode */ /* krep = representative of current k-th supernode * fsupc = first supernodal column * nsupc = no of columns in a supernode * nsupr = no of rows in a supernode */ krep = segrep[k--]; fsupc = xsup[supno[krep]]; nsupc = krep - fsupc + 1; nsupr = xlsub[fsupc+1] - xlsub[fsupc]; nrow = nsupr - nsupc; lptr = xlsub[fsupc]; krep_ind = lptr + nsupc - 1; repfnz_col = repfnz; dense_col = dense; if ( nsupc >= colblk && nrow > rowblk ) { /* 2-D block update */ TriTmp = tempv; /* Sequence through each column in panel -- triangular solves */ for (jj = jcol; jj < jcol + w; jj++, repfnz_col += m, dense_col += m, TriTmp += ldaTmp ) { kfnz = repfnz_col[krep]; if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ segsze = krep - kfnz + 1; luptr = xlusup[fsupc]; ops[TRSV] += segsze * (segsze - 1); ops[GEMV] += 2 * nrow * segsze; /* Case 1: Update U-segment of size 1 -- col-col update */ if ( segsze == 1 ) { ukj = dense_col[lsub[krep_ind]]; luptr += nsupr*(nsupc-1) + nsupc; for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) { irow = lsub[i]; dense_col[irow] -= ukj * lusup[luptr]; ++luptr; } } else if ( segsze <= 3 ) { ukj = dense_col[lsub[krep_ind]]; ukj1 = dense_col[lsub[krep_ind - 1]]; luptr += nsupr*(nsupc-1) + nsupc-1; luptr1 = luptr - nsupr; if ( segsze == 2 ) { ukj -= ukj1 * lusup[luptr1]; dense_col[lsub[krep_ind]] = ukj; for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { irow = lsub[i]; luptr++; luptr1++; dense_col[irow] -= (ukj*lusup[luptr] + ukj1*lusup[luptr1]); } } else { ukj2 = dense_col[lsub[krep_ind - 2]]; luptr2 = luptr1 - nsupr; ukj1 -= ukj2 * lusup[luptr2-1]; ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; dense_col[lsub[krep_ind]] = ukj; dense_col[lsub[krep_ind-1]] = ukj1; for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { irow = lsub[i]; luptr++; luptr1++; luptr2++; dense_col[irow] -= ( ukj*lusup[luptr] + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); } } } else { /* segsze >= 4 */ /* Copy U[*,j] segment from dense[*] to TriTmp[*], which holds the result of triangular solves. */ no_zeros = kfnz - fsupc; isub = lptr + no_zeros; for (i = 0; i < segsze; ++i) { irow = lsub[isub]; TriTmp[i] = dense_col[irow]; /* Gather */ ++isub; } /* start effective triangle */ luptr += nsupr * no_zeros + no_zeros; #ifdef USE_VENDOR_BLAS #ifdef _CRAY STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], &nsupr, TriTmp, &incx ); #else dtrsv_( "L", "N", "U", &segsze, &lusup[luptr], &nsupr, TriTmp, &incx ); #endif #else dlsolve ( nsupr, segsze, &lusup[luptr], TriTmp ); #endif } /* else ... */ } /* for jj ... end tri-solves */ /* Block row updates; push all the way into dense[*] block */ for ( r_ind = 0; r_ind < nrow; r_ind += rowblk ) { r_hi = SUPERLU_MIN(nrow, r_ind + rowblk); block_nrow = SUPERLU_MIN(rowblk, r_hi - r_ind); luptr = xlusup[fsupc] + nsupc + r_ind; isub1 = lptr + nsupc + r_ind; repfnz_col = repfnz; TriTmp = tempv; dense_col = dense; /* Sequence through each column in panel -- matrix-vector */ for (jj = jcol; jj < jcol + w; jj++, repfnz_col += m, dense_col += m, TriTmp += ldaTmp) { kfnz = repfnz_col[krep]; if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ segsze = krep - kfnz + 1; if ( segsze <= 3 ) continue; /* skip unrolled cases */ /* Perform a block update, and scatter the result of matrix-vector to dense[]. */ no_zeros = kfnz - fsupc; luptr1 = luptr + nsupr * no_zeros; MatvecTmp = &TriTmp[maxsuper]; #ifdef USE_VENDOR_BLAS alpha = one; beta = zero; #ifdef _CRAY SGEMV(ftcs2, &block_nrow, &segsze, &alpha, &lusup[luptr1], &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy); #else dgemv_("N", &block_nrow, &segsze, &alpha, &lusup[luptr1], &nsupr, TriTmp, &incx, &beta, MatvecTmp, &incy); #endif #else dmatvec(nsupr, block_nrow, segsze, &lusup[luptr1], TriTmp, MatvecTmp); #endif /* Scatter MatvecTmp[*] into SPA dense[*] temporarily * such that MatvecTmp[*] can be re-used for the * the next blok row update. dense[] will be copied into * global store after the whole panel has been finished. */ isub = isub1; for (i = 0; i < block_nrow; i++) { irow = lsub[isub]; dense_col[irow] -= MatvecTmp[i]; MatvecTmp[i] = zero; ++isub; } } /* for jj ... */ } /* for each block row ... */ /* Scatter the triangular solves into SPA dense[*] */ repfnz_col = repfnz; TriTmp = tempv; dense_col = dense; for (jj = jcol; jj < jcol + w; jj++, repfnz_col += m, dense_col += m, TriTmp += ldaTmp) { kfnz = repfnz_col[krep]; if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ segsze = krep - kfnz + 1; if ( segsze <= 3 ) continue; /* skip unrolled cases */ no_zeros = kfnz - fsupc; isub = lptr + no_zeros; for (i = 0; i < segsze; i++) { irow = lsub[isub]; dense_col[irow] = TriTmp[i]; TriTmp[i] = zero; ++isub; } } /* for jj ... */ } else { /* 1-D block modification */ /* Sequence through each column in the panel */ for (jj = jcol; jj < jcol + w; jj++, repfnz_col += m, dense_col += m) { kfnz = repfnz_col[krep]; if ( kfnz == EMPTY ) continue; /* Skip any zero segment */ segsze = krep - kfnz + 1; luptr = xlusup[fsupc]; ops[TRSV] += segsze * (segsze - 1); ops[GEMV] += 2 * nrow * segsze; /* Case 1: Update U-segment of size 1 -- col-col update */ if ( segsze == 1 ) { ukj = dense_col[lsub[krep_ind]]; luptr += nsupr*(nsupc-1) + nsupc; for (i = lptr + nsupc; i < xlsub[fsupc+1]; i++) { irow = lsub[i]; dense_col[irow] -= ukj * lusup[luptr]; ++luptr; } } else if ( segsze <= 3 ) { ukj = dense_col[lsub[krep_ind]]; luptr += nsupr*(nsupc-1) + nsupc-1; ukj1 = dense_col[lsub[krep_ind - 1]]; luptr1 = luptr - nsupr; if ( segsze == 2 ) { ukj -= ukj1 * lusup[luptr1]; dense_col[lsub[krep_ind]] = ukj; for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { irow = lsub[i]; ++luptr; ++luptr1; dense_col[irow] -= (ukj*lusup[luptr] + ukj1*lusup[luptr1]); } } else { ukj2 = dense_col[lsub[krep_ind - 2]]; luptr2 = luptr1 - nsupr; ukj1 -= ukj2 * lusup[luptr2-1]; ukj = ukj - ukj1*lusup[luptr1] - ukj2*lusup[luptr2]; dense_col[lsub[krep_ind]] = ukj; dense_col[lsub[krep_ind-1]] = ukj1; for (i = lptr + nsupc; i < xlsub[fsupc+1]; ++i) { irow = lsub[i]; ++luptr; ++luptr1; ++luptr2; dense_col[irow] -= ( ukj*lusup[luptr] + ukj1*lusup[luptr1] + ukj2*lusup[luptr2] ); } } } else { /* segsze >= 4 */ /* * Perform a triangular solve and block update, * then scatter the result of sup-col update to dense[]. */ no_zeros = kfnz - fsupc; /* Copy U[*,j] segment from dense[*] to tempv[*]: * The result of triangular solve is in tempv[*]; * The result of matrix vector update is in dense_col[*] */ isub = lptr + no_zeros; for (i = 0; i < segsze; ++i) { irow = lsub[isub]; tempv[i] = dense_col[irow]; /* Gather */ ++isub; } /* start effective triangle */ luptr += nsupr * no_zeros + no_zeros; #ifdef USE_VENDOR_BLAS #ifdef _CRAY STRSV( ftcs1, ftcs2, ftcs3, &segsze, &lusup[luptr], &nsupr, tempv, &incx ); #else dtrsv_( "L", "N", "U", &segsze, &lusup[luptr], &nsupr, tempv, &incx ); #endif luptr += segsze; /* Dense matrix-vector */ tempv1 = &tempv[segsze]; alpha = one; beta = zero; #ifdef _CRAY SGEMV( ftcs2, &nrow, &segsze, &alpha, &lusup[luptr], &nsupr, tempv, &incx, &beta, tempv1, &incy ); #else dgemv_( "N", &nrow, &segsze, &alpha, &lusup[luptr], &nsupr, tempv, &incx, &beta, tempv1, &incy ); #endif #else dlsolve ( nsupr, segsze, &lusup[luptr], tempv ); luptr += segsze; /* Dense matrix-vector */ tempv1 = &tempv[segsze]; dmatvec (nsupr, nrow, segsze, &lusup[luptr], tempv, tempv1); #endif /* Scatter tempv[*] into SPA dense[*] temporarily, such * that tempv[*] can be used for the triangular solve of * the next column of the panel. They will be copied into * ucol[*] after the whole panel has been finished. */ isub = lptr + no_zeros; for (i = 0; i < segsze; i++) { irow = lsub[isub]; dense_col[irow] = tempv[i]; tempv[i] = zero; isub++; } /* Scatter the update from tempv1[*] into SPA dense[*] */ /* Start dense rectangular L */ for (i = 0; i < nrow; i++) { irow = lsub[isub]; dense_col[irow] -= tempv1[i]; tempv1[i] = zero; ++isub; } } /* else segsze>=4 ... */ } /* for each column in the panel... */ } /* else 1-D update ... */ } /* for each updating supernode ... */ } pysparse-1.1.1/superlu/dpanel_dfs.c0000644010116400000240000001640711402270240016316 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "dsp_defs.h" #include "util.h" void dpanel_dfs ( const int m, /* in - number of rows in the matrix */ const int w, /* in */ const int jcol, /* in */ SuperMatrix *A, /* in - original matrix */ int *perm_r, /* in */ int *nseg, /* out */ double *dense, /* out */ int *panel_lsub, /* out */ int *segrep, /* out */ int *repfnz, /* out */ int *xprune, /* out */ int *marker, /* out */ int *parent, /* working array */ int *xplore, /* working array */ GlobalLU_t *Glu /* modified */ ) { /* * Purpose * ======= * * Performs a symbolic factorization on a panel of columns [jcol, jcol+w). * * A supernode representative is the last column of a supernode. * The nonzeros in U[*,j] are segments that end at supernodal * representatives. * * The routine returns one list of the supernodal representatives * in topological order of the dfs that generates them. This list is * a superset of the topological order of each individual column within * the panel. * The location of the first nonzero in each supernodal segment * (supernodal entry location) is also returned. Each column has a * separate list for this purpose. * * Two marker arrays are used for dfs: * marker[i] == jj, if i was visited during dfs of current column jj; * marker1[i] >= jcol, if i was visited by earlier columns in this panel; * * marker: A-row --> A-row/col (0/1) * repfnz: SuperA-col --> PA-row * parent: SuperA-col --> SuperA-col * xplore: SuperA-col --> index to L-structure * */ NCPformat *Astore; double *a; int *asub; int *xa_begin, *xa_end; int krep, chperm, chmark, chrep, oldrep, kchild, myfnz; int k, krow, kmark, kperm; int xdfs, maxdfs, kpar; int jj; /* index through each column in the panel */ int *marker1; /* marker1[jj] >= jcol if vertex jj was visited by a previous column within this panel. */ int *repfnz_col; /* start of each column in the panel */ double *dense_col; /* start of each column in the panel */ int nextl_col; /* next available position in panel_lsub[*,jj] */ int *xsup, *supno; int *lsub, *xlsub; /* Initialize pointers */ Astore = A->Store; a = Astore->nzval; asub = Astore->rowind; xa_begin = Astore->colbeg; xa_end = Astore->colend; marker1 = marker + m; repfnz_col = repfnz; dense_col = dense; *nseg = 0; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; /* For each column in the panel */ for (jj = jcol; jj < jcol + w; jj++) { nextl_col = (jj - jcol) * m; #ifdef CHK_DFS printf("\npanel col %d: ", jj); #endif /* For each nonz in A[*,jj] do dfs */ for (k = xa_begin[jj]; k < xa_end[jj]; k++) { krow = asub[k]; dense_col[krow] = a[k]; kmark = marker[krow]; if ( kmark == jj ) continue; /* krow visited before, go to the next nonzero */ /* For each unmarked nbr krow of jj * krow is in L: place it in structure of L[*,jj] */ marker[krow] = jj; kperm = perm_r[krow]; if ( kperm == EMPTY ) { panel_lsub[nextl_col++] = krow; /* krow is indexed into A */ } /* * krow is in U: if its supernode-rep krep * has been explored, update repfnz[*] */ else { krep = xsup[supno[kperm]+1] - 1; myfnz = repfnz_col[krep]; #ifdef CHK_DFS printf("krep %d, myfnz %d, perm_r[%d] %d\n", krep, myfnz, krow, kperm); #endif if ( myfnz != EMPTY ) { /* Representative visited before */ if ( myfnz > kperm ) repfnz_col[krep] = kperm; /* continue; */ } else { /* Otherwise, perform dfs starting at krep */ oldrep = EMPTY; parent[krep] = oldrep; repfnz_col[krep] = kperm; xdfs = xlsub[krep]; maxdfs = xprune[krep]; #ifdef CHK_DFS printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs); for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); printf("\n"); #endif do { /* * For each unmarked kchild of krep */ while ( xdfs < maxdfs ) { kchild = lsub[xdfs]; xdfs++; chmark = marker[kchild]; if ( chmark != jj ) { /* Not reached yet */ marker[kchild] = jj; chperm = perm_r[kchild]; /* Case kchild is in L: place it in L[*,j] */ if ( chperm == EMPTY ) { panel_lsub[nextl_col++] = kchild; } /* Case kchild is in U: * chrep = its supernode-rep. If its rep has * been explored, update its repfnz[*] */ else { chrep = xsup[supno[chperm]+1] - 1; myfnz = repfnz_col[chrep]; #ifdef CHK_DFS printf("chrep %d,myfnz %d,perm_r[%d] %d\n",chrep,myfnz,kchild,chperm); #endif if ( myfnz != EMPTY ) { /* Visited before */ if ( myfnz > chperm ) repfnz_col[chrep] = chperm; } else { /* Cont. dfs at snode-rep of kchild */ xplore[krep] = xdfs; oldrep = krep; krep = chrep; /* Go deeper down G(L) */ parent[krep] = oldrep; repfnz_col[krep] = chperm; xdfs = xlsub[krep]; maxdfs = xprune[krep]; #ifdef CHK_DFS printf(" xdfs %d, maxdfs %d: ", xdfs, maxdfs); for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); printf("\n"); #endif } /* else */ } /* else */ } /* if... */ } /* while xdfs < maxdfs */ /* krow has no more unexplored nbrs: * Place snode-rep krep in postorder DFS, if this * segment is seen for the first time. (Note that * "repfnz[krep]" may change later.) * Backtrack dfs to its parent. */ if ( marker1[krep] < jcol ) { segrep[*nseg] = krep; ++(*nseg); marker1[krep] = jj; } kpar = parent[krep]; /* Pop stack, mimic recursion */ if ( kpar == EMPTY ) break; /* dfs done */ krep = kpar; xdfs = xplore[krep]; maxdfs = xprune[krep]; #ifdef CHK_DFS printf(" pop stack: krep %d,xdfs %d,maxdfs %d: ", krep,xdfs,maxdfs); for (i = xdfs; i < maxdfs; i++) printf(" %d", lsub[i]); printf("\n"); #endif } while ( kpar != EMPTY ); /* do-while - until empty stack */ } /* else */ } /* else */ } /* for each nonz in A[*,jj] */ repfnz_col += m; /* Move to next column */ dense_col += m; } /* for jj ... */ } pysparse-1.1.1/superlu/dpivotL.c0000644010116400000240000001221111402270236015632 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include #include #include "dsp_defs.h" #include "util.h" #undef DEBUG int dpivotL( const int jcol, /* in */ const double u, /* in - diagonal pivoting threshold */ int *usepr, /* re-use the pivot sequence given by perm_r/iperm_r */ int *perm_r, /* may be modified */ int *iperm_r, /* in - inverse of perm_r */ int *iperm_c, /* in - used to find diagonal of Pc*A*Pc' */ int *pivrow, /* out */ GlobalLU_t *Glu /* modified - global LU data structures */ ) { /* * Purpose * ======= * Performs the numerical pivoting on the current column of L, * and the CDIV operation. * * Pivot policy: * (1) Compute thresh = u * max_(i>=j) abs(A_ij); * (2) IF user specifies pivot row k and abs(A_kj) >= thresh THEN * pivot row = k; * ELSE IF abs(A_jj) >= thresh THEN * pivot row = j; * ELSE * pivot row = m; * * Note: If you absolutely want to use a given pivot order, then set u=0.0. * * Return value: 0 success; * i > 0 U(i,i) is exactly zero. * */ int fsupc; /* first column in the supernode */ int nsupc; /* no of columns in the supernode */ int nsupr; /* no of rows in the supernode */ int lptr; /* points to the starting subscript of the supernode */ int pivptr, old_pivptr, diag, diagind; double pivmax, rtemp, thresh; double temp; double *lu_sup_ptr; double *lu_col_ptr; int *lsub_ptr; int isub, icol, k, itemp; int *lsub, *xlsub; double *lusup; int *xlusup; extern SuperLUStat_t SuperLUStat; flops_t *ops = SuperLUStat.ops; /* Initialize pointers */ lsub = Glu->lsub; xlsub = Glu->xlsub; lusup = Glu->lusup; xlusup = Glu->xlusup; fsupc = (Glu->xsup)[(Glu->supno)[jcol]]; nsupc = jcol - fsupc; /* excluding jcol; nsupc >= 0 */ lptr = xlsub[fsupc]; nsupr = xlsub[fsupc+1] - lptr; lu_sup_ptr = &lusup[xlusup[fsupc]]; /* start of the current supernode */ lu_col_ptr = &lusup[xlusup[jcol]]; /* start of jcol in the supernode */ lsub_ptr = &lsub[lptr]; /* start of row indices of the supernode */ #ifdef DEBUG if ( jcol == MIN_COL ) { printf("Before cdiv: col %d\n", jcol); for (k = nsupc; k < nsupr; k++) printf(" lu[%d] %f\n", lsub_ptr[k], lu_col_ptr[k]); } #endif /* Determine the largest abs numerical value for partial pivoting; Also search for user-specified pivot, and diagonal element. */ if ( *usepr ) *pivrow = iperm_r[jcol]; diagind = iperm_c[jcol]; pivmax = 0.0; pivptr = nsupc; diag = EMPTY; old_pivptr = nsupc; for (isub = nsupc; isub < nsupr; ++isub) { rtemp = fabs (lu_col_ptr[isub]); if ( rtemp > pivmax ) { pivmax = rtemp; pivptr = isub; } if ( *usepr && lsub_ptr[isub] == *pivrow ) old_pivptr = isub; if ( lsub_ptr[isub] == diagind ) diag = isub; } /* Test for singularity */ if ( pivmax == 0.0 ) { *pivrow = lsub_ptr[pivptr]; perm_r[*pivrow] = jcol; *usepr = 0; return (jcol+1); } thresh = u * pivmax; /* Choose appropriate pivotal element by our policy. */ if ( *usepr ) { rtemp = fabs (lu_col_ptr[old_pivptr]); if ( rtemp != 0.0 && rtemp >= thresh ) pivptr = old_pivptr; else *usepr = 0; } if ( *usepr == 0 ) { /* Use diagonal pivot? */ if ( diag >= 0 ) { /* diagonal exists */ rtemp = fabs (lu_col_ptr[diag]); if ( rtemp != 0.0 && rtemp >= thresh ) pivptr = diag; } *pivrow = lsub_ptr[pivptr]; } /* Record pivot row */ perm_r[*pivrow] = jcol; /* Interchange row subscripts */ if ( pivptr != nsupc ) { itemp = lsub_ptr[pivptr]; lsub_ptr[pivptr] = lsub_ptr[nsupc]; lsub_ptr[nsupc] = itemp; /* Interchange numerical values as well, for the whole snode, such * that L is indexed the same way as A. */ for (icol = 0; icol <= nsupc; icol++) { itemp = pivptr + icol * nsupr; temp = lu_sup_ptr[itemp]; lu_sup_ptr[itemp] = lu_sup_ptr[nsupc + icol*nsupr]; lu_sup_ptr[nsupc + icol*nsupr] = temp; } } /* if */ /* cdiv operation */ ops[FACT] += nsupr - nsupc; temp = 1.0 / lu_col_ptr[nsupc]; for (k = nsupc+1; k < nsupr; k++) lu_col_ptr[k] *= temp; return 0; } pysparse-1.1.1/superlu/dpivotgrowth.c0000644010116400000240000000545111402270241016755 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include #include "dsp_defs.h" #include "util.h" double dPivotGrowth(int ncols, SuperMatrix *A, int *perm_c, SuperMatrix *L, SuperMatrix *U) { /* * Purpose * ======= * * Compute the reciprocal pivot growth factor of the leading ncols columns * of the matrix, using the formula: * min_j ( max_i(abs(A_ij)) / max_i(abs(U_ij)) ) * * Arguments * ========= * * ncols (input) int * The number of columns of matrices A, L and U. * * A (input) SuperMatrix* * Original matrix A, permuted by columns, of dimension * (A->nrow, A->ncol). The type of A can be: * Stype = NC; Dtype = D_; Mtype = GE. * * L (output) SuperMatrix* * The factor L from the factorization Pr*A=L*U; use compressed row * subscripts storage for supernodes, i.e., L has type: * Stype = SC; Dtype = D_; Mtype = TRLU. * * U (output) SuperMatrix* * The factor U from the factorization Pr*A*Pc=L*U. Use column-wise * storage scheme, i.e., U has types: Stype = NC; * Dtype = D_; Mtype = TRU. * */ NCformat *Astore; SCformat *Lstore; NCformat *Ustore; double *Aval, *Lval, *Uval; int fsupc, nsupr, luptr, nz_in_U; int i, j, k, oldcol; int *inv_perm_c; double rpg, maxaj, maxuj; extern double dlamch_(char *); double smlnum; double *luval; /* Get machine constants. */ smlnum = dlamch_("S"); rpg = 1. / smlnum; Astore = A->Store; Lstore = L->Store; Ustore = U->Store; Aval = Astore->nzval; Lval = Lstore->nzval; Uval = Ustore->nzval; inv_perm_c = (int *) SUPERLU_MALLOC(A->ncol*sizeof(int)); for (j = 0; j < A->ncol; ++j) inv_perm_c[perm_c[j]] = j; for (k = 0; k <= Lstore->nsuper; ++k) { fsupc = L_FST_SUPC(k); nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc); luptr = L_NZ_START(fsupc); luval = &Lval[luptr]; nz_in_U = 1; for (j = fsupc; j < L_FST_SUPC(k+1) && j < ncols; ++j) { maxaj = 0.; oldcol = inv_perm_c[j]; for (i = Astore->colptr[oldcol]; i < Astore->colptr[oldcol+1]; ++i) maxaj = SUPERLU_MAX( maxaj, fabs(Aval[i]) ); maxuj = 0.; for (i = Ustore->colptr[j]; i < Ustore->colptr[j+1]; i++) maxuj = SUPERLU_MAX( maxuj, fabs(Uval[i]) ); /* Supernode */ for (i = 0; i < nz_in_U; ++i) maxuj = SUPERLU_MAX( maxuj, fabs(luval[i]) ); ++nz_in_U; luval += nsupr; if ( maxuj == 0. ) rpg = SUPERLU_MIN( rpg, 1.); else rpg = SUPERLU_MIN( rpg, maxaj / maxuj ); } if ( j >= ncols ) break; } SUPERLU_FREE(inv_perm_c); return (rpg); } pysparse-1.1.1/superlu/dpruneL.c0000644010116400000240000000756211402270235015636 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "dsp_defs.h" #include "util.h" void dpruneL( const int jcol, /* in */ const int *perm_r, /* in */ const int pivrow, /* in */ const int nseg, /* in */ const int *segrep, /* in */ const int *repfnz, /* in */ int *xprune, /* out */ GlobalLU_t *Glu /* modified - global LU data structures */ ) { /* * Purpose * ======= * Prunes the L-structure of supernodes whose L-structure * contains the current pivot row "pivrow" * */ double utemp; int jsupno, irep, irep1, kmin, kmax, krow, movnum; int i, ktemp, minloc, maxloc; int do_prune; /* logical variable */ int *xsup, *supno; int *lsub, *xlsub; double *lusup; int *xlusup; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; lusup = Glu->lusup; xlusup = Glu->xlusup; /* * For each supernode-rep irep in U[*,j] */ jsupno = supno[jcol]; for (i = 0; i < nseg; i++) { irep = segrep[i]; irep1 = irep + 1; do_prune = FALSE; /* Don't prune with a zero U-segment */ if ( repfnz[irep] == EMPTY ) continue; /* If a snode overlaps with the next panel, then the U-segment * is fragmented into two parts -- irep and irep1. We should let * pruning occur at the rep-column in irep1's snode. */ if ( supno[irep] == supno[irep1] ) /* Don't prune */ continue; /* * If it has not been pruned & it has a nonz in row L[pivrow,i] */ if ( supno[irep] != jsupno ) { if ( xprune[irep] >= xlsub[irep1] ) { kmin = xlsub[irep]; kmax = xlsub[irep1] - 1; for (krow = kmin; krow <= kmax; krow++) if ( lsub[krow] == pivrow ) { do_prune = TRUE; break; } } if ( do_prune ) { /* Do a quicksort-type partition * movnum=TRUE means that the num values have to be exchanged. */ movnum = FALSE; if ( irep == xsup[supno[irep]] ) /* Snode of size 1 */ movnum = TRUE; while ( kmin <= kmax ) { if ( perm_r[lsub[kmax]] == EMPTY ) kmax--; else if ( perm_r[lsub[kmin]] != EMPTY ) kmin++; else { /* kmin below pivrow, and kmax above pivrow: * interchange the two subscripts */ ktemp = lsub[kmin]; lsub[kmin] = lsub[kmax]; lsub[kmax] = ktemp; /* If the supernode has only one column, then we * only keep one set of subscripts. For any subscript * interchange performed, similar interchange must be * done on the numerical values. */ if ( movnum ) { minloc = xlusup[irep] + (kmin - xlsub[irep]); maxloc = xlusup[irep] + (kmax - xlsub[irep]); utemp = lusup[minloc]; lusup[minloc] = lusup[maxloc]; lusup[maxloc] = utemp; } kmin++; kmax--; } } /* while */ xprune[irep] = kmin; /* Pruning */ #ifdef CHK_PRUNE printf(" After dpruneL(),using col %d: xprune[%d] = %d\n", jcol, irep, kmin); #endif } /* if do_prune */ } /* if */ } /* for each U-segment... */ } pysparse-1.1.1/superlu/dreadhb.c0000644010116400000240000001560011402270237015610 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include #include #include "dsp_defs.h" /* Eat up the rest of the current line */ int dDumpLine(FILE *fp) { register int c; while ((c = fgetc(fp)) != '\n') ; return 0; } int dParseIntFormat(char *buf, int *num, int *size) { char *tmp; tmp = buf; while (*tmp++ != '(') ; sscanf(tmp, "%d", num); while (*tmp != 'I' && *tmp != 'i') ++tmp; ++tmp; sscanf(tmp, "%d", size); return 0; } int dParseFloatFormat(char *buf, int *num, int *size) { char *tmp, *period; tmp = buf; while (*tmp++ != '(') ; sscanf(tmp, "%d", num); while (*tmp != 'E' && *tmp != 'e' && *tmp != 'D' && *tmp != 'd' && *tmp != 'F' && *tmp != 'f') ++tmp; ++tmp; period = tmp; while (*period != '.' && *period != ')') ++period ; *period = '\0'; sscanf(tmp, "%2d", size); return 0; } int dReadVector(FILE *fp, int n, int *where, int perline, int persize) { register int i, j, item; char tmp, buf[100]; i = 0; while (i < n) { fgets(buf, 100, fp); /* read a line at a time */ for (j=0; jlsub; xlsub = Glu->xlsub; lusup = Glu->lusup; xlusup = Glu->xlusup; nextlu = xlusup[jcol]; /* * Process the supernodal portion of L\U[*,j] */ for (isub = xlsub[fsupc]; isub < xlsub[fsupc+1]; isub++) { irow = lsub[isub]; lusup[nextlu] = dense[irow]; dense[irow] = 0; ++nextlu; } xlusup[jcol + 1] = nextlu; /* Initialize xlusup for next column */ if ( fsupc < jcol ) { luptr = xlusup[fsupc]; nsupr = xlsub[fsupc+1] - xlsub[fsupc]; nsupc = jcol - fsupc; /* Excluding jcol */ ufirst = xlusup[jcol]; /* Points to the beginning of column jcol in supernode L\U(jsupno). */ nrow = nsupr - nsupc; ops[TRSV] += nsupc * (nsupc - 1); ops[GEMV] += 2 * nrow * nsupc; #ifdef USE_VENDOR_BLAS #ifdef _CRAY STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &lusup[luptr], &nsupr, &lusup[ufirst], &incx ); SGEMV( ftcs2, &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); #else dtrsv_( "L", "N", "U", &nsupc, &lusup[luptr], &nsupr, &lusup[ufirst], &incx ); dgemv_( "N", &nrow, &nsupc, &alpha, &lusup[luptr+nsupc], &nsupr, &lusup[ufirst], &incx, &beta, &lusup[ufirst+nsupc], &incy ); #endif #else dlsolve ( nsupr, nsupc, &lusup[luptr], &lusup[ufirst] ); dmatvec ( nsupr, nrow, nsupc, &lusup[luptr+nsupc], &lusup[ufirst], &tempv[0] ); /* Scatter tempv[*] into lusup[*] */ iptr = ufirst + nsupc; for (i = 0; i < nrow; i++) { lusup[iptr++] -= tempv[i]; tempv[i] = 0.0; } #endif } return 0; } pysparse-1.1.1/superlu/dsnode_dfs.c0000644010116400000240000000567511402270177016345 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "dsp_defs.h" #include "util.h" int dsnode_dfs ( const int jcol, /* in - start of the supernode */ const int kcol, /* in - end of the supernode */ const int *asub, /* in */ const int *xa_begin, /* in */ const int *xa_end, /* in */ int *xprune, /* out */ int *marker, /* modified */ GlobalLU_t *Glu /* modified */ ) { /* Purpose * ======= * dsnode_dfs() - Determine the union of the row structures of those * columns within the relaxed snode. * Note: The relaxed snodes are leaves of the supernodal etree, therefore, * the portion outside the rectangular supernode must be zero. * * Return value * ============ * 0 success; * >0 number of bytes allocated when run out of memory. * */ register int i, k, ifrom, ito, nextl, new_next; int nsuper, krow, kmark, mem_error; int *xsup, *supno; int *lsub, *xlsub; int nzlmax; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; nzlmax = Glu->nzlmax; nsuper = ++supno[jcol]; /* Next available supernode number */ nextl = xlsub[jcol]; for (i = jcol; i <= kcol; i++) { /* For each nonzero in A[*,i] */ for (k = xa_begin[i]; k < xa_end[i]; k++) { krow = asub[k]; kmark = marker[krow]; if ( kmark != kcol ) { /* First time visit krow */ marker[krow] = kcol; lsub[nextl++] = krow; if ( nextl >= nzlmax ) { if ( mem_error = dLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu) ) return (mem_error); lsub = Glu->lsub; } } } supno[i] = nsuper; } /* Supernode > 1, then make a copy of the subscripts for pruning */ if ( jcol < kcol ) { new_next = nextl + (nextl - xlsub[jcol]); while ( new_next > nzlmax ) { if ( mem_error = dLUMemXpand(jcol, nextl, LSUB, &nzlmax, Glu) ) return (mem_error); lsub = Glu->lsub; } ito = nextl; for (ifrom = xlsub[jcol]; ifrom < nextl; ) lsub[ito++] = lsub[ifrom++]; for (i = jcol+1; i <= kcol; i++) xlsub[i] = nextl; nextl = ito; } xsup[nsuper+1] = kcol + 1; supno[kcol+1] = nsuper; xprune[kcol] = nextl; xlsub[kcol+1] = nextl; return 0; } pysparse-1.1.1/superlu/dsp_blas2.c0000644010116400000240000003230111402270221016056 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * File name: sp_blas2.c * Purpose: Sparse BLAS 2, using some dense BLAS 2 operations. */ #include "dsp_defs.h" #include "util.h" /* * Function prototypes */ void dusolve(int, int, double*, double*); void dlsolve(int, int, double*, double*); void dmatvec(int, int, int, double*, double*, double*); int sp_dtrsv(char *uplo, char *trans, char *diag, SuperMatrix *L, SuperMatrix *U, double *x, int *info) { /* * Purpose * ======= * * sp_dtrsv() solves one of the systems of equations * A*x = b, or A'*x = b, * where b and x are n element vectors and A is a sparse unit , or * non-unit, upper or lower triangular matrix. * No test for singularity or near-singularity is included in this * routine. Such tests must be performed before calling this routine. * * Parameters * ========== * * uplo - (input) char* * On entry, uplo specifies whether the matrix is an upper or * lower triangular matrix as follows: * uplo = 'U' or 'u' A is an upper triangular matrix. * uplo = 'L' or 'l' A is a lower triangular matrix. * * trans - (input) char* * On entry, trans specifies the equations to be solved as * follows: * trans = 'N' or 'n' A*x = b. * trans = 'T' or 't' A'*x = b. * trans = 'C' or 'c' A'*x = b. * * diag - (input) char* * On entry, diag specifies whether or not A is unit * triangular as follows: * diag = 'U' or 'u' A is assumed to be unit triangular. * diag = 'N' or 'n' A is not assumed to be unit * triangular. * * L - (input) SuperMatrix* * The factor L from the factorization Pr*A*Pc=L*U. Use * compressed row subscripts storage for supernodes, * i.e., L has types: Stype = SC, Dtype = D_, Mtype = TRLU. * * U - (input) SuperMatrix* * The factor U from the factorization Pr*A*Pc=L*U. * U has types: Stype = NC, Dtype = D_, Mtype = TRU. * * x - (input/output) double* * Before entry, the incremented array X must contain the n * element right-hand side vector b. On exit, X is overwritten * with the solution vector x. * * info - (output) int* * If *info = -i, the i-th argument had an illegal value. * */ #ifdef _CRAY _fcd ftcs1 = _cptofcd("L", strlen("L")), ftcs2 = _cptofcd("N", strlen("N")), ftcs3 = _cptofcd("U", strlen("U")); #endif SCformat *Lstore; NCformat *Ustore; double *Lval, *Uval; int incx = 1, incy = 1; double alpha = 1.0, beta = 1.0; int nrow; int fsupc, nsupr, nsupc, luptr, istart, irow; int i, k, iptr, jcol; double *work; flops_t solve_ops; extern SuperLUStat_t SuperLUStat; /* Test the input parameters */ *info = 0; if ( !lsame_(uplo,"L") && !lsame_(uplo, "U") ) *info = -1; else if ( !lsame_(trans, "N") && !lsame_(trans, "T") ) *info = -2; else if ( !lsame_(diag, "U") && !lsame_(diag, "N") ) *info = -3; else if ( L->nrow != L->ncol || L->nrow < 0 ) *info = -4; else if ( U->nrow != U->ncol || U->nrow < 0 ) *info = -5; if ( *info ) { i = -(*info); xerbla_("sp_dtrsv", &i); return 0; } Lstore = L->Store; Lval = Lstore->nzval; Ustore = U->Store; Uval = Ustore->nzval; solve_ops = 0; if ( !(work = doubleCalloc(L->nrow)) ) ABORT("Malloc fails for work in sp_dtrsv()."); if ( lsame_(trans, "N") ) { /* Form x := inv(A)*x. */ if ( lsame_(uplo, "L") ) { /* Form x := inv(L)*x */ if ( L->nrow == 0 ) return 0; /* Quick return */ for (k = 0; k <= Lstore->nsuper; k++) { fsupc = L_FST_SUPC(k); istart = L_SUB_START(fsupc); nsupr = L_SUB_START(fsupc+1) - istart; nsupc = L_FST_SUPC(k+1) - fsupc; luptr = L_NZ_START(fsupc); nrow = nsupr - nsupc; solve_ops += nsupc * (nsupc - 1); solve_ops += 2 * nrow * nsupc; if ( nsupc == 1 ) { for (iptr=istart+1; iptr < L_SUB_START(fsupc+1); ++iptr) { irow = L_SUB(iptr); ++luptr; x[irow] -= x[fsupc] * Lval[luptr]; } } else { #ifdef USE_VENDOR_BLAS #ifdef _CRAY STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); SGEMV(ftcs2, &nrow, &nsupc, &alpha, &Lval[luptr+nsupc], &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy); #else dtrsv_("L", "N", "U", &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); dgemv_("N", &nrow, &nsupc, &alpha, &Lval[luptr+nsupc], &nsupr, &x[fsupc], &incx, &beta, &work[0], &incy); #endif #else dlsolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc]); dmatvec ( nsupr, nsupr-nsupc, nsupc, &Lval[luptr+nsupc], &x[fsupc], &work[0] ); #endif iptr = istart + nsupc; for (i = 0; i < nrow; ++i, ++iptr) { irow = L_SUB(iptr); x[irow] -= work[i]; /* Scatter */ work[i] = 0.0; } } } /* for k ... */ } else { /* Form x := inv(U)*x */ if ( U->nrow == 0 ) return 0; /* Quick return */ for (k = Lstore->nsuper; k >= 0; k--) { fsupc = L_FST_SUPC(k); nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc); nsupc = L_FST_SUPC(k+1) - fsupc; luptr = L_NZ_START(fsupc); solve_ops += nsupc * (nsupc + 1); if ( nsupc == 1 ) { x[fsupc] /= Lval[luptr]; for (i = U_NZ_START(fsupc); i < U_NZ_START(fsupc+1); ++i) { irow = U_SUB(i); x[irow] -= x[fsupc] * Uval[i]; } } else { #ifdef USE_VENDOR_BLAS #ifdef _CRAY STRSV(ftcs3, ftcs2, ftcs2, &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); #else dtrsv_("U", "N", "N", &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); #endif #else dusolve ( nsupr, nsupc, &Lval[luptr], &x[fsupc] ); #endif for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++) { irow = U_SUB(i); x[irow] -= x[jcol] * Uval[i]; } } } } /* for k ... */ } } else { /* Form x := inv(A')*x */ if ( lsame_(uplo, "L") ) { /* Form x := inv(L')*x */ if ( L->nrow == 0 ) return 0; /* Quick return */ for (k = Lstore->nsuper; k >= 0; --k) { fsupc = L_FST_SUPC(k); istart = L_SUB_START(fsupc); nsupr = L_SUB_START(fsupc+1) - istart; nsupc = L_FST_SUPC(k+1) - fsupc; luptr = L_NZ_START(fsupc); solve_ops += 2 * (nsupr - nsupc) * nsupc; for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { iptr = istart + nsupc; for (i = L_NZ_START(jcol) + nsupc; i < L_NZ_START(jcol+1); i++) { irow = L_SUB(iptr); x[jcol] -= x[irow] * Lval[i]; iptr++; } } if ( nsupc > 1 ) { solve_ops += nsupc * (nsupc - 1); #ifdef _CRAY ftcs1 = _cptofcd("L", strlen("L")); ftcs2 = _cptofcd("T", strlen("T")); ftcs3 = _cptofcd("U", strlen("U")); STRSV(ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); #else dtrsv_("L", "T", "U", &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); #endif } } } else { /* Form x := inv(U')*x */ if ( U->nrow == 0 ) return 0; /* Quick return */ for (k = 0; k <= Lstore->nsuper; k++) { fsupc = L_FST_SUPC(k); nsupr = L_SUB_START(fsupc+1) - L_SUB_START(fsupc); nsupc = L_FST_SUPC(k+1) - fsupc; luptr = L_NZ_START(fsupc); for (jcol = fsupc; jcol < L_FST_SUPC(k+1); jcol++) { solve_ops += 2*(U_NZ_START(jcol+1) - U_NZ_START(jcol)); for (i = U_NZ_START(jcol); i < U_NZ_START(jcol+1); i++) { irow = U_SUB(i); x[jcol] -= x[irow] * Uval[i]; } } solve_ops += nsupc * (nsupc + 1); if ( nsupc == 1 ) { x[fsupc] /= Lval[luptr]; } else { #ifdef _CRAY ftcs1 = _cptofcd("U", strlen("U")); ftcs2 = _cptofcd("T", strlen("T")); ftcs3 = _cptofcd("N", strlen("N")); STRSV( ftcs1, ftcs2, ftcs3, &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); #else dtrsv_("U", "T", "N", &nsupc, &Lval[luptr], &nsupr, &x[fsupc], &incx); #endif } } /* for k ... */ } } SuperLUStat.ops[SOLVE] += solve_ops; SUPERLU_FREE(work); return 0; } int sp_dgemv(char *trans, double alpha, SuperMatrix *A, double *x, int incx, double beta, double *y, int incy) { /* Purpose ======= sp_dgemv() performs one of the matrix-vector operations y := alpha*A*x + beta*y, or y := alpha*A'*x + beta*y, where alpha and beta are scalars, x and y are vectors and A is a sparse A->nrow by A->ncol matrix. Parameters ========== TRANS - (input) char* On entry, TRANS specifies the operation to be performed as follows: TRANS = 'N' or 'n' y := alpha*A*x + beta*y. TRANS = 'T' or 't' y := alpha*A'*x + beta*y. TRANS = 'C' or 'c' y := alpha*A'*x + beta*y. ALPHA - (input) double On entry, ALPHA specifies the scalar alpha. A - (input) SuperMatrix* Matrix A with a sparse format, of dimension (A->nrow, A->ncol). Currently, the type of A can be: Stype = NC or NCP; Dtype = D_; Mtype = GE. In the future, more general A can be handled. X - (input) double*, array of DIMENSION at least ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n' and at least ( 1 + ( m - 1 )*abs( INCX ) ) otherwise. Before entry, the incremented array X must contain the vector x. INCX - (input) int On entry, INCX specifies the increment for the elements of X. INCX must not be zero. BETA - (input) double On entry, BETA specifies the scalar beta. When BETA is supplied as zero then Y need not be set on input. Y - (output) double*, array of DIMENSION at least ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n' and at least ( 1 + ( n - 1 )*abs( INCY ) ) otherwise. Before entry with BETA non-zero, the incremented array Y must contain the vector y. On exit, Y is overwritten by the updated vector y. INCY - (input) int On entry, INCY specifies the increment for the elements of Y. INCY must not be zero. ==== Sparse Level 2 Blas routine. */ /* Local variables */ NCformat *Astore; double *Aval; int info; double temp; int lenx, leny, i, j, irow; int iy, jx, jy, kx, ky; int notran; notran = lsame_(trans, "N"); Astore = A->Store; Aval = Astore->nzval; /* Test the input parameters */ info = 0; if ( !notran && !lsame_(trans, "T") && !lsame_(trans, "C")) info = 1; else if ( A->nrow < 0 || A->ncol < 0 ) info = 3; else if (incx == 0) info = 5; else if (incy == 0) info = 8; if (info != 0) { xerbla_("sp_dgemv ", &info); return 0; } /* Quick return if possible. */ if (A->nrow == 0 || A->ncol == 0 || alpha == 0. && beta == 1.) return 0; /* Set LENX and LENY, the lengths of the vectors x and y, and set up the start points in X and Y. */ if (lsame_(trans, "N")) { lenx = A->ncol; leny = A->nrow; } else { lenx = A->nrow; leny = A->ncol; } if (incx > 0) kx = 0; else kx = - (lenx - 1) * incx; if (incy > 0) ky = 0; else ky = - (leny - 1) * incy; /* Start the operations. In this version the elements of A are accessed sequentially with one pass through A. */ /* First form y := beta*y. */ if (beta != 1.) { if (incy == 1) { if (beta == 0.) for (i = 0; i < leny; ++i) y[i] = 0.; else for (i = 0; i < leny; ++i) y[i] = beta * y[i]; } else { iy = ky; if (beta == 0.) for (i = 0; i < leny; ++i) { y[iy] = 0.; iy += incy; } else for (i = 0; i < leny; ++i) { y[iy] = beta * y[iy]; iy += incy; } } } if (alpha == 0.) return 0; if ( notran ) { /* Form y := alpha*A*x + y. */ jx = kx; if (incy == 1) { for (j = 0; j < A->ncol; ++j) { if (x[jx] != 0.) { temp = alpha * x[jx]; for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { irow = Astore->rowind[i]; y[irow] += temp * Aval[i]; } } jx += incx; } } else { ABORT("Not implemented."); } } else { /* Form y := alpha*A'*x + y. */ jy = ky; if (incx == 1) { for (j = 0; j < A->ncol; ++j) { temp = 0.; for (i = Astore->colptr[j]; i < Astore->colptr[j+1]; ++i) { irow = Astore->rowind[i]; temp += Aval[i] * x[irow]; } y[jy] += alpha * temp; jy += incy; } } else { ABORT("Not implemented."); } } return 0; } /* sp_dgemv */ pysparse-1.1.1/superlu/dsp_blas3.c0000644010116400000240000001022011402270235016060 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * File name: sp_blas3.c * Purpose: Sparse BLAS3, using some dense BLAS3 operations. */ #include "dsp_defs.h" #include "util.h" int sp_dgemm(char *transa, char *transb, int m, int n, int k, double alpha, SuperMatrix *A, double *b, int ldb, double beta, double *c, int ldc) { /* Purpose ======= sp_d performs one of the matrix-matrix operations C := alpha*op( A )*op( B ) + beta*C, where op( X ) is one of op( X ) = X or op( X ) = X' or op( X ) = conjg( X' ), alpha and beta are scalars, and A, B and C are matrices, with op( A ) an m by k matrix, op( B ) a k by n matrix and C an m by n matrix. Parameters ========== TRANSA - (input) char* On entry, TRANSA specifies the form of op( A ) to be used in the matrix multiplication as follows: TRANSA = 'N' or 'n', op( A ) = A. TRANSA = 'T' or 't', op( A ) = A'. TRANSA = 'C' or 'c', op( A ) = conjg( A' ). Unchanged on exit. TRANSB - (input) char* On entry, TRANSB specifies the form of op( B ) to be used in the matrix multiplication as follows: TRANSB = 'N' or 'n', op( B ) = B. TRANSB = 'T' or 't', op( B ) = B'. TRANSB = 'C' or 'c', op( B ) = conjg( B' ). Unchanged on exit. M - (input) int On entry, M specifies the number of rows of the matrix op( A ) and of the matrix C. M must be at least zero. Unchanged on exit. N - (input) int On entry, N specifies the number of columns of the matrix op( B ) and the number of columns of the matrix C. N must be at least zero. Unchanged on exit. K - (input) int On entry, K specifies the number of columns of the matrix op( A ) and the number of rows of the matrix op( B ). K must be at least zero. Unchanged on exit. ALPHA - (input) double On entry, ALPHA specifies the scalar alpha. A - (input) SuperMatrix* Matrix A with a sparse format, of dimension (A->nrow, A->ncol). Currently, the type of A can be: Stype = NC or NCP; Dtype = D_; Mtype = GE. In the future, more general A can be handled. B - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is n when TRANSB = 'N' or 'n', and is k otherwise. Before entry with TRANSB = 'N' or 'n', the leading k by n part of the array B must contain the matrix B, otherwise the leading n by k part of the array B must contain the matrix B. Unchanged on exit. LDB - (input) int On entry, LDB specifies the first dimension of B as declared in the calling (sub) program. LDB must be at least max( 1, n ). Unchanged on exit. BETA - (input) double On entry, BETA specifies the scalar beta. When BETA is supplied as zero then C need not be set on input. C - DOUBLE PRECISION array of DIMENSION ( LDC, n ). Before entry, the leading m by n part of the array C must contain the matrix C, except when beta is zero, in which case C need not be set on entry. On exit, the array C is overwritten by the m by n matrix ( alpha*op( A )*B + beta*C ). LDC - (input) int On entry, LDC specifies the first dimension of C as declared in the calling (sub)program. LDC must be at least max(1,m). Unchanged on exit. ==== Sparse Level 3 Blas routine. */ int incx = 1, incy = 1; int j; for (j = 0; j < n; ++j) { sp_dgemv(transa, alpha, A, &b[ldb*j], incx, beta, &c[ldc*j], incy); } return 0; } pysparse-1.1.1/superlu/dsp_defs.h0000644010116400000240000002264711402270216016021 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #ifndef __SUPERLU_dSP_DEFS /* allow multiple inclusions */ #define __SUPERLU_dSP_DEFS /* * File name: dsp_defs.h * Purpose: Sparse matrix types and function prototypes * History: */ #ifdef _CRAY #include #include #endif #include "Cnames.h" #include "supermatrix.h" /* No of marker arrays used in the symbolic factorization, each of size n */ #define NO_MARKER 3 #define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) ) typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; typedef enum {HEAD, TAIL} stack_end_t; typedef enum {SYSTEM, USER} LU_space_t; /* * Global data structures used in LU factorization - * * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. * (xsup,supno): supno[i] is the supernode no to which i belongs; * xsup(s) points to the beginning of the s-th supernode. * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) * xsup 0 1 2 4 7 12 * Note: dfs will be performed on supernode rep. relative to the new * row pivoting ordering * * (xlsub,lsub): lsub[*] contains the compressed subscript of * rectangular supernodes; xlsub[j] points to the starting * location of the j-th column in lsub[*]. Note that xlsub * is indexed by column. * Storage: original row subscripts * * During the course of sparse LU factorization, we also use * (xlsub,lsub) for the purpose of symmetric pruning. For each * supernode {s,s+1,...,t=s+r} with first column s and last * column t, the subscript set * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 * is the structure of column s (i.e. structure of this supernode). * It is used for the storage of numerical values. * Furthermore, * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 * is the structure of the last column t of this supernode. * It is for the purpose of symmetric pruning. Therefore, the * structural subscripts can be rearranged without making physical * interchanges among the numerical values. * * However, if the supernode has only one column, then we * only keep one set of subscripts. For any subscript interchange * performed, similar interchange must be done on the numerical * values. * * The last column structures (for pruning) will be removed * after the numercial LU factorization phase. * * (xlusup,lusup): lusup[*] contains the numerical values of the * rectangular supernodes; xlusup[j] points to the starting * location of the j-th column in storage vector lusup[*] * Note: xlusup is indexed by column. * Each rectangular supernode is stored by column-major * scheme, consistent with Fortran 2-dim array storage. * * (xusub,ucol,usub): ucol[*] stores the numerical values of * U-columns outside the rectangular supernodes. The row * subscript of nonzero ucol[k] is stored in usub[k]. * xusub[i] points to the starting location of column i in ucol. * Storage: new row subscripts; that is subscripts of PA. */ typedef struct { int *xsup; /* supernode and column mapping */ int *supno; int *lsub; /* compressed L subscripts */ int *xlsub; double *lusup; /* L supernodes */ int *xlusup; double *ucol; /* U columns */ int *usub; int *xusub; int nzlmax; /* current max size of lsub */ int nzumax; /* " " " ucol */ int nzlumax; /* " " " lusup */ int n; /* number of columns in the matrix */ LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ } GlobalLU_t; typedef struct { int panel_size; int relax; double diag_pivot_thresh; double drop_tol; } factor_param_t; typedef struct { float for_lu; float total_needed; int expansions; } mem_usage_t; #ifdef __cplusplus extern "C" { #endif /* Driver routines */ extern void dgssv(SuperMatrix *, int *, int *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *); extern void dgssvx(char *, char *, char *, SuperMatrix *, factor_param_t *, int *, int *, int *, char *, double *, double *, SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, double *, double *, double *, double *, mem_usage_t *, int *); /* Supernodal LU factor related */ extern void dCreate_CompCol_Matrix(SuperMatrix *, int, int, int, double *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void dCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); extern void dCreate_Dense_Matrix(SuperMatrix *, int, int, double *, int, Stype_t, Dtype_t, Mtype_t); extern void dCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, double *, int *, int *, int *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void dCopy_Dense_Matrix(int, int, double *, int, double *, int); extern void Destroy_SuperMatrix_Store(SuperMatrix *); extern void Destroy_CompCol_Matrix(SuperMatrix *); extern void Destroy_SuperNode_Matrix(SuperMatrix *); extern void Destroy_CompCol_Permuted(SuperMatrix *); extern void Destroy_Dense_Matrix(SuperMatrix *); extern void get_perm_c(int, SuperMatrix *, int *); extern void sp_preorder (char*, SuperMatrix*, int*, int*, SuperMatrix*); extern void countnz (const int, int *, int *, int *, GlobalLU_t *); extern void fixupL (const int, const int *, GlobalLU_t *); extern void dallocateA (int, int, double **, int **, int **); extern void dgstrf (char*, SuperMatrix*, double, double, int, int, int*, void *, int, int *, int *, SuperMatrix *, SuperMatrix *, int *); extern int dsnode_dfs (const int, const int, const int *, const int *, const int *, int *, int *, GlobalLU_t *); extern int dsnode_bmod (const int, const int, const int, double *, double *, GlobalLU_t *); extern void dpanel_dfs (const int, const int, const int, SuperMatrix *, int *, int *, double *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern void dpanel_bmod (const int, const int, const int, const int, double *, double *, int *, int *, GlobalLU_t *); extern int dcolumn_dfs (const int, const int, int *, int *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern int dcolumn_bmod (const int, const int, double *, double *, int *, int *, int, GlobalLU_t *); extern int dcopy_to_ucol (int, int, int *, int *, int *, double *, GlobalLU_t *); extern int dpivotL (const int, const double, int *, int *, int *, int *, int *, GlobalLU_t *); extern void dpruneL (const int, const int *, const int, const int, const int *, const int *, int *, GlobalLU_t *); extern void dreadmt (int *, int *, int *, double **, int **, int **); extern void dGenXtrue (int, int, double *, int); extern void dFillRHS (char *, int, double *, int, SuperMatrix *, SuperMatrix *); extern void dgstrs (char *, SuperMatrix *, SuperMatrix *, int *, int *, SuperMatrix *, int *); /* Driver related */ extern void dgsequ (SuperMatrix *, double *, double *, double *, double *, double *, int *); extern void dlaqgs (SuperMatrix *, double *, double *, double, double, double, char *); extern void dgscon (char *, SuperMatrix *, SuperMatrix *, double, double *, int *); extern double dPivotGrowth(int, SuperMatrix *, int *, SuperMatrix *, SuperMatrix *); extern void dgsrfs (char *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *, int *, char *, double *, double *, SuperMatrix *, SuperMatrix *, double *, double *, int *); extern int sp_dtrsv (char *, char *, char *, SuperMatrix *, SuperMatrix *, double *, int *); extern int sp_dgemv (char *, double, SuperMatrix *, double *, int, double, double *, int); extern int sp_dgemm (char *, char *, int, int, int, double, SuperMatrix *, double *, int, double, double *, int); /* Memory-related */ extern int dLUMemInit (char *, void *, int, int, int, int, int, SuperMatrix *, SuperMatrix *, GlobalLU_t *, int **, double **); extern void dSetRWork (int, int, double *, double **, double **); extern void dLUWorkFree (int *, double *, GlobalLU_t *); extern int dLUMemXpand (int, int, MemType, int *, GlobalLU_t *); extern double *doubleMalloc(int); extern double *doubleCalloc(int); extern int dmemory_usage(const int, const int, const int, const int); extern int dQuerySpace (SuperMatrix *, SuperMatrix *, int, mem_usage_t *); /* Auxiliary routines */ extern void dreadhb(int *, int *, int *, double **, int **, int **); extern void dCompRow_to_CompCol(int, int, int, double*, int*, int*, double **, int **, int **); extern void dfill (double *, int, double); extern void dinf_norm_error (int, SuperMatrix *, double *); extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, double, double, double *, double *, char *); /* Routines for debugging */ extern void dPrint_CompCol_Matrix(char *, SuperMatrix *); extern void dPrint_SuperNode_Matrix(char *, SuperMatrix *); extern void dPrint_Dense_Matrix(char *, SuperMatrix *); extern void print_lu_col(char *, int, int, int *, GlobalLU_t *); extern void check_tempv(int, double *); #ifdef __cplusplus } #endif #endif /* __SUPERLU_dSP_DEFS */ pysparse-1.1.1/superlu/dutil.c0000644010116400000240000003074211402270251015340 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include #include "dsp_defs.h" #include "util.h" void dCreate_CompCol_Matrix(SuperMatrix *A, int m, int n, int nnz, double *nzval, int *rowind, int *colptr, Stype_t stype, Dtype_t dtype, Mtype_t mtype) { NCformat *Astore; A->Stype = stype; A->Dtype = dtype; A->Mtype = mtype; A->nrow = m; A->ncol = n; A->Store = (void *) SUPERLU_MALLOC( sizeof(NCformat) ); if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store"); Astore = A->Store; Astore->nnz = nnz; Astore->nzval = nzval; Astore->rowind = rowind; Astore->colptr = colptr; } void dCreate_CompRow_Matrix(SuperMatrix *A, int m, int n, int nnz, double *nzval, int *colind, int *rowptr, Stype_t stype, Dtype_t dtype, Mtype_t mtype) { NRformat *Astore; A->Stype = stype; A->Dtype = dtype; A->Mtype = mtype; A->nrow = m; A->ncol = n; A->Store = (void *) SUPERLU_MALLOC( sizeof(NRformat) ); if ( !(A->Store) ) ABORT("SUPERLU_MALLOC fails for A->Store"); Astore = A->Store; Astore->nnz = nnz; Astore->nzval = nzval; Astore->colind = colind; Astore->rowptr = rowptr; } /* Copy matrix A into matrix B. */ void dCopy_CompCol_Matrix(SuperMatrix *A, SuperMatrix *B) { NCformat *Astore, *Bstore; int ncol, nnz, i; B->Stype = A->Stype; B->Dtype = A->Dtype; B->Mtype = A->Mtype; B->nrow = A->nrow;; B->ncol = ncol = A->ncol; Astore = (NCformat *) A->Store; Bstore = (NCformat *) B->Store; Bstore->nnz = nnz = Astore->nnz; for (i = 0; i < nnz; ++i) ((double *)Bstore->nzval)[i] = ((double *)Astore->nzval)[i]; for (i = 0; i < nnz; ++i) Bstore->rowind[i] = Astore->rowind[i]; for (i = 0; i <= ncol; ++i) Bstore->colptr[i] = Astore->colptr[i]; } void dCreate_Dense_Matrix(SuperMatrix *X, int m, int n, double *x, int ldx, Stype_t stype, Dtype_t dtype, Mtype_t mtype) { DNformat *Xstore; X->Stype = stype; X->Dtype = dtype; X->Mtype = mtype; X->nrow = m; X->ncol = n; X->Store = (void *) SUPERLU_MALLOC( sizeof(DNformat) ); if ( !(X->Store) ) ABORT("SUPERLU_MALLOC fails for X->Store"); Xstore = (DNformat *) X->Store; Xstore->lda = ldx; Xstore->nzval = (double *) x; } void dCopy_Dense_Matrix(int M, int N, double *X, int ldx, double *Y, int ldy) { /* * * Purpose * ======= * * Copies a two-dimensional matrix X to another matrix Y. */ int i, j; for (j = 0; j < N; ++j) for (i = 0; i < M; ++i) Y[i + j*ldy] = X[i + j*ldx]; } void dCreate_SuperNode_Matrix(SuperMatrix *L, int m, int n, int nnz, double *nzval, int *nzval_colptr, int *rowind, int *rowind_colptr, int *col_to_sup, int *sup_to_col, Stype_t stype, Dtype_t dtype, Mtype_t mtype) { SCformat *Lstore; L->Stype = stype; L->Dtype = dtype; L->Mtype = mtype; L->nrow = m; L->ncol = n; L->Store = (void *) SUPERLU_MALLOC( sizeof(SCformat) ); if ( !(L->Store) ) ABORT("SUPERLU_MALLOC fails for L->Store"); Lstore = L->Store; Lstore->nnz = nnz; Lstore->nsuper = col_to_sup[n]; Lstore->nzval = nzval; Lstore->nzval_colptr = nzval_colptr; Lstore->rowind = rowind; Lstore->rowind_colptr = rowind_colptr; Lstore->col_to_sup = col_to_sup; Lstore->sup_to_col = sup_to_col; } /* * Convert a row compressed storage into a column compressed storage. */ void dCompRow_to_CompCol(int m, int n, int nnz, double *a, int *colind, int *rowptr, double **at, int **rowind, int **colptr) { register int i, j, col, relpos; int *marker; /* Allocate storage for another copy of the matrix. */ *at = (double *) doubleMalloc(nnz); *rowind = (int *) intMalloc(nnz); *colptr = (int *) intMalloc(n+1); marker = (int *) intCalloc(n); /* Get counts of each column of A, and set up column pointers */ for (i = 0; i < m; ++i) for (j = rowptr[i]; j < rowptr[i+1]; ++j) ++marker[colind[j]]; (*colptr)[0] = 0; for (j = 0; j < n; ++j) { (*colptr)[j+1] = (*colptr)[j] + marker[j]; marker[j] = (*colptr)[j]; } /* Transfer the matrix into the compressed column storage. */ for (i = 0; i < m; ++i) { for (j = rowptr[i]; j < rowptr[i+1]; ++j) { col = colind[j]; relpos = marker[col]; (*rowind)[relpos] = i; (*at)[relpos] = a[j]; ++marker[col]; } } SUPERLU_FREE(marker); } void dPrint_CompCol_Matrix(char *what, SuperMatrix *A) { NCformat *Astore; register int i,n; double *dp; printf("\nCompCol matrix %s:\n", what); printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); n = A->ncol; Astore = (NCformat *) A->Store; dp = (double *) Astore->nzval; printf("nrow %d, ncol %d, nnz %d\n", A->nrow,A->ncol,Astore->nnz); printf("nzval: "); for (i = 0; i < Astore->colptr[n]; ++i) printf("%f ", dp[i]); printf("\nrowind: "); for (i = 0; i < Astore->colptr[n]; ++i) printf("%d ", Astore->rowind[i]); printf("\ncolptr: "); for (i = 0; i <= n; ++i) printf("%d ", Astore->colptr[i]); printf("\n"); fflush(stdout); } void dPrint_SuperNode_Matrix(char *what, SuperMatrix *A) { SCformat *Astore; register int i, j, k, c, d, n, nsup; double *dp; int *col_to_sup, *sup_to_col, *rowind, *rowind_colptr; printf("\nSuperNode matrix %s:\n", what); printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); n = A->ncol; Astore = (SCformat *) A->Store; dp = (double *) Astore->nzval; col_to_sup = Astore->col_to_sup; sup_to_col = Astore->sup_to_col; rowind_colptr = Astore->rowind_colptr; rowind = Astore->rowind; printf("nrow %d, ncol %d, nnz %d, nsuper %d\n", A->nrow,A->ncol,Astore->nnz,Astore->nsuper); printf("nzval:\n"); for (k = 0; k <= Astore->nsuper+1; ++k) { c = sup_to_col[k]; nsup = sup_to_col[k+1] - c; for (j = c; j < c + nsup; ++j) { d = Astore->nzval_colptr[j]; for (i = rowind_colptr[c]; i < rowind_colptr[c+1]; ++i) { printf("%d\t%d\t%e\n", rowind[i], j, dp[d++]); } } } #if 0 for (i = 0; i < Astore->nzval_colptr[n]; ++i) printf("%f ", dp[i]); #endif printf("\nnzval_colptr: "); for (i = 0; i <= n; ++i) printf("%d ", Astore->nzval_colptr[i]); printf("\nrowind: "); for (i = 0; i < Astore->rowind_colptr[n]; ++i) printf("%d ", Astore->rowind[i]); printf("\nrowind_colptr: "); for (i = 0; i <= n; ++i) printf("%d ", Astore->rowind_colptr[i]); printf("\ncol_to_sup: "); for (i = 0; i < n; ++i) printf("%d ", col_to_sup[i]); printf("\nsup_to_col: "); for (i = 0; i <= Astore->nsuper+1; ++i) printf("%d ", sup_to_col[i]); printf("\n"); fflush(stdout); } void dPrint_Dense_Matrix(char *what, SuperMatrix *A) { DNformat *Astore; register int i; double *dp; printf("\nDense matrix %s:\n", what); printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype); Astore = (DNformat *) A->Store; dp = (double *) Astore->nzval; printf("nrow %d, ncol %d, lda %d\n", A->nrow,A->ncol,Astore->lda); printf("\nnzval: "); for (i = 0; i < A->nrow; ++i) printf("%f ", dp[i]); printf("\n"); fflush(stdout); } /* * Diagnostic print of column "jcol" in the U/L factor. */ void dprint_lu_col(char *msg, int jcol, int pivrow, int *xprune, GlobalLU_t *Glu) { int i, k, fsupc; int *xsup, *supno; int *xlsub, *lsub; double *lusup; int *xlusup; double *ucol; int *usub, *xusub; xsup = Glu->xsup; supno = Glu->supno; lsub = Glu->lsub; xlsub = Glu->xlsub; lusup = Glu->lusup; xlusup = Glu->xlusup; ucol = Glu->ucol; usub = Glu->usub; xusub = Glu->xusub; printf("%s", msg); printf("col %d: pivrow %d, supno %d, xprune %d\n", jcol, pivrow, supno[jcol], xprune[jcol]); printf("\tU-col:\n"); for (i = xusub[jcol]; i < xusub[jcol+1]; i++) printf("\t%d%10.4f\n", usub[i], ucol[i]); printf("\tL-col in rectangular snode:\n"); fsupc = xsup[supno[jcol]]; /* first col of the snode */ i = xlsub[fsupc]; k = xlusup[jcol]; while ( i < xlsub[fsupc+1] && k < xlusup[jcol+1] ) { printf("\t%d\t%10.4f\n", lsub[i], lusup[k]); i++; k++; } fflush(stdout); } /* * Check whether tempv[] == 0. This should be true before and after * calling any numeric routines, i.e., "panel_bmod" and "column_bmod". */ void dcheck_tempv(int n, double *tempv) { int i; for (i = 0; i < n; i++) { if (tempv[i] != 0.0) { fprintf(stderr,"tempv[%d] = %f\n", i,tempv[i]); ABORT("dcheck_tempv"); } } } void dGenXtrue(int n, int nrhs, double *x, int ldx) { int i, j; for (j = 0; j < nrhs; ++j) for (i = 0; i < n; ++i) { x[i + j*ldx] = 1.0;/* + (double)(i+1.)/n;*/ } } /* * Let rhs[i] = sum of i-th row of A, so the solution vector is all 1's */ void dFillRHS(char *trans, int nrhs, double *x, int ldx, SuperMatrix *A, SuperMatrix *B) { NCformat *Astore; double *Aval; DNformat *Bstore; double *rhs; double one = 1.0; double zero = 0.0; int ldc; Astore = A->Store; Aval = (double *) Astore->nzval; Bstore = B->Store; rhs = Bstore->nzval; ldc = Bstore->lda; sp_dgemm(trans, "N", A->nrow, nrhs, A->ncol, one, A, x, ldx, zero, rhs, ldc); } /* * Fills a double precision array with a given value. */ void dfill(double *a, int alen, double dval) { register int i; for (i = 0; i < alen; i++) a[i] = dval; } /* * Check the inf-norm of the error vector */ void dinf_norm_error(int nrhs, SuperMatrix *X, double *xtrue) { DNformat *Xstore; double err, xnorm; double *Xmat, *soln_work; int i, j; Xstore = X->Store; Xmat = Xstore->nzval; for (j = 0; j < nrhs; j++) { soln_work = &Xmat[j*Xstore->lda]; err = xnorm = 0.0; for (i = 0; i < X->nrow; i++) { err = SUPERLU_MAX(err, fabs(soln_work[i] - xtrue[i])); xnorm = SUPERLU_MAX(xnorm, fabs(soln_work[i])); } err = err / xnorm; printf("||X - Xtrue||/||X|| = %e\n", err); } } /* Print performance of the code. */ void dPrintPerf(SuperMatrix *L, SuperMatrix *U, mem_usage_t *mem_usage, double rpg, double rcond, double *ferr, double *berr, char *equed) { SCformat *Lstore; NCformat *Ustore; extern SuperLUStat_t SuperLUStat; double *utime; flops_t *ops; utime = SuperLUStat.utime; ops = SuperLUStat.ops; if ( utime[FACT] != 0. ) printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT], ops[FACT]*1e-6/utime[FACT]); printf("Identify relaxed snodes = %8.2f\n", utime[RELAX]); if ( utime[SOLVE] != 0. ) printf("Solve flops = %.0f, Mflops = %8.2f\n", ops[SOLVE], ops[SOLVE]*1e-6/utime[SOLVE]); Lstore = (SCformat *) L->Store; Ustore = (NCformat *) U->Store; printf("\tNo of nonzeros in factor L = %d\n", Lstore->nnz); printf("\tNo of nonzeros in factor U = %d\n", Ustore->nnz); printf("\tNo of nonzeros in L+U = %d\n", Lstore->nnz + Ustore->nnz); printf("L\\U MB %.3f\ttotal MB needed %.3f\texpansions %d\n", mem_usage->for_lu/1e6, mem_usage->total_needed/1e6, mem_usage->expansions); printf("\tFactor\tMflops\tSolve\tMflops\tEtree\tEquil\tRcond\tRefine\n"); printf("PERF:%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f%8.2f\n", utime[FACT], ops[FACT]*1e-6/utime[FACT], utime[SOLVE], ops[SOLVE]*1e-6/utime[SOLVE], utime[ETREE], utime[EQUIL], utime[RCOND], utime[REFINE]); printf("\tRpg\t\tRcond\t\tFerr\t\tBerr\t\tEquil?\n"); printf("NUM:\t%e\t%e\t%e\t%e\t%s\n", rpg, rcond, ferr[0], berr[0], equed); } print_double_vec(char *what, int n, double *vec) { int i; printf("%s: n %d\n", what, n); for (i = 0; i < n; ++i) printf("%d\t%f\n", i, vec[i]); return 0; } pysparse-1.1.1/superlu/dzsum1.c0000644010116400000240000000332211402270211015430 0ustar wd15dialout#include "dcomplex.h" double dzsum1_(int *n, doublecomplex *cx, int *incx) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University October 31, 1992 Purpose ======= DZSUM1 takes the sum of the absolute values of a complex vector and returns a double precision result. Based on DZASUM from the Level 1 BLAS. The change is to use the 'genuine' absolute value. Contributed by Nick Higham for use with ZLACON. Arguments ========= N (input) INT The number of elements in the vector CX. CX (input) COMPLEX*16 array, dimension (N) The vector whose elements will be summed. INCX (input) INT The spacing between successive values of CX. INCX > 0. ===================================================================== */ /* Builtin functions */ double z_abs(doublecomplex *); /* Local variables */ int i, nincx; double stemp; #define CX(I) cx[(I)-1] stemp = 0.; if (*n <= 0) { return stemp; } if (*incx == 1) { goto L20; } /* CODE FOR INCREMENT NOT EQUAL TO 1 */ nincx = *n * *incx; for (i = 1; *incx < 0 ? i >= nincx : i <= nincx; i += *incx) { /* NEXT LINE MODIFIED. */ stemp += z_abs(&CX(i)); /* L10: */ } return stemp; /* CODE FOR INCREMENT EQUAL TO 1 */ L20: for (i = 1; i <= *n; ++i) { /* NEXT LINE MODIFIED. */ stemp += z_abs(&CX(i)); /* L30: */ } return stemp; /* End of DZSUM1 */ } /* dzsum1_ */ pysparse-1.1.1/superlu/get_perm_c.c0000644010116400000240000003300111402270232016311 0ustar wd15dialout/* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include "supermatrix.h" #include "util.h" #include "colamd.h" extern int genmmd_(int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *); void get_colamd( const int m, /* number of rows in matrix A. */ const int n, /* number of columns in matrix A. */ const int nnz,/* number of nonzeros in matrix A. */ int *colptr, /* column pointer of size n+1 for matrix A. */ int *rowind, /* row indices of size nz for matrix A. */ int *perm_c /* out - the column permutation vector. */ ) { int Alen, *A, i, info, *p; double *knobs; Alen = colamd_recommended(nnz, m, n); if ( !(knobs = (double *) SUPERLU_MALLOC(COLAMD_KNOBS * sizeof(double))) ) ABORT("Malloc fails for knobs"); colamd_set_defaults(knobs); if (!(A = (int *) SUPERLU_MALLOC(Alen * sizeof(int))) ) ABORT("Malloc fails for A[]"); if (!(p = (int *) SUPERLU_MALLOC((n+1) * sizeof(int))) ) ABORT("Malloc fails for p[]"); for (i = 0; i <= n; ++i) p[i] = colptr[i]; for (i = 0; i < nnz; ++i) A[i] = rowind[i]; info = colamd(m, n, Alen, A, p, knobs); if ( info == FALSE ) ABORT("COLAMD failed"); for (i = 0; i < n; ++i) perm_c[p[i]] = i; SUPERLU_FREE(knobs); SUPERLU_FREE(A); SUPERLU_FREE(p); } void getata( const int m, /* number of rows in matrix A. */ const int n, /* number of columns in matrix A. */ const int nz, /* number of nonzeros in matrix A */ int *colptr, /* column pointer of size n+1 for matrix A. */ int *rowind, /* row indices of size nz for matrix A. */ int *atanz, /* out - on exit, returns the actual number of nonzeros in matrix A'*A. */ int **ata_colptr, /* out - size n+1 */ int **ata_rowind /* out - size *atanz */ ) /* * Purpose * ======= * * Form the structure of A'*A. A is an m-by-n matrix in column oriented * format represented by (colptr, rowind). The output A'*A is in column * oriented format (symmetrically, also row oriented), represented by * (ata_colptr, ata_rowind). * * This routine is modified from GETATA routine by Tim Davis. * The complexity of this algorithm is: SUM_{i=1,m} r(i)^2, * i.e., the sum of the square of the row counts. * * Questions * ========= * o Do I need to withhold the *dense* rows? * o How do I know the number of nonzeros in A'*A? * */ { register int i, j, k, col, num_nz, ti, trow; int *marker, *b_colptr, *b_rowind; int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ if ( !(marker = (int*) SUPERLU_MALLOC((SUPERLU_MAX(m,n)+1)*sizeof(int))) ) ABORT("SUPERLU_MALLOC fails for marker[]"); if ( !(t_colptr = (int*) SUPERLU_MALLOC((m+1) * sizeof(int))) ) ABORT("SUPERLU_MALLOC t_colptr[]"); if ( !(t_rowind = (int*) SUPERLU_MALLOC(nz * sizeof(int))) ) ABORT("SUPERLU_MALLOC fails for t_rowind[]"); /* Get counts of each column of T, and set up column pointers */ for (i = 0; i < m; ++i) marker[i] = 0; for (j = 0; j < n; ++j) { for (i = colptr[j]; i < colptr[j+1]; ++i) ++marker[rowind[i]]; } t_colptr[0] = 0; for (i = 0; i < m; ++i) { t_colptr[i+1] = t_colptr[i] + marker[i]; marker[i] = t_colptr[i]; } /* Transpose the matrix from A to T */ for (j = 0; j < n; ++j) for (i = colptr[j]; i < colptr[j+1]; ++i) { col = rowind[i]; t_rowind[marker[col]] = j; ++marker[col]; } /* ---------------------------------------------------------------- compute B = T * A, where column j of B is: Struct (B_*j) = UNION ( Struct (T_*k) ) A_kj != 0 do not include the diagonal entry ( Partition A as: A = (A_*1, ..., A_*n) Then B = T * A = (T * A_*1, ..., T * A_*n), where T * A_*j = (T_*1, ..., T_*m) * A_*j. ) ---------------------------------------------------------------- */ /* Zero the diagonal flag */ for (i = 0; i < n; ++i) marker[i] = -1; /* First pass determines number of nonzeros in B */ num_nz = 0; for (j = 0; j < n; ++j) { /* Flag the diagonal so it's not included in the B matrix */ marker[j] = j; for (i = colptr[j]; i < colptr[j+1]; ++i) { /* A_kj is nonzero, add pattern of column T_*k to B_*j */ k = rowind[i]; for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { trow = t_rowind[ti]; if ( marker[trow] != j ) { marker[trow] = j; num_nz++; } } } } *atanz = num_nz; /* Allocate storage for A'*A */ if ( !(*ata_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) ABORT("SUPERLU_MALLOC fails for ata_colptr[]"); if ( *atanz ) { if ( !(*ata_rowind = (int*) SUPERLU_MALLOC( *atanz * sizeof(int)) ) ) ABORT("SUPERLU_MALLOC fails for ata_rowind[]"); } b_colptr = *ata_colptr; /* aliasing */ b_rowind = *ata_rowind; /* Zero the diagonal flag */ for (i = 0; i < n; ++i) marker[i] = -1; /* Compute each column of B, one at a time */ num_nz = 0; for (j = 0; j < n; ++j) { b_colptr[j] = num_nz; /* Flag the diagonal so it's not included in the B matrix */ marker[j] = j; for (i = colptr[j]; i < colptr[j+1]; ++i) { /* A_kj is nonzero, add pattern of column T_*k to B_*j */ k = rowind[i]; for (ti = t_colptr[k]; ti < t_colptr[k+1]; ++ti) { trow = t_rowind[ti]; if ( marker[trow] != j ) { marker[trow] = j; b_rowind[num_nz++] = trow; } } } } b_colptr[n] = num_nz; SUPERLU_FREE(marker); SUPERLU_FREE(t_colptr); SUPERLU_FREE(t_rowind); } void a_plus_at( const int n, /* number of columns in matrix A. */ const int nz, /* number of nonzeros in matrix A */ int *colptr, /* column pointer of size n+1 for matrix A. */ int *rowind, /* row indices of size nz for matrix A. */ int *bnz, /* out - on exit, returns the actual number of nonzeros in matrix A'*A. */ int **b_colptr, /* out - size n+1 */ int **b_rowind /* out - size *bnz */ ) { /* * Purpose * ======= * * Form the structure of A'+A. A is an n-by-n matrix in column oriented * format represented by (colptr, rowind). The output A'+A is in column * oriented format (symmetrically, also row oriented), represented by * (b_colptr, b_rowind). * */ register int i, j, k, col, num_nz; int *t_colptr, *t_rowind; /* a column oriented form of T = A' */ int *marker; if ( !(marker = (int*) SUPERLU_MALLOC( n * sizeof(int)) ) ) ABORT("SUPERLU_MALLOC fails for marker[]"); if ( !(t_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) ABORT("SUPERLU_MALLOC fails for t_colptr[]"); if ( !(t_rowind = (int*) SUPERLU_MALLOC( nz * sizeof(int)) ) ) ABORT("SUPERLU_MALLOC fails t_rowind[]"); /* Get counts of each column of T, and set up column pointers */ for (i = 0; i < n; ++i) marker[i] = 0; for (j = 0; j < n; ++j) { for (i = colptr[j]; i < colptr[j+1]; ++i) ++marker[rowind[i]]; } t_colptr[0] = 0; for (i = 0; i < n; ++i) { t_colptr[i+1] = t_colptr[i] + marker[i]; marker[i] = t_colptr[i]; } /* Transpose the matrix from A to T */ for (j = 0; j < n; ++j) for (i = colptr[j]; i < colptr[j+1]; ++i) { col = rowind[i]; t_rowind[marker[col]] = j; ++marker[col]; } /* ---------------------------------------------------------------- compute B = A + T, where column j of B is: Struct (B_*j) = Struct (A_*k) UNION Struct (T_*k) do not include the diagonal entry ---------------------------------------------------------------- */ /* Zero the diagonal flag */ for (i = 0; i < n; ++i) marker[i] = -1; /* First pass determines number of nonzeros in B */ num_nz = 0; for (j = 0; j < n; ++j) { /* Flag the diagonal so it's not included in the B matrix */ marker[j] = j; /* Add pattern of column A_*k to B_*j */ for (i = colptr[j]; i < colptr[j+1]; ++i) { k = rowind[i]; if ( marker[k] != j ) { marker[k] = j; ++num_nz; } } /* Add pattern of column T_*k to B_*j */ for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { k = t_rowind[i]; if ( marker[k] != j ) { marker[k] = j; ++num_nz; } } } *bnz = num_nz; /* Allocate storage for A+A' */ if ( !(*b_colptr = (int*) SUPERLU_MALLOC( (n+1) * sizeof(int)) ) ) ABORT("SUPERLU_MALLOC fails for b_colptr[]"); if ( *bnz) { if ( !(*b_rowind = (int*) SUPERLU_MALLOC( *bnz * sizeof(int)) ) ) ABORT("SUPERLU_MALLOC fails for b_rowind[]"); } /* Zero the diagonal flag */ for (i = 0; i < n; ++i) marker[i] = -1; /* Compute each column of B, one at a time */ num_nz = 0; for (j = 0; j < n; ++j) { (*b_colptr)[j] = num_nz; /* Flag the diagonal so it's not included in the B matrix */ marker[j] = j; /* Add pattern of column A_*k to B_*j */ for (i = colptr[j]; i < colptr[j+1]; ++i) { k = rowind[i]; if ( marker[k] != j ) { marker[k] = j; (*b_rowind)[num_nz++] = k; } } /* Add pattern of column T_*k to B_*j */ for (i = t_colptr[j]; i < t_colptr[j+1]; ++i) { k = t_rowind[i]; if ( marker[k] != j ) { marker[k] = j; (*b_rowind)[num_nz++] = k; } } } (*b_colptr)[n] = num_nz; SUPERLU_FREE(marker); SUPERLU_FREE(t_colptr); SUPERLU_FREE(t_rowind); } void get_perm_c(int ispec, SuperMatrix *A, int *perm_c) /* * Purpose * ======= * * GET_PERM_C obtains a permutation matrix Pc, by applying the multiple * minimum degree ordering code by Joseph Liu to matrix A'*A or A+A'. * or using approximate minimum degree column ordering by Davis et. al. * The LU factorization of A*Pc tends to have less fill than the LU * factorization of A. * * Arguments * ========= * * ispec (input) int * Specifies the type of column ordering to reduce fill: * = 1: minimum degree on the structure of A^T * A * = 2: minimum degree on the structure of A^T + A * = 3: approximate minimum degree for unsymmetric matrices * If ispec == 0, the natural ordering (i.e., Pc = I) is returned. * * A (input) SuperMatrix* * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number * of the linear equations is A->nrow. Currently, the type of A * can be: Stype = NC; Dtype = _D; Mtype = GE. In the future, * more general A can be handled. * * perm_c (output) int* * Column permutation vector of size A->ncol, which defines the * permutation matrix Pc; perm_c[i] = j means column i of A is * in position j in A*Pc. * */ { NCformat *Astore = A->Store; int m, n, bnz, *b_colptr, i; int delta, maxint, nofsub, *invp; int *b_rowind, *dhead, *qsize, *llist, *marker; double t, SuperLU_timer_(); m = A->nrow; n = A->ncol; t = SuperLU_timer_(); switch ( ispec ) { case 0: /* Natural ordering */ for (i = 0; i < n; ++i) perm_c[i] = i; /* printf("Use natural column ordering.\n"); */ return; case 1: /* Minimum degree ordering on A'*A */ getata(m, n, Astore->nnz, Astore->colptr, Astore->rowind, &bnz, &b_colptr, &b_rowind); /* printf("Use minimum degree ordering on A'*A.\n"); */ t = SuperLU_timer_() - t; /*printf("Form A'*A time = %8.3f\n", t);*/ break; case 2: /* Minimum degree ordering on A'+A */ if ( m != n ) ABORT("Matrix is not square"); a_plus_at(n, Astore->nnz, Astore->colptr, Astore->rowind, &bnz, &b_colptr, &b_rowind); /* printf("Use minimum degree ordering on A'+A.\n"); */ t = SuperLU_timer_() - t; /*printf("Form A'+A time = %8.3f\n", t);*/ break; case 3: /* Approximate minimum degree column ordering. */ get_colamd(m, n, Astore->nnz, Astore->colptr, Astore->rowind, perm_c); /* printf(".. Use approximate minimum degree column ordering.\n"); */ return; default: ABORT("Invalid ISPEC"); } if ( bnz != 0 ) { t = SuperLU_timer_(); /* Initialize and allocate storage for GENMMD. */ delta = 1; /* DELTA is a parameter to allow the choice of nodes whose degree <= min-degree + DELTA. */ maxint = 2147483647; /* 2**31 - 1 */ invp = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); if ( !invp ) ABORT("SUPERLU_MALLOC fails for invp."); dhead = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); if ( !dhead ) ABORT("SUPERLU_MALLOC fails for dhead."); qsize = (int *) SUPERLU_MALLOC((n+delta)*sizeof(int)); if ( !qsize ) ABORT("SUPERLU_MALLOC fails for qsize."); llist = (int *) SUPERLU_MALLOC(n*sizeof(int)); if ( !llist ) ABORT("SUPERLU_MALLOC fails for llist."); marker = (int *) SUPERLU_MALLOC(n*sizeof(int)); if ( !marker ) ABORT("SUPERLU_MALLOC fails for marker."); /* Transform adjacency list into 1-based indexing required by GENMMD.*/ for (i = 0; i <= n; ++i) ++b_colptr[i]; for (i = 0; i < bnz; ++i) ++b_rowind[i]; genmmd_(&n, b_colptr, b_rowind, perm_c, invp, &delta, dhead, qsize, llist, marker, &maxint, &nofsub); /* Transform perm_c into 0-based indexing. */ for (i = 0; i < n; ++i) --perm_c[i]; SUPERLU_FREE(b_colptr); SUPERLU_FREE(b_rowind); SUPERLU_FREE(invp); SUPERLU_FREE(dhead); SUPERLU_FREE(qsize); SUPERLU_FREE(llist); SUPERLU_FREE(marker); t = SuperLU_timer_() - t; /* printf("call GENMMD time = %8.3f\n", t);*/ } else { /* Empty adjacency structure */ for (i = 0; i < n; ++i) perm_c[i] = i; } } pysparse-1.1.1/superlu/icmax1.c0000644010116400000240000000442611402270227015404 0ustar wd15dialout/* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include #include "scomplex.h" int icmax1_(int *n, complex *cx, int *incx) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 Purpose ======= ICMAX1 finds the index of the element whose real part has maximum absolute value. Based on ICAMAX from Level 1 BLAS. The change is to use the 'genuine' absolute value. Contributed by Nick Higham for use with CLACON. Arguments ========= N (input) INT The number of elements in the vector CX. CX (input) COMPLEX array, dimension (N) The vector whose elements will be summed. INCX (input) INT The spacing between successive values of CX. INCX >= 1. ===================================================================== NEXT LINE IS THE ONLY MODIFICATION. Parameter adjustments Function Body */ /* System generated locals */ int ret_val, i__1, i__2; float r__1; /* Local variables */ static float smax; static int i, ix; #define CX(I) cx[(I)-1] ret_val = 0; if (*n < 1) { return ret_val; } ret_val = 1; if (*n == 1) { return ret_val; } if (*incx == 1) { goto L30; } /* CODE FOR INCREMENT NOT EQUAL TO 1 */ ix = 1; smax = (r__1 = CX(1).r, fabs(r__1)); ix += *incx; i__1 = *n; for (i = 2; i <= *n; ++i) { i__2 = ix; if ((r__1 = CX(ix).r, fabs(r__1)) <= smax) { goto L10; } ret_val = i; i__2 = ix; smax = (r__1 = CX(ix).r, fabs(r__1)); L10: ix += *incx; /* L20: */ } return ret_val; /* CODE FOR INCREMENT EQUAL TO 1 */ L30: smax = (r__1 = CX(1).r, fabs(r__1)); i__1 = *n; for (i = 2; i <= *n; ++i) { i__2 = i; if ((r__1 = CX(i).r, fabs(r__1)) <= smax) { goto L40; } ret_val = i; i__2 = i; smax = (r__1 = CX(i).r, fabs(r__1)); L40: ; } return ret_val; /* End of ICMAX1 */ } /* icmax1_ */ pysparse-1.1.1/superlu/izmax1.c0000644010116400000240000000422711402270250015426 0ustar wd15dialout/* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #include "dcomplex.h" int izmax1_(int *n, doublecomplex *cx, int *incx) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 Purpose ======= IZMAX1 finds the index of the element whose real part has maximum absolute value. Based on IZAMAX from Level 1 BLAS. The change is to use the 'genuine' absolute value. Contributed by Nick Higham for use with ZLACON. Arguments ========= N (input) INT The number of elements in the vector CX. CX (input) COMPLEX*16 array, dimension (N) The vector whose elements will be summed. INCX (input) INT The spacing between successive values of CX. INCX >= 1. ===================================================================== */ /* System generated locals */ int ret_val, i__1, i__2; double d__1; /* Local variables */ double smax; int i, ix; #define CX(I) cx[(I)-1] ret_val = 0; if (*n < 1) { return ret_val; } ret_val = 1; if (*n == 1) { return ret_val; } if (*incx == 1) { goto L30; } /* CODE FOR INCREMENT NOT EQUAL TO 1 */ ix = 1; smax = (d__1 = CX(1).r, abs(d__1)); ix += *incx; i__1 = *n; for (i = 2; i <= *n; ++i) { i__2 = ix; if ((d__1 = CX(ix).r, abs(d__1)) <= smax) { goto L10; } ret_val = i; i__2 = ix; smax = (d__1 = CX(ix).r, abs(d__1)); L10: ix += *incx; /* L20: */ } return ret_val; /* CODE FOR INCREMENT EQUAL TO 1 */ L30: smax = (d__1 = CX(1).r, abs(d__1)); i__1 = *n; for (i = 2; i <= *n; ++i) { i__2 = i; if ((d__1 = CX(i).r, abs(d__1)) <= smax) { goto L40; } ret_val = i; i__2 = i; smax = (d__1 = CX(i).r, abs(d__1)); L40: ; } return ret_val; /* End of IZMAX1 */ } /* izmax1_ */ pysparse-1.1.1/superlu/lsame.c0000644010116400000240000000421511402270247015321 0ustar wd15dialoutint lsame_(char *ca, char *cb) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 Purpose ======= LSAME returns .TRUE. if CA is the same letter as CB regardless of case. Arguments ========= CA (input) CHARACTER*1 CB (input) CHARACTER*1 CA and CB specify the single characters to be compared. ===================================================================== */ /* System generated locals */ int ret_val; /* Local variables */ int inta, intb, zcode; ret_val = *(unsigned char *)ca == *(unsigned char *)cb; if (ret_val) { return ret_val; } /* Now test for equivalence if both characters are alphabetic. */ zcode = 'Z'; /* Use 'Z' rather than 'A' so that ASCII can be detected on Prime machines, on which ICHAR returns a value with bit 8 set. ICHAR('A') on Prime machines returns 193 which is the same as ICHAR('A') on an EBCDIC machine. */ inta = *(unsigned char *)ca; intb = *(unsigned char *)cb; if (zcode == 90 || zcode == 122) { /* ASCII is assumed - ZCODE is the ASCII code of either lower or upper case 'Z'. */ if (inta >= 97 && inta <= 122) inta += -32; if (intb >= 97 && intb <= 122) intb += -32; } else if (zcode == 233 || zcode == 169) { /* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower or upper case 'Z'. */ if (inta >= 129 && inta <= 137 || inta >= 145 && inta <= 153 || inta >= 162 && inta <= 169) inta += 64; if (intb >= 129 && intb <= 137 || intb >= 145 && intb <= 153 || intb >= 162 && intb <= 169) intb += 64; } else if (zcode == 218 || zcode == 250) { /* ASCII is assumed, on Prime machines - ZCODE is the ASCII code plus 128 of either lower or upper case 'Z'. */ if (inta >= 225 && inta <= 250) inta += -32; if (intb >= 225 && intb <= 250) intb += -32; } ret_val = inta == intb; return ret_val; } /* lsame_ */ pysparse-1.1.1/superlu/memory.c0000644010116400000240000000475611402270234015536 0ustar wd15dialout/* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /** Precision-independent memory-related routines. (Shared by [sdcz]memory.c) **/ #include "util.h" /* * Set up pointers for integer working arrays. */ void SetIWork(int m, int n, int panel_size, int *iworkptr, int **segrep, int **parent, int **xplore, int **repfnz, int **panel_lsub, int **xprune, int **marker) { *segrep = iworkptr; *parent = iworkptr + m; *xplore = *parent + m; *repfnz = *xplore + m; *panel_lsub = *repfnz + panel_size * m; *xprune = *panel_lsub + panel_size * m; *marker = *xprune + n; ifill (*repfnz, m * panel_size, EMPTY); ifill (*panel_lsub, m * panel_size, EMPTY); } void copy_mem_int(int howmany, void *old, void *new) { register int i; int *iold = old; int *inew = new; for (i = 0; i < howmany; i++) inew[i] = iold[i]; } void user_bcopy(char *src, char *dest, int bytes) { char *s_ptr, *d_ptr; s_ptr = src + bytes - 1; d_ptr = dest + bytes - 1; for (; d_ptr >= dest; --s_ptr, --d_ptr ) *d_ptr = *s_ptr; } int *intMalloc(int n) { int *buf; buf = (int *) SUPERLU_MALLOC(n * sizeof(int)); if ( !buf ) { ABORT("SUPERLU_MALLOC fails for buf in intMalloc()"); } return (buf); } int *intCalloc(int n) { int *buf; register int i; buf = (int *) SUPERLU_MALLOC(n * sizeof(int)); if ( !buf ) { ABORT("SUPERLU_MALLOC fails for buf in intCalloc()"); } for (i = 0; i < n; ++i) buf[i] = 0; return (buf); } #if 0 check_expanders() { int p; printf("Check expanders:\n"); for (p = 0; p < NO_MEMTYPE; p++) { printf("type %d, size %d, mem %d\n", p, expanders[p].size, (int)expanders[p].mem); } return 0; } StackInfo() { printf("Stack: size %d, used %d, top1 %d, top2 %d\n", stack.size, stack.used, stack.top1, stack.top2); return 0; } PrintStack(char *msg, GlobalLU_t *Glu) { int i; int *xlsub, *lsub, *xusub, *usub; xlsub = Glu->xlsub; lsub = Glu->lsub; xusub = Glu->xusub; usub = Glu->usub; printf("%s\n", msg); /* printf("\nUCOL: "); for (i = 0; i < xusub[ndim]; ++i) printf("%f ", ucol[i]); printf("\nLSUB: "); for (i = 0; i < xlsub[ndim]; ++i) printf("%d ", lsub[i]); printf("\nUSUB: "); for (i = 0; i < xusub[ndim]; ++i) printf("%d ", usub[i]); printf("\n");*/ return 0; } #endif pysparse-1.1.1/superlu/mmd.c0000644010116400000240000007105111402270251014772 0ustar wd15dialout typedef int shortint; /* *************************************************************** */ /* *************************************************************** */ /* **** GENMMD ..... MULTIPLE MINIMUM EXTERNAL DEGREE **** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE IMPLEMENTS THE MINIMUM DEGREE */ /* ALGORITHM. IT MAKES USE OF THE IMPLICIT REPRESENTATION */ /* OF ELIMINATION GRAPHS BY QUOTIENT GRAPHS, AND THE */ /* NOTION OF INDISTINGUISHABLE NODES. IT ALSO IMPLEMENTS */ /* THE MODIFICATIONS BY MULTIPLE ELIMINATION AND MINIMUM */ /* EXTERNAL DEGREE. */ /* --------------------------------------------- */ /* CAUTION - THE ADJACENCY VECTOR ADJNCY WILL BE */ /* DESTROYED. */ /* --------------------------------------------- */ /* INPUT PARAMETERS - */ /* NEQNS - NUMBER OF EQUATIONS. */ /* (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. */ /* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ /* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) INTEGER */ /* (ANY SMALLER ESTIMATE WILL DO) FOR MARKING */ /* NODES. */ /* OUTPUT PARAMETERS - */ /* PERM - THE MINIMUM DEGREE ORDERING. */ /* INVP - THE INVERSE OF PERM. */ /* NOFSUB - AN UPPER BOUND ON THE NUMBER OF NONZERO */ /* SUBSCRIPTS FOR THE COMPRESSED STORAGE SCHEME. */ /* WORKING PARAMETERS - */ /* DHEAD - VECTOR FOR HEAD OF DEGREE LISTS. */ /* INVP - USED TEMPORARILY FOR DEGREE FORWARD LINK. */ /* PERM - USED TEMPORARILY FOR DEGREE BACKWARD LINK. */ /* QSIZE - VECTOR FOR SIZE OF SUPERNODES. */ /* LLIST - VECTOR FOR TEMPORARY LINKED LISTS. */ /* MARKER - A TEMPORARY MARKER VECTOR. */ /* PROGRAM SUBROUTINES - */ /* MMDELM, MMDINT, MMDNUM, MMDUPD. */ /* *************************************************************** */ /* Subroutine */ int genmmd_(int *neqns, int *xadj, shortint *adjncy, shortint *invp, shortint *perm, int *delta, shortint *dhead, shortint *qsize, shortint *llist, shortint *marker, int *maxint, int *nofsub) { /* System generated locals */ int i__1; /* Local variables */ static int mdeg, ehead, i, mdlmt, mdnode; extern /* Subroutine */ int mmdelm_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *), mmdupd_(int *, int *, int *, shortint *, int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *), mmdint_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *), mmdnum_(int *, shortint *, shortint *, shortint *); static int nextmd, tag, num; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --marker; --llist; --qsize; --dhead; --perm; --invp; --adjncy; --xadj; /* Function Body */ if (*neqns <= 0) { return 0; } /* ------------------------------------------------ */ /* INITIALIZATION FOR THE MINIMUM DEGREE ALGORITHM. */ /* ------------------------------------------------ */ *nofsub = 0; mmdint_(neqns, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & qsize[1], &llist[1], &marker[1]); /* ---------------------------------------------- */ /* NUM COUNTS THE NUMBER OF ORDERED NODES PLUS 1. */ /* ---------------------------------------------- */ num = 1; /* ----------------------------- */ /* ELIMINATE ALL ISOLATED NODES. */ /* ----------------------------- */ nextmd = dhead[1]; L100: if (nextmd <= 0) { goto L200; } mdnode = nextmd; nextmd = invp[mdnode]; marker[mdnode] = *maxint; invp[mdnode] = -num; ++num; goto L100; L200: /* ---------------------------------------- */ /* SEARCH FOR NODE OF THE MINIMUM DEGREE. */ /* MDEG IS THE CURRENT MINIMUM DEGREE; */ /* TAG IS USED TO FACILITATE MARKING NODES. */ /* ---------------------------------------- */ if (num > *neqns) { goto L1000; } tag = 1; dhead[1] = 0; mdeg = 2; L300: if (dhead[mdeg] > 0) { goto L400; } ++mdeg; goto L300; L400: /* ------------------------------------------------- */ /* USE VALUE OF DELTA TO SET UP MDLMT, WHICH GOVERNS */ /* WHEN A DEGREE UPDATE IS TO BE PERFORMED. */ /* ------------------------------------------------- */ mdlmt = mdeg + *delta; ehead = 0; L500: mdnode = dhead[mdeg]; if (mdnode > 0) { goto L600; } ++mdeg; if (mdeg > mdlmt) { goto L900; } goto L500; L600: /* ---------------------------------------- */ /* REMOVE MDNODE FROM THE DEGREE STRUCTURE. */ /* ---------------------------------------- */ nextmd = invp[mdnode]; dhead[mdeg] = nextmd; if (nextmd > 0) { perm[nextmd] = -mdeg; } invp[mdnode] = -num; *nofsub = *nofsub + mdeg + qsize[mdnode] - 2; if (num + qsize[mdnode] > *neqns) { goto L1000; } /* ---------------------------------------------- */ /* ELIMINATE MDNODE AND PERFORM QUOTIENT GRAPH */ /* TRANSFORMATION. RESET TAG VALUE IF NECESSARY. */ /* ---------------------------------------------- */ ++tag; if (tag < *maxint) { goto L800; } tag = 1; i__1 = *neqns; for (i = 1; i <= i__1; ++i) { if (marker[i] < *maxint) { marker[i] = 0; } /* L700: */ } L800: mmdelm_(&mdnode, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & qsize[1], &llist[1], &marker[1], maxint, &tag); num += qsize[mdnode]; llist[mdnode] = ehead; ehead = mdnode; if (*delta >= 0) { goto L500; } L900: /* ------------------------------------------- */ /* UPDATE DEGREES OF THE NODES INVOLVED IN THE */ /* MINIMUM DEGREE NODES ELIMINATION. */ /* ------------------------------------------- */ if (num > *neqns) { goto L1000; } mmdupd_(&ehead, neqns, &xadj[1], &adjncy[1], delta, &mdeg, &dhead[1], & invp[1], &perm[1], &qsize[1], &llist[1], &marker[1], maxint, &tag) ; goto L300; L1000: mmdnum_(neqns, &perm[1], &invp[1], &qsize[1]); return 0; } /* genmmd_ */ /* *************************************************************** */ /* *************************************************************** */ /* *** MMDINT ..... MULT MINIMUM DEGREE INITIALIZATION *** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE PERFORMS INITIALIZATION FOR THE */ /* MULTIPLE ELIMINATION VERSION OF THE MINIMUM DEGREE */ /* ALGORITHM. */ /* INPUT PARAMETERS - */ /* NEQNS - NUMBER OF EQUATIONS. */ /* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ /* OUTPUT PARAMETERS - */ /* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ /* QSIZE - SIZE OF SUPERNODE (INITIALIZED TO ONE). */ /* LLIST - LINKED LIST. */ /* MARKER - MARKER VECTOR. */ /* *************************************************************** */ /* Subroutine */ int mmdint_(int *neqns, int *xadj, shortint *adjncy, shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, shortint *marker) { /* System generated locals */ int i__1; /* Local variables */ static int ndeg, node, fnode; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --marker; --llist; --qsize; --dbakw; --dforw; --dhead; --adjncy; --xadj; /* Function Body */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { dhead[node] = 0; qsize[node] = 1; marker[node] = 0; llist[node] = 0; /* L100: */ } /* ------------------------------------------ */ /* INITIALIZE THE DEGREE DOUBLY LINKED LISTS. */ /* ------------------------------------------ */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { ndeg = xadj[node + 1] - xadj[node] + 1; fnode = dhead[ndeg]; dforw[node] = fnode; dhead[ndeg] = node; if (fnode > 0) { dbakw[fnode] = node; } dbakw[node] = -ndeg; /* L200: */ } return 0; } /* mmdint_ */ /* *************************************************************** */ /* *************************************************************** */ /* ** MMDELM ..... MULTIPLE MINIMUM DEGREE ELIMINATION *** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE ELIMINATES THE NODE MDNODE OF */ /* MINIMUM DEGREE FROM THE ADJACENCY STRUCTURE, WHICH */ /* IS STORED IN THE QUOTIENT GRAPH FORMAT. IT ALSO */ /* TRANSFORMS THE QUOTIENT GRAPH REPRESENTATION OF THE */ /* ELIMINATION GRAPH. */ /* INPUT PARAMETERS - */ /* MDNODE - NODE OF MINIMUM DEGREE. */ /* MAXINT - ESTIMATE OF MAXIMUM REPRESENTABLE (SHORT) */ /* INT. */ /* TAG - TAG VALUE. */ /* UPDATED PARAMETERS - */ /* (XADJ,ADJNCY) - UPDATED ADJACENCY STRUCTURE. */ /* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ /* QSIZE - SIZE OF SUPERNODE. */ /* MARKER - MARKER VECTOR. */ /* LLIST - TEMPORARY LINKED LIST OF ELIMINATED NABORS. */ /* *************************************************************** */ /* Subroutine */ int mmdelm_(int *mdnode, int *xadj, shortint *adjncy, shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, shortint *marker, int *maxint, int *tag) { /* System generated locals */ int i__1, i__2; /* Local variables */ static int node, link, rloc, rlmt, i, j, nabor, rnode, elmnt, xqnbr, istop, jstop, istrt, jstrt, nxnode, pvnode, nqnbrs, npv; /* *************************************************************** */ /* *************************************************************** */ /* ----------------------------------------------- */ /* FIND REACHABLE SET AND PLACE IN DATA STRUCTURE. */ /* ----------------------------------------------- */ /* Parameter adjustments */ --marker; --llist; --qsize; --dbakw; --dforw; --dhead; --adjncy; --xadj; /* Function Body */ marker[*mdnode] = *tag; istrt = xadj[*mdnode]; istop = xadj[*mdnode + 1] - 1; /* ------------------------------------------------------- */ /* ELMNT POINTS TO THE BEGINNING OF THE LIST OF ELIMINATED */ /* NABORS OF MDNODE, AND RLOC GIVES THE STORAGE LOCATION */ /* FOR THE NEXT REACHABLE NODE. */ /* ------------------------------------------------------- */ elmnt = 0; rloc = istrt; rlmt = istop; i__1 = istop; for (i = istrt; i <= i__1; ++i) { nabor = adjncy[i]; if (nabor == 0) { goto L300; } if (marker[nabor] >= *tag) { goto L200; } marker[nabor] = *tag; if (dforw[nabor] < 0) { goto L100; } adjncy[rloc] = nabor; ++rloc; goto L200; L100: llist[nabor] = elmnt; elmnt = nabor; L200: ; } L300: /* ----------------------------------------------------- */ /* MERGE WITH REACHABLE NODES FROM GENERALIZED ELEMENTS. */ /* ----------------------------------------------------- */ if (elmnt <= 0) { goto L1000; } adjncy[rlmt] = -elmnt; link = elmnt; L400: jstrt = xadj[link]; jstop = xadj[link + 1] - 1; i__1 = jstop; for (j = jstrt; j <= i__1; ++j) { node = adjncy[j]; link = -node; if (node < 0) { goto L400; } else if (node == 0) { goto L900; } else { goto L500; } L500: if (marker[node] >= *tag || dforw[node] < 0) { goto L800; } marker[node] = *tag; /* --------------------------------- */ /* USE STORAGE FROM ELIMINATED NODES */ /* IF NECESSARY. */ /* --------------------------------- */ L600: if (rloc < rlmt) { goto L700; } link = -adjncy[rlmt]; rloc = xadj[link]; rlmt = xadj[link + 1] - 1; goto L600; L700: adjncy[rloc] = node; ++rloc; L800: ; } L900: elmnt = llist[elmnt]; goto L300; L1000: if (rloc <= rlmt) { adjncy[rloc] = 0; } /* -------------------------------------------------------- */ /* FOR EACH NODE IN THE REACHABLE SET, DO THE FOLLOWING ... */ /* -------------------------------------------------------- */ link = *mdnode; L1100: istrt = xadj[link]; istop = xadj[link + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { rnode = adjncy[i]; link = -rnode; if (rnode < 0) { goto L1100; } else if (rnode == 0) { goto L1800; } else { goto L1200; } L1200: /* -------------------------------------------- */ /* IF RNODE IS IN THE DEGREE LIST STRUCTURE ... */ /* -------------------------------------------- */ pvnode = dbakw[rnode]; if (pvnode == 0 || pvnode == -(*maxint)) { goto L1300; } /* ------------------------------------- */ /* THEN REMOVE RNODE FROM THE STRUCTURE. */ /* ------------------------------------- */ nxnode = dforw[rnode]; if (nxnode > 0) { dbakw[nxnode] = pvnode; } if (pvnode > 0) { dforw[pvnode] = nxnode; } npv = -pvnode; if (pvnode < 0) { dhead[npv] = nxnode; } L1300: /* ---------------------------------------- */ /* PURGE INACTIVE QUOTIENT NABORS OF RNODE. */ /* ---------------------------------------- */ jstrt = xadj[rnode]; jstop = xadj[rnode + 1] - 1; xqnbr = jstrt; i__2 = jstop; for (j = jstrt; j <= i__2; ++j) { nabor = adjncy[j]; if (nabor == 0) { goto L1500; } if (marker[nabor] >= *tag) { goto L1400; } adjncy[xqnbr] = nabor; ++xqnbr; L1400: ; } L1500: /* ---------------------------------------- */ /* IF NO ACTIVE NABOR AFTER THE PURGING ... */ /* ---------------------------------------- */ nqnbrs = xqnbr - jstrt; if (nqnbrs > 0) { goto L1600; } /* ----------------------------- */ /* THEN MERGE RNODE WITH MDNODE. */ /* ----------------------------- */ qsize[*mdnode] += qsize[rnode]; qsize[rnode] = 0; marker[rnode] = *maxint; dforw[rnode] = -(*mdnode); dbakw[rnode] = -(*maxint); goto L1700; L1600: /* -------------------------------------- */ /* ELSE FLAG RNODE FOR DEGREE UPDATE, AND */ /* ADD MDNODE AS A NABOR OF RNODE. */ /* -------------------------------------- */ dforw[rnode] = nqnbrs + 1; dbakw[rnode] = 0; adjncy[xqnbr] = *mdnode; ++xqnbr; if (xqnbr <= jstop) { adjncy[xqnbr] = 0; } L1700: ; } L1800: return 0; } /* mmdelm_ */ /* *************************************************************** */ /* *************************************************************** */ /* ***** MMDUPD ..... MULTIPLE MINIMUM DEGREE UPDATE ***** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE UPDATES THE DEGREES OF NODES */ /* AFTER A MULTIPLE ELIMINATION STEP. */ /* INPUT PARAMETERS - */ /* EHEAD - THE BEGINNING OF THE LIST OF ELIMINATED */ /* NODES (I.E., NEWLY FORMED ELEMENTS). */ /* NEQNS - NUMBER OF EQUATIONS. */ /* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ /* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ /* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) */ /* INTEGER. */ /* UPDATED PARAMETERS - */ /* MDEG - NEW MINIMUM DEGREE AFTER DEGREE UPDATE. */ /* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ /* QSIZE - SIZE OF SUPERNODE. */ /* LLIST - WORKING LINKED LIST. */ /* MARKER - MARKER VECTOR FOR DEGREE UPDATE. */ /* TAG - TAG VALUE. */ /* *************************************************************** */ /* Subroutine */ int mmdupd_(int *ehead, int *neqns, int *xadj, shortint *adjncy, int *delta, int *mdeg, shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, shortint *marker, int *maxint, int *tag) { /* System generated locals */ int i__1, i__2; /* Local variables */ static int node, mtag, link, mdeg0, i, j, enode, fnode, nabor, elmnt, istop, jstop, q2head, istrt, jstrt, qxhead, iq2, deg, deg0; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --marker; --llist; --qsize; --dbakw; --dforw; --dhead; --adjncy; --xadj; /* Function Body */ mdeg0 = *mdeg + *delta; elmnt = *ehead; L100: /* ------------------------------------------------------- */ /* FOR EACH OF THE NEWLY FORMED ELEMENT, DO THE FOLLOWING. */ /* (RESET TAG VALUE IF NECESSARY.) */ /* ------------------------------------------------------- */ if (elmnt <= 0) { return 0; } mtag = *tag + mdeg0; if (mtag < *maxint) { goto L300; } *tag = 1; i__1 = *neqns; for (i = 1; i <= i__1; ++i) { if (marker[i] < *maxint) { marker[i] = 0; } /* L200: */ } mtag = *tag + mdeg0; L300: /* --------------------------------------------- */ /* CREATE TWO LINKED LISTS FROM NODES ASSOCIATED */ /* WITH ELMNT: ONE WITH TWO NABORS (Q2HEAD) IN */ /* ADJACENCY STRUCTURE, AND THE OTHER WITH MORE */ /* THAN TWO NABORS (QXHEAD). ALSO COMPUTE DEG0, */ /* NUMBER OF NODES IN THIS ELEMENT. */ /* --------------------------------------------- */ q2head = 0; qxhead = 0; deg0 = 0; link = elmnt; L400: istrt = xadj[link]; istop = xadj[link + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { enode = adjncy[i]; link = -enode; if (enode < 0) { goto L400; } else if (enode == 0) { goto L800; } else { goto L500; } L500: if (qsize[enode] == 0) { goto L700; } deg0 += qsize[enode]; marker[enode] = mtag; /* ---------------------------------- */ /* IF ENODE REQUIRES A DEGREE UPDATE, */ /* THEN DO THE FOLLOWING. */ /* ---------------------------------- */ if (dbakw[enode] != 0) { goto L700; } /* --------------------------------------- */ /* PLACE EITHER IN QXHEAD OR Q2HEAD LISTS. */ /* --------------------------------------- */ if (dforw[enode] == 2) { goto L600; } llist[enode] = qxhead; qxhead = enode; goto L700; L600: llist[enode] = q2head; q2head = enode; L700: ; } L800: /* -------------------------------------------- */ /* FOR EACH ENODE IN Q2 LIST, DO THE FOLLOWING. */ /* -------------------------------------------- */ enode = q2head; iq2 = 1; L900: if (enode <= 0) { goto L1500; } if (dbakw[enode] != 0) { goto L2200; } ++(*tag); deg = deg0; /* ------------------------------------------ */ /* IDENTIFY THE OTHER ADJACENT ELEMENT NABOR. */ /* ------------------------------------------ */ istrt = xadj[enode]; nabor = adjncy[istrt]; if (nabor == elmnt) { nabor = adjncy[istrt + 1]; } /* ------------------------------------------------ */ /* IF NABOR IS UNELIMINATED, INCREASE DEGREE COUNT. */ /* ------------------------------------------------ */ link = nabor; if (dforw[nabor] < 0) { goto L1000; } deg += qsize[nabor]; goto L2100; L1000: /* -------------------------------------------- */ /* OTHERWISE, FOR EACH NODE IN THE 2ND ELEMENT, */ /* DO THE FOLLOWING. */ /* -------------------------------------------- */ istrt = xadj[link]; istop = xadj[link + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { node = adjncy[i]; link = -node; if (node == enode) { goto L1400; } if (node < 0) { goto L1000; } else if (node == 0) { goto L2100; } else { goto L1100; } L1100: if (qsize[node] == 0) { goto L1400; } if (marker[node] >= *tag) { goto L1200; } /* ----------------------------------- -- */ /* CASE WHEN NODE IS NOT YET CONSIDERED . */ /* ----------------------------------- -- */ marker[node] = *tag; deg += qsize[node]; goto L1400; L1200: /* ---------------------------------------- */ /* CASE WHEN NODE IS INDISTINGUISHABLE FROM */ /* ENODE. MERGE THEM INTO A NEW SUPERNODE. */ /* ---------------------------------------- */ if (dbakw[node] != 0) { goto L1400; } if (dforw[node] != 2) { goto L1300; } qsize[enode] += qsize[node]; qsize[node] = 0; marker[node] = *maxint; dforw[node] = -enode; dbakw[node] = -(*maxint); goto L1400; L1300: /* -------------------------------------- */ /* CASE WHEN NODE IS OUTMATCHED BY ENODE. */ /* -------------------------------------- */ if (dbakw[node] == 0) { dbakw[node] = -(*maxint); } L1400: ; } goto L2100; L1500: /* ------------------------------------------------ */ /* FOR EACH ENODE IN THE QX LIST, DO THE FOLLOWING. */ /* ------------------------------------------------ */ enode = qxhead; iq2 = 0; L1600: if (enode <= 0) { goto L2300; } if (dbakw[enode] != 0) { goto L2200; } ++(*tag); deg = deg0; /* --------------------------------- */ /* FOR EACH UNMARKED NABOR OF ENODE, */ /* DO THE FOLLOWING. */ /* --------------------------------- */ istrt = xadj[enode]; istop = xadj[enode + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { nabor = adjncy[i]; if (nabor == 0) { goto L2100; } if (marker[nabor] >= *tag) { goto L2000; } marker[nabor] = *tag; link = nabor; /* ------------------------------ */ /* IF UNELIMINATED, INCLUDE IT IN */ /* DEG COUNT. */ /* ------------------------------ */ if (dforw[nabor] < 0) { goto L1700; } deg += qsize[nabor]; goto L2000; L1700: /* ------------------------------- */ /* IF ELIMINATED, INCLUDE UNMARKED */ /* NODES IN THIS ELEMENT INTO THE */ /* DEGREE COUNT. */ /* ------------------------------- */ jstrt = xadj[link]; jstop = xadj[link + 1] - 1; i__2 = jstop; for (j = jstrt; j <= i__2; ++j) { node = adjncy[j]; link = -node; if (node < 0) { goto L1700; } else if (node == 0) { goto L2000; } else { goto L1800; } L1800: if (marker[node] >= *tag) { goto L1900; } marker[node] = *tag; deg += qsize[node]; L1900: ; } L2000: ; } L2100: /* ------------------------------------------- */ /* UPDATE EXTERNAL DEGREE OF ENODE IN DEGREE */ /* STRUCTURE, AND MDEG (MIN DEG) IF NECESSARY. */ /* ------------------------------------------- */ deg = deg - qsize[enode] + 1; fnode = dhead[deg]; dforw[enode] = fnode; dbakw[enode] = -deg; if (fnode > 0) { dbakw[fnode] = enode; } dhead[deg] = enode; if (deg < *mdeg) { *mdeg = deg; } L2200: /* ---------------------------------- */ /* GET NEXT ENODE IN CURRENT ELEMENT. */ /* ---------------------------------- */ enode = llist[enode]; if (iq2 == 1) { goto L900; } goto L1600; L2300: /* ----------------------------- */ /* GET NEXT ELEMENT IN THE LIST. */ /* ----------------------------- */ *tag = mtag; elmnt = llist[elmnt]; goto L100; } /* mmdupd_ */ /* *************************************************************** */ /* *************************************************************** */ /* ***** MMDNUM ..... MULTI MINIMUM DEGREE NUMBERING ***** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE PERFORMS THE FINAL STEP IN */ /* PRODUCING THE PERMUTATION AND INVERSE PERMUTATION */ /* VECTORS IN THE MULTIPLE ELIMINATION VERSION OF THE */ /* MINIMUM DEGREE ORDERING ALGORITHM. */ /* INPUT PARAMETERS - */ /* NEQNS - NUMBER OF EQUATIONS. */ /* QSIZE - SIZE OF SUPERNODES AT ELIMINATION. */ /* UPDATED PARAMETERS - */ /* INVP - INVERSE PERMUTATION VECTOR. ON INPUT, */ /* IF QSIZE(NODE)=0, THEN NODE HAS BEEN MERGED */ /* INTO THE NODE -INVP(NODE); OTHERWISE, */ /* -INVP(NODE) IS ITS INVERSE LABELLING. */ /* OUTPUT PARAMETERS - */ /* PERM - THE PERMUTATION VECTOR. */ /* *************************************************************** */ /* Subroutine */ int mmdnum_(int *neqns, shortint *perm, shortint *invp, shortint *qsize) { /* System generated locals */ int i__1; /* Local variables */ static int node, root, nextf, father, nqsize, num; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --qsize; --invp; --perm; /* Function Body */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { nqsize = qsize[node]; if (nqsize <= 0) { perm[node] = invp[node]; } if (nqsize > 0) { perm[node] = -invp[node]; } /* L100: */ } /* ------------------------------------------------------ */ /* FOR EACH NODE WHICH HAS BEEN MERGED, DO THE FOLLOWING. */ /* ------------------------------------------------------ */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { if (perm[node] > 0) { goto L500; } /* ----------------------------------------- */ /* TRACE THE MERGED TREE UNTIL ONE WHICH HAS */ /* NOT BEEN MERGED, CALL IT ROOT. */ /* ----------------------------------------- */ father = node; L200: if (perm[father] > 0) { goto L300; } father = -perm[father]; goto L200; L300: /* ----------------------- */ /* NUMBER NODE AFTER ROOT. */ /* ----------------------- */ root = father; num = perm[root] + 1; invp[node] = -num; perm[root] = num; /* ------------------------ */ /* SHORTEN THE MERGED TREE. */ /* ------------------------ */ father = node; L400: nextf = -perm[father]; if (nextf <= 0) { goto L500; } perm[father] = -root; father = nextf; goto L400; L500: ; } /* ---------------------- */ /* READY TO COMPUTE PERM. */ /* ---------------------- */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { num = -invp[node]; invp[node] = num; perm[num] = node; /* L600: */ } return 0; } /* mmdnum_ */ pysparse-1.1.1/superlu/relax_snode.c0000644010116400000240000000425411402270214016520 0ustar wd15dialout/* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include "util.h" void relax_snode ( const int n, int *et, /* column elimination tree */ const int relax_columns, /* max no of columns allowed in a relaxed snode */ int *descendants, /* no of descendants of each node in the etree */ int *relax_end /* last column in a supernode */ ) { /* * Purpose * ======= * relax_snode() - Identify the initial relaxed supernodes, assuming that * the matrix has been reordered according to the postorder of the etree. * */ register int i, j, parent; register int snode_start; /* beginning of a snode */ ifill (relax_end, n, EMPTY); for (j = 0; j < n; j++) descendants[j] = 0; /* Compute the number of descendants of each node in the etree */ for (j = 0; j < n; j++) { parent = et[j]; if ( parent != n ) /* not the dummy root */ descendants[parent] += descendants[j] + 1; } /* Identify the relaxed supernodes by postorder traversal of the etree. */ for (j = 0; j < n; ) { parent = et[j]; snode_start = j; while ( parent != n && descendants[parent] < relax_columns ) { j = parent; parent = et[j]; } /* Found a supernode with j being the last column. */ relax_end[snode_start] = j; /* Last column is recorded */ j++; /* Search for a new leaf */ while ( descendants[j] != 0 && j < n ) j++; } /*printf("No of relaxed snodes: %d; relaxed columns: %d\n", nsuper, no_relaxed_col); */ } pysparse-1.1.1/superlu/scomplex.c0000644010116400000240000000356711402270246016062 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* * This file defines common arithmetic operations for complex type. */ #include #include "scomplex.h" #include "util.h" /* Complex Division c = a/b */ void c_div(complex *c, complex *a, complex *b) { float ratio, den; float abr, abi, cr, ci; if( (abr = b->r) < 0.) abr = - abr; if( (abi = b->i) < 0.) abi = - abi; if( abr <= abi ) { if (abi == 0) { ABORT("z_div.c: division by zero"); } ratio = b->r / b->i ; den = b->i * (1 + ratio*ratio); cr = (a->r*ratio + a->i) / den; ci = (a->i*ratio - a->r) / den; } else { ratio = b->i / b->r ; den = b->r * (1 + ratio*ratio); cr = (a->r + a->i*ratio) / den; ci = (a->i - a->r*ratio) / den; } c->r = cr; c->i = ci; } /* Returns sqrt(z.r^2 + z.i^2) */ double c_abs(complex *z) { float temp; float real = z->r; float imag = z->i; if (real < 0) real = -real; if (imag < 0) imag = -imag; if (imag > real) { temp = real; real = imag; imag = temp; } if ((real+imag) == real) return(real); temp = imag/real; temp = real*sqrt(1.0 + temp*temp); /*overflow!!*/ return (temp); } /* Approximates the abs */ /* Returns abs(z.r) + abs(z.i) */ double c_abs1(complex *z) { float real = z->r; float imag = z->i; if (real < 0) real = -real; if (imag < 0) imag = -imag; return (real + imag); } /* Return the exponentiation */ void c_exp(complex *r, complex *z) { float expx; expx = exp(z->r); r->r = expx * cos(z->i); r->i = expx * sin(z->i); } /* Return the complex conjugate */ void r_cnjg(complex *r, complex *z) { r->r = z->r; r->i = -z->i; } /* Return the imaginary part */ double r_imag(complex *z) { return (z->i); } pysparse-1.1.1/superlu/scomplex.h0000644010116400000240000000300011402270246016045 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #ifndef __SUPERLU_SCOMPLEX /* allow multiple inclusions */ #define __SUPERLU_SCOMPLEX /* * This header file is to be included in source files c*.c */ #ifndef SCOMPLEX_INCLUDE #define SCOMPLEX_INCLUDE typedef struct { float r, i; } complex; /* Macro definitions */ /* Complex Addition c = a + b */ #define c_add(c, a, b) { (c)->r = (a)->r + (b)->r; \ (c)->i = (a)->i + (b)->i; } /* Complex Subtraction c = a - b */ #define c_sub(c, a, b) { (c)->r = (a)->r - (b)->r; \ (c)->i = (a)->i - (b)->i; } /* Complex-Double Multiplication */ #define cs_mult(c, a, b) { (c)->r = (a)->r * (b); \ (c)->i = (a)->i * (b); } /* Complex-Complex Multiplication */ #define cc_mult(c, a, b) { \ float cr, ci; \ cr = (a)->r * (b)->r - (a)->i * (b)->i; \ ci = (a)->i * (b)->r + (a)->r * (b)->i; \ (c)->r = cr; \ (c)->i = ci; \ } /* Complex equality testing */ #define c_eq(a, b) ( (a)->r == (b)->r && (a)->i == (b)->i ) #ifdef __cplusplus extern "C" { #endif /* Prototypes for functions in scomplex.c */ void c_div(complex *, complex *, complex *); double c_abs(complex *); /* exact */ double c_abs1(complex *); /* approximate */ void c_exp(complex *, complex *); void r_cnjg(complex *, complex *); double r_imag(complex *); #ifdef __cplusplus } #endif #endif #endif /* __SUPERLU_SCOMPLEX */ pysparse-1.1.1/superlu/sp_coletree.c0000644010116400000240000001404711402270221016520 0ustar wd15dialout /* Elimination tree computation and layout routines */ #include #include #include "util.h" /* * Implementation of disjoint set union routines. * Elements are integers in 0..n-1, and the * names of the sets themselves are of type int. * * Calls are: * initialize_disjoint_sets (n) initial call. * s = make_set (i) returns a set containing only i. * s = link (t, u) returns s = t union u, destroying t and u. * s = find (i) return name of set containing i. * finalize_disjoint_sets final call. * * This implementation uses path compression but not weighted union. * See Tarjan's book for details. * John Gilbert, CMI, 1987. * * Implemented path-halving by XL 7/5/95. */ static int *pp; /* parent array for sets */ static int *mxCallocInt(int n) { register int i; int *buf; buf = (int *) SUPERLU_MALLOC( n * sizeof(int) ); if ( !buf ) { ABORT("SUPERLU_MALLOC fails for buf in mxCallocInt()"); } for (i = 0; i < n; i++) buf[i] = 0; return (buf); } static void initialize_disjoint_sets ( int n ) { pp = mxCallocInt(n); } static int make_set ( int i ) { pp[i] = i; return i; } static int link ( int s, int t ) { pp[s] = t; return t; } /* PATH HALVING */ static int find (int i) { register int p, gp; p = pp[i]; gp = pp[p]; while (gp != p) { pp[i] = gp; i = gp; p = pp[i]; gp = pp[p]; } return (p); } #if 0 /* PATH COMPRESSION */ static int find ( int i ) { if (pp[i] != i) pp[i] = find (pp[i]); return pp[i]; } #endif static void finalize_disjoint_sets ( void ) { SUPERLU_FREE(pp); } /* * Find the elimination tree for A'*A. * This uses something similar to Liu's algorithm. * It runs in time O(nz(A)*log n) and does not form A'*A. * * Input: * Sparse matrix A. Numeric values are ignored, so any * explicit zeros are treated as nonzero. * Output: * Integer array of parents representing the elimination * tree of the symbolic product A'*A. Each vertex is a * column of A, and nc means a root of the elimination forest. * * John R. Gilbert, Xerox, 10 Dec 1990 * Based on code by JRG dated 1987, 1988, and 1990. */ /* * Nonsymmetric elimination tree */ int sp_coletree( int *acolst, int *acolend, /* column start and end past 1 */ int *arow, /* row indices of A */ int nr, int nc, /* dimension of A */ int *parent /* parent in elim tree */ ) { int *root; /* root of subtee of etree */ int *firstcol; /* first nonzero col in each row*/ int rset, cset; int row, col; int rroot; int p; root = mxCallocInt (nc); initialize_disjoint_sets (nc); /* Compute firstcol[row] = first nonzero column in row */ firstcol = mxCallocInt (nr); for (row = 0; row < nr; firstcol[row++] = nc); for (col = 0; col < nc; col++) for (p = acolst[col]; p < acolend[col]; p++) { row = arow[p]; firstcol[row] = SUPERLU_MIN(firstcol[row], col); } /* Compute etree by Liu's algorithm for symmetric matrices, except use (firstcol[r],c) in place of an edge (r,c) of A. Thus each row clique in A'*A is replaced by a star centered at its first vertex, which has the same fill. */ for (col = 0; col < nc; col++) { cset = make_set (col); root[cset] = col; parent[col] = nc; /* Matlab */ for (p = acolst[col]; p < acolend[col]; p++) { row = firstcol[arow[p]]; if (row >= col) continue; rset = find (row); rroot = root[rset]; if (rroot != col) { parent[rroot] = col; cset = link (cset, rset); root[cset] = col; } } } SUPERLU_FREE (root); SUPERLU_FREE (firstcol); finalize_disjoint_sets (); return 0; } /* * q = TreePostorder (n, p); * * Postorder a tree. * Input: * p is a vector of parent pointers for a forest whose * vertices are the integers 0 to n-1; p[root]==n. * Output: * q is a vector indexed by 0..n-1 such that q[i] is the * i-th vertex in a postorder numbering of the tree. * * ( 2/7/95 modified by X.Li: * q is a vector indexed by 0:n-1 such that vertex i is the * q[i]-th vertex in a postorder numbering of the tree. * That is, this is the inverse of the previous q. ) * * In the child structure, lower-numbered children are represented * first, so that a tree which is already numbered in postorder * will not have its order changed. * * Written by John Gilbert, Xerox, 10 Dec 1990. * Based on code written by John Gilbert at CMI in 1987. */ static int *first_kid, *next_kid; /* Linked list of children. */ static int *post, postnum; #define ETDFS_GEUS #ifdef ETDFS_GEUS static int *parent_s; static /* * Depth-first search from vertex v. */ void etdfs_geus ( int v ) { int w, c; w = v; /* traverse non-branching portion of the tree */ while (c = first_kid[w], c != -1 && next_kid[c] == -1) { w = c; } /* call all branches */ for (; c != -1; c = next_kid[c]) { etdfs_geus(c); } /* output non-branching portion in reverse order */ while (w != v) { post[w] = postnum++; w = parent_s[w]; } post[w] = postnum++; } #else void etdfs ( int v ) { int w; for (w = first_kid[v]; w != -1; w = next_kid[w]) { etdfs (w); } /* post[postnum++] = v; in Matlab */ post[v] = postnum++; /* Modified by X.Li on 2/14/95 */ } #endif /* * Post order a tree */ int *TreePostorder( int n, int *parent ) { int v, dad; /* Allocate storage for working arrays and results */ first_kid = mxCallocInt (n+1); next_kid = mxCallocInt (n+1); post = mxCallocInt (n+1); /* Set up structure describing children */ for (v = 0; v <= n; first_kid[v++] = -1); for (v = n-1; v >= 0; v--) { dad = parent[v]; next_kid[v] = first_kid[dad]; first_kid[dad] = v; } /* Depth-first search from dummy root vertex #n */ postnum = 0; #ifdef ETDFS_GEUS parent_s = parent; etdfs_geus (n); #else etdfs (n); #endif SUPERLU_FREE (first_kid); SUPERLU_FREE (next_kid); return post; } pysparse-1.1.1/superlu/sp_ienv.c0000644010116400000240000000373411402270220015657 0ustar wd15dialout/* * File name: sp_ienv.c * History: Modified from lapack routine ILAENV */ int sp_ienv(int ispec) { /* Purpose ======= sp_ienv() is inquired to choose machine-dependent parameters for the local environment. See ISPEC for a description of the parameters. This version provides a set of parameters which should give good, but not optimal, performance on many of the currently available computers. Users are encouraged to modify this subroutine to set the tuning parameters for their particular machine using the option and problem size information in the arguments. Arguments ========= ISPEC (input) int Specifies the parameter to be returned as the value of SP_IENV. = 1: the panel size w; a panel consists of w consecutive columns of matrix A in the process of Gaussian elimination. The best value depends on machine's cache characters. = 2: the relaxation parameter relax; if the number of nodes (columns) in a subtree of the elimination tree is less than relax, this subtree is considered as one supernode, regardless of the their row structures. = 3: the maximum size for a supernode; = 4: the minimum row dimension for 2-D blocking to be used; = 5: the minimum column dimension for 2-D blocking to be used; = 6: the estimated fills factor for L and U, compared with A; (SP_IENV) (output) int >= 0: the value of the parameter specified by ISPEC < 0: if SP_IENV = -k, the k-th argument had an illegal value. ===================================================================== */ int i; switch (ispec) { case 1: return (10); case 2: return (5); case 3: return (100); case 4: return (200); case 5: return (40); case 6: return (20); } /* Invalid value for ISPEC */ i = 1; xerbla_("sp_ienv", &i); return 0; } /* sp_ienv_ */ pysparse-1.1.1/superlu/sp_preorder.c0000644010116400000240000001164511402270223016543 0ustar wd15dialout#include "supermatrix.h" #include "util.h" void sp_preorder(char *refact, SuperMatrix *A, int *perm_c, int *etree, SuperMatrix *AC) { /* * Purpose * ======= * * sp_preorder() permutes the columns of the original matrix. It performs * the following steps: * * 1. Apply column permutation perm_c[] to A's column pointers to form AC; * * 2. If refact = 'N', then * (1) Compute column elimination tree etree[] of AC'AC; * (2) Post order etree[] to get a postordered elimination tree etree[], * and a postorder permutation post[]; * (3) Apply post[] permutation to columns of AC; * (4) Overwrite perm_c[] with the product perm_c * post. * * Arguments * ========= * * refact (input) char * * Specifies whether or not the elimination tree will be re-used. * = 'N': first time factor A, etree is computed and output. * = 'Y': re-factor A, etree is input, unchanged on exit. * * A (input) SuperMatrix* * Matrix A in A*X=B, of dimension (A->nrow, A->ncol). The number * of the linear equations is A->nrow. Currently, the type of A can be: * Stype = NC or NCP; Dtype = _D; Mtype = GE. In the future, * more general A can be handled. * * perm_c (input/output) int* * Column permutation vector of size A->ncol, which defines the * permutation matrix Pc; perm_c[i] = j means column i of A is * in position j in A*Pc. * * etree (input/output) int* * Elimination tree of Pc'*A'*A*Pc, dimension A->ncol. * If fact is not 'F' and refact = 'Y', etree is an input argument, * otherwise it is an output argument. * Note: etree is a vector of parent pointers for a forest whose * vertices are the integers 0 to A->ncol-1; etree[root]==A->ncol. * * AC (output) SuperMatrix* * The resulting matrix after applied the column permutation * perm_c[] to matrix A. The type of AC can be: * Stype = NCP; Dtype = D; Mtype = GE. * */ NCformat *Astore; NCPformat *ACstore; int *iwork, *post; register int n, i; n = A->ncol; iwork = (int*) SUPERLU_MALLOC((n+1)*sizeof(int)); if ( !iwork ) ABORT("SUPERLU_MALLOC fails for iwork[]"); /* Apply column permutation perm_c to A's column pointers so to obtain NCP format in AC = A*Pc. */ AC->Stype = NCP; AC->Dtype = A->Dtype; AC->Mtype = A->Mtype; AC->nrow = A->nrow; AC->ncol = A->ncol; Astore = A->Store; ACstore = AC->Store = (void *) SUPERLU_MALLOC( sizeof(NCPformat) ); if ( !ACstore ) ABORT("SUPERLU_MALLOC fails for ACstore"); ACstore->nnz = Astore->nnz; ACstore->nzval = Astore->nzval; ACstore->rowind = Astore->rowind; ACstore->colbeg = (int*) SUPERLU_MALLOC(n*sizeof(int)); if ( !(ACstore->colbeg) ) ABORT("SUPERLU_MALLOC fails for ACstore->colbeg"); ACstore->colend = (int*) SUPERLU_MALLOC(n*sizeof(int)); if ( !(ACstore->colend) ) ABORT("SUPERLU_MALLOC fails for ACstore->colend"); #ifdef DEBUG print_int_vec("pre_order:", n, perm_c); check_perm("Initial perm_c", n, perm_c); #endif for (i = 0; i < n; i++) { ACstore->colbeg[perm_c[i]] = Astore->colptr[i]; ACstore->colend[perm_c[i]] = Astore->colptr[i+1]; } if ( lsame_(refact, "N") ) { /* Compute the column elimination tree */ sp_coletree(ACstore->colbeg, ACstore->colend, ACstore->rowind, A->nrow, A->ncol, etree); #ifdef DEBUG print_int_vec("etree:", n, etree); #endif /* Post order etree */ post = (int *) TreePostorder(n, etree); /* for (i = 0; i < n+1; ++i) inv_post[post[i]] = i; iwork = post; */ #ifdef DEBUG print_int_vec("post:", n+1, post); check_perm("post", n, post); #endif /* Renumber etree in postorder */ for (i = 0; i < n; ++i) iwork[post[i]] = post[etree[i]]; for (i = 0; i < n; ++i) etree[i] = iwork[i]; #ifdef DEBUG print_int_vec("postorder etree:", n, etree); #endif /* Postmultiply A*Pc by post[] */ for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colbeg[i]; for (i = 0; i < n; ++i) ACstore->colbeg[i] = iwork[i]; for (i = 0; i < n; ++i) iwork[post[i]] = ACstore->colend[i]; for (i = 0; i < n; ++i) ACstore->colend[i] = iwork[i]; for (i = 0; i < n; ++i) iwork[i] = post[perm_c[i]]; /* product of perm_c and post */ for (i = 0; i < n; ++i) perm_c[i] = iwork[i]; #ifdef DEBUG print_int_vec("Pc*post:", n, perm_c); check_perm("final perm_c", n, perm_c); #endif SUPERLU_FREE (post); } /* if refact = 'N' */ SUPERLU_FREE (iwork); } check_perm(char *what, int n, int *perm) { register int i; int *marker; marker = (int *) calloc(n, sizeof(int)); for (i = 0; i < n; ++i) { if ( marker[perm[i]] == 1 || perm[i] >= n ) { printf("%s: Not a valid PERM[%d] = %d\n", what, i, perm[i]); ABORT("check_perm"); } else { marker[perm[i]] = 1; } } SUPERLU_FREE(marker); return 0; } pysparse-1.1.1/superlu/ssp_defs.h0000644010116400000240000002253411402270214016031 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #ifndef __SUPERLU_sSP_DEFS /* allow multiple inclusions */ #define __SUPERLU_sSP_DEFS /* * File name: ssp_defs.h * Purpose: Sparse matrix types and function prototypes * History: */ #ifdef _CRAY #include #include #endif #include "Cnames.h" #include "supermatrix.h" /* No of marker arrays used in the symbolic factorization, each of size n */ #define NO_MARKER 3 #define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) ) typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; typedef enum {HEAD, TAIL} stack_end_t; typedef enum {SYSTEM, USER} LU_space_t; /* * Global data structures used in LU factorization - * * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. * (xsup,supno): supno[i] is the supernode no to which i belongs; * xsup(s) points to the beginning of the s-th supernode. * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) * xsup 0 1 2 4 7 12 * Note: dfs will be performed on supernode rep. relative to the new * row pivoting ordering * * (xlsub,lsub): lsub[*] contains the compressed subscript of * rectangular supernodes; xlsub[j] points to the starting * location of the j-th column in lsub[*]. Note that xlsub * is indexed by column. * Storage: original row subscripts * * During the course of sparse LU factorization, we also use * (xlsub,lsub) for the purpose of symmetric pruning. For each * supernode {s,s+1,...,t=s+r} with first column s and last * column t, the subscript set * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 * is the structure of column s (i.e. structure of this supernode). * It is used for the storage of numerical values. * Furthermore, * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 * is the structure of the last column t of this supernode. * It is for the purpose of symmetric pruning. Therefore, the * structural subscripts can be rearranged without making physical * interchanges among the numerical values. * * However, if the supernode has only one column, then we * only keep one set of subscripts. For any subscript interchange * performed, similar interchange must be done on the numerical * values. * * The last column structures (for pruning) will be removed * after the numercial LU factorization phase. * * (xlusup,lusup): lusup[*] contains the numerical values of the * rectangular supernodes; xlusup[j] points to the starting * location of the j-th column in storage vector lusup[*] * Note: xlusup is indexed by column. * Each rectangular supernode is stored by column-major * scheme, consistent with Fortran 2-dim array storage. * * (xusub,ucol,usub): ucol[*] stores the numerical values of * U-columns outside the rectangular supernodes. The row * subscript of nonzero ucol[k] is stored in usub[k]. * xusub[i] points to the starting location of column i in ucol. * Storage: new row subscripts; that is subscripts of PA. */ typedef struct { int *xsup; /* supernode and column mapping */ int *supno; int *lsub; /* compressed L subscripts */ int *xlsub; float *lusup; /* L supernodes */ int *xlusup; float *ucol; /* U columns */ int *usub; int *xusub; int nzlmax; /* current max size of lsub */ int nzumax; /* " " " ucol */ int nzlumax; /* " " " lusup */ int n; /* number of columns in the matrix */ LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ } GlobalLU_t; typedef struct { int panel_size; int relax; float diag_pivot_thresh; float drop_tol; } factor_param_t; typedef struct { float for_lu; float total_needed; int expansions; } mem_usage_t; #ifdef __cplusplus extern "C" { #endif /* Driver routines */ extern void sgssv(SuperMatrix *, int *, int *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *); extern void sgssvx(char *, char *, char *, SuperMatrix *, factor_param_t *, int *, int *, int *, char *, float *, float *, SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, float *, float *, float *, float *, mem_usage_t *, int *); /* Supernodal LU factor related */ extern void sCreate_CompCol_Matrix(SuperMatrix *, int, int, int, float *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void sCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); extern void sCreate_Dense_Matrix(SuperMatrix *, int, int, float *, int, Stype_t, Dtype_t, Mtype_t); extern void sCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, float *, int *, int *, int *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void sCopy_Dense_Matrix(int, int, float *, int, float *, int); extern void Destroy_SuperMatrix_Store(SuperMatrix *); extern void Destroy_CompCol_Matrix(SuperMatrix *); extern void Destroy_SuperNode_Matrix(SuperMatrix *); extern void Destroy_CompCol_Permuted(SuperMatrix *); extern void Destroy_Dense_Matrix(SuperMatrix *); extern void get_perm_c(int, SuperMatrix *, int *); extern void sp_preorder (char*, SuperMatrix*, int*, int*, SuperMatrix*); extern void countnz (const int, int *, int *, int *, GlobalLU_t *); extern void fixupL (const int, const int *, GlobalLU_t *); extern void sallocateA (int, int, float **, int **, int **); extern void sgstrf (char*, SuperMatrix*, float, float, int, int, int*, void *, int, int *, int *, SuperMatrix *, SuperMatrix *, int *); extern int ssnode_dfs (const int, const int, const int *, const int *, const int *, int *, int *, GlobalLU_t *); extern int ssnode_bmod (const int, const int, const int, float *, float *, GlobalLU_t *); extern void spanel_dfs (const int, const int, const int, SuperMatrix *, int *, int *, float *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern void spanel_bmod (const int, const int, const int, const int, float *, float *, int *, int *, GlobalLU_t *); extern int scolumn_dfs (const int, const int, int *, int *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern int scolumn_bmod (const int, const int, float *, float *, int *, int *, int, GlobalLU_t *); extern int scopy_to_ucol (int, int, int *, int *, int *, float *, GlobalLU_t *); extern int spivotL (const int, const float, int *, int *, int *, int *, int *, GlobalLU_t *); extern void spruneL (const int, const int *, const int, const int, const int *, const int *, int *, GlobalLU_t *); extern void sreadmt (int *, int *, int *, float **, int **, int **); extern void sGenXtrue (int, int, float *, int); extern void sFillRHS (char *, int, float *, int, SuperMatrix *, SuperMatrix *); extern void sgstrs (char *, SuperMatrix *, SuperMatrix *, int *, int *, SuperMatrix *, int *); /* Driver related */ extern void sgsequ (SuperMatrix *, float *, float *, float *, float *, float *, int *); extern void slaqgs (SuperMatrix *, float *, float *, float, float, float, char *); extern void sgscon (char *, SuperMatrix *, SuperMatrix *, float, float *, int *); extern float sPivotGrowth(int, SuperMatrix *, int *, SuperMatrix *, SuperMatrix *); extern void sgsrfs (char *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *, int *, char *, float *, float *, SuperMatrix *, SuperMatrix *, float *, float *, int *); extern int sp_strsv (char *, char *, char *, SuperMatrix *, SuperMatrix *, float *, int *); extern int sp_sgemv (char *, float, SuperMatrix *, float *, int, float, float *, int); extern int sp_sgemm (char *, char *, int, int, int, float, SuperMatrix *, float *, int, float, float *, int); /* Memory-related */ extern int sLUMemInit (char *, void *, int, int, int, int, int, SuperMatrix *, SuperMatrix *, GlobalLU_t *, int **, float **); extern void sSetRWork (int, int, float *, float **, float **); extern void sLUWorkFree (int *, float *, GlobalLU_t *); extern int sLUMemXpand (int, int, MemType, int *, GlobalLU_t *); extern float *floatMalloc(int); extern float *floatCalloc(int); extern int smemory_usage(const int, const int, const int, const int); extern int sQuerySpace (SuperMatrix *, SuperMatrix *, int, mem_usage_t *); /* Auxiliary routines */ extern void sreadhb(int *, int *, int *, float **, int **, int **); extern void sCompRow_to_CompCol(int, int, int, float*, int*, int*, float **, int **, int **); extern void sfill (float *, int, float); extern void sinf_norm_error (int, SuperMatrix *, float *); extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, float, float, float *, float *, char *); /* Routines for debugging */ extern void sPrint_CompCol_Matrix(char *, SuperMatrix *); extern void sPrint_SuperNode_Matrix(char *, SuperMatrix *); extern void sPrint_Dense_Matrix(char *, SuperMatrix *); extern void print_lu_col(char *, int, int, int *, GlobalLU_t *); extern void check_tempv(int, float *); #ifdef __cplusplus } #endif #endif /* __SUPERLU_sSP_DEFS */ pysparse-1.1.1/superlu/superlu_timer.c0000644010116400000240000000150511402270240017107 0ustar wd15dialout/* * Purpose * ======= * Returns the time in seconds used by the process. * * Note: the timer function call is machine dependent. Use conditional * compilation to choose the appropriate function. * */ #ifdef SUN /* * It uses the system call gethrtime(3C), which is accurate to * nanoseconds. */ #include double SuperLU_timer_() { return ( (double)gethrtime() / 1e9 ); } #else #ifndef NO_TIMER #include #include #include #include #endif #ifndef CLK_TCK #define CLK_TCK 60 #endif double SuperLU_timer_() { #ifdef NO_TIMER /* no sys/times.h on WIN32 */ double tmp; tmp = 0.0; #else struct tms use; double tmp; times(&use); tmp = use.tms_utime; tmp += use.tms_stime; #endif return (double)(tmp) / CLK_TCK; } #endif pysparse-1.1.1/superlu/supermatrix.h0000644010116400000240000001360311402270204016602 0ustar wd15dialout#ifndef __SUPERLU_SUPERMATRIX /* allow multiple inclusions */ #define __SUPERLU_SUPERMATRIX /******************************************** * The matrix types are defined as follows. * ********************************************/ typedef enum { NC, /* column-wise, no supernode */ NR, /* row-wize, no supernode */ SC, /* column-wise, supernode */ SR, /* row-wise, supernode */ NCP, /* column-wise, column-permuted, no supernode (The consecutive columns of nonzeros, after permutation, may not be stored contiguously.) */ DN /* Fortran style column-wise storage for dense matrix */ } Stype_t; typedef enum { S_, /* single */ D_, /* double */ C_, /* single complex */ Z_ /* double complex */ } Dtype_t; typedef enum { GE, /* general */ TRLU, /* lower triangular, unit diagonal */ TRUU, /* upper triangular, unit diagonal */ TRL, /* lower triangular */ TRU, /* upper triangular */ SYL, /* symmetric, store lower half */ SYU, /* symmetric, store upper half */ HEL, /* Hermitian, store lower half */ HEU /* Hermitian, store upper half */ } Mtype_t; typedef struct { Stype_t Stype; /* Storage type: interprets the storage structure pointed to by *Store. */ Dtype_t Dtype; /* Data type. */ Mtype_t Mtype; /* Matrix type: describes the mathematical property of the matrix. */ int nrow; /* number of rows */ int ncol; /* number of columns */ void *Store; /* pointer to the actual storage of the matrix */ } SuperMatrix; /*********************************************** * The storage schemes are defined as follows. * ***********************************************/ /* Stype == NC (Also known as Harwell-Boeing sparse matrix format (CCS)) */ typedef struct { int nnz; /* number of nonzeros in the matrix */ void *nzval; /* pointer to array of nonzero values, packed by column */ int *rowind; /* pointer to array of row indices of the nonzeros */ int *colptr; /* pointer to array of beginning of columns in nzval[] and rowind[] */ /* Note: Zero-based indexing is used; nzval[] and rowind[] are of the same length, nnz; colptr[] has ncol+1 entries, the last one pointing beyond the last column, so that colptr[ncol] = nnz. */ } NCformat; /* Stype == NR (Also known as row compressed storage (RCS). */ typedef struct { int nnz; /* number of nonzeros in the matrix */ void *nzval; /* pointer to array of nonzero values, packed by row */ int *colind; /* pointer to array of column indices of the nonzeros */ int *rowptr; /* pointer to array of beginning of rows in nzval[] and colind[] */ /* Note: Zero-based indexing is used; nzval[] and colind[] are of the same length, nnz; rowptr[] has nrow+1 entries, the last one pointing beyond the last column, so that rowptr[nrow] = nnz. */ } NRformat; /* Stype == SC */ typedef struct { int nnz; /* number of nonzeros in the matrix */ int nsuper; /* number of supernodes, minus 1 */ void *nzval; /* pointer to array of nonzero values, packed by column */ int *nzval_colptr;/* pointer to array of beginning of columns in nzval[] */ int *rowind; /* pointer to array of compressed row indices of rectangular supernodes */ int *rowind_colptr;/* pointer to array of beginning of columns in rowind[] */ int *col_to_sup; /* col_to_sup[j] is the supernode number to which column j belongs; mapping from column to supernode number. */ int *sup_to_col; /* sup_to_col[s] points to the start of the s-th supernode; mapping from supernode number to column. e.g.: col_to_sup: 0 1 2 2 3 3 3 4 4 4 4 4 (ncol=12) sup_to_col: 0 1 2 4 7 12 (nsuper=4) */ /* Note: Zero-based indexing is used; nzval_colptr[], rowind_colptr[], col_to_sup[] and sup_to_col[] have ncol+1 entries, the last one pointing beyond the last column. For col_to_sup[], only the first ncol entries are defined. For sup_to_col[], only the first nsuper+2 entries are defined. */ } SCformat; /* Stype == NCP */ typedef struct { int nnz; /* number of nonzeros in the matrix */ void *nzval; /* pointer to array of nonzero values, packed by column */ int *rowind; /* pointer to array of row indices of the nonzeros */ /* Note: nzval[]/rowind[] always have the same length */ int *colbeg; /* colbeg[j] points to the beginning of column j in nzval[] and rowind[] */ int *colend; /* colend[j] points to one past the last element of column j in nzval[] and rowind[] */ /* Note: Zero-based indexing is used; nzval[] and rowind[] are of the same length, nnz; colbeg[] and colend[] are of the same length, ncol; The consecutive columns of the nonzeros may not be contiguous in storage, because the matrix has been postmultiplied by a column permutation matrix. */ } NCPformat; /* Stype == DN */ typedef struct { int lda; /* leading dimension */ void *nzval; /* array of size lda*ncol to represent a dense matrix */ } DNformat; /********************************************************* * Macros used for easy access of sparse matrix entries. * *********************************************************/ #define L_SUB_START(col) ( Lstore->rowind_colptr[col] ) #define L_SUB(ptr) ( Lstore->rowind[ptr] ) #define L_NZ_START(col) ( Lstore->nzval_colptr[col] ) #define L_FST_SUPC(superno) ( Lstore->sup_to_col[superno] ) #define U_NZ_START(col) ( Ustore->colptr[col] ) #define U_SUB(ptr) ( Ustore->rowind[ptr] ) #endif /* __SUPERLU_SUPERMATRIX */ pysparse-1.1.1/superlu/util.c0000644010116400000240000002033111402270227015170 0ustar wd15dialout/* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ /* Copyright (c) 1994 by Xerox Corporation. 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 or copy this program for any purpose, provided the above notices are retained on all copies. Permission to modify the code and to distribute modified code is granted, provided the above notices are retained, and a notice that the code was modified is included with the above copyright notice. */ #include #include "dsp_defs.h" #include "util.h" /* * Global statistics variale */ SuperLUStat_t SuperLUStat; void superlu_abort_and_exit(char* msg) { fprintf(stderr, msg); exit (-1); } void *superlu_malloc(size_t size) { void *buf; buf = (void *) malloc(size); return (buf); } void superlu_free(void *addr) { free (addr); } /* Deallocate the structure pointing to the actual storage of the matrix. */ void Destroy_SuperMatrix_Store(SuperMatrix *A) { SUPERLU_FREE ( A->Store ); } void Destroy_CompCol_Matrix(SuperMatrix *A) { SUPERLU_FREE( ((NCformat *)A->Store)->rowind ); SUPERLU_FREE( ((NCformat *)A->Store)->colptr ); SUPERLU_FREE( ((NCformat *)A->Store)->nzval ); SUPERLU_FREE( A->Store ); } void Destroy_SuperNode_Matrix(SuperMatrix *A) { SUPERLU_FREE ( ((SCformat *)A->Store)->rowind ); SUPERLU_FREE ( ((SCformat *)A->Store)->rowind_colptr ); SUPERLU_FREE ( ((SCformat *)A->Store)->nzval ); SUPERLU_FREE ( ((SCformat *)A->Store)->nzval_colptr ); SUPERLU_FREE ( ((SCformat *)A->Store)->col_to_sup ); SUPERLU_FREE ( ((SCformat *)A->Store)->sup_to_col ); SUPERLU_FREE ( A->Store ); } /* A is of type Stype==NCP */ void Destroy_CompCol_Permuted(SuperMatrix *A) { SUPERLU_FREE ( ((NCPformat *)A->Store)->colbeg ); SUPERLU_FREE ( ((NCPformat *)A->Store)->colend ); SUPERLU_FREE ( A->Store ); } /* A is of type Stype==DN */ void Destroy_Dense_Matrix(SuperMatrix *A) { DNformat* Astore = A->Store; SUPERLU_FREE (Astore->nzval); SUPERLU_FREE ( A->Store ); } /* * Reset repfnz[] for the current column */ void resetrep_col (const int nseg, const int *segrep, int *repfnz) { int i, irep; for (i = 0; i < nseg; i++) { irep = segrep[i]; repfnz[irep] = EMPTY; } } /* * Count the total number of nonzeros in factors L and U, and in the * symmetrically reduced L. */ void countnz(const int n, int *xprune, int *nnzL, int *nnzU, GlobalLU_t *Glu) { int nsuper, fsupc, i, j; int nnzL0, jlen, irep; int *xsup, *xlsub; xsup = Glu->xsup; xlsub = Glu->xlsub; *nnzL = 0; *nnzU = (Glu->xusub)[n]; nnzL0 = 0; nsuper = (Glu->supno)[n]; if ( n <= 0 ) return; /* * For each supernode */ for (i = 0; i <= nsuper; i++) { fsupc = xsup[i]; jlen = xlsub[fsupc+1] - xlsub[fsupc]; for (j = fsupc; j < xsup[i+1]; j++) { *nnzL += jlen; *nnzU += j - fsupc + 1; jlen--; } irep = xsup[i+1] - 1; nnzL0 += xprune[irep] - xlsub[irep]; } /* printf("\tNo of nonzeros in symm-reduced L = %d\n", nnzL0);*/ } /* * Fix up the data storage lsub for L-subscripts. It removes the subscript * sets for structural pruning, and applies permuation to the remaining * subscripts. */ void fixupL(const int n, const int *perm_r, GlobalLU_t *Glu) { register int nsuper, fsupc, nextl, i, j, k, jstrt; int *xsup, *lsub, *xlsub; if ( n <= 1 ) return; xsup = Glu->xsup; lsub = Glu->lsub; xlsub = Glu->xlsub; nextl = 0; nsuper = (Glu->supno)[n]; /* * For each supernode ... */ for (i = 0; i <= nsuper; i++) { fsupc = xsup[i]; jstrt = xlsub[fsupc]; xlsub[fsupc] = nextl; for (j = jstrt; j < xlsub[fsupc+1]; j++) { lsub[nextl] = perm_r[lsub[j]]; /* Now indexed into P*A */ nextl++; } for (k = fsupc+1; k < xsup[i+1]; k++) xlsub[k] = nextl; /* Other columns in supernode i */ } xlsub[n] = nextl; } /* * Diagnostic print of segment info after panel_dfs(). */ void print_panel_seg(int n, int w, int jcol, int nseg, int *segrep, int *repfnz) { int j, k; for (j = jcol; j < jcol+w; j++) { printf("\tcol %d:\n", j); for (k = 0; k < nseg; k++) printf("\t\tseg %d, segrep %d, repfnz %d\n", k, segrep[k], repfnz[(j-jcol)*n + segrep[k]]); } } void StatInit(int panel_size, int relax) { register int i, w; w = SUPERLU_MAX(panel_size, relax); SuperLUStat.panel_histo = intCalloc(w+1); SuperLUStat.utime = (double *) SUPERLU_MALLOC(NPHASES * sizeof(double)); if (!SuperLUStat.utime) ABORT("SUPERLU_MALLOC fails for SuperLUStat.utime"); SuperLUStat.ops = (flops_t *) SUPERLU_MALLOC(NPHASES * sizeof(flops_t)); if (!SuperLUStat.ops) ABORT("SUPERLU_MALLOC fails for SuperLUStat.ops"); for (i = 0; i < NPHASES; ++i) { SuperLUStat.utime[i] = 0.; SuperLUStat.ops[i] = 0.; } } void PrintStat(SuperLUStat_t *SuperLUStat) { double *utime; flops_t *ops; utime = SuperLUStat->utime; ops = SuperLUStat->ops; printf("Factor time = %8.2f\n", utime[FACT]); if ( utime[FACT] != 0.0 ) printf("Factor flops = %e\tMflops = %8.2f\n", ops[FACT], ops[FACT]*1e-6/utime[FACT]); printf("Solve time = %8.2f\n", utime[SOLVE]); if ( utime[SOLVE] != 0.0 ) printf("Solve flops = %e\tMflops = %8.2f\n", ops[SOLVE], ops[SOLVE]*1e-6/utime[SOLVE]); } void StatFree() { SUPERLU_FREE(SuperLUStat.panel_histo); SUPERLU_FREE(SuperLUStat.utime); SUPERLU_FREE(SuperLUStat.ops); } flops_t LUFactFlops() { return (SuperLUStat.ops[FACT]); } flops_t LUSolveFlops() { return (SuperLUStat.ops[SOLVE]); } /* * Fills an integer array with a given value. */ void ifill(int *a, int alen, int ival) { register int i; for (i = 0; i < alen; i++) a[i] = ival; } /* * Get the statistics of the supernodes */ #define NBUCKS 10 static int max_sup_size; void super_stats(int nsuper, int *xsup) { register int nsup1 = 0; int i, isize, whichb, bl, bh; int bucket[NBUCKS]; max_sup_size = 0; for (i = 0; i <= nsuper; i++) { isize = xsup[i+1] - xsup[i]; if ( isize == 1 ) nsup1++; if ( max_sup_size < isize ) max_sup_size = isize; } printf(" Supernode statistics:\n\tno of super = %d\n", nsuper+1); printf("\tmax supernode size = %d\n", max_sup_size); printf("\tno of size 1 supernodes = %d\n", nsup1); /* Histogram of the supernode sizes */ ifill (bucket, NBUCKS, 0); for (i = 0; i <= nsuper; i++) { isize = xsup[i+1] - xsup[i]; whichb = (float) isize / max_sup_size * NBUCKS; if (whichb >= NBUCKS) whichb = NBUCKS - 1; bucket[whichb]++; } printf("\tHistogram of supernode sizes:\n"); for (i = 0; i < NBUCKS; i++) { bl = (float) i * max_sup_size / NBUCKS; bh = (float) (i+1) * max_sup_size / NBUCKS; printf("\tsnode: %d-%d\t\t%d\n", bl+1, bh, bucket[i]); } } float SpaSize(int n, int np, float sum_npw) { return (sum_npw*8 + np*8 + n*4)/1024.; } float DenseSize(int n, float sum_nw) { return (sum_nw*8 + n*8)/1024.;; } /* * Check whether repfnz[] == EMPTY after reset. */ void check_repfnz(int n, int w, int jcol, int *repfnz) { int jj, k; for (jj = jcol; jj < jcol+w; jj++) for (k = 0; k < n; k++) if ( repfnz[(jj-jcol)*n + k] != EMPTY ) { fprintf(stderr, "col %d, repfnz_col[%d] = %d\n", jj, k, repfnz[(jj-jcol)*n + k]); ABORT("check_repfnz"); } } /* Print a summary of the testing results. */ void PrintSumm(char *type, int nfail, int nrun, int nerrs) { if ( nfail > 0 ) printf("%3s driver: %d out of %d tests failed to pass the threshold\n", type, nfail, nrun); else printf("All tests for %3s driver passed the threshold (%6d tests run)\n", type, nrun); if ( nerrs > 0 ) printf("%6d error messages recorded\n", nerrs); } int print_int_vec(char *what, int n, int *vec) { int i; printf("%s\n", what); for (i = 0; i < n; ++i) printf("%d\t%d\n", i, vec[i]); return 0; } pysparse-1.1.1/superlu/util.h0000644010116400000240000000644511402270230015201 0ustar wd15dialout#ifndef __SUPERLU_UTIL /* allow multiple inclusions */ #define __SUPERLU_UTIL #include #include #include #include /* Macros */ #ifndef USER_ABORT #define USER_ABORT(msg) superlu_abort_and_exit(msg) #endif #define ABORT(err_msg) \ { char msg[256];\ sprintf(msg,"%s at line %d in file %s\n",err_msg,__LINE__, __FILE__);\ USER_ABORT(msg); } #ifndef USER_MALLOC #define USER_MALLOC(size) superlu_malloc(size) #endif #define SUPERLU_MALLOC(size) USER_MALLOC(size) #ifndef USER_FREE #define USER_FREE(addr) superlu_free(addr) #endif #define SUPERLU_FREE(addr) USER_FREE(addr) #define SUPERLU_MAX(x, y) ( (x) > (y) ? (x) : (y) ) #define SUPERLU_MIN(x, y) ( (x) < (y) ? (x) : (y) ) /* * Constants */ #define EMPTY (-1) #define NO (-1) #define FALSE 0 #define TRUE 1 /* * Type definitions */ typedef float flops_t; typedef unsigned char Logical; /* * The following enumerate type is used by the statistics variable * SuperLUStat, to keep track of flop count and time spent at various stages. * * Note that not all of the fields are disjoint. */ typedef enum { COLPERM, /* find a column ordering that minimizes fills */ RELAX, /* find artificial supernodes */ ETREE, /* compute column etree */ EQUIL, /* equilibrate the original matrix */ FACT, /* perform LU factorization */ RCOND, /* estimate reciprocal condition number */ SOLVE, /* forward and back solves */ REFINE, /* perform iterative refinement */ FLOAT, /* time spent in floating-point operations */ TRSV, /* fraction of FACT spent in xTRSV */ GEMV, /* fraction of FACT spent in xGEMV */ FERR, /* estimate error bounds after iterative refinement */ NPHASES /* total number of phases */ } PhaseType; typedef struct { int *panel_histo; /* histogram of panel size distribution */ double *utime; /* running time at various phases */ flops_t *ops; /* operation count at various phases */ } SuperLUStat_t; /* Macros */ #define FIRSTCOL_OF_SNODE(i) (xsup[i]) #ifdef __cplusplus extern "C" { #endif extern void superlu_abort_and_exit(char*); extern void *superlu_malloc (size_t); extern int *intMalloc (int); extern int *intCalloc (int); extern void superlu_free (void*); extern void SetIWork (int, int, int, int *, int **, int **, int **, int **, int **, int **, int **); extern void StatInit(int, int); extern void StatFree(); extern int sp_coletree (int *, int *, int *, int, int, int *); extern void relax_snode (const int, int *, const int, int *, int *); extern void resetrep_col (const int, const int *, int *); extern int spcoletree (int *, int *, int *, int, int, int *); extern int *TreePostorder (int, int *); extern double SuperLU_timer_ (); extern int sp_ienv (int); extern int lsame_ (char *, char *); extern int xerbla_ (char *, int *); extern void ifill (int *, int, int); extern void snode_profile (int, int *); extern void super_stats (int, int *); extern void PrintSumm (char *, int, int, int); extern void PrintStat (SuperLUStat_t *); extern void print_panel_seg(int, int, int, int, int *, int *); extern void check_repfnz(int, int, int, int *); #ifdef __cplusplus } #endif #endif /* __SUPERLU_UTIL */ pysparse-1.1.1/superlu/xerbla.c0000644010116400000240000000217011402270227015471 0ustar wd15dialout/* Subroutine */ int xerbla_(char *srname, int *info) { /* -- LAPACK auxiliary routine (version 2.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 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) INT The position of the invalid parameter in the parameter list of the calling routine. ===================================================================== */ printf("** On entry to %6s, parameter number %2d had an illegal value\n", srname, *info); /* End of XERBLA */ return 0; } /* xerbla_ */ pysparse-1.1.1/superlu/zsp_defs.h0000644010116400000240000002352311402270210016033 0ustar wd15dialout /* * -- SuperLU routine (version 2.0) -- * Univ. of California Berkeley, Xerox Palo Alto Research Center, * and Lawrence Berkeley National Lab. * November 15, 1997 * */ #ifndef __SUPERLU_zSP_DEFS /* allow multiple inclusions */ #define __SUPERLU_zSP_DEFS /* * File name: zsp_defs.h * Purpose: Sparse matrix types and function prototypes * History: */ #ifdef _CRAY #include #include #endif #include "Cnames.h" #include "supermatrix.h" #include "dcomplex.h" /* No of marker arrays used in the symbolic factorization, each of size n */ #define NO_MARKER 3 #define NUM_TEMPV(m,w,t,b) ( SUPERLU_MAX(m, (t + b)*w) ) typedef enum {LUSUP, UCOL, LSUB, USUB} MemType; typedef enum {HEAD, TAIL} stack_end_t; typedef enum {SYSTEM, USER} LU_space_t; /* * Global data structures used in LU factorization - * * nsuper: #supernodes = nsuper + 1, numbered [0, nsuper]. * (xsup,supno): supno[i] is the supernode no to which i belongs; * xsup(s) points to the beginning of the s-th supernode. * e.g. supno 0 1 2 2 3 3 3 4 4 4 4 4 (n=12) * xsup 0 1 2 4 7 12 * Note: dfs will be performed on supernode rep. relative to the new * row pivoting ordering * * (xlsub,lsub): lsub[*] contains the compressed subscript of * rectangular supernodes; xlsub[j] points to the starting * location of the j-th column in lsub[*]. Note that xlsub * is indexed by column. * Storage: original row subscripts * * During the course of sparse LU factorization, we also use * (xlsub,lsub) for the purpose of symmetric pruning. For each * supernode {s,s+1,...,t=s+r} with first column s and last * column t, the subscript set * lsub[j], j=xlsub[s], .., xlsub[s+1]-1 * is the structure of column s (i.e. structure of this supernode). * It is used for the storage of numerical values. * Furthermore, * lsub[j], j=xlsub[t], .., xlsub[t+1]-1 * is the structure of the last column t of this supernode. * It is for the purpose of symmetric pruning. Therefore, the * structural subscripts can be rearranged without making physical * interchanges among the numerical values. * * However, if the supernode has only one column, then we * only keep one set of subscripts. For any subscript interchange * performed, similar interchange must be done on the numerical * values. * * The last column structures (for pruning) will be removed * after the numercial LU factorization phase. * * (xlusup,lusup): lusup[*] contains the numerical values of the * rectangular supernodes; xlusup[j] points to the starting * location of the j-th column in storage vector lusup[*] * Note: xlusup is indexed by column. * Each rectangular supernode is stored by column-major * scheme, consistent with Fortran 2-dim array storage. * * (xusub,ucol,usub): ucol[*] stores the numerical values of * U-columns outside the rectangular supernodes. The row * subscript of nonzero ucol[k] is stored in usub[k]. * xusub[i] points to the starting location of column i in ucol. * Storage: new row subscripts; that is subscripts of PA. */ typedef struct { int *xsup; /* supernode and column mapping */ int *supno; int *lsub; /* compressed L subscripts */ int *xlsub; doublecomplex *lusup; /* L supernodes */ int *xlusup; doublecomplex *ucol; /* U columns */ int *usub; int *xusub; int nzlmax; /* current max size of lsub */ int nzumax; /* " " " ucol */ int nzlumax; /* " " " lusup */ int n; /* number of columns in the matrix */ LU_space_t MemModel; /* 0 - system malloc'd; 1 - user provided */ } GlobalLU_t; typedef struct { int panel_size; int relax; double diag_pivot_thresh; double drop_tol; } factor_param_t; typedef struct { float for_lu; float total_needed; int expansions; } mem_usage_t; #ifdef __cplusplus extern "C" { #endif /* Driver routines */ extern void zgssv(SuperMatrix *, int *, int *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *); extern void zgssvx(char *, char *, char *, SuperMatrix *, factor_param_t *, int *, int *, int *, char *, double *, double *, SuperMatrix *, SuperMatrix *, void *, int, SuperMatrix *, SuperMatrix *, double *, double *, double *, double *, mem_usage_t *, int *); /* Supernodal LU factor related */ extern void zCreate_CompCol_Matrix(SuperMatrix *, int, int, int, doublecomplex *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void zCopy_CompCol_Matrix(SuperMatrix *, SuperMatrix *); extern void zCreate_Dense_Matrix(SuperMatrix *, int, int, doublecomplex *, int, Stype_t, Dtype_t, Mtype_t); extern void zCreate_SuperNode_Matrix(SuperMatrix *, int, int, int, doublecomplex *, int *, int *, int *, int *, int *, Stype_t, Dtype_t, Mtype_t); extern void zCopy_Dense_Matrix(int, int, doublecomplex *, int, doublecomplex *, int); extern void Destroy_SuperMatrix_Store(SuperMatrix *); extern void Destroy_CompCol_Matrix(SuperMatrix *); extern void Destroy_SuperNode_Matrix(SuperMatrix *); extern void Destroy_CompCol_Permuted(SuperMatrix *); extern void Destroy_Dense_Matrix(SuperMatrix *); extern void get_perm_c(int, SuperMatrix *, int *); extern void sp_preorder (char*, SuperMatrix*, int*, int*, SuperMatrix*); extern void countnz (const int, int *, int *, int *, GlobalLU_t *); extern void fixupL (const int, const int *, GlobalLU_t *); extern void zallocateA (int, int, doublecomplex **, int **, int **); extern void zgstrf (char*, SuperMatrix*, double, double, int, int, int*, void *, int, int *, int *, SuperMatrix *, SuperMatrix *, int *); extern int zsnode_dfs (const int, const int, const int *, const int *, const int *, int *, int *, GlobalLU_t *); extern int zsnode_bmod (const int, const int, const int, doublecomplex *, doublecomplex *, GlobalLU_t *); extern void zpanel_dfs (const int, const int, const int, SuperMatrix *, int *, int *, doublecomplex *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern void zpanel_bmod (const int, const int, const int, const int, doublecomplex *, doublecomplex *, int *, int *, GlobalLU_t *); extern int zcolumn_dfs (const int, const int, int *, int *, int *, int *, int *, int *, int *, int *, int *, GlobalLU_t *); extern int zcolumn_bmod (const int, const int, doublecomplex *, doublecomplex *, int *, int *, int, GlobalLU_t *); extern int zcopy_to_ucol (int, int, int *, int *, int *, doublecomplex *, GlobalLU_t *); extern int zpivotL (const int, const double, int *, int *, int *, int *, int *, GlobalLU_t *); extern void zpruneL (const int, const int *, const int, const int, const int *, const int *, int *, GlobalLU_t *); extern void zreadmt (int *, int *, int *, doublecomplex **, int **, int **); extern void zGenXtrue (int, int, doublecomplex *, int); extern void zFillRHS (char *, int, doublecomplex *, int, SuperMatrix *, SuperMatrix *); extern void zgstrs (char *, SuperMatrix *, SuperMatrix *, int *, int *, SuperMatrix *, int *); /* Driver related */ extern void zgsequ (SuperMatrix *, double *, double *, double *, double *, double *, int *); extern void zlaqgs (SuperMatrix *, double *, double *, double, double, double, char *); extern void zgscon (char *, SuperMatrix *, SuperMatrix *, double, double *, int *); extern double zPivotGrowth(int, SuperMatrix *, int *, SuperMatrix *, SuperMatrix *); extern void zgsrfs (char *, SuperMatrix *, SuperMatrix *, SuperMatrix *, int *, int *, char *, double *, double *, SuperMatrix *, SuperMatrix *, double *, double *, int *); extern int sp_ztrsv (char *, char *, char *, SuperMatrix *, SuperMatrix *, doublecomplex *, int *); extern int sp_zgemv (char *, doublecomplex, SuperMatrix *, doublecomplex *, int, doublecomplex, doublecomplex *, int); extern int sp_zgemm (char *, char *, int, int, int, doublecomplex, SuperMatrix *, doublecomplex *, int, doublecomplex, doublecomplex *, int); /* Memory-related */ extern int zLUMemInit (char *, void *, int, int, int, int, int, SuperMatrix *, SuperMatrix *, GlobalLU_t *, int **, doublecomplex **); extern void zSetRWork (int, int, doublecomplex *, doublecomplex **, doublecomplex **); extern void zLUWorkFree (int *, doublecomplex *, GlobalLU_t *); extern int zLUMemXpand (int, int, MemType, int *, GlobalLU_t *); extern doublecomplex *doublecomplexMalloc(int); extern doublecomplex *doublecomplexCalloc(int); extern double *doubleMalloc(int); extern double *doubleCalloc(int); extern int zmemory_usage(const int, const int, const int, const int); extern int zQuerySpace (SuperMatrix *, SuperMatrix *, int, mem_usage_t *); /* Auxiliary routines */ extern void zreadhb(int *, int *, int *, doublecomplex **, int **, int **); extern void zCompRow_to_CompCol(int, int, int, doublecomplex*, int*, int*, doublecomplex **, int **, int **); extern void zfill (doublecomplex *, int, doublecomplex); extern void zinf_norm_error (int, SuperMatrix *, doublecomplex *); extern void PrintPerf (SuperMatrix *, SuperMatrix *, mem_usage_t *, doublecomplex, doublecomplex, doublecomplex *, doublecomplex *, char *); /* Routines for debugging */ extern void zPrint_CompCol_Matrix(char *, SuperMatrix *); extern void zPrint_SuperNode_Matrix(char *, SuperMatrix *); extern void zPrint_Dense_Matrix(char *, SuperMatrix *); extern void print_lu_col(char *, int, int, int *, GlobalLU_t *); extern void check_tempv(int, doublecomplex *); #ifdef __cplusplus } #endif #endif /* __SUPERLU_zSP_DEFS */ pysparse-1.1.1/umfpack/0000755010116400000240000000000011402271053013775 5ustar wd15dialoutpysparse-1.1.1/umfpack/umf_2by2.c0000644010116400000240000005623111402270062015574 0ustar wd15dialout/* ========================================================================== */ /* === UMF_2by2 ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* 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. */ #include "umf_internal.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)) ; /* ---------------------------------------------------------------------- */ /* 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 */ /* ---------------------------------------------------------------------- */ 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 ; double cmax, value, rs, ctol, dvalue ; Entry aij ; #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)) ; 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) #ifdef COMPLEX && (Az != (double *) NULL) #endif ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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)) ; 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 } pysparse-1.1.1/umfpack/umf_2by2.h0000644010116400000240000000172011402270062015572 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; pysparse-1.1.1/umfpack/umf_analyze.c0000644010116400000240000005052311402270073016461 0ustar wd15dialout/* ========================================================================== */ /* === UMF_analyze ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_apply_order.h" #include "umf_malloc.h" #include "umf_free.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 ; 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) ; } pysparse-1.1.1/umfpack/umf_analyze.h0000644010116400000240000000142211402270075016462 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_apply_order.c0000644010116400000240000000274411402270102017331 0ustar wd15dialout/* ========================================================================== */ /* === UMF_apply_order ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Apply post-ordering of supernodal elimination tree. */ #include "umf_internal.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] ; } } pysparse-1.1.1/umfpack/umf_apply_order.h0000644010116400000240000000114211402270103017326 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_assemble.c0000644010116400000240000010226611402270052016610 0ustar wd15dialout/* ========================================================================== */ /* === UMF_assemble ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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/long version, for a total of 8 * versions.*/ #include "umf_internal.h" #include "umf_mem_free_tail_block.h" /* ========================================================================== */ /* === row_assemble ========================================================= */ /* ========================================================================== */ PRIVATE void row_assemble ( Int row, NumericType *Numeric, WorkType *Work ) { 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 ; Entry *S, *Fcblock, *Frow ; #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 ) { 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 ; Entry *S, *Fcblock, *Fcol ; #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 */ } pysparse-1.1.1/umfpack/umf_assemble.h0000644010116400000240000000120511402270052016604 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_assemble_fixq.c0000644010116400000240000010230311402270113017625 0ustar wd15dialout#define FIXQ /* ========================================================================== */ /* === UMF_assemble ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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/long version, for a total of 8 * versions.*/ #include "umf_internal.h" #include "umf_mem_free_tail_block.h" /* ========================================================================== */ /* === row_assemble ========================================================= */ /* ========================================================================== */ PRIVATE void row_assemble ( Int row, NumericType *Numeric, WorkType *Work ) { 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 ; Entry *S, *Fcblock, *Frow ; #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 ) { 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 ; Entry *S, *Fcblock, *Fcol ; #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 */ } pysparse-1.1.1/umfpack/umf_blas3_update.c0000644010116400000240000001003411402270074017356 0ustar wd15dialout/* ========================================================================== */ /* === UMF_blas3_update ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.h" GLOBAL void UMF_blas3_update ( WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ Entry *L, *U, *C, *LU ; Int k, m, n, d, nb, dc ; 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) { #ifdef USE_NO_BLAS /* no BLAS available - use plain C code instead */ Int i, j ; /* 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 BLAS_GER (m, n, L, U, C, d) ; #endif /* USE_NO_BLAS */ } else { #ifdef USE_NO_BLAS /* no BLAS available - use plain C code instead */ Int i, j, s ; /* triangular solve to update the U block */ 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) */ 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++ ; } } } } #else BLAS_TRSM_RIGHT (n, k, LU, nb, U, dc) ; BLAS_GEMM (m, n, k, L, U, dc, C, d) ; #endif /* USE_NO_BLAS */ } #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)) ; } pysparse-1.1.1/umfpack/umf_blas3_update.h0000644010116400000240000000103511402270076017366 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_blas3_update ( WorkType *Work ) ; pysparse-1.1.1/umfpack/umf_build_tuples.c0000644010116400000240000001260211402270071017503 0ustar wd15dialout/* ========================================================================== */ /* === UMF_build_tuples ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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) ; } pysparse-1.1.1/umfpack/umf_build_tuples.h0000644010116400000240000000106611402270072017513 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_build_tuples ( NumericType *Numeric, WorkType *Work ) ; pysparse-1.1.1/umfpack/umf_colamd.c0000644010116400000240000026725711402270034016270 0ustar wd15dialout/* ========================================================================== */ /* === UMF_colamd =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 and DMS-9803599. 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 */ pysparse-1.1.1/umfpack/umf_colamd.h0000644010116400000240000002206211402270036016256 0ustar wd15dialout/* ========================================================================== */ /* === umf_colamd.h ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 and DMS-9803599. 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 */ pysparse-1.1.1/umfpack/umf_config.h0000644010116400000240000010510011402270041016253 0ustar wd15dialout/* ========================================================================== */ /* === umf_config.h ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* This file controls the compile-time configuration of UMFPACK. Modify the Makefile, the architecture-dependent Make.* 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 -DNBLAS", for example). These flags are normally placed in your CONFIG string, defined in your Make.*. All of these options, except for the timer, are for accessing the BLAS. -DNBLAS BLAS mode. If -DNBLAS is set, then no BLAS will be used. Vanilla C code will be used instead. This is portable, and easier to install, but you won't get the best performance. If -DNBLAS is not set, then externally-available BLAS routines (dgemm, dger, and dgemv or the equivalent C-BLAS routines) will be used. This will give you the best performance, but perhaps at the expense of portability. The default is to use the BLAS, for both the C-callable libumfpack.a library and the MATLAB mexFunction. If you have trouble installing UMFPACK, set -DNBLAS (but then UMFPACK will be slow). -DCBLAS If -DCBLAS is set, then the C-BLAS interface to the BLAS is used. If your vendor-supplied BLAS library does not have a C-BLAS interface, you can obtain the ATLAS BLAS, available at http://www.netlib.org/atlas. This flag is ignored if -DNBLAS is set. -DLP64 This should be defined if you are compiling in the LP64 model (32 bit int's, 64 bit long's, and 64 bit pointers). In Solaris, this is obtained with the flags -xtarget=ultra -xarch=v9 for the cc compiler (for example). -DLONGBLAS If not defined, then the BLAS are not called in the long integer version of UMFPACK (the umfpack_*l_* routines). The most common definitions of the BLAS, unfortunately, use int arguments, and are thus not suitable for use in the LP64 model. Only the Sun Performance Library, as far as I can tell, has a version of the BLAS that allows long integer (64-bit) input arguments. This flag is set automatically in Sun Solaris if you are using the Sun Performance BLAS. You can set it yourself, too, if your BLAS routines can take long integer input arguments. -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. This flag is ignored if -DNBLAS is set. -DNSCSL Applies only to SGI IRIX. If -DSCSL is set, then the SGI SCSL Scientific Library BLAS will not be used. The SGI SCSL Scientific Library BLAS is used by default when compiling the C-callable libumfpack.a library on SGI IRIX. This flag is ignored if -DNBLAS is set. -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. -DNUTIL If -DNUTIL is set, then the internal MATLAB utMalloc, utFree, and utRealloc routines are not used in the UMFPACK mexFunction. The regular mxMalloc, mxFree, and mxRealloc routines are used instead. These routines are not documented, but are available for use. For Windows, -DNUTIL is defined below, because access to the ut* routines is not available by default. -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. You should normally not set these flags yourself: -DBLAS_BY_VALUE if scalars are passed by value, not reference -DBLAS_NO_UNDERSCORE if no underscore should be appended -DBLAS_CHAR_ARG if BLAS options are single char's, not strings The BLAS options are normally set automatically. If your architecture cannot be determined (see UMFPACK_ARCHITECTURE, below) then you may need to set these flags yourself. 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. When compiling the MATLAB mexFunction, the MATLAB BLAS are used (unless -DNBLAS is set). The -DCBLAS, -DNSCSL, and -DNSUNPERF flags are all ignored. The -DNRECIPROCAL flag is forced on. Otherwise, [L,U,P,Q,R] = umfpack (A) would return either L*U = P*(R\A)*Q or L*U = P*R*A*Q. Rather than returning a flag stating how the scale factors R are to be applied, the umfpack mexFunction always takes the more accurate route and returns L*U = P*(R\A)*Q. -DMATHWORKS This flag is turned on when compiling umfpack as a built-in routine in MATLAB. The MATLAB BLAS are used for all architectures (-DNBLAS, -DCBLAS, -DNSCSL, and -DNSUNPERF flags are all ignored). Internal routines utMalloc, utFree, utRealloc, utPrintf, utDivideComplex, and utFdlibm_hypot are used, and the "util.h" file is included. This avoids the problem discussed in the User Guide regarding memory allocation in MATLAB. utMalloc returns NULL on failure, instead of terminating the mexFunction (which is what mxMalloc does). However, the ut* routines are not documented by The MathWorks, Inc., so I cannot guarantee that you will always be able to use them. The -DNRECIPROCAL flag is turned 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 ====================================== */ /* ========================================================================== */ #ifdef UMF_WINDOWS /* Windows can't access the ut* routines, and it isn't Unix. */ #define NUTIL #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 (V4.0). 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) #define GETRUSAGE #endif /* ========================================================================== */ /* === BLAS ================================================================= */ /* ========================================================================== */ /* The adventure begins. Figure out how to call the BLAS ... This works, but it is incredibly ugly. The C-BLAS was supposed to solve this problem, and make it easier to interface a C program to the BLAS. Unfortunately, the C-BLAS does not have a "long" integer (64 bit) version. Various vendors have done their own 64-bit BLAS. Sun has dgemm_64 routines with "long" integers, SGI has a 64-bit dgemm in their scsl_blas_i8 library with "long long" integers, and so on. Different vendors also have different ways of defining a complex number, some using struct's. That's a bad idea. See umf_version.h for the better way to do it (the method that was also chosen for the complex C-BLAS, which is compatible and guaranteed to be portable with ANSI C). To make matters worse, SGI's SCSL BLAS has a C-BLAS interface which differs from the ATLAS C-BLAS interface (see immediately below); although a more recent version of SGI's C-BLAS interface is correct if SCSL_VOID_ARGS is defined. */ /* -------------------------------------------------------------------------- */ /* Determine which BLAS to use. */ /* -------------------------------------------------------------------------- */ #if defined (MATHWORKS) #define USE_MATLAB_BLAS #elif defined (NBLAS) #define USE_NO_BLAS #elif defined (MATLAB_MEX_FILE) #define USE_MATLAB_BLAS #elif defined (CBLAS) #define USE_C_BLAS #elif defined (UMF_SOL2) && !defined (NSUNPERF) #define USE_SUNPERF_BLAS #elif defined (UMF_SGI) && !defined (NSCSL) #define USE_SCSL_BLAS #else #define USE_FORTRAN_BLAS #endif /* -------------------------------------------------------------------------- */ /* int vs. long integer arguments */ /* -------------------------------------------------------------------------- */ /* Determine if the BLAS exists for the long integer version. It exists if LONGBLAS is defined in the Makefile, or if using the BLAS from the Sun Performance Library, or SGI's SCSL Scientific Library. */ #if defined (USE_SUNPERF_BLAS) || defined (USE_SCSL_BLAS) #ifndef LONGBLAS #define LONGBLAS #endif #endif /* do not use the BLAS if Int's are long and LONGBLAS is not defined */ #if defined (LONG_INTEGER) && !defined (LONGBLAS) && !defined (USE_NO_BLAS) #define USE_NO_BLAS #endif /* -------------------------------------------------------------------------- */ /* Use (void *) arguments for the SGI */ /* -------------------------------------------------------------------------- */ #if defined (UMF_SGI) /* Use (void *) pointers for complex types in SCSL. The ATLAS C-BLAS, and the SGI C-BLAS differ. The former uses (void *) arguments, the latter uses SCSL_ZOMPLEX_T, which are either scsl_zomplex or (void *). Using (void *) is simpler, and is selected by defining SCSL_VOID_ARGS, below. The cc compiler doesn't complain, but gcc is more picky, and generates a warning without this next statement. With gcc and the 07/09/98 version of SGI's cblas.h, spurious warnings about complex BLAS arguments will be reported anyway. This is because this older version of SGI's cblas.h does not make use of the SCSL_VOID_ARGS parameter, which is present in the 12/6/01 version of SGI's cblas.h. You can safely ignore these warnings. */ #define SCSL_VOID_ARGS #endif /* -------------------------------------------------------------------------- */ /* The BLAS exists, construct appropriate macros */ /* -------------------------------------------------------------------------- */ #if !defined (USE_NO_BLAS) /* { */ /* If the compile-time flag -DNBLAS is defined, then the BLAS are not used, portable vanilla C code is used instead, and the remainder of this file is ignored. Using the BLAS is much faster, but how C calls the Fortran BLAS is machine-dependent and thus can cause portability problems. Thus, use -DNBLAS to ensure portability (at the expense of speed). Preferences: *** The best interface to use, regardless of the option you select below, is the standard C-BLAS interface. Not all BLAS libraries use this interface. The only problem with this interface is that it does not extend to the LP64 model. The C-BLAS does not provide for a 64-bit integer. In addition, SGI's older cblas.h can cause spurious warnings when using the C-BLAS interface. 1) often the most preferred (but see option (3)): use the optimized vendor-supplied library (such as the Sun Performance Library, or IBM's ESSL). This is often the fastest, but might not be portable and might not always be available. When compiling a MATLAB mexFunction it might be difficult get the mex compiler script to recognize the vendor- supplied BLAS. Note that the freely-available BLAS (option 3) can be faster than the vendor- specific BLAS. You are encourage to try both option (1) and (3). 2) When compiling the UMFPACK mexFunction to use UMFPACK in MATLAB, use the BLAS provided by The Mathworks, Inc. This assumes you are using MATLAB V6 or higher, since the BLAS are not incorporated in V5 or earlier versions. On my Sun workstation, the MATLAB BLAS gave slightly worse performance than the Sun Perf. BLAS. The advantage of using the MATLAB BLAS is that it's available on any computer that has MATLAB V6 or higher. I have not tried using MATLAB BLAS outside of a mexFunction in a stand-alone C code, but MATLAB (V6) allows for this. This is well worth trying if you have MATLAB and don't want to bother installing the ATLAS BLAS (option 3a, below). The only glitch to this is that MATLAB does not provide a portable interface to the BLAS (an underscore is required for some but not all architectures). For Windows and MATLAB 6.0 or 6.1, you also need to copy the libmwlapack.dll file into your MATLAB installation directory; see the User Guide for details. In the current distribution, the only BLAS that the UMFPACK mexFunction will use is the internal MATLAB BLAS. It's possible to use other BLAS, but handling the porting of using the mex compiler with different BLAS libraries is not trivial. As of MATLAB 6.5, the BLAS used internally in MATLAB is the ATLAS BLAS. 3) Use a freely-available high-performance BLAS library: (a) The BLAS by Kazashige Goto and Robert van de Geijn, at http://www.cs.utexas.edu/users/flame/goto. This BLAS increased the performance of UMFPACK by almost 50% as compared to the ATLAS BLAS (v3.2). (b) The ATLAS BLAS, available at http://www.netlib.org/atlas, by R. Clint Whaley, Antoine Petitet, and Jack Dongarra. This has a standard C interface, and thus the interface to it is fully portable. Its performance rivals, and sometimes exceeds, the vendor-supplied BLAS on many computers. (b) The Fortran RISC BLAS by Michel Dayde', Iain Duff, Antoine Petitet, and Abderrahim Qrichi Aniba, available via anonymous ftp to ftp.enseeiht.fr in the pub/numerique/BLAS/RISC directory, See M. J. Dayde' and I. S. Duff, "The RISC BLAS: A blocked implementation of level 3 BLAS for RISC processors, ACM Trans. Math. Software, vol. 25, no. 3., Sept. 1999. This will give you good performance, but with the same C-to-Fortran portability problems as option (1). 4) Use UMFPACK's built-in vanilla C code by setting -DNBLAS at compile time. The key advantage is portability, which is guaranteed if you have an ANSI C compliant compiler. You also don't need to download any other package - UMFPACK is stand-alone. No Fortran is used anywhere in UMFPACK. UMFPACK will be much slower than when using options (1) through (3), however. 5) least preferred: use the standard Fortran implementation of the BLAS, also available at Netlib (http://www.netlib.org/blas). This will be no faster than option (4), and not portable because of C-to-Fortran calling conventions. Don't bother trying option (5). The mechanics of how C calls the BLAS on various computers are as follows: * C-BLAS (from the ATLAS library, for example): The same interface is used on all computers. * Defaults for calling the Fortran BLAS: add underscore, pass scalars by reference, use string arguments. * The Fortran BLAS on Sun Solaris (when compiling the MATLAB mexFunction or when using the Fortran RISC BLAS), SGI IRIX, Linux, and Compaq Alpha: use defaults. * Sun Solaris (when using the C-callable Sun Performance library): no underscore, pass scalars by value, use character arguments. * The Fortran BLAS (ESSL Library) on the IBM RS 6000, and HP Unix: no underscore, pass scalars by reference, use string arguments. * The Fortran BLAS on Windows: no underscore, pass scalars by reference, use string arguments. If you compile the umfpack mexFunction using umfpack_make, and are using the lcc compiler bundled with MATLAB, then you must first copy the umfpack\lcc_lib\libmwlapack.lib file into the \extern\lib\win32\lcc\ directory, where is the directory in which MATLAB is installed. Next, type mex -setup at the MATLAB prompt, and ask MATLAB to select the lcc compiler. MATLAB has built-in BLAS, but it cannot be accessed by a program compiled by lcc without first copying this file. */ /* -------------------------------------------------------------------------- */ #ifdef USE_C_BLAS /* { */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* use the C-BLAS (any computer) */ /* -------------------------------------------------------------------------- */ /* C-BLAS is the default interface, with the following exceptions. Solaris uses the Sun Performance BLAS for libumfpack.a (the C-callable library). SGI IRIX uses the SCSL BLAS for libumfpack.a. All architectures use MATLAB's internal BLAS for the mexFunction on any architecture. These options are set in the Make.* files. The Make.generic file uses no BLAS at all. If you use the ATLAS C-BLAS, then be sure to set the -I flag to -I/path/ATLAS/include, where /path/ATLAS is the ATLAS installation directory. See Make.solaris for an example. You do not need to do this for the SGI, which has a /usr/include/cblas.h. */ #include "cblas.h" #ifdef COMPLEX #define BLAS_GEMM_ROUTINE cblas_zgemm #define BLAS_TRSM_ROUTINE cblas_ztrsm #define BLAS_TRSV_ROUTINE cblas_ztrsv #define BLAS_GEMV_ROUTINE cblas_zgemv #define BLAS_GER_ROUTINE cblas_zgeru #define BLAS_SCAL_ROUTINE cblas_zscal #define BLAS_COPY_ROUTINE cblas_zcopy #define BLAS_DECLARE_SCALAR(x) double x [2] #define BLAS_ASSIGN(x,xr,xi) { x [0] = xr ; x [1] = xi ; } #else #define BLAS_GEMM_ROUTINE cblas_dgemm #define BLAS_TRSM_ROUTINE cblas_dtrsm #define BLAS_TRSV_ROUTINE cblas_dtrsv #define BLAS_GEMV_ROUTINE cblas_dgemv #define BLAS_GER_ROUTINE cblas_dger #define BLAS_SCAL_ROUTINE cblas_dscal #define BLAS_COPY_ROUTINE cblas_dcopy #define BLAS_DECLARE_SCALAR(x) double x #define BLAS_ASSIGN(x,xr,xi) { x = xr ; } #endif #define BLAS_LOWER CblasLower #define BLAS_UNIT_DIAGONAL CblasUnit #define BLAS_RIGHT CblasRight #define BLAS_NO_TRANSPOSE CblasNoTrans #define BLAS_TRANSPOSE CblasTrans #define BLAS_COLUMN_MAJOR_ORDER CblasColMajor, #define BLAS_SCALAR(x) x #define BLAS_INT_SCALAR(n) n #define BLAS_ARRAY(a) a /* -------------------------------------------------------------------------- */ #else /* } USE_C_BLAS { */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* use Fortran (or other architecture-specific) BLAS */ /* -------------------------------------------------------------------------- */ /* No such argument when not using the C-BLAS */ #define BLAS_COLUMN_MAJOR_ORDER /* Determine which architecture we're on and set options accordingly. */ /* The default, if nothing is defined is to add an underscore, */ /* pass scalars by reference, and use string arguments. */ /* ---------------------------------- */ /* Sun Performance BLAS */ /* ---------------------------------- */ #ifdef USE_SUNPERF_BLAS #ifdef _SUNPERF_H /* has been included somehow anyway, outside of umf_config.h */ #error "sunperf.h must NOT be #include'd. See umf_config.h for details." #endif #define BLAS_BY_VALUE #define BLAS_NO_UNDERSCORE #define BLAS_CHAR_ARG #endif /* USE_SUNPERF_BLAS */ /* ---------------------------------- */ /* SGI SCSL BLAS */ /* ---------------------------------- */ #ifdef USE_SCSL_BLAS #if defined (LP64) #include #else #include #endif #define BLAS_BY_VALUE #define BLAS_NO_UNDERSCORE #endif /* USE_SCSL_BLAS */ /* ---------------------------------- */ /* IBM AIX, Windows, and HP Fortran BLAS */ /* ---------------------------------- */ #if defined (UMF_AIX) || defined (UMF_WINDOWS) || defined (UMF_HP) #define BLAS_NO_UNDERSCORE #endif /* -------------------------------------------------------------------------- */ /* BLAS names */ /* -------------------------------------------------------------------------- */ #if defined (LP64) && defined (USE_SUNPERF_BLAS) && defined (LONG_INTEGER) /* 64-bit sunperf BLAS, for Sun Solaris only */ #ifdef COMPLEX #define BLAS_GEMM_ROUTINE zgemm_64 #define BLAS_TRSM_ROUTINE ztrsm_64 #define BLAS_TRSV_ROUTINE ztrsv_64 #define BLAS_GEMV_ROUTINE zgemv_64 #define BLAS_GER_ROUTINE zgeru_64 #define BLAS_SCAL_ROUTINE zscal_64 #define BLAS_COPY_ROUTINE zcopy_64 #else #define BLAS_GEMM_ROUTINE dgemm_64 #define BLAS_TRSM_ROUTINE dtrsm_64 #define BLAS_TRSV_ROUTINE dtrsv_64 #define BLAS_GEMV_ROUTINE dgemv_64 #define BLAS_GER_ROUTINE dger_64 #define BLAS_SCAL_ROUTINE dscal_64 #define BLAS_COPY_ROUTINE dcopy_64 #endif /* COMPLEX */ #else #ifdef COMPLEX /* naming convention (use underscore, or not) */ #ifdef BLAS_NO_UNDERSCORE #define BLAS_GEMM_ROUTINE zgemm #define BLAS_TRSM_ROUTINE ztrsm #define BLAS_TRSV_ROUTINE ztrsv #define BLAS_GEMV_ROUTINE zgemv #define BLAS_GER_ROUTINE zgeru #define BLAS_SCAL_ROUTINE zscal #define BLAS_COPY_ROUTINE zcopy #else /* default: add underscore */ #define BLAS_GEMM_ROUTINE zgemm_ #define BLAS_TRSM_ROUTINE ztrsm_ #define BLAS_TRSV_ROUTINE ztrsv_ #define BLAS_GEMV_ROUTINE zgemv_ #define BLAS_GER_ROUTINE zgeru_ #define BLAS_SCAL_ROUTINE zscal_ #define BLAS_COPY_ROUTINE zcopy_ #endif #else /* naming convention (use underscore, or not) */ #ifdef BLAS_NO_UNDERSCORE #define BLAS_GEMM_ROUTINE dgemm #define BLAS_TRSM_ROUTINE dtrsm #define BLAS_TRSV_ROUTINE dtrsv #define BLAS_GEMV_ROUTINE dgemv #define BLAS_GER_ROUTINE dger #define BLAS_SCAL_ROUTINE dscal #define BLAS_COPY_ROUTINE dcopy #else /* default: add underscore */ #define BLAS_GEMM_ROUTINE dgemm_ #define BLAS_TRSM_ROUTINE dtrsm_ #define BLAS_TRSV_ROUTINE dtrsv_ #define BLAS_GEMV_ROUTINE dgemv_ #define BLAS_GER_ROUTINE dger_ #define BLAS_SCAL_ROUTINE dscal_ #define BLAS_COPY_ROUTINE dcopy_ #endif #endif /* COMPLEX */ #endif /* LP64 && USE_SUNPERF_BLAS */ /* -------------------------------------------------------------------------- */ /* BLAS real or complex floating-point scalars */ /* -------------------------------------------------------------------------- */ #ifdef COMPLEX /* The SunPerf BLAS expects to see a doublecomplex scalar, but it also will accept an array of size 2. See the manual, normally at file:///opt/SUNWspro/WS6U1/lib/locale/C/html/manuals/perflib/user_guide /plug_using_perflib.html . This manual is inconsistent with the man pages for zgemm, zgemv, and zgeru and also inconsistent with the include file. Use this instead, for SunPerf (only works if you do NOT include sunperf.h). Fortunately, this file (umf_config.h) is not included in any user code that calls UMFPACK. Thus, the caller may include sunperf.h in his or her own code, and that is safely ignored here. SGI's SCSL BLAS has yet a different kind of struct, but we can use a double array of size 2 instead (since SCSL_VOID_ARGS is defined). Most BLAS expect complex scalars as pointers to double arrays of size 2. */ #define BLAS_DECLARE_SCALAR(x) double x [2] #define BLAS_ASSIGN(x,xr,xi) { x [0] = xr ; x [1] = xi ; } #define BLAS_SCALAR(x) x #else #define BLAS_DECLARE_SCALAR(x) double x #define BLAS_ASSIGN(x,xr,xi) { x = xr ; } #ifdef BLAS_BY_VALUE #define BLAS_SCALAR(x) x #else #define BLAS_SCALAR(x) &(x) #endif #endif /* COMPLEX */ /* -------------------------------------------------------------------------- */ /* BLAS integer scalars */ /* -------------------------------------------------------------------------- */ /* Fortran requires integers to be passed by reference. The SCSL BLAS requires long long arguments in LP64 mode. */ #if defined (USE_SCSL_BLAS) && defined (LP64) #define BLAS_INT_SCALAR(n) ((long long) n) #else #ifdef BLAS_BY_VALUE #define BLAS_INT_SCALAR(n) n #else #define BLAS_INT_SCALAR(n) &(n) #endif #endif /* -------------------------------------------------------------------------- */ /* BLAS strings */ /* -------------------------------------------------------------------------- */ /* The Sun Performance BLAS wants a character instead of a string. */ #ifdef BLAS_CHAR_ARG #define BLAS_NO_TRANSPOSE 'N' #define BLAS_TRANSPOSE 'T' #define BLAS_LEFT 'L' #define BLAS_RIGHT 'R' #define BLAS_LOWER 'L' #define BLAS_UNIT_DIAGONAL 'U' #else #define BLAS_NO_TRANSPOSE "N" #define BLAS_TRANSPOSE "T" #define BLAS_LEFT "L" #define BLAS_RIGHT "R" #define BLAS_LOWER "L" #define BLAS_UNIT_DIAGONAL "U" #endif /* -------------------------------------------------------------------------- */ /* BLAS arrays */ /* -------------------------------------------------------------------------- */ /* The complex SunPerf BLAS expects to see a doublecomplex array of size s. This is broken (see above, regarding complex scalars in sunperf.h). For SunPerf BLAS, just pass a pointer to the array, and ignore sunperf.h. With sunperf.h, you would need: #define BLAS_ARRAY(a) ((doublecomplex *)(a)) SGI's SCSL BLAS has yet a different kind of struct, but we can use a double array of size 2 instead (since SCSL_VOID_ARGS is defined). The real versions all use just a (double *) pointer. In all cases, no typecast is required. This will break if is included. If you have read this far, I hope you see now why (void *) a much better choice for complex BLAS prototypes, and why double x [2] is better than an architecture dependent struct { double real ; double imag ; } type definition. */ #define BLAS_ARRAY(a) (a) /* -------------------------------------------------------------------------- */ #endif /* USE_C_BLAS } */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* BLAS macros, for all interfaces */ /* -------------------------------------------------------------------------- */ /* All architecture dependent issues have now been taken into consideration, and folded into the macros BLAS_DECLARE_SCALAR, BLAS_ASSIGN, BLAS_*_ROUTINE, BLAS_COLUMN_MAJOR_ORDER, BLAS_NO_TRANSPOSE, BLAS_TRANSPOSE, BLAS_SCALAR, BLAS_INT_SCALAR, BLAS_ARRAY, and Int. You will note that there is not a *** single *** name, declaration, or argument to the BLAS which is not somehow different in one or more versions of the BLAS! */ /* 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 */ #define BLAS_GEMM(m,n,k,A,B,ldb,C,ldac) \ { \ BLAS_DECLARE_SCALAR (alpha) ; \ BLAS_DECLARE_SCALAR (beta) ; \ BLAS_ASSIGN (alpha, -1.0, 0.0) ; \ BLAS_ASSIGN (beta, 1.0, 0.0) ; \ (void) BLAS_GEMM_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \ BLAS_NO_TRANSPOSE, BLAS_TRANSPOSE, \ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), BLAS_INT_SCALAR (k), \ BLAS_SCALAR (alpha), \ BLAS_ARRAY (A), BLAS_INT_SCALAR (ldac), \ BLAS_ARRAY (B), BLAS_INT_SCALAR (ldb), BLAS_SCALAR (beta), \ BLAS_ARRAY (C), BLAS_INT_SCALAR (ldac)) ; \ } /* 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 */ #define BLAS_GER(m,n,x,y,A,d) \ { \ Int one = 1 ; \ BLAS_DECLARE_SCALAR (alpha) ; \ BLAS_ASSIGN (alpha, -1.0, 0.0) ; \ (void) BLAS_GER_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \ BLAS_SCALAR (alpha), \ BLAS_ARRAY (x), BLAS_INT_SCALAR (one), \ BLAS_ARRAY (y), BLAS_INT_SCALAR (one), \ BLAS_ARRAY (A), BLAS_INT_SCALAR (d)) ; \ } /* 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 */ #define BLAS_GEMV(m,n,A,x,y,d) \ { \ Int one = 1 ; \ BLAS_DECLARE_SCALAR (alpha) ; \ BLAS_DECLARE_SCALAR (beta) ; \ BLAS_ASSIGN (alpha, -1.0, 0.0) ; \ BLAS_ASSIGN (beta, 1.0, 0.0) ; \ (void) BLAS_GEMV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \ BLAS_NO_TRANSPOSE, \ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \ BLAS_SCALAR (alpha), \ BLAS_ARRAY (A), BLAS_INT_SCALAR (d), \ BLAS_ARRAY (x), BLAS_INT_SCALAR (one), BLAS_SCALAR (beta), \ BLAS_ARRAY (y), BLAS_INT_SCALAR (one)) ; \ } /* 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 */ #define BLAS_TRSV(m,A,b,d) \ { \ Int one = 1 ; \ (void) BLAS_TRSV_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \ BLAS_LOWER, BLAS_NO_TRANSPOSE, BLAS_UNIT_DIAGONAL, \ BLAS_INT_SCALAR (m), \ BLAS_ARRAY (A), BLAS_INT_SCALAR (d), \ BLAS_ARRAY (b), BLAS_INT_SCALAR (one)) ; \ } /* solve XL'=B where: * B is m-by-n with leading dimension ldb * A is n-by-n with leading dimension lda */ #define BLAS_TRSM_RIGHT(m,n,A,lda,B,ldb) \ { \ BLAS_DECLARE_SCALAR (alpha) ; \ BLAS_ASSIGN (alpha, 1.0, 0.0) ; \ (void) BLAS_TRSM_ROUTINE (BLAS_COLUMN_MAJOR_ORDER \ BLAS_RIGHT, BLAS_LOWER, BLAS_TRANSPOSE, BLAS_UNIT_DIAGONAL, \ BLAS_INT_SCALAR (m), BLAS_INT_SCALAR (n), \ BLAS_SCALAR (alpha), \ BLAS_ARRAY (A), BLAS_INT_SCALAR (lda), \ BLAS_ARRAY (B), BLAS_INT_SCALAR (ldb)) ; \ } /* x = s*x, where x is a stride-1 vector of length n */ #define BLAS_SCAL(n,s,x) \ { \ Int one = 1 ; \ BLAS_DECLARE_SCALAR (alpha) ; \ BLAS_ASSIGN (alpha, REAL_COMPONENT (s), IMAG_COMPONENT (s)) ; \ (void) BLAS_SCAL_ROUTINE ( \ BLAS_INT_SCALAR (n), BLAS_SCALAR (alpha), \ BLAS_ARRAY (x), BLAS_INT_SCALAR (one)) ; \ } /* x = y, where x and y are a stride-1 vectors of length n */ #define BLAS_COPY(n,x,y) \ { \ Int one = 1 ; \ (void) BLAS_COPY_ROUTINE ( \ BLAS_INT_SCALAR (n), \ BLAS_ARRAY (x), BLAS_INT_SCALAR (one), \ BLAS_ARRAY (y), BLAS_INT_SCALAR (one)) ; \ } #endif /* !defined (USE_NO_BLAS) } */ pysparse-1.1.1/umfpack/umf_create_element.c0000644010116400000240000004220611402270042017765 0ustar wd15dialout/* ========================================================================== */ /* === UMF_create_element =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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) ; #if 0 #ifdef USE_NO_BLAS copy_column (fnrows, Fcol, C) ; #else could also use BLAS-COPY (fnrows, Fcol, C) here, but it is typically not as fast as the inlined copy_column subroutine, above. #endif for (i = 0 ; i < fnrows ; i++) { C [i] = Fcol [i] ; } #endif 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) ; } pysparse-1.1.1/umfpack/umf_create_element.h0000644010116400000240000000112411402270043017765 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_create_element ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; pysparse-1.1.1/umfpack/umf_dump.c0000644010116400000240000010030711402270074015760 0ustar wd15dialout/* ========================================================================== */ /* === UMF_dump ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 */ ) { 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 ; Entry value, *C ; 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 ; 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 (Az != (double *) NULL) { DEBUG6 ((" (%e+%ei) ", Ax [p], Az [p])) ; } else { DEBUG6 ((" %e", Ax [p])) ; } #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 ; /* 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 ((" BLAS: ")) ; #if defined (USE_NO_BLAS) DEBUG0 (("none.")) ; #elif defined (USE_C_BLAS) DEBUG0 (("C-BLAS.")) ; #elif defined (USE_MATLAB_BLAS) DEBUG0 (("built-in MATLAB BLAS.")) ; #elif defined (USE_SUNPERF_BLAS) DEBUG0 (("Sun Performance Library BLAS.")) ; #elif defined (USE_SCSL_BLAS) DEBUG0 (("SGI SCSL BLAS.")) ; #elif defined (USE_FORTRAN_BLAS) DEBUG0 (("Fortran BLAS.")) ; #endif DEBUG0 ((" MATLAB: ")) ; #ifdef MATLAB_MEX_FILE DEBUG0 (("mexFunction.\n")) ; #else #ifdef MATHWORKS DEBUG0 (("yes (uses MathWorks internal ut* routines).\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 (long) %u %u %u\n", sizeof (long), sizeof (long) / sizeof (long), UNITS (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 n1, Int nn, Int nempty ) { Int row, col ; if (Diagonal_map != (Int *) NULL) { DEBUG2 (("\nDump the Diagonal_map: n1 "ID" nn "ID" nempty "ID"\n", n1, nn, nempty)) ; for (col = n1 ; col < nn - nempty ; 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 */ pysparse-1.1.1/umfpack/umf_dump.h0000644010116400000240000000771611402270076016001 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 n1, Int nn, Int nempty ) ; #define UMF_DBMAX 50000 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 */ pysparse-1.1.1/umfpack/umf_extend_front.c0000644010116400000240000002676511402270057017532 0ustar wd15dialout/* ========================================================================== */ /* === UMF_extend_front ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Called by kernel. */ #include "umf_internal.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) ; } pysparse-1.1.1/umfpack/umf_extend_front.h0000644010116400000240000000106611402270061017515 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_extend_front ( NumericType *Numeric, WorkType *Work ) ; pysparse-1.1.1/umfpack/umf_free.c0000644010116400000240000000272511402270067015743 0ustar wd15dialout/* ========================================================================== */ /* === UMF_free ============================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" #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 umf_config.h for the memory allocator selection */ 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) ; } pysparse-1.1.1/umfpack/umf_free.h0000644010116400000240000000101711402270070015733 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void *UMF_free ( void *p ) ; pysparse-1.1.1/umfpack/umf_fsize.c0000644010116400000240000000442011402270112016123 0ustar wd15dialout/* ========================================================================== */ /* === UMF_fsize ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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])); } } } } pysparse-1.1.1/umfpack/umf_fsize.h0000644010116400000240000000116211402270115016133 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; pysparse-1.1.1/umfpack/umf_garbage_collection.c0000644010116400000240000005151211402270073020620 0ustar wd15dialout/* ========================================================================== */ /* === UMF_garbage_collection =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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")) ; } pysparse-1.1.1/umfpack/umf_garbage_collection.h0000644010116400000240000000115511402270076020626 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_get_memory.c0000644010116400000240000001623711402270075017173 0ustar wd15dialout/* ========================================================================== */ /* === UMF_get_memory ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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 ) { Int i, minsize, newsize, newmem, costly, row, col, *Row_tlen, *Col_tlen, n_row, n_col, *Row_degree, *Col_degree ; Unit *mnew, *p ; double nsize, bsize, tsize ; /* ---------------------------------------------------------------------- */ /* 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)) ; } pysparse-1.1.1/umfpack/umf_get_memory.h0000644010116400000240000000116111402270077017170 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_grow_front.c0000644010116400000240000002374611402270050017206 0ustar wd15dialout/* ========================================================================== */ /* === UMF_grow_front ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Current frontal matrix is too small. Make it bigger. */ #include "umf_internal.h" #include "umf_realloc.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 */ /* ---------------------------------------------------------------------- */ 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 ; double s ; /* ---------------------------------------------------------------------- */ /* 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) ; } pysparse-1.1.1/umfpack/umf_grow_front.h0000644010116400000240000000114111402270052017176 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_init_front.c0000644010116400000240000002012311402270045017161 0ustar wd15dialout/* ========================================================================== */ /* === UMF_init_front ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.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) ; } pysparse-1.1.1/umfpack/umf_init_front.h0000644010116400000240000000106411402270046017172 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_init_front ( NumericType *Numeric, WorkType *Work ) ; pysparse-1.1.1/umfpack/umf_internal.h0000644010116400000240000006462111402270112016635 0ustar wd15dialout/* ========================================================================== */ /* === umf_internal.h ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_". */ /* -------------------------------------------------------------------------- */ /* 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) || defined (_win32) || defined (__win32) || defined (WIN32) #define UMF_WINDOWS #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, and MATLAB include files */ #include "amd_internal.h" /* -------------------------------------------------------------------------- */ /* Real/complex and int/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 */ /* -------------------------------------------------------------------------- */ /* The MATLAB mexFunction uses MATLAB's memory manager, while the C-callable * AMD library uses the ANSI C malloc, free, and realloc routines. To use * the mx* memory allocation routines, use -DNUTIL when compiling. */ #undef ALLOCATE #undef FREE #undef REALLOC #ifdef MATLAB_MEX_FILE #ifdef NUTIL /* These functions simply terminate the mexFunction if they fail to allocate * memory. That's too restrictive for UMFPACK. */ #define ALLOCATE mxMalloc #define FREE mxFree #define REALLOCATE mxRealloc #else /* Use internal MATLAB memory allocation routines, used by built-in MATLAB * functions. These are not documented, but are available for use. Their * prototypes are in util.h, but that file is not provided to the MATLAB user. * The advantage of using these routines is that they return NULL if out of * memory, instead of terminating the mexFunction. UMFPACK attempts to allocate * extra space for "elbow room", and then reduces its request if the memory is * not available. That strategy doesn't work with the mx* routines. */ void *utMalloc (size_t size) ; void utFree (void *p) ; void *utRealloc (void *p, size_t size) ; #define ALLOCATE utMalloc #define FREE utFree #define REALLOCATE utRealloc #endif #else #ifdef MATHWORKS /* Compiling as a built-in routine. Since out-of-memory conditions are checked * after every allocation, we can use ut* routines here. */ #define ALLOCATE utMalloc #define FREE utFree #define REALLOCATE utRealloc #else /* use the ANSI C memory allocation routines */ #define ALLOCATE malloc #define FREE free #define REALLOCATE realloc #endif #endif /* -------------------------------------------------------------------------- */ /* 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 15974 #define SYMBOLIC_VALID 41934 #endif #ifdef DLONG #define NUMERIC_VALID 399789120 #define SYMBOLIC_VALID 399192913 #endif #ifdef ZINT #define NUMERIC_VALID 17954 #define SYMBOLIC_VALID 40923 #endif #ifdef ZLONG #define NUMERIC_VALID 129987654 #define SYMBOLIC_VALID 110291234 #endif typedef struct /* NumericType */ { double flops, /* "true" flop count */ relpt, /* relative pivot tolerance used */ relpt2, /* relative pivot tolerance used for sym. */ 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 */ unz, /* number of nonzero entries in U, excl. diagonal */ 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 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 pysparse-1.1.1/umfpack/umf_is_permutation.c0000644010116400000240000000302211402270072020047 0ustar wd15dialout/* ========================================================================== */ /* === UMF_is_permutation =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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) ; } pysparse-1.1.1/umfpack/umf_is_permutation.h0000644010116400000240000000110411402270075020056 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_is_permutation ( const Int P [ ], Int W [ ], Int n, Int r ) ; pysparse-1.1.1/umfpack/umf_kernel.c0000644010116400000240000002234111402270102016264 0ustar wd15dialout/* ========================================================================== */ /* === UMF_kernel =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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 ; /* ---------------------------------------------------------------------- */ /* 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 ; #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) ; 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) ; 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) ; 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) ; } pysparse-1.1.1/umfpack/umf_kernel.h0000644010116400000240000000130011402270104016263 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_kernel_init.c0000644010116400000240000007063411402270045017325 0ustar wd15dialout/* ========================================================================== */ /* === UMF_kernel_init ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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_free.h" #include "umf_scale.h" /* ========================================================================== */ /* === packsp =============================================================== */ /* ========================================================================== */ /* remove zero entries from a singleton 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 */ Unit *Memory /* contains the sparse vector on input and output */ ) { Entry x, *Bx, *Bx2 ; Int p, i, len, len_new, *Bi, *Bi2 ; double s ; /* 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 */ if (IS_ZERO (x)) 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 */ /* ---------------------------------------------------------------------- */ 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, **Rpi, nempty_row, dense_row_threshold, empty_elements, rpi, rpx ; double unused = 0, *Rs, rsmin, rsmax, rs ; Entry *D, *C, x, *Lval, pivot_value, **Rpx ; Element *ep ; Unit *Memory ; #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->maxfrsize = 0 ; Numeric->maxnrows = 0 ; Numeric->maxncols = 0 ; Numeric->flops = 0. ; Numeric->n1 = n1 ; /* ---------------------------------------------------------------------- */ /* 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++) { double value ; Entry aij ; 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 [p], Az [p]) ; 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)) { /* 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) ; for (i = 0 ; i < nn ; i++) { Diagonal_map [i] = EMPTY ; Diagonal_imap [i] = EMPTY ; } for (k = n1 ; k < nn - nempty ; k++) { newrow = Symbolic->Diagonal_map [k] ; Diagonal_map [k] = newrow ; Diagonal_imap [newrow] = k ; } } /* ---------------------------------------------------------------------- */ /* 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 */ } /* 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 [pa], Az [pa]) ; /* scale the value using the scale factors, Rs */ if (do_scale) { #ifndef NRECIPROCAL if (do_recip) { SCALE_RECIP (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 long) :: */ DEBUGm4 (("bad U singleton row (too long)\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 long)\n")) ; return (FALSE) ; /* pattern changed */ } Li [llen] = newrow ; Lval [llen] = x ; llen++ ; } } if (llen != lilen) { /* :: pattern change (singleton column too long) :: */ 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 [pa], Az [pa]) ; /* scale the value using the scale factors, Rs */ if (do_scale) { #ifndef NRECIPROCAL if (do_recip) { /* multiply by the reciprocal */ SCALE_RECIP (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 long)\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 long)\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 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], Memory) ; Numeric->lnz += Lilen [k] ; DEBUGm4 (("\nPrune singleton U row "ID"\n", k)) ; pnew = packsp (pnew, &Uip [k], &Uilen [k], 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) ; } } #ifndef NDEBUG if (prefer_diagonal) { Int *InvCperm, newcol ; Entry aij ; UMF_dump_diagonal_map (Diagonal_map, Diagonal_imap, n1, nn, nempty) ; 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 [p], Az [p]) ; 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_RECIP (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) ; } pysparse-1.1.1/umfpack/umf_kernel_init.h0000644010116400000240000000130511402270045017317 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_kernel_wrapup.c0000644010116400000240000003042111402270111017660 0ustar wd15dialout/* ========================================================================== */ /* === UMF_kernel_wrapup ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The matrix is factorized. Finish the LU data structure. */ #include "umf_internal.h" GLOBAL void UMF_kernel_wrapup ( NumericType *Numeric, SymbolicType *Symbolic, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ 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 ; Entry *D, pivot_value ; double d ; #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). */ } pysparse-1.1.1/umfpack/umf_kernel_wrapup.h0000644010116400000240000000112411402270114017666 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_kernel_wrapup ( NumericType *Numeric, SymbolicType *Symbolic, WorkType *Work ) ; pysparse-1.1.1/umfpack/umf_lhsolve.c0000644010116400000240000001453211402270101016462 0ustar wd15dialout#define CONJUGATE_SOLVE /* ========================================================================== */ /* === UMF_ltsolve ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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 */ ) { Int k, deg, *ip, j, row, *Lpos, *Lilen, kstart, kend, *Lip, llen, lp, pos, npiv, n1, *Li ; Entry *xp, xk, *Lval ; /* ---------------------------------------------------------------------- */ 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)) ; } pysparse-1.1.1/umfpack/umf_local_search.c0000644010116400000240000016344111402270112017433 0ustar wd15dialout/* ========================================================================== */ /* === UMF_local_search ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_row_search.h" #include "umf_mem_free_tail_block.h" /* Version 4.1: relaxed amalgamation control parameters are now fixed, and * cannot be changed via Control [..] settings, as they could in Version 4.0. */ #define RELAX1 0.25 /* this was UMFPACK_DEFAULT_RELAXED_AMALGAMATION */ #define SYM_RELAX1 0.0 /* this is new to Version 4.1 */ #define RELAX2 0.1 /* this was UMFPACK_DEFAULT_RELAXED2_AMALGAMATION */ #define RELAX3 0.125 /* this was UMFPACK_DEFAULT_RELAXED3_AMALGAMATION */ /* ========================================================================== */ /* === 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 */ /* ---------------------------------------------------------------------- */ Entry *Flblock, *Fublock, *Fs, *Fcblock, *C, *Wx, *Wy, *Fu, *Flublock, *Flu ; double relax1 ; 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 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 */ #ifdef USE_NO_BLAS /* no BLAS available - use plain C code instead */ 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 ; } #else BLAS_TRSV (fnpiv, Flublock, Flu, nb) ; #endif } /* ------------------------------------------------------------------ */ /* 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 USE_NO_BLAS /* 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 && Work->pivcol < Work->n_col - Symbolic->nempty_col) { Diagonal_map = Work->Diagonal_map ; Diagonal_imap = Work->Diagonal_imap ; ASSERT (Diagonal_map != (Int *) NULL) ; ASSERT (Diagonal_imap != (Int *) NULL) ; 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->n1, Symbolic->n_col, Symbolic->nempty_col) ; #endif } return (UMFPACK_OK) ; } pysparse-1.1.1/umfpack/umf_local_search.h0000644010116400000240000000112211402270114017425 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_local_search ( NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; pysparse-1.1.1/umfpack/umf_lsolve.c0000644010116400000240000001030211402270036016310 0ustar wd15dialout/* ========================================================================== */ /* === UMF_lsolve =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" GLOBAL double UMF_lsolve ( NumericType *Numeric, Entry X [ ], /* b on input, solution x on output */ Int Pattern [ ] /* a work array of size n */ ) { Int k, deg, *ip, j, row, *Lpos, *Lilen, *Lip, llen, lp, newLchain, pos, npiv, n1, *Li ; Entry *xp, xk, *Lval ; /* ---------------------------------------------------------------------- */ 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)) ; } pysparse-1.1.1/umfpack/umf_lsolve.h0000644010116400000240000000110511402270040016311 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL double UMF_lsolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; pysparse-1.1.1/umfpack/umf_ltsolve.c0000644010116400000240000001450211402270056016504 0ustar wd15dialout/* ========================================================================== */ /* === UMF_ltsolve ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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 */ ) { Int k, deg, *ip, j, row, *Lpos, *Lilen, kstart, kend, *Lip, llen, lp, pos, npiv, n1, *Li ; Entry *xp, xk, *Lval ; /* ---------------------------------------------------------------------- */ 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)) ; } pysparse-1.1.1/umfpack/umf_ltsolve.h0000644010116400000240000000124611402270057016513 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; pysparse-1.1.1/umfpack/umf_malloc.c0000644010116400000240000000554311402270053016265 0ustar wd15dialout/* ========================================================================== */ /* === UMF_malloc =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" #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 umf_config.h for the memory allocator selection */ p = ALLOCATE (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) ; } pysparse-1.1.1/umfpack/umf_malloc.h0000644010116400000240000000122311402270054016262 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #if defined (UMF_MALLOC_COUNT) || !defined (NDEBUG) GLOBAL extern Int UMF_malloc_count ; #endif GLOBAL void *UMF_malloc ( Int n_objects, size_t size_of_object ) ; pysparse-1.1.1/umfpack/umf_mem_alloc_element.c0000644010116400000240000000514611402270035020456 0ustar wd15dialout/* ========================================================================== */ /* === UMF_mem_alloc_element ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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) ; } pysparse-1.1.1/umfpack/umf_mem_alloc_element.h0000644010116400000240000000123011402270040020445 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_mem_alloc_head_block.c0000644010116400000240000000350111402270062021071 0ustar wd15dialout/* ========================================================================== */ /* === UMF_mem_alloc_head_block ============================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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) ; } pysparse-1.1.1/umfpack/umf_mem_alloc_head_block.h0000644010116400000240000000107211402270064021101 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_mem_alloc_head_block ( NumericType *Numeric, Int nunits ) ; pysparse-1.1.1/umfpack/umf_mem_alloc_tail_block.c0000644010116400000240000001011711402270042021120 0ustar wd15dialout/* ========================================================================== */ /* === UMF_mem_alloc_tail_block ============================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ #include "umf_internal.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) ; } pysparse-1.1.1/umfpack/umf_mem_alloc_tail_block.h0000644010116400000240000000107211402270043021126 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_mem_alloc_tail_block ( NumericType *Numeric, Int nunits ) ; pysparse-1.1.1/umfpack/umf_mem_free_tail_block.c0000644010116400000240000001111211402270106020744 0ustar wd15dialout/* ========================================================================== */ /* === UMF_mem_free_tail_block ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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))) ; } pysparse-1.1.1/umfpack/umf_mem_free_tail_block.h0000644010116400000240000000106511402270110020752 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_mem_free_tail_block ( NumericType *Numeric, Int i ) ; pysparse-1.1.1/umfpack/umf_mem_init_memoryspace.c0000644010116400000240000000432711402270065021225 0ustar wd15dialout/* ========================================================================== */ /* === UMF_mem_init_memoryspace ============================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ #include "umf_internal.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 } pysparse-1.1.1/umfpack/umf_mem_init_memoryspace.h0000644010116400000240000000105311402270066021224 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_mem_init_memoryspace ( NumericType *Numeric ) ; pysparse-1.1.1/umfpack/umf_realloc.c0000644010116400000240000000446111402270066016441 0ustar wd15dialout/* ========================================================================== */ /* === UMF_realloc ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" #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 umf_config.h for the memory allocator selection */ p2 = REALLOCATE (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) ; } pysparse-1.1.1/umfpack/umf_realloc.h0000644010116400000240000000110011402270070016424 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void *UMF_realloc ( void *p, Int n_objects, size_t size_of_object ) ; pysparse-1.1.1/umfpack/umf_report_perm.c0000644010116400000240000000411011402270104017336 0ustar wd15dialout/* ========================================================================== */ /* === UMF_report_perm ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.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) ; } pysparse-1.1.1/umfpack/umf_report_perm.h0000644010116400000240000000112111402270107017345 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_report_vector.c0000644010116400000240000000547711402270100017712 0ustar wd15dialout/* ========================================================================== */ /* === UMF_report_vector ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.h" /* ========================================================================== */ /* === print_value ========================================================== */ /* ========================================================================== */ PRIVATE void print_value ( Int i, const double Xx [ ], const double Xz [ ], Int scalar /* if true, then print real part only */ ) { Entry *X, xi ; /* if Xz is null, then X is in "merged" format (compatible with Entry, */ /* and ANSI C99 double _Complex type). */ X = (Entry *) Xx ; PRINTF ((" "ID" :", INDEX (i))) ; if (scalar) { PRINT_SCALAR (Xx [i]) ; } else { if (Xz != (double *) NULL) { ASSIGN (xi, Xx [i], Xz [i]) ; } else { xi = X [i] ; } 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) ; } pysparse-1.1.1/umfpack/umf_report_vector.h0000644010116400000240000000116111402270100017701 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_row_search.c0000644010116400000240000005532511402270033017153 0ustar wd15dialout/* ========================================================================== */ /* === UMF_row_search ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) ; } pysparse-1.1.1/umfpack/umf_row_search.h0000644010116400000240000000164111402270035017152 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 pysparse-1.1.1/umfpack/umf_scale.c0000644010116400000240000000727011402270055016106 0ustar wd15dialout/* ========================================================================== */ /* === UMF_scale ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Divide a vector of stride 1 by the pivot value. */ #include "umf_internal.h" GLOBAL void UMF_scale ( Int n, Entry pivot, Entry X [ ] ) { Int i ; Entry x ; double s ; /* ---------------------------------------------------------------------- */ /* 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] ; if (IS_NONZERO (x)) { DIV (X [i], x, pivot) ; } } } else { /* ------------------------------------------------------------------ */ /* normal case. select the x/pivot or x * (1/pivot) method */ /* ------------------------------------------------------------------ */ /* The pivot is not tiny, and is not NaN. Don't bother to check for * zeros in the pivot column, X. */ #if !defined (NRECIPROCAL) && !(defined (__GNUC__) && defined (COMPLEX)) /* -------------------------------------------------------------- */ /* multiply x by (1/pivot) */ /* -------------------------------------------------------------- */ /* Slightly less accurate, but faster. It allows the use of * the level-1 BLAS dscal or zscal routine. This not used when * UMFPACK is used in MATLAB (either as a built-in routine, or as * a mexFunction). * * Using gcc version 3.2 can cause the following code to fail for * some complex matrices (not all), with or without the BLAS. This * was found in Red Hat Linux 7.3 on a Dell Latitude C840 with a * Pentium 4M. Thus, this code is not used when gcc is used, for * the complex case. * * It works just fine with Intel's icc compiler, version 7.0. */ /* pivot = 1 / pivot */ RECIPROCAL (pivot) ; #if defined (USE_NO_BLAS) for (i = 0 ; i < n ; i++) { /* X [i] *= pivot ; */ x = X [i] ; MULT (X [i], x, pivot) ; } #else BLAS_SCAL (n, pivot, X) ; #endif #else /* -------------------------------------------------------------- */ /* divide x by the pivot */ /* -------------------------------------------------------------- */ /* This is slightly more accurate, particularly if the pivot column * consists of only IEEE subnormals. Always do this if UMFPACK is * being compiled as a built-in routine or mexFunction in MATLAB, * or if gcc is being used with complex matrices. */ for (i = 0 ; i < n ; i++) { /* X [i] /= pivot ; */ x = X [i] ; DIV (X [i], x, pivot) ; } #endif } } pysparse-1.1.1/umfpack/umf_scale.h0000644010116400000240000000105711402270056016111 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_scale ( Int n, Entry alpha, Entry X [ ] ) ; pysparse-1.1.1/umfpack/umf_scale_column.c0000644010116400000240000003342211402270073017461 0ustar wd15dialout/* ========================================================================== */ /* === UMF_scale_column ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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 */ /* ---------------------------------------------------------------------- */ 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 ; Entry pivot_value, *Fcol, *Flublock, *Flblock, *Fublock, *Fcblock ; #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 } pysparse-1.1.1/umfpack/umf_scale_column.h0000644010116400000240000000106711402270076017471 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL void UMF_scale_column ( NumericType *Numeric, WorkType *Work ) ; pysparse-1.1.1/umfpack/umf_set_stats.c0000644010116400000240000001332711402270053017026 0ustar wd15dialout/* ========================================================================== */ /* === UMF_set_stats ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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 ; } pysparse-1.1.1/umfpack/umf_set_stats.h0000644010116400000240000000146011402270054017027 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_singletons.c0000644010116400000240000006122211402270115017176 0ustar wd15dialout/* ========================================================================== */ /* === UMF_singletons ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 * 0 x x x x x x x x * 0 0 x x x x x x x * 0 0 0 x 0 0 0 0 0 * 0 0 0 x x 0 0 0 0 * 0 0 0 x x s s s s * 0 0 0 x x s s s s * 0 0 0 x x s s s s * 0 0 0 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). */ #include "umf_internal.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) ; 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 */ /* 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) { /* 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 { /* 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 */ /* ---------------------------------------------------------------------- */ 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 */ /* ---------------------------------------------------------------------- */ 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 ; s < n_col - nempty_col ; s++) { if (Cperm [s] != Rperm [s]) { is_sym = FALSE ; break ; } } } 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) ; } pysparse-1.1.1/umfpack/umf_singletons.h0000644010116400000240000000160111402270033017175 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 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 [ ] ) ; pysparse-1.1.1/umfpack/umf_solve.c0000644010116400000240000010057711402270050016146 0ustar wd15dialout/* ========================================================================== */ /* === UMF_solve ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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). */ #include "umf_internal.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 */ /* ---------------------------------------------------------------------- */ Int *Rperm, *Cperm, i, n, p, step, j, nz, status, p2, do_scale ; Entry axx, wi, xj, zi, xi, aij, *W, *Z, *S, *X, bi ; double omega [3], d, *Z2, *Y, z2i, yi, *B2, *Rs, flops ; #ifndef NRECIPROCAL Int do_recip = Numeric->do_recip ; #endif /* ---------------------------------------------------------------------- */ /* initializations */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG UMF_dump_lu (Numeric) ; ASSERT (Numeric && Xx && Bx && Pattern && SolveWork && Info) ; #ifdef COMPLEX ASSERT (Xz && Bz) ; #endif #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 X = (Entry *) (SolveWork + 2*n) ; /* Entry X [0..n-1] */ if (irstep > 0) { if (!Ap || !Ai || !Ax || !Az) { return (UMFPACK_ERROR_argument_missing) ; } 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 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 [p], Az [p]) ; 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 [i], Bz [i]) ; 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 [i], Bz [i]) ; SCALE_RECIP (X [i], Rs [i]) ; } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { ASSIGN (X [i], Bx [i], Bz [i]) ; 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 [Rperm [i]], Bz [Rperm [i]]) ; } } } else { for (i = 0 ; i < n ; i++) { /* Z [i] = B [i] ; */ ASSIGN (Z [i], Bx [i], Bz [i]) ; } 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 [p], Az [p]) ; 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_RECIP (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 [i], Bz [i]) ; 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 [p], Az [p]) ; 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_RECIP (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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [i], Bz [i]) ; 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 [Cperm [i]], Bz [Cperm [i]]) ; } } else { /* Z = b - A' x */ for (i = 0 ; i < n ; i++) { /* Z [i] = B [i] ; */ ASSIGN (Z [i], Bx [i], Bz [i]) ; } 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 [p], Az [p]) ; 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_RECIP (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_RECIP (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] += W [i] ; */ ASSEMBLE (X [i], W [i]) ; } } /* -------------------------------------------------------------- */ /* 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 [i], Bz [i]) ; z2i = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* axx = conjugate (Ax [p]) * X [Ai [p]] ; */ ASSIGN (aij, Ax [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [p], Az [p]) ; 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 [i], Bz [i]) ; 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 [Cperm [i]], Bz [Cperm [i]]) ; } } else { /* Z = b - A.' x */ for (i = 0 ; i < n ; i++) { /* Z [i] = B [i] ; */ ASSIGN (Z [i], Bx [i], Bz [i]) ; } 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 [p], Az [p]) ; 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_RECIP (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_RECIP (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] += W [i] ; */ ASSEMBLE (X [i], W [i]) ; } } /* -------------------------------------------------------------- */ /* 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 [i], Bz [i]) ; z2i = 0. ; p2 = Ap [i+1] ; for (p = Ap [i] ; p < p2 ; p++) { /* axx = Ax [p] * X [Ai [p]] ; */ ASSIGN (aij, Ax [p], Az [p]) ; 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 [Rperm [i]], Bz [Rperm [i]]) ; } 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 [i], Bz [i]) ; } 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 [i], Bz [i]) ; } 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 [i], Bz [i]) ; } 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 [i], Bz [i]) ; } 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 [i], Bz [i]) ; } 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 [i], Bz [i]) ; } 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 [i], Bz [i]) ; } 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 [Cperm [i]], Bz [Cperm [i]]) ; } 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 [Cperm [i]], Bz [Cperm [i]]) ; } 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 [i], Bz [i]) ; } 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 [i], Bz [i]) ; } 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 [ ] */ 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) ; } pysparse-1.1.1/umfpack/umf_solve.h0000644010116400000240000000152311402270052016144 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; pysparse-1.1.1/umfpack/umf_start_front.c0000644010116400000240000002121711402270037017361 0ustar wd15dialout/* ========================================================================== */ /* === UMF_start_front ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_grow_front.h" GLOBAL Int UMF_start_front /* returns TRUE if successful, FALSE otherwise */ ( Int chain, NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) { Int fnrows_max, fncols_max, fnr2, fnc2, fsize, fcurr_size, maxfrsize, overflow, nb, f, cdeg ; double maxbytes ; 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) ; } pysparse-1.1.1/umfpack/umf_start_front.h0000644010116400000240000000114011402270041017352 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_start_front ( Int chain, NumericType *Numeric, WorkType *Work, SymbolicType *Symbolic ) ; pysparse-1.1.1/umfpack/umf_store_lu.c0000644010116400000240000005165611402270056016663 0ustar wd15dialout/* ========================================================================== */ /* === UMF_store_lu ========================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_mem_alloc_head_block.h" #include "umf_mem_free_tail_block.h" #include "umf_get_memory.h" /* ========================================================================== */ GLOBAL Int UMF_store_lu ( NumericType *Numeric, WorkType *Work ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ 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] ; Entry *D, pivot_value, *Lval, *Uval, *Fl1, *Fl2, *Fu1, *Fu2, *Flublock, *Flblock, *Fublock ; #ifndef NDEBUG Int *Col_degree, *Row_degree ; #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 (("\n##################################### STORE 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 ; 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++ ; } 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) ; for (i = kk + 1 ; i < fnpiv ; i++) { Int row2, pos ; Entry 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++) { Int row2, pos ; Entry 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 ; } } else { ASSERT (llen > 0) ; for (i = kk + 1 ; i < fnpiv ; i++) { Int row2, pos ; Entry 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++) { Int row2, pos ; Entry 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 ; } } DEBUG4 (("llen "ID" lnzx "ID"\n", llen, lnzx)) ; ASSERT (llen == lnzx) ; ASSERT (lnz <= llen) ; DEBUG4 (("lnz "ID" \n", lnz)) ; Numeric->lnz += lnz ; Lnz [kk] = lnz ; 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) ; 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++ ; } 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) ; for (i = kk + 1 ; i < fnpiv ; i++) { Int col2, pos ; Entry 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++) { Int col2, pos ; Entry x = Fu2 [i] ; if (IS_ZERO (x)) continue ; col2 = Fcols [i] ; pos = ulen++ ; Upattern [pos] = col2 ; Upos [col2] = pos ; Uval [pos] = x ; } } else { ASSERT (ulen > 0) ; /* store the numerical entries and find new nonzeros */ for (i = kk + 1 ; i < fnpiv ; i++) { Int col2, pos ; Entry 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++) { Int col2, pos ; Entry 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 ; } } ASSERT (ulen == unzx) ; ASSERT (unz <= ulen) ; DEBUG4 (("unz "ID" \n", unz)) ; Numeric->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 */ 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) ; } pysparse-1.1.1/umfpack/umf_store_lu.h0000644010116400000240000000106211402270060016645 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_store_lu ( NumericType *Numeric, WorkType *Work ) ; pysparse-1.1.1/umfpack/umf_symbolic_usage.c0000644010116400000240000000305011402270037020014 0ustar wd15dialout/* ========================================================================== */ /* === UMF_symbolic_usage =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* Returns the final size of the Symbolic object, in Units */ #include "umf_internal.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) ; } pysparse-1.1.1/umfpack/umf_symbolic_usage.h0000644010116400000240000000116111402270041020015 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_transpose.c0000644010116400000240000001664311402270111017032 0ustar wd15dialout/* ========================================================================== */ /* === UMF_transpose ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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_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 ; /* ---------------------------------------------------------------------- */ /* 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)) { 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 do_values = do_values && Az && Rz ; #endif #ifdef COMPLEX if (do_conjugate && do_values) { if (Q != (Int *) NULL) { /* 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,:)' */ 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 #endif { if (Q != (Int *) NULL) { if (do_values) { /* 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 } } } 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) { /* 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 } } } 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)) ; #endif return (UMFPACK_OK) ; } pysparse-1.1.1/umfpack/umf_transpose.h0000644010116400000240000000151211402270114017027 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; pysparse-1.1.1/umfpack/umf_triplet.h0000644010116400000240000000334411402270044016503 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; pysparse-1.1.1/umfpack/umf_triplet_map_nox.c0000644010116400000240000002202411402270045020214 0ustar wd15dialout#define DO_MAP /* ========================================================================== */ /* === UMF_triplet ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 occured. 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_malloc.h" #include "umf_free.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 /* ---------------------------------------------------------------------- */ /* 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 [k], Tz [k]) ; 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 Rx [p] = Tx [k] ; #ifdef COMPLEX Rz [p] = Tz [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 */ Rx [pj] += Rx [p] ; #ifdef COMPLEX Rz [pj] += Rz [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 Rx [pdest] = Rx [p] ; #ifdef COMPLEX Rz [pdest] = Rz [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 Ax [cp] = Rx [p] ; #ifdef COMPLEX Az [cp] = Rz [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) ; } pysparse-1.1.1/umfpack/umf_triplet_map_x.c0000644010116400000240000002204611402270110017654 0ustar wd15dialout#define DO_MAP #define DO_VALUES /* ========================================================================== */ /* === UMF_triplet ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 occured. 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_malloc.h" #include "umf_free.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 /* ---------------------------------------------------------------------- */ /* 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 [k], Tz [k]) ; 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 Rx [p] = Tx [k] ; #ifdef COMPLEX Rz [p] = Tz [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 */ Rx [pj] += Rx [p] ; #ifdef COMPLEX Rz [pj] += Rz [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 Rx [pdest] = Rx [p] ; #ifdef COMPLEX Rz [pdest] = Rz [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 Ax [cp] = Rx [p] ; #ifdef COMPLEX Az [cp] = Rz [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) ; } pysparse-1.1.1/umfpack/umf_triplet_nomap_nox.c0000644010116400000240000002200511402270106020546 0ustar wd15dialout/* ========================================================================== */ /* === UMF_triplet ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 occured. 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_malloc.h" #include "umf_free.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 /* ---------------------------------------------------------------------- */ /* 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 [k], Tz [k]) ; 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 Rx [p] = Tx [k] ; #ifdef COMPLEX Rz [p] = Tz [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 */ Rx [pj] += Rx [p] ; #ifdef COMPLEX Rz [pj] += Rz [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 Rx [pdest] = Rx [p] ; #ifdef COMPLEX Rz [pdest] = Rz [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 Ax [cp] = Rx [p] ; #ifdef COMPLEX Az [cp] = Rz [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) ; } pysparse-1.1.1/umfpack/umf_triplet_nomap_x.c0000644010116400000240000002202711402270061020215 0ustar wd15dialout#define DO_VALUES /* ========================================================================== */ /* === UMF_triplet ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 occured. 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_malloc.h" #include "umf_free.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 /* ---------------------------------------------------------------------- */ /* 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 [k], Tz [k]) ; 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 Rx [p] = Tx [k] ; #ifdef COMPLEX Rz [p] = Tz [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 */ Rx [pj] += Rx [p] ; #ifdef COMPLEX Rz [pj] += Rz [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 Rx [pdest] = Rx [p] ; #ifdef COMPLEX Rz [pdest] = Rz [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 Ax [cp] = Rx [p] ; #ifdef COMPLEX Az [cp] = Rz [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) ; } pysparse-1.1.1/umfpack/umf_tuple_lengths.c0000644010116400000240000001062211402270046017667 0ustar wd15dialout/* ========================================================================== */ /* === UMF_tuple_lengths ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" GLOBAL Int UMF_tuple_lengths /* return memory usage */ ( NumericType *Numeric, WorkType *Work, double *p_dusage /* output argument */ ) { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ 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 ; double dusage ; 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) ; } pysparse-1.1.1/umfpack/umf_tuple_lengths.h0000644010116400000240000000111311402270047017670 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_tuple_lengths ( NumericType *Numeric, WorkType *Work, double *dusage ) ; pysparse-1.1.1/umfpack/umf_uhsolve.c0000644010116400000240000002112311402270103016467 0ustar wd15dialout#define CONJUGATE_SOLVE /* ========================================================================== */ /* === UMF_utsolve ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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 */ /* ---------------------------------------------------------------------- */ Int k, deg, j, *ip, col, *Upos, *Uilen, kstart, kend, up, *Uip, n, uhead, ulen, pos, npiv, n1, *Ui ; Entry *xp, xk, *D, *Uval ; /* ---------------------------------------------------------------------- */ /* 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)) ; /* 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 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 */ /* -------------------------------------------------------------- */ /* 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 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) ; } 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 ; } #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)); } pysparse-1.1.1/umfpack/umf_usolve.c0000644010116400000240000001345711402270110016330 0ustar wd15dialout/* ========================================================================== */ /* === UMF_usolve =========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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 */ /* ---------------------------------------------------------------------- */ Int k, deg, j, *ip, col, *Upos, *Uilen, pos, *Uip, n, ulen, up, newUchain, npiv, n1, *Ui ; Entry *xp, xk, *D, *Uval ; /* ---------------------------------------------------------------------- */ /* 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 */ /* ---------------------------------------------------------------------- */ /* 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]) ; } 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++ ; } /* Go ahead and divide by zero if D [k] is zero */ /* X [k] = xk / D [k] ; */ DIV (X [k], xk, D [k]) ; /* ------------------------------------------------------------------ */ /* 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]) ; } } /* Go ahead and divide by zero if D [k] is zero */ /* X [k] = xk / D [k] ; */ DIV (X [k], xk, D [k]) ; } #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)); } pysparse-1.1.1/umfpack/umf_usolve.h0000644010116400000240000000110511402270113016323 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL double UMF_usolve ( NumericType *Numeric, Entry X [ ], Int Pattern [ ] ) ; pysparse-1.1.1/umfpack/umf_utsolve.c0000644010116400000240000002107311402270060016511 0ustar wd15dialout/* ========================================================================== */ /* === UMF_utsolve ========================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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 */ /* ---------------------------------------------------------------------- */ Int k, deg, j, *ip, col, *Upos, *Uilen, kstart, kend, up, *Uip, n, uhead, ulen, pos, npiv, n1, *Ui ; Entry *xp, xk, *D, *Uval ; /* ---------------------------------------------------------------------- */ /* 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)) ; /* 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 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 */ /* -------------------------------------------------------------- */ /* 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 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) ; } 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 ; } #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)); } pysparse-1.1.1/umfpack/umf_utsolve.h0000644010116400000240000000124711402270061016520 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; pysparse-1.1.1/umfpack/umf_valid_numeric.c0000644010116400000240000000321211402270043017625 0ustar wd15dialout/* ========================================================================== */ /* === UMF_valid_numeric ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" 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) ; } pysparse-1.1.1/umfpack/umf_valid_numeric.h0000644010116400000240000000104311402270044017633 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_valid_numeric ( NumericType *Numeric ) ; pysparse-1.1.1/umfpack/umf_valid_symbolic.c0000644010116400000240000000325411402270072020014 0ustar wd15dialout/* ========================================================================== */ /* === UMF_valid_symbolic =================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ #include "umf_internal.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) ; } pysparse-1.1.1/umfpack/umf_valid_symbolic.h0000644010116400000240000000104611402270074020020 0ustar wd15dialout/* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ GLOBAL Int UMF_valid_symbolic ( SymbolicType *Symbolic ) ; pysparse-1.1.1/umfpack/umf_version.h0000644010116400000240000010534411402270044016510 0ustar wd15dialout/* ========================================================================== */ /* === umf_version.h ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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, long's as integers ZLONG: complex double precision, 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 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 (MATHWORKS) /* The MathWorks has their own macros in util.h that handle NaN's properly. */ #define SCALAR_IS_NAN(x) (utIsNaN (x)) #define SCALAR_IS_ZERO(x) (utEQZero (x)) #define SCALAR_IS_NONZERO(x) (utNEZero (x)) #define SCALAR_IS_LTZERO(x) (utLTZero (x)) #elif defined (UMF_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 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 REAL_COMPONENT(c) (c) #define IMAG_COMPONENT(c) (0.) #define ASSIGN(c,s1,s2) { (c) = (s1) ; } #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) ; } #ifndef NRECIPROCAL #define SCALE_RECIP(c,s) { (c) *= (s) ; } #endif #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 RECIPROCAL(c) { (c) = 1.0 / (c) ; } #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) /* -------------------------------------------------------------------------- */ /* c = (s1) + (s2)i */ #define ASSIGN(c,s1,s2) \ { \ (c).Real = (s1) ; \ (c).Imag = (s2) ; \ } /* -------------------------------------------------------------------------- */ /* 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, where s is the reciprocal scale factor. Not used if * NRECIPROCAL is defined at compile time. */ #ifndef NRECIPROCAL #define SCALE_RECIP(c,s) \ { \ (c).Real *= (s) ; \ (c).Imag *= (s) ; \ } #endif /* -------------------------------------------------------------------------- */ /* 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, be careful to avoid underflow and overflow */ #ifdef MATHWORKS #define DIV(c,a,b) \ { \ (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (b).Imag, \ &((c).Real), &((c).Imag)) ; \ } #else /* This uses ACM Algo 116, by R. L. Smith, 1962. */ /* c can be the same variable as a or b. */ /* Ignore NaN case for double relop br>=bi. */ #define DIV(c,a,b) \ { \ double r, den, ar, ai, br, bi ; \ br = (b).Real ; \ bi = (b).Imag ; \ ar = (a).Real ; \ ai = (a).Imag ; \ if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \ { \ r = bi / br ; \ den = br + r * bi ; \ (c).Real = (ar + ai * r) / den ; \ (c).Imag = (ai - ar * r) / den ; \ } \ else \ { \ r = br / bi ; \ den = r * br + bi ; \ (c).Real = (ar * r + ai) / den ; \ (c).Imag = (ai * r - ar) / den ; \ } \ } #endif /* -------------------------------------------------------------------------- */ /* c = 1/c, be careful to avoid underflow and overflow */ /* Not used if MATHWORKS is defined. */ /* This uses ACM Algo 116, by R. L. Smith, 1962. */ /* Ignore NaN case for double relop cr>=ci. */ #define RECIPROCAL(c) \ { \ double r, den, cr, ci ; \ cr = (c).Real ; \ ci = (c).Imag ; \ if (SCALAR_ABS (cr) >= SCALAR_ABS (ci)) \ { \ r = ci / cr ; \ den = cr + r * ci ; \ (c).Real = 1.0 / den ; \ (c).Imag = - r / den ; \ } \ else \ { \ r = cr / ci ; \ den = r * cr + ci ; \ (c).Real = r / den ; \ (c).Imag = - 1.0 / den ; \ } \ } /* -------------------------------------------------------------------------- */ /* c = a/conjugate(b), be careful to avoid underflow and overflow */ #ifdef MATHWORKS #define DIV_CONJ(c,a,b) \ { \ (void) utDivideComplex ((a).Real, (a).Imag, (b).Real, (-(b).Imag), \ &((c).Real), &((c).Imag)) ; \ } #else /* This uses ACM Algo 116, by R. L. Smith, 1962. */ /* c can be the same variable as a or b. */ /* Ignore NaN case for double relop br>=bi. */ #define DIV_CONJ(c,a,b) \ { \ double r, den, ar, ai, br, bi ; \ br = (b).Real ; \ bi = (b).Imag ; \ ar = (a).Real ; \ ai = (a).Imag ; \ if (SCALAR_ABS (br) >= SCALAR_ABS (bi)) \ { \ r = (-bi) / br ; \ den = br - r * bi ; \ (c).Real = (ar + ai * r) / den ; \ (c).Imag = (ai - ar * r) / den ; \ } \ else \ { \ r = br / (-bi) ; \ den = r * br - bi; \ (c).Real = (ar * r + ai) / den ; \ (c).Imag = (ai * r - ar) / den ; \ } \ } #endif /* -------------------------------------------------------------------------- */ /* 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 + amag^2) */ #ifdef MATHWORKS #define ABS(s,a) \ { \ (s) = utFdlibm_hypot ((a).Real, (a).Imag) ; \ } #else /* Ignore NaN case for the double relops ar>=ai and ar+ai==ar. */ #define ABS(s,a) \ { \ double r, ar, ai ; \ ar = SCALAR_ABS ((a).Real) ; \ ai = SCALAR_ABS ((a).Imag) ; \ if (ar >= ai) \ { \ if (ar + ai == ar) \ { \ (s) = ar ; \ } \ else \ { \ r = ai / ar ; \ (s) = ar * sqrt (1.0 + r*r) ; \ } \ } \ else \ { \ if (ai + ar == ai) \ { \ (s) = ai ; \ } \ else \ { \ r = ar / ai ; \ (s) = ai * sqrt (1.0 + r*r) ; \ } \ } \ } #endif /* -------------------------------------------------------------------------- */ /* 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_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_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 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_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_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_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_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 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_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_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 pysparse-1.1.1/umfpack/umfpack.h0000644010116400000240000004434211402270063015603 0ustar wd15dialout/* ========================================================================== */ /* === umfpack.h ============================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 /* -------------------------------------------------------------------------- */ /* size of Info and Control arrays */ /* -------------------------------------------------------------------------- */ #define UMFPACK_INFO 90 /* these might be larger in future versions */ #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" /* 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" /* -------------------------------------------------------------------------- */ /* Version, copyright, and license */ /* -------------------------------------------------------------------------- */ #define UMFPACK_VERSION "UMFPACK V4.1 (Apr. 30, 2003)" #define UMFPACK_COPYRIGHT \ "UMFPACK: Copyright (c) 2003 by Timothy A. Davis. All Rights Reserved.\n" #define UMFPACK_LICENSE_PART1 \ "\nUMFPACK License:\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 MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY\n" \ " EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.\n" #define UMFPACK_LICENSE_PART2 \ "\n" \ " Permission is hereby granted to use or copy this program, provided\n" \ " that the Copyright, this License, and the Availability of the original\n" \ " version is retained on all copies. User documentation of any code that\n" \ " uses UMFPACK or any modified version of UMFPACK code must cite the\n" \ " Copyright, this License, the Availability note, and \"Used by permission.\"\n" #define UMFPACK_LICENSE_PART3 \ " Permission to modify the code and to distribute modified code is granted,\n" \ " provided the Copyright, this License, and the Availability note are\n" \ " retained, and a notice that the code was modified is included. This\n" \ " software was developed with support from the National Science Foundation,\n" \ " and is provided to you free of charge.\n" \ "\n" \ "Availability: http://www.cise.ufl.edu/research/sparse/umfpack\n" \ "\n" /* -------------------------------------------------------------------------- */ /* contents of Info */ /* -------------------------------------------------------------------------- */ /* Note that umfpack_report.m must coincide with these definitions. */ /* 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 (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 #define UMFPACK_ROW_SINGLETONS 57 #define UMFPACK_N2 58 #define UMFPACK_S_SYMMETRIC 59 /* 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 */ /* 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 [77, 78, 79, 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 */ /* 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!) */ #if 0 /* No longer unused. These parameters are now used for the new symmetric and * 2-by-2 ordering strategies. See 5, 12, 13, and 14, above. */ #define UMFPACK_RELAXED_AMALGAMATION 5 /* unused (was in v4.0) */ #define UMFPACK_PIVOT_OPTION 12 /* unused (was in v3.2) */ #define UMFPACK_RELAXED2_AMALGAMATION 13 /* unused (was in v4.0) */ #define UMFPACK_RELAXED3_AMALGAMATION 14 /* unused (was in v4.0) */ #endif /* Control [18] unused */ /* -------------------------------------------------------------------------- */ /* 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: */ /* -------------------------------------------------------------------------- */ /* Note that the default block sized changed for Version 3.1 and following. * In Version 4.1, the relaxed amalgamation parameters were removed. These are * now fixed internally (see umf_local_search.c), and cannot be changed. * COLAMD aggressive absorption did not exist in v4.0. In v4.1, it is in * use by default (but can be turned off). Aggressive absorption is used by * default in AMD, also. */ #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 #if 0 /* no longer unused: for unsymmetric strategy (were used in v4.0) */ #define UMFPACK_DEFAULT_RELAXED_AMALGAMATION 0.25 /* unused */ #define UMFPACK_DEFAULT_RELAXED2_AMALGAMATION 0.1 /* unused */ #define UMFPACK_DEFAULT_RELAXED3_AMALGAMATION 0.125 /* unused */ #endif /* 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) /* 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) /* replaces errors -[7:10,12,14] */ #define UMFPACK_ERROR_different_pattern (-11) #define UMFPACK_ERROR_invalid_system (-13) #define UMFPACK_ERROR_invalid_permutation (-15) #define UMFPACK_ERROR_internal_error (-911) #define UMFPACK_ERROR_file_IO (-17) /* The following error codes are no longer used. They are left in for * historical reasons. They appeared in Version 4.0. Most of them are combined * into the single UMFPACK_ERROR_invalid_matrix error code (-8). The last one, * UMFPACK_ERROR_problem_too_large, has been removed. This error can no longer * occur. */ #define UMFPACK_ERROR_nz_negative (-7) /* unused */ #define UMFPACK_ERROR_jumbled_matrix (-8) /* unused */ #define UMFPACK_ERROR_Ap0_nonzero (-9) /* unused */ #define UMFPACK_ERROR_row_index_out_of_bounds (-10) /* unused */ #define UMFPACK_ERROR_col_length_negative (-12) /* unused */ #define UMFPACK_ERROR_invalid_triplet (-14) /* unused */ #define UMFPACK_ERROR_problem_too_large (-16) /* unused */ /* -------------------------------------------------------------------------- */ /* 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. */ #endif /* UMFPACK_H */ pysparse-1.1.1/umfpack/umfpack_col_to_triplet.c0000644010116400000240000000404111402270046020671 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_col_to_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) ; } pysparse-1.1.1/umfpack/umfpack_col_to_triplet.h0000644010116400000240000000725511402270050020703 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_col_to_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_col_to_triplet ( int n_col, const int Ap [ ], int Tj [ ] ) ; long umfpack_dl_col_to_triplet ( long n_col, const long Ap [ ], long Tj [ ] ) ; int umfpack_zi_col_to_triplet ( int n_col, const int Ap [ ], int Tj [ ] ) ; long umfpack_zl_col_to_triplet ( long n_col, const long Ap [ ], 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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. */ pysparse-1.1.1/umfpack/umfpack_defaults.c0000644010116400000240000001031111402270074017454 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_defaults ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 USE_NO_BLAS /* 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 /* use mxMalloc, mxFree, mxRealloc, and mexPrintf */ /* use mxAssert if debugging is enabled */ Control [UMFPACK_COMPILED_FOR_MATLAB] = 1 ; #else #ifdef MATHWORKS /* use internal utMalloc, utFree, utRealloc, and utPrintf routines. */ /* use utDivideComplex and utFdlibm_hypot for complex version. */ /* use utAssert if debugging is enabled. */ Control [UMFPACK_COMPILED_FOR_MATLAB] = 2 ; #else /* use ANSI C malloc, free, realloc, and print */ /* use ANSI C assert if debugging is enabled */ Control [UMFPACK_COMPILED_FOR_MATLAB] = 0 ; #endif #endif #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 #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 } pysparse-1.1.1/umfpack/umfpack_defaults.h0000644010116400000240000000434611402270077017477 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_defaults ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 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 long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; umfpack_zl_defaults (Control) ; Purpose: Sets the default control parameter settings. NOTE: new control parameters have been added to the Control array for Version 4.1. These entries were unused in Version 4.0. The default block size for the BLAS has increased from 24 to 32. Some rarely used control parameters have been removed (those that controlled relaxed amalgamation). 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). */ pysparse-1.1.1/umfpack/umfpack_free_numeric.c0000644010116400000240000000372711402270065020325 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_free_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ; } pysparse-1.1.1/umfpack/umfpack_free_numeric.h0000644010116400000240000000334511402270065020326 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_free_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 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 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. */ pysparse-1.1.1/umfpack/umfpack_free_symbolic.c0000644010116400000240000000400011402270046020464 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_free_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ; } pysparse-1.1.1/umfpack/umfpack_free_symbolic.h0000644010116400000240000000336711402270047020511 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_free_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 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 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. */ pysparse-1.1.1/umfpack/umfpack_get_lunz.c0000644010116400000240000000331111402270047017476 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_get_lunz ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) ; } pysparse-1.1.1/umfpack/umfpack_get_lunz.h0000644010116400000240000000753611402270051017513 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_get_lunz ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; long umfpack_dl_get_lunz ( long *lnz, long *unz, long *n_row, long *n_col, 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 ) ; long umfpack_zl_get_lunz ( long *lnz, long *unz, long *n_row, long *n_col, long *nz_udiag, void *Numeric ) ; /* double int Syntax: #include "umfpack.h" void *Numeric ; int status, lnz, unz, n_row, n_col ; status = umfpack_di_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ; double long Syntax: #include "umfpack.h" void *Numeric ; long status, lnz, unz, n_row, n_col ; status = umfpack_dl_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ; complex int Syntax: #include "umfpack.h" void *Numeric ; int status, lnz, unz, n_row, n_col ; status = umfpack_zi_get_lunz (&lnz, &unz, &n_row, &n_col, Numeric) ; complex long Syntax: #include "umfpack.h" void *Numeric ; long status, lnz, unz, n_row, n_col ; status = umfpack_zl_get_lunz (&lnz, &unz, &n_row, &n_col, 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. */ pysparse-1.1.1/umfpack/umfpack_get_numeric.c0000644010116400000240000006322711402270105020157 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_get_numeric ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 */ /* ---------------------------------------------------------------------- */ #ifdef COMPLEX getL = Lp && Lj && Lx && Lz ; getU = Up && Ui && Ux && Uz ; #else getL = Lp && Lj && Lx ; getU = Up && Ui && Ux ; #endif 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 ; for (k = 0 ; k < n_inner ; k++) { Dx [k] = REAL_COMPONENT (D [k]) ; } } #ifdef COMPLEX if (Dz != (double *) NULL) { D = Numeric->D ; for (k = 0 ; k < n_inner ; k++) { Dz [k] = IMAG_COMPONENT (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 */ /* ---------------------------------------------------------------------- */ Int deg, *ip, j, row, n_row, n_col, n_inner, *Lpos, *Lilen, *Lip, p, llen, lnz2, lp, newLchain, k, pos, npiv, *Li, n1 ; Entry *xp, value, *Lval ; /* ---------------------------------------------------------------------- */ /* 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 ; Lx [p] = REAL_COMPONENT (value) ; #ifdef COMPLEX Lz [p] = IMAG_COMPONENT (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 ; Lx [p] = REAL_COMPONENT (value) ; #ifdef COMPLEX Lz [p] = IMAG_COMPONENT (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 ; Lx [p] = 1. ; #ifdef COMPLEX Lz [p] = 0. ; #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 */ /* ---------------------------------------------------------------------- */ Int deg, j, *ip, col, *Upos, *Uilen, *Uip, n_col, ulen, *Usi, unz2, p, k, up, newUchain, pos, npiv, n1 ; Entry *xp, *D, value, *Uval ; #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 ; Ux [p] = REAL_COMPONENT (D [col]) ; #ifdef COMPLEX Uz [p] = IMAG_COMPONENT (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 ; Ux [p] = REAL_COMPONENT (value) ; #ifdef COMPLEX Uz [p] = IMAG_COMPONENT (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 ; Ux [p] = REAL_COMPONENT (value) ; #ifdef COMPLEX Uz [p] = IMAG_COMPONENT (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 } pysparse-1.1.1/umfpack/umfpack_get_numeric.h0000644010116400000240000002157611402270110020161 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_get_numeric ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; long umfpack_dl_get_numeric ( long Lp [ ], long Lj [ ], double Lx [ ], long Up [ ], long Ui [ ], double Ux [ ], long P [ ], long Q [ ], double Dx [ ], 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 ) ; long umfpack_zl_get_numeric ( long Lp [ ], long Lj [ ], double Lx [ ], double Lz [ ], long Up [ ], long Ui [ ], double Ux [ ], double Uz [ ], long P [ ], long Q [ ], double Dx [ ], double Dz [ ], 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 long Syntax: #include "umfpack.h" void *Numeric ; 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 long Syntax: #include "umfpack.h" void *Numeric ; 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) ; 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. Similarly, Lz, Uz and Dz must exist on input for the complex versions. 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. 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 Ux (or Uz for the complex version) 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 complex versions) are passed to umfpack_*_report_matrix (using the "row" form). Future complex version: if Lx is present and Lz is NULL, then both real and imaginary parts will be 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. 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 (or Uz for the complex version) 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 complex versions) are passed to umfpack_*_report_matrix (using the "column" form). Future complex version: if Ux is present and Uz is NULL, then both real and imaginary parts will be 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. 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. Future complex version: if Dx is present and Dz is NULL, then both real and imaginary parts will be 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. If do_recip is returned as zero (false), 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 zero (false). NOTE: this argument is new to version 4.1. 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|). NOTE: this argument is new to version 4.1. void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric. */ pysparse-1.1.1/umfpack/umfpack_get_symbolic.c0000644010116400000240000001014411402270054020327 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_get_symbolic ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) ; } pysparse-1.1.1/umfpack/umfpack_get_symbolic.h0000644010116400000240000003161611402270055020344 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_get_symbolic ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ) ; long umfpack_dl_get_symbolic ( long *n_row, long *n_col, long *n1, long *nz, long *nfr, long *nchains, long P [ ], long Q [ ], long Front_npivcol [ ], long Front_parent [ ], long Front_1strow [ ], long Front_leftmostdesc [ ], long Chain_start [ ], long Chain_maxrows [ ], 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 ) ; long umfpack_zl_get_symbolic ( long *n_row, long *n_col, long *n1, long *nz, long *nfr, long *nchains, long P [ ], long Q [ ], long Front_npivcol [ ], long Front_parent [ ], long Front_1strow [ ], long Front_leftmostdesc [ ], long Chain_start [ ], long Chain_maxrows [ ], 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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. NOTE: this argument is new to version 4.1. 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. It is new to Version 4.0. 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. */ pysparse-1.1.1/umfpack/umfpack_load_numeric.c0000644010116400000240000001206511402270034020312 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_load_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) != 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) ; } pysparse-1.1.1/umfpack/umfpack_load_numeric.h0000644010116400000240000000513011402270037020315 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_load_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_load_numeric ( void **Numeric, char *filename ) ; long umfpack_dl_load_numeric ( void **Numeric, char *filename ) ; int umfpack_zi_load_numeric ( void **Numeric, char *filename ) ; 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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. */ pysparse-1.1.1/umfpack/umfpack_load_symbolic.c0000644010116400000240000001303511402270062020470 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_load_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) != 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) ; } pysparse-1.1.1/umfpack/umfpack_load_symbolic.h0000644010116400000240000000516311402270063020501 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_load_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_load_symbolic ( void **Symbolic, char *filename ) ; long umfpack_dl_load_symbolic ( void **Symbolic, char *filename ) ; int umfpack_zi_load_symbolic ( void **Symbolic, char *filename ) ; 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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. */ pysparse-1.1.1/umfpack/umfpack_numeric.c0000644010116400000240000006700011402270035017313 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_numeric ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 */ /* ---------------------------------------------------------------------- */ NumericType *Numeric ; SymbolicType *Symbolic ; WorkType WorkSpace, *Work ; Int n_row, n_col, n_inner, newsize, i, status, *inew, npiv, ulen, scale ; Unit *mnew ; double Info2 [UMFPACK_INFO], *Info, alloc_init, relpt, relpt2, front_alloc_init, stats [2] ; /* ---------------------------------------------------------------------- */ /* 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) ; relpt = MAX (0.0, MIN (relpt, 1.0)) ; relpt2 = MAX (0.0, MIN (relpt2, 1.0)) ; 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 #ifdef COMPLEX || !Az #endif ) { 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->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 ; /* 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 ) { Int n_row, n_col, n_inner, min_usage, trying ; NumericType *Numeric ; double nsize, bsize ; 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) ; } pysparse-1.1.1/umfpack/umfpack_numeric.h0000644010116400000240000005505711402270040017325 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_numeric ====================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) ; long umfpack_dl_numeric ( const long Ap [ ], const 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] ) ; long umfpack_zl_numeric ( const long Ap [ ], const 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 long Syntax: #include "umfpack.h" void *Symbolic, *Numeric ; 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 long Syntax: #include "umfpack.h" void *Symbolic, *Numeric ; long *Ap, *Ai, status ; double *Ax, *Az, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO] ; status = umfpack_zl_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info) ; 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]. 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)]. Future complex version: if Ax is present and Az is NULL, then both real and imaginary parts will be 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 (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. 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]: 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. 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]: This parameter has changed in V4.1. 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 under MATLAB, since mxMalloc aborts the mexFunction if it fails. The built-in umfpack routine (version 4.0) in MATLAB 6.5 uses utMalloc instead, which avoids this problem. As a mexFunction, utMalloc is used unless -DNUTIL is defined at compile time. The utMalloc routine, and utFree and utRealloc, are not documented. If the mexFunction doesn't work, then compile it with -DNUTIL instead. 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]: This parameter is new to V4.1. 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. 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). ------------------------------------------------------------------------ The following statistics were added to Version 4.1: ------------------------------------------------------------------------ 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. 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. */ pysparse-1.1.1/umfpack/umfpack_qsymbolic.c0000644010116400000240000023065611402270035017664 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_qsymbolic ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ; nzdiag = 0 ; do_nzdiag = (Ax != (double *) NULL) #ifdef COMPLEX && (Az != (double *) NULL) #endif ; #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 */ if (SCALAR_IS_NONZERO (Ax [p]) #ifdef COMPLEX || SCALAR_IS_NONZERO (Az [p]) #endif ) { nzdiag++ ; } } } } DEBUG5 (("\n")) ; } } Sp [n_col - n1] = pp ; ASSERT (AMD_valid (n_row - n1, n_col - n1, Sp, Si)) ; 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 */ /* ---------------------------------------------------------------------- */ 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 ; double knobs [COLAMD_KNOBS], flops, f, r, c, *Info, 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, scale ; 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) ; tol = GET_CONTROL (UMFPACK_2BY2_TOLERANCE, UMFPACK_DEFAULT_2BY2_TOLERANCE) ; 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)) ; tol = MAX (0.0, MIN (tol, 1.0)) ; 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 (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 ; } 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 long integer 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, 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)) ; 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]. * For the auto strategy, switch to the unsymmetric strategy. * Otherwise, if the strategy selected by the user is symmetric or * 2-by-2, then the singletons will be discarded. */ 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 ) ; nzaat = AMD_aat (n2, Sp, Si, 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 */ #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 (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")) ; } } /* ---------------------------------------------------------------------- */ /* 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) { Int *Rp, *Ri, *Blen, *W, nz_papat, nzd2, nweak, unmatched, Clen3 ; double sym2 ; /* ------------------------------------------------------------------ */ /* 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)) ; /* 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 ] */ } /* ---------------------------------------------------------------------- */ /* 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 ; } 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 ; } 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)) ; } } for (i = 0 ; i <= nfr ; i++) { DEBUG1 (("Front "ID" has 1strows: "ID" pivcols "ID"\n", i, f1rows, fpivcol)) ; } #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. Diagonal_map only needs to be defined for * k = n1 to nn - nempty, but go ahead and define it for all of * k = 0 to nn */ 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 (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] ; Diagonal_map [newcol] = newrow ; } } else { for (newcol = 0 ; newcol < nn ; newcol++) { oldcol = Cperm_init [newcol] ; /* no 2-by-2 pivoting in S */ oldrow = oldcol ; newrow = Ci [oldrow] ; Diagonal_map [newcol] = newrow ; } } #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 ; oldrow = Ai [p] ; newrow = Ci [oldrow] ; if (Ax != (double *) NULL #ifdef COMPLEX && Az != (double *) NULL #endif ) { ASSIGN (aij, Ax [p], Az [p]) ; } 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) ; } pysparse-1.1.1/umfpack/umfpack_qsymbolic.h0000644010116400000240000001127111402270040017653 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_qsymbolic ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) ; long umfpack_dl_qsymbolic ( long n_row, long n_col, const long Ap [ ], const long Ai [ ], const double Ax [ ], const 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] ) ; long umfpack_zl_qsymbolic ( long n_row, long n_col, const long Ap [ ], const long Ai [ ], const double Ax [ ], const double Az [ ], const 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 long Syntax: #include "umfpack.h" void *Symbolic ; 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 long Syntax: #include "umfpack.h" void *Symbolic ; 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) ; 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. */ pysparse-1.1.1/umfpack/umfpack_report_control.c0000644010116400000240000003211011402270053020716 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_control =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) { Int prl, nb, irstep, strategy, scale, s ; double drow, dcol, relpt, relpt2, alloc_init, front_alloc_init, amd_alpha, tol, force_fixQ, aggr ; prl = GET_CONTROL (UMFPACK_PRL, UMFPACK_DEFAULT_PRL) ; if (prl < 2) { /* default is to print nothing */ return ; } PRINTF (("\n%s, Control:\n\n", UMFPACK_VERSION)) ; /* ---------------------------------------------------------------------- */ /* 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: 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: 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")) ; } 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")) ; } 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)) ; } /* ---------------------------------------------------------------------- */ /* 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))) ; #if defined (USE_NO_BLAS) PRINTF (("none. UMFPACK will be slow.\n")) ; #elif defined (USE_C_BLAS) PRINTF (("C-BLAS.\n")) ; #elif defined (USE_MATLAB_BLAS) PRINTF (("built-in MATLAB BLAS (ATLAS).\n")) ; #elif defined (USE_SUNPERF_BLAS) PRINTF (("Sun Performance Library BLAS.\n")) ; #elif defined (USE_SCSL_BLAS) PRINTF (("SGI SCSL BLAS.\n")) ; #elif defined (USE_FORTRAN_BLAS) PRINTF (("Fortran BLAS.\n")) ; #endif #ifdef MATLAB_MEX_FILE #ifdef NUTIL PRINTF ((" "ID": compiled for MATLAB" " (uses mxMalloc, mxFree, mxRealloc, and mexPrintf)\n", (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ; #else PRINTF ((" "ID": compiled for MATLAB" " (uses utMalloc, utFree, utRealloc, and mexPrintf)\n", (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ; #endif #else #ifdef MATHWORKS PRINTF ((" "ID": compiled for MATLAB, using internal utility routines\n" " (uses utMalloc, utFree, utRealloc, and utPrintf)\n", (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ; PRINTF ((" (complex version uses utDivideComplex, utFdlibm_hypot)\n")) ; #else PRINTF ((" "ID": compiled for ANSI C" " (uses malloc, free, realloc, and printf)\n", (Int) INDEX (UMFPACK_COMPILED_FOR_MATLAB))) ; #endif #endif #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 #ifndef NDEBUG PRINTF (( "**** Debugging enabled (UMFPACK will be exceedingly slow!) *****************\n" " "ID": compiled with debugging enabled. ", (Int) INDEX (UMFPACK_COMPILED_IN_DEBUG_MODE))) ; #ifdef MATLAB_MEX_FILE PRINTF (("Uses mxAssert.\n")) ; #else #ifdef MATHWORKS PRINTF (("Uses utAssert.\n")) ; #else PRINTF (("Uses ANSI C assert.\n")) ; #endif #endif #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 long: %g Int: %g pointer: %g" " double: %g Entry: %g (in bytes)\n\n", (double) sizeof (int), (double) sizeof (long), (double) sizeof (Int), (double) sizeof (void *), (double) sizeof (double), (double) sizeof (Entry))) ; } pysparse-1.1.1/umfpack/umfpack_report_control.h0000644010116400000240000000434011402270055020731 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_control =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 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 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 */ pysparse-1.1.1/umfpack/umfpack_report_info.c0000644010116400000240000005224011402270063020200 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_info ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 (("\n%s, Info:\n", UMFPACK_VERSION)) ; #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: 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: long\n")) ; #endif /* ---------------------------------------------------------------------- */ /* print compile-time options */ /* ---------------------------------------------------------------------- */ PRINTF ((" BLAS library used: ")) ; #if defined (USE_NO_BLAS) PRINTF (("none. UMFPACK will be slow.\n")) ; #elif defined (USE_C_BLAS) PRINTF (("C-BLAS.\n")) ; #elif defined (USE_MATLAB_BLAS) PRINTF (("built-in MATLAB BLAS.\n")) ; #elif defined (USE_SUNPERF_BLAS) PRINTF (("Sun Performance Library BLAS.\n")) ; #elif defined (USE_SCSL_BLAS) PRINTF (("SGI SCSL BLAS.\n")) ; #elif defined (USE_FORTRAN_BLAS) PRINTF (("Fortran BLAS.\n")) ; #endif PRINTF ((" MATLAB: ")) ; #ifdef MATLAB_MEX_FILE PRINTF (("yes.\n")) ; #else #ifdef MATHWORKS PRINTF (("yes (using internal ut* routines).\n")) ; #else PRINTF (("no.\n")) ; #endif #endif PRINTF ((" CPU timer: ")) ; #ifdef GETRUSAGE PRINTF (("getrusage.\n")) ; #else PRINTF (("ANSI C clock (may wrap-around).\n")) ; #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 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")) ; } else if (Info [UMFPACK_STRATEGY_USED] == UMFPACK_STRATEGY_2BY2) { PRINTF (("\n strategy used: symmetric 2-by-2\n")); } 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 */ /* ---------------------------------------------------------------------- */ 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)) ; } /* ---------------------------------------------------------------------- */ /* 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 (" 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) ; if (tnum > 0 && fnum > 0) { PRINT_INFO ( " numeric factorization mflops (CPU time): %.2f\n", 1e-6 * fnum / tnum) ; } if (twnum > 0 && fnum > 0) { PRINT_INFO ( " numeric factorization mflops (wallclock): %.2f\n", 1e-6 * fnum / twnum) ; } ttot = EMPTY ; ftot = fnum ; if (tsym >= 0 && tnum >= 0) { ttot = tsym + tnum ; PRINT_INFO (" symbolic + numeric CPU time (sec): %.2f\n", ttot) ; if (ftot > 0 && ttot > 0) { PRINT_INFO ( " symbolic + numeric mflops (CPU time): %.2f\n", 1e-6 * ftot / ttot) ; } } twtot = EMPTY ; if (twsym >= 0 && twnum >= 0) { twtot = twsym + twnum ; PRINT_INFO (" symbolic + numeric wall clock time (sec): %.2f\n", twtot) ; if (ftot > 0 && twtot > 0) { 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 > 0) { PRINT_INFO ( " solve mflops (CPU time): %.2f\n", 1e-6 * fsolve / tsolve) ; } if (fsolve > 0 && twsolve > 0) { 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 >= 0) { if (ttot >= 0 && ftot >= 0) { ttot += tsolve ; PRINT_INFO ( " total symbolic + numeric + solve CPU time: %.2f\n", ttot) ; if (ftot > 0 && ttot > 0) { PRINT_INFO ( " total symbolic + numeric + solve mflops (CPU): %.2f\n", 1e-6 * ftot / ttot) ; } } } if (twsolve >= 0) { if (twtot >= 0 && ftot >= 0) { twtot += tsolve ; PRINT_INFO ( " total symbolic+numeric+solve wall clock time: %.2f\n", twtot) ; if (ftot > 0 && twtot > 0) { PRINT_INFO ( " total symbolic+numeric+solve mflops(wallclock) %.2f\n", 1e-6 * ftot / twtot) ; } } } PRINTF (("\n")) ; } pysparse-1.1.1/umfpack/umfpack_report_info.h0000644010116400000240000000523211402270064020205 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_info ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 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 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. */ pysparse-1.1.1/umfpack/umfpack_report_matrix.c0000644010116400000240000001245611402270033020553 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_matrix ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" #include "umf_malloc.h" #include "umf_free.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] ) { Int prl, i, k, length, ilast, p, nz, prl1, p1, p2, n, n_i, do_values ; char *vector, *index ; Entry a ; /* ---------------------------------------------------------------------- */ /* 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) ; } #ifdef COMPLEX do_values = Ax && Az ; #else do_values = Ax != (double *) NULL ; #endif 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 [p], Az [p]) ; 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) ; } pysparse-1.1.1/umfpack/umfpack_report_matrix.h0000644010116400000240000001551611402270036020563 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_matrix ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) ; long umfpack_dl_report_matrix ( long n_row, long n_col, const long Ap [ ], const long Ai [ ], const double Ax [ ], 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] ) ; long umfpack_zl_report_matrix ( long n_row, long n_col, const long Ap [ ], const long Ai [ ], const double Ax [ ], const double Az [ ], 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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) ; 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]. 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. 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. No numerical values are printed if Ax or Az are (double *) 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. No numerical values are printed if Az is NULL. Future complex version: if Ax is present and Az is NULL, then both real and imaginary parts will be 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 */ pysparse-1.1.1/umfpack/umfpack_report_numeric.c0000644010116400000240000004174011402270104020706 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_numeric =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) ; } pysparse-1.1.1/umfpack/umfpack_report_numeric.h0000644010116400000240000000713311402270106020713 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_numeric =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_numeric ( void *Numeric, const double Control [UMFPACK_CONTROL] ) ; long umfpack_dl_report_numeric ( void *Numeric, const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_numeric ( void *Numeric, const double Control [UMFPACK_CONTROL] ) ; 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 long Syntax: #include "umfpack.h" void *Numeric ; double Control [UMFPACK_CONTROL] ; 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 long Syntax: #include "umfpack.h" void *Numeric ; double Control [UMFPACK_CONTROL] ; 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 */ pysparse-1.1.1/umfpack/umfpack_report_perm.c0000644010116400000240000000276011402270057020215 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_perm ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) ; } pysparse-1.1.1/umfpack/umfpack_report_perm.h0000644010116400000240000000676311402270060020223 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_perm ================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_perm ( int np, const int Perm [ ], const double Control [UMFPACK_CONTROL] ) ; long umfpack_dl_report_perm ( long np, const long Perm [ ], const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_perm ( int np, const int Perm [ ], const double Control [UMFPACK_CONTROL] ) ; long umfpack_zl_report_perm ( long np, const 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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 */ pysparse-1.1.1/umfpack/umfpack_report_status.c0000644010116400000240000000736611402270111020573 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_status ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 occured. */ /* 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 (("%s: ", UMFPACK_VERSION)) ; 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")) ; } pysparse-1.1.1/umfpack/umfpack_report_status.h0000644010116400000240000000510111402270113020563 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_status ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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], long status ) ; void umfpack_zi_report_status ( const double Control [UMFPACK_CONTROL], int status ) ; void umfpack_zl_report_status ( const double Control [UMFPACK_CONTROL], long status ) ; /* double int Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; int status ; umfpack_di_report_status (Control, status) ; double long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; 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 long Syntax: #include "umfpack.h" double Control [UMFPACK_CONTROL] ; 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 occured 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. */ pysparse-1.1.1/umfpack/umfpack_report_symbolic.c0000644010116400000240000001600311402270100021053 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_symbolic ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ /* User-callable. Prints the Symbolic object. See umfpack_report_symbolic.h for details. Does not print new Cdeg, Rdeg, Esize, and the Diagonal_map. 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")) ; } else if (Symbolic->strategy == UMFPACK_STRATEGY_2BY2) { PRINTF (("symmetric 2-by-2")) ; } 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) ; } pysparse-1.1.1/umfpack/umfpack_report_symbolic.h0000644010116400000240000000703611402270102021070 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_symbolic ============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_symbolic ( void *Symbolic, const double Control [UMFPACK_CONTROL] ) ; long umfpack_dl_report_symbolic ( void *Symbolic, const double Control [UMFPACK_CONTROL] ) ; int umfpack_zi_report_symbolic ( void *Symbolic, const double Control [UMFPACK_CONTROL] ) ; 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 long Syntax: #include "umfpack.h" void *Symbolic ; double Control [UMFPACK_CONTROL] ; 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 long Syntax: #include "umfpack.h" void *Symbolic ; double Control [UMFPACK_CONTROL] ; 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 */ pysparse-1.1.1/umfpack/umfpack_report_triplet.c0000644010116400000240000000471411402270111020725 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) { Int prl, prl1, k, i, j, do_values ; Entry t ; 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")) ; #ifdef COMPLEX do_values = Tx && Tz ; #else do_values = Tx != (double *) NULL ; #endif 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 [k], Tz [k]) ; 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) ; } pysparse-1.1.1/umfpack/umfpack_report_triplet.h0000644010116400000240000001140611402270114020731 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_triplet =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) ; long umfpack_dl_report_triplet ( long n_row, long n_col, long nz, const long Ti [ ], const 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] ) ; long umfpack_zl_report_triplet ( long n_row, long n_col, long nz, const long Ti [ ], const 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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) ; 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. 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 or Tz are not present ((double *) NULL pointers), then the numerical values are not printed. Future complex version: if Tx is present and Tz is NULL, then both real and imaginary parts will be 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 */ pysparse-1.1.1/umfpack/umfpack_report_vector.c0000644010116400000240000000244011402270033020541 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_report_vector ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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)) ; } pysparse-1.1.1/umfpack/umfpack_report_vector.h0000644010116400000240000001070711402270036020556 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_report_vector ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_report_vector ( int n, const double X [ ], const double Control [UMFPACK_CONTROL] ) ; long umfpack_dl_report_vector ( 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] ) ; long umfpack_zl_report_vector ( 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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. Future work: all complex routines in UMFPACK could 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 merged 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 the current version, only umfpack_*_report_vector supports both formats. 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 */ pysparse-1.1.1/umfpack/umfpack_save_numeric.c0000644010116400000240000000562011402270066020335 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_save_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) != 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) ; } pysparse-1.1.1/umfpack/umfpack_save_numeric.h0000644010116400000240000000456211402270067020347 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_save_numeric ================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_save_numeric ( void *Numeric, char *filename ) ; long umfpack_dl_save_numeric ( void *Numeric, char *filename ) ; int umfpack_zi_save_numeric ( void *Numeric, char *filename ) ; 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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. You need to call umfpack_*_free_numeric if you to delete the Numeric object after saving it to a file. 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. */ pysparse-1.1.1/umfpack/umfpack_save_symbolic.c0000644010116400000240000000627511402270105020515 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_save_symbolic ================================================ */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) != 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) ; } pysparse-1.1.1/umfpack/umfpack_save_symbolic.h0000644010116400000240000000462311402270107020517 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_save_symbolic================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_save_symbolic ( void *Symbolic, char *filename ) ; long umfpack_dl_save_symbolic ( void *Symbolic, char *filename ) ; int umfpack_zi_save_symbolic ( void *Symbolic, char *filename ) ; 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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. You need to call umfpack_*_free_symbolic if you to delete the Symbolic object after saving it to a file. 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. */ pysparse-1.1.1/umfpack/umfpack_scale.c0000644010116400000240000000551311402270070016740 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_scale ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 ; Numeric = (NumericType *) NumericHandle ; if (!UMF_valid_numeric (Numeric)) { return (UMFPACK_ERROR_invalid_Numeric_object) ; } n = Numeric->n_row ; Rs = Numeric->Rs ; if (!Xx || !Bx #ifdef COMPLEX || !Xz || !Bz #endif ) { 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 */ for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] * Rs [i] ; #ifdef COMPLEX Xz [i] = Bz [i] * Rs [i] ; #endif } } else #endif { /* divide by the scale factors */ for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] / Rs [i] ; #ifdef COMPLEX Xz [i] = Bz [i] / Rs [i] ; #endif } } } else { /* no scale factors, just copy B into X */ for (i = 0 ; i < n ; i++) { Xx [i] = Bx [i] ; #ifdef COMPLEX Xz [i] = Bz [i] ; #endif } } return (UMFPACK_OK) ; } pysparse-1.1.1/umfpack/umfpack_scale.h0000644010116400000240000000552611402270071016752 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_scale ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* web: http://www.cise.ufl.edu/research/sparse/umfpack */ /* -------------------------------------------------------------------------- */ int umfpack_di_scale ( double X [ ], const double B [ ], void *Numeric ) ; 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 ) ; 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 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 long Syntax: #include "umfpack.h" void *Numeric ; double *Bx, *Bz, *Xx, *Xz ; status = umfpack_zl_scale (Xx, Xz, Bx, Bz, Numeric) ; 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, Xz, Bx, and Bz for the complex version). Arguments: double X [n_row] ; Output argument. or: double Xx [n_row] ; Output argument, real part. double Xz [n_row] ; Output argument, imaginary part. The output vector X. double B [n_row] ; Input argument, not modified. or: double Bx [n_row] ; Input argument, not modified, real part. double Bz [n_row] ; Input argument, not modified, imaginary part. The input vector B. void *Numeric ; Input argument, not modified. Numeric must point to a valid Numeric object, computed by umfpack_*_numeric. */ pysparse-1.1.1/umfpack/umfpack_solve.c0000644010116400000240000001535611402270064017012 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_solve ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 */ /* ---------------------------------------------------------------------- */ NumericType *Numeric ; Int n, i, irstep, status ; double Info2 [UMFPACK_INFO], *Info, /* tstart, tend */ stats [2] ; #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 #ifdef COMPLEX || !Xz || !Bz #endif ) { 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) ; } pysparse-1.1.1/umfpack/umfpack_solve.h0000644010116400000240000002543411402270064017015 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_solve ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) ; long umfpack_dl_solve ( long sys, const long Ap [ ], const 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] ) ; long umfpack_zl_solve ( long sys, const long Ap [ ], const 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 long Syntax: #include "umfpack.h" void *Numeric ; 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 long Syntax: #include "umfpack.h" void *Numeric ; 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) ; 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). Earlier versions used a string argument for sys. It was changed to an integer to make it easier for a Fortran code to call UMFPACK. Int Ap [n+1] ; Input argument, not modified. Int Ai [nz] ; Input argument, not modified. double Ax [nz] ; Input argument, not modified. 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. Future complex version: if Ax is present and Az is NULL, then both real and imaginary parts will be 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. 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. Future complex version: if Xx is present and Xz is NULL, then both real and imaginary parts will be 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. 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. Future complex version: if Bx is present and Bz is NULL, then both real and imaginary parts will be 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 occured. 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, Bz, Xx and Xz for the complex versions) arguments are always required. Info and Control are not required. Ap, Ai, Ax (and Az for complex versions) 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. ------------------------------------------------------------------------ The following statistic was added to Version 4.1: ------------------------------------------------------------------------ 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. */ pysparse-1.1.1/umfpack/umfpack_symbolic.c0000644010116400000240000000242611402270066017477 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_symbolic ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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)) ; } pysparse-1.1.1/umfpack/umfpack_symbolic.h0000644010116400000240000005432211402270067017507 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_symbolic ===================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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] ) ; long umfpack_dl_symbolic ( long n_row, long n_col, const long Ap [ ], const 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] ) ; long umfpack_zl_symbolic ( long n_row, long n_col, const long Ap [ ], const 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 long Syntax: #include "umfpack.h" void *Symbolic ; 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 long Syntax: #include "umfpack.h" void *Symbolic ; 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) ; 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. 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)]. Future complex version: if Ax is present and Az is NULL, then both real and imaginary parts will be 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. 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 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: a row permutation P2 is found that places large entries on the diagonal. The matrix P2*A is then factorized using the symmetric strategy, described above. Refer to the User Guide for more information. 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. As long as the block size is large enough (8 or so), this parameter has a modest effect on performance. Control [UMFPACK_2BY2_TOLERANCE]: a diagonal entry S (k,k) is considered "small" if it is < tol * max (abs (S (:,k))), where S a submatrix of the scaled input matrix, with pivots of zero Markowitz cost removed. 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. 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). Note that the UMFPACK_ERROR_problem_too_large error code is no longer returned (it was in Version 4.0). 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 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. ------------------------------------------------------------------------ The rest of the statistics are new to Version 4.1: ------------------------------------------------------------------------ Info [UMFPACK_SYMBOLIC_WALLTIME]: The wallclock time taken, in seconds. Info [UMFPACK_STRATEGY_USED]: The ordering strategy used: UMFPACK_STRATEGY_SYMMETRIC, UMFPACK_STRATEGY_UNSYMMETRIC, or UMFPACK_STRATEGY_2BY2. 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. ------------------------------------------------------------------------ The following statistics are computed only if the 2-by-2 strategy is used or attempted: ------------------------------------------------------------------------ Info [UMFPACK_2BY2_NWEAK]: the number of small diagonal entries in S. Info [UMFPACK_2BY2_UNMATCHED]: the number of small diagonal entries in P2*S. Info [UMFPACK_2BY2_PATTERN_SYMMETRY]: the symmetry of P2*S. Info [UMFPACK_2BY2_NZ_PA_PLUS_AT]: the number of off-diagonal entries in (P2*S)+(P2*S)'. Info [UMFPACK_2BY2_NZDIAG]: the number of nonzero entries on the diagonal of P2*S. 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. */ pysparse-1.1.1/umfpack/umfpack_tictoc.c0000644010116400000240000000500011402270115017125 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_tictoc ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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" #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 */ struct tms t ; double ticks ; 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 /* -------------------------------------------------------------------------- */ 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 ; } pysparse-1.1.1/umfpack/umfpack_tictoc.h0000644010116400000240000000440211402270032017135 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_tictoc ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 */ pysparse-1.1.1/umfpack/umfpack_timer.c0000644010116400000240000000520211402270101016757 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_timer ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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. This was the timer used internally by UMFPACK Version 4.0. See umfpack_tictoc.h, which is the timer now used internally by UMFPACK V4.1. */ #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 pysparse-1.1.1/umfpack/umfpack_timer.h0000644010116400000240000000350611402270103016773 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_timer ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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. This was the timer used internally in UMFPACK V4.0. See umfpack_tic and umfpack_toc (the file umfpack_tictoc.h) for the timer used internally by UMFPACK V4.1. 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. */ pysparse-1.1.1/umfpack/umfpack_transpose.c0000644010116400000240000000717511402270077017704 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_transpose ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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) ; } pysparse-1.1.1/umfpack/umfpack_transpose.h0000644010116400000240000002034511402270100017666 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_transpose ==================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; long umfpack_dl_transpose ( long n_row, long n_col, const long Ap [ ], const long Ai [ ], const double Ax [ ], const long P [ ], const long Q [ ], long Rp [ ], 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 ) ; long umfpack_zl_transpose ( long n_row, long n_col, const long Ap [ ], const long Ai [ ], const double Ax [ ], const double Az [ ], const long P [ ], const long Q [ ], long Rp [ ], long Ri [ ], double Rx [ ], double Rz [ ], 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 long Syntax: #include "umfpack.h" 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 long Syntax: #include "umfpack.h" 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) ; 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. The umfpack mexFunction (umfpackmex.c) is one example. To compute x = A/b, it computes x = (A.'\b.').' instead, by factorizing A.'. It then uses the regular solve, since b.' and x.' are stored identically as b and x, respectively (both b.' and b are dense vectors). If b and x were arrays, the umfpack mexFunction would need to first compute b.' and then transpose the resulting solution. 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]. 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 (for the real version), and only if all four (Ax, Az, Rx, and Rz) are present for the complex version. These are not an error conditions; you are able to transpose and permute just the pattern of a matrix. Future complex version: if Ax is present and Az is NULL, then both real and imaginary parts will be 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. 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. Future complex version: if Rx is present and Rz is NULL, then both real and imaginary parts will be 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, Az, Rx, and Rz are all present, then the linear algebraic transpose is computed (complex conjugate). If false, the array transpose is computed instead. */ pysparse-1.1.1/umfpack/umfpack_triplet_to_col.c0000644010116400000240000001555311402270112020675 0ustar wd15dialout/* ========================================================================== */ /* === UMFPACK_triplet_to_col =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 occured. 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, *Rz ; #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 ; Rz = (double *) NULL ; #ifdef COMPLEX do_values = Ax && Tx && Az && Tz ; if (do_values) { Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ; Rz = (double *) UMF_malloc (nz+1, sizeof (double)) ; if (!Rx || !Rz) { DEBUGm4 (("out of memory: triplet work (complex)\n")) ; (void) UMF_free ((void *) Rx) ; (void) UMF_free ((void *) Rz) ; ASSERT (UMF_malloc_count == init_count) ; return (UMFPACK_ERROR_out_of_memory) ; } } #else do_values = Ax && Tx ; if (do_values) { Rx = (double *) UMF_malloc (nz+1, sizeof (double)) ; if (!Rx) { DEBUGm4 (("out of memory: triplet work (real)\n")) ; ASSERT (UMF_malloc_count == init_count) ; return (UMFPACK_ERROR_out_of_memory) ; } } #endif 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) ; (void) UMF_free ((void *) Rz) ; 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 *) Rz) ; (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) + (Rz != (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 *) Rz) ; (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) ; } pysparse-1.1.1/umfpack/umfpack_triplet_to_col.h0000644010116400000240000002454011402270115020701 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_triplet_to_col =============================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; long umfpack_dl_triplet_to_col ( long n_row, long n_col, long nz, const long Ti [ ], const long Tj [ ], const double Tx [ ], long Ap [ ], long Ai [ ], double Ax [ ], 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 [ ] ) ; long umfpack_zl_triplet_to_col ( long n_row, long n_col, long nz, const long Ti [ ], const long Tj [ ], const double Tx [ ], const double Tz [ ], long Ap [ ], long Ai [ ], double Ax [ ], double Az [ ], 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 long Syntax: #include "umfpack.h" 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) ; long Syntax: #include "umfpack.h" 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) ; Purpose: Converts a sparse matrix from "triplet" form to compressed-column form. Analogous to A = spconvert (Ti, Tj, Tx + Tx*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. 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. For the real version, Ax is computed only if both Ax and Tx are present (not (double *) NULL). For the complex version, Ax and Az are computed only if Tx, Tz, Ax, and Az are all present. These are not error conditions; the routine can create just the pattern of the output matrix from the pattern of the triplets. Future complex version: if Tx is present and Tz is NULL, then both real and imaginary parts will be 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. 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. Az is also optional; if Tz and/or Az are not present, then Az 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. Future complex version: if Ax is present and Az is NULL, then both real and imaginary parts will be 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 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. */ pysparse-1.1.1/umfpack/umfpack_wsolve.c0000644010116400000240000001537511402270101017172 0ustar wd15dialout#define WSOLVE /* ========================================================================== */ /* === UMFPACK_solve ======================================================== */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 */ /* ---------------------------------------------------------------------- */ NumericType *Numeric ; Int n, i, irstep, status ; double Info2 [UMFPACK_INFO], *Info, /* tstart, tend */ stats [2] ; #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 #ifdef COMPLEX || !Xz || !Bz #endif ) { 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) ; } pysparse-1.1.1/umfpack/umfpack_wsolve.h0000644010116400000240000001242311402270102017167 0ustar wd15dialout/* ========================================================================== */ /* === umfpack_wsolve ======================================================= */ /* ========================================================================== */ /* -------------------------------------------------------------------------- */ /* UMFPACK Version 4.1 (Apr. 30, 2003), Copyright (c) 2003 by Timothy A. */ /* Davis. All Rights Reserved. See ../README for License. */ /* email: davis@cise.ufl.edu CISE Department, Univ. of Florida. */ /* 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 [ ] ) ; long umfpack_dl_wsolve ( long sys, const long Ap [ ], const long Ai [ ], const double Ax [ ], double X [ ], const double B [ ], void *Numeric, const double Control [UMFPACK_CONTROL], double Info [UMFPACK_INFO], 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 [ ] ) ; long umfpack_zl_wsolve ( long sys, const long Ap [ ], const 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], 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 long Syntax: #include "umfpack.h" void *Numeric ; 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 long Syntax: #include "umfpack.h" void *Numeric ; 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) ; 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. 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. double Xz [n] ; Output argument, imaginary part double Bx [n] ; Input argument, not modified, real part 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 */ pysparse-1.1.1/CHANGES0000644010116400000240000002107111402270406013344 0ustar wd15dialout1.1.1 ------------------------------------------------------------------------------- Fixed memory leak in find() method merged trunk revisions 131-136,158 Fixed to locate numpy header files correctly Automate installation of numpy (no flags to change in setup.py) Removed some Numeric imports Moved version number from __init__.py to __version__.py 1.0 -------------------------------------------------------------------------------- Moved modules inside "pysparse" name space. Updated to use the new numpy, but still compatible with the old Numeric. 0.34.032 --------------------------------------------------------------------------------- Fixed a memory leak in ll_mat.keys(). (Reported by c chui) Improved the performance of ll_mat.scale(), ll_mat.values() and ll_mat.items(). 0.34.031 --------------------------------------------------------------------------------- Modules using the pysparse C API can now define NO_IMPORT_SPMATRIX together with SPMATRIX_UNIQUE_SYMBOL to avoid multiple definition of the SpMatrix_API pointer. This fix was suggested by Erica Madeleine Ligner. 0.34.030 --------------------------------------------------------------------------------- Applied patches 1089844, 1089837, 1089831 (supplied by Daniel Wheeler & Jonathan Guyer): Added three new ll_mat methods: update_add_at(b,id1,id2), put(b,id1,id2), take(b,id1,id2), fixed OS X compatibility issues, Numpy compatibility fixes. Applied some additional fixes for 64-bit machines. PySparse now works with Numeric 23.7 (also on 64-bit machines). [1111727] Replaced #include by #include to fix compatibility issue on OS X (reported by Jonathan Guyer). Removed reference to libm.a which broke compilation on Win32 (reported by Mark Dausch). 0.33.029 --------------------------------------------------------------------------------- added new umfpack module. (by Nathaniel C. Domingo) added Umfpack library source files to distribution (by Nathaniel C. Domingo) added new module sparray, implementing a multidimensional sparse array (by Pascal Barbedor) fixed bug in SSOR preconditioner (precon module) for omega != 1.0 and steps > 1 0.32.028 --------------------------------------------------------------------------------- added Xavier Vasseur's gmres solver to the itsolvers module. Thanks Xavier! 0.31.027 --------------------------------------------------------------------------------- fixed: call to SpMatrix_MATVEC in Src/pcg.c 0.31.026 --------------------------------------------------------------------------------- PySparse is placed under a BSD style license 0.30.025 --------------------------------------------------------------------------------- fixed bug in "generalize" member function of ll_mat type. Reported by Xavier Vasseur. the result tuple returned by jdsym.jdsym now includes an additional value representing the avg. number of inner iterations. This change may be incompatble with existing code calling this module function. 0.29.024 --------------------------------------------------------------------------------- PySparse can be build using MinGW on Win32 platforms. Check the instructions in INSTALL. 0.29.023 --------------------------------------------------------------------------------- fixed memory leaks in SpMatrix_LLMatSetItem and SpMatrix_LLMatUpdateItemAdd that occur if PyMem_Resize would fail. More detailed installation instructions for Win32 platforms in INSTALL 0.29.022 --------------------------------------------------------------------------------- new method for ll_mat objects: compress nicer output for ll_mat objects representing small matrices optimised matrix-matrix-multiplication routine included (unsym-unsym case) new version of bicgstab solver (uses less memory) 0.28.021 --------------------------------------------------------------------------------- fixed error handling in ll_mat.generalize fixed name mismatched in solver kernels in itsolvers 0.28.020 --------------------------------------------------------------------------------- new method itsolvers.bicgstab (implemented by Oliver Broeker) all solvers in the itsolvers module now check for exceptions after each precon or matvec call. solver kernels in itsolvers now have names that conflict less likely with other modules 0.28.019 --------------------------------------------------------------------------------- uncommented call to PrintStat in superlu/dgssv.c and superlu/dgssvx.c to prevent unwanted output in ML package fixed memory leak in sss_mat.c: diag array was not freed new method for ll_mat objects: generalize 0.27.018 --------------------------------------------------------------------------------- updated test modules to reflect earlier bug fix in poisson.poisson2d() new default precision in ll_mat.export_mtx(): 16 instead of 6 fixed bug in Src/jdsymmodule.c: solution now copied correctly if not all requested eigenvectors converged. 0.27.017 --------------------------------------------------------------------------------- fixed bug in SRC/cgs.c: now returns correct iteration count, if initial guess satisfies stopping criterion fixed bug in Src/superlumodule.c solve transposed system, since matrix was passed row-wise new method for ll_mat matrices: norm(p) 0.26.016 --------------------------------------------------------------------------------- changed interface of SpMatrix_Matvec(), now supports non-square matrices 0.26.015 --------------------------------------------------------------------------------- reimplemented SpMatrix_LLMatBuildColIndex and SpMatrix_LLMatDestroyColIndex 0.26.014 --------------------------------------------------------------------------------- new module itsolvers_util: encapsulation objects for all iterative solvers 0.25.013 --------------------------------------------------------------------------------- fixed bug in poisson.poisson2d_sym_blk(): diagonal entries are now 4, not 2. changed superlu_superlu_timer.c to support Win32 0.25.012 --------------------------------------------------------------------------------- test module for superlu poisson module for generating 1D and 2D Poisson matrices 0.25.011 --------------------------------------------------------------------------------- incorporated a new version of SuperLU (date 2002/09/23) changed postorder tree traversal in sp_coletree.c to be more stack friendly (max stack size on Linux seems to be 6 MBytes) removed stdout in get_perm_c.c 0.25.008 --------------------------------------------------------------------------------- fixed bug in matvec method of csr_mat, occuring if stride of vector y is not one ll_mat.shift now supports shift of a general matrix by a symmetric matrix new matvec and matvec:transp object methods for ll_mat type fixed bug when assigning a symmetric matrix to a block of a general matrix delete_cols method added for ll_mat objects 0.24.007 --------------------------------------------------------------------------------- fixed bug occurring when the spmatrix C API is used in an extension consisting of more than one file. Now SPMATRIX_UNIQUE_SYMBOL has to be defined. This broke the itsolvers.pcg function. 0.24.006 --------------------------------------------------------------------------------- Bug fixed in spmatrix.h: LLMatType now exported properly Genereation of boiler plate code for C API is automated now More functions exported in C API spmatrix module no longer uses extern symbols delete_rows and delete_rowcols methods added for ll_mat objects matvec and matvec_transp methods of csr_mat and sss_mat objects now accept strided arrays as input 0.23.005 --------------------------------------------------------------------------------- Header files are now installed to python directory tree. External packages may now import pysparse. 0.23.004 --------------------------------------------------------------------------------- new module Lib/pysparse_version.py defining pysparse version number 0.23.003 --------------------------------------------------------------------------------- Updated README Removed some illegal characters from superlu/superlu_timer.c Removed SuperLU output from superlu/get_perm_c.c stating the matrix reordering used. 0.23.002 --------------------------------------------------------------------------------- SuperLU is now incorporated into pysparse. No need to build the library separately from now on. Now compiles under Win32. Tested under WinXP with MS Visual Studio 6.0 and the Inter Math Kernel Library for LAPACK and BLAS Removed some unused local variables Changed interface of LLMat_parse_index. Can now be safely used in sss_mat.c. 0.22.001 --------------------------------------------------------------------- initial release pysparse-1.1.1/INSTALL0000644010116400000240000001051111402270405013376 0ustar wd15dialoutSpecial installation instructions for various platforms ======================================================= Win32 using MS VC++ 2008 and ACML 4.3 ------------------------------------- PySparse was successfully built with Microsoft Visual C++ 2008 (Express Edition) together with AMD Core Math Library (ACML) 4.3.0 for Python 2.6.4 and NumPy 1.4.0 (All the above mentioned software can be obtained free of charge). In the following it is assumed that ACML is installed into C:\AMD\acml4.3.0 Please follow the following steps to build and install PySparse 1. Copy the three DLL files in the directory C:\AMD\acml4.3.0\ifort32\lib to the Lib subdirectory of the PySparse. 2. Modify setup.py to use the following settings: library_dirs_list= [r"C:\AMD\acml4.3.0\ifort32\lib"] libraries_list = ['libacml_dll', "python26"] superlu_defs = [('USE_VENDOR_BLAS',1), ('F77_CALL_C', 'UPCASE')] superlu_defs += [('NO_TIMER', 1)] f77_defs = [("F77UPPERCASE", "1")] package_data = ['libacml_dll.dll', 'libifcoremd.dll', 'libmmd.dll'] compily=[] linky=[] 3. python.exe setup.py build -f 4. python.exe setup.py install -f The DLL files will be automatically copied to the pysparse install directory. It is not necessary to modify the PATH variable. Note: To compile the PySpare for debugging the following settings can be used: linky=["/DEBUG"] compily=["/Od", "/Zi"] Win32 using MS VC++ 2008 and ACML 4.3 (statically linked) --------------------------------------------------------- These build instructions are similiar to the above ones. However here ACML is linked statically, which makes it more suitable for creating a Windows Installer. This type of build requires the presence Fotran standard libraries, which are not included in ACML or MSVC++ (they are part of Intel Fotran). It assumed that they are available in the directory C:\AMD\acml4.3.0\ifort32\lib\ifort Please follow the following steps to build and install PySparse 1. Copy the DLL files libifcoremd.dll and libmmd.dll from the directory C:\AMD\acml4.3.0\ifort32\lib to the Lib subdirectory of the PySparse. 2. Modify setup.py to use the following settings: library_dirs_list= [r"C:\AMD\acml4.3.0\ifort32\lib", r"C:\AMD\acml4.3.0\ifort32\lib\ifort"] libraries_list = ['libacml', "python26"] superlu_defs = [('USE_VENDOR_BLAS',1), ('F77_CALL_C', 'UPCASE')] if sys.platform == 'win32': superlu_defs += [('NO_TIMER', 1)] f77_defs = [("F77UPPERCASE", "1")] package_data = ['libifcoremd.dll', 'libmmd.dll'] compily=[] linky=[] 3. python.exe setup.py build -f 4. python.exe setup.py install -f The DLL files will be automatically copied to the pysparse install directory. It is not necessary to modify the PATH variable. Win32 using MS VC++ 6.0 and Intel MKL ------------------------------------- PySparse was successfully built with Microsoft Visual C++ 6.0 together with the Intel Math Kernel Library (MKL). When adjusting "setup.py" you can use the settings under "elif hostname == 'Rivendell':" and change the library_dirs_list according to your MKL installation. Before running the setup script please make sure that the VC++ executables are in your PATH environment variable. It is also important that you include the directory containing the MKL DLLs in your PATH environment variable. Otherwise runtime errors will occur when PySparse is imported and called. Win32 using MinGW ----------------- 1. Follow the instructions at http://sebsauvage.net/python/mingw.html to - install MinGW - build libpythonXX.a from python.dll - Note that enthought python comes with libpythonXX.a 2. Install BLAS/LAPACK - Download the LAPACK and BLAS sources from http://www.netlib.org. - Follow the included instructions to build the libraries using the MinGW development tools. - Install the libraries in your MinGW tree. - Pre-compiled libraries for windows are available in Tools/win32_blas_lapack 3. Build pysparse - set PATH=C:\mingw\bin - Customize setup.py (this should not now be necessary): Your should use the following settings: libraries_list = ['lapack', 'blas', 'g2c'] superlu_defs = [("NO_TIMER",1), ('USE_VENDOR_BLAS',1)] - Build build and install: C:\pythonXX\python setup.py build --compiler mingw32 bdist --format=wininst - Build a distribution for windows: C:\pythonXX\python setup.py build --compiler=mingw32 --install pysparse-1.1.1/LICENSE0000644010116400000240000000300111402270404013345 0ustar wd15dialoutCopyright (c) 2001-2003, ETH Zurich and Roman Geus All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pysparse-1.1.1/README0000644010116400000240000000603011402270405013226 0ustar wd15dialoutTHE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND "WITH ALL FAULTS". THE AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE QUALITY, SAFETY OR SUITABILITY OF THE SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. Overview -------- PySparse extends the Python interpreter by a set of sparse matrix types holding double precision values. PySparse also includes modules that implement - iterative methods for solving linear systems of equations - a set of standard preconditioners - an interface to a direct solver for sparse linear systems of equations (SuperLU) - a Jacobi-Davidson eigenvalue solver for the symmetric, generalised matrix eigenvalue problem (JDSYM) All these modules are implemented as C extension modules for maximum performance. PySparse uses Numerical Python (NumPy) for handling dense vectors and matrices and makes use of SuperLU for factorising sparse matrices. Installation ------------ 1. Install Numerical Python - Download NumPy from http://www.numpy.org/ PySparse was tested with NumPy version 1.0 Pysparse works with both the new "numpy" and the old "Numeric". - Unpack and Install the NumPy package Refer to the documentation provided in the NumPy package for installation hints. 2. Customise the setup.py file PySparse is needs to link against the BLAS and LAPACK libraries, which must be available on your system. Set the library_dirs_list, libraries_list, superlu_defs, f77_defs variables according to your local configuration. Examples for several architectures are provided. Change the "use_numpy" flag to False in setup.py when using the old "Numeric". 3. Install PySparse Run 'python setup.py install' to install PySparse into the default directory of your Python installation. Refer to the Python documentation, if you have advanced installation needs. 4. Testing Testing support is only rudimentary. Run the scripts in the Examples directory. Check if the results are meaningful :-; PySparse was successfully tested on many UNIX brands, including Linux, Solaris (SunOS 5.6), Digital UNIX (OSF1 V4.0) and HP-UX 11.11, and Windows XP. PySparse was tested using Python version 2.1 and 2.2. Documentation ------------- Some documentation is located in the Doc subdirectory. Alternatively you can consult the documentation in the source code using the 'pydoc' utility. Acknowledgements ---------------- Major parts of this work was done while I was working as a PhD student at Institute of Scientific Computing ETH Zentrum CH-8092 Zurich, Switzerland and while I was working as a postdoc at Paul Scherrer Institute CH-5232 Villigen, Switzerland I would like thank the developers of the SuperLU and Umfpack packages. Both SuperLU and Umfpack are incorporated into the PySparse software distribution. Contact ------- For comments, questions, bug reports, etc. contact me by email: roman@geus.ch Roman Geus pysparse-1.1.1/setup.py0000644010116400000240000005036411402270404014070 0ustar wd15dialout#!/usr/bin/env python from distutils import sysconfig, version from distutils.core import setup, Extension import glob import os, socket import sys # default settings package_data = [] library_dirs_list= [] libraries_list = ['lapack', 'blas'] superlu_defs = [('USE_VENDOR_BLAS',1)] if sys.platform == 'win32': superlu_defs += [('NO_TIMER', 1)] f77_defs = [] linky=[] compily=[] # Specify whether to link against user's SuperLU library use_users_superlu = False #True umfpack_defs = [('DINT', 1), ('NBLAS', 1)] # No BLAS. Ok if using your system's BLAS. #umfpack_defs = [('DINT', 1), ('CBLAS', 1)] # with atlas c-blas (http://math-atlas.sf.net) if use_users_superlu: # Specify location of include files superlu_include_dirs = ['/Users/dpo/local/linalg/SuperLU/SuperLU_3.1/SRC'] # AND specify ONE of the following: # 1) Location of source files (overrides linking with existing library) superlu_src_dir = '/Users/dpo/local/linalg/SuperLU/SuperLU_3.1/SRC' # 2) Location of precompiled library superlu_lib_dir = [''] superlu_libraries = [''] # Specify whether to link against user's UMFPACK library use_users_umfpack = False #True if use_users_umfpack: # Specify location of include files umfpack_include_dirs = ['/Users/dpo/local/linalg/UMFPACK/UMFPACK/Include'] # AND specify ONE of the following: # 1) Location of source files (overrides linking with existing library) umfpack_src_dir = '/Users/dpo/local/linalg/UMFPACK/UMFPACK/Source' # 2) Location of precompiled library umfpack_lib_dir = [''] umfpack_libraries = [''] # Do the same for AMD amd_include_dirs = ['/Users/dpo/local/linalg/UMFPACK/AMD/Include'] # AND specify ONE of the following: # 1) Location of source files (overrides linking with existing library) amd_src_dir = '/Users/dpo/local/linalg/UMFPACK/AMD/Source' # 2) Location of precompiled library amd_lib_dir = [''] amd_libraries = [''] else: umfpack_libraries = [] umfpack_include_dirs = ['amd', 'umfpack'] umfpack_library_dirs = [] #umfpack_libraries = ['atlas', 'cblas', 'm'] #umfpack_include_dirs = ['amd', 'umfpack'] # you may need to set this to find the atlas #umfpack_library_dirs = [] # Obtain Python version pyver = sysconfig.get_python_version() # Returns something like '2.5' current = version.StrictVersion(pyver) # Object that can be compored target = version.StrictVersion('2.6') newpy_defs = [] if current >= target: newpy_defs = [('LENFUNC_OK', 1)] # For PyMappingMethods types ## numpy / Numeric settings try: import numpy use_numpy = True except: try: import Numeric use_numpy = False except: raise ImportError, "Failed to import either numpy or Numeric" package_name = 'pysparse' if use_numpy: numerix_macro = [('NUMPY', '1')] numerix_include_dirs = [numpy.get_include()] else: numerix_macro = [] numerix_include_dirs = [] if sys.platform == 'darwin': superlu_defs = [('USE_VENDOR_BLAS',1)] library_dirs_list = ['/System/Library/Frameworks'] libraries_list = [] f77_defs = [] # the following 'linky' arguments must not be concatenated together into a single # string, c.f. if sys.exec_prefix == '/sw': # fink python linky=["-faltivec","-framework","vecLib","-bundle_loader","/sw/bin/python"] else: # Apple python #linky=["-faltivec","-framework","Accelerate"] linky=["-framework","Accelerate"] # The python Framework build is compiled with (and propagates to all # library builds) the '-fno-common' flag. Nobody seems to know why. # (c.f. ) # This flag wreaks havoc with the nightmarishly circular declarations # in the itsolvers module. We reset it by appending this flag: compily=["-fcommon"] elif sys.platform == 'linux2': ## fix for Fedora core 4, 'g2c' doesn't exist and isn't required if 'redhat-release' in os.listdir('/etc'): f = open('/etc/redhat-release', 'r') if 'release 4' in f.read(): libraries_list = ['lapack', 'blas'] f.close() from distutils.core import Command ext_modules = [Extension(package_name + '.spmatrix', ['Src/spmatrixmodule.c'], define_macros=numerix_macro + newpy_defs), Extension(package_name + '.itsolvers', ['Src/itsolversmodule.c', 'Src/pcg.c', 'Src/gmres.c', 'Src/minres.c', 'Src/qmrs.c', 'Src/bicgstab.c', 'Src/cgs.c'], library_dirs=library_dirs_list, libraries=libraries_list, define_macros=f77_defs + numerix_macro, extra_compile_args=compily, extra_link_args=linky), Extension(package_name + '.precon', [os.path.join('Src', 'preconmodule.c')], library_dirs=library_dirs_list, libraries=libraries_list, define_macros=f77_defs + numerix_macro, extra_compile_args=compily, extra_link_args=linky), Extension(package_name + '.jdsym', [os.path.join('Src', 'jdsymmodule.c')], library_dirs=library_dirs_list, libraries=libraries_list, define_macros=f77_defs + numerix_macro, extra_compile_args=compily, extra_link_args=linky) ] # Schedule UMFPACK if not use_users_umfpack: ext_modules += [Extension(package_name + '.umfpack', sources=[os.path.join('Src', 'umfpackmodule.c'), 'amd/amd_aat.c', 'amd/amd_1.c', 'amd/amd_2.c', 'amd/amd_dump.c', 'amd/amd_postorder.c', 'amd/amd_post_tree.c', 'amd/amd_defaults.c', 'amd/amd_order.c', 'amd/amd_control.c', 'amd/amd_info.c', 'amd/amd_valid.c', 'umfpack/umf_analyze.c', 'umfpack/umf_apply_order.c', 'umfpack/umf_colamd.c', 'umfpack/umf_free.c', 'umfpack/umf_fsize.c', 'umfpack/umf_is_permutation.c', 'umfpack/umf_malloc.c', 'umfpack/umf_realloc.c', 'umfpack/umf_report_perm.c', 'umfpack/umf_singletons.c', 'umfpack/umfpack_timer.c', 'umfpack/umfpack_tictoc.c', 'umfpack/umf_lhsolve.c', 'umfpack/umf_uhsolve.c', 'umfpack/umf_triplet_map_nox.c', 'umfpack/umf_triplet_nomap_x.c', 'umfpack/umf_triplet_nomap_nox.c', 'umfpack/umf_triplet_map_x.c', 'umfpack/umf_assemble_fixq.c', 'umfpack/umf_assemble.c', 'umfpack/umf_blas3_update.c', 'umfpack/umf_build_tuples.c', 'umfpack/umf_create_element.c', 'umfpack/umf_dump.c', 'umfpack/umf_extend_front.c', 'umfpack/umf_garbage_collection.c', 'umfpack/umf_get_memory.c', 'umfpack/umf_init_front.c', 'umfpack/umf_kernel.c', 'umfpack/umf_kernel_init.c', 'umfpack/umf_kernel_wrapup.c', 'umfpack/umf_local_search.c', 'umfpack/umf_lsolve.c', 'umfpack/umf_ltsolve.c', 'umfpack/umf_mem_alloc_element.c', 'umfpack/umf_mem_alloc_head_block.c', 'umfpack/umf_mem_alloc_tail_block.c', 'umfpack/umf_mem_free_tail_block.c', 'umfpack/umf_mem_init_memoryspace.c', 'umfpack/umf_report_vector.c', 'umfpack/umf_row_search.c', 'umfpack/umf_scale_column.c', 'umfpack/umf_set_stats.c', 'umfpack/umf_solve.c', 'umfpack/umf_symbolic_usage.c', 'umfpack/umf_transpose.c', 'umfpack/umf_tuple_lengths.c', 'umfpack/umf_usolve.c', 'umfpack/umf_utsolve.c', 'umfpack/umf_valid_numeric.c', 'umfpack/umf_valid_symbolic.c', 'umfpack/umf_grow_front.c', 'umfpack/umf_start_front.c', 'umfpack/umf_2by2.c', 'umfpack/umf_store_lu.c', 'umfpack/umf_scale.c', 'umfpack/umfpack_wsolve.c', 'umfpack/umfpack_col_to_triplet.c', 'umfpack/umfpack_defaults.c', 'umfpack/umfpack_free_numeric.c', 'umfpack/umfpack_free_symbolic.c', 'umfpack/umfpack_get_numeric.c', 'umfpack/umfpack_get_lunz.c', 'umfpack/umfpack_get_symbolic.c', 'umfpack/umfpack_numeric.c', 'umfpack/umfpack_qsymbolic.c', 'umfpack/umfpack_report_control.c', 'umfpack/umfpack_report_info.c', 'umfpack/umfpack_report_matrix.c', 'umfpack/umfpack_report_numeric.c', 'umfpack/umfpack_report_perm.c', 'umfpack/umfpack_report_status.c', 'umfpack/umfpack_report_symbolic.c', 'umfpack/umfpack_report_triplet.c', 'umfpack/umfpack_report_vector.c', 'umfpack/umfpack_solve.c', 'umfpack/umfpack_symbolic.c', 'umfpack/umfpack_transpose.c', 'umfpack/umfpack_triplet_to_col.c', 'umfpack/umfpack_scale.c', 'umfpack/umfpack_load_numeric.c', 'umfpack/umfpack_save_numeric.c', 'umfpack/umfpack_load_symbolic.c', 'umfpack/umfpack_save_symbolic.c'], define_macros=umfpack_defs + numerix_macro, include_dirs=umfpack_include_dirs, libraries=umfpack_libraries, extra_compile_args=compily, library_dirs=umfpack_library_dirs) ] else: if umfpack_src_dir.strip() != '': umf_src_files = [ 'umf_2by2.c', 'umf_analyze.c', 'umf_apply_order.c', 'umf_assemble.c', 'umf_blas3_update.c', 'umf_build_tuples.c', 'umf_colamd.c', 'umf_create_element.c', 'umf_dump.c', 'umf_extend_front.c', 'umf_free.c', 'umf_fsize.c', 'umf_garbage_collection.c', 'umf_get_memory.c', 'umf_grow_front.c', 'umf_init_front.c', 'umf_is_permutation.c', 'umf_kernel.c', 'umf_kernel_init.c', 'umf_kernel_wrapup.c', 'umf_local_search.c', 'umf_lsolve.c', 'umf_ltsolve.c', 'umf_malloc.c', 'umf_mem_alloc_element.c', 'umf_mem_alloc_head_block.c', 'umf_mem_alloc_tail_block.c', 'umf_mem_free_tail_block.c', 'umf_mem_init_memoryspace.c', 'umf_multicompile.c', 'umf_realloc.c', 'umf_report_perm.c', 'umf_report_vector.c', 'umf_row_search.c', 'umf_scale.c', 'umf_scale_column.c', 'umf_set_stats.c', 'umf_singletons.c', 'umf_solve.c', 'umf_start_front.c', 'umf_store_lu.c', 'umf_symbolic_usage.c', 'umf_transpose.c', 'umf_triplet.c', 'umf_tuple_lengths.c', 'umf_usolve.c', 'umf_utsolve.c', 'umf_valid_numeric.c', 'umf_valid_symbolic.c', 'umfpack_col_to_triplet.c', 'umfpack_defaults.c', 'umfpack_free_numeric.c', 'umfpack_free_symbolic.c', 'umfpack_get_determinant.c', 'umfpack_get_lunz.c', 'umfpack_get_numeric.c', 'umfpack_get_symbolic.c', 'umfpack_global.c', 'umfpack_load_numeric.c', 'umfpack_load_symbolic.c', 'umfpack_numeric.c', 'umfpack_qsymbolic.c', 'umfpack_report_control.c', 'umfpack_report_info.c', 'umfpack_report_matrix.c', 'umfpack_report_numeric.c', 'umfpack_report_perm.c', 'umfpack_report_status.c', 'umfpack_report_symbolic.c', 'umfpack_report_triplet.c', 'umfpack_report_vector.c', 'umfpack_save_numeric.c', 'umfpack_save_symbolic.c', 'umfpack_scale.c', 'umfpack_solve.c', 'umfpack_symbolic.c', 'umfpack_tictoc.c', 'umfpack_timer.c', 'umfpack_transpose.c', 'umfpack_triplet_to_col.c' ] umf_src_files = map(lambda s: os.path.join(umfpack_src_dir, s), umf_src_files) src_files = umf_src_files + [os.path.join('Src', 'umfpackmodule.c')] else: src_files = [os.path.join('Src', 'umfpackmodule.c')] library_dirs_list += umfpack_lib_dir libraries_list += umfpack_libraries if amd_src_dir.strip() != '': amd_src_files = [ 'amd_1.c', 'amd_2.c', 'amd_aat.c', 'amd_control.c', 'amd_defaults.c', 'amd_dump.c', 'amd_global.c', 'amd_info.c', 'amd_order.c', 'amd_post_tree.c', 'amd_postorder.c', 'amd_preprocess.c', 'amd_valid.c' ] amd_src_files = map(lambda s: os.path.join(amd_src_dir, s), amd_src_files) src_files += amd_src_files else: library_dirs_list += amd_lib_dir libraries_list += amd_libraries ext_modules += [ Extension(package_name + '.umfpack', src_files, define_macros=umfpack_defs + numerix_macro, include_dirs=umfpack_include_dirs + amd_include_dirs, library_dirs=library_dirs_list, libraries=libraries_list, extra_compile_args=compily, extra_link_args=linky) ] # Schedule SuperLU if not use_users_superlu: ext_modules += [ Extension(package_name + '.superlu', [os.path.join('Src', 'superlumodule.c'), "superlu/dcolumn_bmod.c", "superlu/dcolumn_dfs.c", "superlu/dcomplex.c", "superlu/scomplex.c", "superlu/dcopy_to_ucol.c", "superlu/dgscon.c", "superlu/dgsequ.c", "superlu/dgsrfs.c", "superlu/dgssv.c", "superlu/dgssvx.c", "superlu/dgstrf.c", "superlu/dgstrs.c", "superlu/dlacon.c", "superlu/dlamch.c", "superlu/dlangs.c", "superlu/dlaqgs.c", "superlu/dmemory.c", "superlu/colamd.c", "superlu/dpanel_bmod.c", "superlu/dpanel_dfs.c", "superlu/dpivotL.c", "superlu/dpivotgrowth.c", "superlu/dpruneL.c", "superlu/dreadhb.c", "superlu/dsnode_bmod.c", "superlu/dsnode_dfs.c", "superlu/dsp_blas2.c", "superlu/dsp_blas3.c", "superlu/superlu_timer.c", "superlu/dutil.c", "superlu/dzsum1.c", "superlu/get_perm_c.c", "superlu/icmax1.c", "superlu/izmax1.c", "superlu/lsame.c", "superlu/memory.c", "superlu/mmd.c", "superlu/relax_snode.c", "superlu/sp_coletree.c", "superlu/sp_ienv.c", "superlu/sp_preorder.c", "superlu/util.c", "superlu/xerbla.c"], define_macros=superlu_defs + numerix_macro, include_dirs=["superlu"], library_dirs=library_dirs_list, extra_compile_args=compily, libraries=libraries_list,extra_link_args=linky) ] else: if superlu_src_dir.strip() != '': src_files = ['superlu_timer.c', 'util.c', 'memory.c', 'get_perm_c.c', 'mmd.c', 'sp_coletree.c', 'sp_preorder.c', 'sp_ienv.c', 'relax_snode.c', 'heap_relax_snode.c', 'colamd.c', 'lsame.c', 'xerbla.c', 'dlacon.c', 'dlamch.c', 'dgssv.c', 'dgssvx.c', 'dsp_blas2.c', 'dsp_blas3.c', 'dgscon.c', 'dlangs.c', 'dgsequ.c', 'dlaqgs.c', 'dpivotgrowth.c', 'dgsrfs.c', 'dgstrf.c', 'dgstrs.c', 'dcopy_to_ucol.c', 'dsnode_dfs.c', 'dsnode_bmod.c', 'dpanel_dfs.c', 'dpanel_bmod.c', 'dreadhb.c', 'dcolumn_dfs.c', 'dcolumn_bmod.c', 'dpivotL.c', 'dpruneL.c', 'dmemory.c', 'dutil.c'] src_files = map(lambda s: os.path.join(superlu_src_dir, s), src_files) src_files += [os.path.join('Src', 'superlu3module.c')] else: src_files = [os.path.join('Src', 'superlu3module.c')] library_dirs_list += superlu_lib_dir libraries_list += superlu_libraries ext_modules += [ Extension(package_name + '.superlu', src_files, define_macros=superlu_defs + numerix_macro, include_dirs=superlu_include_dirs, library_dirs=library_dirs_list, libraries=libraries_list, extra_compile_args=compily, extra_link_args=linky) ] execfile(os.path.join('Lib', '__version__.py')) setup(name = 'pysparse', version = __version__, description = 'Python Sparse Matrix Package', author = 'Roman Geus', author_email = 'roman@geus.ch', license = 'BSD style', url = 'http://www.geus.ch', packages = [package_name], package_dir = {package_name: 'Lib'}, package_data = {package_name: package_data}, include_dirs = ['Include'] + numerix_include_dirs, headers = glob.glob(os.path.join ("Include","pysparse","*.h")), ext_modules = ext_modules ) pysparse-1.1.1/PKG-INFO0000644010116400000240000000034111402271053013442 0ustar wd15dialoutMetadata-Version: 1.0 Name: pysparse Version: 1.1.1 Summary: Python Sparse Matrix Package Home-page: http://www.geus.ch Author: Roman Geus Author-email: roman@geus.ch License: BSD style Description: UNKNOWN Platform: UNKNOWN